• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * DHD Bus Module for SDIO
3  *
4  * Copyright (C) 1999-2013, Broadcom Corporation
5  *
6  *      Unless you and Broadcom execute a separate written software license
7  * agreement governing use of this software, this software is licensed to you
8  * under the terms of the GNU General Public License version 2 (the "GPL"),
9  * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10  * following added to such license:
11  *
12  *      As a special exception, the copyright holders of this software give you
13  * permission to link this software with independent modules, and to copy and
14  * distribute the resulting executable under terms of your choice, provided that
15  * you also meet, for each linked independent module, the terms and conditions of
16  * the license of that module.  An independent module is a module which is not
17  * derived from this software.  The special exception does not apply to any
18  * modifications of the software.
19  *
20  *      Notwithstanding the above, under no circumstances may you combine this
21  * software in any way with any other Broadcom software provided under a license
22  * other than the GPL, without Broadcom's express prior written consent.
23  *
24  * $Id: dhd_sdio.c 419981 2013-08-23 19:49:45Z $
25  */
26 
27 #include <typedefs.h>
28 #include <osl.h>
29 #include <bcmsdh.h>
30 
31 #ifdef BCMEMBEDIMAGE
32 #include BCMEMBEDIMAGE
33 #endif /* BCMEMBEDIMAGE */
34 
35 #include <bcmdefs.h>
36 #include <bcmutils.h>
37 #include <bcmendian.h>
38 #include <bcmdevs.h>
39 
40 #include <siutils.h>
41 #include <hndpmu.h>
42 #include <hndsoc.h>
43 #include <bcmsdpcm.h>
44 #if defined(DHD_DEBUG)
45 #include <hndrte_armtrap.h>
46 #include <hndrte_cons.h>
47 #endif /* defined(DHD_DEBUG) */
48 #include <sbchipc.h>
49 #include <sbhnddma.h>
50 
51 #include <sdio.h>
52 #include <sbsdio.h>
53 #include <sbsdpcmdev.h>
54 #include <bcmsdpcm.h>
55 #include <bcmsdbus.h>
56 
57 #include <proto/ethernet.h>
58 #include <proto/802.1d.h>
59 #include <proto/802.11.h>
60 
61 #include <dngl_stats.h>
62 #include <dhd.h>
63 #include <dhd_bus.h>
64 #include <dhd_proto.h>
65 #include <dhd_dbg.h>
66 #include <dhdioctl.h>
67 #include <sdiovar.h>
68 
69 bool dhd_mp_halting(dhd_pub_t *dhdp);
70 extern void bcmsdh_waitfor_iodrain(void *sdh);
71 extern void bcmsdh_reject_ioreqs(void *sdh, bool reject);
72 extern bool  bcmsdh_fatal_error(void *sdh);
73 
74 #ifndef DHDSDIO_MEM_DUMP_FNAME
75 #define DHDSDIO_MEM_DUMP_FNAME         "mem_dump"
76 #endif
77 
78 #define QLEN		256	/* bulk rx and tx queue lengths */
79 #define FCHI		(QLEN - 10)
80 #define FCLOW		(FCHI / 2)
81 #define PRIOMASK	7
82 
83 #define TXRETRIES	2	/* # of retries for tx frames */
84 #ifndef DHD_RXBOUND
85 #define DHD_RXBOUND	50	/* Default for max rx frames in one scheduling */
86 #endif
87 
88 #ifndef DHD_TXBOUND
89 #define DHD_TXBOUND	20	/* Default for max tx frames in one scheduling */
90 #endif
91 
92 #define DHD_TXMINMAX	1	/* Max tx frames if rx still pending */
93 
94 #define MEMBLOCK	2048		/* Block size used for downloading of dongle image */
95 #define MAX_NVRAMBUF_SIZE	4096	/* max nvram buf size */
96 #define MAX_DATA_BUF	(32 * 1024)	/* Must be large enough to hold biggest possible glom */
97 
98 #ifndef DHD_FIRSTREAD
99 #define DHD_FIRSTREAD   32
100 #endif
101 #if !ISPOWEROF2(DHD_FIRSTREAD)
102 #error DHD_FIRSTREAD is not a power of 2!
103 #endif
104 
105 #ifdef BCMSDIOH_TXGLOM
106 /* Total length of TX frame header for dongle protocol */
107 #define SDPCM_HDRLEN	(SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN + SDPCM_SWHEADER_LEN)
108 /* Total length of RX frame for dongle protocol */
109 #else
110 /* Total length of TX frame header for dongle protocol */
111 #define SDPCM_HDRLEN	(SDPCM_FRAMETAG_LEN + SDPCM_SWHEADER_LEN)
112 #endif
113 
114 #define SDPCM_HDRLEN_RX	(SDPCM_FRAMETAG_LEN + SDPCM_SWHEADER_LEN)
115 
116 #ifdef SDTEST
117 #define SDPCM_RESERVE	(SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN)
118 #else
119 #define SDPCM_RESERVE	(SDPCM_HDRLEN + DHD_SDALIGN)
120 #endif
121 
122 /* Space for header read, limit for data packets */
123 #ifndef MAX_HDR_READ
124 #define MAX_HDR_READ	32
125 #endif
126 #if !ISPOWEROF2(MAX_HDR_READ)
127 #error MAX_HDR_READ is not a power of 2!
128 #endif
129 
130 #define MAX_RX_DATASZ	2048
131 
132 /* Maximum milliseconds to wait for F2 to come up */
133 #define DHD_WAIT_F2RDY	3000
134 
135 /* Bump up limit on waiting for HT to account for first startup;
136  * if the image is doing a CRC calculation before programming the PMU
137  * for HT availability, it could take a couple hundred ms more, so
138  * max out at a 1 second (1000000us).
139  */
140 #if (PMU_MAX_TRANSITION_DLY <= 1000000)
141 #undef PMU_MAX_TRANSITION_DLY
142 #define PMU_MAX_TRANSITION_DLY 1000000
143 #endif
144 
145 /* Value for ChipClockCSR during initial setup */
146 #define DHD_INIT_CLKCTL1	(SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ)
147 #define DHD_INIT_CLKCTL2	(SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP)
148 
149 /* Flags for SDH calls */
150 #define F2SYNC	(SDIO_REQ_4BYTE | SDIO_REQ_FIXED)
151 
152 /* Packet free applicable unconditionally for sdio and sdspi.  Conditional if
153  * bufpool was present for gspi bus.
154  */
155 #define PKTFREE2()		if ((bus->bus != SPI_BUS) || bus->usebufpool) \
156 					PKTFREE(bus->dhd->osh, pkt, FALSE);
157 DHD_SPINWAIT_SLEEP_INIT(sdioh_spinwait_sleep);
158 #if defined(OOB_INTR_ONLY)
159 extern void bcmsdh_set_irq(int flag);
160 #endif
161 #ifdef PROP_TXSTATUS
162 extern void dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success);
163 extern void dhd_wlfc_trigger_pktcommit(dhd_pub_t *dhd);
164 #endif
165 
166 
167 #ifdef DHD_DEBUG
168 /* Device console log buffer state */
169 #define CONSOLE_LINE_MAX	192
170 #define CONSOLE_BUFFER_MAX	2024
171 typedef struct dhd_console {
172 	uint		count;			/* Poll interval msec counter */
173 	uint		log_addr;		/* Log struct address (fixed) */
174 	hndrte_log_t	log;			/* Log struct (host copy) */
175 	uint		bufsize;		/* Size of log buffer */
176 	uint8		*buf;			/* Log buffer (host copy) */
177 	uint		last;			/* Last buffer read index */
178 } dhd_console_t;
179 #endif /* DHD_DEBUG */
180 
181 #define	REMAP_ENAB(bus)			((bus)->remap)
182 #define	REMAP_ISADDR(bus, a)		(((a) >= ((bus)->orig_ramsize)) && ((a) < ((bus)->ramsize)))
183 #define	KSO_ENAB(bus)			((bus)->kso)
184 #define	SR_ENAB(bus)			((bus)->_srenab)
185 #define	SLPAUTO_ENAB(bus)		((SR_ENAB(bus)) && ((bus)->_slpauto))
186 #define	MIN_RSRC_ADDR			(SI_ENUM_BASE + 0x618)
187 #define	MIN_RSRC_SR			0x3
188 #define	CORE_CAPEXT_ADDR		(SI_ENUM_BASE + 0x64c)
189 #define	CORE_CAPEXT_SR_SUPPORTED_MASK	(1 << 1)
190 #define RCTL_MACPHY_DISABLE_MASK	(1 << 26)
191 #define RCTL_LOGIC_DISABLE_MASK		(1 << 27)
192 
193 #define	OOB_WAKEUP_ENAB(bus)		((bus)->_oobwakeup)
194 #define	GPIO_DEV_SRSTATE		16	/* Host gpio17 mapped to device gpio0 SR state */
195 #define	GPIO_DEV_SRSTATE_TIMEOUT	320000	/* 320ms */
196 #define	GPIO_DEV_WAKEUP			17	/* Host gpio17 mapped to device gpio1 wakeup */
197 #define	CC_CHIPCTRL2_GPIO1_WAKEUP	(1  << 0)
198 #define	CC_CHIPCTRL3_SR_ENG_ENABLE	(1  << 2)
199 #define OVERFLOW_BLKSZ512_WM		48
200 #define OVERFLOW_BLKSZ512_MES		80
201 
202 #define CC_PMUCC3	(0x3)
203 /* Private data for SDIO bus interaction */
204 typedef struct dhd_bus {
205 	dhd_pub_t	*dhd;
206 
207 	bcmsdh_info_t	*sdh;			/* Handle for BCMSDH calls */
208 	si_t		*sih;			/* Handle for SI calls */
209 	char		*vars;			/* Variables (from CIS and/or other) */
210 	uint		varsz;			/* Size of variables buffer */
211 	uint32		sbaddr;			/* Current SB window pointer (-1, invalid) */
212 
213 	sdpcmd_regs_t	*regs;			/* Registers for SDIO core */
214 	uint		sdpcmrev;		/* SDIO core revision */
215 	uint		armrev;			/* CPU core revision */
216 	uint		ramrev;			/* SOCRAM core revision */
217 	uint32		ramsize;		/* Size of RAM in SOCRAM (bytes) */
218 	uint32		orig_ramsize;		/* Size of RAM in SOCRAM (bytes) */
219 	uint32		srmemsize;		/* Size of SRMEM */
220 
221 	uint32		bus;			/* gSPI or SDIO bus */
222 	uint32		hostintmask;		/* Copy of Host Interrupt Mask */
223 	uint32		intstatus;		/* Intstatus bits (events) pending */
224 	bool		dpc_sched;		/* Indicates DPC schedule (intrpt rcvd) */
225 	bool		fcstate;		/* State of dongle flow-control */
226 
227 	uint16		cl_devid;		/* cached devid for dhdsdio_probe_attach() */
228 	char		*fw_path;		/* module_param: path to firmware image */
229 	char		*nv_path;		/* module_param: path to nvram vars file */
230 	const char      *nvram_params;		/* user specified nvram params. */
231 
232 	uint		blocksize;		/* Block size of SDIO transfers */
233 	uint		roundup;		/* Max roundup limit */
234 
235 	struct pktq	txq;			/* Queue length used for flow-control */
236 	uint8		flowcontrol;		/* per prio flow control bitmask */
237 	uint8		tx_seq;			/* Transmit sequence number (next) */
238 	uint8		tx_max;			/* Maximum transmit sequence allowed */
239 
240 	uint8		hdrbuf[MAX_HDR_READ + DHD_SDALIGN];
241 	uint8		*rxhdr;			/* Header of current rx frame (in hdrbuf) */
242 	uint16		nextlen;		/* Next Read Len from last header */
243 	uint8		rx_seq;			/* Receive sequence number (expected) */
244 	bool		rxskip;			/* Skip receive (awaiting NAK ACK) */
245 
246 	void		*glomd;			/* Packet containing glomming descriptor */
247 	void		*glom;			/* Packet chain for glommed superframe */
248 	uint		glomerr;		/* Glom packet read errors */
249 
250 	uint8		*rxbuf;			/* Buffer for receiving control packets */
251 	uint		rxblen;			/* Allocated length of rxbuf */
252 	uint8		*rxctl;			/* Aligned pointer into rxbuf */
253 	uint8		*databuf;		/* Buffer for receiving big glom packet */
254 	uint8		*dataptr;		/* Aligned pointer into databuf */
255 	uint		rxlen;			/* Length of valid data in buffer */
256 
257 	uint8		sdpcm_ver;		/* Bus protocol reported by dongle */
258 
259 	bool		intr;			/* Use interrupts */
260 	bool		poll;			/* Use polling */
261 	bool		ipend;			/* Device interrupt is pending */
262 	bool		intdis;			/* Interrupts disabled by isr */
263 	uint 		intrcount;		/* Count of device interrupt callbacks */
264 	uint		lastintrs;		/* Count as of last watchdog timer */
265 	uint		spurious;		/* Count of spurious interrupts */
266 	uint		pollrate;		/* Ticks between device polls */
267 	uint		polltick;		/* Tick counter */
268 	uint		pollcnt;		/* Count of active polls */
269 
270 #ifdef DHD_DEBUG
271 	dhd_console_t	console;		/* Console output polling support */
272 	uint		console_addr;		/* Console address from shared struct */
273 #endif /* DHD_DEBUG */
274 
275 	uint		regfails;		/* Count of R_REG/W_REG failures */
276 
277 	uint		clkstate;		/* State of sd and backplane clock(s) */
278 	bool		activity;		/* Activity flag for clock down */
279 	int32		idletime;		/* Control for activity timeout */
280 	int32		idlecount;		/* Activity timeout counter */
281 	int32		idleclock;		/* How to set bus driver when idle */
282 	int32		sd_divisor;		/* Speed control to bus driver */
283 	int32		sd_mode;		/* Mode control to bus driver */
284 	int32		sd_rxchain;		/* If bcmsdh api accepts PKT chains */
285 	bool		use_rxchain;		/* If dhd should use PKT chains */
286 	bool		sleeping;		/* Is SDIO bus sleeping? */
287 	uint		rxflow_mode;		/* Rx flow control mode */
288 	bool		rxflow;			/* Is rx flow control on */
289 	uint		prev_rxlim_hit;		/* Is prev rx limit exceeded (per dpc schedule) */
290 	bool		alp_only;		/* Don't use HT clock (ALP only) */
291 	/* Field to decide if rx of control frames happen in rxbuf or lb-pool */
292 	bool		usebufpool;
293 
294 #ifdef SDTEST
295 	/* external loopback */
296 	bool		ext_loop;
297 	uint8		loopid;
298 
299 	/* pktgen configuration */
300 	uint		pktgen_freq;		/* Ticks between bursts */
301 	uint		pktgen_count;		/* Packets to send each burst */
302 	uint		pktgen_print;		/* Bursts between count displays */
303 	uint		pktgen_total;		/* Stop after this many */
304 	uint		pktgen_minlen;		/* Minimum packet data len */
305 	uint		pktgen_maxlen;		/* Maximum packet data len */
306 	uint		pktgen_mode;		/* Configured mode: tx, rx, or echo */
307 	uint		pktgen_stop;		/* Number of tx failures causing stop */
308 
309 	/* active pktgen fields */
310 	uint		pktgen_tick;		/* Tick counter for bursts */
311 	uint		pktgen_ptick;		/* Burst counter for printing */
312 	uint		pktgen_sent;		/* Number of test packets generated */
313 	uint		pktgen_rcvd;		/* Number of test packets received */
314 	uint		pktgen_prev_time;	/* Time at which previous stats where printed */
315 	uint		pktgen_prev_sent;	/* Number of test packets generated when
316 						 * previous stats were printed
317 						 */
318 	uint		pktgen_prev_rcvd;	/* Number of test packets received when
319 						 * previous stats were printed
320 						 */
321 	uint		pktgen_fail;		/* Number of failed send attempts */
322 	uint16		pktgen_len;		/* Length of next packet to send */
323 #define PKTGEN_RCV_IDLE     (0)
324 #define PKTGEN_RCV_ONGOING  (1)
325 	uint16		pktgen_rcv_state;		/* receive state */
326 	uint		pktgen_rcvd_rcvsession;	/* test pkts rcvd per rcv session. */
327 #endif /* SDTEST */
328 
329 	/* Some additional counters */
330 	uint		tx_sderrs;		/* Count of tx attempts with sd errors */
331 	uint		fcqueued;		/* Tx packets that got queued */
332 	uint		rxrtx;			/* Count of rtx requests (NAK to dongle) */
333 	uint		rx_toolong;		/* Receive frames too long to receive */
334 	uint		rxc_errors;		/* SDIO errors when reading control frames */
335 	uint		rx_hdrfail;		/* SDIO errors on header reads */
336 	uint		rx_badhdr;		/* Bad received headers (roosync?) */
337 	uint		rx_badseq;		/* Mismatched rx sequence number */
338 	uint		fc_rcvd;		/* Number of flow-control events received */
339 	uint		fc_xoff;		/* Number which turned on flow-control */
340 	uint		fc_xon;			/* Number which turned off flow-control */
341 	uint		rxglomfail;		/* Failed deglom attempts */
342 	uint		rxglomframes;		/* Number of glom frames (superframes) */
343 	uint		rxglompkts;		/* Number of packets from glom frames */
344 	uint		f2rxhdrs;		/* Number of header reads */
345 	uint		f2rxdata;		/* Number of frame data reads */
346 	uint		f2txdata;		/* Number of f2 frame writes */
347 	uint		f1regdata;		/* Number of f1 register accesses */
348 
349 	uint8		*ctrl_frame_buf;
350 	uint32		ctrl_frame_len;
351 	bool		ctrl_frame_stat;
352 	uint32		rxint_mode;	/* rx interrupt mode */
353 	bool		remap;		/* Contiguous 1MB RAM: 512K socram + 512K devram
354 					 * Available with socram rev 16
355 					 * Remap region not DMA-able
356 					 */
357 	bool		kso;
358 	bool		_slpauto;
359 	bool		_oobwakeup;
360 	bool		_srenab;
361 	bool        readframes;
362 	bool        reqbussleep;
363 	uint32		resetinstr;
364 	uint32		dongle_ram_base;
365 #ifdef BCMSDIOH_TXGLOM
366 	void		*glom_pkt_arr[SDPCM_MAXGLOM_SIZE];	/* Array of pkts for glomming */
367 	uint16		glom_cnt;	/* Number of pkts in the glom array */
368 	uint16		glom_total_len;	/* Total length of pkts in glom array */
369 	bool		glom_enable;	/* Flag to indicate whether tx glom is enabled/disabled */
370 	uint8		glom_mode;	/* Glom mode - 0-copy mode, 1 - Multi-descriptor mode */
371 	uint32		glomsize;	/* Glom size limitation */
372 #endif
373 } dhd_bus_t;
374 
375 /* clkstate */
376 #define CLK_NONE	0
377 #define CLK_SDONLY	1
378 #define CLK_PENDING	2	/* Not used yet */
379 #define CLK_AVAIL	3
380 
381 #define DHD_NOPMU(dhd)	(FALSE)
382 
383 #ifdef DHD_DEBUG
384 static int qcount[NUMPRIO];
385 static int tx_packets[NUMPRIO];
386 #endif /* DHD_DEBUG */
387 
388 /* Deferred transmit */
389 const uint dhd_deferred_tx = 1;
390 
391 extern uint dhd_watchdog_ms;
392 
393 extern void dhd_os_wd_timer(void *bus, uint wdtick);
394 
395 /* Tx/Rx bounds */
396 uint dhd_txbound;
397 uint dhd_rxbound;
398 uint dhd_txminmax = DHD_TXMINMAX;
399 
400 /* override the RAM size if possible */
401 #define DONGLE_MIN_RAMSIZE (128 *1024)
402 int dhd_dongle_ramsize;
403 
404 uint dhd_doflow = TRUE;
405 uint dhd_dpcpoll = FALSE;
406 
407 module_param(dhd_doflow, uint, 0644);
408 module_param(dhd_dpcpoll, uint, 0644);
409 
410 static bool dhd_alignctl;
411 
412 static bool sd1idle;
413 
414 static bool retrydata;
415 #define RETRYCHAN(chan) (((chan) == SDPCM_EVENT_CHANNEL) || retrydata)
416 
417 #if defined(SDIO_CRC_ERROR_FIX)
418 static uint watermark = 48;
419 static uint mesbusyctrl = 80;
420 #else
421 static const uint watermark = 8;
422 static const uint mesbusyctrl = 0;
423 #endif
424 static const uint firstread = DHD_FIRSTREAD;
425 
426 #define HDATLEN (firstread - (SDPCM_HDRLEN))
427 
428 /* Retry count for register access failures */
429 static const uint retry_limit = 2;
430 
431 /* Force even SD lengths (some host controllers mess up on odd bytes) */
432 static bool forcealign;
433 
434 #define ALIGNMENT  4
435 
436 #if defined(OOB_INTR_ONLY) && defined(HW_OOB)
437 extern void bcmsdh_enable_hw_oob_intr(void *sdh, bool enable);
438 #endif
439 
440 #if defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD)
441 #error OOB_INTR_ONLY is NOT working with SDIO_ISR_THREAD
442 #endif /* defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD) */
443 #define PKTALIGN(osh, p, len, align)					\
444 	do {								\
445 		uint datalign;						\
446 		datalign = (uintptr)PKTDATA((osh), (p));		\
447 		datalign = ROUNDUP(datalign, (align)) - datalign;	\
448 		ASSERT(datalign < (align));				\
449 		ASSERT(PKTLEN((osh), (p)) >= ((len) + datalign));	\
450 		if (datalign)						\
451 			PKTPULL((osh), (p), datalign);			\
452 		PKTSETLEN((osh), (p), (len));				\
453 	} while (0)
454 
455 /* Limit on rounding up frames */
456 static const uint max_roundup = 512;
457 
458 /* Try doing readahead */
459 static bool dhd_readahead;
460 
461 /* To check if there's window offered */
462 #define DATAOK(bus) \
463 	(((uint8)(bus->tx_max - bus->tx_seq) > 1) && \
464 	(((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0))
465 
466 /* To check if there's window offered for ctrl frame */
467 #define TXCTLOK(bus) \
468 	(((uint8)(bus->tx_max - bus->tx_seq) != 0) && \
469 	(((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0))
470 
471 /* Number of pkts available in dongle for data RX */
472 #define DATABUFCNT(bus) \
473 	((uint8)(bus->tx_max - bus->tx_seq) - 1)
474 
475 /* Macros to get register read/write status */
476 /* NOTE: these assume a local dhdsdio_bus_t *bus! */
477 #define R_SDREG(regvar, regaddr, retryvar) \
478 do { \
479 	retryvar = 0; \
480 	do { \
481 		regvar = R_REG(bus->dhd->osh, regaddr); \
482 	} while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \
483 	if (retryvar) { \
484 		bus->regfails += (retryvar-1); \
485 		if (retryvar > retry_limit) { \
486 			DHD_ERROR(("%s: FAILED" #regvar "READ, LINE %d\n", \
487 			           __FUNCTION__, __LINE__)); \
488 			regvar = 0; \
489 		} \
490 	} \
491 } while (0)
492 
493 #define W_SDREG(regval, regaddr, retryvar) \
494 do { \
495 	retryvar = 0; \
496 	do { \
497 		W_REG(bus->dhd->osh, regaddr, regval); \
498 	} while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \
499 	if (retryvar) { \
500 		bus->regfails += (retryvar-1); \
501 		if (retryvar > retry_limit) \
502 			DHD_ERROR(("%s: FAILED REGISTER WRITE, LINE %d\n", \
503 			           __FUNCTION__, __LINE__)); \
504 	} \
505 } while (0)
506 
507 #define BUS_WAKE(bus) \
508 	do { \
509 		bus->idlecount = 0; \
510 		if ((bus)->sleeping) \
511 			dhdsdio_bussleep((bus), FALSE); \
512 	} while (0);
513 
514 /*
515  * pktavail interrupts from dongle to host can be managed in 3 different ways
516  * whenever there is a packet available in dongle to transmit to host.
517  *
518  * Mode 0:	Dongle writes the software host mailbox and host is interrupted.
519  * Mode 1:	(sdiod core rev >= 4)
520  *		Device sets a new bit in the intstatus whenever there is a packet
521  *		available in fifo.  Host can't clear this specific status bit until all the
522  *		packets are read from the FIFO.  No need to ack dongle intstatus.
523  * Mode 2:	(sdiod core rev >= 4)
524  *		Device sets a bit in the intstatus, and host acks this by writing
525  *		one to this bit.  Dongle won't generate anymore packet interrupts
526  *		until host reads all the packets from the dongle and reads a zero to
527  *		figure that there are no more packets.  No need to disable host ints.
528  *		Need to ack the intstatus.
529  */
530 
531 #define SDIO_DEVICE_HMB_RXINT		0	/* default old way */
532 #define SDIO_DEVICE_RXDATAINT_MODE_0	1	/* from sdiod rev 4 */
533 #define SDIO_DEVICE_RXDATAINT_MODE_1	2	/* from sdiod rev 4 */
534 
535 
536 #define FRAME_AVAIL_MASK(bus) 	\
537 	((bus->rxint_mode == SDIO_DEVICE_HMB_RXINT) ? I_HMB_FRAME_IND : I_XMTDATA_AVAIL)
538 
539 #define DHD_BUS			SDIO_BUS
540 
541 #define PKT_AVAILABLE(bus, intstatus)	((intstatus) & (FRAME_AVAIL_MASK(bus)))
542 
543 #define HOSTINTMASK		(I_HMB_SW_MASK | I_CHIPACTIVE)
544 
545 #define GSPI_PR55150_BAILOUT
546 
547 #ifdef SDTEST
548 static void dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq);
549 static void dhdsdio_sdtest_set(dhd_bus_t *bus, uint count);
550 #endif
551 
552 #ifdef DHD_DEBUG
553 static int dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size);
554 static int dhd_serialconsole(dhd_bus_t *bus, bool get, bool enable, int *bcmerror);
555 #endif /* DHD_DEBUG */
556 
557 static int dhdsdio_devcap_set(dhd_bus_t *bus, uint8 cap);
558 static int dhdsdio_download_state(dhd_bus_t *bus, bool enter);
559 
560 static void dhdsdio_release(dhd_bus_t *bus, osl_t *osh);
561 static void dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh);
562 static void dhdsdio_disconnect(void *ptr);
563 static bool dhdsdio_chipmatch(uint16 chipid);
564 static bool dhdsdio_probe_attach(dhd_bus_t *bus, osl_t *osh, void *sdh,
565                                  void * regsva, uint16  devid);
566 static bool dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh);
567 static bool dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh);
568 static void dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation,
569 	bool reset_flag);
570 
571 static void dhd_dongle_setramsize(struct dhd_bus *bus, int mem_size);
572 static int dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags,
573 	uint8 *buf, uint nbytes,
574 	void *pkt, bcmsdh_cmplt_fn_t complete, void *handle);
575 static int dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags,
576 	uint8 *buf, uint nbytes,
577 	void *pkt, bcmsdh_cmplt_fn_t complete, void *handle);
578 #ifdef BCMSDIOH_TXGLOM
579 static void dhd_bcmsdh_glom_post(dhd_bus_t *bus, uint8 *frame, void *pkt, uint len);
580 static void dhd_bcmsdh_glom_clear(dhd_bus_t *bus);
581 #endif
582 
583 static bool dhdsdio_download_firmware(dhd_bus_t *bus, osl_t *osh, void *sdh);
584 static int _dhdsdio_download_firmware(dhd_bus_t *bus);
585 
586 static int dhdsdio_download_code_file(dhd_bus_t *bus, char *image_path);
587 static int dhdsdio_download_nvram(dhd_bus_t *bus);
588 #ifdef BCMEMBEDIMAGE
589 static int dhdsdio_download_code_array(dhd_bus_t *bus);
590 #endif
591 static int dhdsdio_bussleep(dhd_bus_t *bus, bool sleep);
592 static int dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok);
593 static uint8 dhdsdio_sleepcsr_get(dhd_bus_t *bus);
594 
595 #ifdef WLMEDIA_HTSF
596 #include <htsf.h>
597 extern uint32 dhd_get_htsf(void *dhd, int ifidx);
598 #endif /* WLMEDIA_HTSF */
599 
600 static void
dhd_overflow_war(struct dhd_bus * bus)601 dhd_overflow_war(struct dhd_bus *bus)
602 {
603 	int err;
604 	uint8 devctl, wm, mes;
605 
606 	/* See .ppt in PR for these recommended values */
607 	if (bus->blocksize == 512) {
608 		wm = OVERFLOW_BLKSZ512_WM;
609 		mes = OVERFLOW_BLKSZ512_MES;
610 	} else {
611 		mes = bus->blocksize/4;
612 		wm = bus->blocksize/4;
613 	}
614 
615 
616 	/* Update watermark */
617 	bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, wm, &err);
618 
619 	devctl = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
620 	devctl |= SBSDIO_DEVCTL_F2WM_ENAB;
621 	bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
622 
623 	/* Update MES */
624 	bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL,
625 		(mes | SBSDIO_MESBUSYCTRL_ENAB), &err);
626 
627 	DHD_INFO(("Apply overflow WAR: 0x%02x 0x%02x 0x%02x\n",
628 		bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err),
629 		bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, &err),
630 		bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL, &err)));
631 }
632 
633 static void
dhd_dongle_setramsize(struct dhd_bus * bus,int mem_size)634 dhd_dongle_setramsize(struct dhd_bus *bus, int mem_size)
635 {
636 	int32 min_size =  DONGLE_MIN_RAMSIZE;
637 	/* Restrict the ramsize to user specified limit */
638 	DHD_ERROR(("user: Restrict the dongle ram size to %d, min accepted %d\n",
639 		dhd_dongle_ramsize, min_size));
640 	if ((dhd_dongle_ramsize > min_size) &&
641 		(dhd_dongle_ramsize < (int32)bus->orig_ramsize))
642 		bus->ramsize = dhd_dongle_ramsize;
643 }
644 
645 static int
dhdsdio_set_siaddr_window(dhd_bus_t * bus,uint32 address)646 dhdsdio_set_siaddr_window(dhd_bus_t *bus, uint32 address)
647 {
648 	int err = 0;
649 	bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW,
650 	                 (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err);
651 	if (!err)
652 		bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID,
653 		                 (address >> 16) & SBSDIO_SBADDRMID_MASK, &err);
654 	if (!err)
655 		bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH,
656 		                 (address >> 24) & SBSDIO_SBADDRHIGH_MASK, &err);
657 	return err;
658 }
659 
660 
661 #ifdef USE_OOB_GPIO1
662 static int
dhdsdio_oobwakeup_init(dhd_bus_t * bus)663 dhdsdio_oobwakeup_init(dhd_bus_t *bus)
664 {
665 	uint32 val, addr, data;
666 
667 	bcmsdh_gpioouten(bus->sdh, GPIO_DEV_WAKEUP);
668 
669 	addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr);
670 	data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data);
671 
672 	/* Set device for gpio1 wakeup */
673 	bcmsdh_reg_write(bus->sdh, addr, 4, 2);
674 	val = bcmsdh_reg_read(bus->sdh, data, 4);
675 	val |= CC_CHIPCTRL2_GPIO1_WAKEUP;
676 	bcmsdh_reg_write(bus->sdh, data, 4, val);
677 
678 	bus->_oobwakeup = TRUE;
679 
680 	return 0;
681 }
682 #endif /* USE_OOB_GPIO1 */
683 
684 /*
685  * Query if FW is in SR mode
686  */
687 static bool
dhdsdio_sr_cap(dhd_bus_t * bus)688 dhdsdio_sr_cap(dhd_bus_t *bus)
689 {
690 	bool cap = FALSE;
691 	uint32  core_capext, addr, data;
692 	if (bus->sih->chip == BCM4324_CHIP_ID) {
693 			addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr);
694 			data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data);
695 			bcmsdh_reg_write(bus->sdh, addr, 4, 3);
696 			core_capext = bcmsdh_reg_read(bus->sdh, data, 4);
697 	} else if (bus->sih->chip == BCM4330_CHIP_ID) {
698 			core_capext = FALSE;
699 	} else if ((bus->sih->chip == BCM4335_CHIP_ID) ||
700 		(bus->sih->chip == BCM4339_CHIP_ID) ||
701 		(bus->sih->chip == BCM4350_CHIP_ID)) {
702 		core_capext = TRUE;
703 	} else {
704 			core_capext = bcmsdh_reg_read(bus->sdh, CORE_CAPEXT_ADDR, 4);
705 			core_capext = (core_capext & CORE_CAPEXT_SR_SUPPORTED_MASK);
706 	}
707 	if (!(core_capext))
708 		return FALSE;
709 
710 	if (bus->sih->chip == BCM4324_CHIP_ID) {
711 		/* FIX: Should change to query SR control register instead */
712 		cap = TRUE;
713 	} else if ((bus->sih->chip == BCM4335_CHIP_ID) ||
714 		(bus->sih->chip == BCM4339_CHIP_ID)) {
715 		uint32 enabval = 0;
716 		addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr);
717 		data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data);
718 		bcmsdh_reg_write(bus->sdh, addr, 4, CC_PMUCC3);
719 		enabval = bcmsdh_reg_read(bus->sdh, data, 4);
720 
721 		if ((bus->sih->chip == BCM4350_CHIP_ID) ||
722 			0)
723 				enabval &= CC_CHIPCTRL3_SR_ENG_ENABLE;
724 
725 
726 		if (enabval)
727 			cap = TRUE;
728 	} else {
729 		data = bcmsdh_reg_read(bus->sdh,
730 			SI_ENUM_BASE + OFFSETOF(chipcregs_t, retention_ctl), 4);
731 		if ((data & (RCTL_MACPHY_DISABLE_MASK | RCTL_LOGIC_DISABLE_MASK)) == 0)
732 			cap = TRUE;
733 	}
734 
735 	return cap;
736 }
737 
738 static int
dhdsdio_srwar_init(dhd_bus_t * bus)739 dhdsdio_srwar_init(dhd_bus_t *bus)
740 {
741 	bcmsdh_gpio_init(bus->sdh);
742 
743 #ifdef USE_OOB_GPIO1
744 	dhdsdio_oobwakeup_init(bus);
745 #endif
746 
747 
748 	return 0;
749 }
750 
751 static int
dhdsdio_sr_init(dhd_bus_t * bus)752 dhdsdio_sr_init(dhd_bus_t *bus)
753 {
754 	uint8 val;
755 	int err = 0;
756 
757 	if ((bus->sih->chip == BCM4334_CHIP_ID) && (bus->sih->chiprev == 2))
758 		dhdsdio_srwar_init(bus);
759 
760 	val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, NULL);
761 	val |= 1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT;
762 	bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL,
763 		1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT, &err);
764 	val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, NULL);
765 
766 	/* Add CMD14 Support */
767 	dhdsdio_devcap_set(bus,
768 		(SDIOD_CCCR_BRCM_CARDCAP_CMD14_SUPPORT | SDIOD_CCCR_BRCM_CARDCAP_CMD14_EXT));
769 
770 	bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1,
771 		SBSDIO_FUNC1_CHIPCLKCSR, SBSDIO_FORCE_HT, &err);
772 
773 	bus->_slpauto = dhd_slpauto ? TRUE : FALSE;
774 
775 	bus->_srenab = TRUE;
776 
777 	return 0;
778 }
779 
780 /*
781  * FIX: Be sure KSO bit is enabled
782  * Currently, it's defaulting to 0 which should be 1.
783  */
784 static int
dhdsdio_clk_kso_init(dhd_bus_t * bus)785 dhdsdio_clk_kso_init(dhd_bus_t *bus)
786 {
787 	uint8 val;
788 	int err = 0;
789 
790 	/* set flag */
791 	bus->kso = TRUE;
792 
793 	/*
794 	 * Enable KeepSdioOn (KSO) bit for normal operation
795 	 * Default is 0 (4334A0) so set it. Fixed in B0.
796 	 */
797 	val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, NULL);
798 	if (!(val & SBSDIO_FUNC1_SLEEPCSR_KSO_MASK)) {
799 		val |= (SBSDIO_FUNC1_SLEEPCSR_KSO_EN << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT);
800 		bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, val, &err);
801 		if (err)
802 			DHD_ERROR(("%s: SBSDIO_FUNC1_SLEEPCSR err: 0x%x\n", __FUNCTION__, err));
803 	}
804 
805 	return 0;
806 }
807 
808 #define KSO_DBG(x)
809 #define KSO_WAIT_US 50
810 #define MAX_KSO_ATTEMPTS (PMU_MAX_TRANSITION_DLY/KSO_WAIT_US)
811 static int
dhdsdio_clk_kso_enab(dhd_bus_t * bus,bool on)812 dhdsdio_clk_kso_enab(dhd_bus_t *bus, bool on)
813 {
814 	uint8 wr_val = 0, rd_val, cmp_val, bmask;
815 	int err = 0;
816 	int try_cnt = 0;
817 
818 	KSO_DBG(("%s> op:%s\n", __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR")));
819 
820 	wr_val |= (on << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT);
821 
822 	bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, wr_val, &err);
823 
824 	if (on) {
825 		cmp_val = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK |  SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK;
826 		bmask = cmp_val;
827 
828 		OSL_SLEEP(3);
829 	} else {
830 		/* Put device to sleep, turn off  KSO  */
831 		cmp_val = 0;
832 		bmask = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK;
833 	}
834 
835 	do {
836 		rd_val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, &err);
837 		if (((rd_val & bmask) == cmp_val) && !err)
838 			break;
839 
840 		KSO_DBG(("%s> KSO wr/rd retry:%d, ERR:%x \n", __FUNCTION__, try_cnt, err));
841 		OSL_DELAY(KSO_WAIT_US);
842 
843 		bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, wr_val, &err);
844 	} while (try_cnt++ < MAX_KSO_ATTEMPTS);
845 
846 
847 	if (try_cnt > 2)
848 		KSO_DBG(("%s> op:%s, try_cnt:%d, rd_val:%x, ERR:%x \n",
849 			__FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"), try_cnt, rd_val, err));
850 
851 	if (try_cnt > MAX_KSO_ATTEMPTS)  {
852 		DHD_ERROR(("%s> op:%s, ERROR: try_cnt:%d, rd_val:%x, ERR:%x \n",
853 			__FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"), try_cnt, rd_val, err));
854 	}
855 	return err;
856 }
857 
858 static int
dhdsdio_clk_kso_iovar(dhd_bus_t * bus,bool on)859 dhdsdio_clk_kso_iovar(dhd_bus_t *bus, bool on)
860 {
861 	int err = 0;
862 
863 	if (on == FALSE) {
864 
865 		BUS_WAKE(bus);
866 		dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
867 
868 		DHD_ERROR(("%s: KSO disable clk: 0x%x\n", __FUNCTION__,
869 			bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
870 			SBSDIO_FUNC1_CHIPCLKCSR, &err)));
871 		dhdsdio_clk_kso_enab(bus, FALSE);
872 	} else {
873 		DHD_ERROR(("%s: KSO enable\n", __FUNCTION__));
874 
875 		/* Make sure we have SD bus access */
876 		if (bus->clkstate == CLK_NONE) {
877 			DHD_ERROR(("%s: Request SD clk\n", __FUNCTION__));
878 			dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
879 		}
880 
881 		dhdsdio_clk_kso_enab(bus, TRUE);
882 
883 		DHD_ERROR(("%s: sleepcsr: 0x%x\n", __FUNCTION__,
884 			dhdsdio_sleepcsr_get(bus)));
885 	}
886 
887 	bus->kso = on;
888 	BCM_REFERENCE(err);
889 
890 	return 0;
891 }
892 
893 static uint8
dhdsdio_sleepcsr_get(dhd_bus_t * bus)894 dhdsdio_sleepcsr_get(dhd_bus_t *bus)
895 {
896 	int err = 0;
897 	uint8 val = 0;
898 
899 	val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, &err);
900 	if (err)
901 		DHD_TRACE(("Failed to read SLEEPCSR: %d\n", err));
902 
903 	return val;
904 }
905 
906 uint8
dhdsdio_devcap_get(dhd_bus_t * bus)907 dhdsdio_devcap_get(dhd_bus_t *bus)
908 {
909 	return bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_BRCM_CARDCAP, NULL);
910 }
911 
912 static int
dhdsdio_devcap_set(dhd_bus_t * bus,uint8 cap)913 dhdsdio_devcap_set(dhd_bus_t *bus, uint8 cap)
914 {
915 	int err = 0;
916 
917 	bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_BRCM_CARDCAP, cap, &err);
918 	if (err)
919 		DHD_ERROR(("%s: devcap set err: 0x%x\n", __FUNCTION__, err));
920 
921 	return 0;
922 }
923 
924 static int
dhdsdio_clk_devsleep_iovar(dhd_bus_t * bus,bool on)925 dhdsdio_clk_devsleep_iovar(dhd_bus_t *bus, bool on)
926 {
927 	int err = 0, retry;
928 	uint8 val;
929 
930 	retry = 0;
931 	if (on == TRUE) {
932 		/* Enter Sleep */
933 
934 		/* Be sure we request clk before going to sleep
935 		 * so we can wake-up with clk request already set
936 		 * else device can go back to sleep immediately
937 		 */
938 		if (!SLPAUTO_ENAB(bus))
939 			dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
940 		else {
941 			val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
942 			if ((val & SBSDIO_CSR_MASK) == 0) {
943 				DHD_ERROR(("%s: No clock before enter sleep:0x%x\n",
944 					__FUNCTION__, val));
945 
946 				/* Reset clock request */
947 				bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
948 					SBSDIO_ALP_AVAIL_REQ, &err);
949 				DHD_ERROR(("%s: clock before sleep:0x%x\n", __FUNCTION__,
950 					bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
951 					SBSDIO_FUNC1_CHIPCLKCSR, &err)));
952 			}
953 		}
954 
955 		DHD_TRACE(("%s: clk before sleep: 0x%x\n", __FUNCTION__,
956 			bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
957 			SBSDIO_FUNC1_CHIPCLKCSR, &err)));
958 #ifdef USE_CMD14
959 		err = bcmsdh_sleep(bus->sdh, TRUE);
960 #else
961 		err = dhdsdio_clk_kso_enab(bus, FALSE);
962 		if (OOB_WAKEUP_ENAB(bus))
963 		{
964 			err = bcmsdh_gpioout(bus->sdh, GPIO_DEV_WAKEUP, FALSE);  /* GPIO_1 is off */
965 		}
966 #endif /* USE_CMD14 */
967 	} else {
968 		/* Exit Sleep */
969 		/* Make sure we have SD bus access */
970 		if (bus->clkstate == CLK_NONE) {
971 			DHD_TRACE(("%s: Request SD clk\n", __FUNCTION__));
972 			dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
973 		}
974 
975 		if ((bus->sih->chip == BCM4334_CHIP_ID) && (bus->sih->chiprev == 2)) {
976 			SPINWAIT_SLEEP(sdioh_spinwait_sleep,
977 				(bcmsdh_gpioin(bus->sdh, GPIO_DEV_SRSTATE) != TRUE),
978 				GPIO_DEV_SRSTATE_TIMEOUT);
979 
980 			if (bcmsdh_gpioin(bus->sdh, GPIO_DEV_SRSTATE) == FALSE) {
981 				DHD_ERROR(("ERROR: GPIO_DEV_SRSTATE still low!\n"));
982 			}
983 		}
984 #ifdef USE_CMD14
985 		err = bcmsdh_sleep(bus->sdh, FALSE);
986 		if (SLPAUTO_ENAB(bus) && (err != 0)) {
987 			OSL_DELAY(10000);
988 			DHD_TRACE(("%s: Resync device sleep\n", __FUNCTION__));
989 
990 			/* Toggle sleep to resync with host and device */
991 			err = bcmsdh_sleep(bus->sdh, TRUE);
992 			OSL_DELAY(10000);
993 			err = bcmsdh_sleep(bus->sdh, FALSE);
994 
995 			if (err) {
996 				OSL_DELAY(10000);
997 				DHD_ERROR(("%s: CMD14 exit failed again!\n", __FUNCTION__));
998 
999 				/* Toggle sleep to resync with host and device */
1000 				err = bcmsdh_sleep(bus->sdh, TRUE);
1001 				OSL_DELAY(10000);
1002 				err = bcmsdh_sleep(bus->sdh, FALSE);
1003 				if (err) {
1004 					DHD_ERROR(("%s: CMD14 exit failed twice!\n", __FUNCTION__));
1005 					DHD_ERROR(("%s: FATAL: Device non-response!\n",
1006 						__FUNCTION__));
1007 					err = 0;
1008 				}
1009 			}
1010 		}
1011 #else
1012 		if (OOB_WAKEUP_ENAB(bus))
1013 		{
1014 			err = bcmsdh_gpioout(bus->sdh, GPIO_DEV_WAKEUP, TRUE);  /* GPIO_1 is on */
1015 		}
1016 		do {
1017 			err = dhdsdio_clk_kso_enab(bus, TRUE);
1018 			if (err)
1019 				OSL_SLEEP(10);
1020 		} while ((err != 0) && (++retry < 3));
1021 
1022 		if (err != 0) {
1023 			DHD_ERROR(("ERROR: kso set failed retry: %d\n", retry));
1024 			err = 0; /* continue anyway */
1025 		}
1026 #endif /* !USE_CMD14 */
1027 
1028 		if (err == 0) {
1029 			uint8 csr;
1030 
1031 			/* Wait for device ready during transition to wake-up */
1032 			SPINWAIT_SLEEP(sdioh_spinwait_sleep,
1033 				(((csr = dhdsdio_sleepcsr_get(bus)) &
1034 				SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK) !=
1035 				(SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK)), (20000));
1036 
1037 			DHD_TRACE(("%s: ExitSleep sleepcsr: 0x%x\n", __FUNCTION__, csr));
1038 
1039 			if (!(csr & SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK)) {
1040 				DHD_ERROR(("%s:ERROR: ExitSleep device NOT Ready! 0x%x\n",
1041 					__FUNCTION__, csr));
1042 				err = BCME_NODEVICE;
1043 			}
1044 
1045 			SPINWAIT_SLEEP(sdioh_spinwait_sleep,
1046 				(((csr = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
1047 				SBSDIO_FUNC1_CHIPCLKCSR, &err)) & SBSDIO_HT_AVAIL) !=
1048 				(SBSDIO_HT_AVAIL)), (10000));
1049 
1050 		}
1051 	}
1052 
1053 	/* Update if successful */
1054 	if (err == 0)
1055 		bus->kso = on ? FALSE : TRUE;
1056 	else {
1057 		DHD_ERROR(("%s: Sleep request failed: on:%d err:%d\n", __FUNCTION__, on, err));
1058 		if (!on && retry > 2)
1059 			bus->kso = TRUE;
1060 	}
1061 
1062 	return err;
1063 }
1064 
1065 /* Turn backplane clock on or off */
1066 static int
dhdsdio_htclk(dhd_bus_t * bus,bool on,bool pendok)1067 dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok)
1068 {
1069 #define HT_AVAIL_ERROR_MAX 10
1070 	static int ht_avail_error = 0;
1071 	int err;
1072 	uint8 clkctl, clkreq, devctl;
1073 	bcmsdh_info_t *sdh;
1074 
1075 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1076 
1077 	clkctl = 0;
1078 	sdh = bus->sdh;
1079 
1080 
1081 	if (!KSO_ENAB(bus))
1082 		return BCME_OK;
1083 
1084 	if (SLPAUTO_ENAB(bus)) {
1085 		bus->clkstate = (on ? CLK_AVAIL : CLK_SDONLY);
1086 		return BCME_OK;
1087 	}
1088 
1089 	if (on) {
1090 		/* Request HT Avail */
1091 		clkreq = bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ;
1092 
1093 
1094 
1095 		bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
1096 		if (err) {
1097 			ht_avail_error++;
1098 			if (ht_avail_error < HT_AVAIL_ERROR_MAX) {
1099 				DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err));
1100 			}
1101 
1102 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
1103 			else if (ht_avail_error == HT_AVAIL_ERROR_MAX) {
1104 				dhd_os_send_hang_message(bus->dhd);
1105 			}
1106 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) */
1107 			return BCME_ERROR;
1108 		} else {
1109 			ht_avail_error = 0;
1110 		}
1111 
1112 
1113 		/* Check current status */
1114 		clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
1115 		if (err) {
1116 			DHD_ERROR(("%s: HT Avail read error: %d\n", __FUNCTION__, err));
1117 			return BCME_ERROR;
1118 		}
1119 
1120 #if !defined(OOB_INTR_ONLY)
1121 		/* Go to pending and await interrupt if appropriate */
1122 		if (!SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) {
1123 			/* Allow only clock-available interrupt */
1124 			devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
1125 			if (err) {
1126 				DHD_ERROR(("%s: Devctl access error setting CA: %d\n",
1127 				           __FUNCTION__, err));
1128 				return BCME_ERROR;
1129 			}
1130 
1131 			devctl |= SBSDIO_DEVCTL_CA_INT_ONLY;
1132 			bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
1133 			DHD_INFO(("CLKCTL: set PENDING\n"));
1134 			bus->clkstate = CLK_PENDING;
1135 			return BCME_OK;
1136 		} else
1137 #endif /* !defined (OOB_INTR_ONLY) */
1138 		{
1139 			if (bus->clkstate == CLK_PENDING) {
1140 				/* Cancel CA-only interrupt filter */
1141 				devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
1142 				devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
1143 				bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
1144 			}
1145 		}
1146 
1147 		/* Otherwise, wait here (polling) for HT Avail */
1148 		if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
1149 			SPINWAIT_SLEEP(sdioh_spinwait_sleep,
1150 				((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
1151 			                                    SBSDIO_FUNC1_CHIPCLKCSR, &err)),
1152 			          !SBSDIO_CLKAV(clkctl, bus->alp_only)), PMU_MAX_TRANSITION_DLY);
1153 		}
1154 		if (err) {
1155 			DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err));
1156 			return BCME_ERROR;
1157 		}
1158 		if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
1159 			DHD_ERROR(("%s: HT Avail timeout (%d): clkctl 0x%02x\n",
1160 			           __FUNCTION__, PMU_MAX_TRANSITION_DLY, clkctl));
1161 			return BCME_ERROR;
1162 		}
1163 
1164 		/* Mark clock available */
1165 		bus->clkstate = CLK_AVAIL;
1166 		DHD_INFO(("CLKCTL: turned ON\n"));
1167 
1168 #if defined(DHD_DEBUG)
1169 		if (bus->alp_only == TRUE) {
1170 #if !defined(BCMLXSDMMC)
1171 			if (!SBSDIO_ALPONLY(clkctl)) {
1172 				DHD_ERROR(("%s: HT Clock, when ALP Only\n", __FUNCTION__));
1173 			}
1174 #endif /* !defined(BCMLXSDMMC) */
1175 		} else {
1176 			if (SBSDIO_ALPONLY(clkctl)) {
1177 				DHD_ERROR(("%s: HT Clock should be on.\n", __FUNCTION__));
1178 			}
1179 		}
1180 #endif /* defined (DHD_DEBUG) */
1181 
1182 		bus->activity = TRUE;
1183 #ifdef DHD_USE_IDLECOUNT
1184 		bus->idlecount = 0;
1185 #endif /* DHD_USE_IDLECOUNT */
1186 	} else {
1187 		clkreq = 0;
1188 
1189 		if (bus->clkstate == CLK_PENDING) {
1190 			/* Cancel CA-only interrupt filter */
1191 			devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
1192 			devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
1193 			bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
1194 		}
1195 
1196 		bus->clkstate = CLK_SDONLY;
1197 		if (!SR_ENAB(bus)) {
1198 			bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
1199 			DHD_INFO(("CLKCTL: turned OFF\n"));
1200 			if (err) {
1201 				DHD_ERROR(("%s: Failed access turning clock off: %d\n",
1202 				           __FUNCTION__, err));
1203 				return BCME_ERROR;
1204 			}
1205 		}
1206 	}
1207 	return BCME_OK;
1208 }
1209 
1210 /* Change idle/active SD state */
1211 static int
dhdsdio_sdclk(dhd_bus_t * bus,bool on)1212 dhdsdio_sdclk(dhd_bus_t *bus, bool on)
1213 {
1214 	int err;
1215 	int32 iovalue;
1216 
1217 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1218 
1219 	if (on) {
1220 		if (bus->idleclock == DHD_IDLE_STOP) {
1221 			/* Turn on clock and restore mode */
1222 			iovalue = 1;
1223 			err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0,
1224 			                      &iovalue, sizeof(iovalue), TRUE);
1225 			if (err) {
1226 				DHD_ERROR(("%s: error enabling sd_clock: %d\n",
1227 				           __FUNCTION__, err));
1228 				return BCME_ERROR;
1229 			}
1230 
1231 			iovalue = bus->sd_mode;
1232 			err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
1233 			                      &iovalue, sizeof(iovalue), TRUE);
1234 			if (err) {
1235 				DHD_ERROR(("%s: error changing sd_mode: %d\n",
1236 				           __FUNCTION__, err));
1237 				return BCME_ERROR;
1238 			}
1239 		} else if (bus->idleclock != DHD_IDLE_ACTIVE) {
1240 			/* Restore clock speed */
1241 			iovalue = bus->sd_divisor;
1242 			err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
1243 			                      &iovalue, sizeof(iovalue), TRUE);
1244 			if (err) {
1245 				DHD_ERROR(("%s: error restoring sd_divisor: %d\n",
1246 				           __FUNCTION__, err));
1247 				return BCME_ERROR;
1248 			}
1249 		}
1250 		bus->clkstate = CLK_SDONLY;
1251 	} else {
1252 		/* Stop or slow the SD clock itself */
1253 		if ((bus->sd_divisor == -1) || (bus->sd_mode == -1)) {
1254 			DHD_TRACE(("%s: can't idle clock, divisor %d mode %d\n",
1255 			           __FUNCTION__, bus->sd_divisor, bus->sd_mode));
1256 			return BCME_ERROR;
1257 		}
1258 		if (bus->idleclock == DHD_IDLE_STOP) {
1259 			if (sd1idle) {
1260 				/* Change to SD1 mode and turn off clock */
1261 				iovalue = 1;
1262 				err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
1263 				                      &iovalue, sizeof(iovalue), TRUE);
1264 				if (err) {
1265 					DHD_ERROR(("%s: error changing sd_clock: %d\n",
1266 					           __FUNCTION__, err));
1267 					return BCME_ERROR;
1268 				}
1269 			}
1270 
1271 			iovalue = 0;
1272 			err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0,
1273 			                      &iovalue, sizeof(iovalue), TRUE);
1274 			if (err) {
1275 				DHD_ERROR(("%s: error disabling sd_clock: %d\n",
1276 				           __FUNCTION__, err));
1277 				return BCME_ERROR;
1278 			}
1279 		} else if (bus->idleclock != DHD_IDLE_ACTIVE) {
1280 			/* Set divisor to idle value */
1281 			iovalue = bus->idleclock;
1282 			err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
1283 			                      &iovalue, sizeof(iovalue), TRUE);
1284 			if (err) {
1285 				DHD_ERROR(("%s: error changing sd_divisor: %d\n",
1286 				           __FUNCTION__, err));
1287 				return BCME_ERROR;
1288 			}
1289 		}
1290 		bus->clkstate = CLK_NONE;
1291 	}
1292 
1293 	return BCME_OK;
1294 }
1295 
1296 /* Transition SD and backplane clock readiness */
1297 static int
dhdsdio_clkctl(dhd_bus_t * bus,uint target,bool pendok)1298 dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok)
1299 {
1300 	int ret = BCME_OK;
1301 #ifdef DHD_DEBUG
1302 	uint oldstate = bus->clkstate;
1303 #endif /* DHD_DEBUG */
1304 
1305 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1306 
1307 	/* Early exit if we're already there */
1308 	if (bus->clkstate == target) {
1309 		if (target == CLK_AVAIL) {
1310 			dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
1311 			bus->activity = TRUE;
1312 #ifdef DHD_USE_IDLECOUNT
1313 			bus->idlecount = 0;
1314 #endif /* DHD_USE_IDLECOUNT */
1315 		}
1316 		return ret;
1317 	}
1318 
1319 	switch (target) {
1320 	case CLK_AVAIL:
1321 		/* Make sure SD clock is available */
1322 		if (bus->clkstate == CLK_NONE)
1323 			dhdsdio_sdclk(bus, TRUE);
1324 		/* Now request HT Avail on the backplane */
1325 		ret = dhdsdio_htclk(bus, TRUE, pendok);
1326 		if (ret == BCME_OK) {
1327 			dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
1328 		bus->activity = TRUE;
1329 #ifdef DHD_USE_IDLECOUNT
1330 			bus->idlecount = 0;
1331 #endif /* DHD_USE_IDLECOUNT */
1332 		}
1333 		break;
1334 
1335 	case CLK_SDONLY:
1336 		/* Remove HT request, or bring up SD clock */
1337 		if (bus->clkstate == CLK_NONE)
1338 			ret = dhdsdio_sdclk(bus, TRUE);
1339 		else if (bus->clkstate == CLK_AVAIL)
1340 			ret = dhdsdio_htclk(bus, FALSE, FALSE);
1341 		else
1342 			DHD_ERROR(("dhdsdio_clkctl: request for %d -> %d\n",
1343 			           bus->clkstate, target));
1344 		if (ret == BCME_OK) {
1345 			dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
1346 		}
1347 		break;
1348 
1349 	case CLK_NONE:
1350 		/* Make sure to remove HT request */
1351 		if (bus->clkstate == CLK_AVAIL)
1352 			ret = dhdsdio_htclk(bus, FALSE, FALSE);
1353 		/* Now remove the SD clock */
1354 		ret = dhdsdio_sdclk(bus, FALSE);
1355 #ifdef DHD_DEBUG
1356 		if (dhd_console_ms == 0)
1357 #endif /* DHD_DEBUG */
1358 		if (bus->poll == 0)
1359 			dhd_os_wd_timer(bus->dhd, 0);
1360 		break;
1361 	}
1362 #ifdef DHD_DEBUG
1363 	DHD_INFO(("dhdsdio_clkctl: %d -> %d\n", oldstate, bus->clkstate));
1364 #endif /* DHD_DEBUG */
1365 
1366 	return ret;
1367 }
1368 
1369 static int
dhdsdio_bussleep(dhd_bus_t * bus,bool sleep)1370 dhdsdio_bussleep(dhd_bus_t *bus, bool sleep)
1371 {
1372 	int err = 0;
1373 	bcmsdh_info_t *sdh = bus->sdh;
1374 	sdpcmd_regs_t *regs = bus->regs;
1375 	uint retries = 0;
1376 
1377 	DHD_INFO(("dhdsdio_bussleep: request %s (currently %s)\n",
1378 	          (sleep ? "SLEEP" : "WAKE"),
1379 	          (bus->sleeping ? "SLEEP" : "WAKE")));
1380 
1381 	/* Done if we're already in the requested state */
1382 	if (sleep == bus->sleeping)
1383 		return BCME_OK;
1384 
1385 	/* Going to sleep: set the alarm and turn off the lights... */
1386 	if (sleep) {
1387 		/* Don't sleep if something is pending */
1388 		if (bus->dpc_sched || bus->rxskip || pktq_len(&bus->txq))
1389 			return BCME_BUSY;
1390 
1391 
1392 		if (!SLPAUTO_ENAB(bus)) {
1393 			/* Disable SDIO interrupts (no longer interested) */
1394 			bcmsdh_intr_disable(bus->sdh);
1395 
1396 			/* Make sure the controller has the bus up */
1397 			dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
1398 
1399 			/* Tell device to start using OOB wakeup */
1400 			W_SDREG(SMB_USE_OOB, &regs->tosbmailbox, retries);
1401 			if (retries > retry_limit)
1402 				DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
1403 
1404 			/* Turn off our contribution to the HT clock request */
1405 			dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
1406 
1407 			bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
1408 				SBSDIO_FORCE_HW_CLKREQ_OFF, NULL);
1409 
1410 			/* Isolate the bus */
1411 			if (bus->sih->chip != BCM4329_CHIP_ID &&
1412 				bus->sih->chip != BCM4319_CHIP_ID) {
1413 				bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL,
1414 					SBSDIO_DEVCTL_PADS_ISO, NULL);
1415 			}
1416 		} else {
1417 			/* Leave interrupts enabled since device can exit sleep and
1418 			 * interrupt host
1419 			 */
1420 			err = dhdsdio_clk_devsleep_iovar(bus, TRUE /* sleep */);
1421 		}
1422 
1423 		/* Change state */
1424 		bus->sleeping = TRUE;
1425 
1426 	} else {
1427 		/* Waking up: bus power up is ok, set local state */
1428 
1429 		if (!SLPAUTO_ENAB(bus)) {
1430 			bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0, &err);
1431 
1432 			/* Force pad isolation off if possible (in case power never toggled) */
1433 			bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, 0, NULL);
1434 
1435 
1436 			/* Make sure the controller has the bus up */
1437 			dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
1438 
1439 			/* Send misc interrupt to indicate OOB not needed */
1440 			W_SDREG(0, &regs->tosbmailboxdata, retries);
1441 			if (retries <= retry_limit)
1442 				W_SDREG(SMB_DEV_INT, &regs->tosbmailbox, retries);
1443 
1444 			if (retries > retry_limit)
1445 				DHD_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n"));
1446 
1447 			/* Make sure we have SD bus access */
1448 			dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
1449 
1450 			/* Enable interrupts again */
1451 			if (bus->intr && (bus->dhd->busstate == DHD_BUS_DATA)) {
1452 				bus->intdis = FALSE;
1453 				bcmsdh_intr_enable(bus->sdh);
1454 			}
1455 		} else {
1456 			err = dhdsdio_clk_devsleep_iovar(bus, FALSE /* wake */);
1457 		}
1458 
1459 		if (err == 0) {
1460 			/* Change state */
1461 			bus->sleeping = FALSE;
1462 		}
1463 	}
1464 
1465 	return err;
1466 }
1467 
1468 
1469 #if defined(OOB_INTR_ONLY)
1470 void
dhd_enable_oob_intr(struct dhd_bus * bus,bool enable)1471 dhd_enable_oob_intr(struct dhd_bus *bus, bool enable)
1472 {
1473 #if defined(HW_OOB)
1474 	bcmsdh_enable_hw_oob_intr(bus->sdh, enable);
1475 #else
1476 	sdpcmd_regs_t *regs = bus->regs;
1477 	uint retries = 0;
1478 
1479 	dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
1480 	if (enable == TRUE) {
1481 
1482 		/* Tell device to start using OOB wakeup */
1483 		W_SDREG(SMB_USE_OOB, &regs->tosbmailbox, retries);
1484 		if (retries > retry_limit)
1485 			DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
1486 
1487 	} else {
1488 		/* Send misc interrupt to indicate OOB not needed */
1489 		W_SDREG(0, &regs->tosbmailboxdata, retries);
1490 		if (retries <= retry_limit)
1491 			W_SDREG(SMB_DEV_INT, &regs->tosbmailbox, retries);
1492 	}
1493 
1494 	/* Turn off our contribution to the HT clock request */
1495 	dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
1496 #endif /* !defined(HW_OOB) */
1497 }
1498 #endif
1499 
1500 #ifdef DHDTCPACK_SUPPRESS
1501 extern bool dhd_use_tcpack_suppress;
1502 
1503 /* Please be sure this function is called under dhd_os_tcpacklock() */
dhd_onoff_tcpack_sup(void * pub,bool on)1504 void dhd_onoff_tcpack_sup(void *pub, bool on)
1505 {
1506 	dhd_pub_t *dhdp = (dhd_pub_t *)pub;
1507 
1508 	if (dhd_use_tcpack_suppress != on) {
1509 
1510 		DHD_ERROR(("dhd_onoff_tcpack_sup: %d -> %d\n", dhd_use_tcpack_suppress, on));
1511 		dhd_use_tcpack_suppress = on;
1512 		dhdp->tcp_ack_info_cnt = 0;
1513 		bzero(dhdp->tcp_ack_info_tbl, sizeof(struct tcp_ack_info)*MAXTCPSTREAMS);
1514 
1515 	} else
1516 		DHD_ERROR(("dhd_onoff_tcpack_sup: alread %d\n", on));
1517 
1518 	return;
1519 }
1520 
dhd_tcpack_check_xmit(dhd_pub_t * dhdp,void * pkt)1521 inline void dhd_tcpack_check_xmit(dhd_pub_t *dhdp, void *pkt)
1522 {
1523 	uint8 i;
1524 	tcp_ack_info_t *tcp_ack_info = NULL;
1525 	int tbl_cnt;
1526 
1527 	dhd_os_tcpacklock(dhdp);
1528 	tbl_cnt = dhdp->tcp_ack_info_cnt;
1529 	for (i = 0; i < tbl_cnt; i++) {
1530 		tcp_ack_info = &dhdp->tcp_ack_info_tbl[i];
1531 		if (tcp_ack_info->p_tcpackinqueue == pkt) {
1532 			/* This pkt is being transmitted so remove the tcp_ack_info of it.
1533 			* compact the array unless the last element,
1534 			* then the pkt's array is removed.
1535 			*/
1536 			if (i < tbl_cnt-1) {
1537 				memmove(&dhdp->tcp_ack_info_tbl[i],
1538 					&dhdp->tcp_ack_info_tbl[i+1],
1539 					sizeof(struct tcp_ack_info)*(tbl_cnt - (i+1)));
1540 			}
1541 			bzero(&dhdp->tcp_ack_info_tbl[tbl_cnt-1], sizeof(struct tcp_ack_info));
1542 			if (--dhdp->tcp_ack_info_cnt < 0) {
1543 				DHD_ERROR(("dhdsdio_sendfromq:(ERROR) tcp_ack_info_cnt %d"
1544 				" Stop using tcpack_suppress\n", dhdp->tcp_ack_info_cnt));
1545 				dhd_onoff_tcpack_sup(dhdp, FALSE);
1546 			}
1547 			break;
1548 		}
1549 	}
1550 	dhd_os_tcpackunlock(dhdp);
1551 }
1552 
1553 bool
dhd_tcpack_suppress(dhd_pub_t * dhdp,void * pkt)1554 dhd_tcpack_suppress(dhd_pub_t *dhdp, void *pkt)
1555 {
1556 	uint8 *eh_header;
1557 	uint16 eh_type;
1558 	uint8 *ip_header;
1559 	uint8 *tcp_header;
1560 	uint32 ip_hdr_len;
1561 	uint32 cur_framelen;
1562 	uint8 bdc_hdr_len = BDC_HEADER_LEN;
1563 	uint8 wlfc_hdr_len = 0;
1564 	uint8 *data = PKTDATA(dhdp->osh, pkt);
1565 	cur_framelen = PKTLEN(dhdp->osh, pkt);
1566 
1567 #ifdef PROP_TXSTATUS
1568 	/* In this case, BDC header is not pushed in dhd_sendpkt() */
1569 	if (dhdp->wlfc_state) {
1570 		bdc_hdr_len = 0;
1571 		wlfc_hdr_len = 8;
1572 	}
1573 #endif
1574 	if (cur_framelen < bdc_hdr_len + ETHER_HDR_LEN) {
1575 		DHD_TRACE(("dhd_tcpack_suppress: Too short packet length %d\n", cur_framelen));
1576 		return FALSE;
1577 	}
1578 
1579 	/* Get rid of BDC header */
1580 	eh_header = data + bdc_hdr_len;
1581 	cur_framelen -= bdc_hdr_len;
1582 	eh_type = eh_header[12] << 8 | eh_header[13];
1583 
1584 	if (eh_type != ETHER_TYPE_IP) {
1585 		DHD_TRACE(("dhd_tcpack_suppress: Not a IP packet 0x%x\n", eh_type));
1586 		return FALSE;
1587 	}
1588 
1589 	DHD_TRACE(("dhd_tcpack_suppress: IP pkt! 0x%x\n", eh_type));
1590 
1591 	ip_header = eh_header + ETHER_HDR_LEN;
1592 	cur_framelen -= ETHER_HDR_LEN;
1593 	ip_hdr_len = 4 * (ip_header[0] & 0x0f);
1594 
1595 	if ((ip_header[0] & 0xf0) != 0x40) {
1596 		DHD_TRACE(("dhd_tcpack_suppress: Not IPv4!\n"));
1597 		return FALSE;
1598 	}
1599 
1600 	if (cur_framelen < ip_hdr_len) {
1601 		DHD_ERROR(("dhd_tcpack_suppress: IP packet length %d wrong!\n", cur_framelen));
1602 		return FALSE;
1603 	}
1604 
1605 	/* not tcp */
1606 	if (ip_header[9] != 0x06) {
1607 		DHD_TRACE(("dhd_tcpack_suppress: Not a TCP packet 0x%x\n", ip_header[9]));
1608 		return FALSE;
1609 	}
1610 
1611 	DHD_TRACE(("dhd_tcpack_suppress: TCP pkt!\n"));
1612 
1613 	tcp_header = ip_header + ip_hdr_len;
1614 
1615 	/* is it an ack ? */
1616 	if (tcp_header[13] == 0x10) {
1617 #if defined(DHD_DEBUG)
1618 		uint32 tcp_seq_num = tcp_header[4] << 24 | tcp_header[5] << 16 |
1619 			tcp_header[6] << 8 | tcp_header[7];
1620 #endif
1621 		uint32 tcp_ack_num = tcp_header[8] << 24 | tcp_header[9] << 16 |
1622 			tcp_header[10] << 8 | tcp_header[11];
1623 		uint16 ip_tcp_ttllen =  (ip_header[3] & 0xff) + (ip_header[2] << 8);
1624 		uint32 tcp_hdr_len = 4*((tcp_header[12] & 0xf0) >> 4);
1625 		DHD_TRACE(("dhd_tcpack_suppress: TCP ACK seq %ud ack %ud\n",
1626 			tcp_seq_num, tcp_ack_num));
1627 
1628 
1629 		/* zero length ? */
1630 		if (ip_tcp_ttllen ==  ip_hdr_len + tcp_hdr_len) {
1631 			int i;
1632 			tcp_ack_info_t *tcp_ack_info = NULL;
1633 			DHD_TRACE(("dhd_tcpack_suppress: TCP ACK zero length\n"));
1634 			/* Look for tcp_ack_info that has the same
1635 			* ip src/dst addrs and tcp src/dst ports
1636 			*/
1637 			dhd_os_tcpacklock(dhdp);
1638 			for (i = 0; i < dhdp->tcp_ack_info_cnt; i++) {
1639 				if (dhdp->tcp_ack_info_tbl[i].p_tcpackinqueue &&
1640 				!memcmp(&ip_header[12], dhdp->tcp_ack_info_tbl[i].ipaddrs, 8) &&
1641 				!memcmp(tcp_header, dhdp->tcp_ack_info_tbl[i].tcpports, 4)) {
1642 					tcp_ack_info = &dhdp->tcp_ack_info_tbl[i];
1643 					break;
1644 				}
1645 			}
1646 
1647 			if (i == dhdp->tcp_ack_info_cnt && i < MAXTCPSTREAMS)
1648 				tcp_ack_info = &dhdp->tcp_ack_info_tbl[dhdp->tcp_ack_info_cnt++];
1649 
1650 			if (!tcp_ack_info) {
1651 				DHD_TRACE(("dhd_tcpack_suppress: No empty tcp ack info"
1652 					"%d %d %d %d, %d %d %d %d\n",
1653 					tcp_header[0], tcp_header[1], tcp_header[2], tcp_header[3],
1654 					dhdp->tcp_ack_info_tbl[i].tcpports[0],
1655 					dhdp->tcp_ack_info_tbl[i].tcpports[1],
1656 					dhdp->tcp_ack_info_tbl[i].tcpports[2],
1657 					dhdp->tcp_ack_info_tbl[i].tcpports[3]));
1658 				dhd_os_tcpackunlock(dhdp);
1659 				return FALSE;
1660 			}
1661 
1662 			if (tcp_ack_info->p_tcpackinqueue) {
1663 				if (tcp_ack_num > tcp_ack_info->tcpack_number) {
1664 					void *prevpkt = tcp_ack_info->p_tcpackinqueue;
1665 					uint8 pushed_len = SDPCM_HDRLEN +
1666 						(BDC_HEADER_LEN - bdc_hdr_len) + wlfc_hdr_len;
1667 #ifdef PROP_TXSTATUS
1668 					/* In case the prev pkt is delayenqueued
1669 					* but not delayedequeued yet, it may not have
1670 					* any additional header yet.
1671 					*/
1672 					if (dhdp->wlfc_state &&	(PKTLEN(dhdp->osh, prevpkt) ==
1673 						tcp_ack_info->ip_tcp_ttllen + ETHER_HDR_LEN))
1674 						pushed_len = 0;
1675 #endif
1676 					if ((ip_tcp_ttllen == tcp_ack_info->ip_tcp_ttllen) &&
1677 						(PKTLEN(dhdp->osh, pkt) ==
1678 						PKTLEN(dhdp->osh, prevpkt) - pushed_len)) {
1679 						bcopy(PKTDATA(dhdp->osh, pkt),
1680 							PKTDATA(dhdp->osh, prevpkt) + pushed_len,
1681 							PKTLEN(dhdp->osh, pkt));
1682 						PKTFREE(dhdp->osh, pkt, FALSE);
1683 						DHD_TRACE(("dhd_tcpack_suppress: pkt 0x%p"
1684 							" TCP ACK replace %ud -> %ud\n", prevpkt,
1685 							tcp_ack_info->tcpack_number, tcp_ack_num));
1686 						tcp_ack_info->tcpack_number = tcp_ack_num;
1687 						dhd_os_tcpackunlock(dhdp);
1688 						return TRUE;
1689 					} else
1690 						DHD_TRACE(("dhd_tcpack_suppress: len mismatch"
1691 							" %d(%d) %d(%d)\n",
1692 							PKTLEN(dhdp->osh, pkt), ip_tcp_ttllen,
1693 							PKTLEN(dhdp->osh, prevpkt),
1694 							tcp_ack_info->ip_tcp_ttllen));
1695 				} else {
1696 #ifdef TCPACK_TEST
1697 					void *prevpkt = tcp_ack_info->p_tcpackinqueue;
1698 #endif
1699 					DHD_TRACE(("dhd_tcpack_suppress: TCP ACK number reverse"
1700 							" prev %ud (0x%p) new %ud (0x%p)\n",
1701 							tcp_ack_info->tcpack_number,
1702 							tcp_ack_info->p_tcpackinqueue,
1703 							tcp_ack_num, pkt));
1704 #ifdef TCPACK_TEST
1705 					if (PKTLEN(dhdp->osh, pkt) == PKTLEN(dhdp->osh, prevpkt)) {
1706 						PKTFREE(dhdp->osh, pkt, FALSE);
1707 						dhd_os_tcpackunlock(dhdp);
1708 						return TRUE;
1709 					}
1710 #endif
1711 				}
1712 			} else {
1713 				tcp_ack_info->p_tcpackinqueue = pkt;
1714 				tcp_ack_info->tcpack_number = tcp_ack_num;
1715 				tcp_ack_info->ip_tcp_ttllen = ip_tcp_ttllen;
1716 				bcopy(&ip_header[12], tcp_ack_info->ipaddrs, 8);
1717 				bcopy(tcp_header, tcp_ack_info->tcpports, 4);
1718 			}
1719 			dhd_os_tcpackunlock(dhdp);
1720 		} else
1721 			DHD_TRACE(("dhd_tcpack_suppress: TCP ACK with DATA len %d\n",
1722 				ip_tcp_ttllen - ip_hdr_len - tcp_hdr_len));
1723 	}
1724 	return FALSE;
1725 }
1726 #endif /* DHDTCPACK_SUPPRESS */
1727 
1728 /* Writes a HW/SW header into the packet and sends it. */
1729 /* Assumes: (a) header space already there, (b) caller holds lock */
1730 static int
dhdsdio_txpkt(dhd_bus_t * bus,void * pkt,uint chan,bool free_pkt,bool queue_only)1731 dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt, bool queue_only)
1732 {
1733 	int ret;
1734 	osl_t *osh;
1735 	uint8 *frame;
1736 	uint16 len, pad1 = 0, act_len = 0;
1737 	uint32 swheader;
1738 	uint retries = 0;
1739 	uint32 real_pad = 0;
1740 	bcmsdh_info_t *sdh;
1741 	void *new;
1742 	int i;
1743 	int pkt_cnt;
1744 #ifdef BCMSDIOH_TXGLOM
1745 	uint8 *frame_tmp;
1746 #endif
1747 #ifdef WLMEDIA_HTSF
1748 	char *p;
1749 	htsfts_t *htsf_ts;
1750 #endif
1751 
1752 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1753 
1754 	sdh = bus->sdh;
1755 	osh = bus->dhd->osh;
1756 
1757 #ifdef DHDTCPACK_SUPPRESS
1758 	if (dhd_use_tcpack_suppress) {
1759 		dhd_tcpack_check_xmit(bus->dhd, pkt);
1760 	}
1761 #endif /* DHDTCPACK_SUPPRESS */
1762 
1763 	if (bus->dhd->dongle_reset) {
1764 		ret = BCME_NOTREADY;
1765 		goto done;
1766 	}
1767 
1768 	frame = (uint8*)PKTDATA(osh, pkt);
1769 
1770 #ifdef WLMEDIA_HTSF
1771 	if (PKTLEN(osh, pkt) >= 100) {
1772 		p = PKTDATA(osh, pkt);
1773 		htsf_ts = (htsfts_t*) (p + HTSF_HOSTOFFSET + 12);
1774 		if (htsf_ts->magic == HTSFMAGIC) {
1775 			htsf_ts->c20 = get_cycles();
1776 			htsf_ts->t20 = dhd_get_htsf(bus->dhd->info, 0);
1777 		}
1778 	}
1779 #endif /* WLMEDIA_HTSF */
1780 
1781 	/* Add alignment padding, allocate new packet if needed */
1782 	if ((pad1 = ((uintptr)frame % DHD_SDALIGN))) {
1783 		if (PKTHEADROOM(osh, pkt) < pad1) {
1784 			DHD_INFO(("%s: insufficient headroom %d for %d pad1\n",
1785 			          __FUNCTION__, (int)PKTHEADROOM(osh, pkt), pad1));
1786 			bus->dhd->tx_realloc++;
1787 			new = PKTGET(osh, (PKTLEN(osh, pkt) + DHD_SDALIGN), TRUE);
1788 			if (!new) {
1789 				DHD_ERROR(("%s: couldn't allocate new %d-byte packet\n",
1790 				           __FUNCTION__, PKTLEN(osh, pkt) + DHD_SDALIGN));
1791 				ret = BCME_NOMEM;
1792 				goto done;
1793 			}
1794 
1795 			PKTALIGN(osh, new, PKTLEN(osh, pkt), DHD_SDALIGN);
1796 			bcopy(PKTDATA(osh, pkt), PKTDATA(osh, new), PKTLEN(osh, pkt));
1797 			if (free_pkt)
1798 				PKTFREE(osh, pkt, TRUE);
1799 			/* free the pkt if canned one is not used */
1800 			free_pkt = TRUE;
1801 			pkt = new;
1802 			frame = (uint8*)PKTDATA(osh, pkt);
1803 			ASSERT(((uintptr)frame % DHD_SDALIGN) == 0);
1804 			pad1 = 0;
1805 		} else {
1806 			PKTPUSH(osh, pkt, pad1);
1807 			frame = (uint8*)PKTDATA(osh, pkt);
1808 
1809 			ASSERT((pad1 + SDPCM_HDRLEN) <= (int) PKTLEN(osh, pkt));
1810 			bzero(frame, pad1 + SDPCM_HDRLEN);
1811 		}
1812 	}
1813 	ASSERT(pad1 < DHD_SDALIGN);
1814 
1815 	/* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
1816 	len = (uint16)PKTLEN(osh, pkt);
1817 	*(uint16*)frame = htol16(len);
1818 	*(((uint16*)frame) + 1) = htol16(~len);
1819 
1820 #ifdef BCMSDIOH_TXGLOM
1821 	if (bus->glom_enable) {
1822 		uint32 hwheader1 = 0, hwheader2 = 0;
1823 		act_len = len;
1824 
1825 		/* Software tag: channel, sequence number, data offset */
1826 		swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) |
1827 			((bus->tx_seq + bus->glom_cnt) % SDPCM_SEQUENCE_WRAP) |
1828 		        (((pad1 + SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
1829 		htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN);
1830 		htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN + sizeof(swheader));
1831 
1832 		if (queue_only) {
1833 			uint8 alignment = ALIGNMENT;
1834 			if (forcealign && (len & (alignment - 1)))
1835 				len = ROUNDUP(len, alignment);
1836 			/* Hardware extention tag */
1837 			/* 2byte frame length, 1byte-, 1byte frame flag,
1838 			 * 2byte-hdrlength, 2byte padlenght
1839 			 */
1840 			hwheader1 = (act_len - SDPCM_FRAMETAG_LEN) | (0 << 24);
1841 			hwheader2 = (len - act_len) << 16;
1842 			htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN);
1843 			htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4);
1844 			real_pad = len - act_len;
1845 			if (PKTTAILROOM(osh, pkt) < real_pad) {
1846 				DHD_INFO(("%s 1: insufficient tailroom %d for %d real_pad\n",
1847 				__FUNCTION__, (int)PKTTAILROOM(osh, pkt), real_pad));
1848 				if (PKTPADTAILROOM(osh, pkt, real_pad)) {
1849 					DHD_ERROR(("CHK1: padding error size %d\n", real_pad));
1850 					ret = BCME_NOMEM;
1851 					goto done;
1852 				}
1853 #ifndef BCMLXSDMMC
1854 				else
1855 					PKTSETLEN(osh, pkt, act_len);
1856 #endif
1857 			}
1858 #ifdef BCMLXSDMMC
1859 			PKTSETLEN(osh, pkt, len);
1860 #endif /* BCMLXSDMMC */
1861 			/* Post the frame pointer to sdio glom array */
1862 			dhd_bcmsdh_glom_post(bus, frame, pkt, len);
1863 			/* Save the pkt pointer in bus glom array */
1864 			bus->glom_pkt_arr[bus->glom_cnt] = pkt;
1865 			bus->glom_total_len += len;
1866 			bus->glom_cnt++;
1867 			return BCME_OK;
1868 		} else {
1869 				/* Raise len to next SDIO block to eliminate tail command */
1870 				if (bus->roundup && bus->blocksize &&
1871 					((bus->glom_total_len + len) > bus->blocksize)) {
1872 					uint16 pad2 = bus->blocksize -
1873 						((bus->glom_total_len + len) % bus->blocksize);
1874 					if ((pad2 <= bus->roundup) && (pad2 < bus->blocksize)) {
1875 							len += pad2;
1876 					} else {
1877 					}
1878 				} else if ((bus->glom_total_len + len) % DHD_SDALIGN) {
1879 					len += DHD_SDALIGN
1880 					    - ((bus->glom_total_len + len) % DHD_SDALIGN);
1881 				}
1882 				if (forcealign && (len & (ALIGNMENT - 1))) {
1883 					len = ROUNDUP(len, ALIGNMENT);
1884 				}
1885 
1886 				/* Hardware extention tag */
1887 				/* 2byte frame length, 1byte-, 1byte frame flag,
1888 				 * 2byte-hdrlength, 2byte padlenght
1889 				 */
1890 				hwheader1 = (act_len - SDPCM_FRAMETAG_LEN) | (1 << 24);
1891 				hwheader2 = (len - act_len) << 16;
1892 				htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN);
1893 				htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4);
1894 				real_pad = len - act_len;
1895 				if (PKTTAILROOM(osh, pkt) < real_pad) {
1896 					DHD_INFO(("%s 2: insufficient tailroom %d"
1897 					" for %d real_pad\n",
1898 					__FUNCTION__, (int)PKTTAILROOM(osh, pkt), real_pad));
1899 					if (PKTPADTAILROOM(osh, pkt, real_pad)) {
1900 						DHD_ERROR(("CHK2: padding error size %d."
1901 							" %d more pkts are discarded together.\n",
1902 							real_pad, bus->glom_cnt));
1903 						/* Save the pkt pointer in bus glom array
1904 						* Otherwise, this last pkt will not be
1905 						* cleaned under "goto done"
1906 						*/
1907 						bus->glom_pkt_arr[bus->glom_cnt] = pkt;
1908 						bus->glom_cnt++;
1909 						bus->glom_total_len += len;
1910 						ret = BCME_NOMEM;
1911 						goto done;
1912 					}
1913 #ifndef BCMLXSDMMC
1914 					else
1915 						PKTSETLEN(osh, pkt, act_len);
1916 #endif
1917 				}
1918 #ifdef BCMLXSDMMC
1919 				PKTSETLEN(osh, pkt, len);
1920 #endif /* BCMLXSDMMC */
1921 
1922 				/* Post the frame pointer to sdio glom array */
1923 				dhd_bcmsdh_glom_post(bus, frame, pkt, len);
1924 				/* Save the pkt pointer in bus glom array */
1925 				bus->glom_pkt_arr[bus->glom_cnt] = pkt;
1926 				bus->glom_cnt++;
1927 				bus->glom_total_len += len;
1928 
1929 				/* Update the total length on the first pkt */
1930 				frame_tmp = (uint8*)PKTDATA(osh, bus->glom_pkt_arr[0]);
1931 				*(uint16*)frame_tmp = htol16(bus->glom_total_len);
1932 				*(((uint16*)frame_tmp) + 1) = htol16(~bus->glom_total_len);
1933 		}
1934 	} else
1935 #endif /* BCMSDIOH_TXGLOM */
1936 	{
1937 	act_len = len;
1938 	/* Software tag: channel, sequence number, data offset */
1939 	swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) | bus->tx_seq |
1940 	        (((pad1 + SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
1941 	htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN);
1942 	htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
1943 
1944 #ifdef DHD_DEBUG
1945 	if (PKTPRIO(pkt) < ARRAYSIZE(tx_packets)) {
1946 		tx_packets[PKTPRIO(pkt)]++;
1947 	}
1948 	if (DHD_BYTES_ON() &&
1949 	    (((DHD_CTL_ON() && (chan == SDPCM_CONTROL_CHANNEL)) ||
1950 	      (DHD_DATA_ON() && (chan != SDPCM_CONTROL_CHANNEL))))) {
1951 		prhex("Tx Frame", frame, len);
1952 	} else if (DHD_HDRS_ON()) {
1953 		prhex("TxHdr", frame, MIN(len, 16));
1954 	}
1955 #endif
1956 
1957 	/* Raise len to next SDIO block to eliminate tail command */
1958 	if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
1959 		uint16 pad2 = bus->blocksize - (len % bus->blocksize);
1960 		if ((pad2 <= bus->roundup) && (pad2 < bus->blocksize))
1961 #ifdef NOTUSED
1962 			if (pad2 <= PKTTAILROOM(osh, pkt))
1963 #endif /* NOTUSED */
1964 				len += pad2;
1965 	} else if (len % DHD_SDALIGN) {
1966 		len += DHD_SDALIGN - (len % DHD_SDALIGN);
1967 	}
1968 
1969 	/* Some controllers have trouble with odd bytes -- round to even */
1970 	if (forcealign && (len & (ALIGNMENT - 1))) {
1971 #ifdef NOTUSED
1972 		if (PKTTAILROOM(osh, pkt))
1973 #endif
1974 			len = ROUNDUP(len, ALIGNMENT);
1975 #ifdef NOTUSED
1976 		else
1977 			DHD_ERROR(("%s: sending unrounded %d-byte packet\n", __FUNCTION__, len));
1978 #endif
1979 	}
1980 	real_pad = len - act_len;
1981 	if (PKTTAILROOM(osh, pkt) < real_pad) {
1982 		DHD_INFO(("%s 3: insufficient tailroom %d for %d real_pad\n",
1983 		__FUNCTION__, (int)PKTTAILROOM(osh, pkt), real_pad));
1984 		if (PKTPADTAILROOM(osh, pkt, real_pad)) {
1985 			DHD_ERROR(("CHK3: padding error size %d\n", real_pad));
1986 			ret = BCME_NOMEM;
1987 			goto done;
1988 		}
1989 #ifndef BCMLXSDMMC
1990 		else
1991 			PKTSETLEN(osh, pkt, act_len);
1992 #endif
1993 	}
1994 #ifdef BCMLXSDMMC
1995 	PKTSETLEN(osh, pkt, len);
1996 #endif /* BCMLXSDMMC */
1997 	}
1998 	do {
1999 		ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
2000 		                          frame, len, pkt, NULL, NULL);
2001 		bus->f2txdata++;
2002 		ASSERT(ret != BCME_PENDING);
2003 
2004 		if (ret == BCME_NODEVICE) {
2005 			DHD_ERROR(("%s: Device asleep already\n", __FUNCTION__));
2006 		} else if (ret < 0) {
2007 			/* On failure, abort the command and terminate the frame */
2008 			DHD_ERROR(("%s: sdio error %d, abort command and terminate frame.\n",
2009 			          __FUNCTION__, ret));
2010 			bus->tx_sderrs++;
2011 
2012 			bcmsdh_abort(sdh, SDIO_FUNC_2);
2013 			bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
2014 			                 SFC_WF_TERM, NULL);
2015 			bus->f1regdata++;
2016 
2017 			for (i = 0; i < 3; i++) {
2018 				uint8 hi, lo;
2019 				hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
2020 				                     SBSDIO_FUNC1_WFRAMEBCHI, NULL);
2021 				lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
2022 				                     SBSDIO_FUNC1_WFRAMEBCLO, NULL);
2023 				bus->f1regdata += 2;
2024 				if ((hi == 0) && (lo == 0))
2025 					break;
2026 			}
2027 		}
2028 		if (ret == 0) {
2029 #ifdef BCMSDIOH_TXGLOM
2030 			if (bus->glom_enable) {
2031 				bus->tx_seq = (bus->tx_seq + bus->glom_cnt) % SDPCM_SEQUENCE_WRAP;
2032 			} else
2033 #endif
2034 			{
2035 			bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
2036 		}
2037 		}
2038 	} while ((ret < 0) && retrydata && retries++ < TXRETRIES);
2039 
2040 done:
2041 
2042 #ifdef BCMSDIOH_TXGLOM
2043 	if (bus->glom_enable && !queue_only) {
2044 		dhd_bcmsdh_glom_clear(bus);
2045 		pkt_cnt = bus->glom_cnt;
2046 	} else
2047 #endif
2048 	{
2049 		pkt_cnt = 1;
2050 	}
2051 		/* restore pkt buffer pointer before calling tx complete routine */
2052 	while (pkt_cnt) {
2053 #ifdef BCMSDIOH_TXGLOM
2054 		uint32 doff;
2055 		if (bus->glom_enable) {
2056 #ifdef BCMLXSDMMC
2057 			uint32 pad2 = 0;
2058 #endif /* BCMLXSDMMC */
2059 			if (!queue_only)
2060 				pkt = bus->glom_pkt_arr[bus->glom_cnt - pkt_cnt];
2061 
2062 			frame = (uint8*)PKTDATA(osh, pkt);
2063 			doff = ltoh32_ua(frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN);
2064 			doff = (doff & SDPCM_DOFFSET_MASK) >> SDPCM_DOFFSET_SHIFT;
2065 #ifdef BCMLXSDMMC
2066 			pad2 = ltoh32_ua(frame + SDPCM_FRAMETAG_LEN + 4) >> 16;
2067 			PKTSETLEN(osh, pkt, PKTLEN(osh, pkt) - pad2);
2068 #endif /* BCMLXSDMMC */
2069 			PKTPULL(osh, pkt, doff);
2070 		} else
2071 #endif /* BCMSDIOH_TXGLOM */
2072 		{
2073 #ifdef BCMLXSDMMC
2074 			if (act_len > 0)
2075 				PKTSETLEN(osh, pkt, act_len);
2076 #endif /* BCMLXSDMMC */
2077 			PKTPULL(osh, pkt, SDPCM_HDRLEN + pad1);
2078 		}
2079 #ifdef PROP_TXSTATUS
2080 	if (bus->dhd->wlfc_state) {
2081 		dhd_os_sdunlock(bus->dhd);
2082 		dhd_wlfc_txcomplete(bus->dhd, pkt, ret == 0);
2083 		dhd_os_sdlock(bus->dhd);
2084 	} else {
2085 #endif /* PROP_TXSTATUS */
2086 #ifdef SDTEST
2087 	if (chan != SDPCM_TEST_CHANNEL) {
2088 		dhd_txcomplete(bus->dhd, pkt, ret != 0);
2089 	}
2090 #else /* SDTEST */
2091 	dhd_txcomplete(bus->dhd, pkt, ret != 0);
2092 #endif /* SDTEST */
2093 	if (free_pkt)
2094 		PKTFREE(osh, pkt, TRUE);
2095 
2096 #ifdef PROP_TXSTATUS
2097 	}
2098 #endif
2099 		pkt_cnt--;
2100 	}
2101 
2102 #ifdef BCMSDIOH_TXGLOM
2103 	/* Reset the glom array */
2104 	if (bus->glom_enable && !queue_only) {
2105 		bus->glom_cnt = 0;
2106 		bus->glom_total_len = 0;
2107 	}
2108 #endif
2109 	return ret;
2110 }
2111 
2112 int
dhd_bus_txdata(struct dhd_bus * bus,void * pkt)2113 dhd_bus_txdata(struct dhd_bus *bus, void *pkt)
2114 {
2115 	int ret = BCME_ERROR;
2116 	osl_t *osh;
2117 	uint datalen, prec;
2118 #ifdef DHD_TX_DUMP
2119 	uint8 *dump_data;
2120 	uint16 protocol;
2121 #ifdef DHD_TX_FULL_DUMP
2122 	int i;
2123 #endif /* DHD_TX_FULL_DUMP */
2124 #endif /* DHD_TX_DUMP */
2125 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2126 
2127 	osh = bus->dhd->osh;
2128 	datalen = PKTLEN(osh, pkt);
2129 
2130 #ifdef SDTEST
2131 	/* Push the test header if doing loopback */
2132 	if (bus->ext_loop) {
2133 		uint8* data;
2134 		PKTPUSH(osh, pkt, SDPCM_TEST_HDRLEN);
2135 		data = PKTDATA(osh, pkt);
2136 		*data++ = SDPCM_TEST_ECHOREQ;
2137 		*data++ = (uint8)bus->loopid++;
2138 		*data++ = (datalen >> 0);
2139 		*data++ = (datalen >> 8);
2140 		datalen += SDPCM_TEST_HDRLEN;
2141 	}
2142 #endif /* SDTEST */
2143 
2144 #ifdef DHD_TX_DUMP
2145 	dump_data = PKTDATA(osh, pkt);
2146 	dump_data += 4; /* skip 4 bytes header */
2147 	protocol = (dump_data[12] << 8) | dump_data[13];
2148 #ifdef DHD_TX_FULL_DUMP
2149 	DHD_ERROR(("TX DUMP\n"));
2150 
2151 	for (i = 0; i < (datalen - 4); i++) {
2152 		DHD_ERROR(("%02X ", dump_data[i]));
2153 		if ((i & 15) == 15)
2154 			printk("\n");
2155 	}
2156 	DHD_ERROR(("\n"));
2157 
2158 #endif /* DHD_TX_FULL_DUMP */
2159 	if (protocol == ETHER_TYPE_802_1X) {
2160 		DHD_ERROR(("ETHER_TYPE_802_1X: ver %d, type %d, replay %d\n",
2161 			dump_data[14], dump_data[15], dump_data[30]));
2162 	}
2163 #endif /* DHD_TX_DUMP */
2164 
2165 	/* Add space for the header */
2166 	PKTPUSH(osh, pkt, SDPCM_HDRLEN);
2167 	ASSERT(ISALIGNED((uintptr)PKTDATA(osh, pkt), 2));
2168 
2169 	prec = PRIO2PREC((PKTPRIO(pkt) & PRIOMASK));
2170 #ifndef DHDTHREAD
2171 	/* Lock: we're about to use shared data/code (and SDIO) */
2172 	dhd_os_sdlock(bus->dhd);
2173 #endif /* DHDTHREAD */
2174 
2175 	/* Check for existing queue, current flow-control, pending event, or pending clock */
2176 	if (dhd_deferred_tx || bus->fcstate || pktq_len(&bus->txq) || bus->dpc_sched ||
2177 	    (!DATAOK(bus)) || (bus->flowcontrol & NBITVAL(prec)) ||
2178 	    (bus->clkstate != CLK_AVAIL)) {
2179 		DHD_TRACE(("%s: deferring pktq len %d\n", __FUNCTION__,
2180 			pktq_len(&bus->txq)));
2181 		bus->fcqueued++;
2182 
2183 		/* Priority based enq */
2184 		dhd_os_sdlock_txq(bus->dhd);
2185 		if (dhd_prec_enq(bus->dhd, &bus->txq, pkt, prec) == FALSE) {
2186 			PKTPULL(osh, pkt, SDPCM_HDRLEN);
2187 #ifndef DHDTHREAD
2188 			/* Need to also release txqlock before releasing sdlock.
2189 			 * This thread still has txqlock and releases sdlock.
2190 			 * Deadlock happens when dpc() grabs sdlock first then
2191 			 * attempts to grab txqlock.
2192 			 */
2193 			dhd_os_sdunlock_txq(bus->dhd);
2194 			dhd_os_sdunlock(bus->dhd);
2195 #endif
2196 #ifdef PROP_TXSTATUS
2197 			if (bus->dhd->wlfc_state)
2198 				dhd_wlfc_txcomplete(bus->dhd, pkt, FALSE);
2199 			else
2200 #endif
2201 			dhd_txcomplete(bus->dhd, pkt, FALSE);
2202 #ifndef DHDTHREAD
2203 			dhd_os_sdlock(bus->dhd);
2204 			dhd_os_sdlock_txq(bus->dhd);
2205 #endif
2206 #ifdef PROP_TXSTATUS
2207 			/* let the caller decide whether to free the packet */
2208 			if (!bus->dhd->wlfc_state)
2209 #endif
2210 			PKTFREE(osh, pkt, TRUE);
2211 			ret = BCME_NORESOURCE;
2212 		}
2213 		else
2214 			ret = BCME_OK;
2215 
2216 		if ((pktq_len(&bus->txq) >= FCHI) && dhd_doflow)
2217 			dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON);
2218 
2219 #ifdef DHD_DEBUG
2220 		if (pktq_plen(&bus->txq, prec) > qcount[prec])
2221 			qcount[prec] = pktq_plen(&bus->txq, prec);
2222 #endif
2223 		dhd_os_sdunlock_txq(bus->dhd);
2224 
2225 		/* Schedule DPC if needed to send queued packet(s) */
2226 		if (dhd_deferred_tx && !bus->dpc_sched) {
2227 			bus->dpc_sched = TRUE;
2228 			dhd_sched_dpc(bus->dhd);
2229 		}
2230 	} else {
2231 #ifdef DHDTHREAD
2232 		/* Lock: we're about to use shared data/code (and SDIO) */
2233 		dhd_os_sdlock(bus->dhd);
2234 #endif /* DHDTHREAD */
2235 
2236 		/* Otherwise, send it now */
2237 		BUS_WAKE(bus);
2238 		/* Make sure back plane ht clk is on, no pending allowed */
2239 		dhdsdio_clkctl(bus, CLK_AVAIL, TRUE);
2240 #ifndef SDTEST
2241 		ret = dhdsdio_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, TRUE, FALSE);
2242 #else
2243 		ret = dhdsdio_txpkt(bus, pkt,
2244 		        (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL), TRUE, FALSE);
2245 #endif
2246 		if (ret)
2247 			bus->dhd->tx_errors++;
2248 		else
2249 			bus->dhd->dstats.tx_bytes += datalen;
2250 
2251 		if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
2252 			bus->activity = FALSE;
2253 			dhdsdio_clkctl(bus, CLK_NONE, TRUE);
2254 		}
2255 
2256 #ifdef DHDTHREAD
2257 		dhd_os_sdunlock(bus->dhd);
2258 #endif /* DHDTHREAD */
2259 	}
2260 
2261 #ifndef DHDTHREAD
2262 	dhd_os_sdunlock(bus->dhd);
2263 #endif /* DHDTHREAD */
2264 
2265 	return ret;
2266 }
2267 
2268 static uint
dhdsdio_sendfromq(dhd_bus_t * bus,uint maxframes)2269 dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes)
2270 {
2271 	void *pkt;
2272 	uint32 intstatus = 0;
2273 	uint retries = 0;
2274 	int ret = 0, prec_out;
2275 	uint cnt = 0;
2276 	uint datalen;
2277 	uint8 tx_prec_map;
2278 	uint16 txpktqlen = 0;
2279 #ifdef BCMSDIOH_TXGLOM
2280 	uint i;
2281 	uint8 glom_cnt;
2282 #endif
2283 
2284 	dhd_pub_t *dhd = bus->dhd;
2285 	sdpcmd_regs_t *regs = bus->regs;
2286 
2287 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2288 
2289 	if (!KSO_ENAB(bus)) {
2290 		DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
2291 		return BCME_NODEVICE;
2292 	}
2293 
2294 	tx_prec_map = ~bus->flowcontrol;
2295 
2296 	/* Send frames until the limit or some other event */
2297 	for (cnt = 0; (cnt < maxframes) && DATAOK(bus); cnt++) {
2298 #ifdef BCMSDIOH_TXGLOM
2299 		if (bus->glom_enable) {
2300 			void *pkttable[SDPCM_MAXGLOM_SIZE];
2301 			dhd_os_sdlock_txq(bus->dhd);
2302 			glom_cnt = MIN(DATABUFCNT(bus), bus->glomsize);
2303 			glom_cnt = MIN(glom_cnt, pktq_mlen(&bus->txq, tx_prec_map));
2304 			glom_cnt = MIN(glom_cnt, maxframes-cnt);
2305 
2306 			/* Limiting the size to 2pkts in case of copy */
2307 			if (bus->glom_mode == SDPCM_TXGLOM_CPY)
2308 			    glom_cnt = MIN(glom_cnt, 10);
2309 
2310 			for (i = 0; i < glom_cnt; i++)
2311 				pkttable[i] = pktq_mdeq(&bus->txq, tx_prec_map, &prec_out);
2312 
2313 			txpktqlen = pktq_len(&bus->txq);
2314 			dhd_os_sdunlock_txq(bus->dhd);
2315 
2316 			if (glom_cnt == 0)
2317 				break;
2318 			datalen = 0;
2319 			for (i = 0; i < glom_cnt; i++) {
2320 				uint datalen_tmp = 0;
2321 
2322 				if ((pkt = pkttable[i]) == NULL) {
2323 					/* This case should not happen */
2324 					DHD_ERROR(("No pkts in the queue for glomming\n"));
2325 					break;
2326 				}
2327 
2328 				datalen_tmp = (PKTLEN(bus->dhd->osh, pkt) - SDPCM_HDRLEN);
2329 
2330 #ifndef SDTEST
2331 				ret = dhdsdio_txpkt(bus,
2332 					pkt,
2333 					SDPCM_DATA_CHANNEL,
2334 					TRUE,
2335 					(i == (glom_cnt-1))? FALSE: TRUE);
2336 #else
2337 				ret = dhdsdio_txpkt(bus,
2338 					pkt,
2339 					(bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL),
2340 					TRUE,
2341 					(i == (glom_cnt-1))? FALSE: TRUE);
2342 #endif
2343 				if (ret == BCME_OK)
2344 					datalen += datalen_tmp;
2345 			}
2346 			cnt += i-1;
2347 		} else
2348 #endif /* BCMSDIOH_TXGLOM */
2349 		{
2350 		dhd_os_sdlock_txq(bus->dhd);
2351 		if ((pkt = pktq_mdeq(&bus->txq, tx_prec_map, &prec_out)) == NULL) {
2352 			txpktqlen = pktq_len(&bus->txq);
2353 			dhd_os_sdunlock_txq(bus->dhd);
2354 			break;
2355 		}
2356 		txpktqlen = pktq_len(&bus->txq);
2357 		dhd_os_sdunlock_txq(bus->dhd);
2358 		datalen = PKTLEN(bus->dhd->osh, pkt) - SDPCM_HDRLEN;
2359 
2360 #ifndef SDTEST
2361 		ret = dhdsdio_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, TRUE, FALSE);
2362 #else
2363 		ret = dhdsdio_txpkt(bus,
2364 			pkt,
2365 			(bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL),
2366 			TRUE,
2367 			FALSE);
2368 #endif
2369 		}
2370 
2371 		if (ret)
2372 			bus->dhd->tx_errors++;
2373 		else
2374 			bus->dhd->dstats.tx_bytes += datalen;
2375 
2376 		/* In poll mode, need to check for other events */
2377 		if (!bus->intr && cnt)
2378 		{
2379 			/* Check device status, signal pending interrupt */
2380 			R_SDREG(intstatus, &regs->intstatus, retries);
2381 			bus->f2txdata++;
2382 			if (bcmsdh_regfail(bus->sdh))
2383 				break;
2384 			if (intstatus & bus->hostintmask)
2385 				bus->ipend = TRUE;
2386 		}
2387 	}
2388 
2389 	/* Deflow-control stack if needed */
2390 	if (dhd_doflow && dhd->up && (dhd->busstate == DHD_BUS_DATA) &&
2391 	    dhd->txoff && (txpktqlen < FCLOW))
2392 		dhd_txflowcontrol(dhd, ALL_INTERFACES, OFF);
2393 
2394 	return cnt;
2395 }
2396 
2397 static void
dhdsdio_sendpendctl(dhd_bus_t * bus)2398 dhdsdio_sendpendctl(dhd_bus_t *bus)
2399 {
2400 	bcmsdh_info_t *sdh = bus->sdh;
2401 	int ret, i;
2402 	uint8* frame_seq = bus->ctrl_frame_buf + SDPCM_FRAMETAG_LEN;
2403 
2404 #ifdef BCMSDIOH_TXGLOM
2405 	if (bus->glom_enable)
2406 		frame_seq += SDPCM_HWEXT_LEN;
2407 #endif
2408 
2409 	if (*frame_seq != bus->tx_seq) {
2410 		DHD_INFO(("%s IOCTL frame seq lag detected!"
2411 			" frm_seq:%d != bus->tx_seq:%d, corrected\n",
2412 			__FUNCTION__, *frame_seq, bus->tx_seq));
2413 		*frame_seq = bus->tx_seq;
2414 	}
2415 
2416 	ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
2417 		(uint8 *)bus->ctrl_frame_buf, (uint32)bus->ctrl_frame_len,
2418 		NULL, NULL, NULL);
2419 	ASSERT(ret != BCME_PENDING);
2420 	if (ret == BCME_NODEVICE) {
2421 		DHD_ERROR(("%s: Device asleep already\n", __FUNCTION__));
2422 	} else if (ret < 0) {
2423 		/* On failure, abort the command and terminate the frame */
2424 		DHD_INFO(("%s: sdio error %d, abort command and terminate frame.\n",
2425 		          __FUNCTION__, ret));
2426 		bus->tx_sderrs++;
2427 
2428 		bcmsdh_abort(sdh, SDIO_FUNC_2);
2429 
2430 		bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
2431 		                 SFC_WF_TERM, NULL);
2432 		bus->f1regdata++;
2433 
2434 		for (i = 0; i < 3; i++) {
2435 			uint8 hi, lo;
2436 			hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
2437 			                     SBSDIO_FUNC1_WFRAMEBCHI, NULL);
2438 			lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
2439 			                     SBSDIO_FUNC1_WFRAMEBCLO, NULL);
2440 			bus->f1regdata += 2;
2441 			if ((hi == 0) && (lo == 0))
2442 				break;
2443 		}
2444 	}
2445 	if (ret == 0) {
2446 		bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
2447 	}
2448 
2449 	bus->ctrl_frame_stat = FALSE;
2450 	dhd_wait_event_wakeup(bus->dhd);
2451 }
2452 
2453 int
dhd_bus_txctl(struct dhd_bus * bus,uchar * msg,uint msglen)2454 dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen)
2455 {
2456 	uint8 *frame;
2457 	uint16 len;
2458 	uint32 swheader;
2459 	uint retries = 0;
2460 	bcmsdh_info_t *sdh = bus->sdh;
2461 	uint8 doff = 0;
2462 	int ret = -1;
2463 	int i;
2464 
2465 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2466 
2467 	if (bus->dhd->dongle_reset)
2468 		return -EIO;
2469 
2470 	/* Back the pointer to make a room for bus header */
2471 	frame = msg - SDPCM_HDRLEN;
2472 	len = (msglen += SDPCM_HDRLEN);
2473 
2474 	/* Add alignment padding (optional for ctl frames) */
2475 	if (dhd_alignctl) {
2476 		if ((doff = ((uintptr)frame % DHD_SDALIGN))) {
2477 			frame -= doff;
2478 			len += doff;
2479 			msglen += doff;
2480 			bzero(frame, doff + SDPCM_HDRLEN);
2481 		}
2482 		ASSERT(doff < DHD_SDALIGN);
2483 	}
2484 	doff += SDPCM_HDRLEN;
2485 
2486 	/* Round send length to next SDIO block */
2487 	if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
2488 		uint16 pad = bus->blocksize - (len % bus->blocksize);
2489 		if ((pad <= bus->roundup) && (pad < bus->blocksize))
2490 			len += pad;
2491 	} else if (len % DHD_SDALIGN) {
2492 		len += DHD_SDALIGN - (len % DHD_SDALIGN);
2493 	}
2494 
2495 	/* Satisfy length-alignment requirements */
2496 	if (forcealign && (len & (ALIGNMENT - 1)))
2497 		len = ROUNDUP(len, ALIGNMENT);
2498 
2499 	ASSERT(ISALIGNED((uintptr)frame, 2));
2500 
2501 
2502 	/* Need to lock here to protect txseq and SDIO tx calls */
2503 	dhd_os_sdlock(bus->dhd);
2504 
2505 	BUS_WAKE(bus);
2506 
2507 	/* Make sure backplane clock is on */
2508 	dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
2509 
2510 	/* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
2511 	*(uint16*)frame = htol16((uint16)msglen);
2512 	*(((uint16*)frame) + 1) = htol16(~msglen);
2513 
2514 #ifdef BCMSDIOH_TXGLOM
2515 	if (bus->glom_enable) {
2516 		uint32 hwheader1, hwheader2;
2517 		/* Software tag: channel, sequence number, data offset */
2518 		swheader = ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK)
2519 				| bus->tx_seq
2520 				| ((doff << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
2521 		htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN);
2522 		htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN
2523 			+ SDPCM_HWEXT_LEN + sizeof(swheader));
2524 
2525 		hwheader1 = (msglen - SDPCM_FRAMETAG_LEN) | (1 << 24);
2526 		hwheader2 = (len - (msglen)) << 16;
2527 		htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN);
2528 		htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4);
2529 
2530 		*(uint16*)frame = htol16(len);
2531 		*(((uint16*)frame) + 1) = htol16(~(len));
2532 	} else
2533 #endif /* BCMSDIOH_TXGLOM */
2534 	{
2535 	/* Software tag: channel, sequence number, data offset */
2536 	swheader = ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK)
2537 	        | bus->tx_seq | ((doff << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
2538 	htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN);
2539 	htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
2540 	}
2541 	if (!TXCTLOK(bus)) {
2542 		DHD_INFO(("%s: No bus credit bus->tx_max %d, bus->tx_seq %d\n",
2543 			__FUNCTION__, bus->tx_max, bus->tx_seq));
2544 		bus->ctrl_frame_stat = TRUE;
2545 		/* Send from dpc */
2546 		bus->ctrl_frame_buf = frame;
2547 		bus->ctrl_frame_len = len;
2548 
2549 		if (!bus->dpc_sched) {
2550 			bus->dpc_sched = TRUE;
2551 			dhd_sched_dpc(bus->dhd);
2552 		}
2553 		if (bus->ctrl_frame_stat) {
2554 			dhd_wait_for_event(bus->dhd, &bus->ctrl_frame_stat);
2555 		}
2556 
2557 		if (bus->ctrl_frame_stat == FALSE) {
2558 			DHD_INFO(("%s: ctrl_frame_stat == FALSE\n", __FUNCTION__));
2559 			ret = 0;
2560 		} else {
2561 			bus->dhd->txcnt_timeout++;
2562 			if (!bus->dhd->hang_was_sent) {
2563 				DHD_ERROR(("%s: ctrl_frame_stat == TRUE txcnt_timeout=%d\n",
2564 					__FUNCTION__, bus->dhd->txcnt_timeout));
2565 			}
2566 			ret = -1;
2567 			bus->ctrl_frame_stat = FALSE;
2568 			goto done;
2569 		}
2570 	}
2571 
2572 	bus->dhd->txcnt_timeout = 0;
2573 
2574 	if (ret == -1) {
2575 #ifdef DHD_DEBUG
2576 		if (DHD_BYTES_ON() && DHD_CTL_ON()) {
2577 			prhex("Tx Frame", frame, len);
2578 		} else if (DHD_HDRS_ON()) {
2579 			prhex("TxHdr", frame, MIN(len, 16));
2580 		}
2581 #endif
2582 
2583 		do {
2584 			ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
2585 			                          frame, len, NULL, NULL, NULL);
2586 			ASSERT(ret != BCME_PENDING);
2587 
2588 			if (ret == BCME_NODEVICE) {
2589 				DHD_ERROR(("%s: Device asleep already\n", __FUNCTION__));
2590 			} else if (ret < 0) {
2591 			/* On failure, abort the command and terminate the frame */
2592 				DHD_INFO(("%s: sdio error %d, abort command and terminate frame.\n",
2593 				          __FUNCTION__, ret));
2594 				bus->tx_sderrs++;
2595 
2596 				bcmsdh_abort(sdh, SDIO_FUNC_2);
2597 
2598 				bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
2599 				                 SFC_WF_TERM, NULL);
2600 				bus->f1regdata++;
2601 
2602 				for (i = 0; i < 3; i++) {
2603 					uint8 hi, lo;
2604 					hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
2605 					                     SBSDIO_FUNC1_WFRAMEBCHI, NULL);
2606 					lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
2607 					                     SBSDIO_FUNC1_WFRAMEBCLO, NULL);
2608 					bus->f1regdata += 2;
2609 					if ((hi == 0) && (lo == 0))
2610 						break;
2611 				}
2612 			}
2613 			if (ret == 0) {
2614 				bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
2615 			}
2616 		} while ((ret < 0) && retries++ < TXRETRIES);
2617 	}
2618 
2619 done:
2620 	if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
2621 		bus->activity = FALSE;
2622 		dhdsdio_clkctl(bus, CLK_NONE, TRUE);
2623 	}
2624 
2625 	dhd_os_sdunlock(bus->dhd);
2626 
2627 	if (ret)
2628 		bus->dhd->tx_ctlerrs++;
2629 	else
2630 		bus->dhd->tx_ctlpkts++;
2631 
2632 	if (bus->dhd->txcnt_timeout >= MAX_CNTL_TX_TIMEOUT)
2633 		return -ETIMEDOUT;
2634 
2635 	return ret ? -EIO : 0;
2636 }
2637 
2638 int
dhd_bus_rxctl(struct dhd_bus * bus,uchar * msg,uint msglen)2639 dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen)
2640 {
2641 	int timeleft;
2642 	uint rxlen = 0;
2643 	bool pending;
2644 
2645 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2646 
2647 	if (bus->dhd->dongle_reset)
2648 		return -EIO;
2649 
2650 	/* Wait until control frame is available */
2651 	timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->rxlen, &pending);
2652 
2653 	dhd_os_sdlock(bus->dhd);
2654 	rxlen = bus->rxlen;
2655 	bcopy(bus->rxctl, msg, MIN(msglen, rxlen));
2656 	bus->rxlen = 0;
2657 	dhd_os_sdunlock(bus->dhd);
2658 
2659 	if (rxlen) {
2660 		DHD_CTL(("%s: resumed on rxctl frame, got %d expected %d\n",
2661 			__FUNCTION__, rxlen, msglen));
2662 	} else if (timeleft == 0) {
2663 #ifdef DHD_DEBUG
2664 		uint32 status, retry = 0;
2665 		R_SDREG(status, &bus->regs->intstatus, retry);
2666 		DHD_ERROR(("%s: resumed on timeout, INT status=0x%08X\n",
2667 			__FUNCTION__, status));
2668 #else
2669 		DHD_ERROR(("%s: resumed on timeout\n", __FUNCTION__));
2670 #endif /* DHD_DEBUG */
2671 #ifdef DHD_DEBUG
2672 			dhd_os_sdlock(bus->dhd);
2673 			dhdsdio_checkdied(bus, NULL, 0);
2674 			dhd_os_sdunlock(bus->dhd);
2675 #endif /* DHD_DEBUG */
2676 	} else if (pending == TRUE) {
2677 		/* signal pending */
2678 		DHD_ERROR(("%s: signal pending\n", __FUNCTION__));
2679 		return -EINTR;
2680 
2681 	} else {
2682 		DHD_CTL(("%s: resumed for unknown reason?\n", __FUNCTION__));
2683 #ifdef DHD_DEBUG
2684 		dhd_os_sdlock(bus->dhd);
2685 		dhdsdio_checkdied(bus, NULL, 0);
2686 		dhd_os_sdunlock(bus->dhd);
2687 #endif /* DHD_DEBUG */
2688 	}
2689 	if (timeleft == 0) {
2690 		if (rxlen == 0)
2691 			bus->dhd->rxcnt_timeout++;
2692 		DHD_ERROR(("%s: rxcnt_timeout=%d, rxlen=%d\n", __FUNCTION__,
2693 			bus->dhd->rxcnt_timeout, rxlen));
2694 	}
2695 	else
2696 		bus->dhd->rxcnt_timeout = 0;
2697 
2698 	if (rxlen)
2699 		bus->dhd->rx_ctlpkts++;
2700 	else
2701 		bus->dhd->rx_ctlerrs++;
2702 
2703 	if (bus->dhd->rxcnt_timeout >= MAX_CNTL_RX_TIMEOUT)
2704 		return -ETIMEDOUT;
2705 
2706 	if (bus->dhd->dongle_trap_occured)
2707 		return -EREMOTEIO;
2708 
2709 	return rxlen ? (int)rxlen : -EIO;
2710 }
2711 
2712 /* IOVar table */
2713 enum {
2714 	IOV_INTR = 1,
2715 	IOV_POLLRATE,
2716 	IOV_SDREG,
2717 	IOV_SBREG,
2718 	IOV_SDCIS,
2719 	IOV_MEMBYTES,
2720 	IOV_RAMSIZE,
2721 	IOV_RAMSTART,
2722 #ifdef DHD_DEBUG
2723 	IOV_CHECKDIED,
2724 	IOV_SERIALCONS,
2725 #endif /* DHD_DEBUG */
2726 	IOV_SET_DOWNLOAD_STATE,
2727 	IOV_SOCRAM_STATE,
2728 	IOV_FORCEEVEN,
2729 	IOV_SDIOD_DRIVE,
2730 	IOV_READAHEAD,
2731 	IOV_SDRXCHAIN,
2732 	IOV_ALIGNCTL,
2733 	IOV_SDALIGN,
2734 	IOV_DEVRESET,
2735 	IOV_CPU,
2736 #if defined(SDIO_CRC_ERROR_FIX)
2737 	IOV_WATERMARK,
2738 	IOV_MESBUSYCTRL,
2739 #endif /* SDIO_CRC_ERROR_FIX */
2740 #ifdef SDTEST
2741 	IOV_PKTGEN,
2742 	IOV_EXTLOOP,
2743 #endif /* SDTEST */
2744 	IOV_SPROM,
2745 	IOV_TXBOUND,
2746 	IOV_RXBOUND,
2747 	IOV_TXMINMAX,
2748 	IOV_IDLETIME,
2749 	IOV_IDLECLOCK,
2750 	IOV_SD1IDLE,
2751 	IOV_SLEEP,
2752 	IOV_DONGLEISOLATION,
2753 	IOV_KSO,
2754 	IOV_DEVSLEEP,
2755 	IOV_DEVCAP,
2756 	IOV_VARS,
2757 #ifdef SOFTAP
2758 	IOV_FWPATH,
2759 #endif
2760 	IOV_TXGLOMSIZE,
2761 	IOV_TXGLOMMODE,
2762 	IOV_HANGREPORT
2763 };
2764 
2765 const bcm_iovar_t dhdsdio_iovars[] = {
2766 	{"intr",	IOV_INTR,	0,	IOVT_BOOL,	0 },
2767 	{"sleep",	IOV_SLEEP,	0,	IOVT_BOOL,	0 },
2768 	{"pollrate",	IOV_POLLRATE,	0,	IOVT_UINT32,	0 },
2769 	{"idletime",	IOV_IDLETIME,	0,	IOVT_INT32,	0 },
2770 	{"idleclock",	IOV_IDLECLOCK,	0,	IOVT_INT32,	0 },
2771 	{"sd1idle",	IOV_SD1IDLE,	0,	IOVT_BOOL,	0 },
2772 	{"membytes",	IOV_MEMBYTES,	0,	IOVT_BUFFER,	2 * sizeof(int) },
2773 	{"ramsize",	IOV_RAMSIZE,	0,	IOVT_UINT32,	0 },
2774 	{"ramstart",	IOV_RAMSTART,	0,	IOVT_UINT32,	0 },
2775 	{"dwnldstate",	IOV_SET_DOWNLOAD_STATE,	0,	IOVT_BOOL,	0 },
2776 	{"socram_state",	IOV_SOCRAM_STATE,	0,	IOVT_BOOL,	0 },
2777 	{"vars",	IOV_VARS,	0,	IOVT_BUFFER,	0 },
2778 	{"sdiod_drive",	IOV_SDIOD_DRIVE, 0,	IOVT_UINT32,	0 },
2779 	{"readahead",	IOV_READAHEAD,	0,	IOVT_BOOL,	0 },
2780 	{"sdrxchain",	IOV_SDRXCHAIN,	0,	IOVT_BOOL,	0 },
2781 	{"alignctl",	IOV_ALIGNCTL,	0,	IOVT_BOOL,	0 },
2782 	{"sdalign",	IOV_SDALIGN,	0,	IOVT_BOOL,	0 },
2783 	{"devreset",	IOV_DEVRESET,	0,	IOVT_BOOL,	0 },
2784 #ifdef DHD_DEBUG
2785 	{"sdreg",	IOV_SDREG,	0,	IOVT_BUFFER,	sizeof(sdreg_t) },
2786 	{"sbreg",	IOV_SBREG,	0,	IOVT_BUFFER,	sizeof(sdreg_t) },
2787 	{"sd_cis",	IOV_SDCIS,	0,	IOVT_BUFFER,	DHD_IOCTL_MAXLEN },
2788 	{"forcealign",	IOV_FORCEEVEN,	0,	IOVT_BOOL,	0 },
2789 	{"txbound",	IOV_TXBOUND,	0,	IOVT_UINT32,	0 },
2790 	{"rxbound",	IOV_RXBOUND,	0,	IOVT_UINT32,	0 },
2791 	{"txminmax",	IOV_TXMINMAX,	0,	IOVT_UINT32,	0 },
2792 	{"cpu",		IOV_CPU,	0,	IOVT_BOOL,	0 },
2793 #ifdef DHD_DEBUG
2794 	{"checkdied",	IOV_CHECKDIED,	0,	IOVT_BUFFER,	0 },
2795 	{"serial",	IOV_SERIALCONS,	0,	IOVT_UINT32,	0 },
2796 #endif /* DHD_DEBUG  */
2797 #endif /* DHD_DEBUG */
2798 #ifdef SDTEST
2799 	{"extloop",	IOV_EXTLOOP,	0,	IOVT_BOOL,	0 },
2800 	{"pktgen",	IOV_PKTGEN,	0,	IOVT_BUFFER,	sizeof(dhd_pktgen_t) },
2801 #endif /* SDTEST */
2802 #if defined(SDIO_CRC_ERROR_FIX)
2803 	{"watermark",	IOV_WATERMARK,	0,	IOVT_UINT32,	0 },
2804 	{"mesbusyctrl",	IOV_MESBUSYCTRL,	0,	IOVT_UINT32,	0 },
2805 #endif /* SDIO_CRC_ERROR_FIX */
2806 	{"devcap", IOV_DEVCAP,	0,	IOVT_UINT32,	0 },
2807 	{"dngl_isolation", IOV_DONGLEISOLATION,	0,	IOVT_UINT32,	0 },
2808 	{"kso",	IOV_KSO,	0,	IOVT_UINT32,	0 },
2809 	{"devsleep", IOV_DEVSLEEP,	0,	IOVT_UINT32,	0 },
2810 #ifdef SOFTAP
2811 	{"fwpath", IOV_FWPATH, 0, IOVT_BUFFER, 0 },
2812 #endif
2813 	{"txglomsize", IOV_TXGLOMSIZE, 0, IOVT_UINT32, 0 },
2814 	{"txglommode", IOV_TXGLOMMODE, 0, IOVT_UINT32, 0 },
2815 	{"fw_hang_report", IOV_HANGREPORT, 0, IOVT_BOOL, 0 },
2816 	{NULL, 0, 0, 0, 0 }
2817 };
2818 
2819 static void
dhd_dump_pct(struct bcmstrbuf * strbuf,char * desc,uint num,uint div)2820 dhd_dump_pct(struct bcmstrbuf *strbuf, char *desc, uint num, uint div)
2821 {
2822 	uint q1, q2;
2823 
2824 	if (!div) {
2825 		bcm_bprintf(strbuf, "%s N/A", desc);
2826 	} else {
2827 		q1 = num / div;
2828 		q2 = (100 * (num - (q1 * div))) / div;
2829 		bcm_bprintf(strbuf, "%s %d.%02d", desc, q1, q2);
2830 	}
2831 }
2832 
2833 void
dhd_bus_dump(dhd_pub_t * dhdp,struct bcmstrbuf * strbuf)2834 dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf)
2835 {
2836 	dhd_bus_t *bus = dhdp->bus;
2837 
2838 	bcm_bprintf(strbuf, "Bus SDIO structure:\n");
2839 	bcm_bprintf(strbuf, "hostintmask 0x%08x intstatus 0x%08x sdpcm_ver %d\n",
2840 	            bus->hostintmask, bus->intstatus, bus->sdpcm_ver);
2841 	bcm_bprintf(strbuf, "fcstate %d qlen %u tx_seq %d, max %d, rxskip %d rxlen %u rx_seq %d\n",
2842 	            bus->fcstate, pktq_len(&bus->txq), bus->tx_seq, bus->tx_max, bus->rxskip,
2843 	            bus->rxlen, bus->rx_seq);
2844 	bcm_bprintf(strbuf, "intr %d intrcount %u lastintrs %u spurious %u\n",
2845 	            bus->intr, bus->intrcount, bus->lastintrs, bus->spurious);
2846 	bcm_bprintf(strbuf, "pollrate %u pollcnt %u regfails %u\n",
2847 	            bus->pollrate, bus->pollcnt, bus->regfails);
2848 
2849 	bcm_bprintf(strbuf, "\nAdditional counters:\n");
2850 	bcm_bprintf(strbuf, "tx_sderrs %u fcqueued %u rxrtx %u rx_toolong %u rxc_errors %u\n",
2851 	            bus->tx_sderrs, bus->fcqueued, bus->rxrtx, bus->rx_toolong,
2852 	            bus->rxc_errors);
2853 	bcm_bprintf(strbuf, "rx_hdrfail %u badhdr %u badseq %u\n",
2854 	            bus->rx_hdrfail, bus->rx_badhdr, bus->rx_badseq);
2855 	bcm_bprintf(strbuf, "fc_rcvd %u, fc_xoff %u, fc_xon %u\n",
2856 	            bus->fc_rcvd, bus->fc_xoff, bus->fc_xon);
2857 	bcm_bprintf(strbuf, "rxglomfail %u, rxglomframes %u, rxglompkts %u\n",
2858 	            bus->rxglomfail, bus->rxglomframes, bus->rxglompkts);
2859 	bcm_bprintf(strbuf, "f2rx (hdrs/data) %u (%u/%u), f2tx %u f1regs %u\n",
2860 	            (bus->f2rxhdrs + bus->f2rxdata), bus->f2rxhdrs, bus->f2rxdata,
2861 	            bus->f2txdata, bus->f1regdata);
2862 	{
2863 		dhd_dump_pct(strbuf, "\nRx: pkts/f2rd", bus->dhd->rx_packets,
2864 		             (bus->f2rxhdrs + bus->f2rxdata));
2865 		dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->rx_packets, bus->f1regdata);
2866 		dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->rx_packets,
2867 		             (bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata));
2868 		dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->rx_packets, bus->intrcount);
2869 		bcm_bprintf(strbuf, "\n");
2870 
2871 		dhd_dump_pct(strbuf, "Rx: glom pct", (100 * bus->rxglompkts),
2872 		             bus->dhd->rx_packets);
2873 		dhd_dump_pct(strbuf, ", pkts/glom", bus->rxglompkts, bus->rxglomframes);
2874 		bcm_bprintf(strbuf, "\n");
2875 
2876 		dhd_dump_pct(strbuf, "Tx: pkts/f2wr", bus->dhd->tx_packets, bus->f2txdata);
2877 		dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->tx_packets, bus->f1regdata);
2878 		dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->tx_packets,
2879 		             (bus->f2txdata + bus->f1regdata));
2880 		dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->tx_packets, bus->intrcount);
2881 		bcm_bprintf(strbuf, "\n");
2882 
2883 		dhd_dump_pct(strbuf, "Total: pkts/f2rw",
2884 		             (bus->dhd->tx_packets + bus->dhd->rx_packets),
2885 		             (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata));
2886 		dhd_dump_pct(strbuf, ", pkts/f1sd",
2887 		             (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->f1regdata);
2888 		dhd_dump_pct(strbuf, ", pkts/sd",
2889 		             (bus->dhd->tx_packets + bus->dhd->rx_packets),
2890 		             (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata));
2891 		dhd_dump_pct(strbuf, ", pkts/int",
2892 		             (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->intrcount);
2893 		bcm_bprintf(strbuf, "\n\n");
2894 	}
2895 
2896 #ifdef SDTEST
2897 	if (bus->pktgen_count) {
2898 		bcm_bprintf(strbuf, "pktgen config and count:\n");
2899 		bcm_bprintf(strbuf, "freq %u count %u print %u total %u min %u len %u\n",
2900 		            bus->pktgen_freq, bus->pktgen_count, bus->pktgen_print,
2901 		            bus->pktgen_total, bus->pktgen_minlen, bus->pktgen_maxlen);
2902 		bcm_bprintf(strbuf, "send attempts %u rcvd %u fail %u\n",
2903 		            bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail);
2904 	}
2905 #endif /* SDTEST */
2906 #ifdef DHD_DEBUG
2907 	bcm_bprintf(strbuf, "dpc_sched %d host interrupt%spending\n",
2908 	            bus->dpc_sched, (bcmsdh_intr_pending(bus->sdh) ? " " : " not "));
2909 	bcm_bprintf(strbuf, "blocksize %u roundup %u\n", bus->blocksize, bus->roundup);
2910 #endif /* DHD_DEBUG */
2911 	bcm_bprintf(strbuf, "clkstate %d activity %d idletime %d idlecount %d sleeping %d\n",
2912 	            bus->clkstate, bus->activity, bus->idletime, bus->idlecount, bus->sleeping);
2913 }
2914 
2915 void
dhd_bus_clearcounts(dhd_pub_t * dhdp)2916 dhd_bus_clearcounts(dhd_pub_t *dhdp)
2917 {
2918 	dhd_bus_t *bus = (dhd_bus_t *)dhdp->bus;
2919 
2920 	bus->intrcount = bus->lastintrs = bus->spurious = bus->regfails = 0;
2921 	bus->rxrtx = bus->rx_toolong = bus->rxc_errors = 0;
2922 	bus->rx_hdrfail = bus->rx_badhdr = bus->rx_badseq = 0;
2923 	bus->tx_sderrs = bus->fc_rcvd = bus->fc_xoff = bus->fc_xon = 0;
2924 	bus->rxglomfail = bus->rxglomframes = bus->rxglompkts = 0;
2925 	bus->f2rxhdrs = bus->f2rxdata = bus->f2txdata = bus->f1regdata = 0;
2926 }
2927 
2928 #ifdef SDTEST
2929 static int
dhdsdio_pktgen_get(dhd_bus_t * bus,uint8 * arg)2930 dhdsdio_pktgen_get(dhd_bus_t *bus, uint8 *arg)
2931 {
2932 	dhd_pktgen_t pktgen;
2933 
2934 	pktgen.version = DHD_PKTGEN_VERSION;
2935 	pktgen.freq = bus->pktgen_freq;
2936 	pktgen.count = bus->pktgen_count;
2937 	pktgen.print = bus->pktgen_print;
2938 	pktgen.total = bus->pktgen_total;
2939 	pktgen.minlen = bus->pktgen_minlen;
2940 	pktgen.maxlen = bus->pktgen_maxlen;
2941 	pktgen.numsent = bus->pktgen_sent;
2942 	pktgen.numrcvd = bus->pktgen_rcvd;
2943 	pktgen.numfail = bus->pktgen_fail;
2944 	pktgen.mode = bus->pktgen_mode;
2945 	pktgen.stop = bus->pktgen_stop;
2946 
2947 	bcopy(&pktgen, arg, sizeof(pktgen));
2948 
2949 	return 0;
2950 }
2951 
2952 static int
dhdsdio_pktgen_set(dhd_bus_t * bus,uint8 * arg)2953 dhdsdio_pktgen_set(dhd_bus_t *bus, uint8 *arg)
2954 {
2955 	dhd_pktgen_t pktgen;
2956 	uint oldcnt, oldmode;
2957 
2958 	bcopy(arg, &pktgen, sizeof(pktgen));
2959 	if (pktgen.version != DHD_PKTGEN_VERSION)
2960 		return BCME_BADARG;
2961 
2962 	oldcnt = bus->pktgen_count;
2963 	oldmode = bus->pktgen_mode;
2964 
2965 	bus->pktgen_freq = pktgen.freq;
2966 	bus->pktgen_count = pktgen.count;
2967 	bus->pktgen_print = pktgen.print;
2968 	bus->pktgen_total = pktgen.total;
2969 	bus->pktgen_minlen = pktgen.minlen;
2970 	bus->pktgen_maxlen = pktgen.maxlen;
2971 	bus->pktgen_mode = pktgen.mode;
2972 	bus->pktgen_stop = pktgen.stop;
2973 
2974 	bus->pktgen_tick = bus->pktgen_ptick = 0;
2975 	bus->pktgen_prev_time = jiffies;
2976 	bus->pktgen_len = MAX(bus->pktgen_len, bus->pktgen_minlen);
2977 	bus->pktgen_len = MIN(bus->pktgen_len, bus->pktgen_maxlen);
2978 
2979 	/* Clear counts for a new pktgen (mode change, or was stopped) */
2980 	if (bus->pktgen_count && (!oldcnt || oldmode != bus->pktgen_mode)) {
2981 		bus->pktgen_sent = bus->pktgen_prev_sent = bus->pktgen_rcvd = 0;
2982 		bus->pktgen_prev_rcvd = bus->pktgen_fail = 0;
2983 	}
2984 
2985 	return 0;
2986 }
2987 #endif /* SDTEST */
2988 
2989 static void
dhdsdio_devram_remap(dhd_bus_t * bus,bool val)2990 dhdsdio_devram_remap(dhd_bus_t *bus, bool val)
2991 {
2992 	uint8 enable, protect, remap;
2993 
2994 	si_socdevram(bus->sih, FALSE, &enable, &protect, &remap);
2995 	remap = val ? TRUE : FALSE;
2996 	si_socdevram(bus->sih, TRUE, &enable, &protect, &remap);
2997 }
2998 
2999 static int
dhdsdio_membytes(dhd_bus_t * bus,bool write,uint32 address,uint8 * data,uint size)3000 dhdsdio_membytes(dhd_bus_t *bus, bool write, uint32 address, uint8 *data, uint size)
3001 {
3002 	int bcmerror = 0;
3003 	uint32 sdaddr;
3004 	uint dsize;
3005 
3006 	/* In remap mode, adjust address beyond socram and redirect
3007 	 * to devram at SOCDEVRAM_BP_ADDR since remap address > orig_ramsize
3008 	 * is not backplane accessible
3009 	 */
3010 	if (REMAP_ENAB(bus) && REMAP_ISADDR(bus, address)) {
3011 		address -= bus->orig_ramsize;
3012 		address += SOCDEVRAM_BP_ADDR;
3013 	}
3014 
3015 	/* Determine initial transfer parameters */
3016 	sdaddr = address & SBSDIO_SB_OFT_ADDR_MASK;
3017 	if ((sdaddr + size) & SBSDIO_SBWINDOW_MASK)
3018 		dsize = (SBSDIO_SB_OFT_ADDR_LIMIT - sdaddr);
3019 	else
3020 		dsize = size;
3021 
3022 	/* Set the backplane window to include the start address */
3023 	if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) {
3024 		DHD_ERROR(("%s: window change failed\n", __FUNCTION__));
3025 		goto xfer_done;
3026 	}
3027 
3028 	/* Do the transfer(s) */
3029 	while (size) {
3030 		DHD_INFO(("%s: %s %d bytes at offset 0x%08x in window 0x%08x\n",
3031 		          __FUNCTION__, (write ? "write" : "read"), dsize, sdaddr,
3032 		          (address & SBSDIO_SBWINDOW_MASK)));
3033 		if ((bcmerror = bcmsdh_rwdata(bus->sdh, write, sdaddr, data, dsize))) {
3034 			DHD_ERROR(("%s: membytes transfer failed\n", __FUNCTION__));
3035 			break;
3036 		}
3037 
3038 		/* Adjust for next transfer (if any) */
3039 		if ((size -= dsize)) {
3040 			data += dsize;
3041 			address += dsize;
3042 			if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) {
3043 				DHD_ERROR(("%s: window change failed\n", __FUNCTION__));
3044 				break;
3045 			}
3046 			sdaddr = 0;
3047 			dsize = MIN(SBSDIO_SB_OFT_ADDR_LIMIT, size);
3048 		}
3049 
3050 	}
3051 
3052 xfer_done:
3053 	/* Return the window to backplane enumeration space for core access */
3054 	if (dhdsdio_set_siaddr_window(bus, bcmsdh_cur_sbwad(bus->sdh))) {
3055 		DHD_ERROR(("%s: FAILED to set window back to 0x%x\n", __FUNCTION__,
3056 			bcmsdh_cur_sbwad(bus->sdh)));
3057 	}
3058 
3059 	return bcmerror;
3060 }
3061 
3062 #ifdef DHD_DEBUG
3063 static int
dhdsdio_readshared(dhd_bus_t * bus,sdpcm_shared_t * sh)3064 dhdsdio_readshared(dhd_bus_t *bus, sdpcm_shared_t *sh)
3065 {
3066 	uint32 addr;
3067 	int rv, i;
3068 	uint32 shaddr = 0;
3069 
3070 	shaddr = bus->dongle_ram_base + bus->ramsize - 4;
3071 	i = 0;
3072 	do {
3073 		/* Read last word in memory to determine address of sdpcm_shared structure */
3074 		if ((rv = dhdsdio_membytes(bus, FALSE, shaddr, (uint8 *)&addr, 4)) < 0)
3075 			return rv;
3076 
3077 		addr = ltoh32(addr);
3078 
3079 		DHD_INFO(("sdpcm_shared address 0x%08X\n", addr));
3080 
3081 		/*
3082 		 * Check if addr is valid.
3083 		 * NVRAM length at the end of memory should have been overwritten.
3084 		 */
3085 		if (addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff)) {
3086 			if ((bus->srmemsize > 0) && (i++ == 0)) {
3087 				shaddr -= bus->srmemsize;
3088 			} else {
3089 				DHD_ERROR(("%s: address (0x%08x) of sdpcm_shared invalid\n",
3090 					__FUNCTION__, addr));
3091 				return BCME_ERROR;
3092 			}
3093 		} else
3094 			break;
3095 	} while (i < 2);
3096 
3097 	/* Read hndrte_shared structure */
3098 	if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)sh, sizeof(sdpcm_shared_t))) < 0)
3099 		return rv;
3100 
3101 	/* Endianness */
3102 	sh->flags = ltoh32(sh->flags);
3103 	sh->trap_addr = ltoh32(sh->trap_addr);
3104 	sh->assert_exp_addr = ltoh32(sh->assert_exp_addr);
3105 	sh->assert_file_addr = ltoh32(sh->assert_file_addr);
3106 	sh->assert_line = ltoh32(sh->assert_line);
3107 	sh->console_addr = ltoh32(sh->console_addr);
3108 	sh->msgtrace_addr = ltoh32(sh->msgtrace_addr);
3109 
3110 	if ((sh->flags & SDPCM_SHARED_VERSION_MASK) == 3 && SDPCM_SHARED_VERSION == 1)
3111 		return BCME_OK;
3112 
3113 	if ((sh->flags & SDPCM_SHARED_VERSION_MASK) != SDPCM_SHARED_VERSION) {
3114 		DHD_ERROR(("%s: sdpcm_shared version %d in dhd "
3115 		           "is different than sdpcm_shared version %d in dongle\n",
3116 		           __FUNCTION__, SDPCM_SHARED_VERSION,
3117 		           sh->flags & SDPCM_SHARED_VERSION_MASK));
3118 		return BCME_ERROR;
3119 	}
3120 
3121 	return BCME_OK;
3122 }
3123 
3124 #define CONSOLE_LINE_MAX	192
3125 
3126 static int
dhdsdio_readconsole(dhd_bus_t * bus)3127 dhdsdio_readconsole(dhd_bus_t *bus)
3128 {
3129 	dhd_console_t *c = &bus->console;
3130 	uint8 line[CONSOLE_LINE_MAX], ch;
3131 	uint32 n, idx, addr;
3132 	int rv;
3133 
3134 	/* Don't do anything until FWREADY updates console address */
3135 	if (bus->console_addr == 0)
3136 		return 0;
3137 
3138 	if (!KSO_ENAB(bus))
3139 		return 0;
3140 
3141 	/* Read console log struct */
3142 	addr = bus->console_addr + OFFSETOF(hndrte_cons_t, log);
3143 	if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)&c->log, sizeof(c->log))) < 0)
3144 		return rv;
3145 
3146 	/* Allocate console buffer (one time only) */
3147 	if (c->buf == NULL) {
3148 		c->bufsize = ltoh32(c->log.buf_size);
3149 		if ((c->buf = MALLOC(bus->dhd->osh, c->bufsize)) == NULL)
3150 			return BCME_NOMEM;
3151 	}
3152 
3153 	idx = ltoh32(c->log.idx);
3154 
3155 	/* Protect against corrupt value */
3156 	if (idx > c->bufsize)
3157 		return BCME_ERROR;
3158 
3159 	/* Skip reading the console buffer if the index pointer has not moved */
3160 	if (idx == c->last)
3161 		return BCME_OK;
3162 
3163 	/* Read the console buffer */
3164 	addr = ltoh32(c->log.buf);
3165 	if ((rv = dhdsdio_membytes(bus, FALSE, addr, c->buf, c->bufsize)) < 0)
3166 		return rv;
3167 
3168 	while (c->last != idx) {
3169 		for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) {
3170 			if (c->last == idx) {
3171 				/* This would output a partial line.  Instead, back up
3172 				 * the buffer pointer and output this line next time around.
3173 				 */
3174 				if (c->last >= n)
3175 					c->last -= n;
3176 				else
3177 					c->last = c->bufsize - n;
3178 				goto break2;
3179 			}
3180 			ch = c->buf[c->last];
3181 			c->last = (c->last + 1) % c->bufsize;
3182 			if (ch == '\n')
3183 				break;
3184 			line[n] = ch;
3185 		}
3186 
3187 		if (n > 0) {
3188 			if (line[n - 1] == '\r')
3189 				n--;
3190 			line[n] = 0;
3191 			printf("CONSOLE: %s\n", line);
3192 		}
3193 	}
3194 break2:
3195 
3196 	return BCME_OK;
3197 }
3198 
3199 static int
dhdsdio_checkdied(dhd_bus_t * bus,char * data,uint size)3200 dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size)
3201 {
3202 	int bcmerror = 0;
3203 	uint msize = 512;
3204 	char *mbuffer = NULL;
3205 	char *console_buffer = NULL;
3206 	uint maxstrlen = 256;
3207 	char *str = NULL;
3208 	trap_t tr;
3209 	sdpcm_shared_t sdpcm_shared;
3210 	struct bcmstrbuf strbuf;
3211 	uint32 console_ptr, console_size, console_index;
3212 	uint8 line[CONSOLE_LINE_MAX], ch;
3213 	uint32 n, i, addr;
3214 	int rv;
3215 
3216 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3217 
3218 	if (DHD_NOCHECKDIED_ON())
3219 		return 0;
3220 
3221 	if (data == NULL) {
3222 		/*
3223 		 * Called after a rx ctrl timeout. "data" is NULL.
3224 		 * allocate memory to trace the trap or assert.
3225 		 */
3226 		size = msize;
3227 		mbuffer = data = MALLOC(bus->dhd->osh, msize);
3228 		if (mbuffer == NULL) {
3229 			DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, msize));
3230 			bcmerror = BCME_NOMEM;
3231 			goto done;
3232 		}
3233 	}
3234 
3235 	if ((str = MALLOC(bus->dhd->osh, maxstrlen)) == NULL) {
3236 		DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, maxstrlen));
3237 		bcmerror = BCME_NOMEM;
3238 		goto done;
3239 	}
3240 
3241 	if ((bcmerror = dhdsdio_readshared(bus, &sdpcm_shared)) < 0)
3242 		goto done;
3243 
3244 	bcm_binit(&strbuf, data, size);
3245 
3246 	bcm_bprintf(&strbuf, "msgtrace address : 0x%08X\nconsole address  : 0x%08X\n",
3247 	            sdpcm_shared.msgtrace_addr, sdpcm_shared.console_addr);
3248 
3249 	if ((sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT) == 0) {
3250 		/* NOTE: Misspelled assert is intentional - DO NOT FIX.
3251 		 * (Avoids conflict with real asserts for programmatic parsing of output.)
3252 		 */
3253 		bcm_bprintf(&strbuf, "Assrt not built in dongle\n");
3254 	}
3255 
3256 	if ((sdpcm_shared.flags & (SDPCM_SHARED_ASSERT|SDPCM_SHARED_TRAP)) == 0) {
3257 		/* NOTE: Misspelled assert is intentional - DO NOT FIX.
3258 		 * (Avoids conflict with real asserts for programmatic parsing of output.)
3259 		 */
3260 		bcm_bprintf(&strbuf, "No trap%s in dongle",
3261 		          (sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT)
3262 		          ?"/assrt" :"");
3263 	} else {
3264 		if (sdpcm_shared.flags & SDPCM_SHARED_ASSERT) {
3265 			/* Download assert */
3266 			bcm_bprintf(&strbuf, "Dongle assert");
3267 			if (sdpcm_shared.assert_exp_addr != 0) {
3268 				str[0] = '\0';
3269 				if ((bcmerror = dhdsdio_membytes(bus, FALSE,
3270 				                                 sdpcm_shared.assert_exp_addr,
3271 				                                 (uint8 *)str, maxstrlen)) < 0)
3272 					goto done;
3273 
3274 				str[maxstrlen - 1] = '\0';
3275 				bcm_bprintf(&strbuf, " expr \"%s\"", str);
3276 			}
3277 
3278 			if (sdpcm_shared.assert_file_addr != 0) {
3279 				str[0] = '\0';
3280 				if ((bcmerror = dhdsdio_membytes(bus, FALSE,
3281 				                                 sdpcm_shared.assert_file_addr,
3282 				                                 (uint8 *)str, maxstrlen)) < 0)
3283 					goto done;
3284 
3285 				str[maxstrlen - 1] = '\0';
3286 				bcm_bprintf(&strbuf, " file \"%s\"", str);
3287 			}
3288 
3289 			bcm_bprintf(&strbuf, " line %d ", sdpcm_shared.assert_line);
3290 		}
3291 
3292 		if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) {
3293 			bus->dhd->dongle_trap_occured = TRUE;
3294 			if ((bcmerror = dhdsdio_membytes(bus, FALSE,
3295 			                                 sdpcm_shared.trap_addr,
3296 			                                 (uint8*)&tr, sizeof(trap_t))) < 0)
3297 				goto done;
3298 
3299 			bcm_bprintf(&strbuf,
3300 			"Dongle trap type 0x%x @ epc 0x%x, cpsr 0x%x, spsr 0x%x, sp 0x%x,"
3301 			            "lp 0x%x, rpc 0x%x Trap offset 0x%x, "
3302 			"r0 0x%x, r1 0x%x, r2 0x%x, r3 0x%x, "
3303 			"r4 0x%x, r5 0x%x, r6 0x%x, r7 0x%x\n\n",
3304 			ltoh32(tr.type), ltoh32(tr.epc), ltoh32(tr.cpsr), ltoh32(tr.spsr),
3305 			ltoh32(tr.r13), ltoh32(tr.r14), ltoh32(tr.pc),
3306 			ltoh32(sdpcm_shared.trap_addr),
3307 			ltoh32(tr.r0), ltoh32(tr.r1), ltoh32(tr.r2), ltoh32(tr.r3),
3308 			ltoh32(tr.r4), ltoh32(tr.r5), ltoh32(tr.r6), ltoh32(tr.r7));
3309 
3310 			addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log);
3311 			if ((rv = dhdsdio_membytes(bus, FALSE, addr,
3312 				(uint8 *)&console_ptr, sizeof(console_ptr))) < 0)
3313 				goto printbuf;
3314 
3315 			addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log.buf_size);
3316 			if ((rv = dhdsdio_membytes(bus, FALSE, addr,
3317 				(uint8 *)&console_size, sizeof(console_size))) < 0)
3318 				goto printbuf;
3319 
3320 			addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log.idx);
3321 			if ((rv = dhdsdio_membytes(bus, FALSE, addr,
3322 				(uint8 *)&console_index, sizeof(console_index))) < 0)
3323 				goto printbuf;
3324 
3325 			console_ptr = ltoh32(console_ptr);
3326 			console_size = ltoh32(console_size);
3327 			console_index = ltoh32(console_index);
3328 
3329 			if (console_size > CONSOLE_BUFFER_MAX ||
3330 				!(console_buffer = MALLOC(bus->dhd->osh, console_size)))
3331 				goto printbuf;
3332 
3333 			if ((rv = dhdsdio_membytes(bus, FALSE, console_ptr,
3334 				(uint8 *)console_buffer, console_size)) < 0)
3335 				goto printbuf;
3336 
3337 			for (i = 0, n = 0; i < console_size; i += n + 1) {
3338 				for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) {
3339 					ch = console_buffer[(console_index + i + n) % console_size];
3340 					if (ch == '\n')
3341 						break;
3342 					line[n] = ch;
3343 				}
3344 
3345 
3346 				if (n > 0) {
3347 					if (line[n - 1] == '\r')
3348 						n--;
3349 					line[n] = 0;
3350 					/* Don't use DHD_ERROR macro since we print
3351 					 * a lot of information quickly. The macro
3352 					 * will truncate a lot of the printfs
3353 					 */
3354 
3355 					if (dhd_msg_level & DHD_ERROR_VAL)
3356 						printf("CONSOLE: %s\n", line);
3357 				}
3358 			}
3359 		}
3360 	}
3361 
3362 printbuf:
3363 	if (sdpcm_shared.flags & (SDPCM_SHARED_ASSERT | SDPCM_SHARED_TRAP)) {
3364 		DHD_ERROR(("%s: %s\n", __FUNCTION__, strbuf.origbuf));
3365 	}
3366 
3367 
3368 done:
3369 	if (mbuffer)
3370 		MFREE(bus->dhd->osh, mbuffer, msize);
3371 	if (str)
3372 		MFREE(bus->dhd->osh, str, maxstrlen);
3373 	if (console_buffer)
3374 		MFREE(bus->dhd->osh, console_buffer, console_size);
3375 
3376 	return bcmerror;
3377 }
3378 #endif /* #ifdef DHD_DEBUG */
3379 
3380 
3381 int
dhdsdio_downloadvars(dhd_bus_t * bus,void * arg,int len)3382 dhdsdio_downloadvars(dhd_bus_t *bus, void *arg, int len)
3383 {
3384 	int bcmerror = BCME_OK;
3385 
3386 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3387 
3388 	/* Basic sanity checks */
3389 	if (bus->dhd->up) {
3390 		bcmerror = BCME_NOTDOWN;
3391 		goto err;
3392 	}
3393 	if (!len) {
3394 		bcmerror = BCME_BUFTOOSHORT;
3395 		goto err;
3396 	}
3397 
3398 	/* Free the old ones and replace with passed variables */
3399 	if (bus->vars)
3400 		MFREE(bus->dhd->osh, bus->vars, bus->varsz);
3401 
3402 	bus->vars = MALLOC(bus->dhd->osh, len);
3403 	bus->varsz = bus->vars ? len : 0;
3404 	if (bus->vars == NULL) {
3405 		bcmerror = BCME_NOMEM;
3406 		goto err;
3407 	}
3408 
3409 	/* Copy the passed variables, which should include the terminating double-null */
3410 	bcopy(arg, bus->vars, bus->varsz);
3411 err:
3412 	return bcmerror;
3413 }
3414 
3415 #ifdef DHD_DEBUG
3416 
3417 #define CC_PLL_CHIPCTRL_SERIAL_ENAB		(1  << 24)
3418 #define CC_CHIPCTRL_JTAG_SEL			(1  << 3)
3419 #define CC_CHIPCTRL_GPIO_SEL				(0x3)
3420 #define CC_PLL_CHIPCTRL_SERIAL_ENAB_4334	(1  << 28)
3421 
3422 static int
dhd_serialconsole(dhd_bus_t * bus,bool set,bool enable,int * bcmerror)3423 dhd_serialconsole(dhd_bus_t *bus, bool set, bool enable, int *bcmerror)
3424 {
3425 	int int_val;
3426 	uint32 addr, data, uart_enab = 0;
3427 	uint32 jtag_sel = CC_CHIPCTRL_JTAG_SEL;
3428 	uint32 gpio_sel = CC_CHIPCTRL_GPIO_SEL;
3429 
3430 	addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr);
3431 	data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data);
3432 	*bcmerror = 0;
3433 
3434 	bcmsdh_reg_write(bus->sdh, addr, 4, 1);
3435 	if (bcmsdh_regfail(bus->sdh)) {
3436 		*bcmerror = BCME_SDIO_ERROR;
3437 		return -1;
3438 	}
3439 	int_val = bcmsdh_reg_read(bus->sdh, data, 4);
3440 	if (bcmsdh_regfail(bus->sdh)) {
3441 		*bcmerror = BCME_SDIO_ERROR;
3442 		return -1;
3443 	}
3444 	if (bus->sih->chip == BCM4330_CHIP_ID) {
3445 		uart_enab = CC_PLL_CHIPCTRL_SERIAL_ENAB;
3446 	}
3447 	else if (bus->sih->chip == BCM4334_CHIP_ID ||
3448 		bus->sih->chip == BCM43340_CHIP_ID ||
3449 		bus->sih->chip == BCM43341_CHIP_ID) {
3450 		if (enable) {
3451 			/* Moved to PMU chipcontrol 1 from 4330 */
3452 			int_val &= ~gpio_sel;
3453 			int_val |= jtag_sel;
3454 		} else {
3455 			int_val |= gpio_sel;
3456 			int_val &= ~jtag_sel;
3457 		}
3458 		uart_enab = CC_PLL_CHIPCTRL_SERIAL_ENAB_4334;
3459 	}
3460 
3461 	if (!set)
3462 		return (int_val & uart_enab);
3463 	if (enable)
3464 		int_val |= uart_enab;
3465 	else
3466 		int_val &= ~uart_enab;
3467 	bcmsdh_reg_write(bus->sdh, data, 4, int_val);
3468 	if (bcmsdh_regfail(bus->sdh)) {
3469 		*bcmerror = BCME_SDIO_ERROR;
3470 		return -1;
3471 	}
3472 	if (bus->sih->chip == BCM4330_CHIP_ID) {
3473 		uint32 chipcontrol;
3474 		addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol);
3475 		chipcontrol = bcmsdh_reg_read(bus->sdh, addr, 4);
3476 		chipcontrol &= ~jtag_sel;
3477 		if (enable) {
3478 			chipcontrol |=  jtag_sel;
3479 			chipcontrol &= ~gpio_sel;
3480 		}
3481 		bcmsdh_reg_write(bus->sdh, addr, 4, chipcontrol);
3482 	}
3483 
3484 	return (int_val & uart_enab);
3485 }
3486 #endif
3487 
3488 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)3489 dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const char *name,
3490                 void *params, int plen, void *arg, int len, int val_size)
3491 {
3492 	int bcmerror = 0;
3493 	int32 int_val = 0;
3494 	bool bool_val = 0;
3495 
3496 	DHD_TRACE(("%s: Enter, action %d name %s params %p plen %d arg %p len %d val_size %d\n",
3497 	           __FUNCTION__, actionid, name, params, plen, arg, len, val_size));
3498 
3499 	if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0)
3500 		goto exit;
3501 
3502 	if (plen >= (int)sizeof(int_val))
3503 		bcopy(params, &int_val, sizeof(int_val));
3504 
3505 	bool_val = (int_val != 0) ? TRUE : FALSE;
3506 
3507 
3508 	/* Some ioctls use the bus */
3509 	dhd_os_sdlock(bus->dhd);
3510 
3511 	/* Check if dongle is in reset. If so, only allow DEVRESET iovars */
3512 	if (bus->dhd->dongle_reset && !(actionid == IOV_SVAL(IOV_DEVRESET) ||
3513 	                                actionid == IOV_GVAL(IOV_DEVRESET))) {
3514 		bcmerror = BCME_NOTREADY;
3515 		goto exit;
3516 	}
3517 
3518 	/*
3519 	 * Special handling for keepSdioOn: New SDIO Wake-up Mechanism
3520 	 */
3521 	if ((vi->varid == IOV_KSO) && (IOV_ISSET(actionid))) {
3522 		dhdsdio_clk_kso_iovar(bus, bool_val);
3523 		goto exit;
3524 	} else if ((vi->varid == IOV_DEVSLEEP) && (IOV_ISSET(actionid))) {
3525 		{
3526 			dhdsdio_clk_devsleep_iovar(bus, bool_val);
3527 			if (!SLPAUTO_ENAB(bus) && (bool_val == FALSE) && (bus->ipend)) {
3528 				DHD_ERROR(("INT pending in devsleep 1, dpc_sched: %d\n",
3529 					bus->dpc_sched));
3530 				if (!bus->dpc_sched) {
3531 					bus->dpc_sched = TRUE;
3532 					dhd_sched_dpc(bus->dhd);
3533 				}
3534 			}
3535 		}
3536 		goto exit;
3537 	}
3538 
3539 	/* Handle sleep stuff before any clock mucking */
3540 	if (vi->varid == IOV_SLEEP) {
3541 		if (IOV_ISSET(actionid)) {
3542 			bcmerror = dhdsdio_bussleep(bus, bool_val);
3543 		} else {
3544 			int_val = (int32)bus->sleeping;
3545 			bcopy(&int_val, arg, val_size);
3546 		}
3547 		goto exit;
3548 	}
3549 
3550 	/* Request clock to allow SDIO accesses */
3551 	if (!bus->dhd->dongle_reset) {
3552 		BUS_WAKE(bus);
3553 		dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
3554 	}
3555 
3556 	switch (actionid) {
3557 	case IOV_GVAL(IOV_INTR):
3558 		int_val = (int32)bus->intr;
3559 		bcopy(&int_val, arg, val_size);
3560 		break;
3561 
3562 	case IOV_SVAL(IOV_INTR):
3563 		bus->intr = bool_val;
3564 		bus->intdis = FALSE;
3565 		if (bus->dhd->up) {
3566 			if (bus->intr) {
3567 				DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__));
3568 				bcmsdh_intr_enable(bus->sdh);
3569 			} else {
3570 				DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
3571 				bcmsdh_intr_disable(bus->sdh);
3572 			}
3573 		}
3574 		break;
3575 
3576 	case IOV_GVAL(IOV_POLLRATE):
3577 		int_val = (int32)bus->pollrate;
3578 		bcopy(&int_val, arg, val_size);
3579 		break;
3580 
3581 	case IOV_SVAL(IOV_POLLRATE):
3582 		bus->pollrate = (uint)int_val;
3583 		bus->poll = (bus->pollrate != 0);
3584 		break;
3585 
3586 	case IOV_GVAL(IOV_IDLETIME):
3587 		int_val = bus->idletime;
3588 		bcopy(&int_val, arg, val_size);
3589 		break;
3590 
3591 	case IOV_SVAL(IOV_IDLETIME):
3592 		if ((int_val < 0) && (int_val != DHD_IDLE_IMMEDIATE)) {
3593 			bcmerror = BCME_BADARG;
3594 		} else {
3595 			bus->idletime = int_val;
3596 		}
3597 		break;
3598 
3599 	case IOV_GVAL(IOV_IDLECLOCK):
3600 		int_val = (int32)bus->idleclock;
3601 		bcopy(&int_val, arg, val_size);
3602 		break;
3603 
3604 	case IOV_SVAL(IOV_IDLECLOCK):
3605 		bus->idleclock = int_val;
3606 		break;
3607 
3608 	case IOV_GVAL(IOV_SD1IDLE):
3609 		int_val = (int32)sd1idle;
3610 		bcopy(&int_val, arg, val_size);
3611 		break;
3612 
3613 	case IOV_SVAL(IOV_SD1IDLE):
3614 		sd1idle = bool_val;
3615 		break;
3616 
3617 
3618 	case IOV_SVAL(IOV_MEMBYTES):
3619 	case IOV_GVAL(IOV_MEMBYTES):
3620 	{
3621 		uint32 address;
3622 		uint size, dsize;
3623 		uint8 *data;
3624 
3625 		bool set = (actionid == IOV_SVAL(IOV_MEMBYTES));
3626 
3627 		ASSERT(plen >= 2*sizeof(int));
3628 
3629 		address = (uint32)int_val;
3630 		bcopy((char *)params + sizeof(int_val), &int_val, sizeof(int_val));
3631 		size = (uint)int_val;
3632 
3633 		/* Do some validation */
3634 		dsize = set ? plen - (2 * sizeof(int)) : len;
3635 		if (dsize < size) {
3636 			DHD_ERROR(("%s: error on %s membytes, addr 0x%08x size %d dsize %d\n",
3637 			           __FUNCTION__, (set ? "set" : "get"), address, size, dsize));
3638 			bcmerror = BCME_BADARG;
3639 			break;
3640 		}
3641 
3642 		DHD_INFO(("%s: Request to %s %d bytes at address 0x%08x\n", __FUNCTION__,
3643 		          (set ? "write" : "read"), size, address));
3644 
3645 		/* check if CR4 */
3646 		if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
3647 			/*
3648 			 * If address is start of RAM (i.e. a downloaded image),
3649 			 * store the reset instruction to be written in 0
3650 			 */
3651 			if (address == bus->dongle_ram_base) {
3652 				bus->resetinstr = *(((uint32*)params) + 2);
3653 			}
3654 		} else {
3655 		/* If we know about SOCRAM, check for a fit */
3656 		if ((bus->orig_ramsize) &&
3657 		    ((address > bus->orig_ramsize) || (address + size > bus->orig_ramsize)))
3658 		{
3659 			uint8 enable, protect, remap;
3660 			si_socdevram(bus->sih, FALSE, &enable, &protect, &remap);
3661 			if (!enable || protect) {
3662 				DHD_ERROR(("%s: ramsize 0x%08x doesn't have %d bytes at 0x%08x\n",
3663 					__FUNCTION__, bus->orig_ramsize, size, address));
3664 				DHD_ERROR(("%s: socram enable %d, protect %d\n",
3665 					__FUNCTION__, enable, protect));
3666 				bcmerror = BCME_BADARG;
3667 				break;
3668 			}
3669 
3670 			if (!REMAP_ENAB(bus) && (address >= SOCDEVRAM_ARM_ADDR)) {
3671 				uint32 devramsize = si_socdevram_size(bus->sih);
3672 				if ((address < SOCDEVRAM_ARM_ADDR) ||
3673 					(address + size > (SOCDEVRAM_ARM_ADDR + devramsize))) {
3674 					DHD_ERROR(("%s: bad address 0x%08x, size 0x%08x\n",
3675 						__FUNCTION__, address, size));
3676 					DHD_ERROR(("%s: socram range 0x%08x,size 0x%08x\n",
3677 						__FUNCTION__, SOCDEVRAM_ARM_ADDR, devramsize));
3678 					bcmerror = BCME_BADARG;
3679 					break;
3680 				}
3681 				/* move it such that address is real now */
3682 				address -= SOCDEVRAM_ARM_ADDR;
3683 				address += SOCDEVRAM_BP_ADDR;
3684 				DHD_INFO(("%s: Request to %s %d bytes @ Mapped address 0x%08x\n",
3685 					__FUNCTION__, (set ? "write" : "read"), size, address));
3686 			} else if (REMAP_ENAB(bus) && REMAP_ISADDR(bus, address) && remap) {
3687 				/* Can not access remap region while devram remap bit is set
3688 				 * ROM content would be returned in this case
3689 				 */
3690 				DHD_ERROR(("%s: Need to disable remap for address 0x%08x\n",
3691 					__FUNCTION__, address));
3692 				bcmerror = BCME_ERROR;
3693 				break;
3694 			}
3695 		}
3696 		}
3697 
3698 		/* Generate the actual data pointer */
3699 		data = set ? (uint8*)params + 2 * sizeof(int): (uint8*)arg;
3700 
3701 		/* Call to do the transfer */
3702 		bcmerror = dhdsdio_membytes(bus, set, address, data, size);
3703 
3704 		break;
3705 	}
3706 
3707 	case IOV_GVAL(IOV_RAMSIZE):
3708 		int_val = (int32)bus->ramsize;
3709 		bcopy(&int_val, arg, val_size);
3710 		break;
3711 
3712 	case IOV_GVAL(IOV_RAMSTART):
3713 		int_val = (int32)bus->dongle_ram_base;
3714 		bcopy(&int_val, arg, val_size);
3715 		break;
3716 
3717 	case IOV_GVAL(IOV_SDIOD_DRIVE):
3718 		int_val = (int32)dhd_sdiod_drive_strength;
3719 		bcopy(&int_val, arg, val_size);
3720 		break;
3721 
3722 	case IOV_SVAL(IOV_SDIOD_DRIVE):
3723 		dhd_sdiod_drive_strength = int_val;
3724 		si_sdiod_drive_strength_init(bus->sih, bus->dhd->osh, dhd_sdiod_drive_strength);
3725 		break;
3726 
3727 	case IOV_SVAL(IOV_SET_DOWNLOAD_STATE):
3728 		bcmerror = dhdsdio_download_state(bus, bool_val);
3729 		break;
3730 
3731 	case IOV_SVAL(IOV_SOCRAM_STATE):
3732 		bcmerror = dhdsdio_download_state(bus, bool_val);
3733 		break;
3734 
3735 	case IOV_SVAL(IOV_VARS):
3736 		bcmerror = dhdsdio_downloadvars(bus, arg, len);
3737 		break;
3738 
3739 	case IOV_GVAL(IOV_READAHEAD):
3740 		int_val = (int32)dhd_readahead;
3741 		bcopy(&int_val, arg, val_size);
3742 		break;
3743 
3744 	case IOV_SVAL(IOV_READAHEAD):
3745 		if (bool_val && !dhd_readahead)
3746 			bus->nextlen = 0;
3747 		dhd_readahead = bool_val;
3748 		break;
3749 
3750 	case IOV_GVAL(IOV_SDRXCHAIN):
3751 		int_val = (int32)bus->use_rxchain;
3752 		bcopy(&int_val, arg, val_size);
3753 		break;
3754 
3755 	case IOV_SVAL(IOV_SDRXCHAIN):
3756 		if (bool_val && !bus->sd_rxchain)
3757 			bcmerror = BCME_UNSUPPORTED;
3758 		else
3759 			bus->use_rxchain = bool_val;
3760 		break;
3761 	case IOV_GVAL(IOV_ALIGNCTL):
3762 		int_val = (int32)dhd_alignctl;
3763 		bcopy(&int_val, arg, val_size);
3764 		break;
3765 
3766 	case IOV_SVAL(IOV_ALIGNCTL):
3767 		dhd_alignctl = bool_val;
3768 		break;
3769 
3770 	case IOV_GVAL(IOV_SDALIGN):
3771 		int_val = DHD_SDALIGN;
3772 		bcopy(&int_val, arg, val_size);
3773 		break;
3774 
3775 #ifdef DHD_DEBUG
3776 	case IOV_GVAL(IOV_VARS):
3777 		if (bus->varsz < (uint)len)
3778 			bcopy(bus->vars, arg, bus->varsz);
3779 		else
3780 			bcmerror = BCME_BUFTOOSHORT;
3781 		break;
3782 #endif /* DHD_DEBUG */
3783 
3784 #ifdef DHD_DEBUG
3785 	case IOV_GVAL(IOV_SDREG):
3786 	{
3787 		sdreg_t *sd_ptr;
3788 		uint32 addr, size;
3789 
3790 		sd_ptr = (sdreg_t *)params;
3791 
3792 		addr = (uintptr)bus->regs + sd_ptr->offset;
3793 		size = sd_ptr->func;
3794 		int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size);
3795 		if (bcmsdh_regfail(bus->sdh))
3796 			bcmerror = BCME_SDIO_ERROR;
3797 		bcopy(&int_val, arg, sizeof(int32));
3798 		break;
3799 	}
3800 
3801 	case IOV_SVAL(IOV_SDREG):
3802 	{
3803 		sdreg_t *sd_ptr;
3804 		uint32 addr, size;
3805 
3806 		sd_ptr = (sdreg_t *)params;
3807 
3808 		addr = (uintptr)bus->regs + sd_ptr->offset;
3809 		size = sd_ptr->func;
3810 		bcmsdh_reg_write(bus->sdh, addr, size, sd_ptr->value);
3811 		if (bcmsdh_regfail(bus->sdh))
3812 			bcmerror = BCME_SDIO_ERROR;
3813 		break;
3814 	}
3815 
3816 	/* Same as above, but offset is not backplane (not SDIO core) */
3817 	case IOV_GVAL(IOV_SBREG):
3818 	{
3819 		sdreg_t sdreg;
3820 		uint32 addr, size;
3821 
3822 		bcopy(params, &sdreg, sizeof(sdreg));
3823 
3824 		addr = SI_ENUM_BASE + sdreg.offset;
3825 		size = sdreg.func;
3826 		int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size);
3827 		if (bcmsdh_regfail(bus->sdh))
3828 			bcmerror = BCME_SDIO_ERROR;
3829 		bcopy(&int_val, arg, sizeof(int32));
3830 		break;
3831 	}
3832 
3833 	case IOV_SVAL(IOV_SBREG):
3834 	{
3835 		sdreg_t sdreg;
3836 		uint32 addr, size;
3837 
3838 		bcopy(params, &sdreg, sizeof(sdreg));
3839 
3840 		addr = SI_ENUM_BASE + sdreg.offset;
3841 		size = sdreg.func;
3842 		bcmsdh_reg_write(bus->sdh, addr, size, sdreg.value);
3843 		if (bcmsdh_regfail(bus->sdh))
3844 			bcmerror = BCME_SDIO_ERROR;
3845 		break;
3846 	}
3847 
3848 	case IOV_GVAL(IOV_SDCIS):
3849 	{
3850 		*(char *)arg = 0;
3851 
3852 		bcmstrcat(arg, "\nFunc 0\n");
3853 		bcmsdh_cis_read(bus->sdh, 0x10, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
3854 		bcmstrcat(arg, "\nFunc 1\n");
3855 		bcmsdh_cis_read(bus->sdh, 0x11, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
3856 		bcmstrcat(arg, "\nFunc 2\n");
3857 		bcmsdh_cis_read(bus->sdh, 0x12, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
3858 		break;
3859 	}
3860 
3861 	case IOV_GVAL(IOV_FORCEEVEN):
3862 		int_val = (int32)forcealign;
3863 		bcopy(&int_val, arg, val_size);
3864 		break;
3865 
3866 	case IOV_SVAL(IOV_FORCEEVEN):
3867 		forcealign = bool_val;
3868 		break;
3869 
3870 	case IOV_GVAL(IOV_TXBOUND):
3871 		int_val = (int32)dhd_txbound;
3872 		bcopy(&int_val, arg, val_size);
3873 		break;
3874 
3875 	case IOV_SVAL(IOV_TXBOUND):
3876 		dhd_txbound = (uint)int_val;
3877 		break;
3878 
3879 	case IOV_GVAL(IOV_RXBOUND):
3880 		int_val = (int32)dhd_rxbound;
3881 		bcopy(&int_val, arg, val_size);
3882 		break;
3883 
3884 	case IOV_SVAL(IOV_RXBOUND):
3885 		dhd_rxbound = (uint)int_val;
3886 		break;
3887 
3888 	case IOV_GVAL(IOV_TXMINMAX):
3889 		int_val = (int32)dhd_txminmax;
3890 		bcopy(&int_val, arg, val_size);
3891 		break;
3892 
3893 	case IOV_SVAL(IOV_TXMINMAX):
3894 		dhd_txminmax = (uint)int_val;
3895 		break;
3896 
3897 	case IOV_GVAL(IOV_SERIALCONS):
3898 		int_val = dhd_serialconsole(bus, FALSE, 0, &bcmerror);
3899 		if (bcmerror != 0)
3900 			break;
3901 
3902 		bcopy(&int_val, arg, val_size);
3903 		break;
3904 
3905 	case IOV_SVAL(IOV_SERIALCONS):
3906 		dhd_serialconsole(bus, TRUE, bool_val, &bcmerror);
3907 		break;
3908 
3909 
3910 
3911 #endif /* DHD_DEBUG */
3912 
3913 
3914 #ifdef SDTEST
3915 	case IOV_GVAL(IOV_EXTLOOP):
3916 		int_val = (int32)bus->ext_loop;
3917 		bcopy(&int_val, arg, val_size);
3918 		break;
3919 
3920 	case IOV_SVAL(IOV_EXTLOOP):
3921 		bus->ext_loop = bool_val;
3922 		break;
3923 
3924 	case IOV_GVAL(IOV_PKTGEN):
3925 		bcmerror = dhdsdio_pktgen_get(bus, arg);
3926 		break;
3927 
3928 	case IOV_SVAL(IOV_PKTGEN):
3929 		bcmerror = dhdsdio_pktgen_set(bus, arg);
3930 		break;
3931 #endif /* SDTEST */
3932 
3933 #if defined(SDIO_CRC_ERROR_FIX)
3934 	case IOV_GVAL(IOV_WATERMARK):
3935 		int_val = (int32)watermark;
3936 		bcopy(&int_val, arg, val_size);
3937 		break;
3938 
3939 	case IOV_SVAL(IOV_WATERMARK):
3940 		watermark = (uint)int_val;
3941 		watermark = (watermark > SBSDIO_WATERMARK_MASK) ? SBSDIO_WATERMARK_MASK : watermark;
3942 		DHD_ERROR(("Setting watermark as 0x%x.\n", watermark));
3943 		bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, (uint8)watermark, NULL);
3944 		break;
3945 
3946 	case IOV_GVAL(IOV_MESBUSYCTRL):
3947 		int_val = (int32)mesbusyctrl;
3948 		bcopy(&int_val, arg, val_size);
3949 		break;
3950 
3951 	case IOV_SVAL(IOV_MESBUSYCTRL):
3952 		mesbusyctrl = (uint)int_val;
3953 		mesbusyctrl = (mesbusyctrl > SBSDIO_MESBUSYCTRL_MASK)
3954 			? SBSDIO_MESBUSYCTRL_MASK : mesbusyctrl;
3955 		DHD_ERROR(("Setting mesbusyctrl as 0x%x.\n", mesbusyctrl));
3956 		bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL,
3957 			((uint8)mesbusyctrl | 0x80), NULL);
3958 		break;
3959 #endif /* SDIO_CRC_ERROR_FIX */
3960 
3961 
3962 	case IOV_GVAL(IOV_DONGLEISOLATION):
3963 		int_val = bus->dhd->dongle_isolation;
3964 		bcopy(&int_val, arg, val_size);
3965 		break;
3966 
3967 	case IOV_SVAL(IOV_DONGLEISOLATION):
3968 		bus->dhd->dongle_isolation = bool_val;
3969 		break;
3970 
3971 	case IOV_SVAL(IOV_DEVRESET):
3972 		DHD_TRACE(("%s: Called set IOV_DEVRESET=%d dongle_reset=%d busstate=%d\n",
3973 		           __FUNCTION__, bool_val, bus->dhd->dongle_reset,
3974 		           bus->dhd->busstate));
3975 
3976 		ASSERT(bus->dhd->osh);
3977 		/* ASSERT(bus->cl_devid); */
3978 
3979 		dhd_bus_devreset(bus->dhd, (uint8)bool_val);
3980 
3981 		break;
3982 #ifdef SOFTAP
3983 	case IOV_GVAL(IOV_FWPATH):
3984 	{
3985 		uint32  fw_path_len;
3986 
3987 		fw_path_len = strlen(bus->fw_path);
3988 		DHD_INFO(("[softap] get fwpath, l=%d\n", len));
3989 
3990 		if (fw_path_len > len-1) {
3991 			bcmerror = BCME_BUFTOOSHORT;
3992 			break;
3993 		}
3994 
3995 		if (fw_path_len) {
3996 			bcopy(bus->fw_path, arg, fw_path_len);
3997 			((uchar*)arg)[fw_path_len] = 0;
3998 		}
3999 		break;
4000 	}
4001 
4002 	case IOV_SVAL(IOV_FWPATH):
4003 		DHD_INFO(("[softap] set fwpath, idx=%d\n", int_val));
4004 
4005 		switch (int_val) {
4006 		case 1:
4007 			bus->fw_path = fw_path; /* ordinary one */
4008 			break;
4009 		case 2:
4010 			bus->fw_path = fw_path2;
4011 			break;
4012 		default:
4013 			bcmerror = BCME_BADARG;
4014 			break;
4015 		}
4016 
4017 		DHD_INFO(("[softap] new fw path: %s\n", (bus->fw_path[0] ? bus->fw_path : "NULL")));
4018 		break;
4019 
4020 #endif /* SOFTAP */
4021 	case IOV_GVAL(IOV_DEVRESET):
4022 		DHD_TRACE(("%s: Called get IOV_DEVRESET\n", __FUNCTION__));
4023 
4024 		/* Get its status */
4025 		int_val = (bool) bus->dhd->dongle_reset;
4026 		bcopy(&int_val, arg, val_size);
4027 
4028 		break;
4029 
4030 	case IOV_GVAL(IOV_KSO):
4031 		int_val = dhdsdio_sleepcsr_get(bus);
4032 		bcopy(&int_val, arg, val_size);
4033 		break;
4034 
4035 	case IOV_GVAL(IOV_DEVCAP):
4036 		int_val = dhdsdio_devcap_get(bus);
4037 		bcopy(&int_val, arg, val_size);
4038 		break;
4039 
4040 	case IOV_SVAL(IOV_DEVCAP):
4041 		dhdsdio_devcap_set(bus, (uint8) int_val);
4042 		break;
4043 
4044 #ifdef BCMSDIOH_TXGLOM
4045 	case IOV_GVAL(IOV_TXGLOMSIZE):
4046 		int_val = (int32)bus->glomsize;
4047 		bcopy(&int_val, arg, val_size);
4048 		break;
4049 
4050 	case IOV_SVAL(IOV_TXGLOMSIZE):
4051 		if (int_val > SDPCM_MAXGLOM_SIZE) {
4052 			bcmerror = BCME_ERROR;
4053 		} else {
4054 			bus->glomsize = (uint)int_val;
4055 		}
4056 		break;
4057 	case IOV_GVAL(IOV_TXGLOMMODE):
4058 		int_val = (int32)bus->glom_mode;
4059 		bcopy(&int_val, arg, val_size);
4060 		break;
4061 
4062 	case IOV_SVAL(IOV_TXGLOMMODE):
4063 		if ((int_val != SDPCM_TXGLOM_CPY) && (int_val != SDPCM_TXGLOM_MDESC)) {
4064 			bcmerror = BCME_RANGE;
4065 		} else {
4066 			if ((bus->glom_mode = bcmsdh_set_mode(bus->sdh, (uint)int_val)) != int_val)
4067 				bcmerror = BCME_ERROR;
4068 		}
4069 		break;
4070 #endif /* BCMSDIOH_TXGLOM */
4071 
4072 	case IOV_SVAL(IOV_HANGREPORT):
4073 		bus->dhd->hang_report = bool_val;
4074 		DHD_ERROR(("%s: Set hang_report as %d\n", __FUNCTION__, bus->dhd->hang_report));
4075 		break;
4076 
4077 	case IOV_GVAL(IOV_HANGREPORT):
4078 		int_val = (int32)bus->dhd->hang_report;
4079 		bcopy(&int_val, arg, val_size);
4080 		break;
4081 	default:
4082 		bcmerror = BCME_UNSUPPORTED;
4083 		break;
4084 	}
4085 
4086 exit:
4087 	if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
4088 		bus->activity = FALSE;
4089 		dhdsdio_clkctl(bus, CLK_NONE, TRUE);
4090 	}
4091 
4092 	dhd_os_sdunlock(bus->dhd);
4093 
4094 	return bcmerror;
4095 }
4096 
4097 static int
dhdsdio_write_vars(dhd_bus_t * bus)4098 dhdsdio_write_vars(dhd_bus_t *bus)
4099 {
4100 	int bcmerror = 0;
4101 	uint32 varsize, phys_size;
4102 	uint32 varaddr;
4103 	uint8 *vbuffer;
4104 	uint32 varsizew;
4105 #ifdef DHD_DEBUG
4106 	uint8 *nvram_ularray;
4107 #endif /* DHD_DEBUG */
4108 
4109 	/* Even if there are no vars are to be written, we still need to set the ramsize. */
4110 	varsize = bus->varsz ? ROUNDUP(bus->varsz, 4) : 0;
4111 	varaddr = (bus->ramsize - 4) - varsize;
4112 
4113 	varaddr += bus->dongle_ram_base;
4114 
4115 	if (bus->vars) {
4116 		if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 7)) {
4117 			if (((varaddr & 0x3C) == 0x3C) && (varsize > 4)) {
4118 				DHD_ERROR(("PR85623WAR in place\n"));
4119 				varsize += 4;
4120 				varaddr -= 4;
4121 			}
4122 		}
4123 
4124 		vbuffer = (uint8 *)MALLOC(bus->dhd->osh, varsize);
4125 		if (!vbuffer)
4126 			return BCME_NOMEM;
4127 
4128 		bzero(vbuffer, varsize);
4129 		bcopy(bus->vars, vbuffer, bus->varsz);
4130 
4131 		/* Write the vars list */
4132 		bcmerror = dhdsdio_membytes(bus, TRUE, varaddr, vbuffer, varsize);
4133 #ifdef DHD_DEBUG
4134 		/* Verify NVRAM bytes */
4135 		DHD_INFO(("Compare NVRAM dl & ul; varsize=%d\n", varsize));
4136 		nvram_ularray = (uint8*)MALLOC(bus->dhd->osh, varsize);
4137 		if (!nvram_ularray)
4138 			return BCME_NOMEM;
4139 
4140 		/* Upload image to verify downloaded contents. */
4141 		memset(nvram_ularray, 0xaa, varsize);
4142 
4143 		/* Read the vars list to temp buffer for comparison */
4144 		bcmerror = dhdsdio_membytes(bus, FALSE, varaddr, nvram_ularray, varsize);
4145 		if (bcmerror) {
4146 				DHD_ERROR(("%s: error %d on reading %d nvram bytes at 0x%08x\n",
4147 					__FUNCTION__, bcmerror, varsize, varaddr));
4148 		}
4149 		/* Compare the org NVRAM with the one read from RAM */
4150 		if (memcmp(vbuffer, nvram_ularray, varsize)) {
4151 			DHD_ERROR(("%s: Downloaded NVRAM image is corrupted.\n", __FUNCTION__));
4152 		} else
4153 			DHD_ERROR(("%s: Download, Upload and compare of NVRAM succeeded.\n",
4154 			__FUNCTION__));
4155 
4156 		MFREE(bus->dhd->osh, nvram_ularray, varsize);
4157 #endif /* DHD_DEBUG */
4158 
4159 		MFREE(bus->dhd->osh, vbuffer, varsize);
4160 	}
4161 
4162 	phys_size = REMAP_ENAB(bus) ? bus->ramsize : bus->orig_ramsize;
4163 
4164 	phys_size += bus->dongle_ram_base;
4165 
4166 	/* adjust to the user specified RAM */
4167 	DHD_INFO(("Physical memory size: %d, usable memory size: %d\n",
4168 		phys_size, bus->ramsize));
4169 	DHD_INFO(("Vars are at %d, orig varsize is %d\n",
4170 		varaddr, varsize));
4171 	varsize = ((phys_size - 4) - varaddr);
4172 
4173 	/*
4174 	 * Determine the length token:
4175 	 * Varsize, converted to words, in lower 16-bits, checksum in upper 16-bits.
4176 	 */
4177 	if (bcmerror) {
4178 		varsizew = 0;
4179 	} else {
4180 		varsizew = varsize / 4;
4181 		varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF);
4182 		varsizew = htol32(varsizew);
4183 	}
4184 
4185 	DHD_INFO(("New varsize is %d, length token=0x%08x\n", varsize, varsizew));
4186 
4187 	/* Write the length token to the last word */
4188 	bcmerror = dhdsdio_membytes(bus, TRUE, (phys_size - 4),
4189 		(uint8*)&varsizew, 4);
4190 
4191 	return bcmerror;
4192 }
4193 
4194 static int
dhdsdio_download_state(dhd_bus_t * bus,bool enter)4195 dhdsdio_download_state(dhd_bus_t *bus, bool enter)
4196 {
4197 	uint retries;
4198 	int bcmerror = 0;
4199 	int foundcr4 = 0;
4200 
4201 	if (!bus->sih)
4202 		return BCME_ERROR;
4203 	/* To enter download state, disable ARM and reset SOCRAM.
4204 	 * To exit download state, simply reset ARM (default is RAM boot).
4205 	 */
4206 	if (enter) {
4207 		bus->alp_only = TRUE;
4208 
4209 		if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) &&
4210 		    !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) {
4211 			if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
4212 				foundcr4 = 1;
4213 			} else {
4214 				DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__));
4215 				bcmerror = BCME_ERROR;
4216 				goto fail;
4217 			}
4218 		}
4219 
4220 		if (!foundcr4) {
4221 			si_core_disable(bus->sih, 0);
4222 			if (bcmsdh_regfail(bus->sdh)) {
4223 				bcmerror = BCME_SDIO_ERROR;
4224 				goto fail;
4225 			}
4226 
4227 			if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) {
4228 				DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__));
4229 				bcmerror = BCME_ERROR;
4230 				goto fail;
4231 			}
4232 
4233 			si_core_reset(bus->sih, 0, 0);
4234 			if (bcmsdh_regfail(bus->sdh)) {
4235 				DHD_ERROR(("%s: Failure trying reset SOCRAM core?\n",
4236 				           __FUNCTION__));
4237 				bcmerror = BCME_SDIO_ERROR;
4238 				goto fail;
4239 			}
4240 
4241 			/* Disable remap for download */
4242 			if (REMAP_ENAB(bus) && si_socdevram_remap_isenb(bus->sih))
4243 				dhdsdio_devram_remap(bus, FALSE);
4244 
4245 			/* Clear the top bit of memory */
4246 			if (bus->ramsize) {
4247 				uint32 zeros = 0;
4248 				if (dhdsdio_membytes(bus, TRUE, bus->ramsize - 4,
4249 				                     (uint8*)&zeros, 4) < 0) {
4250 					bcmerror = BCME_SDIO_ERROR;
4251 					goto fail;
4252 				}
4253 			}
4254 		} else {
4255 			/* For CR4,
4256 			 * Halt ARM
4257 			 * Remove ARM reset
4258 			 * Read RAM base address [0x18_0000]
4259 			 * [next] Download firmware
4260 			 * [done at else] Populate the reset vector
4261 			 * [done at else] Remove ARM halt
4262 			*/
4263 			/* Halt ARM & remove reset */
4264 			si_core_reset(bus->sih, SICF_CPUHALT, SICF_CPUHALT);
4265 		}
4266 	} else {
4267 		if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
4268 			if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) {
4269 				DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__));
4270 				bcmerror = BCME_ERROR;
4271 				goto fail;
4272 			}
4273 
4274 			if (!si_iscoreup(bus->sih)) {
4275 				DHD_ERROR(("%s: SOCRAM core is down after reset?\n", __FUNCTION__));
4276 				bcmerror = BCME_ERROR;
4277 				goto fail;
4278 			}
4279 
4280 			if ((bcmerror = dhdsdio_write_vars(bus))) {
4281 				DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__));
4282 				goto fail;
4283 			}
4284 
4285 			/* Enable remap before ARM reset but after vars.
4286 			 * No backplane access in remap mode
4287 			 */
4288 			if (REMAP_ENAB(bus) && !si_socdevram_remap_isenb(bus->sih))
4289 				dhdsdio_devram_remap(bus, TRUE);
4290 
4291 			if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) &&
4292 			    !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) {
4293 				DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__));
4294 				bcmerror = BCME_ERROR;
4295 				goto fail;
4296 			}
4297 			W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries);
4298 
4299 
4300 			if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) &&
4301 			    !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) {
4302 				DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__));
4303 				bcmerror = BCME_ERROR;
4304 				goto fail;
4305 			}
4306 		} else {
4307 			/* cr4 has no socram, but tcm's */
4308 			/* write vars */
4309 			if ((bcmerror = dhdsdio_write_vars(bus))) {
4310 				DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__));
4311 				goto fail;
4312 			}
4313 
4314 			if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) &&
4315 			    !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) {
4316 				DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__));
4317 				bcmerror = BCME_ERROR;
4318 				goto fail;
4319 			}
4320 			W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries);
4321 
4322 			/* switch back to arm core again */
4323 			if (!(si_setcore(bus->sih, ARMCR4_CORE_ID, 0))) {
4324 				DHD_ERROR(("%s: Failed to find ARM CR4 core!\n", __FUNCTION__));
4325 				bcmerror = BCME_ERROR;
4326 				goto fail;
4327 			}
4328 			/* write address 0 with reset instruction */
4329 			bcmerror = dhdsdio_membytes(bus, TRUE, 0,
4330 				(uint8 *)&bus->resetinstr, sizeof(bus->resetinstr));
4331 
4332 			/* now remove reset and halt and continue to run CR4 */
4333 		}
4334 
4335 		si_core_reset(bus->sih, 0, 0);
4336 		if (bcmsdh_regfail(bus->sdh)) {
4337 			DHD_ERROR(("%s: Failure trying to reset ARM core?\n", __FUNCTION__));
4338 			bcmerror = BCME_SDIO_ERROR;
4339 			goto fail;
4340 		}
4341 
4342 		/* Allow HT Clock now that the ARM is running. */
4343 		bus->alp_only = FALSE;
4344 
4345 		bus->dhd->busstate = DHD_BUS_LOAD;
4346 	}
4347 
4348 fail:
4349 	/* Always return to SDIOD core */
4350 	if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0))
4351 		si_setcore(bus->sih, SDIOD_CORE_ID, 0);
4352 
4353 	return bcmerror;
4354 }
4355 
4356 int
dhd_bus_iovar_op(dhd_pub_t * dhdp,const char * name,void * params,int plen,void * arg,int len,bool set)4357 dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name,
4358                  void *params, int plen, void *arg, int len, bool set)
4359 {
4360 	dhd_bus_t *bus = dhdp->bus;
4361 	const bcm_iovar_t *vi = NULL;
4362 	int bcmerror = 0;
4363 	int val_size;
4364 	uint32 actionid;
4365 
4366 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4367 
4368 	ASSERT(name);
4369 	ASSERT(len >= 0);
4370 
4371 	/* Get MUST have return space */
4372 	ASSERT(set || (arg && len));
4373 
4374 	/* Set does NOT take qualifiers */
4375 	ASSERT(!set || (!params && !plen));
4376 
4377 	/* Look up var locally; if not found pass to host driver */
4378 	if ((vi = bcm_iovar_lookup(dhdsdio_iovars, name)) == NULL) {
4379 		dhd_os_sdlock(bus->dhd);
4380 
4381 		BUS_WAKE(bus);
4382 
4383 		/* Turn on clock in case SD command needs backplane */
4384 		dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
4385 
4386 		bcmerror = bcmsdh_iovar_op(bus->sdh, name, params, plen, arg, len, set);
4387 
4388 		/* Check for bus configuration changes of interest */
4389 
4390 		/* If it was divisor change, read the new one */
4391 		if (set && strcmp(name, "sd_divisor") == 0) {
4392 			if (bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
4393 			                    &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) {
4394 				bus->sd_divisor = -1;
4395 				DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, name));
4396 			} else {
4397 				DHD_INFO(("%s: noted %s update, value now %d\n",
4398 				          __FUNCTION__, name, bus->sd_divisor));
4399 			}
4400 		}
4401 		/* If it was a mode change, read the new one */
4402 		if (set && strcmp(name, "sd_mode") == 0) {
4403 			if (bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
4404 			                    &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) {
4405 				bus->sd_mode = -1;
4406 				DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, name));
4407 			} else {
4408 				DHD_INFO(("%s: noted %s update, value now %d\n",
4409 				          __FUNCTION__, name, bus->sd_mode));
4410 			}
4411 		}
4412 		/* Similar check for blocksize change */
4413 		if (set && strcmp(name, "sd_blocksize") == 0) {
4414 			int32 fnum = 2;
4415 			if (bcmsdh_iovar_op(bus->sdh, "sd_blocksize", &fnum, sizeof(int32),
4416 			                    &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) {
4417 				bus->blocksize = 0;
4418 				DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize"));
4419 			} else {
4420 				DHD_INFO(("%s: noted %s update, value now %d\n",
4421 				          __FUNCTION__, "sd_blocksize", bus->blocksize));
4422 
4423 				if ((bus->sih->chip == BCM4335_CHIP_ID) ||
4424 					(bus->sih->chip == BCM4339_CHIP_ID))
4425 					dhd_overflow_war(bus);
4426 			}
4427 		}
4428 		bus->roundup = MIN(max_roundup, bus->blocksize);
4429 
4430 		if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
4431 			bus->activity = FALSE;
4432 			dhdsdio_clkctl(bus, CLK_NONE, TRUE);
4433 		}
4434 
4435 		dhd_os_sdunlock(bus->dhd);
4436 		goto exit;
4437 	}
4438 
4439 	DHD_CTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__,
4440 	         name, (set ? "set" : "get"), len, plen));
4441 
4442 	/* set up 'params' pointer in case this is a set command so that
4443 	 * the convenience int and bool code can be common to set and get
4444 	 */
4445 	if (params == NULL) {
4446 		params = arg;
4447 		plen = len;
4448 	}
4449 
4450 	if (vi->type == IOVT_VOID)
4451 		val_size = 0;
4452 	else if (vi->type == IOVT_BUFFER)
4453 		val_size = len;
4454 	else
4455 		/* all other types are integer sized */
4456 		val_size = sizeof(int);
4457 
4458 	actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
4459 	bcmerror = dhdsdio_doiovar(bus, vi, actionid, name, params, plen, arg, len, val_size);
4460 
4461 exit:
4462 	return bcmerror;
4463 }
4464 
4465 void
dhd_bus_stop(struct dhd_bus * bus,bool enforce_mutex)4466 dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex)
4467 {
4468 	osl_t *osh;
4469 	uint32 local_hostintmask;
4470 	uint8 saveclk;
4471 	uint retries;
4472 	int err;
4473 	if (!bus->dhd)
4474 		return;
4475 
4476 	osh = bus->dhd->osh;
4477 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4478 
4479 	bcmsdh_waitlockfree(NULL);
4480 
4481 	if (enforce_mutex)
4482 		dhd_os_sdlock(bus->dhd);
4483 
4484 	if ((bus->dhd->busstate == DHD_BUS_DOWN) || bus->dhd->hang_was_sent) {
4485 		/* if Firmware already hangs disbale any interrupt */
4486 		bus->dhd->busstate = DHD_BUS_DOWN;
4487 		bus->hostintmask = 0;
4488 		bcmsdh_intr_disable(bus->sdh);
4489 	} else {
4490 
4491 		BUS_WAKE(bus);
4492 
4493 		/* Change our idea of bus state */
4494 		bus->dhd->busstate = DHD_BUS_DOWN;
4495 
4496 		if (KSO_ENAB(bus)) {
4497 
4498 		/* Enable clock for device interrupts */
4499 		dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
4500 
4501 		/* Disable and clear interrupts at the chip level also */
4502 		W_SDREG(0, &bus->regs->hostintmask, retries);
4503 		local_hostintmask = bus->hostintmask;
4504 		bus->hostintmask = 0;
4505 
4506 		/* Force clocks on backplane to be sure F2 interrupt propagates */
4507 		saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
4508 		if (!err) {
4509 			bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
4510 			                 (saveclk | SBSDIO_FORCE_HT), &err);
4511 		}
4512 		if (err) {
4513 			DHD_ERROR(("%s: Failed to force clock for F2: err %d\n",
4514 			            __FUNCTION__, err));
4515 		}
4516 
4517 		/* Turn off the bus (F2), free any pending packets */
4518 		DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
4519 		bcmsdh_intr_disable(bus->sdh);
4520 		bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL);
4521 
4522 		/* Clear any pending interrupts now that F2 is disabled */
4523 		W_SDREG(local_hostintmask, &bus->regs->intstatus, retries);
4524 		}
4525 
4526 		/* Turn off the backplane clock (only) */
4527 		dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
4528 	}
4529 
4530 	/* Clear the data packet queues */
4531 	pktq_flush(osh, &bus->txq, TRUE, NULL, 0);
4532 
4533 	/* Clear any held glomming stuff */
4534 	if (bus->glomd)
4535 		PKTFREE(osh, bus->glomd, FALSE);
4536 
4537 	if (bus->glom)
4538 		PKTFREE(osh, bus->glom, FALSE);
4539 
4540 	bus->glom = bus->glomd = NULL;
4541 
4542 	/* Clear rx control and wake any waiters */
4543 	bus->rxlen = 0;
4544 	dhd_os_ioctl_resp_wake(bus->dhd);
4545 
4546 	/* Reset some F2 state stuff */
4547 	bus->rxskip = FALSE;
4548 	bus->tx_seq = bus->rx_seq = 0;
4549 
4550 	bus->tx_max = 4;
4551 
4552 	if (enforce_mutex)
4553 		dhd_os_sdunlock(bus->dhd);
4554 }
4555 
4556 #ifdef BCMSDIOH_TXGLOM
4557 void
dhd_txglom_enable(dhd_pub_t * dhdp,bool enable)4558 dhd_txglom_enable(dhd_pub_t *dhdp, bool enable)
4559 {
4560 	dhd_bus_t *bus = dhdp->bus;
4561 
4562 	char buf[256];
4563 	uint32 rxglom;
4564 	int32 ret;
4565 
4566 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4567 
4568 	if (enable) {
4569 		rxglom = 1;
4570 		memset(buf, 0, sizeof(buf));
4571 		bcm_mkiovar("bus:rxglom",
4572 			(void *)&rxglom,
4573 			4, buf, sizeof(buf));
4574 		ret = dhd_wl_ioctl_cmd(dhdp,
4575 			WLC_SET_VAR, buf,
4576 			sizeof(buf), TRUE, 0);
4577 		if (!(ret < 0)) {
4578 			bus->glom_enable = TRUE;
4579 		}
4580 	} else {
4581 		bus->glom_enable = FALSE;
4582 	}
4583 }
4584 #endif /* BCMSDIOH_TXGLOM */
4585 
4586 int
dhd_bus_init(dhd_pub_t * dhdp,bool enforce_mutex)4587 dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex)
4588 {
4589 	dhd_bus_t *bus = dhdp->bus;
4590 	dhd_timeout_t tmo;
4591 	uint retries = 0;
4592 	uint8 ready, enable;
4593 	int err, ret = 0;
4594 	uint8 saveclk;
4595 
4596 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4597 
4598 	ASSERT(bus->dhd);
4599 	if (!bus->dhd)
4600 		return 0;
4601 
4602 	if (enforce_mutex)
4603 		dhd_os_sdlock(bus->dhd);
4604 
4605 	/* Make sure backplane clock is on, needed to generate F2 interrupt */
4606 	dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
4607 	if (bus->clkstate != CLK_AVAIL) {
4608 		DHD_ERROR(("%s: clock state is wrong. state = %d\n", __FUNCTION__, bus->clkstate));
4609 		ret = -1;
4610 		goto exit;
4611 	}
4612 
4613 
4614 	/* Force clocks on backplane to be sure F2 interrupt propagates */
4615 	saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
4616 	if (!err) {
4617 		bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
4618 		                 (saveclk | SBSDIO_FORCE_HT), &err);
4619 	}
4620 	if (err) {
4621 		DHD_ERROR(("%s: Failed to force clock for F2: err %d\n", __FUNCTION__, err));
4622 		ret = -1;
4623 		goto exit;
4624 	}
4625 
4626 	/* Enable function 2 (frame transfers) */
4627 	W_SDREG((SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT),
4628 	        &bus->regs->tosbmailboxdata, retries);
4629 	enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2);
4630 
4631 	bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL);
4632 
4633 	/* Give the dongle some time to do its thing and set IOR2 */
4634 	dhd_timeout_start(&tmo, DHD_WAIT_F2RDY * 1000);
4635 
4636 	ready = 0;
4637 	while (ready != enable && !dhd_timeout_expired(&tmo))
4638 	        ready = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IORDY, NULL);
4639 
4640 	DHD_ERROR(("%s: enable 0x%02x, ready 0x%02x (waited %uus)\n",
4641 	          __FUNCTION__, enable, ready, tmo.elapsed));
4642 
4643 
4644 	/* If F2 successfully enabled, set core and enable interrupts */
4645 	if (ready == enable) {
4646 		/* Make sure we're talking to the core. */
4647 		if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0)))
4648 			bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0);
4649 		ASSERT(bus->regs != NULL);
4650 
4651 		/* Set up the interrupt mask and enable interrupts */
4652 		bus->hostintmask = HOSTINTMASK;
4653 		/* corerev 4 could use the newer interrupt logic to detect the frames */
4654 		if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 4) &&
4655 			(bus->rxint_mode != SDIO_DEVICE_HMB_RXINT)) {
4656 			bus->hostintmask &= ~I_HMB_FRAME_IND;
4657 			bus->hostintmask |= I_XMTDATA_AVAIL;
4658 		}
4659 		W_SDREG(bus->hostintmask, &bus->regs->hostintmask, retries);
4660 #ifdef SDIO_CRC_ERROR_FIX
4661 		if (bus->blocksize < 512) {
4662 			mesbusyctrl = watermark = bus->blocksize / 4;
4663 		}
4664 #endif /* SDIO_CRC_ERROR_FIX */
4665 		if (!((bus->sih->chip == BCM4335_CHIP_ID) ||
4666 			(bus->sih->chip == BCM4339_CHIP_ID))) {
4667 			bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK,
4668 				(uint8)watermark, &err);
4669 		}
4670 #ifdef SDIO_CRC_ERROR_FIX
4671 		bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL,
4672 			(uint8)mesbusyctrl|0x80, &err);
4673 		bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL,
4674 			SBSDIO_DEVCTL_EN_F2_BLK_WATERMARK, NULL);
4675 #endif /* SDIO_CRC_ERROR_FIX */
4676 
4677 		/* Set bus state according to enable result */
4678 		dhdp->busstate = DHD_BUS_DATA;
4679 
4680 		/* bcmsdh_intr_unmask(bus->sdh); */
4681 
4682 		bus->intdis = FALSE;
4683 		if (bus->intr) {
4684 			DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__));
4685 			bcmsdh_intr_enable(bus->sdh);
4686 		} else {
4687 			DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
4688 			bcmsdh_intr_disable(bus->sdh);
4689 		}
4690 
4691 	}
4692 
4693 
4694 	else {
4695 		/* Disable F2 again */
4696 		enable = SDIO_FUNC_ENABLE_1;
4697 		bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL);
4698 	}
4699 
4700 	if (dhdsdio_sr_cap(bus)) {
4701 		dhdsdio_sr_init(bus);
4702 		/* Masking the chip active interrupt  permanantly */
4703 		bus->hostintmask &= ~I_CHIPACTIVE;
4704 		W_SDREG(bus->hostintmask, &bus->regs->hostintmask, retries);
4705 		DHD_INFO(("%s: disable I_CHIPACTIVE in hostintmask[0x%08x]\n",
4706 		__FUNCTION__, bus->hostintmask));
4707 	}
4708 	else
4709 		bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1,
4710 			SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err);
4711 
4712 	/* If we didn't come up, turn off backplane clock */
4713 	if (dhdp->busstate != DHD_BUS_DATA)
4714 		dhdsdio_clkctl(bus, CLK_NONE, FALSE);
4715 
4716 exit:
4717 	if (enforce_mutex)
4718 		dhd_os_sdunlock(bus->dhd);
4719 
4720 	return ret;
4721 }
4722 
4723 static void
dhdsdio_rxfail(dhd_bus_t * bus,bool abort,bool rtx)4724 dhdsdio_rxfail(dhd_bus_t *bus, bool abort, bool rtx)
4725 {
4726 	bcmsdh_info_t *sdh = bus->sdh;
4727 	sdpcmd_regs_t *regs = bus->regs;
4728 	uint retries = 0;
4729 	uint16 lastrbc;
4730 	uint8 hi, lo;
4731 	int err;
4732 
4733 	DHD_ERROR(("%s: %sterminate frame%s\n", __FUNCTION__,
4734 	           (abort ? "abort command, " : ""), (rtx ? ", send NAK" : "")));
4735 
4736 	if (!KSO_ENAB(bus)) {
4737 		DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
4738 		return;
4739 	}
4740 
4741 	if (abort) {
4742 		bcmsdh_abort(sdh, SDIO_FUNC_2);
4743 	}
4744 
4745 	bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, SFC_RF_TERM, &err);
4746 	if (err) {
4747 		DHD_ERROR(("%s: SBSDIO_FUNC1_FRAMECTRL cmd err\n", __FUNCTION__));
4748 		goto fail;
4749 	}
4750 	bus->f1regdata++;
4751 
4752 	/* Wait until the packet has been flushed (device/FIFO stable) */
4753 	for (lastrbc = retries = 0xffff; retries > 0; retries--) {
4754 		hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCHI, NULL);
4755 		lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCLO, &err);
4756 		if (err) {
4757 			DHD_ERROR(("%s: SBSDIO_FUNC1_RFAMEBCLO cmd err\n", __FUNCTION__));
4758 			goto fail;
4759 		}
4760 
4761 		bus->f1regdata += 2;
4762 
4763 		if ((hi == 0) && (lo == 0))
4764 			break;
4765 
4766 		if ((hi > (lastrbc >> 8)) && (lo > (lastrbc & 0x00ff))) {
4767 			DHD_ERROR(("%s: count growing: last 0x%04x now 0x%04x\n",
4768 			           __FUNCTION__, lastrbc, ((hi << 8) + lo)));
4769 		}
4770 		lastrbc = (hi << 8) + lo;
4771 	}
4772 
4773 	if (!retries) {
4774 		DHD_ERROR(("%s: count never zeroed: last 0x%04x\n", __FUNCTION__, lastrbc));
4775 	} else {
4776 		DHD_INFO(("%s: flush took %d iterations\n", __FUNCTION__, (0xffff - retries)));
4777 	}
4778 
4779 	if (rtx) {
4780 		bus->rxrtx++;
4781 		W_SDREG(SMB_NAK, &regs->tosbmailbox, retries);
4782 		bus->f1regdata++;
4783 		if (retries <= retry_limit) {
4784 			bus->rxskip = TRUE;
4785 		}
4786 	}
4787 
4788 	/* Clear partial in any case */
4789 	bus->nextlen = 0;
4790 
4791 fail:
4792 	/* If we can't reach the device, signal failure */
4793 	if (err || bcmsdh_regfail(sdh))
4794 		bus->dhd->busstate = DHD_BUS_DOWN;
4795 }
4796 
4797 static void
dhdsdio_read_control(dhd_bus_t * bus,uint8 * hdr,uint len,uint doff)4798 dhdsdio_read_control(dhd_bus_t *bus, uint8 *hdr, uint len, uint doff)
4799 {
4800 	bcmsdh_info_t *sdh = bus->sdh;
4801 	uint rdlen, pad;
4802 
4803 	int sdret;
4804 
4805 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4806 
4807 	/* Control data already received in aligned rxctl */
4808 	if ((bus->bus == SPI_BUS) && (!bus->usebufpool))
4809 		goto gotpkt;
4810 
4811 	ASSERT(bus->rxbuf);
4812 	/* Set rxctl for frame (w/optional alignment) */
4813 	bus->rxctl = bus->rxbuf;
4814 	if (dhd_alignctl) {
4815 		bus->rxctl += firstread;
4816 		if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN)))
4817 			bus->rxctl += (DHD_SDALIGN - pad);
4818 		bus->rxctl -= firstread;
4819 	}
4820 	ASSERT(bus->rxctl >= bus->rxbuf);
4821 
4822 	/* Copy the already-read portion over */
4823 	bcopy(hdr, bus->rxctl, firstread);
4824 	if (len <= firstread)
4825 		goto gotpkt;
4826 
4827 	/* Copy the full data pkt in gSPI case and process ioctl. */
4828 	if (bus->bus == SPI_BUS) {
4829 		bcopy(hdr, bus->rxctl, len);
4830 		goto gotpkt;
4831 	}
4832 
4833 	/* Raise rdlen to next SDIO block to avoid tail command */
4834 	rdlen = len - firstread;
4835 	if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
4836 		pad = bus->blocksize - (rdlen % bus->blocksize);
4837 		if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
4838 		    ((len + pad) < bus->dhd->maxctl))
4839 			rdlen += pad;
4840 	} else if (rdlen % DHD_SDALIGN) {
4841 		rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
4842 	}
4843 
4844 	/* Satisfy length-alignment requirements */
4845 	if (forcealign && (rdlen & (ALIGNMENT - 1)))
4846 		rdlen = ROUNDUP(rdlen, ALIGNMENT);
4847 
4848 	/* Drop if the read is too big or it exceeds our maximum */
4849 	if ((rdlen + firstread) > bus->dhd->maxctl) {
4850 		DHD_ERROR(("%s: %d-byte control read exceeds %d-byte buffer\n",
4851 		           __FUNCTION__, rdlen, bus->dhd->maxctl));
4852 		bus->dhd->rx_errors++;
4853 		dhdsdio_rxfail(bus, FALSE, FALSE);
4854 		goto done;
4855 	}
4856 
4857 	if ((len - doff) > bus->dhd->maxctl) {
4858 		DHD_ERROR(("%s: %d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n",
4859 		           __FUNCTION__, len, (len - doff), bus->dhd->maxctl));
4860 		bus->dhd->rx_errors++; bus->rx_toolong++;
4861 		dhdsdio_rxfail(bus, FALSE, FALSE);
4862 		goto done;
4863 	}
4864 
4865 
4866 	/* Read remainder of frame body into the rxctl buffer */
4867 	sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
4868 	                            (bus->rxctl + firstread), rdlen, NULL, NULL, NULL);
4869 	bus->f2rxdata++;
4870 	ASSERT(sdret != BCME_PENDING);
4871 
4872 	/* Control frame failures need retransmission */
4873 	if (sdret < 0) {
4874 		DHD_ERROR(("%s: read %d control bytes failed: %d\n", __FUNCTION__, rdlen, sdret));
4875 		bus->rxc_errors++; /* dhd.rx_ctlerrs is higher level */
4876 		dhdsdio_rxfail(bus, TRUE, TRUE);
4877 		goto done;
4878 	}
4879 
4880 gotpkt:
4881 
4882 #ifdef DHD_DEBUG
4883 	if (DHD_BYTES_ON() && DHD_CTL_ON()) {
4884 		prhex("RxCtrl", bus->rxctl, len);
4885 	}
4886 #endif
4887 
4888 	/* Point to valid data and indicate its length */
4889 	bus->rxctl += doff;
4890 	bus->rxlen = len - doff;
4891 
4892 done:
4893 	/* Awake any waiters */
4894 	dhd_os_ioctl_resp_wake(bus->dhd);
4895 }
4896 int
4897 dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf, uint reorder_info_len,
4898 	void **pkt, uint32 *pkt_count);
4899 
4900 static uint8
dhdsdio_rxglom(dhd_bus_t * bus,uint8 rxseq)4901 dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq)
4902 {
4903 	uint16 dlen, totlen;
4904 	uint8 *dptr, num = 0;
4905 
4906 	uint16 sublen, check;
4907 	void *pfirst, *plast, *pnext;
4908 	void * list_tail[DHD_MAX_IFS] = { NULL };
4909 	void * list_head[DHD_MAX_IFS] = { NULL };
4910 	uint8 idx;
4911 	osl_t *osh = bus->dhd->osh;
4912 
4913 	int errcode;
4914 	uint8 chan, seq, doff, sfdoff;
4915 	uint8 txmax;
4916 	uchar reorder_info_buf[WLHOST_REORDERDATA_TOTLEN];
4917 	uint reorder_info_len;
4918 
4919 	int ifidx = 0;
4920 	bool usechain = bus->use_rxchain;
4921 
4922 	/* If packets, issue read(s) and send up packet chain */
4923 	/* Return sequence numbers consumed? */
4924 
4925 	DHD_TRACE(("dhdsdio_rxglom: start: glomd %p glom %p\n", bus->glomd, bus->glom));
4926 
4927 	/* If there's a descriptor, generate the packet chain */
4928 	if (bus->glomd) {
4929 		dhd_os_sdlock_rxq(bus->dhd);
4930 
4931 		pfirst = plast = pnext = NULL;
4932 		dlen = (uint16)PKTLEN(osh, bus->glomd);
4933 		dptr = PKTDATA(osh, bus->glomd);
4934 		if (!dlen || (dlen & 1)) {
4935 			DHD_ERROR(("%s: bad glomd len (%d), ignore descriptor\n",
4936 			           __FUNCTION__, dlen));
4937 			dlen = 0;
4938 		}
4939 
4940 		for (totlen = num = 0; dlen; num++) {
4941 			/* Get (and move past) next length */
4942 			sublen = ltoh16_ua(dptr);
4943 			dlen -= sizeof(uint16);
4944 			dptr += sizeof(uint16);
4945 			if ((sublen < SDPCM_HDRLEN_RX) ||
4946 			    ((num == 0) && (sublen < (2 * SDPCM_HDRLEN_RX)))) {
4947 				DHD_ERROR(("%s: descriptor len %d bad: %d\n",
4948 				           __FUNCTION__, num, sublen));
4949 				pnext = NULL;
4950 				break;
4951 			}
4952 			if (sublen % DHD_SDALIGN) {
4953 				DHD_ERROR(("%s: sublen %d not a multiple of %d\n",
4954 				           __FUNCTION__, sublen, DHD_SDALIGN));
4955 				usechain = FALSE;
4956 			}
4957 			totlen += sublen;
4958 
4959 			/* For last frame, adjust read len so total is a block multiple */
4960 			if (!dlen) {
4961 				sublen += (ROUNDUP(totlen, bus->blocksize) - totlen);
4962 				totlen = ROUNDUP(totlen, bus->blocksize);
4963 			}
4964 
4965 			/* Allocate/chain packet for next subframe */
4966 			if ((pnext = PKTGET(osh, sublen + DHD_SDALIGN, FALSE)) == NULL) {
4967 				DHD_ERROR(("%s: PKTGET failed, num %d len %d\n",
4968 				           __FUNCTION__, num, sublen));
4969 				break;
4970 			}
4971 			ASSERT(!PKTLINK(pnext));
4972 			if (!pfirst) {
4973 				ASSERT(!plast);
4974 				pfirst = plast = pnext;
4975 			} else {
4976 				ASSERT(plast);
4977 				PKTSETNEXT(osh, plast, pnext);
4978 				plast = pnext;
4979 			}
4980 
4981 			/* Adhere to start alignment requirements */
4982 			PKTALIGN(osh, pnext, sublen, DHD_SDALIGN);
4983 		}
4984 
4985 		/* If all allocations succeeded, save packet chain in bus structure */
4986 		if (pnext) {
4987 			DHD_GLOM(("%s: allocated %d-byte packet chain for %d subframes\n",
4988 			          __FUNCTION__, totlen, num));
4989 			if (DHD_GLOM_ON() && bus->nextlen) {
4990 				if (totlen != bus->nextlen) {
4991 					DHD_GLOM(("%s: glomdesc mismatch: nextlen %d glomdesc %d "
4992 					          "rxseq %d\n", __FUNCTION__, bus->nextlen,
4993 					          totlen, rxseq));
4994 				}
4995 			}
4996 			bus->glom = pfirst;
4997 			pfirst = pnext = NULL;
4998 		} else {
4999 			if (pfirst)
5000 				PKTFREE(osh, pfirst, FALSE);
5001 			bus->glom = NULL;
5002 			num = 0;
5003 		}
5004 
5005 		/* Done with descriptor packet */
5006 		PKTFREE(osh, bus->glomd, FALSE);
5007 		bus->glomd = NULL;
5008 		bus->nextlen = 0;
5009 
5010 		dhd_os_sdunlock_rxq(bus->dhd);
5011 	}
5012 
5013 	/* Ok -- either we just generated a packet chain, or had one from before */
5014 	if (bus->glom) {
5015 		if (DHD_GLOM_ON()) {
5016 			DHD_GLOM(("%s: attempt superframe read, packet chain:\n", __FUNCTION__));
5017 			for (pnext = bus->glom; pnext; pnext = PKTNEXT(osh, pnext)) {
5018 				DHD_GLOM(("    %p: %p len 0x%04x (%d)\n",
5019 				          pnext, (uint8*)PKTDATA(osh, pnext),
5020 				          PKTLEN(osh, pnext), PKTLEN(osh, pnext)));
5021 			}
5022 		}
5023 
5024 		pfirst = bus->glom;
5025 		dlen = (uint16)pkttotlen(osh, pfirst);
5026 
5027 		/* Do an SDIO read for the superframe.  Configurable iovar to
5028 		 * read directly into the chained packet, or allocate a large
5029 		 * packet and and copy into the chain.
5030 		 */
5031 		if (usechain) {
5032 			errcode = dhd_bcmsdh_recv_buf(bus,
5033 			                              bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2,
5034 			                              F2SYNC, (uint8*)PKTDATA(osh, pfirst),
5035 			                              dlen, pfirst, NULL, NULL);
5036 		} else if (bus->dataptr) {
5037 			errcode = dhd_bcmsdh_recv_buf(bus,
5038 			                              bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2,
5039 			                              F2SYNC, bus->dataptr,
5040 			                              dlen, NULL, NULL, NULL);
5041 			sublen = (uint16)pktfrombuf(osh, pfirst, 0, dlen, bus->dataptr);
5042 			if (sublen != dlen) {
5043 				DHD_ERROR(("%s: FAILED TO COPY, dlen %d sublen %d\n",
5044 				           __FUNCTION__, dlen, sublen));
5045 				errcode = -1;
5046 			}
5047 			pnext = NULL;
5048 		} else {
5049 			DHD_ERROR(("COULDN'T ALLOC %d-BYTE GLOM, FORCE FAILURE\n", dlen));
5050 			errcode = -1;
5051 		}
5052 		bus->f2rxdata++;
5053 		ASSERT(errcode != BCME_PENDING);
5054 
5055 		/* On failure, kill the superframe, allow a couple retries */
5056 		if (errcode < 0) {
5057 			DHD_ERROR(("%s: glom read of %d bytes failed: %d\n",
5058 			           __FUNCTION__, dlen, errcode));
5059 			bus->dhd->rx_errors++;
5060 
5061 			if (bus->glomerr++ < 3) {
5062 				dhdsdio_rxfail(bus, TRUE, TRUE);
5063 			} else {
5064 				bus->glomerr = 0;
5065 				dhdsdio_rxfail(bus, TRUE, FALSE);
5066 				dhd_os_sdlock_rxq(bus->dhd);
5067 				PKTFREE(osh, bus->glom, FALSE);
5068 				dhd_os_sdunlock_rxq(bus->dhd);
5069 				bus->rxglomfail++;
5070 				bus->glom = NULL;
5071 			}
5072 			return 0;
5073 		}
5074 
5075 #ifdef DHD_DEBUG
5076 		if (DHD_GLOM_ON()) {
5077 			prhex("SUPERFRAME", PKTDATA(osh, pfirst),
5078 			      MIN(PKTLEN(osh, pfirst), 48));
5079 		}
5080 #endif
5081 
5082 
5083 		/* Validate the superframe header */
5084 		dptr = (uint8 *)PKTDATA(osh, pfirst);
5085 		sublen = ltoh16_ua(dptr);
5086 		check = ltoh16_ua(dptr + sizeof(uint16));
5087 
5088 		chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
5089 		seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
5090 		bus->nextlen = dptr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
5091 		if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
5092 			DHD_INFO(("%s: got frame w/nextlen too large (%d) seq %d\n",
5093 			          __FUNCTION__, bus->nextlen, seq));
5094 			bus->nextlen = 0;
5095 		}
5096 		doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
5097 		txmax = SDPCM_WINDOW_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
5098 
5099 		errcode = 0;
5100 		if ((uint16)~(sublen^check)) {
5101 			DHD_ERROR(("%s (superframe): HW hdr error: len/check 0x%04x/0x%04x\n",
5102 			           __FUNCTION__, sublen, check));
5103 			errcode = -1;
5104 		} else if (ROUNDUP(sublen, bus->blocksize) != dlen) {
5105 			DHD_ERROR(("%s (superframe): len 0x%04x, rounded 0x%04x, expect 0x%04x\n",
5106 			           __FUNCTION__, sublen, ROUNDUP(sublen, bus->blocksize), dlen));
5107 			errcode = -1;
5108 		} else if (SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]) != SDPCM_GLOM_CHANNEL) {
5109 			DHD_ERROR(("%s (superframe): bad channel %d\n", __FUNCTION__,
5110 			           SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN])));
5111 			errcode = -1;
5112 		} else if (SDPCM_GLOMDESC(&dptr[SDPCM_FRAMETAG_LEN])) {
5113 			DHD_ERROR(("%s (superframe): got second descriptor?\n", __FUNCTION__));
5114 			errcode = -1;
5115 		} else if ((doff < SDPCM_HDRLEN_RX) ||
5116 		           (doff > (PKTLEN(osh, pfirst) - SDPCM_HDRLEN_RX))) {
5117 			DHD_ERROR(("%s (superframe): Bad data offset %d: HW %d pkt %d min %d\n",
5118 				__FUNCTION__, doff, sublen, PKTLEN(osh, pfirst),
5119 				SDPCM_HDRLEN_RX));
5120 			errcode = -1;
5121 		}
5122 
5123 		/* Check sequence number of superframe SW header */
5124 		if (rxseq != seq) {
5125 			DHD_INFO(("%s: (superframe) rx_seq %d, expected %d\n",
5126 			          __FUNCTION__, seq, rxseq));
5127 			bus->rx_badseq++;
5128 			rxseq = seq;
5129 		}
5130 
5131 		/* Check window for sanity */
5132 		if ((uint8)(txmax - bus->tx_seq) > 0x40) {
5133 			DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
5134 			           __FUNCTION__, txmax, bus->tx_seq));
5135 			txmax = bus->tx_max;
5136 		}
5137 		bus->tx_max = txmax;
5138 
5139 		/* Remove superframe header, remember offset */
5140 		PKTPULL(osh, pfirst, doff);
5141 		sfdoff = doff;
5142 
5143 		/* Validate all the subframe headers */
5144 		for (num = 0, pnext = pfirst; pnext && !errcode;
5145 		     num++, pnext = PKTNEXT(osh, pnext)) {
5146 			dptr = (uint8 *)PKTDATA(osh, pnext);
5147 			dlen = (uint16)PKTLEN(osh, pnext);
5148 			sublen = ltoh16_ua(dptr);
5149 			check = ltoh16_ua(dptr + sizeof(uint16));
5150 			chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
5151 			doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
5152 #ifdef DHD_DEBUG
5153 			if (DHD_GLOM_ON()) {
5154 				prhex("subframe", dptr, 32);
5155 			}
5156 #endif
5157 
5158 			if ((uint16)~(sublen^check)) {
5159 				DHD_ERROR(("%s (subframe %d): HW hdr error: "
5160 				           "len/check 0x%04x/0x%04x\n",
5161 				           __FUNCTION__, num, sublen, check));
5162 				errcode = -1;
5163 			} else if ((sublen > dlen) || (sublen < SDPCM_HDRLEN_RX)) {
5164 				DHD_ERROR(("%s (subframe %d): length mismatch: "
5165 				           "len 0x%04x, expect 0x%04x\n",
5166 				           __FUNCTION__, num, sublen, dlen));
5167 				errcode = -1;
5168 			} else if ((chan != SDPCM_DATA_CHANNEL) &&
5169 			           (chan != SDPCM_EVENT_CHANNEL)) {
5170 				DHD_ERROR(("%s (subframe %d): bad channel %d\n",
5171 				           __FUNCTION__, num, chan));
5172 				errcode = -1;
5173 			} else if ((doff < SDPCM_HDRLEN_RX) || (doff > sublen)) {
5174 				DHD_ERROR(("%s (subframe %d): Bad data offset %d: HW %d min %d\n",
5175 				           __FUNCTION__, num, doff, sublen, SDPCM_HDRLEN_RX));
5176 				errcode = -1;
5177 			}
5178 		}
5179 
5180 		if (errcode) {
5181 			/* Terminate frame on error, request a couple retries */
5182 			if (bus->glomerr++ < 3) {
5183 				/* Restore superframe header space */
5184 				PKTPUSH(osh, pfirst, sfdoff);
5185 				dhdsdio_rxfail(bus, TRUE, TRUE);
5186 			} else {
5187 				bus->glomerr = 0;
5188 				dhdsdio_rxfail(bus, TRUE, FALSE);
5189 				dhd_os_sdlock_rxq(bus->dhd);
5190 				PKTFREE(osh, bus->glom, FALSE);
5191 				dhd_os_sdunlock_rxq(bus->dhd);
5192 				bus->rxglomfail++;
5193 				bus->glom = NULL;
5194 			}
5195 			bus->nextlen = 0;
5196 			return 0;
5197 		}
5198 
5199 		/* Basic SD framing looks ok - process each packet (header) */
5200 		bus->glom = NULL;
5201 		plast = NULL;
5202 
5203 		dhd_os_sdlock_rxq(bus->dhd);
5204 		for (num = 0; pfirst; rxseq++, pfirst = pnext) {
5205 			pnext = PKTNEXT(osh, pfirst);
5206 			PKTSETNEXT(osh, pfirst, NULL);
5207 
5208 			dptr = (uint8 *)PKTDATA(osh, pfirst);
5209 			sublen = ltoh16_ua(dptr);
5210 			chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
5211 			seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
5212 			doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
5213 
5214 			DHD_GLOM(("%s: Get subframe %d, %p(%p/%d), sublen %d chan %d seq %d\n",
5215 			          __FUNCTION__, num, pfirst, PKTDATA(osh, pfirst),
5216 			          PKTLEN(osh, pfirst), sublen, chan, seq));
5217 
5218 			ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL));
5219 
5220 			if (rxseq != seq) {
5221 				DHD_GLOM(("%s: rx_seq %d, expected %d\n",
5222 				          __FUNCTION__, seq, rxseq));
5223 				bus->rx_badseq++;
5224 				rxseq = seq;
5225 			}
5226 
5227 #ifdef DHD_DEBUG
5228 			if (DHD_BYTES_ON() && DHD_DATA_ON()) {
5229 				prhex("Rx Subframe Data", dptr, dlen);
5230 			}
5231 #endif
5232 
5233 			PKTSETLEN(osh, pfirst, sublen);
5234 			PKTPULL(osh, pfirst, doff);
5235 
5236 			reorder_info_len = sizeof(reorder_info_buf);
5237 
5238 			if (PKTLEN(osh, pfirst) == 0) {
5239 				PKTFREE(bus->dhd->osh, pfirst, FALSE);
5240 				continue;
5241 			} else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pfirst, reorder_info_buf,
5242 				&reorder_info_len) != 0) {
5243 				DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__));
5244 				bus->dhd->rx_errors++;
5245 				PKTFREE(osh, pfirst, FALSE);
5246 				continue;
5247 			}
5248 			if (reorder_info_len) {
5249 				uint32 free_buf_count;
5250 				void *ppfirst;
5251 
5252 				ppfirst = pfirst;
5253 				/* Reordering info from the firmware */
5254 				dhd_process_pkt_reorder_info(bus->dhd, reorder_info_buf,
5255 					reorder_info_len, &ppfirst, &free_buf_count);
5256 
5257 				if (free_buf_count == 0) {
5258 					continue;
5259 				}
5260 				else {
5261 					void *temp;
5262 
5263 					/*  go to the end of the chain and attach the pnext there */
5264 					temp = ppfirst;
5265 					while (PKTNEXT(osh, temp) != NULL) {
5266 						temp = PKTNEXT(osh, temp);
5267 					}
5268 					pfirst = temp;
5269 					if (list_tail[ifidx] == NULL)
5270 						list_head[ifidx] = ppfirst;
5271 					else
5272 						PKTSETNEXT(osh, list_tail[ifidx], ppfirst);
5273 					list_tail[ifidx] = pfirst;
5274 				}
5275 
5276 				num += (uint8)free_buf_count;
5277 			}
5278 			else {
5279 				/* this packet will go up, link back into chain and count it */
5280 
5281 				if (list_tail[ifidx] == NULL) {
5282 					list_head[ifidx] = list_tail[ifidx] = pfirst;
5283 				}
5284 				else {
5285 					PKTSETNEXT(osh, list_tail[ifidx], pfirst);
5286 					list_tail[ifidx] = pfirst;
5287 				}
5288 				num++;
5289 			}
5290 #ifdef DHD_DEBUG
5291 			if (DHD_GLOM_ON()) {
5292 				DHD_GLOM(("%s subframe %d to stack, %p(%p/%d) nxt/lnk %p/%p\n",
5293 				          __FUNCTION__, num, pfirst,
5294 				          PKTDATA(osh, pfirst), PKTLEN(osh, pfirst),
5295 				          PKTNEXT(osh, pfirst), PKTLINK(pfirst)));
5296 				prhex("", (uint8 *)PKTDATA(osh, pfirst),
5297 				      MIN(PKTLEN(osh, pfirst), 32));
5298 			}
5299 #endif /* DHD_DEBUG */
5300 		}
5301 		dhd_os_sdunlock_rxq(bus->dhd);
5302 
5303 		for (idx = 0; idx < DHD_MAX_IFS; idx++) {
5304 			if (list_head[idx]) {
5305 				void *temp;
5306 				uint8 cnt = 0;
5307 				temp = list_head[idx];
5308 				do {
5309 					temp = PKTNEXT(osh, temp);
5310 					cnt++;
5311 				} while (temp);
5312 				if (cnt) {
5313 					dhd_os_sdunlock(bus->dhd);
5314 					dhd_rx_frame(bus->dhd, idx, list_head[idx], cnt, 0);
5315 					dhd_os_sdlock(bus->dhd);
5316 				}
5317 			}
5318 		}
5319 		bus->rxglomframes++;
5320 		bus->rxglompkts += num;
5321 	}
5322 	return num;
5323 }
5324 
5325 
5326 /* Return TRUE if there may be more frames to read */
5327 static uint
dhdsdio_readframes(dhd_bus_t * bus,uint maxframes,bool * finished)5328 dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished)
5329 {
5330 	osl_t *osh = bus->dhd->osh;
5331 	bcmsdh_info_t *sdh = bus->sdh;
5332 
5333 	uint16 len, check;	/* Extracted hardware header fields */
5334 	uint8 chan, seq, doff;	/* Extracted software header fields */
5335 	uint8 fcbits;		/* Extracted fcbits from software header */
5336 	uint8 delta;
5337 
5338 	void *pkt;	/* Packet for event or data frames */
5339 	uint16 pad;	/* Number of pad bytes to read */
5340 	uint16 rdlen;	/* Total number of bytes to read */
5341 	uint8 rxseq;	/* Next sequence number to expect */
5342 	uint rxleft = 0;	/* Remaining number of frames allowed */
5343 	int sdret;	/* Return code from bcmsdh calls */
5344 	uint8 txmax;	/* Maximum tx sequence offered */
5345 	bool len_consistent; /* Result of comparing readahead len and len from hw-hdr */
5346 	uint8 *rxbuf;
5347 	int ifidx = 0;
5348 	uint rxcount = 0; /* Total frames read */
5349 	uchar reorder_info_buf[WLHOST_REORDERDATA_TOTLEN];
5350 	uint reorder_info_len;
5351 	uint pkt_count;
5352 
5353 #if defined(DHD_DEBUG) || defined(SDTEST)
5354 	bool sdtest = FALSE;	/* To limit message spew from test mode */
5355 #endif
5356 
5357 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5358 
5359 	bus->readframes = TRUE;
5360 
5361 	if (!KSO_ENAB(bus)) {
5362 		DHD_ERROR(("%s: KSO off\n", __FUNCTION__));
5363 		bus->readframes = FALSE;
5364 		return 0;
5365 	}
5366 
5367 	ASSERT(maxframes);
5368 
5369 #ifdef SDTEST
5370 	/* Allow pktgen to override maxframes */
5371 	if (bus->pktgen_count && (bus->pktgen_mode == DHD_PKTGEN_RECV)) {
5372 		maxframes = bus->pktgen_count;
5373 		sdtest = TRUE;
5374 	}
5375 #endif
5376 
5377 	/* Not finished unless we encounter no more frames indication */
5378 	*finished = FALSE;
5379 
5380 
5381 	for (rxseq = bus->rx_seq, rxleft = maxframes;
5382 	     !bus->rxskip && rxleft && bus->dhd->busstate != DHD_BUS_DOWN;
5383 	     rxseq++, rxleft--) {
5384 
5385 #ifdef DHDTHREAD
5386 		/* tx more to improve rx performance */
5387 		if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL)) {
5388 			dhdsdio_sendpendctl(bus);
5389 		} else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate &&
5390 			pktq_mlen(&bus->txq, ~bus->flowcontrol) && DATAOK(bus)) {
5391 			dhdsdio_sendfromq(bus, dhd_txbound);
5392 		}
5393 #endif /* DHDTHREAD */
5394 
5395 		/* Handle glomming separately */
5396 		if (bus->glom || bus->glomd) {
5397 			uint8 cnt;
5398 			DHD_GLOM(("%s: calling rxglom: glomd %p, glom %p\n",
5399 			          __FUNCTION__, bus->glomd, bus->glom));
5400 			cnt = dhdsdio_rxglom(bus, rxseq);
5401 			DHD_GLOM(("%s: rxglom returned %d\n", __FUNCTION__, cnt));
5402 			rxseq += cnt - 1;
5403 			rxleft = (rxleft > cnt) ? (rxleft - cnt) : 1;
5404 			continue;
5405 		}
5406 
5407 		/* Try doing single read if we can */
5408 		if (dhd_readahead && bus->nextlen) {
5409 			uint16 nextlen = bus->nextlen;
5410 			bus->nextlen = 0;
5411 
5412 			if (bus->bus == SPI_BUS) {
5413 				rdlen = len = nextlen;
5414 			}
5415 			else {
5416 				rdlen = len = nextlen << 4;
5417 
5418 				/* Pad read to blocksize for efficiency */
5419 				if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
5420 					pad = bus->blocksize - (rdlen % bus->blocksize);
5421 					if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
5422 						((rdlen + pad + firstread) < MAX_RX_DATASZ))
5423 						rdlen += pad;
5424 				} else if (rdlen % DHD_SDALIGN) {
5425 					rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
5426 				}
5427 			}
5428 
5429 			/* We use bus->rxctl buffer in WinXP for initial control pkt receives.
5430 			 * Later we use buffer-poll for data as well as control packets.
5431 			 * This is required because dhd receives full frame in gSPI unlike SDIO.
5432 			 * After the frame is received we have to distinguish whether it is data
5433 			 * or non-data frame.
5434 			 */
5435 			/* Allocate a packet buffer */
5436 			dhd_os_sdlock_rxq(bus->dhd);
5437 			if (!(pkt = PKTGET(osh, rdlen + DHD_SDALIGN, FALSE))) {
5438 				if (bus->bus == SPI_BUS) {
5439 					bus->usebufpool = FALSE;
5440 					bus->rxctl = bus->rxbuf;
5441 					if (dhd_alignctl) {
5442 						bus->rxctl += firstread;
5443 						if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN)))
5444 							bus->rxctl += (DHD_SDALIGN - pad);
5445 						bus->rxctl -= firstread;
5446 					}
5447 					ASSERT(bus->rxctl >= bus->rxbuf);
5448 					rxbuf = bus->rxctl;
5449 					/* Read the entire frame */
5450 					sdret = dhd_bcmsdh_recv_buf(bus,
5451 					                            bcmsdh_cur_sbwad(sdh),
5452 					                            SDIO_FUNC_2,
5453 					                            F2SYNC, rxbuf, rdlen,
5454 					                            NULL, NULL, NULL);
5455 					bus->f2rxdata++;
5456 					ASSERT(sdret != BCME_PENDING);
5457 
5458 
5459 					/* Control frame failures need retransmission */
5460 					if (sdret < 0) {
5461 						DHD_ERROR(("%s: read %d control bytes failed: %d\n",
5462 						   __FUNCTION__, rdlen, sdret));
5463 						/* dhd.rx_ctlerrs is higher level */
5464 						bus->rxc_errors++;
5465 						dhd_os_sdunlock_rxq(bus->dhd);
5466 						dhdsdio_rxfail(bus, TRUE,
5467 						    (bus->bus == SPI_BUS) ? FALSE : TRUE);
5468 						continue;
5469 					}
5470 				} else {
5471 					/* Give up on data, request rtx of events */
5472 					DHD_ERROR(("%s (nextlen): PKTGET failed: len %d rdlen %d "
5473 					           "expected rxseq %d\n",
5474 					           __FUNCTION__, len, rdlen, rxseq));
5475 					/* Just go try again w/normal header read */
5476 					dhd_os_sdunlock_rxq(bus->dhd);
5477 					continue;
5478 				}
5479 			} else {
5480 				if (bus->bus == SPI_BUS)
5481 					bus->usebufpool = TRUE;
5482 
5483 				ASSERT(!PKTLINK(pkt));
5484 				PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN);
5485 				rxbuf = (uint8 *)PKTDATA(osh, pkt);
5486 				/* Read the entire frame */
5487 				sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh),
5488 				                            SDIO_FUNC_2,
5489 				                            F2SYNC, rxbuf, rdlen,
5490 				                            pkt, NULL, NULL);
5491 				bus->f2rxdata++;
5492 				ASSERT(sdret != BCME_PENDING);
5493 
5494 				if (sdret < 0) {
5495 					DHD_ERROR(("%s (nextlen): read %d bytes failed: %d\n",
5496 					   __FUNCTION__, rdlen, sdret));
5497 					PKTFREE(bus->dhd->osh, pkt, FALSE);
5498 					bus->dhd->rx_errors++;
5499 					dhd_os_sdunlock_rxq(bus->dhd);
5500 					/* Force retry w/normal header read.  Don't attempt NAK for
5501 					 * gSPI
5502 					 */
5503 					dhdsdio_rxfail(bus, TRUE,
5504 					      (bus->bus == SPI_BUS) ? FALSE : TRUE);
5505 					continue;
5506 				}
5507 			}
5508 			dhd_os_sdunlock_rxq(bus->dhd);
5509 
5510 			/* Now check the header */
5511 			bcopy(rxbuf, bus->rxhdr, SDPCM_HDRLEN_RX);
5512 
5513 			/* Extract hardware header fields */
5514 			len = ltoh16_ua(bus->rxhdr);
5515 			check = ltoh16_ua(bus->rxhdr + sizeof(uint16));
5516 
5517 			/* All zeros means readahead info was bad */
5518 			if (!(len|check)) {
5519 				DHD_INFO(("%s (nextlen): read zeros in HW header???\n",
5520 				           __FUNCTION__));
5521 				dhd_os_sdlock_rxq(bus->dhd);
5522 				PKTFREE2();
5523 				dhd_os_sdunlock_rxq(bus->dhd);
5524 				GSPI_PR55150_BAILOUT;
5525 				continue;
5526 			}
5527 
5528 			/* Validate check bytes */
5529 			if ((uint16)~(len^check)) {
5530 				DHD_ERROR(("%s (nextlen): HW hdr error: nextlen/len/check"
5531 				           " 0x%04x/0x%04x/0x%04x\n", __FUNCTION__, nextlen,
5532 				           len, check));
5533 				dhd_os_sdlock_rxq(bus->dhd);
5534 				PKTFREE2();
5535 				dhd_os_sdunlock_rxq(bus->dhd);
5536 				bus->rx_badhdr++;
5537 				dhdsdio_rxfail(bus, FALSE, FALSE);
5538 				GSPI_PR55150_BAILOUT;
5539 				continue;
5540 			}
5541 
5542 			/* Validate frame length */
5543 			if (len < SDPCM_HDRLEN_RX) {
5544 				DHD_ERROR(("%s (nextlen): HW hdr length invalid: %d\n",
5545 				           __FUNCTION__, len));
5546 				dhd_os_sdlock_rxq(bus->dhd);
5547 				PKTFREE2();
5548 				dhd_os_sdunlock_rxq(bus->dhd);
5549 				GSPI_PR55150_BAILOUT;
5550 				continue;
5551 			}
5552 
5553 			/* Check for consistency with readahead info */
5554 				len_consistent = (nextlen != (ROUNDUP(len, 16) >> 4));
5555 			if (len_consistent) {
5556 				/* Mismatch, force retry w/normal header (may be >4K) */
5557 				DHD_ERROR(("%s (nextlen): mismatch, nextlen %d len %d rnd %d; "
5558 				           "expected rxseq %d\n",
5559 				           __FUNCTION__, nextlen, len, ROUNDUP(len, 16), rxseq));
5560 				dhd_os_sdlock_rxq(bus->dhd);
5561 				PKTFREE2();
5562 				dhd_os_sdunlock_rxq(bus->dhd);
5563 				dhdsdio_rxfail(bus, TRUE, (bus->bus == SPI_BUS) ? FALSE : TRUE);
5564 				GSPI_PR55150_BAILOUT;
5565 				continue;
5566 			}
5567 
5568 
5569 			/* Extract software header fields */
5570 			chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5571 			seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5572 			doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5573 			txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5574 
5575 				bus->nextlen =
5576 				         bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
5577 				if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
5578 					DHD_INFO(("%s (nextlen): got frame w/nextlen too large"
5579 					          " (%d), seq %d\n", __FUNCTION__, bus->nextlen,
5580 					          seq));
5581 					bus->nextlen = 0;
5582 				}
5583 
5584 				bus->dhd->rx_readahead_cnt ++;
5585 			/* Handle Flow Control */
5586 			fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5587 
5588 			delta = 0;
5589 			if (~bus->flowcontrol & fcbits) {
5590 				bus->fc_xoff++;
5591 				delta = 1;
5592 			}
5593 			if (bus->flowcontrol & ~fcbits) {
5594 				bus->fc_xon++;
5595 				delta = 1;
5596 			}
5597 
5598 			if (delta) {
5599 				bus->fc_rcvd++;
5600 				bus->flowcontrol = fcbits;
5601 			}
5602 
5603 			/* Check and update sequence number */
5604 			if (rxseq != seq) {
5605 				DHD_INFO(("%s (nextlen): rx_seq %d, expected %d\n",
5606 				          __FUNCTION__, seq, rxseq));
5607 				bus->rx_badseq++;
5608 				rxseq = seq;
5609 			}
5610 
5611 			/* Check window for sanity */
5612 			if ((uint8)(txmax - bus->tx_seq) > 0x40) {
5613 					DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
5614 						__FUNCTION__, txmax, bus->tx_seq));
5615 					txmax = bus->tx_max;
5616 			}
5617 			bus->tx_max = txmax;
5618 
5619 #ifdef DHD_DEBUG
5620 			if (DHD_BYTES_ON() && DHD_DATA_ON()) {
5621 				prhex("Rx Data", rxbuf, len);
5622 			} else if (DHD_HDRS_ON()) {
5623 				prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN_RX);
5624 			}
5625 #endif
5626 
5627 			if (chan == SDPCM_CONTROL_CHANNEL) {
5628 				if (bus->bus == SPI_BUS) {
5629 					dhdsdio_read_control(bus, rxbuf, len, doff);
5630 					if (bus->usebufpool) {
5631 						dhd_os_sdlock_rxq(bus->dhd);
5632 						PKTFREE(bus->dhd->osh, pkt, FALSE);
5633 						dhd_os_sdunlock_rxq(bus->dhd);
5634 					}
5635 					continue;
5636 				} else {
5637 					DHD_ERROR(("%s (nextlen): readahead on control"
5638 					           " packet %d?\n", __FUNCTION__, seq));
5639 					/* Force retry w/normal header read */
5640 					bus->nextlen = 0;
5641 					dhdsdio_rxfail(bus, FALSE, TRUE);
5642 					dhd_os_sdlock_rxq(bus->dhd);
5643 					PKTFREE2();
5644 					dhd_os_sdunlock_rxq(bus->dhd);
5645 					continue;
5646 				}
5647 			}
5648 
5649 			if ((bus->bus == SPI_BUS) && !bus->usebufpool) {
5650 				DHD_ERROR(("Received %d bytes on %d channel. Running out of "
5651 				           "rx pktbuf's or not yet malloced.\n", len, chan));
5652 				continue;
5653 			}
5654 
5655 			/* Validate data offset */
5656 			if ((doff < SDPCM_HDRLEN_RX) || (doff > len)) {
5657 				DHD_ERROR(("%s (nextlen): bad data offset %d: HW len %d min %d\n",
5658 				           __FUNCTION__, doff, len, SDPCM_HDRLEN_RX));
5659 				dhd_os_sdlock_rxq(bus->dhd);
5660 				PKTFREE2();
5661 				dhd_os_sdunlock_rxq(bus->dhd);
5662 				ASSERT(0);
5663 				dhdsdio_rxfail(bus, FALSE, FALSE);
5664 				continue;
5665 			}
5666 
5667 			/* All done with this one -- now deliver the packet */
5668 			goto deliver;
5669 		}
5670 		/* gSPI frames should not be handled in fractions */
5671 		if (bus->bus == SPI_BUS) {
5672 			break;
5673 		}
5674 
5675 		/* Read frame header (hardware and software) */
5676 		sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
5677 		                            bus->rxhdr, firstread, NULL, NULL, NULL);
5678 		bus->f2rxhdrs++;
5679 		ASSERT(sdret != BCME_PENDING);
5680 
5681 		if (sdret < 0) {
5682 			DHD_ERROR(("%s: RXHEADER FAILED: %d\n", __FUNCTION__, sdret));
5683 			bus->rx_hdrfail++;
5684 			dhdsdio_rxfail(bus, TRUE, TRUE);
5685 			continue;
5686 		}
5687 
5688 #ifdef DHD_DEBUG
5689 		if (DHD_BYTES_ON() || DHD_HDRS_ON()) {
5690 			prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN_RX);
5691 		}
5692 #endif
5693 
5694 		/* Extract hardware header fields */
5695 		len = ltoh16_ua(bus->rxhdr);
5696 		check = ltoh16_ua(bus->rxhdr + sizeof(uint16));
5697 
5698 		/* All zeros means no more frames */
5699 		if (!(len|check)) {
5700 			*finished = TRUE;
5701 			break;
5702 		}
5703 
5704 		/* Validate check bytes */
5705 		if ((uint16)~(len^check)) {
5706 			DHD_ERROR(("%s: HW hdr error: len/check 0x%04x/0x%04x\n",
5707 			           __FUNCTION__, len, check));
5708 			bus->rx_badhdr++;
5709 			dhdsdio_rxfail(bus, FALSE, FALSE);
5710 			continue;
5711 		}
5712 
5713 		/* Validate frame length */
5714 		if (len < SDPCM_HDRLEN_RX) {
5715 			DHD_ERROR(("%s: HW hdr length invalid: %d\n", __FUNCTION__, len));
5716 			continue;
5717 		}
5718 
5719 		/* Extract software header fields */
5720 		chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5721 		seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5722 		doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5723 		txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5724 
5725 		/* Validate data offset */
5726 		if ((doff < SDPCM_HDRLEN_RX) || (doff > len)) {
5727 			DHD_ERROR(("%s: Bad data offset %d: HW len %d, min %d seq %d\n",
5728 			           __FUNCTION__, doff, len, SDPCM_HDRLEN_RX, seq));
5729 			bus->rx_badhdr++;
5730 			ASSERT(0);
5731 			dhdsdio_rxfail(bus, FALSE, FALSE);
5732 			continue;
5733 		}
5734 
5735 		/* Save the readahead length if there is one */
5736 		bus->nextlen = bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
5737 		if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
5738 			DHD_INFO(("%s (nextlen): got frame w/nextlen too large (%d), seq %d\n",
5739 			          __FUNCTION__, bus->nextlen, seq));
5740 			bus->nextlen = 0;
5741 		}
5742 
5743 		/* Handle Flow Control */
5744 		fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5745 
5746 		delta = 0;
5747 		if (~bus->flowcontrol & fcbits) {
5748 			bus->fc_xoff++;
5749 			delta = 1;
5750 		}
5751 		if (bus->flowcontrol & ~fcbits) {
5752 			bus->fc_xon++;
5753 			delta = 1;
5754 		}
5755 
5756 		if (delta) {
5757 			bus->fc_rcvd++;
5758 			bus->flowcontrol = fcbits;
5759 		}
5760 
5761 		/* Check and update sequence number */
5762 		if (rxseq != seq) {
5763 			DHD_INFO(("%s: rx_seq %d, expected %d\n", __FUNCTION__, seq, rxseq));
5764 			bus->rx_badseq++;
5765 			rxseq = seq;
5766 		}
5767 
5768 		/* Check window for sanity */
5769 		if ((uint8)(txmax - bus->tx_seq) > 0x40) {
5770 			DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
5771 			           __FUNCTION__, txmax, bus->tx_seq));
5772 			txmax = bus->tx_max;
5773 		}
5774 		bus->tx_max = txmax;
5775 
5776 		/* Call a separate function for control frames */
5777 		if (chan == SDPCM_CONTROL_CHANNEL) {
5778 			dhdsdio_read_control(bus, bus->rxhdr, len, doff);
5779 			continue;
5780 		}
5781 
5782 		ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL) ||
5783 		       (chan == SDPCM_TEST_CHANNEL) || (chan == SDPCM_GLOM_CHANNEL));
5784 
5785 		/* Length to read */
5786 		rdlen = (len > firstread) ? (len - firstread) : 0;
5787 
5788 		/* May pad read to blocksize for efficiency */
5789 		if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
5790 			pad = bus->blocksize - (rdlen % bus->blocksize);
5791 			if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
5792 			    ((rdlen + pad + firstread) < MAX_RX_DATASZ))
5793 				rdlen += pad;
5794 		} else if (rdlen % DHD_SDALIGN) {
5795 			rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
5796 		}
5797 
5798 		/* Satisfy length-alignment requirements */
5799 		if (forcealign && (rdlen & (ALIGNMENT - 1)))
5800 			rdlen = ROUNDUP(rdlen, ALIGNMENT);
5801 
5802 		if ((rdlen + firstread) > MAX_RX_DATASZ) {
5803 			/* Too long -- skip this frame */
5804 			DHD_ERROR(("%s: too long: len %d rdlen %d\n", __FUNCTION__, len, rdlen));
5805 			bus->dhd->rx_errors++; bus->rx_toolong++;
5806 			dhdsdio_rxfail(bus, FALSE, FALSE);
5807 			continue;
5808 		}
5809 
5810 		dhd_os_sdlock_rxq(bus->dhd);
5811 		if (!(pkt = PKTGET(osh, (rdlen + firstread + DHD_SDALIGN), FALSE))) {
5812 			/* Give up on data, request rtx of events */
5813 			DHD_ERROR(("%s: PKTGET failed: rdlen %d chan %d\n",
5814 			           __FUNCTION__, rdlen, chan));
5815 			bus->dhd->rx_dropped++;
5816 			dhd_os_sdunlock_rxq(bus->dhd);
5817 			dhdsdio_rxfail(bus, FALSE, RETRYCHAN(chan));
5818 			continue;
5819 		}
5820 		dhd_os_sdunlock_rxq(bus->dhd);
5821 
5822 		ASSERT(!PKTLINK(pkt));
5823 
5824 		/* Leave room for what we already read, and align remainder */
5825 		ASSERT(firstread < (PKTLEN(osh, pkt)));
5826 		PKTPULL(osh, pkt, firstread);
5827 		PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN);
5828 
5829 		/* Read the remaining frame data */
5830 		sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
5831 		                            ((uint8 *)PKTDATA(osh, pkt)), rdlen, pkt, NULL, NULL);
5832 		bus->f2rxdata++;
5833 		ASSERT(sdret != BCME_PENDING);
5834 
5835 		if (sdret < 0) {
5836 			DHD_ERROR(("%s: read %d %s bytes failed: %d\n", __FUNCTION__, rdlen,
5837 			           ((chan == SDPCM_EVENT_CHANNEL) ? "event" :
5838 			            ((chan == SDPCM_DATA_CHANNEL) ? "data" : "test")), sdret));
5839 			dhd_os_sdlock_rxq(bus->dhd);
5840 			PKTFREE(bus->dhd->osh, pkt, FALSE);
5841 			dhd_os_sdunlock_rxq(bus->dhd);
5842 			bus->dhd->rx_errors++;
5843 			dhdsdio_rxfail(bus, TRUE, RETRYCHAN(chan));
5844 			continue;
5845 		}
5846 
5847 		/* Copy the already-read portion */
5848 		PKTPUSH(osh, pkt, firstread);
5849 		bcopy(bus->rxhdr, PKTDATA(osh, pkt), firstread);
5850 
5851 #ifdef DHD_DEBUG
5852 		if (DHD_BYTES_ON() && DHD_DATA_ON()) {
5853 			prhex("Rx Data", PKTDATA(osh, pkt), len);
5854 		}
5855 #endif
5856 
5857 deliver:
5858 		/* Save superframe descriptor and allocate packet frame */
5859 		if (chan == SDPCM_GLOM_CHANNEL) {
5860 			if (SDPCM_GLOMDESC(&bus->rxhdr[SDPCM_FRAMETAG_LEN])) {
5861 				DHD_GLOM(("%s: got glom descriptor, %d bytes:\n",
5862 				          __FUNCTION__, len));
5863 #ifdef DHD_DEBUG
5864 				if (DHD_GLOM_ON()) {
5865 					prhex("Glom Data", PKTDATA(osh, pkt), len);
5866 				}
5867 #endif
5868 				PKTSETLEN(osh, pkt, len);
5869 				ASSERT(doff == SDPCM_HDRLEN_RX);
5870 				PKTPULL(osh, pkt, SDPCM_HDRLEN_RX);
5871 				bus->glomd = pkt;
5872 			} else {
5873 				DHD_ERROR(("%s: glom superframe w/o descriptor!\n", __FUNCTION__));
5874 				dhdsdio_rxfail(bus, FALSE, FALSE);
5875 			}
5876 			continue;
5877 		}
5878 
5879 		/* Fill in packet len and prio, deliver upward */
5880 		PKTSETLEN(osh, pkt, len);
5881 		PKTPULL(osh, pkt, doff);
5882 
5883 #ifdef SDTEST
5884 		/* Test channel packets are processed separately */
5885 		if (chan == SDPCM_TEST_CHANNEL) {
5886 			dhdsdio_testrcv(bus, pkt, seq);
5887 			continue;
5888 		}
5889 #endif /* SDTEST */
5890 
5891 		if (PKTLEN(osh, pkt) == 0) {
5892 			dhd_os_sdlock_rxq(bus->dhd);
5893 			PKTFREE(bus->dhd->osh, pkt, FALSE);
5894 			dhd_os_sdunlock_rxq(bus->dhd);
5895 			continue;
5896 		} else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pkt, reorder_info_buf,
5897 			&reorder_info_len) != 0) {
5898 			DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__));
5899 			dhd_os_sdlock_rxq(bus->dhd);
5900 			PKTFREE(bus->dhd->osh, pkt, FALSE);
5901 			dhd_os_sdunlock_rxq(bus->dhd);
5902 			bus->dhd->rx_errors++;
5903 			continue;
5904 		}
5905 		if (reorder_info_len) {
5906 			/* Reordering info from the firmware */
5907 			dhd_process_pkt_reorder_info(bus->dhd, reorder_info_buf, reorder_info_len,
5908 				&pkt, &pkt_count);
5909 			if (pkt_count == 0)
5910 				continue;
5911 		}
5912 		else
5913 			pkt_count = 1;
5914 
5915 		/* Unlock during rx call */
5916 		dhd_os_sdunlock(bus->dhd);
5917 		dhd_rx_frame(bus->dhd, ifidx, pkt, pkt_count, chan);
5918 		dhd_os_sdlock(bus->dhd);
5919 	}
5920 	rxcount = maxframes - rxleft;
5921 #ifdef DHD_DEBUG
5922 	/* Message if we hit the limit */
5923 	if (!rxleft && !sdtest)
5924 		DHD_DATA(("%s: hit rx limit of %d frames\n", __FUNCTION__, maxframes));
5925 	else
5926 #endif /* DHD_DEBUG */
5927 	DHD_DATA(("%s: processed %d frames\n", __FUNCTION__, rxcount));
5928 	/* Back off rxseq if awaiting rtx, update rx_seq */
5929 	if (bus->rxskip)
5930 		rxseq--;
5931 	bus->rx_seq = rxseq;
5932 
5933 	if (bus->reqbussleep)
5934 	{
5935 	    dhdsdio_bussleep(bus, TRUE);
5936 		bus->reqbussleep = FALSE;
5937 	}
5938 	bus->readframes = FALSE;
5939 
5940 	return rxcount;
5941 }
5942 
5943 static uint32
dhdsdio_hostmail(dhd_bus_t * bus)5944 dhdsdio_hostmail(dhd_bus_t *bus)
5945 {
5946 	sdpcmd_regs_t *regs = bus->regs;
5947 	uint32 intstatus = 0;
5948 	uint32 hmb_data;
5949 	uint8 fcbits;
5950 	uint retries = 0;
5951 
5952 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5953 
5954 	/* Read mailbox data and ack that we did so */
5955 	R_SDREG(hmb_data, &regs->tohostmailboxdata, retries);
5956 	if (retries <= retry_limit)
5957 		W_SDREG(SMB_INT_ACK, &regs->tosbmailbox, retries);
5958 	bus->f1regdata += 2;
5959 
5960 	/* Dongle recomposed rx frames, accept them again */
5961 	if (hmb_data & HMB_DATA_NAKHANDLED) {
5962 		DHD_INFO(("Dongle reports NAK handled, expect rtx of %d\n", bus->rx_seq));
5963 		if (!bus->rxskip) {
5964 			DHD_ERROR(("%s: unexpected NAKHANDLED!\n", __FUNCTION__));
5965 		}
5966 		bus->rxskip = FALSE;
5967 		intstatus |= FRAME_AVAIL_MASK(bus);
5968 	}
5969 
5970 	/*
5971 	 * DEVREADY does not occur with gSPI.
5972 	 */
5973 	if (hmb_data & (HMB_DATA_DEVREADY | HMB_DATA_FWREADY)) {
5974 		bus->sdpcm_ver = (hmb_data & HMB_DATA_VERSION_MASK) >> HMB_DATA_VERSION_SHIFT;
5975 		if (bus->sdpcm_ver != SDPCM_PROT_VERSION)
5976 			DHD_ERROR(("Version mismatch, dongle reports %d, expecting %d\n",
5977 			           bus->sdpcm_ver, SDPCM_PROT_VERSION));
5978 		else
5979 			DHD_INFO(("Dongle ready, protocol version %d\n", bus->sdpcm_ver));
5980 		/* make sure for the SDIO_DEVICE_RXDATAINT_MODE_1 corecontrol is proper */
5981 		if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev >= 4) &&
5982 		    (bus->rxint_mode  == SDIO_DEVICE_RXDATAINT_MODE_1)) {
5983 			uint32 val;
5984 
5985 			val = R_REG(bus->dhd->osh, &bus->regs->corecontrol);
5986 			val &= ~CC_XMTDATAAVAIL_MODE;
5987 			val |= CC_XMTDATAAVAIL_CTRL;
5988 			W_REG(bus->dhd->osh, &bus->regs->corecontrol, val);
5989 
5990 			val = R_REG(bus->dhd->osh, &bus->regs->corecontrol);
5991 		}
5992 
5993 #ifdef DHD_DEBUG
5994 		/* Retrieve console state address now that firmware should have updated it */
5995 		{
5996 			sdpcm_shared_t shared;
5997 			if (dhdsdio_readshared(bus, &shared) == 0)
5998 				bus->console_addr = shared.console_addr;
5999 		}
6000 #endif /* DHD_DEBUG */
6001 	}
6002 
6003 	/*
6004 	 * Flow Control has been moved into the RX headers and this out of band
6005 	 * method isn't used any more.  Leave this here for possibly remaining backward
6006 	 * compatible with older dongles
6007 	 */
6008 	if (hmb_data & HMB_DATA_FC) {
6009 		fcbits = (hmb_data & HMB_DATA_FCDATA_MASK) >> HMB_DATA_FCDATA_SHIFT;
6010 
6011 		if (fcbits & ~bus->flowcontrol)
6012 			bus->fc_xoff++;
6013 		if (bus->flowcontrol & ~fcbits)
6014 			bus->fc_xon++;
6015 
6016 		bus->fc_rcvd++;
6017 		bus->flowcontrol = fcbits;
6018 	}
6019 
6020 #ifdef DHD_DEBUG
6021 	/* At least print a message if FW halted */
6022 	if (hmb_data & HMB_DATA_FWHALT) {
6023 		DHD_ERROR(("INTERNAL ERROR: FIRMWARE HALTED : set BUS DOWN\n"));
6024 		dhdsdio_checkdied(bus, NULL, 0);
6025 		bus->dhd->busstate = DHD_BUS_DOWN;
6026 	}
6027 #endif /* DHD_DEBUG */
6028 
6029 	/* Shouldn't be any others */
6030 	if (hmb_data & ~(HMB_DATA_DEVREADY |
6031 	                 HMB_DATA_FWHALT |
6032 	                 HMB_DATA_NAKHANDLED |
6033 	                 HMB_DATA_FC |
6034 	                 HMB_DATA_FWREADY |
6035 	                 HMB_DATA_FCDATA_MASK |
6036 	                 HMB_DATA_VERSION_MASK)) {
6037 		DHD_ERROR(("Unknown mailbox data content: 0x%02x\n", hmb_data));
6038 	}
6039 
6040 	return intstatus;
6041 }
6042 
6043 static bool
dhdsdio_dpc(dhd_bus_t * bus)6044 dhdsdio_dpc(dhd_bus_t *bus)
6045 {
6046 	bcmsdh_info_t *sdh = bus->sdh;
6047 	sdpcmd_regs_t *regs = bus->regs;
6048 	uint32 intstatus, newstatus = 0;
6049 	uint retries = 0;
6050 	uint rxlimit = dhd_rxbound; /* Rx frames to read before resched */
6051 	uint txlimit = dhd_txbound; /* Tx frames to send before resched */
6052 	uint framecnt = 0;		  /* Temporary counter of tx/rx frames */
6053 	bool rxdone = TRUE;		  /* Flag for no more read data */
6054 	bool resched = FALSE;	  /* Flag indicating resched wanted */
6055 
6056 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
6057 
6058 	if (bus->dhd->busstate == DHD_BUS_DOWN) {
6059 		DHD_ERROR(("%s: Bus down, ret\n", __FUNCTION__));
6060 		bus->intstatus = 0;
6061 		return 0;
6062 	}
6063 
6064 	/* Start with leftover status bits */
6065 	intstatus = bus->intstatus;
6066 
6067 	dhd_os_sdlock(bus->dhd);
6068 
6069 	if (!SLPAUTO_ENAB(bus) && !KSO_ENAB(bus)) {
6070 		DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
6071 		goto exit;
6072 	}
6073 
6074 	/* If waiting for HTAVAIL, check status */
6075 	if (!SLPAUTO_ENAB(bus) && (bus->clkstate == CLK_PENDING)) {
6076 		int err;
6077 		uint8 clkctl, devctl = 0;
6078 
6079 #ifdef DHD_DEBUG
6080 		/* Check for inconsistent device control */
6081 		devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
6082 		if (err) {
6083 			DHD_ERROR(("%s: error reading DEVCTL: %d\n", __FUNCTION__, err));
6084 			bus->dhd->busstate = DHD_BUS_DOWN;
6085 		} else {
6086 			ASSERT(devctl & SBSDIO_DEVCTL_CA_INT_ONLY);
6087 		}
6088 #endif /* DHD_DEBUG */
6089 
6090 		/* Read CSR, if clock on switch to AVAIL, else ignore */
6091 		clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
6092 		if (err) {
6093 			DHD_ERROR(("%s: error reading CSR: %d\n", __FUNCTION__, err));
6094 			bus->dhd->busstate = DHD_BUS_DOWN;
6095 		}
6096 
6097 		DHD_INFO(("DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n", devctl, clkctl));
6098 
6099 		if (SBSDIO_HTAV(clkctl)) {
6100 			devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
6101 			if (err) {
6102 				DHD_ERROR(("%s: error reading DEVCTL: %d\n",
6103 				           __FUNCTION__, err));
6104 				bus->dhd->busstate = DHD_BUS_DOWN;
6105 			}
6106 			devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
6107 			bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
6108 			if (err) {
6109 				DHD_ERROR(("%s: error writing DEVCTL: %d\n",
6110 				           __FUNCTION__, err));
6111 				bus->dhd->busstate = DHD_BUS_DOWN;
6112 			}
6113 			bus->clkstate = CLK_AVAIL;
6114 		} else {
6115 			goto clkwait;
6116 		}
6117 	}
6118 
6119 	BUS_WAKE(bus);
6120 
6121 	/* Make sure backplane clock is on */
6122 	dhdsdio_clkctl(bus, CLK_AVAIL, TRUE);
6123 	if (bus->clkstate != CLK_AVAIL)
6124 		goto clkwait;
6125 
6126 	/* Pending interrupt indicates new device status */
6127 	if (bus->ipend) {
6128 		bus->ipend = FALSE;
6129 		R_SDREG(newstatus, &regs->intstatus, retries);
6130 		bus->f1regdata++;
6131 		if (bcmsdh_regfail(bus->sdh))
6132 			newstatus = 0;
6133 		newstatus &= bus->hostintmask;
6134 		bus->fcstate = !!(newstatus & I_HMB_FC_STATE);
6135 		if (newstatus) {
6136 			bus->f1regdata++;
6137 			if ((bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_0) &&
6138 				(newstatus == I_XMTDATA_AVAIL)) {
6139 			}
6140 			else
6141 				W_SDREG(newstatus, &regs->intstatus, retries);
6142 		}
6143 	}
6144 
6145 	/* Merge new bits with previous */
6146 	intstatus |= newstatus;
6147 	bus->intstatus = 0;
6148 
6149 	/* Handle flow-control change: read new state in case our ack
6150 	 * crossed another change interrupt.  If change still set, assume
6151 	 * FC ON for safety, let next loop through do the debounce.
6152 	 */
6153 	if (intstatus & I_HMB_FC_CHANGE) {
6154 		intstatus &= ~I_HMB_FC_CHANGE;
6155 		W_SDREG(I_HMB_FC_CHANGE, &regs->intstatus, retries);
6156 		R_SDREG(newstatus, &regs->intstatus, retries);
6157 		bus->f1regdata += 2;
6158 		bus->fcstate = !!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE));
6159 		intstatus |= (newstatus & bus->hostintmask);
6160 	}
6161 
6162 	/* Just being here means nothing more to do for chipactive */
6163 	if (intstatus & I_CHIPACTIVE) {
6164 		/* ASSERT(bus->clkstate == CLK_AVAIL); */
6165 		intstatus &= ~I_CHIPACTIVE;
6166 	}
6167 
6168 	/* Handle host mailbox indication */
6169 	if (intstatus & I_HMB_HOST_INT) {
6170 		intstatus &= ~I_HMB_HOST_INT;
6171 		intstatus |= dhdsdio_hostmail(bus);
6172 	}
6173 
6174 	/* Generally don't ask for these, can get CRC errors... */
6175 	if (intstatus & I_WR_OOSYNC) {
6176 		DHD_ERROR(("Dongle reports WR_OOSYNC\n"));
6177 		intstatus &= ~I_WR_OOSYNC;
6178 	}
6179 
6180 	if (intstatus & I_RD_OOSYNC) {
6181 		DHD_ERROR(("Dongle reports RD_OOSYNC\n"));
6182 		intstatus &= ~I_RD_OOSYNC;
6183 	}
6184 
6185 	if (intstatus & I_SBINT) {
6186 		DHD_ERROR(("Dongle reports SBINT\n"));
6187 		intstatus &= ~I_SBINT;
6188 	}
6189 
6190 	/* Would be active due to wake-wlan in gSPI */
6191 	if (intstatus & I_CHIPACTIVE) {
6192 		DHD_INFO(("Dongle reports CHIPACTIVE\n"));
6193 		intstatus &= ~I_CHIPACTIVE;
6194 	}
6195 
6196 	/* Ignore frame indications if rxskip is set */
6197 	if (bus->rxskip) {
6198 		intstatus &= ~FRAME_AVAIL_MASK(bus);
6199 	}
6200 
6201 	/* On frame indication, read available frames */
6202 	if (PKT_AVAILABLE(bus, intstatus)) {
6203 		framecnt = dhdsdio_readframes(bus, rxlimit, &rxdone);
6204 		if (rxdone || bus->rxskip)
6205 			intstatus  &= ~FRAME_AVAIL_MASK(bus);
6206 		rxlimit -= MIN(framecnt, rxlimit);
6207 	}
6208 
6209 	/* Keep still-pending events for next scheduling */
6210 	bus->intstatus = intstatus;
6211 
6212 clkwait:
6213 	/* Re-enable interrupts to detect new device events (mailbox, rx frame)
6214 	 * or clock availability.  (Allows tx loop to check ipend if desired.)
6215 	 * (Unless register access seems hosed, as we may not be able to ACK...)
6216 	 */
6217 	if (bus->intr && bus->intdis && !bcmsdh_regfail(sdh)) {
6218 		DHD_INTR(("%s: enable SDIO interrupts, rxdone %d framecnt %d\n",
6219 		          __FUNCTION__, rxdone, framecnt));
6220 		bus->intdis = FALSE;
6221 #if defined(OOB_INTR_ONLY)
6222 		bcmsdh_oob_intr_set(1);
6223 #endif /* defined(OOB_INTR_ONLY) */
6224 		bcmsdh_intr_enable(sdh);
6225 	}
6226 
6227 #if defined(OOB_INTR_ONLY) && !defined(HW_OOB)
6228 	/* In case of SW-OOB(using edge trigger),
6229 	 * Check interrupt status in the dongle again after enable irq on the host.
6230 	 * and rechedule dpc if interrupt is pended in the dongle.
6231 	 * There is a chance to miss OOB interrupt while irq is disabled on the host.
6232 	 * No need to do this with HW-OOB(level trigger)
6233 	 */
6234 	R_SDREG(newstatus, &regs->intstatus, retries);
6235 	if (bcmsdh_regfail(bus->sdh))
6236 		newstatus = 0;
6237 	if (newstatus & bus->hostintmask) {
6238 		bus->ipend = TRUE;
6239 		resched = TRUE;
6240 	}
6241 #endif /* defined(OOB_INTR_ONLY) && !defined(HW_OOB) */
6242 
6243 #ifdef PROP_TXSTATUS
6244 	dhd_wlfc_trigger_pktcommit(bus->dhd);
6245 #endif
6246 
6247 	if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL))
6248 		dhdsdio_sendpendctl(bus);
6249 
6250 	/* Send queued frames (limit 1 if rx may still be pending) */
6251 	else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate &&
6252 	    pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit && DATAOK(bus)) {
6253 		framecnt = rxdone ? txlimit : MIN(txlimit, dhd_txminmax);
6254 		framecnt = dhdsdio_sendfromq(bus, framecnt);
6255 		txlimit -= framecnt;
6256 	}
6257 	/* Resched the DPC if ctrl cmd is pending on bus credit */
6258 	if (bus->ctrl_frame_stat)
6259 		resched = TRUE;
6260 
6261 	/* Resched if events or tx frames are pending, else await next interrupt */
6262 	/* On failed register access, all bets are off: no resched or interrupts */
6263 	if ((bus->dhd->busstate == DHD_BUS_DOWN) || bcmsdh_regfail(sdh)) {
6264 		if ((bus->sih && bus->sih->buscorerev >= 12) && !(dhdsdio_sleepcsr_get(bus) &
6265 			SBSDIO_FUNC1_SLEEPCSR_KSO_MASK)) {
6266 			/* Bus failed because of KSO */
6267 			DHD_ERROR(("%s: Bus failed due to KSO\n", __FUNCTION__));
6268 			bus->kso = FALSE;
6269 		} else {
6270 			DHD_ERROR(("%s: failed backplane access over SDIO, halting operation\n",
6271 				__FUNCTION__));
6272 			bus->dhd->busstate = DHD_BUS_DOWN;
6273 			bus->intstatus = 0;
6274 		}
6275 	} else if (bus->clkstate == CLK_PENDING) {
6276 		/* Awaiting I_CHIPACTIVE; don't resched */
6277 	} else if (bus->intstatus || bus->ipend ||
6278 	           (!bus->fcstate && pktq_mlen(&bus->txq, ~bus->flowcontrol) && DATAOK(bus)) ||
6279 			PKT_AVAILABLE(bus, bus->intstatus)) {  /* Read multiple frames */
6280 		resched = TRUE;
6281 	}
6282 
6283 	bus->dpc_sched = resched;
6284 
6285 	/* If we're done for now, turn off clock request. */
6286 	if ((bus->idletime == DHD_IDLE_IMMEDIATE) && (bus->clkstate != CLK_PENDING)) {
6287 		bus->activity = FALSE;
6288 		dhdsdio_clkctl(bus, CLK_NONE, FALSE);
6289 	}
6290 
6291 exit:
6292 
6293 	if (!resched && dhd_dpcpoll) {
6294 		if (dhdsdio_readframes(bus, dhd_rxbound, &rxdone) != 0) {
6295 			resched = TRUE;
6296 		}
6297 	}
6298 
6299 	dhd_os_sdunlock(bus->dhd);
6300 	return resched;
6301 }
6302 
6303 bool
dhd_bus_dpc(struct dhd_bus * bus)6304 dhd_bus_dpc(struct dhd_bus *bus)
6305 {
6306 	bool resched;
6307 
6308 	/* Call the DPC directly. */
6309 	DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__));
6310 	resched = dhdsdio_dpc(bus);
6311 
6312 	return resched;
6313 }
6314 
6315 void
dhdsdio_isr(void * arg)6316 dhdsdio_isr(void *arg)
6317 {
6318 	dhd_bus_t *bus = (dhd_bus_t*)arg;
6319 	bcmsdh_info_t *sdh;
6320 
6321 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
6322 
6323 	if (!bus) {
6324 		DHD_ERROR(("%s : bus is null pointer , exit \n", __FUNCTION__));
6325 		return;
6326 	}
6327 	sdh = bus->sdh;
6328 
6329 	if (bus->dhd->busstate == DHD_BUS_DOWN) {
6330 		DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__));
6331 		return;
6332 	}
6333 
6334 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
6335 
6336 	/* Count the interrupt call */
6337 	bus->intrcount++;
6338 	bus->ipend = TRUE;
6339 
6340 	/* Shouldn't get this interrupt if we're sleeping? */
6341 	if (!SLPAUTO_ENAB(bus)) {
6342 		if (bus->sleeping) {
6343 			DHD_ERROR(("INTERRUPT WHILE SLEEPING??\n"));
6344 			return;
6345 		} else if (!KSO_ENAB(bus)) {
6346 			DHD_ERROR(("ISR in devsleep 1\n"));
6347 		}
6348 	}
6349 
6350 	/* Disable additional interrupts (is this needed now)? */
6351 	if (bus->intr) {
6352 		DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
6353 	} else {
6354 		DHD_ERROR(("dhdsdio_isr() w/o interrupt configured!\n"));
6355 	}
6356 
6357 	bcmsdh_intr_disable(sdh);
6358 	bus->intdis = TRUE;
6359 
6360 #if defined(SDIO_ISR_THREAD)
6361 	DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__));
6362 	DHD_OS_WAKE_LOCK(bus->dhd);
6363 	dhdsdio_dpc(bus);
6364 	DHD_OS_WAKE_UNLOCK(bus->dhd);
6365 #else
6366 
6367 	bus->dpc_sched = TRUE;
6368 	dhd_sched_dpc(bus->dhd);
6369 
6370 #endif
6371 
6372 }
6373 
6374 #ifdef SDTEST
6375 static void
dhdsdio_pktgen_init(dhd_bus_t * bus)6376 dhdsdio_pktgen_init(dhd_bus_t *bus)
6377 {
6378 	/* Default to specified length, or full range */
6379 	if (dhd_pktgen_len) {
6380 		bus->pktgen_maxlen = MIN(dhd_pktgen_len, MAX_PKTGEN_LEN);
6381 		bus->pktgen_minlen = bus->pktgen_maxlen;
6382 	} else {
6383 		bus->pktgen_maxlen = MAX_PKTGEN_LEN;
6384 		bus->pktgen_minlen = 0;
6385 	}
6386 	bus->pktgen_len = (uint16)bus->pktgen_minlen;
6387 
6388 	/* Default to per-watchdog burst with 10s print time */
6389 	bus->pktgen_freq = 1;
6390 	bus->pktgen_print = dhd_watchdog_ms ? (10000 / dhd_watchdog_ms) : 0;
6391 	bus->pktgen_count = (dhd_pktgen * dhd_watchdog_ms + 999) / 1000;
6392 
6393 	/* Default to echo mode */
6394 	bus->pktgen_mode = DHD_PKTGEN_ECHO;
6395 	bus->pktgen_stop = 1;
6396 }
6397 
6398 static void
dhdsdio_pktgen(dhd_bus_t * bus)6399 dhdsdio_pktgen(dhd_bus_t *bus)
6400 {
6401 	void *pkt;
6402 	uint8 *data;
6403 	uint pktcount;
6404 	uint fillbyte;
6405 	osl_t *osh = bus->dhd->osh;
6406 	uint16 len;
6407 	ulong time_lapse;
6408 	uint sent_pkts;
6409 	uint rcvd_pkts;
6410 
6411 	/* Display current count if appropriate */
6412 	if (bus->pktgen_print && (++bus->pktgen_ptick >= bus->pktgen_print)) {
6413 		bus->pktgen_ptick = 0;
6414 		printf("%s: send attempts %d, rcvd %d, errors %d\n",
6415 		       __FUNCTION__, bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail);
6416 
6417 		/* Print throughput stats only for constant length packet runs */
6418 		if (bus->pktgen_minlen == bus->pktgen_maxlen) {
6419 			time_lapse = jiffies - bus->pktgen_prev_time;
6420 			bus->pktgen_prev_time = jiffies;
6421 			sent_pkts = bus->pktgen_sent - bus->pktgen_prev_sent;
6422 			bus->pktgen_prev_sent = bus->pktgen_sent;
6423 			rcvd_pkts = bus->pktgen_rcvd - bus->pktgen_prev_rcvd;
6424 			bus->pktgen_prev_rcvd = bus->pktgen_rcvd;
6425 
6426 			printf("%s: Tx Throughput %d kbps, Rx Throughput %d kbps\n",
6427 			  __FUNCTION__,
6428 			  (sent_pkts * bus->pktgen_len / jiffies_to_msecs(time_lapse)) * 8,
6429 			  (rcvd_pkts * bus->pktgen_len  / jiffies_to_msecs(time_lapse)) * 8);
6430 		}
6431 	}
6432 
6433 	/* For recv mode, just make sure dongle has started sending */
6434 	if (bus->pktgen_mode == DHD_PKTGEN_RECV) {
6435 		if (bus->pktgen_rcv_state == PKTGEN_RCV_IDLE) {
6436 			bus->pktgen_rcv_state = PKTGEN_RCV_ONGOING;
6437 			dhdsdio_sdtest_set(bus, bus->pktgen_total);
6438 		}
6439 		return;
6440 	}
6441 
6442 	/* Otherwise, generate or request the specified number of packets */
6443 	for (pktcount = 0; pktcount < bus->pktgen_count; pktcount++) {
6444 		/* Stop if total has been reached */
6445 		if (bus->pktgen_total && (bus->pktgen_sent >= bus->pktgen_total)) {
6446 			bus->pktgen_count = 0;
6447 			break;
6448 		}
6449 
6450 		/* Allocate an appropriate-sized packet */
6451 		if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) {
6452 			len = SDPCM_TEST_PKT_CNT_FLD_LEN;
6453 		} else {
6454 			len = bus->pktgen_len;
6455 		}
6456 		if (!(pkt = PKTGET(osh, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN),
6457 		                   TRUE))) {;
6458 			DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__));
6459 			break;
6460 		}
6461 		PKTALIGN(osh, pkt, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN), DHD_SDALIGN);
6462 		data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
6463 
6464 		/* Write test header cmd and extra based on mode */
6465 		switch (bus->pktgen_mode) {
6466 		case DHD_PKTGEN_ECHO:
6467 			*data++ = SDPCM_TEST_ECHOREQ;
6468 			*data++ = (uint8)bus->pktgen_sent;
6469 			break;
6470 
6471 		case DHD_PKTGEN_SEND:
6472 			*data++ = SDPCM_TEST_DISCARD;
6473 			*data++ = (uint8)bus->pktgen_sent;
6474 			break;
6475 
6476 		case DHD_PKTGEN_RXBURST:
6477 			*data++ = SDPCM_TEST_BURST;
6478 			*data++ = (uint8)bus->pktgen_count; /* Just for backward compatability */
6479 			break;
6480 
6481 		default:
6482 			DHD_ERROR(("Unrecognized pktgen mode %d\n", bus->pktgen_mode));
6483 			PKTFREE(osh, pkt, TRUE);
6484 			bus->pktgen_count = 0;
6485 			return;
6486 		}
6487 
6488 		/* Write test header length field */
6489 		*data++ = (bus->pktgen_len >> 0);
6490 		*data++ = (bus->pktgen_len >> 8);
6491 
6492 		/* Write frame count in a 4 byte field adjucent to SDPCM test header for
6493 		 * burst mode
6494 		 */
6495 		if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) {
6496 			*data++ = (uint8)(bus->pktgen_count >> 0);
6497 			*data++ = (uint8)(bus->pktgen_count >> 8);
6498 			*data++ = (uint8)(bus->pktgen_count >> 16);
6499 			*data++ = (uint8)(bus->pktgen_count >> 24);
6500 		} else {
6501 
6502 			/* Then fill in the remainder -- N/A for burst */
6503 			for (fillbyte = 0; fillbyte < len; fillbyte++)
6504 				*data++ = SDPCM_TEST_FILL(fillbyte, (uint8)bus->pktgen_sent);
6505 		}
6506 
6507 #ifdef DHD_DEBUG
6508 		if (DHD_BYTES_ON() && DHD_DATA_ON()) {
6509 			data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
6510 			prhex("dhdsdio_pktgen: Tx Data", data, PKTLEN(osh, pkt) - SDPCM_HDRLEN);
6511 		}
6512 #endif
6513 
6514 		/* Send it */
6515 		if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE, FALSE)) {
6516 			bus->pktgen_fail++;
6517 			if (bus->pktgen_stop && bus->pktgen_stop == bus->pktgen_fail)
6518 				bus->pktgen_count = 0;
6519 		}
6520 		bus->pktgen_sent++;
6521 
6522 		/* Bump length if not fixed, wrap at max */
6523 		if (++bus->pktgen_len > bus->pktgen_maxlen)
6524 			bus->pktgen_len = (uint16)bus->pktgen_minlen;
6525 
6526 		/* Special case for burst mode: just send one request! */
6527 		if (bus->pktgen_mode == DHD_PKTGEN_RXBURST)
6528 			break;
6529 	}
6530 }
6531 
6532 static void
dhdsdio_sdtest_set(dhd_bus_t * bus,uint count)6533 dhdsdio_sdtest_set(dhd_bus_t *bus, uint count)
6534 {
6535 	void *pkt;
6536 	uint8 *data;
6537 	osl_t *osh = bus->dhd->osh;
6538 
6539 	/* Allocate the packet */
6540 	if (!(pkt = PKTGET(osh, SDPCM_HDRLEN + SDPCM_TEST_HDRLEN +
6541 		SDPCM_TEST_PKT_CNT_FLD_LEN + DHD_SDALIGN, TRUE))) {
6542 		DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__));
6543 		return;
6544 	}
6545 	PKTALIGN(osh, pkt, (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN +
6546 		SDPCM_TEST_PKT_CNT_FLD_LEN), DHD_SDALIGN);
6547 	data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
6548 
6549 	/* Fill in the test header */
6550 	*data++ = SDPCM_TEST_SEND;
6551 	*data++ = (count > 0)?TRUE:FALSE;
6552 	*data++ = (bus->pktgen_maxlen >> 0);
6553 	*data++ = (bus->pktgen_maxlen >> 8);
6554 	*data++ = (uint8)(count >> 0);
6555 	*data++ = (uint8)(count >> 8);
6556 	*data++ = (uint8)(count >> 16);
6557 	*data++ = (uint8)(count >> 24);
6558 
6559 	/* Send it */
6560 	if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE, FALSE))
6561 		bus->pktgen_fail++;
6562 }
6563 
6564 
6565 static void
dhdsdio_testrcv(dhd_bus_t * bus,void * pkt,uint seq)6566 dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq)
6567 {
6568 	osl_t *osh = bus->dhd->osh;
6569 	uint8 *data;
6570 	uint pktlen;
6571 
6572 	uint8 cmd;
6573 	uint8 extra;
6574 	uint16 len;
6575 	uint16 offset;
6576 
6577 	/* Check for min length */
6578 	if ((pktlen = PKTLEN(osh, pkt)) < SDPCM_TEST_HDRLEN) {
6579 		DHD_ERROR(("dhdsdio_restrcv: toss runt frame, pktlen %d\n", pktlen));
6580 		PKTFREE(osh, pkt, FALSE);
6581 		return;
6582 	}
6583 
6584 	/* Extract header fields */
6585 	data = PKTDATA(osh, pkt);
6586 	cmd = *data++;
6587 	extra = *data++;
6588 	len = *data++; len += *data++ << 8;
6589 	DHD_TRACE(("%s:cmd:%d, xtra:%d,len:%d\n", __FUNCTION__, cmd, extra, len));
6590 	/* Check length for relevant commands */
6591 	if (cmd == SDPCM_TEST_DISCARD || cmd == SDPCM_TEST_ECHOREQ || cmd == SDPCM_TEST_ECHORSP) {
6592 		if (pktlen != len + SDPCM_TEST_HDRLEN) {
6593 			DHD_ERROR(("dhdsdio_testrcv: frame length mismatch, pktlen %d seq %d"
6594 			           " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len));
6595 			PKTFREE(osh, pkt, FALSE);
6596 			return;
6597 		}
6598 	}
6599 
6600 	/* Process as per command */
6601 	switch (cmd) {
6602 	case SDPCM_TEST_ECHOREQ:
6603 		/* Rx->Tx turnaround ok (even on NDIS w/current implementation) */
6604 		*(uint8 *)(PKTDATA(osh, pkt)) = SDPCM_TEST_ECHORSP;
6605 		if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE, FALSE) == 0) {
6606 			bus->pktgen_sent++;
6607 		} else {
6608 			bus->pktgen_fail++;
6609 			PKTFREE(osh, pkt, FALSE);
6610 		}
6611 		bus->pktgen_rcvd++;
6612 		break;
6613 
6614 	case SDPCM_TEST_ECHORSP:
6615 		if (bus->ext_loop) {
6616 			PKTFREE(osh, pkt, FALSE);
6617 			bus->pktgen_rcvd++;
6618 			break;
6619 		}
6620 
6621 		for (offset = 0; offset < len; offset++, data++) {
6622 			if (*data != SDPCM_TEST_FILL(offset, extra)) {
6623 				DHD_ERROR(("dhdsdio_testrcv: echo data mismatch: "
6624 				           "offset %d (len %d) expect 0x%02x rcvd 0x%02x\n",
6625 				           offset, len, SDPCM_TEST_FILL(offset, extra), *data));
6626 				break;
6627 			}
6628 		}
6629 		PKTFREE(osh, pkt, FALSE);
6630 		bus->pktgen_rcvd++;
6631 		break;
6632 
6633 	case SDPCM_TEST_DISCARD:
6634 		{
6635 			int i = 0;
6636 			uint8 *prn = data;
6637 			uint8 testval = extra;
6638 			for (i = 0; i < len; i++) {
6639 				if (*prn != testval) {
6640 					DHD_ERROR(("DIErr@Pkt#:%d,Ix:%d, expected:0x%x, got:0x%x\n",
6641 						i, bus->pktgen_rcvd_rcvsession, testval, *prn));
6642 					prn++; testval++;
6643 				}
6644 			}
6645 		}
6646 		PKTFREE(osh, pkt, FALSE);
6647 		bus->pktgen_rcvd++;
6648 		break;
6649 
6650 	case SDPCM_TEST_BURST:
6651 	case SDPCM_TEST_SEND:
6652 	default:
6653 		DHD_INFO(("dhdsdio_testrcv: unsupported or unknown command, pktlen %d seq %d"
6654 		          " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len));
6655 		PKTFREE(osh, pkt, FALSE);
6656 		break;
6657 	}
6658 
6659 	/* For recv mode, stop at limit (and tell dongle to stop sending) */
6660 	if (bus->pktgen_mode == DHD_PKTGEN_RECV) {
6661 		if (bus->pktgen_rcv_state != PKTGEN_RCV_IDLE) {
6662 			bus->pktgen_rcvd_rcvsession++;
6663 
6664 			if (bus->pktgen_total &&
6665 				(bus->pktgen_rcvd_rcvsession >= bus->pktgen_total)) {
6666 			bus->pktgen_count = 0;
6667 			DHD_ERROR(("Pktgen:rcv test complete!\n"));
6668 			bus->pktgen_rcv_state = PKTGEN_RCV_IDLE;
6669 			dhdsdio_sdtest_set(bus, FALSE);
6670 				bus->pktgen_rcvd_rcvsession = 0;
6671 			}
6672 		}
6673 	}
6674 }
6675 #endif /* SDTEST */
6676 
6677 extern void
dhd_disable_intr(dhd_pub_t * dhdp)6678 dhd_disable_intr(dhd_pub_t *dhdp)
6679 {
6680 	dhd_bus_t *bus;
6681 	bus = dhdp->bus;
6682 	bcmsdh_intr_disable(bus->sdh);
6683 }
6684 
6685 extern bool
dhd_bus_watchdog(dhd_pub_t * dhdp)6686 dhd_bus_watchdog(dhd_pub_t *dhdp)
6687 {
6688 	dhd_bus_t *bus;
6689 
6690 	DHD_TIMER(("%s: Enter\n", __FUNCTION__));
6691 
6692 	bus = dhdp->bus;
6693 
6694 	if (bus->dhd->dongle_reset)
6695 		return FALSE;
6696 
6697 	/* Ignore the timer if simulating bus down */
6698 	if (!SLPAUTO_ENAB(bus) && bus->sleeping)
6699 		return FALSE;
6700 
6701 	if (dhdp->busstate == DHD_BUS_DOWN)
6702 		return FALSE;
6703 
6704 	/* Poll period: check device if appropriate. */
6705 	if (!SLPAUTO_ENAB(bus) && (bus->poll && (++bus->polltick >= bus->pollrate))) {
6706 		uint32 intstatus = 0;
6707 
6708 		/* Reset poll tick */
6709 		bus->polltick = 0;
6710 
6711 		/* Check device if no interrupts */
6712 		if (!bus->intr || (bus->intrcount == bus->lastintrs)) {
6713 
6714 			if (!bus->dpc_sched) {
6715 				uint8 devpend;
6716 				devpend = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0,
6717 				                          SDIOD_CCCR_INTPEND, NULL);
6718 				intstatus = devpend & (INTR_STATUS_FUNC1 | INTR_STATUS_FUNC2);
6719 			}
6720 
6721 			/* If there is something, make like the ISR and schedule the DPC */
6722 			if (intstatus) {
6723 				bus->pollcnt++;
6724 				bus->ipend = TRUE;
6725 				if (bus->intr) {
6726 					bcmsdh_intr_disable(bus->sdh);
6727 				}
6728 				bus->dpc_sched = TRUE;
6729 				dhd_sched_dpc(bus->dhd);
6730 
6731 			}
6732 		}
6733 
6734 		/* Update interrupt tracking */
6735 		bus->lastintrs = bus->intrcount;
6736 	}
6737 
6738 #ifdef DHD_DEBUG
6739 	/* Poll for console output periodically */
6740 	if (dhdp->busstate == DHD_BUS_DATA && dhd_console_ms != 0) {
6741 		bus->console.count += dhd_watchdog_ms;
6742 		if (bus->console.count >= dhd_console_ms) {
6743 			bus->console.count -= dhd_console_ms;
6744 			/* Make sure backplane clock is on */
6745 			if (SLPAUTO_ENAB(bus))
6746 				dhdsdio_bussleep(bus, FALSE);
6747 			else
6748 			dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
6749 			if (dhdsdio_readconsole(bus) < 0)
6750 				dhd_console_ms = 0;	/* On error, stop trying */
6751 		}
6752 	}
6753 #endif /* DHD_DEBUG */
6754 
6755 #ifdef SDTEST
6756 	/* Generate packets if configured */
6757 	if (bus->pktgen_count && (++bus->pktgen_tick >= bus->pktgen_freq)) {
6758 		/* Make sure backplane clock is on */
6759 		if (SLPAUTO_ENAB(bus))
6760 			dhdsdio_bussleep(bus, FALSE);
6761 		else
6762 			dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
6763 		bus->pktgen_tick = 0;
6764 		dhdsdio_pktgen(bus);
6765 	}
6766 #endif
6767 
6768 	/* On idle timeout clear activity flag and/or turn off clock */
6769 #ifdef DHD_USE_IDLECOUNT
6770 	if (bus->activity)
6771 		bus->activity = FALSE;
6772 	else {
6773 		bus->idlecount++;
6774 
6775 		if ((bus->idletime > 0) && (bus->idlecount >= bus->idletime)) {
6776 			DHD_TIMER(("%s: DHD Idle state!!\n", __FUNCTION__));
6777 			if (SLPAUTO_ENAB(bus)) {
6778 				if (dhdsdio_bussleep(bus, TRUE) != BCME_BUSY)
6779 					dhd_os_wd_timer(bus->dhd, 0);
6780 			} else
6781 				dhdsdio_clkctl(bus, CLK_NONE, FALSE);
6782 
6783 			bus->idlecount = 0;
6784 		}
6785 	}
6786 #else
6787 	if ((bus->idletime > 0) && (bus->clkstate == CLK_AVAIL)) {
6788 		if (++bus->idlecount > bus->idletime) {
6789 			bus->idlecount = 0;
6790 			if (bus->activity) {
6791 				bus->activity = FALSE;
6792 				if (SLPAUTO_ENAB(bus)) {
6793 					if (!bus->readframes)
6794 						dhdsdio_bussleep(bus, TRUE);
6795 					else
6796 						bus->reqbussleep = TRUE;
6797 				}
6798 				else
6799 					dhdsdio_clkctl(bus, CLK_NONE, FALSE);
6800 			}
6801 		}
6802 	}
6803 #endif /* DHD_USE_IDLECOUNT */
6804 
6805 	return bus->ipend;
6806 }
6807 
6808 #ifdef DHD_DEBUG
6809 extern int
dhd_bus_console_in(dhd_pub_t * dhdp,uchar * msg,uint msglen)6810 dhd_bus_console_in(dhd_pub_t *dhdp, uchar *msg, uint msglen)
6811 {
6812 	dhd_bus_t *bus = dhdp->bus;
6813 	uint32 addr, val;
6814 	int rv;
6815 	void *pkt;
6816 
6817 	/* Address could be zero if CONSOLE := 0 in dongle Makefile */
6818 	if (bus->console_addr == 0)
6819 		return BCME_UNSUPPORTED;
6820 
6821 	/* Exclusive bus access */
6822 	dhd_os_sdlock(bus->dhd);
6823 
6824 	/* Don't allow input if dongle is in reset */
6825 	if (bus->dhd->dongle_reset) {
6826 		dhd_os_sdunlock(bus->dhd);
6827 		return BCME_NOTREADY;
6828 	}
6829 
6830 	/* Request clock to allow SDIO accesses */
6831 	BUS_WAKE(bus);
6832 	/* No pend allowed since txpkt is called later, ht clk has to be on */
6833 	dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
6834 
6835 	/* Zero cbuf_index */
6836 	addr = bus->console_addr + OFFSETOF(hndrte_cons_t, cbuf_idx);
6837 	val = htol32(0);
6838 	if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0)
6839 		goto done;
6840 
6841 	/* Write message into cbuf */
6842 	addr = bus->console_addr + OFFSETOF(hndrte_cons_t, cbuf);
6843 	if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)msg, msglen)) < 0)
6844 		goto done;
6845 
6846 	/* Write length into vcons_in */
6847 	addr = bus->console_addr + OFFSETOF(hndrte_cons_t, vcons_in);
6848 	val = htol32(msglen);
6849 	if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0)
6850 		goto done;
6851 
6852 	/* Bump dongle by sending an empty packet on the event channel.
6853 	 * sdpcm_sendup (RX) checks for virtual console input.
6854 	 */
6855 	if ((pkt = PKTGET(bus->dhd->osh, 4 + SDPCM_RESERVE, TRUE)) != NULL)
6856 		dhdsdio_txpkt(bus, pkt, SDPCM_EVENT_CHANNEL, TRUE, FALSE);
6857 
6858 done:
6859 	if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
6860 		bus->activity = FALSE;
6861 		dhdsdio_clkctl(bus, CLK_NONE, TRUE);
6862 	}
6863 
6864 	dhd_os_sdunlock(bus->dhd);
6865 
6866 	return rv;
6867 }
6868 #endif /* DHD_DEBUG */
6869 
6870 #ifdef DHD_DEBUG
6871 static void
dhd_dump_cis(uint fn,uint8 * cis)6872 dhd_dump_cis(uint fn, uint8 *cis)
6873 {
6874 	uint byte, tag, tdata;
6875 	DHD_INFO(("Function %d CIS:\n", fn));
6876 
6877 	for (tdata = byte = 0; byte < SBSDIO_CIS_SIZE_LIMIT; byte++) {
6878 		if ((byte % 16) == 0)
6879 			DHD_INFO(("    "));
6880 		DHD_INFO(("%02x ", cis[byte]));
6881 		if ((byte % 16) == 15)
6882 			DHD_INFO(("\n"));
6883 		if (!tdata--) {
6884 			tag = cis[byte];
6885 			if (tag == 0xff)
6886 				break;
6887 			else if (!tag)
6888 				tdata = 0;
6889 			else if ((byte + 1) < SBSDIO_CIS_SIZE_LIMIT)
6890 				tdata = cis[byte + 1] + 1;
6891 			else
6892 				DHD_INFO(("]"));
6893 		}
6894 	}
6895 	if ((byte % 16) != 15)
6896 		DHD_INFO(("\n"));
6897 }
6898 #endif /* DHD_DEBUG */
6899 
6900 static bool
dhdsdio_chipmatch(uint16 chipid)6901 dhdsdio_chipmatch(uint16 chipid)
6902 {
6903 	if (chipid == BCM4325_CHIP_ID)
6904 		return TRUE;
6905 	if (chipid == BCM4329_CHIP_ID)
6906 		return TRUE;
6907 	if (chipid == BCM4315_CHIP_ID)
6908 		return TRUE;
6909 	if (chipid == BCM4319_CHIP_ID)
6910 		return TRUE;
6911 	if (chipid == BCM4336_CHIP_ID)
6912 		return TRUE;
6913 	if (chipid == BCM4330_CHIP_ID)
6914 		return TRUE;
6915 	if (chipid == BCM43237_CHIP_ID)
6916 		return TRUE;
6917 	if (chipid == BCM43362_CHIP_ID)
6918 		return TRUE;
6919 	if (chipid == BCM4314_CHIP_ID)
6920 		return TRUE;
6921 	if (chipid == BCM43242_CHIP_ID)
6922 		return TRUE;
6923 	if (chipid == BCM43340_CHIP_ID)
6924 		return TRUE;
6925 	if (chipid == BCM43341_CHIP_ID)
6926 		return TRUE;
6927 	if (chipid == BCM43143_CHIP_ID)
6928 		return TRUE;
6929 	if (chipid == BCM43342_CHIP_ID)
6930 		return TRUE;
6931 	if (chipid == BCM4334_CHIP_ID)
6932 		return TRUE;
6933 	if (chipid == BCM43239_CHIP_ID)
6934 		return TRUE;
6935 	if (chipid == BCM4324_CHIP_ID)
6936 		return TRUE;
6937 	if (chipid == BCM4335_CHIP_ID)
6938 		return TRUE;
6939 	if (chipid == BCM4339_CHIP_ID)
6940 		return TRUE;
6941 	if (chipid == BCM4350_CHIP_ID)
6942 		return TRUE;
6943 	return FALSE;
6944 }
6945 
6946 static void *
dhdsdio_probe(uint16 venid,uint16 devid,uint16 bus_no,uint16 slot,uint16 func,uint bustype,void * regsva,osl_t * osh,void * sdh)6947 dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot,
6948 	uint16 func, uint bustype, void *regsva, osl_t * osh, void *sdh)
6949 {
6950 	int ret;
6951 	dhd_bus_t *bus;
6952 #ifdef GET_CUSTOM_MAC_ENABLE
6953 	struct ether_addr ea_addr;
6954 #endif /* GET_CUSTOM_MAC_ENABLE */
6955 
6956 
6957 	/* Init global variables at run-time, not as part of the declaration.
6958 	 * This is required to support init/de-init of the driver. Initialization
6959 	 * of globals as part of the declaration results in non-deterministic
6960 	 * behavior since the value of the globals may be different on the
6961 	 * first time that the driver is initialized vs subsequent initializations.
6962 	 */
6963 	dhd_txbound = DHD_TXBOUND;
6964 	dhd_rxbound = DHD_RXBOUND;
6965 	dhd_alignctl = TRUE;
6966 	sd1idle = TRUE;
6967 	dhd_readahead = TRUE;
6968 	retrydata = FALSE;
6969 	dhd_doflow = TRUE;
6970 	dhd_dongle_ramsize = 0;
6971 	dhd_txminmax = DHD_TXMINMAX;
6972 
6973 	forcealign = TRUE;
6974 
6975 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
6976 	DHD_INFO(("%s: venid 0x%04x devid 0x%04x\n", __FUNCTION__, venid, devid));
6977 
6978 	/* We make assumptions about address window mappings */
6979 	ASSERT((uintptr)regsva == SI_ENUM_BASE);
6980 
6981 	/* BCMSDH passes venid and devid based on CIS parsing -- but low-power start
6982 	 * means early parse could fail, so here we should get either an ID
6983 	 * we recognize OR (-1) indicating we must request power first.
6984 	 */
6985 	/* Check the Vendor ID */
6986 	switch (venid) {
6987 		case 0x0000:
6988 		case VENDOR_BROADCOM:
6989 			break;
6990 		default:
6991 			DHD_ERROR(("%s: unknown vendor: 0x%04x\n",
6992 			           __FUNCTION__, venid));
6993 			goto forcereturn;
6994 	}
6995 
6996 	/* Check the Device ID and make sure it's one that we support */
6997 	switch (devid) {
6998 		case BCM4325_D11DUAL_ID:		/* 4325 802.11a/g id */
6999 		case BCM4325_D11G_ID:			/* 4325 802.11g 2.4Ghz band id */
7000 		case BCM4325_D11A_ID:			/* 4325 802.11a 5Ghz band id */
7001 			DHD_INFO(("%s: found 4325 Dongle\n", __FUNCTION__));
7002 			break;
7003 		case BCM4329_D11N_ID:		/* 4329 802.11n dualband device */
7004 		case BCM4329_D11N2G_ID:		/* 4329 802.11n 2.4G device */
7005 		case BCM4329_D11N5G_ID:		/* 4329 802.11n 5G device */
7006 		case 0x4329:
7007 			DHD_INFO(("%s: found 4329 Dongle\n", __FUNCTION__));
7008 			break;
7009 		case BCM4315_D11DUAL_ID:		/* 4315 802.11a/g id */
7010 		case BCM4315_D11G_ID:			/* 4315 802.11g id */
7011 		case BCM4315_D11A_ID:			/* 4315 802.11a id */
7012 			DHD_INFO(("%s: found 4315 Dongle\n", __FUNCTION__));
7013 			break;
7014 		case BCM4319_D11N_ID:			/* 4319 802.11n id */
7015 		case BCM4319_D11N2G_ID:			/* 4319 802.11n2g id */
7016 		case BCM4319_D11N5G_ID:			/* 4319 802.11n5g id */
7017 			DHD_INFO(("%s: found 4319 Dongle\n", __FUNCTION__));
7018 			break;
7019 		case 0:
7020 			DHD_INFO(("%s: allow device id 0, will check chip internals\n",
7021 			          __FUNCTION__));
7022 			break;
7023 
7024 		default:
7025 			DHD_ERROR(("%s: skipping 0x%04x/0x%04x, not a dongle\n",
7026 			           __FUNCTION__, venid, devid));
7027 			goto forcereturn;
7028 	}
7029 
7030 	if (osh == NULL) {
7031 		/* Ask the OS interface part for an OSL handle */
7032 		if (!(osh = dhd_osl_attach(sdh, DHD_BUS))) {
7033 			DHD_ERROR(("%s: osl_attach failed!\n", __FUNCTION__));
7034 			goto forcereturn;
7035 		}
7036 	}
7037 
7038 	/* Allocate private bus interface state */
7039 	if (!(bus = MALLOC(osh, sizeof(dhd_bus_t)))) {
7040 		DHD_ERROR(("%s: MALLOC of dhd_bus_t failed\n", __FUNCTION__));
7041 		goto fail;
7042 	}
7043 	bzero(bus, sizeof(dhd_bus_t));
7044 	bus->sdh = sdh;
7045 	bus->cl_devid = (uint16)devid;
7046 	bus->bus = DHD_BUS;
7047 	bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1;
7048 	bus->usebufpool = FALSE; /* Use bufpool if allocated, else use locally malloced rxbuf */
7049 
7050 	/* attach the common module */
7051 	dhd_common_init(osh);
7052 
7053 	/* attempt to attach to the dongle */
7054 	if (!(dhdsdio_probe_attach(bus, osh, sdh, regsva, devid))) {
7055 		DHD_ERROR(("%s: dhdsdio_probe_attach failed\n", __FUNCTION__));
7056 		goto fail;
7057 	}
7058 
7059 	/* Attach to the dhd/OS/network interface */
7060 	if (!(bus->dhd = dhd_attach(osh, bus, SDPCM_RESERVE))) {
7061 		DHD_ERROR(("%s: dhd_attach failed\n", __FUNCTION__));
7062 		goto fail;
7063 	}
7064 
7065 	/* Allocate buffers */
7066 	if (!(dhdsdio_probe_malloc(bus, osh, sdh))) {
7067 		DHD_ERROR(("%s: dhdsdio_probe_malloc failed\n", __FUNCTION__));
7068 		goto fail;
7069 	}
7070 
7071 	if (!(dhdsdio_probe_init(bus, osh, sdh))) {
7072 		DHD_ERROR(("%s: dhdsdio_probe_init failed\n", __FUNCTION__));
7073 		goto fail;
7074 	}
7075 
7076 	if (bus->intr) {
7077 		/* Register interrupt callback, but mask it (not operational yet). */
7078 		DHD_INTR(("%s: disable SDIO interrupts (not interested yet)\n", __FUNCTION__));
7079 		bcmsdh_intr_disable(sdh);
7080 		if ((ret = bcmsdh_intr_reg(sdh, dhdsdio_isr, bus)) != 0) {
7081 			DHD_ERROR(("%s: FAILED: bcmsdh_intr_reg returned %d\n",
7082 			           __FUNCTION__, ret));
7083 			goto fail;
7084 		}
7085 		DHD_INTR(("%s: registered SDIO interrupt function ok\n", __FUNCTION__));
7086 	} else {
7087 		DHD_INFO(("%s: SDIO interrupt function is NOT registered due to polling mode\n",
7088 		           __FUNCTION__));
7089 	}
7090 
7091 	DHD_INFO(("%s: completed!!\n", __FUNCTION__));
7092 
7093 #ifdef GET_CUSTOM_MAC_ENABLE
7094 	/* Read MAC address from external customer place 	*/
7095 	memset(&ea_addr, 0, sizeof(ea_addr));
7096 	ret = dhd_custom_get_mac_address(ea_addr.octet);
7097 	if (!ret) {
7098 		memcpy(bus->dhd->mac.octet, (void *)&ea_addr, ETHER_ADDR_LEN);
7099 	}
7100 #endif /* GET_CUSTOM_MAC_ENABLE */
7101 
7102 	/* if firmware path present try to download and bring up bus */
7103 	bus->dhd->hang_report  = TRUE;
7104 	if (dhd_download_fw_on_driverload) {
7105 		if ((ret = dhd_bus_start(bus->dhd)) != 0) {
7106 			DHD_ERROR(("%s: dhd_bus_start failed\n", __FUNCTION__));
7107 				goto fail;
7108 		}
7109 	}
7110 	/* Ok, have the per-port tell the stack we're open for business */
7111 	if (dhd_net_attach(bus->dhd, 0) != 0) {
7112 		DHD_ERROR(("%s: Net attach failed!!\n", __FUNCTION__));
7113 		goto fail;
7114 	}
7115 
7116 
7117 
7118 	return bus;
7119 
7120 fail:
7121 	dhdsdio_release(bus, osh);
7122 
7123 forcereturn:
7124 
7125 	return NULL;
7126 }
7127 
7128 static bool
dhdsdio_probe_attach(struct dhd_bus * bus,osl_t * osh,void * sdh,void * regsva,uint16 devid)7129 dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva,
7130                      uint16 devid)
7131 {
7132 	int err = 0;
7133 	uint8 clkctl = 0;
7134 
7135 	bus->alp_only = TRUE;
7136 	bus->sih = NULL;
7137 
7138 	/* Return the window to backplane enumeration space for core access */
7139 	if (dhdsdio_set_siaddr_window(bus, SI_ENUM_BASE)) {
7140 		DHD_ERROR(("%s: FAILED to return to SI_ENUM_BASE\n", __FUNCTION__));
7141 	}
7142 
7143 
7144 	/* Force PLL off until si_attach() programs PLL control regs */
7145 
7146 
7147 
7148 	bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, DHD_INIT_CLKCTL1, &err);
7149 	if (!err)
7150 		clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
7151 
7152 	if (err || ((clkctl & ~SBSDIO_AVBITS) != DHD_INIT_CLKCTL1)) {
7153 		DHD_ERROR(("dhdsdio_probe: ChipClkCSR access: err %d wrote 0x%02x read 0x%02x\n",
7154 		           err, DHD_INIT_CLKCTL1, clkctl));
7155 		goto fail;
7156 	}
7157 
7158 #ifdef DHD_DEBUG
7159 	if (DHD_INFO_ON()) {
7160 		uint fn, numfn;
7161 		uint8 *cis[SDIOD_MAX_IOFUNCS];
7162 		int err = 0;
7163 
7164 		numfn = bcmsdh_query_iofnum(sdh);
7165 		ASSERT(numfn <= SDIOD_MAX_IOFUNCS);
7166 
7167 		/* Make sure ALP is available before trying to read CIS */
7168 		SPINWAIT(((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
7169 		                                    SBSDIO_FUNC1_CHIPCLKCSR, NULL)),
7170 		          !SBSDIO_ALPAV(clkctl)), PMU_MAX_TRANSITION_DLY);
7171 
7172 		/* Now request ALP be put on the bus */
7173 		bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
7174 		                 DHD_INIT_CLKCTL2, &err);
7175 		OSL_DELAY(65);
7176 
7177 		for (fn = 0; fn <= numfn; fn++) {
7178 			if (!(cis[fn] = MALLOC(osh, SBSDIO_CIS_SIZE_LIMIT))) {
7179 				DHD_INFO(("dhdsdio_probe: fn %d cis malloc failed\n", fn));
7180 				break;
7181 			}
7182 			bzero(cis[fn], SBSDIO_CIS_SIZE_LIMIT);
7183 
7184 			if ((err = bcmsdh_cis_read(sdh, fn, cis[fn], SBSDIO_CIS_SIZE_LIMIT))) {
7185 				DHD_INFO(("dhdsdio_probe: fn %d cis read err %d\n", fn, err));
7186 				MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT);
7187 				break;
7188 			}
7189 			dhd_dump_cis(fn, cis[fn]);
7190 		}
7191 
7192 		while (fn-- > 0) {
7193 			ASSERT(cis[fn]);
7194 			MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT);
7195 		}
7196 
7197 		if (err) {
7198 			DHD_ERROR(("dhdsdio_probe: failure reading or parsing CIS\n"));
7199 			goto fail;
7200 		}
7201 	}
7202 #endif /* DHD_DEBUG */
7203 
7204 	/* si_attach() will provide an SI handle and scan the backplane */
7205 	if (!(bus->sih = si_attach((uint)devid, osh, regsva, DHD_BUS, sdh,
7206 	                           &bus->vars, &bus->varsz))) {
7207 		DHD_ERROR(("%s: si_attach failed!\n", __FUNCTION__));
7208 		goto fail;
7209 	}
7210 
7211 
7212 #ifdef DHD_DEBUG
7213 	DHD_ERROR(("F1 signature OK, socitype:0x%x chip:0x%4x rev:0x%x pkg:0x%x\n",
7214 		bus->sih->socitype, bus->sih->chip, bus->sih->chiprev,
7215 		bus->sih->chippkg));
7216 #endif /* DHD_DEBUG */
7217 
7218 
7219 	bcmsdh_chipinfo(sdh, bus->sih->chip, bus->sih->chiprev);
7220 
7221 	if (!dhdsdio_chipmatch((uint16)bus->sih->chip)) {
7222 		DHD_ERROR(("%s: unsupported chip: 0x%04x\n",
7223 		           __FUNCTION__, bus->sih->chip));
7224 		goto fail;
7225 	}
7226 
7227 	if (bus->sih->buscorerev >= 12)
7228 		dhdsdio_clk_kso_init(bus);
7229 	else
7230 		bus->kso = TRUE;
7231 
7232 	if (CST4330_CHIPMODE_SDIOD(bus->sih->chipst)) {
7233 	}
7234 
7235 	si_sdiod_drive_strength_init(bus->sih, osh, dhd_sdiod_drive_strength);
7236 
7237 
7238 	/* Get info on the ARM and SOCRAM cores... */
7239 	if (!DHD_NOPMU(bus)) {
7240 		if ((si_setcore(bus->sih, ARM7S_CORE_ID, 0)) ||
7241 		    (si_setcore(bus->sih, ARMCM3_CORE_ID, 0)) ||
7242 		    (si_setcore(bus->sih, ARMCR4_CORE_ID, 0))) {
7243 			bus->armrev = si_corerev(bus->sih);
7244 		} else {
7245 			DHD_ERROR(("%s: failed to find ARM core!\n", __FUNCTION__));
7246 			goto fail;
7247 		}
7248 
7249 		if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
7250 			if (!(bus->orig_ramsize = si_socram_size(bus->sih))) {
7251 				DHD_ERROR(("%s: failed to find SOCRAM memory!\n", __FUNCTION__));
7252 				goto fail;
7253 			}
7254 		} else {
7255 			/* cr4 has a different way to find the RAM size from TCM's */
7256 			if (!(bus->orig_ramsize = si_tcm_size(bus->sih))) {
7257 				DHD_ERROR(("%s: failed to find CR4-TCM memory!\n", __FUNCTION__));
7258 				goto fail;
7259 			}
7260 			/* also populate base address */
7261 			switch ((uint16)bus->sih->chip) {
7262 			case BCM4335_CHIP_ID:
7263 			case BCM4339_CHIP_ID:
7264 				bus->dongle_ram_base = CR4_4335_RAM_BASE;
7265 				break;
7266 			case BCM4350_CHIP_ID:
7267 				bus->dongle_ram_base = CR4_4350_RAM_BASE;
7268 				break;
7269 			case BCM4360_CHIP_ID:
7270 				bus->dongle_ram_base = CR4_4360_RAM_BASE;
7271 				break;
7272 			default:
7273 				bus->dongle_ram_base = 0;
7274 				DHD_ERROR(("%s: WARNING: Using default ram base at 0x%x\n",
7275 				           __FUNCTION__, bus->dongle_ram_base));
7276 			}
7277 		}
7278 		bus->ramsize = bus->orig_ramsize;
7279 		if (dhd_dongle_ramsize)
7280 			dhd_dongle_setramsize(bus, dhd_dongle_ramsize);
7281 
7282 		DHD_ERROR(("DHD: dongle ram size is set to %d(orig %d) at 0x%x\n",
7283 		           bus->ramsize, bus->orig_ramsize, bus->dongle_ram_base));
7284 
7285 		bus->srmemsize = si_socram_srmem_size(bus->sih);
7286 	}
7287 
7288 	/* ...but normally deal with the SDPCMDEV core */
7289 	if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0)) &&
7290 	    !(bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0))) {
7291 		DHD_ERROR(("%s: failed to find SDIODEV core!\n", __FUNCTION__));
7292 		goto fail;
7293 	}
7294 	bus->sdpcmrev = si_corerev(bus->sih);
7295 
7296 	/* Set core control so an SDIO reset does a backplane reset */
7297 	OR_REG(osh, &bus->regs->corecontrol, CC_BPRESEN);
7298 	bus->rxint_mode = SDIO_DEVICE_HMB_RXINT;
7299 
7300 	if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev >= 4) &&
7301 		(bus->rxint_mode  == SDIO_DEVICE_RXDATAINT_MODE_1))
7302 	{
7303 		uint32 val;
7304 
7305 		val = R_REG(osh, &bus->regs->corecontrol);
7306 		val &= ~CC_XMTDATAAVAIL_MODE;
7307 		val |= CC_XMTDATAAVAIL_CTRL;
7308 		W_REG(osh, &bus->regs->corecontrol, val);
7309 	}
7310 
7311 
7312 	pktq_init(&bus->txq, (PRIOMASK + 1), QLEN);
7313 
7314 	/* Locate an appropriately-aligned portion of hdrbuf */
7315 	bus->rxhdr = (uint8 *)ROUNDUP((uintptr)&bus->hdrbuf[0], DHD_SDALIGN);
7316 
7317 	/* Set the poll and/or interrupt flags */
7318 	bus->intr = (bool)dhd_intr;
7319 	if ((bus->poll = (bool)dhd_poll))
7320 		bus->pollrate = 1;
7321 
7322 #ifdef BCMSDIOH_TXGLOM
7323 	/* Setting default Glom mode */
7324 	bus->glom_mode = bcmsdh_set_mode(bus->sdh, SDPCM_DEFGLOM_MODE);
7325 	/* Setting default Glom size */
7326 	bus->glomsize = SDPCM_DEFGLOM_SIZE;
7327 #endif
7328 
7329 	return TRUE;
7330 
7331 fail:
7332 	if (bus->sih != NULL) {
7333 		si_detach(bus->sih);
7334 		bus->sih = NULL;
7335 	}
7336 	return FALSE;
7337 }
7338 
7339 static bool
dhdsdio_probe_malloc(dhd_bus_t * bus,osl_t * osh,void * sdh)7340 dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh)
7341 {
7342 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7343 
7344 	if (bus->dhd->maxctl) {
7345 		bus->rxblen = ROUNDUP((bus->dhd->maxctl + SDPCM_HDRLEN), ALIGNMENT) + DHD_SDALIGN;
7346 		if (!(bus->rxbuf = DHD_OS_PREALLOC(osh, DHD_PREALLOC_RXBUF, bus->rxblen))) {
7347 			DHD_ERROR(("%s: MALLOC of %d-byte rxbuf failed\n",
7348 			           __FUNCTION__, bus->rxblen));
7349 			goto fail;
7350 		}
7351 	}
7352 	/* Allocate buffer to receive glomed packet */
7353 	if (!(bus->databuf = DHD_OS_PREALLOC(osh, DHD_PREALLOC_DATABUF, MAX_DATA_BUF))) {
7354 		DHD_ERROR(("%s: MALLOC of %d-byte databuf failed\n",
7355 			__FUNCTION__, MAX_DATA_BUF));
7356 		/* release rxbuf which was already located as above */
7357 		if (!bus->rxblen)
7358 			DHD_OS_PREFREE(osh, bus->rxbuf, bus->rxblen);
7359 		goto fail;
7360 	}
7361 
7362 	/* Align the buffer */
7363 	if ((uintptr)bus->databuf % DHD_SDALIGN)
7364 		bus->dataptr = bus->databuf + (DHD_SDALIGN - ((uintptr)bus->databuf % DHD_SDALIGN));
7365 	else
7366 		bus->dataptr = bus->databuf;
7367 
7368 	return TRUE;
7369 
7370 fail:
7371 	return FALSE;
7372 }
7373 
7374 static bool
dhdsdio_probe_init(dhd_bus_t * bus,osl_t * osh,void * sdh)7375 dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh)
7376 {
7377 	int32 fnum;
7378 
7379 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7380 
7381 #ifdef SDTEST
7382 	dhdsdio_pktgen_init(bus);
7383 #endif /* SDTEST */
7384 
7385 	/* Disable F2 to clear any intermediate frame state on the dongle */
7386 	bcmsdh_cfg_write(sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL);
7387 
7388 	bus->dhd->busstate = DHD_BUS_DOWN;
7389 	bus->sleeping = FALSE;
7390 	bus->rxflow = FALSE;
7391 	bus->prev_rxlim_hit = 0;
7392 
7393 	/* Done with backplane-dependent accesses, can drop clock... */
7394 	bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
7395 
7396 	/* ...and initialize clock/power states */
7397 	bus->clkstate = CLK_SDONLY;
7398 	bus->idletime = (int32)dhd_idletime;
7399 	bus->idleclock = DHD_IDLE_ACTIVE;
7400 
7401 	/* Query the SD clock speed */
7402 	if (bcmsdh_iovar_op(sdh, "sd_divisor", NULL, 0,
7403 	                    &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) {
7404 		DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_divisor"));
7405 		bus->sd_divisor = -1;
7406 	} else {
7407 		DHD_INFO(("%s: Initial value for %s is %d\n",
7408 		          __FUNCTION__, "sd_divisor", bus->sd_divisor));
7409 	}
7410 
7411 	/* Query the SD bus mode */
7412 	if (bcmsdh_iovar_op(sdh, "sd_mode", NULL, 0,
7413 	                    &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) {
7414 		DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_mode"));
7415 		bus->sd_mode = -1;
7416 	} else {
7417 		DHD_INFO(("%s: Initial value for %s is %d\n",
7418 		          __FUNCTION__, "sd_mode", bus->sd_mode));
7419 	}
7420 
7421 	/* Query the F2 block size, set roundup accordingly */
7422 	fnum = 2;
7423 	if (bcmsdh_iovar_op(sdh, "sd_blocksize", &fnum, sizeof(int32),
7424 	                    &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) {
7425 		bus->blocksize = 0;
7426 		DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize"));
7427 	} else {
7428 		DHD_INFO(("%s: Initial value for %s is %d\n",
7429 		          __FUNCTION__, "sd_blocksize", bus->blocksize));
7430 
7431 		if ((bus->sih->chip == BCM4335_CHIP_ID) ||
7432 			(bus->sih->chip == BCM4339_CHIP_ID))
7433 			dhd_overflow_war(bus);
7434 	}
7435 	bus->roundup = MIN(max_roundup, bus->blocksize);
7436 
7437 	/* Query if bus module supports packet chaining, default to use if supported */
7438 	if (bcmsdh_iovar_op(sdh, "sd_rxchain", NULL, 0,
7439 	                    &bus->sd_rxchain, sizeof(int32), FALSE) != BCME_OK) {
7440 		bus->sd_rxchain = FALSE;
7441 	} else {
7442 		DHD_INFO(("%s: bus module (through bcmsdh API) %s chaining\n",
7443 		          __FUNCTION__, (bus->sd_rxchain ? "supports" : "does not support")));
7444 	}
7445 	bus->use_rxchain = (bool)bus->sd_rxchain;
7446 
7447 	return TRUE;
7448 }
7449 
7450 bool
dhd_bus_download_firmware(struct dhd_bus * bus,osl_t * osh,char * pfw_path,char * pnv_path)7451 dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh,
7452                           char *pfw_path, char *pnv_path)
7453 {
7454 	bool ret;
7455 	bus->fw_path = pfw_path;
7456 	bus->nv_path = pnv_path;
7457 
7458 	ret = dhdsdio_download_firmware(bus, osh, bus->sdh);
7459 
7460 
7461 	return ret;
7462 }
7463 
7464 static bool
dhdsdio_download_firmware(struct dhd_bus * bus,osl_t * osh,void * sdh)7465 dhdsdio_download_firmware(struct dhd_bus *bus, osl_t *osh, void *sdh)
7466 {
7467 	bool ret;
7468 
7469 	DHD_OS_WAKE_LOCK(bus->dhd);
7470 
7471 	/* Download the firmware */
7472 	dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
7473 
7474 	ret = _dhdsdio_download_firmware(bus) == 0;
7475 
7476 	dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
7477 
7478 	DHD_OS_WAKE_UNLOCK(bus->dhd);
7479 	return ret;
7480 }
7481 
7482 /* Detach and free everything */
7483 static void
dhdsdio_release(dhd_bus_t * bus,osl_t * osh)7484 dhdsdio_release(dhd_bus_t *bus, osl_t *osh)
7485 {
7486 	bool dongle_isolation = FALSE;
7487 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7488 
7489 	if (bus) {
7490 		ASSERT(osh);
7491 
7492 		if (bus->dhd) {
7493 			dongle_isolation = bus->dhd->dongle_isolation;
7494 			dhd_detach(bus->dhd);
7495 		}
7496 
7497 		/* De-register interrupt handler */
7498 		bcmsdh_intr_disable(bus->sdh);
7499 		bcmsdh_intr_dereg(bus->sdh);
7500 
7501 		if (bus->dhd) {
7502 			dhdsdio_release_dongle(bus, osh, dongle_isolation, TRUE);
7503 			dhd_free(bus->dhd);
7504 			bus->dhd = NULL;
7505 		}
7506 
7507 		dhdsdio_release_malloc(bus, osh);
7508 
7509 #ifdef DHD_DEBUG
7510 		if (bus->console.buf != NULL)
7511 			MFREE(osh, bus->console.buf, bus->console.bufsize);
7512 #endif
7513 
7514 		MFREE(osh, bus, sizeof(dhd_bus_t));
7515 	}
7516 
7517 	if (osh)
7518 		dhd_osl_detach(osh);
7519 
7520 	DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
7521 }
7522 
7523 static void
dhdsdio_release_malloc(dhd_bus_t * bus,osl_t * osh)7524 dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh)
7525 {
7526 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7527 
7528 	if (bus->dhd && bus->dhd->dongle_reset)
7529 		return;
7530 
7531 	if (bus->rxbuf) {
7532 #ifndef CONFIG_DHD_USE_STATIC_BUF
7533 		MFREE(osh, bus->rxbuf, bus->rxblen);
7534 #endif
7535 		bus->rxctl = bus->rxbuf = NULL;
7536 		bus->rxlen = 0;
7537 	}
7538 
7539 	if (bus->databuf) {
7540 #ifndef CONFIG_DHD_USE_STATIC_BUF
7541 		MFREE(osh, bus->databuf, MAX_DATA_BUF);
7542 #endif
7543 		bus->databuf = NULL;
7544 	}
7545 
7546 	if (bus->vars && bus->varsz) {
7547 		MFREE(osh, bus->vars, bus->varsz);
7548 		bus->vars = NULL;
7549 	}
7550 
7551 }
7552 
7553 
7554 static void
dhdsdio_release_dongle(dhd_bus_t * bus,osl_t * osh,bool dongle_isolation,bool reset_flag)7555 dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation, bool reset_flag)
7556 {
7557 	DHD_TRACE(("%s: Enter bus->dhd %p bus->dhd->dongle_reset %d \n", __FUNCTION__,
7558 		bus->dhd, bus->dhd->dongle_reset));
7559 
7560 	if ((bus->dhd && bus->dhd->dongle_reset) && reset_flag)
7561 		return;
7562 
7563 	if (bus->sih) {
7564 #if !defined(BCMLXSDMMC)
7565 		if (bus->dhd) {
7566 			dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
7567 		}
7568 		if (KSO_ENAB(bus) && (dongle_isolation == FALSE))
7569 			si_watchdog(bus->sih, 4);
7570 #endif /* !defined(BCMLXSDMMC) */
7571 		if (bus->dhd) {
7572 			dhdsdio_clkctl(bus, CLK_NONE, FALSE);
7573 		}
7574 		si_detach(bus->sih);
7575 		bus->sih = NULL;
7576 		if (bus->vars && bus->varsz)
7577 			MFREE(osh, bus->vars, bus->varsz);
7578 		bus->vars = NULL;
7579 	}
7580 
7581 	DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
7582 }
7583 
7584 static void
dhdsdio_disconnect(void * ptr)7585 dhdsdio_disconnect(void *ptr)
7586 {
7587 	dhd_bus_t *bus = (dhd_bus_t *)ptr;
7588 
7589 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7590 
7591 
7592 
7593 	if (bus) {
7594 		ASSERT(bus->dhd);
7595 		dhdsdio_release(bus, bus->dhd->osh);
7596 	}
7597 
7598 
7599 
7600 	DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
7601 }
7602 
7603 
7604 /* Register/Unregister functions are called by the main DHD entry
7605  * point (e.g. module insertion) to link with the bus driver, in
7606  * order to look for or await the device.
7607  */
7608 
7609 static bcmsdh_driver_t dhd_sdio = {
7610 	dhdsdio_probe,
7611 	dhdsdio_disconnect
7612 };
7613 
7614 int
dhd_bus_register(void)7615 dhd_bus_register(void)
7616 {
7617 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7618 
7619 	return bcmsdh_register(&dhd_sdio);
7620 }
7621 
7622 void
dhd_bus_unregister(void)7623 dhd_bus_unregister(void)
7624 {
7625 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7626 
7627 	bcmsdh_unregister();
7628 }
7629 
7630 #if defined(BCMLXSDMMC)
7631 /* Register a dummy SDIO client driver in order to be notified of new SDIO device */
dhd_bus_reg_sdio_notify(void * semaphore)7632 int dhd_bus_reg_sdio_notify(void* semaphore)
7633 {
7634 	return bcmsdh_reg_sdio_notify(semaphore);
7635 }
7636 
dhd_bus_unreg_sdio_notify(void)7637 void dhd_bus_unreg_sdio_notify(void)
7638 {
7639 	bcmsdh_unreg_sdio_notify();
7640 }
7641 #endif /* defined(BCMLXSDMMC) */
7642 
7643 #ifdef BCMEMBEDIMAGE
7644 static int
dhdsdio_download_code_array(struct dhd_bus * bus)7645 dhdsdio_download_code_array(struct dhd_bus *bus)
7646 {
7647 	int bcmerror = -1;
7648 	int offset = 0;
7649 	unsigned char *ularray = NULL;
7650 
7651 	DHD_INFO(("%s: download embedded firmware...\n", __FUNCTION__));
7652 
7653 	/* Download image */
7654 	while ((offset + MEMBLOCK) < sizeof(dlarray)) {
7655 		/* check if CR4 */
7656 		if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
7657 			/* if address is 0, store the reset instruction to be written in 0 */
7658 
7659 			if (offset == 0) {
7660 				bus->resetinstr = *(((uint32*)dlarray));
7661 				/* Add start of RAM address to the address given by user */
7662 				offset += bus->dongle_ram_base;
7663 			}
7664 		}
7665 
7666 		bcmerror = dhdsdio_membytes(bus, TRUE, offset,
7667 			(uint8 *) (dlarray + offset), MEMBLOCK);
7668 		if (bcmerror) {
7669 			DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
7670 			        __FUNCTION__, bcmerror, MEMBLOCK, offset));
7671 			goto err;
7672 		}
7673 
7674 		offset += MEMBLOCK;
7675 	}
7676 
7677 	if (offset < sizeof(dlarray)) {
7678 		bcmerror = dhdsdio_membytes(bus, TRUE, offset,
7679 			(uint8 *) (dlarray + offset), sizeof(dlarray) - offset);
7680 		if (bcmerror) {
7681 			DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
7682 			        __FUNCTION__, bcmerror, sizeof(dlarray) - offset, offset));
7683 			goto err;
7684 		}
7685 	}
7686 
7687 #ifdef DHD_DEBUG
7688 	/* Upload and compare the downloaded code */
7689 	{
7690 		ularray = MALLOC(bus->dhd->osh, bus->ramsize);
7691 		/* Upload image to verify downloaded contents. */
7692 		offset = 0;
7693 		memset(ularray, 0xaa, bus->ramsize);
7694 		while ((offset + MEMBLOCK) < sizeof(dlarray)) {
7695 			bcmerror = dhdsdio_membytes(bus, FALSE, offset, ularray + offset, MEMBLOCK);
7696 			if (bcmerror) {
7697 				DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n",
7698 					__FUNCTION__, bcmerror, MEMBLOCK, offset));
7699 				goto err;
7700 			}
7701 
7702 			offset += MEMBLOCK;
7703 		}
7704 
7705 		if (offset < sizeof(dlarray)) {
7706 			bcmerror = dhdsdio_membytes(bus, FALSE, offset,
7707 				ularray + offset, sizeof(dlarray) - offset);
7708 			if (bcmerror) {
7709 				DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n",
7710 					__FUNCTION__, bcmerror, sizeof(dlarray) - offset, offset));
7711 				goto err;
7712 			}
7713 		}
7714 
7715 		if (memcmp(dlarray, ularray, sizeof(dlarray))) {
7716 			DHD_ERROR(("%s: Downloaded image is corrupted (%s, %s, %s).\n",
7717 			           __FUNCTION__, dlimagename, dlimagever, dlimagedate));
7718 			goto err;
7719 		} else
7720 			DHD_ERROR(("%s: Download, Upload and compare succeeded (%s, %s, %s).\n",
7721 			           __FUNCTION__, dlimagename, dlimagever, dlimagedate));
7722 
7723 	}
7724 #endif /* DHD_DEBUG */
7725 
7726 err:
7727 	if (ularray)
7728 		MFREE(bus->dhd->osh, ularray, bus->ramsize);
7729 	return bcmerror;
7730 }
7731 #endif /* BCMEMBEDIMAGE */
7732 
7733 static int
dhdsdio_download_code_file(struct dhd_bus * bus,char * pfw_path)7734 dhdsdio_download_code_file(struct dhd_bus *bus, char *pfw_path)
7735 {
7736 	int bcmerror = -1;
7737 	int offset = 0;
7738 	int len;
7739 	void *image = NULL;
7740 	uint8 *memblock = NULL, *memptr;
7741 
7742 	DHD_INFO(("%s: download firmware %s\n", __FUNCTION__, pfw_path));
7743 
7744 	image = dhd_os_open_image(pfw_path);
7745 	if (image == NULL)
7746 		goto err;
7747 
7748 	memptr = memblock = MALLOC(bus->dhd->osh, MEMBLOCK + DHD_SDALIGN);
7749 	if (memblock == NULL) {
7750 		DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, MEMBLOCK));
7751 		goto err;
7752 	}
7753 	if ((uint32)(uintptr)memblock % DHD_SDALIGN)
7754 		memptr += (DHD_SDALIGN - ((uint32)(uintptr)memblock % DHD_SDALIGN));
7755 
7756 	/* Download image */
7757 	while ((len = dhd_os_get_image_block((char*)memptr, MEMBLOCK, image))) {
7758 		if (len < 0) {
7759 			DHD_ERROR(("%s: dhd_os_get_image_block failed (%d)\n", __FUNCTION__, len));
7760 			bcmerror = BCME_ERROR;
7761 			goto err;
7762 		}
7763 		/* check if CR4 */
7764 		if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
7765 			/* if address is 0, store the reset instruction to be written in 0 */
7766 
7767 			if (offset == 0) {
7768 				bus->resetinstr = *(((uint32*)memptr));
7769 				/* Add start of RAM address to the address given by user */
7770 				offset += bus->dongle_ram_base;
7771 			}
7772 		}
7773 
7774 		bcmerror = dhdsdio_membytes(bus, TRUE, offset, memptr, len);
7775 		if (bcmerror) {
7776 			DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
7777 			        __FUNCTION__, bcmerror, MEMBLOCK, offset));
7778 			goto err;
7779 		}
7780 
7781 		offset += MEMBLOCK;
7782 	}
7783 
7784 err:
7785 	if (memblock)
7786 		MFREE(bus->dhd->osh, memblock, MEMBLOCK + DHD_SDALIGN);
7787 
7788 	if (image)
7789 		dhd_os_close_image(image);
7790 
7791 	return bcmerror;
7792 }
7793 
7794 /*
7795 	EXAMPLE: nvram_array
7796 	nvram_arry format:
7797 	name=value
7798 	Use carriage return at the end of each assignment, and an empty string with
7799 	carriage return at the end of array.
7800 
7801 	For example:
7802 	unsigned char  nvram_array[] = {"name1=value1\n", "name2=value2\n", "\n"};
7803 	Hex values start with 0x, and mac addr format: xx:xx:xx:xx:xx:xx.
7804 
7805 	Search "EXAMPLE: nvram_array" to see how the array is activated.
7806 */
7807 
7808 void
dhd_bus_set_nvram_params(struct dhd_bus * bus,const char * nvram_params)7809 dhd_bus_set_nvram_params(struct dhd_bus * bus, const char *nvram_params)
7810 {
7811 	bus->nvram_params = nvram_params;
7812 }
7813 
7814 static int
dhdsdio_download_nvram(struct dhd_bus * bus)7815 dhdsdio_download_nvram(struct dhd_bus *bus)
7816 {
7817 	int bcmerror = -1;
7818 	uint len;
7819 	void * image = NULL;
7820 	char * memblock = NULL;
7821 	char *bufp;
7822 	char *pnv_path;
7823 	bool nvram_file_exists;
7824 
7825 	pnv_path = bus->nv_path;
7826 
7827 	nvram_file_exists = ((pnv_path != NULL) && (pnv_path[0] != '\0'));
7828 	if (!nvram_file_exists && (bus->nvram_params == NULL))
7829 		return (0);
7830 
7831 	if (nvram_file_exists) {
7832 		image = dhd_os_open_image(pnv_path);
7833 		if (image == NULL)
7834 			goto err;
7835 	}
7836 
7837 	memblock = MALLOC(bus->dhd->osh, MAX_NVRAMBUF_SIZE);
7838 	if (memblock == NULL) {
7839 		DHD_ERROR(("%s: Failed to allocate memory %d bytes\n",
7840 		           __FUNCTION__, MAX_NVRAMBUF_SIZE));
7841 		goto err;
7842 	}
7843 
7844 	/* Download variables */
7845 	if (nvram_file_exists) {
7846 		len = dhd_os_get_image_block(memblock, MAX_NVRAMBUF_SIZE, image);
7847 	}
7848 	else {
7849 		len = strlen(bus->nvram_params);
7850 		ASSERT(len <= MAX_NVRAMBUF_SIZE);
7851 		memcpy(memblock, bus->nvram_params, len);
7852 	}
7853 	if (len > 0 && len < MAX_NVRAMBUF_SIZE) {
7854 		bufp = (char *)memblock;
7855 		bufp[len] = 0;
7856 		len = process_nvram_vars(bufp, len);
7857 		if (len % 4) {
7858 			len += 4 - (len % 4);
7859 		}
7860 		bufp += len;
7861 		*bufp++ = 0;
7862 		if (len)
7863 			bcmerror = dhdsdio_downloadvars(bus, memblock, len + 1);
7864 		if (bcmerror) {
7865 			DHD_ERROR(("%s: error downloading vars: %d\n",
7866 			           __FUNCTION__, bcmerror));
7867 		}
7868 	}
7869 	else {
7870 		DHD_ERROR(("%s: error reading nvram file: %d\n",
7871 		           __FUNCTION__, len));
7872 		bcmerror = BCME_SDIO_ERROR;
7873 	}
7874 
7875 err:
7876 	if (memblock)
7877 		MFREE(bus->dhd->osh, memblock, MAX_NVRAMBUF_SIZE);
7878 
7879 	if (image)
7880 		dhd_os_close_image(image);
7881 
7882 	return bcmerror;
7883 }
7884 
7885 static int
_dhdsdio_download_firmware(struct dhd_bus * bus)7886 _dhdsdio_download_firmware(struct dhd_bus *bus)
7887 {
7888 	int bcmerror = -1;
7889 
7890 	bool embed = FALSE;	/* download embedded firmware */
7891 	bool dlok = FALSE;	/* download firmware succeeded */
7892 
7893 	/* Out immediately if no image to download */
7894 	if ((bus->fw_path == NULL) || (bus->fw_path[0] == '\0')) {
7895 #ifdef BCMEMBEDIMAGE
7896 		embed = TRUE;
7897 #else
7898 		return 0;
7899 #endif
7900 	}
7901 
7902 	/* Keep arm in reset */
7903 	if (dhdsdio_download_state(bus, TRUE)) {
7904 		DHD_ERROR(("%s: error placing ARM core in reset\n", __FUNCTION__));
7905 		goto err;
7906 	}
7907 
7908 	/* External image takes precedence if specified */
7909 	if ((bus->fw_path != NULL) && (bus->fw_path[0] != '\0')) {
7910 		if (dhdsdio_download_code_file(bus, bus->fw_path)) {
7911 			DHD_ERROR(("%s: dongle image file download failed\n", __FUNCTION__));
7912 #ifdef BCMEMBEDIMAGE
7913 			embed = TRUE;
7914 #else
7915 			goto err;
7916 #endif
7917 		}
7918 		else {
7919 			embed = FALSE;
7920 			dlok = TRUE;
7921 		}
7922 	}
7923 
7924 #ifdef BCMEMBEDIMAGE
7925 	if (embed) {
7926 		if (dhdsdio_download_code_array(bus)) {
7927 			DHD_ERROR(("%s: dongle image array download failed\n", __FUNCTION__));
7928 			goto err;
7929 		}
7930 		else {
7931 			dlok = TRUE;
7932 		}
7933 	}
7934 #else
7935 	BCM_REFERENCE(embed);
7936 #endif
7937 	if (!dlok) {
7938 		DHD_ERROR(("%s: dongle image download failed\n", __FUNCTION__));
7939 		goto err;
7940 	}
7941 
7942 	/* EXAMPLE: nvram_array */
7943 	/* If a valid nvram_arry is specified as above, it can be passed down to dongle */
7944 	/* dhd_bus_set_nvram_params(bus, (char *)&nvram_array); */
7945 
7946 	/* External nvram takes precedence if specified */
7947 	if (dhdsdio_download_nvram(bus)) {
7948 		DHD_ERROR(("%s: dongle nvram file download failed\n", __FUNCTION__));
7949 		goto err;
7950 	}
7951 
7952 	/* Take arm out of reset */
7953 	if (dhdsdio_download_state(bus, FALSE)) {
7954 		DHD_ERROR(("%s: error getting out of ARM core reset\n", __FUNCTION__));
7955 		goto err;
7956 	}
7957 
7958 	bcmerror = 0;
7959 
7960 err:
7961 	return bcmerror;
7962 }
7963 
7964 static int
dhd_bcmsdh_recv_buf(dhd_bus_t * bus,uint32 addr,uint fn,uint flags,uint8 * buf,uint nbytes,void * pkt,bcmsdh_cmplt_fn_t complete,void * handle)7965 dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes,
7966 	void *pkt, bcmsdh_cmplt_fn_t complete, void *handle)
7967 {
7968 	int status;
7969 
7970 	if (!KSO_ENAB(bus)) {
7971 		DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
7972 		return BCME_NODEVICE;
7973 	}
7974 
7975 	status = bcmsdh_recv_buf(bus->sdh, addr, fn, flags, buf, nbytes, pkt, complete, handle);
7976 
7977 	return status;
7978 }
7979 
7980 static int
dhd_bcmsdh_send_buf(dhd_bus_t * bus,uint32 addr,uint fn,uint flags,uint8 * buf,uint nbytes,void * pkt,bcmsdh_cmplt_fn_t complete,void * handle)7981 dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes,
7982 	void *pkt, bcmsdh_cmplt_fn_t complete, void *handle)
7983 {
7984 	if (!KSO_ENAB(bus)) {
7985 		DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
7986 		return BCME_NODEVICE;
7987 	}
7988 
7989 	return (bcmsdh_send_buf(bus->sdh, addr, fn, flags, buf, nbytes, pkt, complete, handle));
7990 }
7991 
7992 #ifdef BCMSDIOH_TXGLOM
7993 static void
dhd_bcmsdh_glom_post(dhd_bus_t * bus,uint8 * frame,void * pkt,uint len)7994 dhd_bcmsdh_glom_post(dhd_bus_t *bus, uint8 *frame, void *pkt, uint len)
7995 {
7996 	bcmsdh_glom_post(bus->sdh, frame, pkt, len);
7997 }
7998 
7999 static void
dhd_bcmsdh_glom_clear(dhd_bus_t * bus)8000 dhd_bcmsdh_glom_clear(dhd_bus_t *bus)
8001 {
8002 	bcmsdh_glom_clear(bus->sdh);
8003 }
8004 #endif
8005 
8006 uint
dhd_bus_chip(struct dhd_bus * bus)8007 dhd_bus_chip(struct dhd_bus *bus)
8008 {
8009 	ASSERT(bus->sih != NULL);
8010 	return bus->sih->chip;
8011 }
8012 
8013 void *
dhd_bus_pub(struct dhd_bus * bus)8014 dhd_bus_pub(struct dhd_bus *bus)
8015 {
8016 	return bus->dhd;
8017 }
8018 
8019 void *
dhd_bus_txq(struct dhd_bus * bus)8020 dhd_bus_txq(struct dhd_bus *bus)
8021 {
8022 	return &bus->txq;
8023 }
8024 
8025 uint
dhd_bus_hdrlen(struct dhd_bus * bus)8026 dhd_bus_hdrlen(struct dhd_bus *bus)
8027 {
8028 	return SDPCM_HDRLEN;
8029 }
8030 
8031 int
dhd_bus_devreset(dhd_pub_t * dhdp,uint8 flag)8032 dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag)
8033 {
8034 	int bcmerror = 0;
8035 	dhd_bus_t *bus;
8036 
8037 	bus = dhdp->bus;
8038 
8039 	if (flag == TRUE) {
8040 		if (!bus->dhd->dongle_reset) {
8041 			dhd_os_sdlock(dhdp);
8042 			dhd_os_wd_timer(dhdp, 0);
8043 #if !defined(IGNORE_ETH0_DOWN)
8044 			/* Force flow control as protection when stop come before ifconfig_down */
8045 			dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON);
8046 #endif /* !defined(IGNORE_ETH0_DOWN) */
8047 			/* Expect app to have torn down any connection before calling */
8048 			/* Stop the bus, disable F2 */
8049 			dhd_bus_stop(bus, FALSE);
8050 
8051 #if defined(OOB_INTR_ONLY)
8052 			/* Clean up any pending IRQ */
8053 			dhd_enable_oob_intr(bus, FALSE);
8054 			bcmsdh_set_irq(FALSE);
8055 			bcmsdh_unregister_oob_intr();
8056 #endif
8057 
8058 			/* Clean tx/rx buffer pointers, detach from the dongle */
8059 			dhdsdio_release_dongle(bus, bus->dhd->osh, TRUE, TRUE);
8060 
8061 			bus->dhd->dongle_reset = TRUE;
8062 			bus->dhd->up = FALSE;
8063 #ifdef BCMSDIOH_TXGLOM
8064 			dhd_txglom_enable(dhdp, FALSE);
8065 #endif
8066 			dhd_os_sdunlock(dhdp);
8067 
8068 			DHD_TRACE(("%s:  WLAN OFF DONE\n", __FUNCTION__));
8069 			/* App can now remove power from device */
8070 		} else
8071 			bcmerror = BCME_SDIO_ERROR;
8072 	} else {
8073 		/* App must have restored power to device before calling */
8074 
8075 		DHD_TRACE(("\n\n%s: == WLAN ON ==\n", __FUNCTION__));
8076 
8077 		if (bus->dhd->dongle_reset) {
8078 			/* Turn on WLAN */
8079 #ifdef DHDTHREAD
8080 			dhd_os_sdlock(dhdp);
8081 #endif /* DHDTHREAD */
8082 			/* Reset SD client */
8083 			bcmsdh_reset(bus->sdh);
8084 
8085 			/* Attempt to re-attach & download */
8086 			if (dhdsdio_probe_attach(bus, bus->dhd->osh, bus->sdh,
8087 			                        (uint32 *)SI_ENUM_BASE,
8088 			                        bus->cl_devid)) {
8089 				/* Attempt to download binary to the dongle */
8090 				if (dhdsdio_probe_init(bus, bus->dhd->osh, bus->sdh) &&
8091 					dhdsdio_download_firmware(bus, bus->dhd->osh, bus->sdh)) {
8092 
8093 					/* Re-init bus, enable F2 transfer */
8094 					bcmerror = dhd_bus_init((dhd_pub_t *) bus->dhd, FALSE);
8095 					if (bcmerror == BCME_OK) {
8096 #if defined(OOB_INTR_ONLY)
8097 						/* make sure oob intr get registered */
8098 						if (!bcmsdh_is_oob_intr_registered()) {
8099 							sdioh_start(NULL, 1);
8100 							bcmsdh_register_oob_intr(dhdp);
8101 							dhdp->iswl = TRUE;
8102 						}
8103 
8104 						bcmsdh_set_irq(TRUE);
8105 						dhd_enable_oob_intr(bus, TRUE);
8106 #endif
8107 
8108 						bus->dhd->dongle_reset = FALSE;
8109 						bus->dhd->up = TRUE;
8110 
8111 #if !defined(IGNORE_ETH0_DOWN)
8112 						/* Restore flow control  */
8113 						dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF);
8114 #endif
8115 						dhd_os_wd_timer(dhdp, dhd_watchdog_ms);
8116 						DHD_TRACE(("%s: WLAN ON DONE\n", __FUNCTION__));
8117 					} else {
8118 						dhd_bus_stop(bus, FALSE);
8119 						dhdsdio_release_dongle(bus, bus->dhd->osh,
8120 							TRUE, FALSE);
8121 					}
8122 				} else
8123 					bcmerror = BCME_SDIO_ERROR;
8124 			} else
8125 				bcmerror = BCME_SDIO_ERROR;
8126 
8127 #ifdef DHDTHREAD
8128 				dhd_os_sdunlock(dhdp);
8129 #endif /* DHDTHREAD */
8130 		} else {
8131 			bcmerror = BCME_SDIO_ERROR;
8132 			DHD_INFO(("%s called when dongle is not in reset\n",
8133 				__FUNCTION__));
8134 			DHD_INFO(("Will call dhd_bus_start instead\n"));
8135 			sdioh_start(NULL, 1);
8136 			if ((bcmerror = dhd_bus_start(dhdp)) != 0)
8137 				DHD_ERROR(("%s: dhd_bus_start fail with %d\n",
8138 					__FUNCTION__, bcmerror));
8139 		}
8140 	}
8141 	return bcmerror;
8142 }
8143 
8144 /* Get Chip ID version */
dhd_bus_chip_id(dhd_pub_t * dhdp)8145 uint dhd_bus_chip_id(dhd_pub_t *dhdp)
8146 {
8147 	dhd_bus_t *bus = dhdp->bus;
8148 
8149 	return bus->sih->chip;
8150 }
8151 
8152 /* Get Chip Rev ID version */
dhd_bus_chiprev_id(dhd_pub_t * dhdp)8153 uint dhd_bus_chiprev_id(dhd_pub_t *dhdp)
8154 {
8155 	dhd_bus_t *bus = dhdp->bus;
8156 
8157 	return bus->sih->chiprev;
8158 }
8159 
8160 /* Get Chip Pkg ID version */
dhd_bus_chippkg_id(dhd_pub_t * dhdp)8161 uint dhd_bus_chippkg_id(dhd_pub_t *dhdp)
8162 {
8163 	dhd_bus_t *bus = dhdp->bus;
8164 
8165 	return bus->sih->chippkg;
8166 }
8167 
8168 int
dhd_bus_membytes(dhd_pub_t * dhdp,bool set,uint32 address,uint8 * data,uint size)8169 dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint size)
8170 {
8171 	dhd_bus_t *bus;
8172 
8173 	bus = dhdp->bus;
8174 	return dhdsdio_membytes(bus, set, address, data, size);
8175 }
8176 
8177 int
dhd_enableOOB(dhd_pub_t * dhd,bool sleep)8178 dhd_enableOOB(dhd_pub_t *dhd, bool sleep)
8179 {
8180 	dhd_bus_t *bus = dhd->bus;
8181 	sdpcmd_regs_t *regs = bus->regs;
8182 	uint retries = 0;
8183 
8184 	if (sleep) {
8185 		dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
8186 		/* Tell device to start using OOB wakeup */
8187 		W_SDREG(SMB_USE_OOB, &regs->tosbmailbox, retries);
8188 		if (retries > retry_limit) {
8189 			DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
8190 			return BCME_BUSY;
8191 		}
8192 		/* Turn off our contribution to the HT clock request */
8193 		dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
8194 	} else {
8195 		/* Make sure the controller has the bus up */
8196 		dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
8197 
8198 		/* Send misc interrupt to indicate OOB not needed */
8199 		W_SDREG(0, &regs->tosbmailboxdata, retries);
8200 		if (retries <= retry_limit)
8201 			W_SDREG(SMB_DEV_INT, &regs->tosbmailbox, retries);
8202 
8203 		if (retries > retry_limit)
8204 			DHD_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n"));
8205 
8206 		/* Make sure we have SD bus access */
8207 		dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
8208 	}
8209 	return BCME_OK;
8210 }
8211 
8212 void
dhd_bus_pktq_flush(dhd_pub_t * dhdp)8213 dhd_bus_pktq_flush(dhd_pub_t *dhdp)
8214 {
8215 	dhd_bus_t *bus = dhdp->bus;
8216 	/* Clear the data packet queues */
8217 	pktq_flush(dhdp->osh, &bus->txq, TRUE, NULL, 0);
8218 }
8219 
8220 int
dhd_sr_config(dhd_pub_t * dhd,bool on)8221 dhd_sr_config(dhd_pub_t *dhd, bool on)
8222 {
8223 	dhd_bus_t *bus = dhd->bus;
8224 
8225 	if (!bus->_srenab)
8226 		return -1;
8227 
8228 	return dhdsdio_clk_devsleep_iovar(bus, on);
8229 }
8230 
8231 uint16
dhd_get_chipid(dhd_pub_t * dhd)8232 dhd_get_chipid(dhd_pub_t *dhd)
8233 {
8234 	dhd_bus_t *bus = dhd->bus;
8235 
8236 	if (bus && bus->sih)
8237 		return (uint16)bus->sih->chip;
8238 	else
8239 		return 0;
8240 }
8241