• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * DHD Bus Module for SDIO
3  *
4  * Copyright (C) 1999-2009, 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,v 1.157.2.27.2.33.2.89 2009/10/28 05:49:40 Exp $
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 <sbchipc.h>
44 #include <sbhnddma.h>
45 
46 #include <sdio.h>
47 #include <sbsdio.h>
48 #include <sbsdpcmdev.h>
49 #include <bcmsdpcm.h>
50 
51 #include <proto/ethernet.h>
52 #include <proto/802.1d.h>
53 #include <proto/802.11.h>
54 
55 #include <dngl_stats.h>
56 #include <dhd.h>
57 #include <dhd_bus.h>
58 #include <dhd_proto.h>
59 #include <dhd_dbg.h>
60 #include <dhdioctl.h>
61 #include <sdiovar.h>
62 
63 #define QLEN		256	/* bulk rx and tx queue lengths */
64 #define FCHI		(QLEN - 10)
65 #define FCLOW		(FCHI / 2)
66 #define PRIOMASK	7
67 
68 #define TXRETRIES	2	/* # of retries for tx frames */
69 
70 #if defined(CONFIG_MACH_SANDGATE2G)
71 #define DHD_RXBOUND	250	/* Default for max rx frames in one scheduling */
72 #else
73 #define DHD_RXBOUND	50	/* Default for max rx frames in one scheduling */
74 #endif /* defined(CONFIG_MACH_SANDGATE2G) */
75 
76 #define DHD_TXBOUND	20	/* Default for max tx frames in one scheduling */
77 
78 #define DHD_TXMINMAX	1	/* Max tx frames if rx still pending */
79 
80 #define MEMBLOCK	2048		/* Block size used for downloading of dongle image */
81 #define MAX_DATA_BUF	(32 * 1024)	/* Must be large enough to hold biggest possible glom */
82 
83 /* Packet alignment for most efficient SDIO (can change based on platform) */
84 #ifndef DHD_SDALIGN
85 #define DHD_SDALIGN	32
86 #endif
87 #if !ISPOWEROF2(DHD_SDALIGN)
88 #error DHD_SDALIGN is not a power of 2!
89 #endif
90 
91 #ifndef DHD_FIRSTREAD
92 #define DHD_FIRSTREAD	32
93 #endif
94 #if !ISPOWEROF2(DHD_FIRSTREAD)
95 #error DHD_FIRSTREAD is not a power of 2!
96 #endif
97 
98 /* Total length of frame header for dongle protocol */
99 #define SDPCM_HDRLEN	(SDPCM_FRAMETAG_LEN + SDPCM_SWHEADER_LEN)
100 #ifdef SDTEST
101 #define SDPCM_RESERVE	(SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN)
102 #else
103 #define SDPCM_RESERVE	(SDPCM_HDRLEN + DHD_SDALIGN)
104 #endif
105 
106 /* Space for header read, limit for data packets */
107 #ifndef MAX_HDR_READ
108 #define MAX_HDR_READ	32
109 #endif
110 #if !ISPOWEROF2(MAX_HDR_READ)
111 #error MAX_HDR_READ is not a power of 2!
112 #endif
113 
114 #define MAX_RX_DATASZ	2048
115 
116 /* Maximum milliseconds to wait for F2 to come up */
117 #define DHD_WAIT_F2RDY	3000
118 
119 /* Bump up limit on waiting for HT to account for first startup;
120  * if the image is doing a CRC calculation before programming the PMU
121  * for HT availability, it could take a couple hundred ms more, so
122  * max out at a half second (500000us).
123  */
124 #if (PMU_MAX_TRANSITION_DLY <= 500000)
125 #undef PMU_MAX_TRANSITION_DLY
126 #define PMU_MAX_TRANSITION_DLY 500000
127 #endif
128 
129 /* Value for ChipClockCSR during initial setup */
130 #define DHD_INIT_CLKCTL1	(SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ)
131 #define DHD_INIT_CLKCTL2	(SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP)
132 
133 /* Flags for SDH calls */
134 #define F2SYNC	(SDIO_REQ_4BYTE | SDIO_REQ_FIXED)
135 
136 /* Packet free applicable unconditionally for sdio and sdspi.  Conditional if
137  * bufpool was present for gspi bus.
138  */
139 #define PKTFREE2()		if ((bus->bus != SPI_BUS) || bus->usebufpool) \
140 					PKTFREE(bus->dhd->osh, pkt, FALSE);
141 DHD_SPINWAIT_SLEEP_INIT(sdioh_spinwait_sleep);
142 extern int dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len);
143 
144 
145 /* Private data for SDIO bus interaction */
146 typedef struct dhd_bus {
147 	dhd_pub_t	*dhd;
148 
149 	bcmsdh_info_t	*sdh;			/* Handle for BCMSDH calls */
150 	si_t		*sih;			/* Handle for SI calls */
151 	char		*vars;			/* Variables (from CIS and/or other) */
152 	uint		varsz;			/* Size of variables buffer */
153 	uint32		sbaddr;			/* Current SB window pointer (-1, invalid) */
154 
155 	sdpcmd_regs_t	*regs;			/* Registers for SDIO core */
156 	uint		sdpcmrev;		/* SDIO core revision */
157 	uint		armrev;			/* CPU core revision */
158 	uint		ramrev;			/* SOCRAM core revision */
159 	uint32		ramsize;		/* Size of RAM in SOCRAM (bytes) */
160 	uint32		orig_ramsize;		/* Size of RAM in SOCRAM (bytes) */
161 
162 	uint32		bus;			/* gSPI or SDIO bus */
163 	uint32		hostintmask;		/* Copy of Host Interrupt Mask */
164 	uint32		intstatus;		/* Intstatus bits (events) pending */
165 	bool		dpc_sched;		/* Indicates DPC schedule (intrpt rcvd) */
166 	bool		fcstate;		/* State of dongle flow-control */
167 
168 	uint16		cl_devid;		/* cached devid for dhdsdio_probe_attach() */
169 	char		*fw_path; /* module_param: path to firmware image */
170 	char		*nv_path; /* module_param: path to nvram vars file */
171 	const char      *nvram_params;		/* user specified nvram params. */
172 
173 	uint		blocksize;		/* Block size of SDIO transfers */
174 	uint		roundup;		/* Max roundup limit */
175 
176 	struct pktq	txq;			/* Queue length used for flow-control */
177 	uint8		flowcontrol;		/* per prio flow control bitmask */
178 	uint8		tx_seq;			/* Transmit sequence number (next) */
179 	uint8		tx_max;			/* Maximum transmit sequence allowed */
180 
181 	uint8		hdrbuf[MAX_HDR_READ + DHD_SDALIGN];
182 	uint8		*rxhdr;			/* Header of current rx frame (in hdrbuf) */
183 	uint16		nextlen;		/* Next Read Len from last header */
184 	uint8		rx_seq;			/* Receive sequence number (expected) */
185 	bool		rxskip;			/* Skip receive (awaiting NAK ACK) */
186 
187 	void		*glomd;			/* Packet containing glomming descriptor */
188 	void		*glom;			/* Packet chain for glommed superframe */
189 	uint		glomerr;		/* Glom packet read errors */
190 
191 	uint8		*rxbuf;			/* Buffer for receiving control packets */
192 	uint		rxblen;			/* Allocated length of rxbuf */
193 	uint8		*rxctl;			/* Aligned pointer into rxbuf */
194 	uint8		*databuf;		/* Buffer for receiving big glom packet */
195 	uint8		*dataptr;		/* Aligned pointer into databuf */
196 	uint		rxlen;			/* Length of valid data in buffer */
197 
198 	uint8		sdpcm_ver;		/* Bus protocol reported by dongle */
199 
200 	bool		intr;			/* Use interrupts */
201 	bool		poll;			/* Use polling */
202 	bool		ipend;			/* Device interrupt is pending */
203 	bool		intdis;			/* Interrupts disabled by isr */
204 	uint 		intrcount;		/* Count of device interrupt callbacks */
205 	uint		lastintrs;		/* Count as of last watchdog timer */
206 	uint		spurious;		/* Count of spurious interrupts */
207 	uint		pollrate;		/* Ticks between device polls */
208 	uint		polltick;		/* Tick counter */
209 	uint		pollcnt;		/* Count of active polls */
210 
211 
212 	uint		regfails;		/* Count of R_REG/W_REG failures */
213 
214 	uint		clkstate;		/* State of sd and backplane clock(s) */
215 	bool		activity;		/* Activity flag for clock down */
216 	int32		idletime;		/* Control for activity timeout */
217 	int32		idlecount;		/* Activity timeout counter */
218 	int32		idleclock;		/* How to set bus driver when idle */
219 	int32		sd_divisor;		/* Speed control to bus driver */
220 	int32		sd_mode;		/* Mode control to bus driver */
221 	int32		sd_rxchain;		/* If bcmsdh api accepts PKT chains */
222 	bool		use_rxchain;		/* If dhd should use PKT chains */
223 	bool		sleeping;		/* Is SDIO bus sleeping? */
224 	bool		rxflow_mode;	/* Rx flow control mode */
225 	bool		rxflow;			/* Is rx flow control on */
226 	uint		prev_rxlim_hit;		/* Is prev rx limit exceeded (per dpc schedule) */
227 	bool		alp_only;		/* Don't use HT clock (ALP only) */
228 	/* Field to decide if rx of control frames happen in rxbuf or lb-pool */
229 	bool		usebufpool;
230 
231 #ifdef SDTEST
232 	/* external loopback */
233 	bool		ext_loop;
234 	uint8		loopid;
235 
236 	/* pktgen configuration */
237 	uint		pktgen_freq;		/* Ticks between bursts */
238 	uint		pktgen_count;		/* Packets to send each burst */
239 	uint		pktgen_print;		/* Bursts between count displays */
240 	uint		pktgen_total;		/* Stop after this many */
241 	uint		pktgen_minlen;		/* Minimum packet data len */
242 	uint		pktgen_maxlen;		/* Maximum packet data len */
243 	uint		pktgen_mode;		/* Configured mode: tx, rx, or echo */
244 	uint		pktgen_stop;		/* Number of tx failures causing stop */
245 
246 	/* active pktgen fields */
247 	uint		pktgen_tick;		/* Tick counter for bursts */
248 	uint		pktgen_ptick;		/* Burst counter for printing */
249 	uint		pktgen_sent;		/* Number of test packets generated */
250 	uint		pktgen_rcvd;		/* Number of test packets received */
251 	uint		pktgen_fail;		/* Number of failed send attempts */
252 	uint16		pktgen_len;		/* Length of next packet to send */
253 #endif /* SDTEST */
254 
255 	/* Some additional counters */
256 	uint		tx_sderrs;		/* Count of tx attempts with sd errors */
257 	uint		fcqueued;		/* Tx packets that got queued */
258 	uint		rxrtx;			/* Count of rtx requests (NAK to dongle) */
259 	uint		rx_toolong;		/* Receive frames too long to receive */
260 	uint		rxc_errors;		/* SDIO errors when reading control frames */
261 	uint		rx_hdrfail;		/* SDIO errors on header reads */
262 	uint		rx_badhdr;		/* Bad received headers (roosync?) */
263 	uint		rx_badseq;		/* Mismatched rx sequence number */
264 	uint		fc_rcvd;		/* Number of flow-control events received */
265 	uint		fc_xoff;		/* Number which turned on flow-control */
266 	uint		fc_xon;			/* Number which turned off flow-control */
267 	uint		rxglomfail;		/* Failed deglom attempts */
268 	uint		rxglomframes;		/* Number of glom frames (superframes) */
269 	uint		rxglompkts;		/* Number of packets from glom frames */
270 	uint		f2rxhdrs;		/* Number of header reads */
271 	uint		f2rxdata;		/* Number of frame data reads */
272 	uint		f2txdata;		/* Number of f2 frame writes */
273 	uint		f1regdata;		/* Number of f1 register accesses */
274 
275 	uint8		*ctrl_frame_buf;
276 	uint32		ctrl_frame_len;
277 	bool		ctrl_frame_stat;
278 } dhd_bus_t;
279 
280 /* clkstate */
281 #define CLK_NONE	0
282 #define CLK_SDONLY	1
283 #define CLK_PENDING	2	/* Not used yet */
284 #define CLK_AVAIL	3
285 
286 #define DHD_NOPMU(dhd)	(FALSE)
287 
288 #ifdef DHD_DEBUG
289 static int qcount[NUMPRIO];
290 static int tx_packets[NUMPRIO];
291 #endif /* DHD_DEBUG */
292 
293 /* Deferred transmit */
294 const uint dhd_deferred_tx = 1;
295 
296 #if !defined(CONTINUOUS_WATCHDOG)
297 extern uint dhd_watchdog_ms;
298 extern void dhd_os_wd_timer(void *bus, uint wdtick);
299 #endif /* !defined(CONTINUOUS_WATCHDOG) */
300 
301 /* Tx/Rx bounds */
302 uint dhd_txbound;
303 uint dhd_rxbound;
304 uint dhd_txminmax;
305 
306 /* override the RAM size if possible */
307 #define DONGLE_MIN_MEMSIZE (128 *1024)
308 int dhd_dongle_memsize;
309 
310 static bool dhd_doflow;
311 static bool dhd_alignctl;
312 
313 static bool sd1idle;
314 
315 static bool retrydata;
316 #define RETRYCHAN(chan) (((chan) == SDPCM_EVENT_CHANNEL) || retrydata)
317 
318 static const uint watermark = 8;
319 static const uint firstread = DHD_FIRSTREAD;
320 
321 #define HDATLEN (firstread - (SDPCM_HDRLEN))
322 
323 /* Retry count for register access failures */
324 static const uint retry_limit = 2;
325 
326 /* Force even SD lengths (some host controllers mess up on odd bytes) */
327 static bool forcealign;
328 
329 #define ALIGNMENT  4
330 
331 #if defined(OOB_INTR_ONLY) && defined(HW_OOB)
332 extern void bcmsdh_enable_hw_oob_intr(void *sdh, bool enable);
333 #endif
334 
335 #if defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD)
336 #error OOB_INTR_ONLY is NOT working with SDIO_ISR_THREAD
337 #endif /* defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD) */
338 #define PKTALIGN(osh, p, len, align)					\
339 	do {								\
340 		uint datalign;						\
341 		datalign = (uintptr)PKTDATA((osh), (p));		\
342 		datalign = ROUNDUP(datalign, (align)) - datalign;	\
343 		ASSERT(datalign < (align));				\
344 		ASSERT(PKTLEN((osh), (p)) >= ((len) + datalign));	\
345 		if (datalign)						\
346 			PKTPULL((osh), (p), datalign);			\
347 		PKTSETLEN((osh), (p), (len));				\
348 	} while (0)
349 
350 /* Limit on rounding up frames */
351 static const uint max_roundup = 512;
352 
353 /* Try doing readahead */
354 static bool dhd_readahead;
355 
356 
357 /* To check if there's window offered */
358 #define DATAOK(bus) \
359 	(((uint8)(bus->tx_max - bus->tx_seq) != 0) && \
360 	(((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0))
361 
362 /* Macros to get register read/write status */
363 /* NOTE: these assume a local dhdsdio_bus_t *bus! */
364 #define R_SDREG(regvar, regaddr, retryvar) \
365 do { \
366 	retryvar = 0; \
367 	do { \
368 		regvar = R_REG(bus->dhd->osh, regaddr); \
369 	} while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \
370 	if (retryvar) { \
371 		bus->regfails += (retryvar-1); \
372 		if (retryvar > retry_limit) { \
373 			DHD_ERROR(("%s: FAILED" #regvar "READ, LINE %d\n", \
374 			           __FUNCTION__, __LINE__)); \
375 			regvar = 0; \
376 		} \
377 	} \
378 } while (0)
379 
380 #define W_SDREG(regval, regaddr, retryvar) \
381 do { \
382 	retryvar = 0; \
383 	do { \
384 		W_REG(bus->dhd->osh, regaddr, regval); \
385 	} while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \
386 	if (retryvar) { \
387 		bus->regfails += (retryvar-1); \
388 		if (retryvar > retry_limit) \
389 			DHD_ERROR(("%s: FAILED REGISTER WRITE, LINE %d\n", \
390 			           __FUNCTION__, __LINE__)); \
391 	} \
392 } while (0)
393 
394 
395 #define DHD_BUS			SDIO_BUS
396 
397 #define PKT_AVAILABLE()		(intstatus & I_HMB_FRAME_IND)
398 
399 #define HOSTINTMASK		(I_HMB_SW_MASK | I_CHIPACTIVE)
400 
401 #define GSPI_PR55150_BAILOUT
402 
403 
404 #ifdef SDTEST
405 static void dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq);
406 static void dhdsdio_sdtest_set(dhd_bus_t *bus, bool start);
407 #endif
408 
409 static int dhdsdio_download_state(dhd_bus_t *bus, bool enter);
410 
411 static void dhdsdio_release(dhd_bus_t *bus, osl_t *osh);
412 static void dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh);
413 static void dhdsdio_disconnect(void *ptr);
414 static bool dhdsdio_chipmatch(uint16 chipid);
415 static bool dhdsdio_probe_attach(dhd_bus_t *bus, osl_t *osh, void *sdh,
416                                  void * regsva, uint16  devid);
417 static bool dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh);
418 static bool dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh);
419 static void dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh);
420 
421 static uint process_nvram_vars(char *varbuf, uint len);
422 
423 static void dhd_dongle_setmemsize(struct dhd_bus *bus, int mem_size);
424 static int dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags,
425 	uint8 *buf, uint nbytes,
426 	void *pkt, bcmsdh_cmplt_fn_t complete, void *handle);
427 static int dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags,
428 	uint8 *buf, uint nbytes,
429 	void *pkt, bcmsdh_cmplt_fn_t complete, void *handle);
430 
431 static bool dhdsdio_download_firmware(struct dhd_bus *bus, osl_t *osh, void *sdh);
432 static int _dhdsdio_download_firmware(struct dhd_bus *bus);
433 
434 static int dhdsdio_download_code_file(struct dhd_bus *bus, char *image_path);
435 static int dhdsdio_download_nvram(struct dhd_bus *bus);
436 #ifdef BCMEMBEDIMAGE
437 static int dhdsdio_download_code_array(struct dhd_bus *bus);
438 #endif
439 
440 
441 static void
dhd_dongle_setmemsize(struct dhd_bus * bus,int mem_size)442 dhd_dongle_setmemsize(struct dhd_bus *bus, int mem_size)
443 {
444 	int32 min_size =  DONGLE_MIN_MEMSIZE;
445 	/* Restrict the memsize to user specified limit */
446 	DHD_ERROR(("user: Restrict the dongle ram size to %d, min accepted %d\n",
447 		dhd_dongle_memsize, min_size));
448 	if ((dhd_dongle_memsize > min_size) &&
449 		(dhd_dongle_memsize < (int32)bus->orig_ramsize))
450 		bus->ramsize = dhd_dongle_memsize;
451 }
452 
453 static int
dhdsdio_set_siaddr_window(dhd_bus_t * bus,uint32 address)454 dhdsdio_set_siaddr_window(dhd_bus_t *bus, uint32 address)
455 {
456 	int err = 0;
457 	bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW,
458 	                 (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err);
459 	if (!err)
460 		bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID,
461 		                 (address >> 16) & SBSDIO_SBADDRMID_MASK, &err);
462 	if (!err)
463 		bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH,
464 		                 (address >> 24) & SBSDIO_SBADDRHIGH_MASK, &err);
465 	return err;
466 }
467 
468 
469 /* Turn backplane clock on or off */
470 static int
dhdsdio_htclk(dhd_bus_t * bus,bool on,bool pendok)471 dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok)
472 {
473 	int err;
474 	uint8 clkctl, clkreq, devctl;
475 	bcmsdh_info_t *sdh;
476 
477 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
478 
479 #if defined(OOB_INTR_ONLY)
480 	pendok = FALSE;
481 #endif
482 	clkctl = 0;
483 	sdh = bus->sdh;
484 
485 
486 	if (on) {
487 		/* Request HT Avail */
488 		clkreq = bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ;
489 
490 		if ((bus->sih->chip == BCM4329_CHIP_ID) && (bus->sih->chiprev == 0))
491 			clkreq |= SBSDIO_FORCE_ALP;
492 
493 
494 
495 
496 		bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
497 		if (err) {
498 			DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err));
499 			return BCME_ERROR;
500 		}
501 
502 		if (pendok &&
503 		    ((bus->sih->buscoretype == PCMCIA_CORE_ID) && (bus->sih->buscorerev == 9))) {
504 			uint32 dummy, retries;
505 			R_SDREG(dummy, &bus->regs->clockctlstatus, retries);
506 		}
507 
508 		/* Check current status */
509 		clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
510 		if (err) {
511 			DHD_ERROR(("%s: HT Avail read error: %d\n", __FUNCTION__, err));
512 			return BCME_ERROR;
513 		}
514 
515 		/* Go to pending and await interrupt if appropriate */
516 		if (!SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) {
517 			DHD_INFO(("CLKCTL: set PENDING\n"));
518 			bus->clkstate = CLK_PENDING;
519 
520 			/* Allow only clock-available interrupt */
521 			devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
522 			if (err) {
523 				DHD_ERROR(("%s: Devctl access error setting CA: %d\n",
524 				           __FUNCTION__, err));
525 				return BCME_ERROR;
526 			}
527 
528 			devctl |= SBSDIO_DEVCTL_CA_INT_ONLY;
529 			bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
530 			return BCME_OK;
531 		} else if (bus->clkstate == CLK_PENDING) {
532 			/* Cancel CA-only interrupt filter */
533 			devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
534 			devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
535 			bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
536 		}
537 
538 		/* Otherwise, wait here (polling) for HT Avail */
539 		if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
540 			SPINWAIT_SLEEP(sdioh_spinwait_sleep,
541 				((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
542 			                                    SBSDIO_FUNC1_CHIPCLKCSR, &err)),
543 			          !SBSDIO_CLKAV(clkctl, bus->alp_only)), PMU_MAX_TRANSITION_DLY);
544 		}
545 		if (err) {
546 			DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err));
547 			return BCME_ERROR;
548 		}
549 		if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
550 			DHD_ERROR(("%s: HT Avail timeout (%d): clkctl 0x%02x\n",
551 			           __FUNCTION__, PMU_MAX_TRANSITION_DLY, clkctl));
552 			return BCME_ERROR;
553 		}
554 
555 
556 		/* Mark clock available */
557 		bus->clkstate = CLK_AVAIL;
558 		DHD_INFO(("CLKCTL: turned ON\n"));
559 
560 #if defined(DHD_DEBUG)
561 		if (bus->alp_only == TRUE) {
562 #if !defined(BCMLXSDMMC)
563 			if (!SBSDIO_ALPONLY(clkctl)) {
564 				DHD_ERROR(("%s: HT Clock, when ALP Only\n", __FUNCTION__));
565 			}
566 #endif /* !defined(BCMLXSDMMC) */
567 		} else {
568 			if (SBSDIO_ALPONLY(clkctl)) {
569 				DHD_ERROR(("%s: HT Clock should be on.\n", __FUNCTION__));
570 			}
571 		}
572 #endif /* defined (DHD_DEBUG) */
573 
574 		bus->activity = TRUE;
575 	} else {
576 		clkreq = 0;
577 
578 		if (bus->clkstate == CLK_PENDING) {
579 			/* Cancel CA-only interrupt filter */
580 			devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
581 			devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
582 			bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
583 		}
584 
585 		bus->clkstate = CLK_SDONLY;
586 		bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
587 		DHD_INFO(("CLKCTL: turned OFF\n"));
588 		if (err) {
589 			DHD_ERROR(("%s: Failed access turning clock off: %d\n",
590 			           __FUNCTION__, err));
591 			return BCME_ERROR;
592 		}
593 	}
594 	return BCME_OK;
595 }
596 
597 /* Change idle/active SD state */
598 static int
dhdsdio_sdclk(dhd_bus_t * bus,bool on)599 dhdsdio_sdclk(dhd_bus_t *bus, bool on)
600 {
601 	int err;
602 	int32 iovalue;
603 
604 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
605 
606 	if (on) {
607 		if (bus->idleclock == DHD_IDLE_STOP) {
608 			/* Turn on clock and restore mode */
609 			iovalue = 1;
610 			err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0,
611 			                      &iovalue, sizeof(iovalue), TRUE);
612 			if (err) {
613 				DHD_ERROR(("%s: error enabling sd_clock: %d\n",
614 				           __FUNCTION__, err));
615 				return BCME_ERROR;
616 			}
617 
618 			iovalue = bus->sd_mode;
619 			err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
620 			                      &iovalue, sizeof(iovalue), TRUE);
621 			if (err) {
622 				DHD_ERROR(("%s: error changing sd_mode: %d\n",
623 				           __FUNCTION__, err));
624 				return BCME_ERROR;
625 			}
626 		} else if (bus->idleclock != DHD_IDLE_ACTIVE) {
627 			/* Restore clock speed */
628 			iovalue = bus->sd_divisor;
629 			err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
630 			                      &iovalue, sizeof(iovalue), TRUE);
631 			if (err) {
632 				DHD_ERROR(("%s: error restoring sd_divisor: %d\n",
633 				           __FUNCTION__, err));
634 				return BCME_ERROR;
635 			}
636 		}
637 		bus->clkstate = CLK_SDONLY;
638 	} else {
639 		/* Stop or slow the SD clock itself */
640 		if ((bus->sd_divisor == -1) || (bus->sd_mode == -1)) {
641 			DHD_TRACE(("%s: can't idle clock, divisor %d mode %d\n",
642 			           __FUNCTION__, bus->sd_divisor, bus->sd_mode));
643 			return BCME_ERROR;
644 		}
645 		if (bus->idleclock == DHD_IDLE_STOP) {
646 			if (sd1idle) {
647 				/* Change to SD1 mode and turn off clock */
648 				iovalue = 1;
649 				err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
650 				                      &iovalue, sizeof(iovalue), TRUE);
651 				if (err) {
652 					DHD_ERROR(("%s: error changing sd_clock: %d\n",
653 					           __FUNCTION__, err));
654 					return BCME_ERROR;
655 				}
656 			}
657 
658 			iovalue = 0;
659 			err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0,
660 			                      &iovalue, sizeof(iovalue), TRUE);
661 			if (err) {
662 				DHD_ERROR(("%s: error disabling sd_clock: %d\n",
663 				           __FUNCTION__, err));
664 				return BCME_ERROR;
665 			}
666 		} else if (bus->idleclock != DHD_IDLE_ACTIVE) {
667 			/* Set divisor to idle value */
668 			iovalue = bus->idleclock;
669 			err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
670 			                      &iovalue, sizeof(iovalue), TRUE);
671 			if (err) {
672 				DHD_ERROR(("%s: error changing sd_divisor: %d\n",
673 				           __FUNCTION__, err));
674 				return BCME_ERROR;
675 			}
676 		}
677 		bus->clkstate = CLK_NONE;
678 	}
679 
680 	return BCME_OK;
681 }
682 
683 /* Transition SD and backplane clock readiness */
684 static int
dhdsdio_clkctl(dhd_bus_t * bus,uint target,bool pendok)685 dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok)
686 {
687 #ifdef DHD_DEBUG
688 	uint oldstate = bus->clkstate;
689 #endif /* DHD_DEBUG */
690 
691 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
692 
693 	/* Early exit if we're already there */
694 	if (bus->clkstate == target) {
695 		if (target == CLK_AVAIL) {
696 #if !defined(CONTINUOUS_WATCHDOG)
697 			dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
698 #endif /* !defined(CONTINUOUS_WATCHDOG) */
699 			bus->activity = TRUE;
700 		}
701 		return BCME_OK;
702 	}
703 
704 	switch (target) {
705 	case CLK_AVAIL:
706 		/* Make sure SD clock is available */
707 		if (bus->clkstate == CLK_NONE)
708 			dhdsdio_sdclk(bus, TRUE);
709 		/* Now request HT Avail on the backplane */
710 		dhdsdio_htclk(bus, TRUE, pendok);
711 #if !defined(CONTINUOUS_WATCHDOG)
712 		dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
713 #endif /* !defined(CONTINUOUS_WATCHDOG) */
714 		bus->activity = TRUE;
715 		break;
716 
717 	case CLK_SDONLY:
718 		/* Remove HT request, or bring up SD clock */
719 		if (bus->clkstate == CLK_NONE)
720 			dhdsdio_sdclk(bus, TRUE);
721 		else if (bus->clkstate == CLK_AVAIL)
722 			dhdsdio_htclk(bus, FALSE, FALSE);
723 		else
724 			DHD_ERROR(("dhdsdio_clkctl: request for %d -> %d\n",
725 			           bus->clkstate, target));
726 #if !defined(CONTINUOUS_WATCHDOG)
727 		dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
728 #endif /* !defined(CONTINUOUS_WATCHDOG) */
729 		break;
730 
731 	case CLK_NONE:
732 		/* Make sure to remove HT request */
733 		if (bus->clkstate == CLK_AVAIL)
734 			dhdsdio_htclk(bus, FALSE, FALSE);
735 		/* Now remove the SD clock */
736 		dhdsdio_sdclk(bus, FALSE);
737 #if !defined(CONTINUOUS_WATCHDOG)
738 		dhd_os_wd_timer(bus->dhd, 0);
739 #endif /* !defined(CONTINUOUS_WATCHDOG) */
740 		break;
741 	}
742 #ifdef DHD_DEBUG
743 	DHD_INFO(("dhdsdio_clkctl: %d -> %d\n", oldstate, bus->clkstate));
744 #endif /* DHD_DEBUG */
745 
746 	return BCME_OK;
747 }
748 
749 int
dhdsdio_bussleep(dhd_bus_t * bus,bool sleep)750 dhdsdio_bussleep(dhd_bus_t *bus, bool sleep)
751 {
752 	bcmsdh_info_t *sdh = bus->sdh;
753 	sdpcmd_regs_t *regs = bus->regs;
754 	uint retries = 0;
755 
756 	DHD_INFO(("dhdsdio_bussleep: request %s (currently %s)\n",
757 	          (sleep ? "SLEEP" : "WAKE"),
758 	          (bus->sleeping ? "SLEEP" : "WAKE")));
759 
760 	/* Done if we're already in the requested state */
761 	if (sleep == bus->sleeping)
762 		return BCME_OK;
763 
764 	/* Going to sleep: set the alarm and turn off the lights... */
765 	if (sleep) {
766 		/* Don't sleep if something is pending */
767 		if (bus->dpc_sched || bus->rxskip || pktq_len(&bus->txq))
768 			return BCME_BUSY;
769 
770 
771 		/* Disable SDIO interrupts (no longer interested) */
772 		bcmsdh_intr_disable(bus->sdh);
773 
774 		/* Make sure the controller has the bus up */
775 		dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
776 
777 		/* Tell device to start using OOB wakeup */
778 		W_SDREG(SMB_USE_OOB, &regs->tosbmailbox, retries);
779 		if (retries > retry_limit)
780 			DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
781 
782 		/* Turn off our contribution to the HT clock request */
783 		dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
784 
785 		bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
786 		                 SBSDIO_FORCE_HW_CLKREQ_OFF, NULL);
787 
788 		/* Isolate the bus */
789 		if (bus->sih->chip != BCM4329_CHIP_ID && bus->sih->chip != BCM4319_CHIP_ID) {
790 				bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL,
791 					SBSDIO_DEVCTL_PADS_ISO, NULL);
792 		}
793 
794 		/* Change state */
795 		bus->sleeping = TRUE;
796 
797 	} else {
798 		/* Waking up: bus power up is ok, set local state */
799 
800 		bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
801 		                 0, NULL);
802 
803 		/* Force pad isolation off if possible (in case power never toggled) */
804 		if ((bus->sih->buscoretype == PCMCIA_CORE_ID) && (bus->sih->buscorerev >= 10))
805 			bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, 0, NULL);
806 
807 
808 		/* Make sure the controller has the bus up */
809 		dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
810 
811 		/* Send misc interrupt to indicate OOB not needed */
812 		W_SDREG(0, &regs->tosbmailboxdata, retries);
813 		if (retries <= retry_limit)
814 			W_SDREG(SMB_DEV_INT, &regs->tosbmailbox, retries);
815 
816 		if (retries > retry_limit)
817 			DHD_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n"));
818 
819 		/* Make sure we have SD bus access */
820 		dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
821 
822 		/* Change state */
823 		bus->sleeping = FALSE;
824 
825 		/* Enable interrupts again */
826 		if (bus->intr && (bus->dhd->busstate == DHD_BUS_DATA)) {
827 			bus->intdis = FALSE;
828 			bcmsdh_intr_enable(bus->sdh);
829 		}
830 	}
831 
832 	return BCME_OK;
833 }
834 #if defined(OOB_INTR_ONLY)
835 void
dhd_enable_oob_intr(struct dhd_bus * bus,bool enable)836 dhd_enable_oob_intr(struct dhd_bus *bus, bool enable)
837 {
838 #if defined(HW_OOB)
839 	bcmsdh_enable_hw_oob_intr(bus->sdh, enable);
840 #else
841 	sdpcmd_regs_t *regs = bus->regs;
842 	uint retries = 0;
843 
844 	dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
845 	if (enable == TRUE) {
846 
847 		/* Tell device to start using OOB wakeup */
848 		W_SDREG(SMB_USE_OOB, &regs->tosbmailbox, retries);
849 		if (retries > retry_limit)
850 			DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
851 
852 	} else {
853 		/* Send misc interrupt to indicate OOB not needed */
854 		W_SDREG(0, &regs->tosbmailboxdata, retries);
855 		if (retries <= retry_limit)
856 			W_SDREG(SMB_DEV_INT, &regs->tosbmailbox, retries);
857 	}
858 
859 	/* Turn off our contribution to the HT clock request */
860 	dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
861 #endif /* defined(HW_OOB) */
862 }
863 #endif /* defined(OOB_INTR_ONLY) */
864 
865 #define BUS_WAKE(bus) \
866 	do { \
867 		if ((bus)->sleeping) \
868 			dhdsdio_bussleep((bus), FALSE); \
869 	} while (0);
870 
871 
872 /* Writes a HW/SW header into the packet and sends it. */
873 /* Assumes: (a) header space already there, (b) caller holds lock */
874 static int
dhdsdio_txpkt(dhd_bus_t * bus,void * pkt,uint chan,bool free_pkt)875 dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt)
876 {
877 	int ret;
878 	osl_t *osh;
879 	uint8 *frame;
880 	uint16 len, pad = 0;
881 	uint32 swheader;
882 	uint retries = 0;
883 	bcmsdh_info_t *sdh;
884 	void *new;
885 	int i;
886 
887 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
888 
889 	sdh = bus->sdh;
890 	osh = bus->dhd->osh;
891 
892 	if (bus->dhd->dongle_reset) {
893 		ret = BCME_NOTREADY;
894 		goto done;
895 	}
896 
897 	frame = (uint8*)PKTDATA(osh, pkt);
898 
899 	/* Add alignment padding, allocate new packet if needed */
900 	if ((pad = ((uintptr)frame % DHD_SDALIGN))) {
901 		if (PKTHEADROOM(osh, pkt) < pad) {
902 			DHD_INFO(("%s: insufficient headroom %d for %d pad\n",
903 			          __FUNCTION__, (int)PKTHEADROOM(osh, pkt), pad));
904 			bus->dhd->tx_realloc++;
905 			new = PKTGET(osh, (PKTLEN(osh, pkt) + DHD_SDALIGN), TRUE);
906 			if (!new) {
907 				DHD_ERROR(("%s: couldn't allocate new %d-byte packet\n",
908 				           __FUNCTION__, PKTLEN(osh, pkt) + DHD_SDALIGN));
909 				ret = BCME_NOMEM;
910 				goto done;
911 			}
912 
913 			PKTALIGN(osh, new, PKTLEN(osh, pkt), DHD_SDALIGN);
914 			bcopy(PKTDATA(osh, pkt), PKTDATA(osh, new), PKTLEN(osh, pkt));
915 			if (free_pkt)
916 				PKTFREE(osh, pkt, TRUE);
917 			/* free the pkt if canned one is not used */
918 			free_pkt = TRUE;
919 			pkt = new;
920 			frame = (uint8*)PKTDATA(osh, pkt);
921 			ASSERT(((uintptr)frame % DHD_SDALIGN) == 0);
922 			pad = 0;
923 		} else {
924 			PKTPUSH(osh, pkt, pad);
925 			frame = (uint8*)PKTDATA(osh, pkt);
926 
927 			ASSERT((pad + SDPCM_HDRLEN) <= (int) PKTLEN(osh, pkt));
928 			bzero(frame, pad + SDPCM_HDRLEN);
929 		}
930 	}
931 	ASSERT(pad < DHD_SDALIGN);
932 
933 	/* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
934 	len = (uint16)PKTLEN(osh, pkt);
935 	*(uint16*)frame = htol16(len);
936 	*(((uint16*)frame) + 1) = htol16(~len);
937 
938 	/* Software tag: channel, sequence number, data offset */
939 	swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) | bus->tx_seq |
940 	        (((pad + SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
941 	htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN);
942 	htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
943 	bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
944 
945 #ifdef DHD_DEBUG
946 	tx_packets[PKTPRIO(pkt)]++;
947 	if (DHD_BYTES_ON() &&
948 	    (((DHD_CTL_ON() && (chan == SDPCM_CONTROL_CHANNEL)) ||
949 	      (DHD_DATA_ON() && (chan != SDPCM_CONTROL_CHANNEL))))) {
950 		prhex("Tx Frame", frame, len);
951 	} else if (DHD_HDRS_ON()) {
952 		prhex("TxHdr", frame, MIN(len, 16));
953 	}
954 #endif
955 
956 	/* Raise len to next SDIO block to eliminate tail command */
957 	if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
958 		uint16 pad = bus->blocksize - (len % bus->blocksize);
959 		if ((pad <= bus->roundup) && (pad < bus->blocksize))
960 #ifdef NOTUSED
961 			if (pad <= PKTTAILROOM(osh, pkt))
962 #endif /* NOTUSED */
963 				len += pad;
964 	} else if (len % DHD_SDALIGN) {
965 		len += DHD_SDALIGN - (len % DHD_SDALIGN);
966 	}
967 
968 	/* Some controllers have trouble with odd bytes -- round to even */
969 	if (forcealign && (len & (ALIGNMENT - 1))) {
970 #ifdef NOTUSED
971 		if (PKTTAILROOM(osh, pkt))
972 #endif
973 			len = ROUNDUP(len, ALIGNMENT);
974 #ifdef NOTUSED
975 		else
976 			DHD_ERROR(("%s: sending unrounded %d-byte packet\n", __FUNCTION__, len));
977 #endif
978 	}
979 
980 	do {
981 		ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
982 		                      frame, len, pkt, NULL, NULL);
983 		bus->f2txdata++;
984 		ASSERT(ret != BCME_PENDING);
985 
986 		if (ret < 0) {
987 			/* On failure, abort the command and terminate the frame */
988 			DHD_INFO(("%s: sdio error %d, abort command and terminate frame.\n",
989 			          __FUNCTION__, ret));
990 			bus->tx_sderrs++;
991 
992 			bcmsdh_abort(sdh, SDIO_FUNC_2);
993 			bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
994 			                 SFC_WF_TERM, NULL);
995 			bus->f1regdata++;
996 
997 			for (i = 0; i < 3; i++) {
998 				uint8 hi, lo;
999 				hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
1000 				                     SBSDIO_FUNC1_WFRAMEBCHI, NULL);
1001 				lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
1002 				                     SBSDIO_FUNC1_WFRAMEBCLO, NULL);
1003 				bus->f1regdata += 2;
1004 				if ((hi == 0) && (lo == 0))
1005 					break;
1006 			}
1007 
1008 		}
1009 	} while ((ret < 0) && retrydata && retries++ < TXRETRIES);
1010 
1011 done:
1012 	/* restore pkt buffer pointer before calling tx complete routine */
1013 	PKTPULL(osh, pkt, SDPCM_HDRLEN + pad);
1014 	dhd_os_sdunlock(bus->dhd);
1015 	dhd_txcomplete(bus->dhd, pkt, ret != 0);
1016 	dhd_os_sdlock(bus->dhd);
1017 
1018 	if (free_pkt)
1019 		PKTFREE(osh, pkt, TRUE);
1020 
1021 	return ret;
1022 }
1023 
1024 int
dhd_bus_txdata(struct dhd_bus * bus,void * pkt)1025 dhd_bus_txdata(struct dhd_bus *bus, void *pkt)
1026 {
1027 	int ret = BCME_ERROR;
1028 	osl_t *osh;
1029 	uint datalen, prec;
1030 
1031 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1032 
1033 	osh = bus->dhd->osh;
1034 	datalen = PKTLEN(osh, pkt);
1035 
1036 #ifdef SDTEST
1037 	/* Push the test header if doing loopback */
1038 	if (bus->ext_loop) {
1039 		uint8* data;
1040 		PKTPUSH(osh, pkt, SDPCM_TEST_HDRLEN);
1041 		data = PKTDATA(osh, pkt);
1042 		*data++ = SDPCM_TEST_ECHOREQ;
1043 		*data++ = (uint8)bus->loopid++;
1044 		*data++ = (datalen >> 0);
1045 		*data++ = (datalen >> 8);
1046 		datalen += SDPCM_TEST_HDRLEN;
1047 	}
1048 #endif /* SDTEST */
1049 
1050 	/* Add space for the header */
1051 	PKTPUSH(osh, pkt, SDPCM_HDRLEN);
1052 	ASSERT(ISALIGNED((uintptr)PKTDATA(osh, pkt), 2));
1053 
1054 	prec = PRIO2PREC((PKTPRIO(pkt) & PRIOMASK));
1055 
1056 
1057 	/* Check for existing queue, current flow-control, pending event, or pending clock */
1058 	if (dhd_deferred_tx || bus->fcstate || pktq_len(&bus->txq) || bus->dpc_sched ||
1059 	    (!DATAOK(bus)) || (bus->flowcontrol & NBITVAL(prec)) ||
1060 	    (bus->clkstate == CLK_PENDING)) {
1061 		bus->fcqueued++;
1062 
1063 		/* Priority based enq */
1064 		dhd_os_sdlock_txq(bus->dhd);
1065 		if (dhd_prec_enq(bus->dhd, &bus->txq, pkt, prec) == FALSE) {
1066 			PKTPULL(osh, pkt, SDPCM_HDRLEN);
1067 			dhd_txcomplete(bus->dhd, pkt, FALSE);
1068 			PKTFREE(osh, pkt, TRUE);
1069 			ret = BCME_NORESOURCE;
1070 		}
1071 		else
1072 			ret = BCME_OK;
1073 		dhd_os_sdunlock_txq(bus->dhd);
1074 
1075 		if ((pktq_len(&bus->txq) >= FCHI) && dhd_doflow)
1076 			dhd_txflowcontrol(bus->dhd, 0, ON);
1077 
1078 #ifdef DHD_DEBUG
1079 		if (pktq_plen(&bus->txq, prec) > qcount[prec])
1080 			qcount[prec] = pktq_plen(&bus->txq, prec);
1081 #endif
1082 		/* Schedule DPC if needed to send queued packet(s) */
1083 		if (dhd_deferred_tx && !bus->dpc_sched) {
1084 			bus->dpc_sched = TRUE;
1085 			dhd_sched_dpc(bus->dhd);
1086 		}
1087 	} else {
1088 		/* Lock: we're about to use shared data/code (and SDIO) */
1089 		dhd_os_sdlock(bus->dhd);
1090 
1091 		/* Otherwise, send it now */
1092 		BUS_WAKE(bus);
1093 		dhdsdio_clkctl(bus, CLK_AVAIL, TRUE);
1094 
1095 #ifndef SDTEST
1096 		ret = dhdsdio_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, TRUE);
1097 #else
1098 		ret = dhdsdio_txpkt(bus, pkt,
1099 		        (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL), TRUE);
1100 #endif
1101 		if (ret)
1102 			bus->dhd->tx_errors++;
1103 		else
1104 			bus->dhd->dstats.tx_bytes += datalen;
1105 
1106 		if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
1107 			bus->activity = FALSE;
1108 			dhdsdio_clkctl(bus, CLK_NONE, TRUE);
1109 		}
1110 
1111 		dhd_os_sdunlock(bus->dhd);
1112 	}
1113 
1114 
1115 	return ret;
1116 }
1117 
1118 static uint
dhdsdio_sendfromq(dhd_bus_t * bus,uint maxframes)1119 dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes)
1120 {
1121 	void *pkt;
1122 	uint32 intstatus = 0;
1123 	uint retries = 0;
1124 	int ret = 0, prec_out;
1125 	uint cnt = 0;
1126 	uint datalen;
1127 	uint8 tx_prec_map;
1128 
1129 	dhd_pub_t *dhd = bus->dhd;
1130 	sdpcmd_regs_t *regs = bus->regs;
1131 
1132 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1133 
1134 	tx_prec_map = ~bus->flowcontrol;
1135 
1136 	/* Send frames until the limit or some other event */
1137 	for (cnt = 0; (cnt < maxframes) && DATAOK(bus); cnt++) {
1138 		dhd_os_sdlock_txq(bus->dhd);
1139 		if ((pkt = pktq_mdeq(&bus->txq, tx_prec_map, &prec_out)) == NULL) {
1140 			dhd_os_sdunlock_txq(bus->dhd);
1141 			break;
1142 		}
1143 		dhd_os_sdunlock_txq(bus->dhd);
1144 		datalen = PKTLEN(bus->dhd->osh, pkt) - SDPCM_HDRLEN;
1145 
1146 #ifndef SDTEST
1147 		ret = dhdsdio_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, TRUE);
1148 #else
1149 		ret = dhdsdio_txpkt(bus, pkt,
1150 		        (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL), TRUE);
1151 #endif
1152 		if (ret)
1153 			bus->dhd->tx_errors++;
1154 		else
1155 			bus->dhd->dstats.tx_bytes += datalen;
1156 
1157 		/* In poll mode, need to check for other events */
1158 		if (!bus->intr && cnt)
1159 		{
1160 			/* Check device status, signal pending interrupt */
1161 			R_SDREG(intstatus, &regs->intstatus, retries);
1162 			bus->f2txdata++;
1163 			if (bcmsdh_regfail(bus->sdh))
1164 				break;
1165 			if (intstatus & bus->hostintmask)
1166 				bus->ipend = TRUE;
1167 		}
1168 	}
1169 
1170 	/* Deflow-control stack if needed */
1171 	if (dhd_doflow && dhd->up && (dhd->busstate == DHD_BUS_DATA) &&
1172 	    dhd->txoff && (pktq_len(&bus->txq) < FCLOW))
1173 		dhd_txflowcontrol(dhd, 0, OFF);
1174 
1175 	return cnt;
1176 }
1177 
1178 int
dhd_bus_txctl(struct dhd_bus * bus,uchar * msg,uint msglen)1179 dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen)
1180 {
1181 	uint8 *frame;
1182 	uint16 len;
1183 	uint32 swheader;
1184 	uint retries = 0;
1185 	bcmsdh_info_t *sdh = bus->sdh;
1186 	uint8 doff = 0;
1187 	int ret = -1;
1188 	int i;
1189 
1190 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1191 
1192 	if (bus->dhd->dongle_reset)
1193 		return -EIO;
1194 
1195 	/* Back the pointer to make a room for bus header */
1196 	frame = msg - SDPCM_HDRLEN;
1197 	len = (msglen += SDPCM_HDRLEN);
1198 
1199 	/* Add alignment padding (optional for ctl frames) */
1200 	if (dhd_alignctl) {
1201 		if ((doff = ((uintptr)frame % DHD_SDALIGN))) {
1202 			frame -= doff;
1203 			len += doff;
1204 			msglen += doff;
1205 			bzero(frame, doff + SDPCM_HDRLEN);
1206 		}
1207 		ASSERT(doff < DHD_SDALIGN);
1208 	}
1209 	doff += SDPCM_HDRLEN;
1210 
1211 	/* Round send length to next SDIO block */
1212 	if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
1213 		uint16 pad = bus->blocksize - (len % bus->blocksize);
1214 		if ((pad <= bus->roundup) && (pad < bus->blocksize))
1215 			len += pad;
1216 	} else if (len % DHD_SDALIGN) {
1217 		len += DHD_SDALIGN - (len % DHD_SDALIGN);
1218 	}
1219 
1220 	/* Satisfy length-alignment requirements */
1221 	if (forcealign && (len & (ALIGNMENT - 1)))
1222 		len = ROUNDUP(len, ALIGNMENT);
1223 
1224 	ASSERT(ISALIGNED((uintptr)frame, 2));
1225 
1226 
1227 	/* Need to lock here to protect txseq and SDIO tx calls */
1228 	dhd_os_sdlock(bus->dhd);
1229 
1230 	BUS_WAKE(bus);
1231 
1232 	/* Make sure backplane clock is on */
1233 	dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
1234 
1235 	/* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
1236 	*(uint16*)frame = htol16((uint16)msglen);
1237 	*(((uint16*)frame) + 1) = htol16(~msglen);
1238 
1239 	/* Software tag: channel, sequence number, data offset */
1240 	swheader = ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK)
1241 	        | bus->tx_seq | ((doff << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
1242 	htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN);
1243 	htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
1244 
1245 	if (!DATAOK(bus)) {
1246 		bus->ctrl_frame_stat = TRUE;
1247 		/* Send from dpc */
1248 		bus->ctrl_frame_buf = frame;
1249 		bus->ctrl_frame_len = len;
1250 
1251 		dhd_wait_for_event(bus->dhd, &bus->ctrl_frame_stat);
1252 
1253 		if (bus->ctrl_frame_stat == FALSE)
1254 			ret = 0;
1255 		else
1256 			ret = -1;
1257 	}
1258 
1259 	if (ret == -1) {
1260 		bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
1261 
1262 #ifdef DHD_DEBUG
1263 		if (DHD_BYTES_ON() && DHD_CTL_ON()) {
1264 			prhex("Tx Frame", frame, len);
1265 		} else if (DHD_HDRS_ON()) {
1266 			prhex("TxHdr", frame, MIN(len, 16));
1267 		}
1268 #endif
1269 
1270 		do {
1271 			ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
1272 			                          frame, len, NULL, NULL, NULL);
1273 			ASSERT(ret != BCME_PENDING);
1274 
1275 			if (ret < 0) {
1276 				/* On failure, abort the command and terminate the frame */
1277 				DHD_INFO(("%s: sdio error %d, abort command and terminate frame.\n",
1278 				          __FUNCTION__, ret));
1279 				bus->tx_sderrs++;
1280 
1281 				bcmsdh_abort(sdh, SDIO_FUNC_2);
1282 
1283 				bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
1284 				                 SFC_WF_TERM, NULL);
1285 				bus->f1regdata++;
1286 
1287 				for (i = 0; i < 3; i++) {
1288 					uint8 hi, lo;
1289 					hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
1290 					                     SBSDIO_FUNC1_WFRAMEBCHI, NULL);
1291 					lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
1292 					                     SBSDIO_FUNC1_WFRAMEBCLO, NULL);
1293 					bus->f1regdata += 2;
1294 					if ((hi == 0) && (lo == 0))
1295 						break;
1296 				}
1297 
1298 			}
1299 		} while ((ret < 0) && retries++ < TXRETRIES);
1300 	}
1301 
1302 	if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
1303 		bus->activity = FALSE;
1304 		dhdsdio_clkctl(bus, CLK_NONE, TRUE);
1305 	}
1306 
1307 	dhd_os_sdunlock(bus->dhd);
1308 
1309 	if (ret)
1310 		bus->dhd->tx_ctlerrs++;
1311 	else
1312 		bus->dhd->tx_ctlpkts++;
1313 
1314 	return ret ? -EIO : 0;
1315 }
1316 
1317 int
dhd_bus_rxctl(struct dhd_bus * bus,uchar * msg,uint msglen)1318 dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen)
1319 {
1320 	int timeleft;
1321 	uint rxlen = 0;
1322 	bool pending;
1323 
1324 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1325 
1326 	if (bus->dhd->dongle_reset)
1327 		return -EIO;
1328 
1329 	/* Wait until control frame is available */
1330 	timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->rxlen, &pending);
1331 
1332 	dhd_os_sdlock(bus->dhd);
1333 	rxlen = bus->rxlen;
1334 	bcopy(bus->rxctl, msg, MIN(msglen, rxlen));
1335 	bus->rxlen = 0;
1336 	dhd_os_sdunlock(bus->dhd);
1337 
1338 	if (rxlen) {
1339 		DHD_CTL(("%s: resumed on rxctl frame, got %d expected %d\n",
1340 		         __FUNCTION__, rxlen, msglen));
1341 	} else if (timeleft == 0) {
1342 		DHD_ERROR(("%s: resumed on timeout\n", __FUNCTION__));
1343 	} else if (pending == TRUE) {
1344 		DHD_CTL(("%s: cancelled\n", __FUNCTION__));
1345 		return -ERESTARTSYS;
1346 	} else {
1347 		DHD_CTL(("%s: resumed for unknown reason?\n", __FUNCTION__));
1348 	}
1349 
1350 	if (rxlen)
1351 		bus->dhd->rx_ctlpkts++;
1352 	else
1353 		bus->dhd->rx_ctlerrs++;
1354 
1355 	return rxlen ? (int)rxlen : -ETIMEDOUT;
1356 }
1357 
1358 /* IOVar table */
1359 enum {
1360 	IOV_INTR = 1,
1361 	IOV_POLLRATE,
1362 	IOV_SDREG,
1363 	IOV_SBREG,
1364 	IOV_SDCIS,
1365 	IOV_MEMBYTES,
1366 	IOV_MEMSIZE,
1367 	IOV_DOWNLOAD,
1368 	IOV_FORCEEVEN,
1369 	IOV_SDIOD_DRIVE,
1370 	IOV_READAHEAD,
1371 	IOV_SDRXCHAIN,
1372 	IOV_ALIGNCTL,
1373 	IOV_SDALIGN,
1374 	IOV_DEVRESET,
1375 	IOV_CPU,
1376 #ifdef SDTEST
1377 	IOV_PKTGEN,
1378 	IOV_EXTLOOP,
1379 #endif /* SDTEST */
1380 	IOV_SPROM,
1381 	IOV_TXBOUND,
1382 	IOV_RXBOUND,
1383 	IOV_TXMINMAX,
1384 	IOV_IDLETIME,
1385 	IOV_IDLECLOCK,
1386 	IOV_SD1IDLE,
1387 	IOV_SLEEP,
1388 	IOV_VARS
1389 };
1390 
1391 const bcm_iovar_t dhdsdio_iovars[] = {
1392 	{"intr",	IOV_INTR,	0,	IOVT_BOOL,	0 },
1393 	{"sleep",	IOV_SLEEP,	0,	IOVT_BOOL,	0 },
1394 	{"pollrate",	IOV_POLLRATE,	0,	IOVT_UINT32,	0 },
1395 	{"idletime",	IOV_IDLETIME,	0,	IOVT_INT32,	0 },
1396 	{"idleclock",	IOV_IDLECLOCK,	0,	IOVT_INT32,	0 },
1397 	{"sd1idle",	IOV_SD1IDLE,	0,	IOVT_BOOL,	0 },
1398 	{"membytes",	IOV_MEMBYTES,	0,	IOVT_BUFFER,	2 * sizeof(int) },
1399 	{"memsize",	IOV_MEMSIZE,	0,	IOVT_UINT32,	0 },
1400 	{"download",	IOV_DOWNLOAD,	0,	IOVT_BOOL,	0 },
1401 	{"vars",	IOV_VARS,	0,	IOVT_BUFFER,	0 },
1402 	{"sdiod_drive",	IOV_SDIOD_DRIVE, 0,	IOVT_UINT32,	0 },
1403 	{"readahead",	IOV_READAHEAD,	0,	IOVT_BOOL,	0 },
1404 	{"sdrxchain",	IOV_SDRXCHAIN,	0,	IOVT_BOOL,	0 },
1405 	{"alignctl",	IOV_ALIGNCTL,	0,	IOVT_BOOL,	0 },
1406 	{"sdalign",	IOV_SDALIGN,	0,	IOVT_BOOL,	0 },
1407 	{"devreset",	IOV_DEVRESET,	0,	IOVT_BOOL,	0 },
1408 #ifdef DHD_DEBUG
1409 	{"sdreg",	IOV_SDREG,	0,	IOVT_BUFFER,	sizeof(sdreg_t) },
1410 	{"sbreg",	IOV_SBREG,	0,	IOVT_BUFFER,	sizeof(sdreg_t) },
1411 	{"sd_cis",	IOV_SDCIS,	0,	IOVT_BUFFER,	DHD_IOCTL_MAXLEN },
1412 	{"forcealign",	IOV_FORCEEVEN,	0,	IOVT_BOOL,	0 },
1413 	{"txbound",	IOV_TXBOUND,	0,	IOVT_UINT32,	0 },
1414 	{"rxbound",	IOV_RXBOUND,	0,	IOVT_UINT32,	0 },
1415 	{"txminmax", IOV_TXMINMAX,	0,	IOVT_UINT32,	0 },
1416 	{"cpu",		IOV_CPU,	0,	IOVT_BOOL,	0 },
1417 #endif /* DHD_DEBUG */
1418 #ifdef SDTEST
1419 	{"extloop",	IOV_EXTLOOP,	0,	IOVT_BOOL,	0 },
1420 	{"pktgen",	IOV_PKTGEN,	0,	IOVT_BUFFER,	sizeof(dhd_pktgen_t) },
1421 #endif /* SDTEST */
1422 
1423 	{NULL, 0, 0, 0, 0 }
1424 };
1425 
1426 static void
dhd_dump_pct(struct bcmstrbuf * strbuf,char * desc,uint num,uint div)1427 dhd_dump_pct(struct bcmstrbuf *strbuf, char *desc, uint num, uint div)
1428 {
1429 	uint q1, q2;
1430 
1431 	if (!div) {
1432 		bcm_bprintf(strbuf, "%s N/A", desc);
1433 	} else {
1434 		q1 = num / div;
1435 		q2 = (100 * (num - (q1 * div))) / div;
1436 		bcm_bprintf(strbuf, "%s %d.%02d", desc, q1, q2);
1437 	}
1438 }
1439 
1440 void
dhd_bus_dump(dhd_pub_t * dhdp,struct bcmstrbuf * strbuf)1441 dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf)
1442 {
1443 	dhd_bus_t *bus = dhdp->bus;
1444 
1445 	bcm_bprintf(strbuf, "Bus SDIO structure:\n");
1446 	bcm_bprintf(strbuf, "hostintmask 0x%08x intstatus 0x%08x sdpcm_ver %d\n",
1447 	            bus->hostintmask, bus->intstatus, bus->sdpcm_ver);
1448 	bcm_bprintf(strbuf, "fcstate %d qlen %d tx_seq %d, max %d, rxskip %d rxlen %d rx_seq %d\n",
1449 	            bus->fcstate, pktq_len(&bus->txq), bus->tx_seq, bus->tx_max, bus->rxskip,
1450 	            bus->rxlen, bus->rx_seq);
1451 	bcm_bprintf(strbuf, "intr %d intrcount %d lastintrs %d spurious %d\n",
1452 	            bus->intr, bus->intrcount, bus->lastintrs, bus->spurious);
1453 	bcm_bprintf(strbuf, "pollrate %d pollcnt %d regfails %d\n",
1454 	            bus->pollrate, bus->pollcnt, bus->regfails);
1455 
1456 	bcm_bprintf(strbuf, "\nAdditional counters:\n");
1457 	bcm_bprintf(strbuf, "tx_sderrs %d fcqueued %d rxrtx %d rx_toolong %d rxc_errors %d\n",
1458 	            bus->tx_sderrs, bus->fcqueued, bus->rxrtx, bus->rx_toolong,
1459 	            bus->rxc_errors);
1460 	bcm_bprintf(strbuf, "rx_hdrfail %d badhdr %d badseq %d\n",
1461 	            bus->rx_hdrfail, bus->rx_badhdr, bus->rx_badseq);
1462 	bcm_bprintf(strbuf, "fc_rcvd %d, fc_xoff %d, fc_xon %d\n",
1463 	            bus->fc_rcvd, bus->fc_xoff, bus->fc_xon);
1464 	bcm_bprintf(strbuf, "rxglomfail %d, rxglomframes %d, rxglompkts %d\n",
1465 	            bus->rxglomfail, bus->rxglomframes, bus->rxglompkts);
1466 	bcm_bprintf(strbuf, "f2rx (hdrs/data) %d (%d/%d), f2tx %d f1regs %d\n",
1467 	            (bus->f2rxhdrs + bus->f2rxdata), bus->f2rxhdrs, bus->f2rxdata,
1468 	            bus->f2txdata, bus->f1regdata);
1469 	{
1470 		dhd_dump_pct(strbuf, "\nRx: pkts/f2rd", bus->dhd->rx_packets,
1471 		             (bus->f2rxhdrs + bus->f2rxdata));
1472 		dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->rx_packets, bus->f1regdata);
1473 		dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->rx_packets,
1474 		             (bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata));
1475 		dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->rx_packets, bus->intrcount);
1476 		bcm_bprintf(strbuf, "\n");
1477 
1478 		dhd_dump_pct(strbuf, "Rx: glom pct", (100 * bus->rxglompkts),
1479 		             bus->dhd->rx_packets);
1480 		dhd_dump_pct(strbuf, ", pkts/glom", bus->rxglompkts, bus->rxglomframes);
1481 		bcm_bprintf(strbuf, "\n");
1482 
1483 		dhd_dump_pct(strbuf, "Tx: pkts/f2wr", bus->dhd->tx_packets, bus->f2txdata);
1484 		dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->tx_packets, bus->f1regdata);
1485 		dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->tx_packets,
1486 		             (bus->f2txdata + bus->f1regdata));
1487 		dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->tx_packets, bus->intrcount);
1488 		bcm_bprintf(strbuf, "\n");
1489 
1490 		dhd_dump_pct(strbuf, "Total: pkts/f2rw",
1491 		             (bus->dhd->tx_packets + bus->dhd->rx_packets),
1492 		             (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata));
1493 		dhd_dump_pct(strbuf, ", pkts/f1sd",
1494 		             (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->f1regdata);
1495 		dhd_dump_pct(strbuf, ", pkts/sd",
1496 		             (bus->dhd->tx_packets + bus->dhd->rx_packets),
1497 		             (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata));
1498 		dhd_dump_pct(strbuf, ", pkts/int",
1499 		             (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->intrcount);
1500 		bcm_bprintf(strbuf, "\n\n");
1501 	}
1502 
1503 #ifdef SDTEST
1504 	if (bus->pktgen_count) {
1505 		bcm_bprintf(strbuf, "pktgen config and count:\n");
1506 		bcm_bprintf(strbuf, "freq %d count %d print %d total %d min %d len %d\n",
1507 		            bus->pktgen_freq, bus->pktgen_count, bus->pktgen_print,
1508 		            bus->pktgen_total, bus->pktgen_minlen, bus->pktgen_maxlen);
1509 		bcm_bprintf(strbuf, "send attempts %d rcvd %d fail %d\n",
1510 		            bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail);
1511 	}
1512 #endif /* SDTEST */
1513 #ifdef DHD_DEBUG
1514 	bcm_bprintf(strbuf, "dpc_sched %d host interrupt%spending\n",
1515 	            bus->dpc_sched, (bcmsdh_intr_pending(bus->sdh) ? " " : " not "));
1516 	bcm_bprintf(strbuf, "blocksize %d roundup %d\n", bus->blocksize, bus->roundup);
1517 #endif /* DHD_DEBUG */
1518 	bcm_bprintf(strbuf, "clkstate %d activity %d idletime %d idlecount %d sleeping %d\n",
1519 	            bus->clkstate, bus->activity, bus->idletime, bus->idlecount, bus->sleeping);
1520 }
1521 
1522 void
dhd_bus_clearcounts(dhd_pub_t * dhdp)1523 dhd_bus_clearcounts(dhd_pub_t *dhdp)
1524 {
1525 	dhd_bus_t *bus = (dhd_bus_t *)dhdp->bus;
1526 
1527 	bus->intrcount = bus->lastintrs = bus->spurious = bus->regfails = 0;
1528 	bus->rxrtx = bus->rx_toolong = bus->rxc_errors = 0;
1529 	bus->rx_hdrfail = bus->rx_badhdr = bus->rx_badseq = 0;
1530 	bus->tx_sderrs = bus->fc_rcvd = bus->fc_xoff = bus->fc_xon = 0;
1531 	bus->rxglomfail = bus->rxglomframes = bus->rxglompkts = 0;
1532 	bus->f2rxhdrs = bus->f2rxdata = bus->f2txdata = bus->f1regdata = 0;
1533 }
1534 
1535 #ifdef SDTEST
1536 static int
dhdsdio_pktgen_get(dhd_bus_t * bus,uint8 * arg)1537 dhdsdio_pktgen_get(dhd_bus_t *bus, uint8 *arg)
1538 {
1539 	dhd_pktgen_t pktgen;
1540 
1541 	pktgen.version = DHD_PKTGEN_VERSION;
1542 	pktgen.freq = bus->pktgen_freq;
1543 	pktgen.count = bus->pktgen_count;
1544 	pktgen.print = bus->pktgen_print;
1545 	pktgen.total = bus->pktgen_total;
1546 	pktgen.minlen = bus->pktgen_minlen;
1547 	pktgen.maxlen = bus->pktgen_maxlen;
1548 	pktgen.numsent = bus->pktgen_sent;
1549 	pktgen.numrcvd = bus->pktgen_rcvd;
1550 	pktgen.numfail = bus->pktgen_fail;
1551 	pktgen.mode = bus->pktgen_mode;
1552 	pktgen.stop = bus->pktgen_stop;
1553 
1554 	bcopy(&pktgen, arg, sizeof(pktgen));
1555 
1556 	return 0;
1557 }
1558 
1559 static int
dhdsdio_pktgen_set(dhd_bus_t * bus,uint8 * arg)1560 dhdsdio_pktgen_set(dhd_bus_t *bus, uint8 *arg)
1561 {
1562 	dhd_pktgen_t pktgen;
1563 	uint oldcnt, oldmode;
1564 
1565 	bcopy(arg, &pktgen, sizeof(pktgen));
1566 	if (pktgen.version != DHD_PKTGEN_VERSION)
1567 		return BCME_BADARG;
1568 
1569 	oldcnt = bus->pktgen_count;
1570 	oldmode = bus->pktgen_mode;
1571 
1572 	bus->pktgen_freq = pktgen.freq;
1573 	bus->pktgen_count = pktgen.count;
1574 	bus->pktgen_print = pktgen.print;
1575 	bus->pktgen_total = pktgen.total;
1576 	bus->pktgen_minlen = pktgen.minlen;
1577 	bus->pktgen_maxlen = pktgen.maxlen;
1578 	bus->pktgen_mode = pktgen.mode;
1579 	bus->pktgen_stop = pktgen.stop;
1580 
1581 	bus->pktgen_tick = bus->pktgen_ptick = 0;
1582 	bus->pktgen_len = MAX(bus->pktgen_len, bus->pktgen_minlen);
1583 	bus->pktgen_len = MIN(bus->pktgen_len, bus->pktgen_maxlen);
1584 
1585 	/* Clear counts for a new pktgen (mode change, or was stopped) */
1586 	if (bus->pktgen_count && (!oldcnt || oldmode != bus->pktgen_mode))
1587 		bus->pktgen_sent = bus->pktgen_rcvd = bus->pktgen_fail = 0;
1588 
1589 	return 0;
1590 }
1591 #endif /* SDTEST */
1592 
1593 static int
dhdsdio_membytes(dhd_bus_t * bus,bool write,uint32 address,uint8 * data,uint size)1594 dhdsdio_membytes(dhd_bus_t *bus, bool write, uint32 address, uint8 *data, uint size)
1595 {
1596 	int bcmerror = 0;
1597 	uint32 sdaddr;
1598 	uint dsize;
1599 
1600 	if (size % 4) {
1601 		size += 3;
1602 		size &= 0xFFFFFFFC;
1603 	}
1604 
1605 	/* Determine initial transfer parameters */
1606 	sdaddr = address & SBSDIO_SB_OFT_ADDR_MASK;
1607 	if ((sdaddr + size) & SBSDIO_SBWINDOW_MASK)
1608 		dsize = (SBSDIO_SB_OFT_ADDR_LIMIT - sdaddr);
1609 	else
1610 		dsize = size;
1611 
1612 	/* Set the backplane window to include the start address */
1613 	if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) {
1614 		DHD_ERROR(("%s: window change failed\n", __FUNCTION__));
1615 		goto xfer_done;
1616 	}
1617 
1618 	/* Do the transfer(s) */
1619 	while (size) {
1620 		DHD_INFO(("%s: %s %d bytes at offset 0x%08x in window 0x%08x\n",
1621 		          __FUNCTION__, (write ? "write" : "read"), dsize, sdaddr,
1622 		          (address & SBSDIO_SBWINDOW_MASK)));
1623 		if ((bcmerror = bcmsdh_rwdata(bus->sdh, write, sdaddr, data, dsize))) {
1624 			DHD_ERROR(("%s: membytes transfer failed\n", __FUNCTION__));
1625 			break;
1626 		}
1627 
1628 		/* Adjust for next transfer (if any) */
1629 		if ((size -= dsize)) {
1630 			data += dsize;
1631 			address += dsize;
1632 			if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) {
1633 				DHD_ERROR(("%s: window change failed\n", __FUNCTION__));
1634 				break;
1635 			}
1636 			sdaddr = 0;
1637 			dsize = MIN(SBSDIO_SB_OFT_ADDR_LIMIT, size);
1638 		}
1639 	}
1640 
1641 xfer_done:
1642 	/* Return the window to backplane enumeration space for core access */
1643 	if (dhdsdio_set_siaddr_window(bus, bcmsdh_cur_sbwad(bus->sdh))) {
1644 		DHD_ERROR(("%s: FAILED to set window back to 0x%x\n", __FUNCTION__,
1645 			bcmsdh_cur_sbwad(bus->sdh)));
1646 	}
1647 
1648 	return bcmerror;
1649 }
1650 
1651 
1652 int
dhdsdio_downloadvars(dhd_bus_t * bus,void * arg,int len)1653 dhdsdio_downloadvars(dhd_bus_t *bus, void *arg, int len)
1654 {
1655 	int bcmerror = BCME_OK;
1656 
1657 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1658 
1659 	/* Basic sanity checks */
1660 	if (bus->dhd->up) {
1661 		bcmerror = BCME_NOTDOWN;
1662 		goto err;
1663 	}
1664 	if (!len) {
1665 		bcmerror = BCME_BUFTOOSHORT;
1666 		goto err;
1667 	}
1668 
1669 	/* Free the old ones and replace with passed variables */
1670 	if (bus->vars)
1671 		MFREE(bus->dhd->osh, bus->vars, bus->varsz);
1672 
1673 	bus->vars = MALLOC(bus->dhd->osh, len);
1674 	bus->varsz = bus->vars ? len : 0;
1675 	if (bus->vars == NULL) {
1676 		bcmerror = BCME_NOMEM;
1677 		goto err;
1678 	}
1679 
1680 	/* Copy the passed variables, which should include the terminating double-null */
1681 	bcopy(arg, bus->vars, bus->varsz);
1682 err:
1683 	return bcmerror;
1684 }
1685 
1686 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)1687 dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const char *name,
1688                 void *params, int plen, void *arg, int len, int val_size)
1689 {
1690 	int bcmerror = 0;
1691 	int32 int_val = 0;
1692 	bool bool_val = 0;
1693 
1694 	DHD_TRACE(("%s: Enter, action %d name %s params %p plen %d arg %p len %d val_size %d\n",
1695 	           __FUNCTION__, actionid, name, params, plen, arg, len, val_size));
1696 
1697 	if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0)
1698 		goto exit;
1699 
1700 	if (plen >= (int)sizeof(int_val))
1701 		bcopy(params, &int_val, sizeof(int_val));
1702 
1703 	bool_val = (int_val != 0) ? TRUE : FALSE;
1704 
1705 
1706 	/* Some ioctls use the bus */
1707 	dhd_os_sdlock(bus->dhd);
1708 
1709 	/* Check if dongle is in reset. If so, only allow DEVRESET iovars */
1710 	if (bus->dhd->dongle_reset && !(actionid == IOV_SVAL(IOV_DEVRESET) ||
1711 	                                actionid == IOV_GVAL(IOV_DEVRESET))) {
1712 		bcmerror = BCME_NOTREADY;
1713 		goto exit;
1714 	}
1715 
1716 	/* Handle sleep stuff before any clock mucking */
1717 	if (vi->varid == IOV_SLEEP) {
1718 		if (IOV_ISSET(actionid)) {
1719 			bcmerror = dhdsdio_bussleep(bus, bool_val);
1720 		} else {
1721 			int_val = (int32)bus->sleeping;
1722 			bcopy(&int_val, arg, val_size);
1723 		}
1724 		goto exit;
1725 	}
1726 
1727 	/* Request clock to allow SDIO accesses */
1728 	if (!bus->dhd->dongle_reset) {
1729 		BUS_WAKE(bus);
1730 		dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
1731 	}
1732 
1733 	switch (actionid) {
1734 	case IOV_GVAL(IOV_INTR):
1735 		int_val = (int32)bus->intr;
1736 		bcopy(&int_val, arg, val_size);
1737 		break;
1738 
1739 	case IOV_SVAL(IOV_INTR):
1740 		bus->intr = bool_val;
1741 		bus->intdis = FALSE;
1742 		if (bus->dhd->up) {
1743 			if (bus->intr) {
1744 				DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__));
1745 				bcmsdh_intr_enable(bus->sdh);
1746 			} else {
1747 				DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
1748 				bcmsdh_intr_disable(bus->sdh);
1749 			}
1750 		}
1751 		break;
1752 
1753 	case IOV_GVAL(IOV_POLLRATE):
1754 		int_val = (int32)bus->pollrate;
1755 		bcopy(&int_val, arg, val_size);
1756 		break;
1757 
1758 	case IOV_SVAL(IOV_POLLRATE):
1759 		bus->pollrate = (uint)int_val;
1760 		bus->poll = (bus->pollrate != 0);
1761 		break;
1762 
1763 	case IOV_GVAL(IOV_IDLETIME):
1764 		int_val = bus->idletime;
1765 		bcopy(&int_val, arg, val_size);
1766 		break;
1767 
1768 	case IOV_SVAL(IOV_IDLETIME):
1769 		if ((int_val < 0) && (int_val != DHD_IDLE_IMMEDIATE)) {
1770 			bcmerror = BCME_BADARG;
1771 		} else {
1772 			bus->idletime = int_val;
1773 		}
1774 		break;
1775 
1776 	case IOV_GVAL(IOV_IDLECLOCK):
1777 		int_val = (int32)bus->idleclock;
1778 		bcopy(&int_val, arg, val_size);
1779 		break;
1780 
1781 	case IOV_SVAL(IOV_IDLECLOCK):
1782 		bus->idleclock = int_val;
1783 		break;
1784 
1785 	case IOV_GVAL(IOV_SD1IDLE):
1786 		int_val = (int32)sd1idle;
1787 		bcopy(&int_val, arg, val_size);
1788 		break;
1789 
1790 	case IOV_SVAL(IOV_SD1IDLE):
1791 		sd1idle = bool_val;
1792 		break;
1793 
1794 
1795 	case IOV_SVAL(IOV_MEMBYTES):
1796 	case IOV_GVAL(IOV_MEMBYTES):
1797 	{
1798 		uint32 address;
1799 		uint size, dsize;
1800 		uint8 *data;
1801 
1802 		bool set = (actionid == IOV_SVAL(IOV_MEMBYTES));
1803 
1804 		ASSERT(plen >= 2*sizeof(int));
1805 
1806 		address = (uint32)int_val;
1807 		bcopy((char *)params + sizeof(int_val), &int_val, sizeof(int_val));
1808 		size = (uint)int_val;
1809 
1810 		/* Do some validation */
1811 		dsize = set ? plen - (2 * sizeof(int)) : len;
1812 		if (dsize < size) {
1813 			DHD_ERROR(("%s: error on %s membytes, addr 0x%08x size %d dsize %d\n",
1814 			           __FUNCTION__, (set ? "set" : "get"), address, size, dsize));
1815 			bcmerror = BCME_BADARG;
1816 			break;
1817 		}
1818 
1819 		DHD_INFO(("%s: Request to %s %d bytes at address 0x%08x\n", __FUNCTION__,
1820 		          (set ? "write" : "read"), size, address));
1821 
1822 		/* If we know about SOCRAM, check for a fit */
1823 		if ((bus->orig_ramsize) &&
1824 		    ((address > bus->orig_ramsize) || (address + size > bus->orig_ramsize))) {
1825 			DHD_ERROR(("%s: ramsize 0x%08x doesn't have %d bytes at 0x%08x\n",
1826 			           __FUNCTION__, bus->orig_ramsize, size, address));
1827 			bcmerror = BCME_BADARG;
1828 			break;
1829 		}
1830 
1831 		/* Generate the actual data pointer */
1832 		data = set ? (uint8*)params + 2 * sizeof(int): (uint8*)arg;
1833 
1834 		/* Call to do the transfer */
1835 		bcmerror = dhdsdio_membytes(bus, set, address, data, size);
1836 
1837 		break;
1838 	}
1839 
1840 	case IOV_GVAL(IOV_MEMSIZE):
1841 		int_val = (int32)bus->ramsize;
1842 		bcopy(&int_val, arg, val_size);
1843 		break;
1844 
1845 	case IOV_GVAL(IOV_SDIOD_DRIVE):
1846 		int_val = (int32)dhd_sdiod_drive_strength;
1847 		bcopy(&int_val, arg, val_size);
1848 		break;
1849 
1850 	case IOV_SVAL(IOV_SDIOD_DRIVE):
1851 		dhd_sdiod_drive_strength = int_val;
1852 		si_sdiod_drive_strength_init(bus->sih, bus->dhd->osh, dhd_sdiod_drive_strength);
1853 		break;
1854 
1855 	case IOV_SVAL(IOV_DOWNLOAD):
1856 		bcmerror = dhdsdio_download_state(bus, bool_val);
1857 		break;
1858 
1859 	case IOV_SVAL(IOV_VARS):
1860 		bcmerror = dhdsdio_downloadvars(bus, arg, len);
1861 		break;
1862 
1863 	case IOV_GVAL(IOV_READAHEAD):
1864 		int_val = (int32)dhd_readahead;
1865 		bcopy(&int_val, arg, val_size);
1866 		break;
1867 
1868 	case IOV_SVAL(IOV_READAHEAD):
1869 		if (bool_val && !dhd_readahead)
1870 			bus->nextlen = 0;
1871 		dhd_readahead = bool_val;
1872 		break;
1873 
1874 	case IOV_GVAL(IOV_SDRXCHAIN):
1875 		int_val = (int32)bus->use_rxchain;
1876 		bcopy(&int_val, arg, val_size);
1877 		break;
1878 
1879 	case IOV_SVAL(IOV_SDRXCHAIN):
1880 		if (bool_val && !bus->sd_rxchain)
1881 			bcmerror = BCME_UNSUPPORTED;
1882 		else
1883 			bus->use_rxchain = bool_val;
1884 		break;
1885 	case IOV_GVAL(IOV_ALIGNCTL):
1886 		int_val = (int32)dhd_alignctl;
1887 		bcopy(&int_val, arg, val_size);
1888 		break;
1889 
1890 	case IOV_SVAL(IOV_ALIGNCTL):
1891 		dhd_alignctl = bool_val;
1892 		break;
1893 
1894 	case IOV_GVAL(IOV_SDALIGN):
1895 		int_val = DHD_SDALIGN;
1896 		bcopy(&int_val, arg, val_size);
1897 		break;
1898 
1899 #ifdef DHD_DEBUG
1900 	case IOV_GVAL(IOV_VARS):
1901 		if (bus->varsz < (uint)len)
1902 			bcopy(bus->vars, arg, bus->varsz);
1903 		else
1904 			bcmerror = BCME_BUFTOOSHORT;
1905 		break;
1906 #endif /* DHD_DEBUG */
1907 
1908 #ifdef DHD_DEBUG
1909 	case IOV_GVAL(IOV_SDREG):
1910 	{
1911 		sdreg_t *sd_ptr;
1912 		uint32 addr, size;
1913 
1914 		sd_ptr = (sdreg_t *)params;
1915 
1916 		addr = (uintptr)bus->regs + sd_ptr->offset;
1917 		size = sd_ptr->func;
1918 		int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size);
1919 		if (bcmsdh_regfail(bus->sdh))
1920 			bcmerror = BCME_SDIO_ERROR;
1921 		bcopy(&int_val, arg, sizeof(int32));
1922 		break;
1923 	}
1924 
1925 	case IOV_SVAL(IOV_SDREG):
1926 	{
1927 		sdreg_t *sd_ptr;
1928 		uint32 addr, size;
1929 
1930 		sd_ptr = (sdreg_t *)params;
1931 
1932 		addr = (uintptr)bus->regs + sd_ptr->offset;
1933 		size = sd_ptr->func;
1934 		bcmsdh_reg_write(bus->sdh, addr, size, sd_ptr->value);
1935 		if (bcmsdh_regfail(bus->sdh))
1936 			bcmerror = BCME_SDIO_ERROR;
1937 		break;
1938 	}
1939 
1940 	/* Same as above, but offset is not backplane (not SDIO core) */
1941 	case IOV_GVAL(IOV_SBREG):
1942 	{
1943 		sdreg_t sdreg;
1944 		uint32 addr, size;
1945 
1946 		bcopy(params, &sdreg, sizeof(sdreg));
1947 
1948 		addr = SI_ENUM_BASE + sdreg.offset;
1949 		size = sdreg.func;
1950 		int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size);
1951 		if (bcmsdh_regfail(bus->sdh))
1952 			bcmerror = BCME_SDIO_ERROR;
1953 		bcopy(&int_val, arg, sizeof(int32));
1954 		break;
1955 	}
1956 
1957 	case IOV_SVAL(IOV_SBREG):
1958 	{
1959 		sdreg_t sdreg;
1960 		uint32 addr, size;
1961 
1962 		bcopy(params, &sdreg, sizeof(sdreg));
1963 
1964 		addr = SI_ENUM_BASE + sdreg.offset;
1965 		size = sdreg.func;
1966 		bcmsdh_reg_write(bus->sdh, addr, size, sdreg.value);
1967 		if (bcmsdh_regfail(bus->sdh))
1968 			bcmerror = BCME_SDIO_ERROR;
1969 		break;
1970 	}
1971 
1972 	case IOV_GVAL(IOV_SDCIS):
1973 	{
1974 		*(char *)arg = 0;
1975 
1976 		bcmstrcat(arg, "\nFunc 0\n");
1977 		bcmsdh_cis_read(bus->sdh, 0x10, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
1978 		bcmstrcat(arg, "\nFunc 1\n");
1979 		bcmsdh_cis_read(bus->sdh, 0x11, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
1980 		bcmstrcat(arg, "\nFunc 2\n");
1981 		bcmsdh_cis_read(bus->sdh, 0x12, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
1982 		break;
1983 	}
1984 
1985 	case IOV_GVAL(IOV_FORCEEVEN):
1986 		int_val = (int32)forcealign;
1987 		bcopy(&int_val, arg, val_size);
1988 		break;
1989 
1990 	case IOV_SVAL(IOV_FORCEEVEN):
1991 		forcealign = bool_val;
1992 		break;
1993 
1994 	case IOV_GVAL(IOV_TXBOUND):
1995 		int_val = (int32)dhd_txbound;
1996 		bcopy(&int_val, arg, val_size);
1997 		break;
1998 
1999 	case IOV_SVAL(IOV_TXBOUND):
2000 		dhd_txbound = (uint)int_val;
2001 		break;
2002 
2003 	case IOV_GVAL(IOV_RXBOUND):
2004 		int_val = (int32)dhd_rxbound;
2005 		bcopy(&int_val, arg, val_size);
2006 		break;
2007 
2008 	case IOV_SVAL(IOV_RXBOUND):
2009 		dhd_rxbound = (uint)int_val;
2010 		break;
2011 
2012 	case IOV_GVAL(IOV_TXMINMAX):
2013 		int_val = (int32)dhd_txminmax;
2014 		bcopy(&int_val, arg, val_size);
2015 		break;
2016 
2017 	case IOV_SVAL(IOV_TXMINMAX):
2018 		dhd_txminmax = (uint)int_val;
2019 		break;
2020 
2021 
2022 
2023 #endif /* DHD_DEBUG */
2024 
2025 
2026 #ifdef SDTEST
2027 	case IOV_GVAL(IOV_EXTLOOP):
2028 		int_val = (int32)bus->ext_loop;
2029 		bcopy(&int_val, arg, val_size);
2030 		break;
2031 
2032 	case IOV_SVAL(IOV_EXTLOOP):
2033 		bus->ext_loop = bool_val;
2034 		break;
2035 
2036 	case IOV_GVAL(IOV_PKTGEN):
2037 		bcmerror = dhdsdio_pktgen_get(bus, arg);
2038 		break;
2039 
2040 	case IOV_SVAL(IOV_PKTGEN):
2041 		bcmerror = dhdsdio_pktgen_set(bus, arg);
2042 		break;
2043 #endif /* SDTEST */
2044 
2045 
2046 	case IOV_SVAL(IOV_DEVRESET):
2047 		DHD_TRACE(("%s: Called set IOV_DEVRESET=%d dongle_reset=%d busstate=%d\n",
2048 		           __FUNCTION__, bool_val, bus->dhd->dongle_reset,
2049 		           bus->dhd->busstate));
2050 
2051 		ASSERT(bus->dhd->osh);
2052 		/* ASSERT(bus->cl_devid); */
2053 
2054 		dhd_bus_devreset(bus->dhd, (uint8)bool_val);
2055 
2056 		break;
2057 
2058 	case IOV_GVAL(IOV_DEVRESET):
2059 		DHD_TRACE(("%s: Called get IOV_DEVRESET\n", __FUNCTION__));
2060 
2061 		/* Get its status */
2062 		int_val = (bool) bus->dhd->dongle_reset;
2063 		bcopy(&int_val, arg, val_size);
2064 
2065 		break;
2066 
2067 	default:
2068 		bcmerror = BCME_UNSUPPORTED;
2069 		break;
2070 	}
2071 
2072 exit:
2073 	if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
2074 		bus->activity = FALSE;
2075 		dhdsdio_clkctl(bus, CLK_NONE, TRUE);
2076 	}
2077 
2078 	dhd_os_sdunlock(bus->dhd);
2079 
2080 	if (actionid == IOV_SVAL(IOV_DEVRESET) && bool_val == FALSE)
2081 		dhd_preinit_ioctls((dhd_pub_t *) bus->dhd);
2082 
2083 	return bcmerror;
2084 }
2085 
2086 static int
dhdsdio_write_vars(dhd_bus_t * bus)2087 dhdsdio_write_vars(dhd_bus_t *bus)
2088 {
2089 	int bcmerror = 0;
2090 	uint32 varsize;
2091 	uint32 varaddr;
2092 	uint8 *vbuffer;
2093 	uint32 varsizew;
2094 #ifdef DHD_DEBUG
2095 	char *nvram_ularray;
2096 #endif /* DHD_DEBUG */
2097 
2098 	/* Even if there are no vars are to be written, we still need to set the ramsize. */
2099 	varsize = bus->varsz ? ROUNDUP(bus->varsz, 4) : 0;
2100 	varaddr = (bus->ramsize - 4) - varsize;
2101 
2102 	if (bus->vars) {
2103 		vbuffer = (uint8 *)MALLOC(bus->dhd->osh, varsize);
2104 		if (!vbuffer)
2105 			return BCME_NOMEM;
2106 
2107 		bzero(vbuffer, varsize);
2108 		bcopy(bus->vars, vbuffer, bus->varsz);
2109 
2110 		/* Write the vars list */
2111 		bcmerror = dhdsdio_membytes(bus, TRUE, varaddr, vbuffer, varsize);
2112 #ifdef DHD_DEBUG
2113 		/* Verify NVRAM bytes */
2114 		DHD_INFO(("Compare NVRAM dl & ul; varsize=%d\n", varsize));
2115 		nvram_ularray = (char*)MALLOC(bus->dhd->osh, varsize);
2116 		if (!nvram_ularray)
2117 			return BCME_NOMEM;
2118 
2119 		/* Upload image to verify downloaded contents. */
2120 		memset(nvram_ularray, 0xaa, varsize);
2121 
2122 		/* Read the vars list to temp buffer for comparison */
2123 		bcmerror = dhdsdio_membytes(bus, FALSE, varaddr, nvram_ularray, varsize);
2124 		if (bcmerror) {
2125 				DHD_ERROR(("%s: error %d on reading %d nvram bytes at 0x%08x\n",
2126 					__FUNCTION__, bcmerror, varsize, varaddr));
2127 		}
2128 		/* Compare the org NVRAM with the one read from RAM */
2129 		if (memcmp(vbuffer, nvram_ularray, varsize)) {
2130 			DHD_ERROR(("%s: Downloaded NVRAM image is corrupted.\n", __FUNCTION__));
2131 		} else
2132 			DHD_ERROR(("%s: Download, Upload and compare of NVRAM succeeded.\n",
2133 			__FUNCTION__));
2134 
2135 		MFREE(bus->dhd->osh, nvram_ularray, varsize);
2136 #endif /* DHD_DEBUG */
2137 
2138 		MFREE(bus->dhd->osh, vbuffer, varsize);
2139 	}
2140 
2141 	/* adjust to the user specified RAM */
2142 	DHD_INFO(("Physical memory size: %d, usable memory size: %d\n",
2143 		bus->orig_ramsize, bus->ramsize));
2144 	DHD_INFO(("Vars are at %d, orig varsize is %d\n",
2145 		varaddr, varsize));
2146 	varsize = ((bus->orig_ramsize - 4) - varaddr);
2147 
2148 	/*
2149 	 * Determine the length token:
2150 	 * Varsize, converted to words, in lower 16-bits, checksum in upper 16-bits.
2151 	 */
2152 	if (bcmerror) {
2153 		varsizew = 0;
2154 	} else {
2155 		varsizew = varsize / 4;
2156 		varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF);
2157 		varsizew = htol32(varsizew);
2158 	}
2159 
2160 	DHD_INFO(("New varsize is %d, length token=0x%08x\n", varsize, varsizew));
2161 
2162 	/* Write the length token to the last word */
2163 	bcmerror = dhdsdio_membytes(bus, TRUE, (bus->orig_ramsize - 4),
2164 		(uint8*)&varsizew, 4);
2165 
2166 	return bcmerror;
2167 }
2168 
2169 static int
dhdsdio_download_state(dhd_bus_t * bus,bool enter)2170 dhdsdio_download_state(dhd_bus_t *bus, bool enter)
2171 {
2172 	uint retries;
2173 	int bcmerror = 0;
2174 
2175 	/* To enter download state, disable ARM and reset SOCRAM.
2176 	 * To exit download state, simply reset ARM (default is RAM boot).
2177 	 */
2178 	if (enter) {
2179 
2180 		bus->alp_only = TRUE;
2181 
2182 		if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) &&
2183 		    !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) {
2184 			DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__));
2185 			bcmerror = BCME_ERROR;
2186 			goto fail;
2187 		}
2188 
2189 		si_core_disable(bus->sih, 0);
2190 		if (bcmsdh_regfail(bus->sdh)) {
2191 			bcmerror = BCME_SDIO_ERROR;
2192 			goto fail;
2193 		}
2194 
2195 		if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) {
2196 			DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__));
2197 			bcmerror = BCME_ERROR;
2198 			goto fail;
2199 		}
2200 
2201 		si_core_reset(bus->sih, 0, 0);
2202 		if (bcmsdh_regfail(bus->sdh)) {
2203 			DHD_ERROR(("%s: Failure trying reset SOCRAM core?\n", __FUNCTION__));
2204 			bcmerror = BCME_SDIO_ERROR;
2205 			goto fail;
2206 		}
2207 
2208 		/* Clear the top bit of memory */
2209 		if (bus->ramsize) {
2210 			uint32 zeros = 0;
2211 			dhdsdio_membytes(bus, TRUE, bus->ramsize - 4, (uint8*)&zeros, 4);
2212 		}
2213 	} else {
2214 		if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) {
2215 			DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__));
2216 			bcmerror = BCME_ERROR;
2217 			goto fail;
2218 		}
2219 
2220 		if (!si_iscoreup(bus->sih)) {
2221 			DHD_ERROR(("%s: SOCRAM core is down after reset?\n", __FUNCTION__));
2222 			bcmerror = BCME_ERROR;
2223 			goto fail;
2224 		}
2225 
2226 		if ((bcmerror = dhdsdio_write_vars(bus))) {
2227 			DHD_ERROR(("%s: no vars written to RAM\n", __FUNCTION__));
2228 			bcmerror = 0;
2229 		}
2230 
2231 		if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) &&
2232 		    !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) {
2233 			DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__));
2234 			bcmerror = BCME_ERROR;
2235 			goto fail;
2236 		}
2237 		W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries);
2238 
2239 
2240 		if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) &&
2241 		    !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) {
2242 			DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__));
2243 			bcmerror = BCME_ERROR;
2244 			goto fail;
2245 		}
2246 
2247 		si_core_reset(bus->sih, 0, 0);
2248 		if (bcmsdh_regfail(bus->sdh)) {
2249 			DHD_ERROR(("%s: Failure trying to reset ARM core?\n", __FUNCTION__));
2250 			bcmerror = BCME_SDIO_ERROR;
2251 			goto fail;
2252 		}
2253 
2254 		/* Allow HT Clock now that the ARM is running. */
2255 		bus->alp_only = FALSE;
2256 
2257 		bus->dhd->busstate = DHD_BUS_LOAD;
2258 	}
2259 
2260 fail:
2261 	/* Always return to SDIOD core */
2262 	if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0))
2263 		si_setcore(bus->sih, SDIOD_CORE_ID, 0);
2264 
2265 	return bcmerror;
2266 }
2267 
2268 int
dhd_bus_iovar_op(dhd_pub_t * dhdp,const char * name,void * params,int plen,void * arg,int len,bool set)2269 dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name,
2270                  void *params, int plen, void *arg, int len, bool set)
2271 {
2272 	dhd_bus_t *bus = dhdp->bus;
2273 	const bcm_iovar_t *vi = NULL;
2274 	int bcmerror = 0;
2275 	int val_size;
2276 	uint32 actionid;
2277 
2278 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2279 
2280 	ASSERT(name);
2281 	ASSERT(len >= 0);
2282 
2283 	/* Get MUST have return space */
2284 	ASSERT(set || (arg && len));
2285 
2286 	/* Set does NOT take qualifiers */
2287 	ASSERT(!set || (!params && !plen));
2288 
2289 	/* Look up var locally; if not found pass to host driver */
2290 	if ((vi = bcm_iovar_lookup(dhdsdio_iovars, name)) == NULL) {
2291 		dhd_os_sdlock(bus->dhd);
2292 
2293 		BUS_WAKE(bus);
2294 
2295 		/* Turn on clock in case SD command needs backplane */
2296 		dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
2297 
2298 		bcmerror = bcmsdh_iovar_op(bus->sdh, name, params, plen, arg, len, set);
2299 
2300 		/* Check for bus configuration changes of interest */
2301 
2302 		/* If it was divisor change, read the new one */
2303 		if (set && strcmp(name, "sd_divisor") == 0) {
2304 			if (bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
2305 			                    &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) {
2306 				bus->sd_divisor = -1;
2307 				DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, name));
2308 			} else {
2309 				DHD_INFO(("%s: noted %s update, value now %d\n",
2310 				          __FUNCTION__, name, bus->sd_divisor));
2311 			}
2312 		}
2313 		/* If it was a mode change, read the new one */
2314 		if (set && strcmp(name, "sd_mode") == 0) {
2315 			if (bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
2316 			                    &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) {
2317 				bus->sd_mode = -1;
2318 				DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, name));
2319 			} else {
2320 				DHD_INFO(("%s: noted %s update, value now %d\n",
2321 				          __FUNCTION__, name, bus->sd_mode));
2322 			}
2323 		}
2324 		/* Similar check for blocksize change */
2325 		if (set && strcmp(name, "sd_blocksize") == 0) {
2326 			int32 fnum = 2;
2327 			if (bcmsdh_iovar_op(bus->sdh, "sd_blocksize", &fnum, sizeof(int32),
2328 			                    &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) {
2329 				bus->blocksize = 0;
2330 				DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize"));
2331 			} else {
2332 				DHD_INFO(("%s: noted %s update, value now %d\n",
2333 				          __FUNCTION__, "sd_blocksize", bus->blocksize));
2334 			}
2335 		}
2336 		bus->roundup = MIN(max_roundup, bus->blocksize);
2337 
2338 		if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
2339 			bus->activity = FALSE;
2340 			dhdsdio_clkctl(bus, CLK_NONE, TRUE);
2341 		}
2342 
2343 		dhd_os_sdunlock(bus->dhd);
2344 		goto exit;
2345 	}
2346 
2347 	DHD_CTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__,
2348 	         name, (set ? "set" : "get"), len, plen));
2349 
2350 	/* set up 'params' pointer in case this is a set command so that
2351 	 * the convenience int and bool code can be common to set and get
2352 	 */
2353 	if (params == NULL) {
2354 		params = arg;
2355 		plen = len;
2356 	}
2357 
2358 	if (vi->type == IOVT_VOID)
2359 		val_size = 0;
2360 	else if (vi->type == IOVT_BUFFER)
2361 		val_size = len;
2362 	else
2363 		/* all other types are integer sized */
2364 		val_size = sizeof(int);
2365 
2366 	actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
2367 	bcmerror = dhdsdio_doiovar(bus, vi, actionid, name, params, plen, arg, len, val_size);
2368 
2369 exit:
2370 	return bcmerror;
2371 }
2372 
2373 void
dhd_bus_stop(struct dhd_bus * bus,bool enforce_mutex)2374 dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex)
2375 {
2376 	osl_t *osh = bus->dhd->osh;
2377 	uint32 local_hostintmask;
2378 	uint8 saveclk;
2379 	uint retries;
2380 	int err;
2381 
2382 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2383 
2384 	if (enforce_mutex)
2385 		dhd_os_sdlock(bus->dhd);
2386 
2387 	BUS_WAKE(bus);
2388 
2389 	/* Enable clock for device interrupts */
2390 	dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
2391 
2392 	/* Disable and clear interrupts at the chip level also */
2393 	W_SDREG(0, &bus->regs->hostintmask, retries);
2394 	local_hostintmask = bus->hostintmask;
2395 	bus->hostintmask = 0;
2396 
2397 	/* Change our idea of bus state */
2398 	bus->dhd->busstate = DHD_BUS_DOWN;
2399 
2400 	/* Force clocks on backplane to be sure F2 interrupt propagates */
2401 	saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
2402 	if (!err) {
2403 		bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
2404 		                 (saveclk | SBSDIO_FORCE_HT), &err);
2405 	}
2406 	if (err) {
2407 		DHD_ERROR(("%s: Failed to force clock for F2: err %d\n", __FUNCTION__, err));
2408 	}
2409 
2410 	/* Turn off the bus (F2), free any pending packets */
2411 	DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
2412 	bcmsdh_intr_disable(bus->sdh);
2413 	bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL);
2414 
2415 	/* Clear any pending interrupts now that F2 is disabled */
2416 	W_SDREG(local_hostintmask, &bus->regs->intstatus, retries);
2417 
2418 	/* Turn off the backplane clock (only) */
2419 	dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
2420 
2421 	/* Clear the data packet queues */
2422 	pktq_flush(osh, &bus->txq, TRUE);
2423 
2424 	/* Clear any held glomming stuff */
2425 	if (bus->glomd)
2426 		PKTFREE(osh, bus->glomd, FALSE);
2427 
2428 	if (bus->glom)
2429 		PKTFREE(osh, bus->glom, FALSE);
2430 
2431 	bus->glom = bus->glomd = NULL;
2432 
2433 	/* Clear rx control and wake any waiters */
2434 	bus->rxlen = 0;
2435 	dhd_os_ioctl_resp_wake(bus->dhd);
2436 
2437 	/* Reset some F2 state stuff */
2438 	bus->rxskip = FALSE;
2439 	bus->tx_seq = bus->rx_seq = 0;
2440 
2441 	if (enforce_mutex)
2442 		dhd_os_sdunlock(bus->dhd);
2443 }
2444 
2445 int
dhd_bus_init(dhd_pub_t * dhdp,bool enforce_mutex)2446 dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex)
2447 {
2448 	dhd_bus_t *bus = dhdp->bus;
2449 	dhd_timeout_t tmo;
2450 	uint retries = 0;
2451 	uint8 ready, enable;
2452 	int err, ret = 0;
2453 	uint8 saveclk;
2454 
2455 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2456 
2457 	ASSERT(bus->dhd);
2458 	if (!bus->dhd)
2459 		return 0;
2460 
2461 	if (enforce_mutex)
2462 		dhd_os_sdlock(bus->dhd);
2463 
2464 	/* Make sure backplane clock is on, needed to generate F2 interrupt */
2465 	dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
2466 	if (bus->clkstate != CLK_AVAIL)
2467 		goto exit;
2468 
2469 
2470 	/* Force clocks on backplane to be sure F2 interrupt propagates */
2471 	saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
2472 	if (!err) {
2473 		bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
2474 		                 (saveclk | SBSDIO_FORCE_HT), &err);
2475 	}
2476 	if (err) {
2477 		DHD_ERROR(("%s: Failed to force clock for F2: err %d\n", __FUNCTION__, err));
2478 		goto exit;
2479 	}
2480 
2481 	/* Enable function 2 (frame transfers) */
2482 	W_SDREG((SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT),
2483 	        &bus->regs->tosbmailboxdata, retries);
2484 	enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2);
2485 
2486 	bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL);
2487 
2488 	/* Give the dongle some time to do its thing and set IOR2 */
2489 	dhd_timeout_start(&tmo, DHD_WAIT_F2RDY * 1000);
2490 
2491 	ready = 0;
2492 	while (ready != enable && !dhd_timeout_expired(&tmo))
2493 	        ready = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IORDY, NULL);
2494 
2495 
2496 	DHD_INFO(("%s: enable 0x%02x, ready 0x%02x (waited %uus)\n",
2497 	          __FUNCTION__, enable, ready, tmo.elapsed));
2498 
2499 
2500 	/* If F2 successfully enabled, set core and enable interrupts */
2501 	if (ready == enable) {
2502 		/* Make sure we're talking to the core. */
2503 		if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0)))
2504 			bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0);
2505 
2506 		/* Set up the interrupt mask and enable interrupts */
2507 		bus->hostintmask = HOSTINTMASK;
2508 		W_SDREG(bus->hostintmask, &bus->regs->hostintmask, retries);
2509 
2510 		bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, (uint8)watermark, &err);
2511 
2512 		/* Set bus state according to enable result */
2513 		dhdp->busstate = DHD_BUS_DATA;
2514 
2515 		/* bcmsdh_intr_unmask(bus->sdh); */
2516 
2517 		bus->intdis = FALSE;
2518 		if (bus->intr) {
2519 			DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__));
2520 			bcmsdh_intr_enable(bus->sdh);
2521 		} else {
2522 			DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
2523 			bcmsdh_intr_disable(bus->sdh);
2524 		}
2525 
2526 	}
2527 
2528 
2529 	else {
2530 		/* Disable F2 again */
2531 		enable = SDIO_FUNC_ENABLE_1;
2532 		bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL);
2533 	}
2534 
2535 	/* Restore previous clock setting */
2536 	bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err);
2537 
2538 
2539 	/* If we didn't come up, turn off backplane clock */
2540 	if (dhdp->busstate != DHD_BUS_DATA)
2541 		dhdsdio_clkctl(bus, CLK_NONE, FALSE);
2542 
2543 exit:
2544 	if (enforce_mutex)
2545 		dhd_os_sdunlock(bus->dhd);
2546 
2547 	return ret;
2548 }
2549 
2550 static void
dhdsdio_rxfail(dhd_bus_t * bus,bool abort,bool rtx)2551 dhdsdio_rxfail(dhd_bus_t *bus, bool abort, bool rtx)
2552 {
2553 	bcmsdh_info_t *sdh = bus->sdh;
2554 	sdpcmd_regs_t *regs = bus->regs;
2555 	uint retries = 0;
2556 	uint16 lastrbc;
2557 	uint8 hi, lo;
2558 	int err;
2559 
2560 	DHD_ERROR(("%s: %sterminate frame%s\n", __FUNCTION__,
2561 	           (abort ? "abort command, " : ""), (rtx ? ", send NAK" : "")));
2562 
2563 	if (abort) {
2564 		bcmsdh_abort(sdh, SDIO_FUNC_2);
2565 	}
2566 
2567 	bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, SFC_RF_TERM, &err);
2568 	bus->f1regdata++;
2569 
2570 	/* Wait until the packet has been flushed (device/FIFO stable) */
2571 	for (lastrbc = retries = 0xffff; retries > 0; retries--) {
2572 		hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCHI, NULL);
2573 		lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCLO, NULL);
2574 		bus->f1regdata += 2;
2575 
2576 		if ((hi == 0) && (lo == 0))
2577 			break;
2578 
2579 		if ((hi > (lastrbc >> 8)) && (lo > (lastrbc & 0x00ff))) {
2580 			DHD_ERROR(("%s: count growing: last 0x%04x now 0x%04x\n",
2581 			           __FUNCTION__, lastrbc, ((hi << 8) + lo)));
2582 		}
2583 		lastrbc = (hi << 8) + lo;
2584 	}
2585 
2586 	if (!retries) {
2587 		DHD_ERROR(("%s: count never zeroed: last 0x%04x\n", __FUNCTION__, lastrbc));
2588 	} else {
2589 		DHD_INFO(("%s: flush took %d iterations\n", __FUNCTION__, (0xffff - retries)));
2590 	}
2591 
2592 	if (rtx) {
2593 		bus->rxrtx++;
2594 		W_SDREG(SMB_NAK, &regs->tosbmailbox, retries);
2595 		bus->f1regdata++;
2596 		if (retries <= retry_limit) {
2597 			bus->rxskip = TRUE;
2598 		}
2599 	}
2600 
2601 	/* Clear partial in any case */
2602 	bus->nextlen = 0;
2603 
2604 	/* If we can't reach the device, signal failure */
2605 	if (err || bcmsdh_regfail(sdh))
2606 		bus->dhd->busstate = DHD_BUS_DOWN;
2607 }
2608 
2609 static void
dhdsdio_read_control(dhd_bus_t * bus,uint8 * hdr,uint len,uint doff)2610 dhdsdio_read_control(dhd_bus_t *bus, uint8 *hdr, uint len, uint doff)
2611 {
2612 	bcmsdh_info_t *sdh = bus->sdh;
2613 	uint rdlen, pad;
2614 
2615 	int sdret;
2616 
2617 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2618 
2619 	/* Control data already received in aligned rxctl */
2620 	if ((bus->bus == SPI_BUS) && (!bus->usebufpool))
2621 		goto gotpkt;
2622 
2623 	ASSERT(bus->rxbuf);
2624 	/* Set rxctl for frame (w/optional alignment) */
2625 	bus->rxctl = bus->rxbuf;
2626 	if (dhd_alignctl) {
2627 		bus->rxctl += firstread;
2628 		if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN)))
2629 			bus->rxctl += (DHD_SDALIGN - pad);
2630 		bus->rxctl -= firstread;
2631 	}
2632 	ASSERT(bus->rxctl >= bus->rxbuf);
2633 
2634 	/* Copy the already-read portion over */
2635 	bcopy(hdr, bus->rxctl, firstread);
2636 	if (len <= firstread)
2637 		goto gotpkt;
2638 
2639 	/* Copy the full data pkt in gSPI case and process ioctl. */
2640 	if (bus->bus == SPI_BUS) {
2641 		bcopy(hdr, bus->rxctl, len);
2642 		goto gotpkt;
2643 	}
2644 
2645 	/* Raise rdlen to next SDIO block to avoid tail command */
2646 	rdlen = len - firstread;
2647 	if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
2648 		pad = bus->blocksize - (rdlen % bus->blocksize);
2649 		if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
2650 		    ((len + pad) < bus->dhd->maxctl))
2651 			rdlen += pad;
2652 	} else if (rdlen % DHD_SDALIGN) {
2653 		rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
2654 	}
2655 
2656 	/* Satisfy length-alignment requirements */
2657 	if (forcealign && (rdlen & (ALIGNMENT - 1)))
2658 		rdlen = ROUNDUP(rdlen, ALIGNMENT);
2659 
2660 	/* Drop if the read is too big or it exceeds our maximum */
2661 	if ((rdlen + firstread) > bus->dhd->maxctl) {
2662 		DHD_ERROR(("%s: %d-byte control read exceeds %d-byte buffer\n",
2663 		           __FUNCTION__, rdlen, bus->dhd->maxctl));
2664 		bus->dhd->rx_errors++;
2665 		dhdsdio_rxfail(bus, FALSE, FALSE);
2666 		goto done;
2667 	}
2668 
2669 	if ((len - doff) > bus->dhd->maxctl) {
2670 		DHD_ERROR(("%s: %d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n",
2671 		           __FUNCTION__, len, (len - doff), bus->dhd->maxctl));
2672 		bus->dhd->rx_errors++; bus->rx_toolong++;
2673 		dhdsdio_rxfail(bus, FALSE, FALSE);
2674 		goto done;
2675 	}
2676 
2677 
2678 	/* Read remainder of frame body into the rxctl buffer */
2679 	sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
2680 	                            (bus->rxctl + firstread), rdlen, NULL, NULL, NULL);
2681 	bus->f2rxdata++;
2682 	ASSERT(sdret != BCME_PENDING);
2683 
2684 	/* Control frame failures need retransmission */
2685 	if (sdret < 0) {
2686 		DHD_ERROR(("%s: read %d control bytes failed: %d\n", __FUNCTION__, rdlen, sdret));
2687 		bus->rxc_errors++; /* dhd.rx_ctlerrs is higher level */
2688 		dhdsdio_rxfail(bus, TRUE, TRUE);
2689 		goto done;
2690 	}
2691 
2692 gotpkt:
2693 
2694 #ifdef DHD_DEBUG
2695 	if (DHD_BYTES_ON() && DHD_CTL_ON()) {
2696 		prhex("RxCtrl", bus->rxctl, len);
2697 	}
2698 #endif
2699 
2700 	/* Point to valid data and indicate its length */
2701 	bus->rxctl += doff;
2702 	bus->rxlen = len - doff;
2703 
2704 done:
2705 	/* Awake any waiters */
2706 	dhd_os_ioctl_resp_wake(bus->dhd);
2707 }
2708 
2709 static uint8
dhdsdio_rxglom(dhd_bus_t * bus,uint8 rxseq)2710 dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq)
2711 {
2712 	uint16 dlen, totlen;
2713 	uint8 *dptr, num = 0;
2714 
2715 	uint16 sublen, check;
2716 	void *pfirst, *plast, *pnext, *save_pfirst;
2717 	osl_t *osh = bus->dhd->osh;
2718 
2719 	int errcode;
2720 	uint8 chan, seq, doff, sfdoff;
2721 	uint8 txmax;
2722 
2723 	int ifidx = 0;
2724 	bool usechain = bus->use_rxchain;
2725 
2726 	/* If packets, issue read(s) and send up packet chain */
2727 	/* Return sequence numbers consumed? */
2728 
2729 	DHD_TRACE(("dhdsdio_rxglom: start: glomd %p glom %p\n", bus->glomd, bus->glom));
2730 
2731 	/* If there's a descriptor, generate the packet chain */
2732 	if (bus->glomd) {
2733 		dhd_os_sdlock_rxq(bus->dhd);
2734 
2735 		pfirst = plast = pnext = NULL;
2736 		dlen = (uint16)PKTLEN(osh, bus->glomd);
2737 		dptr = PKTDATA(osh, bus->glomd);
2738 		if (!dlen || (dlen & 1)) {
2739 			DHD_ERROR(("%s: bad glomd len (%d), ignore descriptor\n",
2740 			           __FUNCTION__, dlen));
2741 			dlen = 0;
2742 		}
2743 
2744 		for (totlen = num = 0; dlen; num++) {
2745 			/* Get (and move past) next length */
2746 			sublen = ltoh16_ua(dptr);
2747 			dlen -= sizeof(uint16);
2748 			dptr += sizeof(uint16);
2749 			if ((sublen < SDPCM_HDRLEN) ||
2750 			    ((num == 0) && (sublen < (2 * SDPCM_HDRLEN)))) {
2751 				DHD_ERROR(("%s: descriptor len %d bad: %d\n",
2752 				           __FUNCTION__, num, sublen));
2753 				pnext = NULL;
2754 				break;
2755 			}
2756 			if (sublen % DHD_SDALIGN) {
2757 				DHD_ERROR(("%s: sublen %d not a multiple of %d\n",
2758 				           __FUNCTION__, sublen, DHD_SDALIGN));
2759 				usechain = FALSE;
2760 			}
2761 			totlen += sublen;
2762 
2763 			/* For last frame, adjust read len so total is a block multiple */
2764 			if (!dlen) {
2765 				sublen += (ROUNDUP(totlen, bus->blocksize) - totlen);
2766 				totlen = ROUNDUP(totlen, bus->blocksize);
2767 			}
2768 
2769 			/* Allocate/chain packet for next subframe */
2770 			if ((pnext = PKTGET(osh, sublen + DHD_SDALIGN, FALSE)) == NULL) {
2771 				DHD_ERROR(("%s: PKTGET failed, num %d len %d\n",
2772 				           __FUNCTION__, num, sublen));
2773 				break;
2774 			}
2775 			ASSERT(!PKTLINK(pnext));
2776 			if (!pfirst) {
2777 				ASSERT(!plast);
2778 				pfirst = plast = pnext;
2779 			} else {
2780 				ASSERT(plast);
2781 				PKTSETNEXT(osh, plast, pnext);
2782 				plast = pnext;
2783 			}
2784 
2785 			/* Adhere to start alignment requirements */
2786 			PKTALIGN(osh, pnext, sublen, DHD_SDALIGN);
2787 		}
2788 
2789 		/* If all allocations succeeded, save packet chain in bus structure */
2790 		if (pnext) {
2791 			DHD_GLOM(("%s: allocated %d-byte packet chain for %d subframes\n",
2792 			          __FUNCTION__, totlen, num));
2793 			if (DHD_GLOM_ON() && bus->nextlen) {
2794 				if (totlen != bus->nextlen) {
2795 					DHD_GLOM(("%s: glomdesc mismatch: nextlen %d glomdesc %d "
2796 					          "rxseq %d\n", __FUNCTION__, bus->nextlen,
2797 					          totlen, rxseq));
2798 				}
2799 			}
2800 			bus->glom = pfirst;
2801 			pfirst = pnext = NULL;
2802 		} else {
2803 			if (pfirst)
2804 				PKTFREE(osh, pfirst, FALSE);
2805 			bus->glom = NULL;
2806 			num = 0;
2807 		}
2808 
2809 		/* Done with descriptor packet */
2810 		PKTFREE(osh, bus->glomd, FALSE);
2811 		bus->glomd = NULL;
2812 		bus->nextlen = 0;
2813 
2814 		dhd_os_sdunlock_rxq(bus->dhd);
2815 	}
2816 
2817 	/* Ok -- either we just generated a packet chain, or had one from before */
2818 	if (bus->glom) {
2819 		if (DHD_GLOM_ON()) {
2820 			DHD_GLOM(("%s: attempt superframe read, packet chain:\n", __FUNCTION__));
2821 			for (pnext = bus->glom; pnext; pnext = PKTNEXT(osh, pnext)) {
2822 				DHD_GLOM(("    %p: %p len 0x%04x (%d)\n",
2823 				          pnext, (uint8*)PKTDATA(osh, pnext),
2824 				          PKTLEN(osh, pnext), PKTLEN(osh, pnext)));
2825 			}
2826 		}
2827 
2828 		pfirst = bus->glom;
2829 		dlen = (uint16)pkttotlen(osh, pfirst);
2830 
2831 		/* Do an SDIO read for the superframe.  Configurable iovar to
2832 		 * read directly into the chained packet, or allocate a large
2833 		 * packet and and copy into the chain.
2834 		 */
2835 		if (usechain) {
2836 			errcode = dhd_bcmsdh_recv_buf(bus,
2837 			                              bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2,
2838 			                              F2SYNC, (uint8*)PKTDATA(osh, pfirst),
2839 			                              dlen, pfirst, NULL, NULL);
2840 		} else if (bus->dataptr) {
2841 			errcode = dhd_bcmsdh_recv_buf(bus,
2842 			                              bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2,
2843 			                              F2SYNC, bus->dataptr,
2844 			                              dlen, NULL, NULL, NULL);
2845 			sublen = (uint16)pktfrombuf(osh, pfirst, 0, dlen, bus->dataptr);
2846 			if (sublen != dlen) {
2847 				DHD_ERROR(("%s: FAILED TO COPY, dlen %d sublen %d\n",
2848 				           __FUNCTION__, dlen, sublen));
2849 				errcode = -1;
2850 			}
2851 			pnext = NULL;
2852 		} else {
2853 			DHD_ERROR(("COULDN'T ALLOC %d-BYTE GLOM, FORCE FAILURE\n", dlen));
2854 			errcode = -1;
2855 		}
2856 		bus->f2rxdata++;
2857 		ASSERT(errcode != BCME_PENDING);
2858 
2859 		/* On failure, kill the superframe, allow a couple retries */
2860 		if (errcode < 0) {
2861 			DHD_ERROR(("%s: glom read of %d bytes failed: %d\n",
2862 			           __FUNCTION__, dlen, errcode));
2863 			bus->dhd->rx_errors++;
2864 
2865 			if (bus->glomerr++ < 3) {
2866 				dhdsdio_rxfail(bus, TRUE, TRUE);
2867 			} else {
2868 				bus->glomerr = 0;
2869 				dhdsdio_rxfail(bus, TRUE, FALSE);
2870 				dhd_os_sdlock_rxq(bus->dhd);
2871 				PKTFREE(osh, bus->glom, FALSE);
2872 				dhd_os_sdunlock_rxq(bus->dhd);
2873 				bus->rxglomfail++;
2874 				bus->glom = NULL;
2875 			}
2876 			return 0;
2877 		}
2878 
2879 #ifdef DHD_DEBUG
2880 		if (DHD_GLOM_ON()) {
2881 			prhex("SUPERFRAME", PKTDATA(osh, pfirst),
2882 			      MIN(PKTLEN(osh, pfirst), 48));
2883 		}
2884 #endif
2885 
2886 
2887 		/* Validate the superframe header */
2888 		dptr = (uint8 *)PKTDATA(osh, pfirst);
2889 		sublen = ltoh16_ua(dptr);
2890 		check = ltoh16_ua(dptr + sizeof(uint16));
2891 
2892 		chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
2893 		seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
2894 		bus->nextlen = dptr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
2895 		if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
2896 			DHD_INFO(("%s: got frame w/nextlen too large (%d) seq %d\n",
2897 			          __FUNCTION__, bus->nextlen, seq));
2898 			bus->nextlen = 0;
2899 		}
2900 		doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
2901 		txmax = SDPCM_WINDOW_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
2902 
2903 		errcode = 0;
2904 		if ((uint16)~(sublen^check)) {
2905 			DHD_ERROR(("%s (superframe): HW hdr error: len/check 0x%04x/0x%04x\n",
2906 			           __FUNCTION__, sublen, check));
2907 			errcode = -1;
2908 		} else if (ROUNDUP(sublen, bus->blocksize) != dlen) {
2909 			DHD_ERROR(("%s (superframe): len 0x%04x, rounded 0x%04x, expect 0x%04x\n",
2910 			           __FUNCTION__, sublen, ROUNDUP(sublen, bus->blocksize), dlen));
2911 			errcode = -1;
2912 		} else if (SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]) != SDPCM_GLOM_CHANNEL) {
2913 			DHD_ERROR(("%s (superframe): bad channel %d\n", __FUNCTION__,
2914 			           SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN])));
2915 			errcode = -1;
2916 		} else if (SDPCM_GLOMDESC(&dptr[SDPCM_FRAMETAG_LEN])) {
2917 			DHD_ERROR(("%s (superframe): got second descriptor?\n", __FUNCTION__));
2918 			errcode = -1;
2919 		} else if ((doff < SDPCM_HDRLEN) ||
2920 		           (doff > (PKTLEN(osh, pfirst) - SDPCM_HDRLEN))) {
2921 			DHD_ERROR(("%s (superframe): Bad data offset %d: HW %d pkt %d min %d\n",
2922 			           __FUNCTION__, doff, sublen, PKTLEN(osh, pfirst), SDPCM_HDRLEN));
2923 			errcode = -1;
2924 		}
2925 
2926 		/* Check sequence number of superframe SW header */
2927 		if (rxseq != seq) {
2928 			DHD_INFO(("%s: (superframe) rx_seq %d, expected %d\n",
2929 			          __FUNCTION__, seq, rxseq));
2930 			bus->rx_badseq++;
2931 			rxseq = seq;
2932 		}
2933 
2934 		/* Check window for sanity */
2935 		if ((uint8)(txmax - bus->tx_seq) > 0x40) {
2936 			DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
2937 			           __FUNCTION__, txmax, bus->tx_seq));
2938 			txmax = bus->tx_seq + 2;
2939 		}
2940 		bus->tx_max = txmax;
2941 
2942 		/* Remove superframe header, remember offset */
2943 		PKTPULL(osh, pfirst, doff);
2944 		sfdoff = doff;
2945 
2946 		/* Validate all the subframe headers */
2947 		for (num = 0, pnext = pfirst; pnext && !errcode;
2948 		     num++, pnext = PKTNEXT(osh, pnext)) {
2949 			dptr = (uint8 *)PKTDATA(osh, pnext);
2950 			dlen = (uint16)PKTLEN(osh, pnext);
2951 			sublen = ltoh16_ua(dptr);
2952 			check = ltoh16_ua(dptr + sizeof(uint16));
2953 			chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
2954 			doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
2955 #ifdef DHD_DEBUG
2956 			if (DHD_GLOM_ON()) {
2957 				prhex("subframe", dptr, 32);
2958 			}
2959 #endif
2960 
2961 			if ((uint16)~(sublen^check)) {
2962 				DHD_ERROR(("%s (subframe %d): HW hdr error: "
2963 				           "len/check 0x%04x/0x%04x\n",
2964 				           __FUNCTION__, num, sublen, check));
2965 				errcode = -1;
2966 			} else if ((sublen > dlen) || (sublen < SDPCM_HDRLEN)) {
2967 				DHD_ERROR(("%s (subframe %d): length mismatch: "
2968 				           "len 0x%04x, expect 0x%04x\n",
2969 				           __FUNCTION__, num, sublen, dlen));
2970 				errcode = -1;
2971 			} else if ((chan != SDPCM_DATA_CHANNEL) &&
2972 			           (chan != SDPCM_EVENT_CHANNEL)) {
2973 				DHD_ERROR(("%s (subframe %d): bad channel %d\n",
2974 				           __FUNCTION__, num, chan));
2975 				errcode = -1;
2976 			} else if ((doff < SDPCM_HDRLEN) || (doff > sublen)) {
2977 				DHD_ERROR(("%s (subframe %d): Bad data offset %d: HW %d min %d\n",
2978 				           __FUNCTION__, num, doff, sublen, SDPCM_HDRLEN));
2979 				errcode = -1;
2980 			}
2981 		}
2982 
2983 		if (errcode) {
2984 			/* Terminate frame on error, request a couple retries */
2985 			if (bus->glomerr++ < 3) {
2986 				/* Restore superframe header space */
2987 				PKTPUSH(osh, pfirst, sfdoff);
2988 				dhdsdio_rxfail(bus, TRUE, TRUE);
2989 			} else {
2990 				bus->glomerr = 0;
2991 				dhdsdio_rxfail(bus, TRUE, FALSE);
2992 				dhd_os_sdlock_rxq(bus->dhd);
2993 				PKTFREE(osh, bus->glom, FALSE);
2994 				dhd_os_sdunlock_rxq(bus->dhd);
2995 				bus->rxglomfail++;
2996 				bus->glom = NULL;
2997 			}
2998 			bus->nextlen = 0;
2999 			return 0;
3000 		}
3001 
3002 		/* Basic SD framing looks ok - process each packet (header) */
3003 		save_pfirst = pfirst;
3004 		bus->glom = NULL;
3005 		plast = NULL;
3006 
3007 		dhd_os_sdlock_rxq(bus->dhd);
3008 		for (num = 0; pfirst; rxseq++, pfirst = pnext) {
3009 			pnext = PKTNEXT(osh, pfirst);
3010 			PKTSETNEXT(osh, pfirst, NULL);
3011 
3012 			dptr = (uint8 *)PKTDATA(osh, pfirst);
3013 			sublen = ltoh16_ua(dptr);
3014 			chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
3015 			seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
3016 			doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
3017 
3018 			DHD_GLOM(("%s: Get subframe %d, %p(%p/%d), sublen %d chan %d seq %d\n",
3019 			          __FUNCTION__, num, pfirst, PKTDATA(osh, pfirst),
3020 			          PKTLEN(osh, pfirst), sublen, chan, seq));
3021 
3022 			ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL));
3023 
3024 			if (rxseq != seq) {
3025 				DHD_GLOM(("%s: rx_seq %d, expected %d\n",
3026 				          __FUNCTION__, seq, rxseq));
3027 				bus->rx_badseq++;
3028 				rxseq = seq;
3029 			}
3030 
3031 #ifdef DHD_DEBUG
3032 			if (DHD_BYTES_ON() && DHD_DATA_ON()) {
3033 				prhex("Rx Subframe Data", dptr, dlen);
3034 			}
3035 #endif
3036 
3037 			PKTSETLEN(osh, pfirst, sublen);
3038 			PKTPULL(osh, pfirst, doff);
3039 
3040 			if (PKTLEN(osh, pfirst) == 0) {
3041 				PKTFREE(bus->dhd->osh, pfirst, FALSE);
3042 				if (plast) {
3043 					PKTSETNEXT(osh, plast, pnext);
3044 				} else {
3045 					ASSERT(save_pfirst == pfirst);
3046 					save_pfirst = pnext;
3047 				}
3048 				continue;
3049 			} else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pfirst) != 0) {
3050 				DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__));
3051 				bus->dhd->rx_errors++;
3052 				PKTFREE(osh, pfirst, FALSE);
3053 				if (plast) {
3054 					PKTSETNEXT(osh, plast, pnext);
3055 				} else {
3056 					ASSERT(save_pfirst == pfirst);
3057 					save_pfirst = pnext;
3058 				}
3059 				continue;
3060 			}
3061 
3062 			/* this packet will go up, link back into chain and count it */
3063 			PKTSETNEXT(osh, pfirst, pnext);
3064 			plast = pfirst;
3065 			num++;
3066 
3067 #ifdef DHD_DEBUG
3068 			if (DHD_GLOM_ON()) {
3069 				DHD_GLOM(("%s subframe %d to stack, %p(%p/%d) nxt/lnk %p/%p\n",
3070 				          __FUNCTION__, num, pfirst,
3071 				          PKTDATA(osh, pfirst), PKTLEN(osh, pfirst),
3072 				          PKTNEXT(osh, pfirst), PKTLINK(pfirst)));
3073 				prhex("", (uint8 *)PKTDATA(osh, pfirst),
3074 				      MIN(PKTLEN(osh, pfirst), 32));
3075 			}
3076 #endif /* DHD_DEBUG */
3077 		}
3078 		dhd_os_sdunlock_rxq(bus->dhd);
3079 		if (num) {
3080 			dhd_os_sdunlock(bus->dhd);
3081 			dhd_rx_frame(bus->dhd, ifidx, save_pfirst, num);
3082 			dhd_os_sdlock(bus->dhd);
3083 		}
3084 
3085 		bus->rxglomframes++;
3086 		bus->rxglompkts += num;
3087 	}
3088 	return num;
3089 }
3090 
3091 /* Return TRUE if there may be more frames to read */
3092 static uint
dhdsdio_readframes(dhd_bus_t * bus,uint maxframes,bool * finished)3093 dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished)
3094 {
3095 	osl_t *osh = bus->dhd->osh;
3096 	bcmsdh_info_t *sdh = bus->sdh;
3097 
3098 	uint16 len, check;	/* Extracted hardware header fields */
3099 	uint8 chan, seq, doff;	/* Extracted software header fields */
3100 	uint8 fcbits;		/* Extracted fcbits from software header */
3101 	uint8 delta;
3102 
3103 	void *pkt;	/* Packet for event or data frames */
3104 	uint16 pad;	/* Number of pad bytes to read */
3105 	uint16 rdlen;	/* Total number of bytes to read */
3106 	uint8 rxseq;	/* Next sequence number to expect */
3107 	uint rxleft = 0;	/* Remaining number of frames allowed */
3108 	int sdret;	/* Return code from bcmsdh calls */
3109 	uint8 txmax;	/* Maximum tx sequence offered */
3110 	bool len_consistent; /* Result of comparing readahead len and len from hw-hdr */
3111 	uint8 *rxbuf;
3112 	int ifidx = 0;
3113 	uint rxcount = 0; /* Total frames read */
3114 
3115 #if defined(DHD_DEBUG) || defined(SDTEST)
3116 	bool sdtest = FALSE;	/* To limit message spew from test mode */
3117 #endif
3118 
3119 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3120 
3121 	ASSERT(maxframes);
3122 
3123 #ifdef SDTEST
3124 	/* Allow pktgen to override maxframes */
3125 	if (bus->pktgen_count && (bus->pktgen_mode == DHD_PKTGEN_RECV)) {
3126 		maxframes = bus->pktgen_count;
3127 		sdtest = TRUE;
3128 	}
3129 #endif
3130 
3131 	/* Not finished unless we encounter no more frames indication */
3132 	*finished = FALSE;
3133 
3134 
3135 	for (rxseq = bus->rx_seq, rxleft = maxframes;
3136 	     !bus->rxskip && rxleft && bus->dhd->busstate != DHD_BUS_DOWN;
3137 	     rxseq++, rxleft--) {
3138 
3139 		/* Handle glomming separately */
3140 		if (bus->glom || bus->glomd) {
3141 			uint8 cnt;
3142 			DHD_GLOM(("%s: calling rxglom: glomd %p, glom %p\n",
3143 			          __FUNCTION__, bus->glomd, bus->glom));
3144 			cnt = dhdsdio_rxglom(bus, rxseq);
3145 			DHD_GLOM(("%s: rxglom returned %d\n", __FUNCTION__, cnt));
3146 			rxseq += cnt - 1;
3147 			rxleft = (rxleft > cnt) ? (rxleft - cnt) : 1;
3148 			continue;
3149 		}
3150 
3151 		/* Try doing single read if we can */
3152 		if (dhd_readahead && bus->nextlen) {
3153 			uint16 nextlen = bus->nextlen;
3154 			bus->nextlen = 0;
3155 
3156 			if (bus->bus == SPI_BUS) {
3157 				rdlen = len = nextlen;
3158 			}
3159 			else {
3160 				rdlen = len = nextlen << 4;
3161 
3162 				/* Pad read to blocksize for efficiency */
3163 				if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
3164 					pad = bus->blocksize - (rdlen % bus->blocksize);
3165 					if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
3166 						((rdlen + pad + firstread) < MAX_RX_DATASZ))
3167 						rdlen += pad;
3168 				} else if (rdlen % DHD_SDALIGN) {
3169 					rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
3170 				}
3171 			}
3172 
3173 			/* We use bus->rxctl buffer in WinXP for initial control pkt receives.
3174 			 * Later we use buffer-poll for data as well as control packets.
3175 			 * This is required becuase dhd receives full frame in gSPI unlike SDIO.
3176 			 * After the frame is received we have to distinguish whether it is data
3177 			 * or non-data frame.
3178 			 */
3179 			/* Allocate a packet buffer */
3180 			dhd_os_sdlock_rxq(bus->dhd);
3181 			if (!(pkt = PKTGET(osh, rdlen + DHD_SDALIGN, FALSE))) {
3182 				if (bus->bus == SPI_BUS) {
3183 					bus->usebufpool = FALSE;
3184 					bus->rxctl = bus->rxbuf;
3185 					if (dhd_alignctl) {
3186 						bus->rxctl += firstread;
3187 						if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN)))
3188 							bus->rxctl += (DHD_SDALIGN - pad);
3189 						bus->rxctl -= firstread;
3190 					}
3191 					ASSERT(bus->rxctl >= bus->rxbuf);
3192 					rxbuf = bus->rxctl;
3193 					/* Read the entire frame */
3194 					sdret = dhd_bcmsdh_recv_buf(bus,
3195 					                            bcmsdh_cur_sbwad(sdh),
3196 					                            SDIO_FUNC_2,
3197 					                            F2SYNC, rxbuf, rdlen,
3198 					                            NULL, NULL, NULL);
3199 					bus->f2rxdata++;
3200 					ASSERT(sdret != BCME_PENDING);
3201 
3202 
3203 					/* Control frame failures need retransmission */
3204 					if (sdret < 0) {
3205 						DHD_ERROR(("%s: read %d control bytes failed: %d\n",
3206 						   __FUNCTION__, rdlen, sdret));
3207 						/* dhd.rx_ctlerrs is higher level */
3208 						bus->rxc_errors++;
3209 						dhd_os_sdunlock_rxq(bus->dhd);
3210 						dhdsdio_rxfail(bus, TRUE,
3211 						    (bus->bus == SPI_BUS) ? FALSE : TRUE);
3212 						continue;
3213 					}
3214 				} else {
3215 					/* Give up on data, request rtx of events */
3216 					DHD_ERROR(("%s (nextlen): PKTGET failed: len %d rdlen %d "
3217 					           "expected rxseq %d\n",
3218 					           __FUNCTION__, len, rdlen, rxseq));
3219 					/* Just go try again w/normal header read */
3220 					dhd_os_sdunlock_rxq(bus->dhd);
3221 					continue;
3222 				}
3223 			} else {
3224 				if (bus->bus == SPI_BUS)
3225 					bus->usebufpool = TRUE;
3226 
3227 				ASSERT(!PKTLINK(pkt));
3228 				PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN);
3229 				rxbuf = (uint8 *)PKTDATA(osh, pkt);
3230 				/* Read the entire frame */
3231 				sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh),
3232 				                            SDIO_FUNC_2,
3233 				                            F2SYNC, rxbuf, rdlen,
3234 				                            pkt, NULL, NULL);
3235 				bus->f2rxdata++;
3236 				ASSERT(sdret != BCME_PENDING);
3237 
3238 				if (sdret < 0) {
3239 					DHD_ERROR(("%s (nextlen): read %d bytes failed: %d\n",
3240 					   __FUNCTION__, rdlen, sdret));
3241 					PKTFREE(bus->dhd->osh, pkt, FALSE);
3242 					bus->dhd->rx_errors++;
3243 					dhd_os_sdunlock_rxq(bus->dhd);
3244 					/* Force retry w/normal header read.  Don't attemp NAK for
3245 					 * gSPI
3246 					 */
3247 					dhdsdio_rxfail(bus, TRUE,
3248 					      (bus->bus == SPI_BUS) ? FALSE : TRUE);
3249 					continue;
3250 				}
3251 			}
3252 			dhd_os_sdunlock_rxq(bus->dhd);
3253 
3254 			/* Now check the header */
3255 			bcopy(rxbuf, bus->rxhdr, SDPCM_HDRLEN);
3256 
3257 			/* Extract hardware header fields */
3258 			len = ltoh16_ua(bus->rxhdr);
3259 			check = ltoh16_ua(bus->rxhdr + sizeof(uint16));
3260 
3261 			/* All zeros means readahead info was bad */
3262 			if (!(len|check)) {
3263 				DHD_INFO(("%s (nextlen): read zeros in HW header???\n",
3264 				           __FUNCTION__));
3265 				dhd_os_sdlock_rxq(bus->dhd);
3266 				PKTFREE2();
3267 				dhd_os_sdunlock_rxq(bus->dhd);
3268 				GSPI_PR55150_BAILOUT;
3269 				continue;
3270 			}
3271 
3272 			/* Validate check bytes */
3273 			if ((uint16)~(len^check)) {
3274 				DHD_ERROR(("%s (nextlen): HW hdr error: nextlen/len/check"
3275 				           " 0x%04x/0x%04x/0x%04x\n", __FUNCTION__, nextlen,
3276 				           len, check));
3277 				dhd_os_sdlock_rxq(bus->dhd);
3278 				PKTFREE2();
3279 				dhd_os_sdunlock_rxq(bus->dhd);
3280 				bus->rx_badhdr++;
3281 				dhdsdio_rxfail(bus, FALSE, FALSE);
3282 				GSPI_PR55150_BAILOUT;
3283 				continue;
3284 			}
3285 
3286 			/* Validate frame length */
3287 			if (len < SDPCM_HDRLEN) {
3288 				DHD_ERROR(("%s (nextlen): HW hdr length invalid: %d\n",
3289 				           __FUNCTION__, len));
3290 				dhd_os_sdlock_rxq(bus->dhd);
3291 				PKTFREE2();
3292 				dhd_os_sdunlock_rxq(bus->dhd);
3293 				GSPI_PR55150_BAILOUT;
3294 				continue;
3295 			}
3296 
3297 			/* Check for consistency with readahead info */
3298 				len_consistent = (nextlen != (ROUNDUP(len, 16) >> 4));
3299 			if (len_consistent) {
3300 				/* Mismatch, force retry w/normal header (may be >4K) */
3301 				DHD_ERROR(("%s (nextlen): mismatch, nextlen %d len %d rnd %d; "
3302 				           "expected rxseq %d\n",
3303 				           __FUNCTION__, nextlen, len, ROUNDUP(len, 16), rxseq));
3304 				dhd_os_sdlock_rxq(bus->dhd);
3305 				PKTFREE2();
3306 				dhd_os_sdunlock_rxq(bus->dhd);
3307 				dhdsdio_rxfail(bus, TRUE, (bus->bus == SPI_BUS) ? FALSE : TRUE);
3308 				GSPI_PR55150_BAILOUT;
3309 				continue;
3310 			}
3311 
3312 
3313 			/* Extract software header fields */
3314 			chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
3315 			seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
3316 			doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
3317 			txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
3318 
3319 				bus->nextlen =
3320 				         bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
3321 				if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
3322 					DHD_INFO(("%s (nextlen): got frame w/nextlen too large"
3323 					          " (%d), seq %d\n", __FUNCTION__, bus->nextlen,
3324 					          seq));
3325 					bus->nextlen = 0;
3326 				}
3327 
3328 				bus->dhd->rx_readahead_cnt ++;
3329 			/* Handle Flow Control */
3330 			fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
3331 
3332 			delta = 0;
3333 			if (~bus->flowcontrol & fcbits) {
3334 				bus->fc_xoff++;
3335 				delta = 1;
3336 			}
3337 			if (bus->flowcontrol & ~fcbits) {
3338 				bus->fc_xon++;
3339 				delta = 1;
3340 			}
3341 
3342 			if (delta) {
3343 				bus->fc_rcvd++;
3344 				bus->flowcontrol = fcbits;
3345 			}
3346 
3347 			/* Check and update sequence number */
3348 			if (rxseq != seq) {
3349 				DHD_INFO(("%s (nextlen): rx_seq %d, expected %d\n",
3350 				          __FUNCTION__, seq, rxseq));
3351 				bus->rx_badseq++;
3352 				rxseq = seq;
3353 			}
3354 
3355 			/* Check window for sanity */
3356 			if ((uint8)(txmax - bus->tx_seq) > 0x40) {
3357 					DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
3358 						__FUNCTION__, txmax, bus->tx_seq));
3359 					txmax = bus->tx_seq + 2;
3360 			}
3361 			bus->tx_max = txmax;
3362 
3363 #ifdef DHD_DEBUG
3364 			if (DHD_BYTES_ON() && DHD_DATA_ON()) {
3365 				prhex("Rx Data", rxbuf, len);
3366 			} else if (DHD_HDRS_ON()) {
3367 				prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN);
3368 			}
3369 #endif
3370 
3371 			if (chan == SDPCM_CONTROL_CHANNEL) {
3372 				if (bus->bus == SPI_BUS) {
3373 					dhdsdio_read_control(bus, rxbuf, len, doff);
3374 					if (bus->usebufpool) {
3375 						dhd_os_sdlock_rxq(bus->dhd);
3376 						PKTFREE(bus->dhd->osh, pkt, FALSE);
3377 						dhd_os_sdunlock_rxq(bus->dhd);
3378 					}
3379 					continue;
3380 				} else {
3381 					DHD_ERROR(("%s (nextlen): readahead on control"
3382 					           " packet %d?\n", __FUNCTION__, seq));
3383 					/* Force retry w/normal header read */
3384 					bus->nextlen = 0;
3385 					dhdsdio_rxfail(bus, FALSE, TRUE);
3386 					dhd_os_sdlock_rxq(bus->dhd);
3387 					PKTFREE2();
3388 					dhd_os_sdunlock_rxq(bus->dhd);
3389 					continue;
3390 				}
3391 			}
3392 
3393 			if ((bus->bus == SPI_BUS) && !bus->usebufpool) {
3394 				DHD_ERROR(("Received %d bytes on %d channel. Running out of "
3395 				           "rx pktbuf's or not yet malloced.\n", len, chan));
3396 				continue;
3397 			}
3398 
3399 			/* Validate data offset */
3400 			if ((doff < SDPCM_HDRLEN) || (doff > len)) {
3401 				DHD_ERROR(("%s (nextlen): bad data offset %d: HW len %d min %d\n",
3402 				           __FUNCTION__, doff, len, SDPCM_HDRLEN));
3403 				dhd_os_sdlock_rxq(bus->dhd);
3404 				PKTFREE2();
3405 				dhd_os_sdunlock_rxq(bus->dhd);
3406 				ASSERT(0);
3407 				dhdsdio_rxfail(bus, FALSE, FALSE);
3408 				continue;
3409 			}
3410 
3411 			/* All done with this one -- now deliver the packet */
3412 			goto deliver;
3413 		}
3414 		/* gSPI frames should not be handled in fractions */
3415 		if (bus->bus == SPI_BUS) {
3416 			break;
3417 		}
3418 
3419 		/* Read frame header (hardware and software) */
3420 		sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
3421 		                            bus->rxhdr, firstread, NULL, NULL, NULL);
3422 		bus->f2rxhdrs++;
3423 		ASSERT(sdret != BCME_PENDING);
3424 
3425 		if (sdret < 0) {
3426 			DHD_ERROR(("%s: RXHEADER FAILED: %d\n", __FUNCTION__, sdret));
3427 			bus->rx_hdrfail++;
3428 			dhdsdio_rxfail(bus, TRUE, TRUE);
3429 			continue;
3430 		}
3431 
3432 #ifdef DHD_DEBUG
3433 		if (DHD_BYTES_ON() || DHD_HDRS_ON()) {
3434 			prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN);
3435 		}
3436 #endif
3437 
3438 		/* Extract hardware header fields */
3439 		len = ltoh16_ua(bus->rxhdr);
3440 		check = ltoh16_ua(bus->rxhdr + sizeof(uint16));
3441 
3442 		/* All zeros means no more frames */
3443 		if (!(len|check)) {
3444 			*finished = TRUE;
3445 			break;
3446 		}
3447 
3448 		/* Validate check bytes */
3449 		if ((uint16)~(len^check)) {
3450 			DHD_ERROR(("%s: HW hdr error: len/check 0x%04x/0x%04x\n",
3451 			           __FUNCTION__, len, check));
3452 			bus->rx_badhdr++;
3453 			dhdsdio_rxfail(bus, FALSE, FALSE);
3454 			continue;
3455 		}
3456 
3457 		/* Validate frame length */
3458 		if (len < SDPCM_HDRLEN) {
3459 			DHD_ERROR(("%s: HW hdr length invalid: %d\n", __FUNCTION__, len));
3460 			continue;
3461 		}
3462 
3463 		/* Extract software header fields */
3464 		chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
3465 		seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
3466 		doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
3467 		txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
3468 
3469 		/* Validate data offset */
3470 		if ((doff < SDPCM_HDRLEN) || (doff > len)) {
3471 			DHD_ERROR(("%s: Bad data offset %d: HW len %d, min %d seq %d\n",
3472 			           __FUNCTION__, doff, len, SDPCM_HDRLEN, seq));
3473 			bus->rx_badhdr++;
3474 			ASSERT(0);
3475 			dhdsdio_rxfail(bus, FALSE, FALSE);
3476 			continue;
3477 		}
3478 
3479 		/* Save the readahead length if there is one */
3480 		bus->nextlen = bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
3481 		if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
3482 			DHD_INFO(("%s (nextlen): got frame w/nextlen too large (%d), seq %d\n",
3483 			          __FUNCTION__, bus->nextlen, seq));
3484 			bus->nextlen = 0;
3485 		}
3486 
3487 		/* Handle Flow Control */
3488 		fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
3489 
3490 		delta = 0;
3491 		if (~bus->flowcontrol & fcbits) {
3492 			bus->fc_xoff++;
3493 			delta = 1;
3494 		}
3495 		if (bus->flowcontrol & ~fcbits) {
3496 			bus->fc_xon++;
3497 			delta = 1;
3498 		}
3499 
3500 		if (delta) {
3501 			bus->fc_rcvd++;
3502 			bus->flowcontrol = fcbits;
3503 		}
3504 
3505 		/* Check and update sequence number */
3506 		if (rxseq != seq) {
3507 			DHD_INFO(("%s: rx_seq %d, expected %d\n", __FUNCTION__, seq, rxseq));
3508 			bus->rx_badseq++;
3509 			rxseq = seq;
3510 		}
3511 
3512 		/* Check window for sanity */
3513 		if ((uint8)(txmax - bus->tx_seq) > 0x40) {
3514 			DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
3515 			           __FUNCTION__, txmax, bus->tx_seq));
3516 			txmax = bus->tx_seq + 2;
3517 		}
3518 		bus->tx_max = txmax;
3519 
3520 		/* Call a separate function for control frames */
3521 		if (chan == SDPCM_CONTROL_CHANNEL) {
3522 			dhdsdio_read_control(bus, bus->rxhdr, len, doff);
3523 			continue;
3524 		}
3525 
3526 		ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL) ||
3527 		       (chan == SDPCM_TEST_CHANNEL) || (chan == SDPCM_GLOM_CHANNEL));
3528 
3529 		/* Length to read */
3530 		rdlen = (len > firstread) ? (len - firstread) : 0;
3531 
3532 		/* May pad read to blocksize for efficiency */
3533 		if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
3534 			pad = bus->blocksize - (rdlen % bus->blocksize);
3535 			if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
3536 			    ((rdlen + pad + firstread) < MAX_RX_DATASZ))
3537 				rdlen += pad;
3538 		} else if (rdlen % DHD_SDALIGN) {
3539 			rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
3540 		}
3541 
3542 		/* Satisfy length-alignment requirements */
3543 		if (forcealign && (rdlen & (ALIGNMENT - 1)))
3544 			rdlen = ROUNDUP(rdlen, ALIGNMENT);
3545 
3546 		if ((rdlen + firstread) > MAX_RX_DATASZ) {
3547 			/* Too long -- skip this frame */
3548 			DHD_ERROR(("%s: too long: len %d rdlen %d\n", __FUNCTION__, len, rdlen));
3549 			bus->dhd->rx_errors++; bus->rx_toolong++;
3550 			dhdsdio_rxfail(bus, FALSE, FALSE);
3551 			continue;
3552 		}
3553 
3554 		dhd_os_sdlock_rxq(bus->dhd);
3555 		if (!(pkt = PKTGET(osh, (rdlen + firstread + DHD_SDALIGN), FALSE))) {
3556 			/* Give up on data, request rtx of events */
3557 			DHD_ERROR(("%s: PKTGET failed: rdlen %d chan %d\n",
3558 			           __FUNCTION__, rdlen, chan));
3559 			bus->dhd->rx_dropped++;
3560 			dhd_os_sdunlock_rxq(bus->dhd);
3561 			dhdsdio_rxfail(bus, FALSE, RETRYCHAN(chan));
3562 			continue;
3563 		}
3564 		dhd_os_sdunlock_rxq(bus->dhd);
3565 
3566 		ASSERT(!PKTLINK(pkt));
3567 
3568 		/* Leave room for what we already read, and align remainder */
3569 		ASSERT(firstread < (PKTLEN(osh, pkt)));
3570 		PKTPULL(osh, pkt, firstread);
3571 		PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN);
3572 
3573 		/* Read the remaining frame data */
3574 		sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
3575 		                            ((uint8 *)PKTDATA(osh, pkt)), rdlen, pkt, NULL, NULL);
3576 		bus->f2rxdata++;
3577 		ASSERT(sdret != BCME_PENDING);
3578 
3579 		if (sdret < 0) {
3580 			DHD_ERROR(("%s: read %d %s bytes failed: %d\n", __FUNCTION__, rdlen,
3581 			           ((chan == SDPCM_EVENT_CHANNEL) ? "event" :
3582 			            ((chan == SDPCM_DATA_CHANNEL) ? "data" : "test")), sdret));
3583 			dhd_os_sdlock_rxq(bus->dhd);
3584 			PKTFREE(bus->dhd->osh, pkt, FALSE);
3585 			dhd_os_sdunlock_rxq(bus->dhd);
3586 			bus->dhd->rx_errors++;
3587 			dhdsdio_rxfail(bus, TRUE, RETRYCHAN(chan));
3588 			continue;
3589 		}
3590 
3591 		/* Copy the already-read portion */
3592 		PKTPUSH(osh, pkt, firstread);
3593 		bcopy(bus->rxhdr, PKTDATA(osh, pkt), firstread);
3594 
3595 #ifdef DHD_DEBUG
3596 		if (DHD_BYTES_ON() && DHD_DATA_ON()) {
3597 			prhex("Rx Data", PKTDATA(osh, pkt), len);
3598 		}
3599 #endif
3600 
3601 deliver:
3602 		/* Save superframe descriptor and allocate packet frame */
3603 		if (chan == SDPCM_GLOM_CHANNEL) {
3604 			if (SDPCM_GLOMDESC(&bus->rxhdr[SDPCM_FRAMETAG_LEN])) {
3605 				DHD_GLOM(("%s: got glom descriptor, %d bytes:\n",
3606 				          __FUNCTION__, len));
3607 #ifdef DHD_DEBUG
3608 				if (DHD_GLOM_ON()) {
3609 					prhex("Glom Data", PKTDATA(osh, pkt), len);
3610 				}
3611 #endif
3612 				PKTSETLEN(osh, pkt, len);
3613 				ASSERT(doff == SDPCM_HDRLEN);
3614 				PKTPULL(osh, pkt, SDPCM_HDRLEN);
3615 				bus->glomd = pkt;
3616 			} else {
3617 				DHD_ERROR(("%s: glom superframe w/o descriptor!\n", __FUNCTION__));
3618 				dhdsdio_rxfail(bus, FALSE, FALSE);
3619 			}
3620 			continue;
3621 		}
3622 
3623 		/* Fill in packet len and prio, deliver upward */
3624 		PKTSETLEN(osh, pkt, len);
3625 		PKTPULL(osh, pkt, doff);
3626 
3627 #ifdef SDTEST
3628 		/* Test channel packets are processed separately */
3629 		if (chan == SDPCM_TEST_CHANNEL) {
3630 			dhdsdio_testrcv(bus, pkt, seq);
3631 			continue;
3632 		}
3633 #endif /* SDTEST */
3634 
3635 		if (PKTLEN(osh, pkt) == 0) {
3636 			dhd_os_sdlock_rxq(bus->dhd);
3637 			PKTFREE(bus->dhd->osh, pkt, FALSE);
3638 			dhd_os_sdunlock_rxq(bus->dhd);
3639 			continue;
3640 		} else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pkt) != 0) {
3641 			DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__));
3642 			dhd_os_sdlock_rxq(bus->dhd);
3643 			PKTFREE(bus->dhd->osh, pkt, FALSE);
3644 			dhd_os_sdunlock_rxq(bus->dhd);
3645 			bus->dhd->rx_errors++;
3646 			continue;
3647 		}
3648 
3649 
3650 		/* Unlock during rx call */
3651 		dhd_os_sdunlock(bus->dhd);
3652 		dhd_rx_frame(bus->dhd, ifidx, pkt, 1);
3653 		dhd_os_sdlock(bus->dhd);
3654 	}
3655 	rxcount = maxframes - rxleft;
3656 #ifdef DHD_DEBUG
3657 	/* Message if we hit the limit */
3658 	if (!rxleft && !sdtest)
3659 		DHD_DATA(("%s: hit rx limit of %d frames\n", __FUNCTION__, maxframes));
3660 	else
3661 #endif /* DHD_DEBUG */
3662 	DHD_DATA(("%s: processed %d frames\n", __FUNCTION__, rxcount));
3663 	/* Back off rxseq if awaiting rtx, update rx_seq */
3664 	if (bus->rxskip)
3665 		rxseq--;
3666 	bus->rx_seq = rxseq;
3667 
3668 	return rxcount;
3669 }
3670 
3671 static uint32
dhdsdio_hostmail(dhd_bus_t * bus)3672 dhdsdio_hostmail(dhd_bus_t *bus)
3673 {
3674 	sdpcmd_regs_t *regs = bus->regs;
3675 	uint32 intstatus = 0;
3676 	uint32 hmb_data;
3677 	uint8 fcbits;
3678 	uint retries = 0;
3679 
3680 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3681 
3682 	/* Read mailbox data and ack that we did so */
3683 	R_SDREG(hmb_data, &regs->tohostmailboxdata, retries);
3684 	if (retries <= retry_limit)
3685 		W_SDREG(SMB_INT_ACK, &regs->tosbmailbox, retries);
3686 	bus->f1regdata += 2;
3687 
3688 	/* Dongle recomposed rx frames, accept them again */
3689 	if (hmb_data & HMB_DATA_NAKHANDLED) {
3690 		DHD_INFO(("Dongle reports NAK handled, expect rtx of %d\n", bus->rx_seq));
3691 		if (!bus->rxskip) {
3692 			DHD_ERROR(("%s: unexpected NAKHANDLED!\n", __FUNCTION__));
3693 		}
3694 		bus->rxskip = FALSE;
3695 		intstatus |= I_HMB_FRAME_IND;
3696 	}
3697 
3698 	/*
3699 	 * DEVREADY does not occur with gSPI.
3700 	 */
3701 	if (hmb_data & (HMB_DATA_DEVREADY | HMB_DATA_FWREADY)) {
3702 		bus->sdpcm_ver = (hmb_data & HMB_DATA_VERSION_MASK) >> HMB_DATA_VERSION_SHIFT;
3703 		if (bus->sdpcm_ver != SDPCM_PROT_VERSION)
3704 			DHD_ERROR(("Version mismatch, dongle reports %d, expecting %d\n",
3705 			           bus->sdpcm_ver, SDPCM_PROT_VERSION));
3706 		else
3707 			DHD_INFO(("Dongle ready, protocol version %d\n", bus->sdpcm_ver));
3708 	}
3709 
3710 	/*
3711 	 * Flow Control has been moved into the RX headers and this out of band
3712 	 * method isn't used any more.  Leae this here for possibly remaining backward
3713 	 * compatible with older dongles
3714 	 */
3715 	if (hmb_data & HMB_DATA_FC) {
3716 		fcbits = (hmb_data & HMB_DATA_FCDATA_MASK) >> HMB_DATA_FCDATA_SHIFT;
3717 
3718 		if (fcbits & ~bus->flowcontrol)
3719 			bus->fc_xoff++;
3720 		if (bus->flowcontrol & ~fcbits)
3721 			bus->fc_xon++;
3722 
3723 		bus->fc_rcvd++;
3724 		bus->flowcontrol = fcbits;
3725 	}
3726 
3727 	/* Shouldn't be any others */
3728 	if (hmb_data & ~(HMB_DATA_DEVREADY |
3729 	                 HMB_DATA_NAKHANDLED |
3730 	                 HMB_DATA_FC |
3731 	                 HMB_DATA_FWREADY |
3732 	                 HMB_DATA_FCDATA_MASK |
3733 	                 HMB_DATA_VERSION_MASK)) {
3734 		DHD_ERROR(("Unknown mailbox data content: 0x%02x\n", hmb_data));
3735 	}
3736 
3737 	return intstatus;
3738 }
3739 
3740 bool
dhdsdio_dpc(dhd_bus_t * bus)3741 dhdsdio_dpc(dhd_bus_t *bus)
3742 {
3743 	bcmsdh_info_t *sdh = bus->sdh;
3744 	sdpcmd_regs_t *regs = bus->regs;
3745 	uint32 intstatus, newstatus = 0;
3746 	uint retries = 0;
3747 	uint rxlimit = dhd_rxbound; /* Rx frames to read before resched */
3748 	uint txlimit = dhd_txbound; /* Tx frames to send before resched */
3749 	uint framecnt = 0;		  /* Temporary counter of tx/rx frames */
3750 	bool rxdone = TRUE;		  /* Flag for no more read data */
3751 	bool resched = FALSE;	  /* Flag indicating resched wanted */
3752 
3753 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3754 
3755 	/* Start with leftover status bits */
3756 	intstatus = bus->intstatus;
3757 
3758 	dhd_os_sdlock(bus->dhd);
3759 
3760 	/* If waiting for HTAVAIL, check status */
3761 	if (bus->clkstate == CLK_PENDING) {
3762 		int err;
3763 		uint8 clkctl, devctl = 0;
3764 
3765 #ifdef DHD_DEBUG
3766 		/* Check for inconsistent device control */
3767 		devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
3768 		if (err) {
3769 			DHD_ERROR(("%s: error reading DEVCTL: %d\n", __FUNCTION__, err));
3770 			bus->dhd->busstate = DHD_BUS_DOWN;
3771 		}
3772 		ASSERT(devctl & SBSDIO_DEVCTL_CA_INT_ONLY);
3773 #endif /* DHD_DEBUG */
3774 
3775 		/* Read CSR, if clock on switch to AVAIL, else ignore */
3776 		clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
3777 		if (err) {
3778 			DHD_ERROR(("%s: error reading CSR: %d\n", __FUNCTION__, err));
3779 			bus->dhd->busstate = DHD_BUS_DOWN;
3780 		}
3781 
3782 		DHD_INFO(("DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n", devctl, clkctl));
3783 
3784 		if (SBSDIO_HTAV(clkctl)) {
3785 			devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
3786 			if (err) {
3787 				DHD_ERROR(("%s: error reading DEVCTL: %d\n",
3788 				           __FUNCTION__, err));
3789 				bus->dhd->busstate = DHD_BUS_DOWN;
3790 			}
3791 			devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
3792 			bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
3793 			if (err) {
3794 				DHD_ERROR(("%s: error writing DEVCTL: %d\n",
3795 				           __FUNCTION__, err));
3796 				bus->dhd->busstate = DHD_BUS_DOWN;
3797 			}
3798 			bus->clkstate = CLK_AVAIL;
3799 		} else {
3800 			goto clkwait;
3801 		}
3802 	}
3803 
3804 	BUS_WAKE(bus);
3805 
3806 	/* Make sure backplane clock is on */
3807 	dhdsdio_clkctl(bus, CLK_AVAIL, TRUE);
3808 	if (bus->clkstate == CLK_PENDING)
3809 		goto clkwait;
3810 
3811 	/* Pending interrupt indicates new device status */
3812 	if (bus->ipend) {
3813 		bus->ipend = FALSE;
3814 		R_SDREG(newstatus, &regs->intstatus, retries);
3815 		bus->f1regdata++;
3816 		if (bcmsdh_regfail(bus->sdh))
3817 			newstatus = 0;
3818 		newstatus &= bus->hostintmask;
3819 		bus->fcstate = !!(newstatus & I_HMB_FC_STATE);
3820 		if (newstatus) {
3821 			W_SDREG(newstatus, &regs->intstatus, retries);
3822 			bus->f1regdata++;
3823 		}
3824 	}
3825 
3826 	/* Merge new bits with previous */
3827 	intstatus |= newstatus;
3828 	bus->intstatus = 0;
3829 
3830 	/* Handle flow-control change: read new state in case our ack
3831 	 * crossed another change interrupt.  If change still set, assume
3832 	 * FC ON for safety, let next loop through do the debounce.
3833 	 */
3834 	if (intstatus & I_HMB_FC_CHANGE) {
3835 		intstatus &= ~I_HMB_FC_CHANGE;
3836 		W_SDREG(I_HMB_FC_CHANGE, &regs->intstatus, retries);
3837 		R_SDREG(newstatus, &regs->intstatus, retries);
3838 		bus->f1regdata += 2;
3839 		bus->fcstate = !!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE));
3840 		intstatus |= (newstatus & bus->hostintmask);
3841 	}
3842 
3843 	/* Handle host mailbox indication */
3844 	if (intstatus & I_HMB_HOST_INT) {
3845 		intstatus &= ~I_HMB_HOST_INT;
3846 		intstatus |= dhdsdio_hostmail(bus);
3847 	}
3848 
3849 	/* Generally don't ask for these, can get CRC errors... */
3850 	if (intstatus & I_WR_OOSYNC) {
3851 		DHD_ERROR(("Dongle reports WR_OOSYNC\n"));
3852 		intstatus &= ~I_WR_OOSYNC;
3853 	}
3854 
3855 	if (intstatus & I_RD_OOSYNC) {
3856 		DHD_ERROR(("Dongle reports RD_OOSYNC\n"));
3857 		intstatus &= ~I_RD_OOSYNC;
3858 	}
3859 
3860 	if (intstatus & I_SBINT) {
3861 		DHD_ERROR(("Dongle reports SBINT\n"));
3862 		intstatus &= ~I_SBINT;
3863 	}
3864 
3865 	/* Would be active due to wake-wlan in gSPI */
3866 	if (intstatus & I_CHIPACTIVE) {
3867 		DHD_INFO(("Dongle reports CHIPACTIVE\n"));
3868 		intstatus &= ~I_CHIPACTIVE;
3869 	}
3870 
3871 	/* Ignore frame indications if rxskip is set */
3872 	if (bus->rxskip)
3873 		intstatus &= ~I_HMB_FRAME_IND;
3874 
3875 	/* On frame indication, read available frames */
3876 	if (PKT_AVAILABLE()) {
3877 		framecnt = dhdsdio_readframes(bus, rxlimit, &rxdone);
3878 		if (rxdone || bus->rxskip)
3879 			intstatus &= ~I_HMB_FRAME_IND;
3880 		rxlimit -= MIN(framecnt, rxlimit);
3881 	}
3882 
3883 	/* Keep still-pending events for next scheduling */
3884 	bus->intstatus = intstatus;
3885 
3886 clkwait:
3887 	/* Re-enable interrupts to detect new device events (mailbox, rx frame)
3888 	 * or clock availability.  (Allows tx loop to check ipend if desired.)
3889 	 * (Unless register access seems hosed, as we may not be able to ACK...)
3890 	 */
3891 	if (bus->intr && bus->intdis && !bcmsdh_regfail(sdh)) {
3892 		DHD_INTR(("%s: enable SDIO interrupts, rxdone %d framecnt %d\n",
3893 		          __FUNCTION__, rxdone, framecnt));
3894 		bus->intdis = FALSE;
3895 		bcmsdh_intr_enable(sdh);
3896 	}
3897 
3898 	if (DATAOK(bus) && bus->ctrl_frame_stat) {
3899 		int ret, i;
3900 
3901 		ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
3902 		                      (uint8 *)bus->ctrl_frame_buf, (uint32)bus->ctrl_frame_len,
3903 			NULL, NULL, NULL);
3904 		ASSERT(ret != BCME_PENDING);
3905 
3906 		if (ret < 0) {
3907 			/* On failure, abort the command and terminate the frame */
3908 			DHD_INFO(("%s: sdio error %d, abort command and terminate frame.\n",
3909 			          __FUNCTION__, ret));
3910 			bus->tx_sderrs++;
3911 
3912 			bcmsdh_abort(sdh, SDIO_FUNC_2);
3913 
3914 			bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
3915 			                 SFC_WF_TERM, NULL);
3916 			bus->f1regdata++;
3917 
3918 			for (i = 0; i < 3; i++) {
3919 				uint8 hi, lo;
3920 				hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
3921 				                     SBSDIO_FUNC1_WFRAMEBCHI, NULL);
3922 				lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
3923 				                     SBSDIO_FUNC1_WFRAMEBCLO, NULL);
3924 				bus->f1regdata += 2;
3925 				if ((hi == 0) && (lo == 0))
3926 					break;
3927 			}
3928 
3929 		}
3930 		printf("Return_dpc value is : %d\n", ret);
3931 		bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
3932 		bus->ctrl_frame_stat = FALSE;
3933 		dhd_wait_event_wakeup(bus->dhd);
3934 	}
3935 	/* Send queued frames (limit 1 if rx may still be pending) */
3936 	else if ((bus->clkstate != CLK_PENDING) && !bus->fcstate &&
3937 	    pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit && DATAOK(bus)) {
3938 		framecnt = rxdone ? txlimit : MIN(txlimit, dhd_txminmax);
3939 		framecnt = dhdsdio_sendfromq(bus, framecnt);
3940 		txlimit -= framecnt;
3941 	}
3942 
3943 	/* Resched if events or tx frames are pending, else await next interrupt */
3944 	/* On failed register access, all bets are off: no resched or interrupts */
3945 	if ((bus->dhd->busstate == DHD_BUS_DOWN) || bcmsdh_regfail(sdh)) {
3946 		DHD_ERROR(("%s: failed backplane access over SDIO, halting operation\n",
3947 		           __FUNCTION__));
3948 		bus->dhd->busstate = DHD_BUS_DOWN;
3949 		bus->intstatus = 0;
3950 	} else if (bus->clkstate == CLK_PENDING) {
3951 		/* Awaiting I_CHIPACTIVE; don't resched */
3952 	} else if (bus->intstatus || bus->ipend ||
3953 	           (!bus->fcstate && pktq_mlen(&bus->txq, ~bus->flowcontrol) && DATAOK(bus)) ||
3954 			PKT_AVAILABLE()) {  /* Read multiple frames */
3955 		resched = TRUE;
3956 	}
3957 
3958 
3959 	bus->dpc_sched = resched;
3960 
3961 	/* If we're done for now, turn off clock request. */
3962 	if ((bus->clkstate != CLK_PENDING) && bus->idletime == DHD_IDLE_IMMEDIATE) {
3963 		bus->activity = FALSE;
3964 		dhdsdio_clkctl(bus, CLK_NONE, FALSE);
3965 	}
3966 
3967 	dhd_os_sdunlock(bus->dhd);
3968 
3969 	return resched;
3970 }
3971 
3972 bool
dhd_bus_dpc(struct dhd_bus * bus)3973 dhd_bus_dpc(struct dhd_bus *bus)
3974 {
3975 #ifdef SDIO_ISR_THREAD
3976 	bool resched;
3977 
3978 	/* Call the DPC directly. */
3979 	DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__));
3980 	resched = dhdsdio_dpc(bus);
3981 
3982 	return resched;
3983 #else
3984 	return dhdsdio_dpc(bus);
3985 #endif /* SDIO_ISR_THREAD */
3986 }
3987 
3988 void
dhdsdio_isr(void * arg)3989 dhdsdio_isr(void *arg)
3990 {
3991 	dhd_bus_t *bus = (dhd_bus_t*)arg;
3992 	bcmsdh_info_t *sdh = bus->sdh;
3993 
3994 	if (bus->dhd->busstate == DHD_BUS_DOWN) {
3995 		DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__));
3996 		return;
3997 	}
3998 
3999 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4000 
4001 	/* Count the interrupt call */
4002 	bus->intrcount++;
4003 	bus->ipend = TRUE;
4004 
4005 	/* Shouldn't get this interrupt if we're sleeping? */
4006 	if (bus->sleeping) {
4007 		DHD_ERROR(("INTERRUPT WHILE SLEEPING??\n"));
4008 		return;
4009 	}
4010 
4011 	/* Disable additional interrupts (is this needed now)? */
4012 	if (bus->intr) {
4013 		DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
4014 	} else {
4015 		DHD_ERROR(("dhdsdio_isr() w/o interrupt configured!\n"));
4016 	}
4017 
4018 	bcmsdh_intr_disable(sdh);
4019 	bus->intdis = TRUE;
4020 
4021 #if defined(SDIO_ISR_THREAD)
4022 	DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__));
4023 	dhd_os_wake_lock(bus->dhd);
4024 	while (dhdsdio_dpc(bus));
4025 	dhd_os_wake_unlock(bus->dhd);
4026 #else
4027 	bus->dpc_sched = TRUE;
4028 	dhd_sched_dpc(bus->dhd);
4029 #endif
4030 
4031 }
4032 
4033 #ifdef SDTEST
4034 static void
dhdsdio_pktgen_init(dhd_bus_t * bus)4035 dhdsdio_pktgen_init(dhd_bus_t *bus)
4036 {
4037 	/* Default to specified length, or full range */
4038 	if (dhd_pktgen_len) {
4039 		bus->pktgen_maxlen = MIN(dhd_pktgen_len, MAX_PKTGEN_LEN);
4040 		bus->pktgen_minlen = bus->pktgen_maxlen;
4041 	} else {
4042 		bus->pktgen_maxlen = MAX_PKTGEN_LEN;
4043 		bus->pktgen_minlen = 0;
4044 	}
4045 	bus->pktgen_len = (uint16)bus->pktgen_minlen;
4046 
4047 	/* Default to per-watchdog burst with 10s print time */
4048 	bus->pktgen_freq = 1;
4049 	bus->pktgen_print = 10000 / dhd_watchdog_ms;
4050 	bus->pktgen_count = (dhd_pktgen * dhd_watchdog_ms + 999) / 1000;
4051 
4052 	/* Default to echo mode */
4053 	bus->pktgen_mode = DHD_PKTGEN_ECHO;
4054 	bus->pktgen_stop = 1;
4055 }
4056 
4057 static void
dhdsdio_pktgen(dhd_bus_t * bus)4058 dhdsdio_pktgen(dhd_bus_t *bus)
4059 {
4060 	void *pkt;
4061 	uint8 *data;
4062 	uint pktcount;
4063 	uint fillbyte;
4064 	osl_t *osh = bus->dhd->osh;
4065 	uint16 len;
4066 
4067 	/* Display current count if appropriate */
4068 	if (bus->pktgen_print && (++bus->pktgen_ptick >= bus->pktgen_print)) {
4069 		bus->pktgen_ptick = 0;
4070 		printf("%s: send attempts %d rcvd %d\n",
4071 		       __FUNCTION__, bus->pktgen_sent, bus->pktgen_rcvd);
4072 	}
4073 
4074 	/* For recv mode, just make sure dongle has started sending */
4075 	if (bus->pktgen_mode == DHD_PKTGEN_RECV) {
4076 		if (!bus->pktgen_rcvd)
4077 			dhdsdio_sdtest_set(bus, TRUE);
4078 		return;
4079 	}
4080 
4081 	/* Otherwise, generate or request the specified number of packets */
4082 	for (pktcount = 0; pktcount < bus->pktgen_count; pktcount++) {
4083 		/* Stop if total has been reached */
4084 		if (bus->pktgen_total && (bus->pktgen_sent >= bus->pktgen_total)) {
4085 			bus->pktgen_count = 0;
4086 			break;
4087 		}
4088 
4089 		/* Allocate an appropriate-sized packet */
4090 		len = bus->pktgen_len;
4091 		if (!(pkt = PKTGET(osh, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN),
4092 		                   TRUE))) {;
4093 			DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__));
4094 			break;
4095 		}
4096 		PKTALIGN(osh, pkt, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN), DHD_SDALIGN);
4097 		data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
4098 
4099 		/* Write test header cmd and extra based on mode */
4100 		switch (bus->pktgen_mode) {
4101 		case DHD_PKTGEN_ECHO:
4102 			*data++ = SDPCM_TEST_ECHOREQ;
4103 			*data++ = (uint8)bus->pktgen_sent;
4104 			break;
4105 
4106 		case DHD_PKTGEN_SEND:
4107 			*data++ = SDPCM_TEST_DISCARD;
4108 			*data++ = (uint8)bus->pktgen_sent;
4109 			break;
4110 
4111 		case DHD_PKTGEN_RXBURST:
4112 			*data++ = SDPCM_TEST_BURST;
4113 			*data++ = (uint8)bus->pktgen_count;
4114 			break;
4115 
4116 		default:
4117 			DHD_ERROR(("Unrecognized pktgen mode %d\n", bus->pktgen_mode));
4118 			PKTFREE(osh, pkt, TRUE);
4119 			bus->pktgen_count = 0;
4120 			return;
4121 		}
4122 
4123 		/* Write test header length field */
4124 		*data++ = (len >> 0);
4125 		*data++ = (len >> 8);
4126 
4127 		/* Then fill in the remainder -- N/A for burst, but who cares... */
4128 		for (fillbyte = 0; fillbyte < len; fillbyte++)
4129 			*data++ = SDPCM_TEST_FILL(fillbyte, (uint8)bus->pktgen_sent);
4130 
4131 #ifdef DHD_DEBUG
4132 		if (DHD_BYTES_ON() && DHD_DATA_ON()) {
4133 			data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
4134 			prhex("dhdsdio_pktgen: Tx Data", data, PKTLEN(osh, pkt) - SDPCM_HDRLEN);
4135 		}
4136 #endif
4137 
4138 		/* Send it */
4139 		if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE)) {
4140 			bus->pktgen_fail++;
4141 			if (bus->pktgen_stop && bus->pktgen_stop == bus->pktgen_fail)
4142 				bus->pktgen_count = 0;
4143 		}
4144 		bus->pktgen_sent++;
4145 
4146 		/* Bump length if not fixed, wrap at max */
4147 		if (++bus->pktgen_len > bus->pktgen_maxlen)
4148 			bus->pktgen_len = (uint16)bus->pktgen_minlen;
4149 
4150 		/* Special case for burst mode: just send one request! */
4151 		if (bus->pktgen_mode == DHD_PKTGEN_RXBURST)
4152 			break;
4153 	}
4154 }
4155 
4156 static void
dhdsdio_sdtest_set(dhd_bus_t * bus,bool start)4157 dhdsdio_sdtest_set(dhd_bus_t *bus, bool start)
4158 {
4159 	void *pkt;
4160 	uint8 *data;
4161 	osl_t *osh = bus->dhd->osh;
4162 
4163 	/* Allocate the packet */
4164 	if (!(pkt = PKTGET(osh, SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN, TRUE))) {
4165 		DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__));
4166 		return;
4167 	}
4168 	PKTALIGN(osh, pkt, (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN), DHD_SDALIGN);
4169 	data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
4170 
4171 	/* Fill in the test header */
4172 	*data++ = SDPCM_TEST_SEND;
4173 	*data++ = start;
4174 	*data++ = (bus->pktgen_maxlen >> 0);
4175 	*data++ = (bus->pktgen_maxlen >> 8);
4176 
4177 	/* Send it */
4178 	if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE))
4179 		bus->pktgen_fail++;
4180 }
4181 
4182 
4183 static void
dhdsdio_testrcv(dhd_bus_t * bus,void * pkt,uint seq)4184 dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq)
4185 {
4186 	osl_t *osh = bus->dhd->osh;
4187 	uint8 *data;
4188 	uint pktlen;
4189 
4190 	uint8 cmd;
4191 	uint8 extra;
4192 	uint16 len;
4193 	uint16 offset;
4194 
4195 	/* Check for min length */
4196 	if ((pktlen = PKTLEN(osh, pkt)) < SDPCM_TEST_HDRLEN) {
4197 		DHD_ERROR(("dhdsdio_restrcv: toss runt frame, pktlen %d\n", pktlen));
4198 		PKTFREE(osh, pkt, FALSE);
4199 		return;
4200 	}
4201 
4202 	/* Extract header fields */
4203 	data = PKTDATA(osh, pkt);
4204 	cmd = *data++;
4205 	extra = *data++;
4206 	len = *data++; len += *data++ << 8;
4207 
4208 	/* Check length for relevant commands */
4209 	if (cmd == SDPCM_TEST_DISCARD || cmd == SDPCM_TEST_ECHOREQ || cmd == SDPCM_TEST_ECHORSP) {
4210 		if (pktlen != len + SDPCM_TEST_HDRLEN) {
4211 			DHD_ERROR(("dhdsdio_testrcv: frame length mismatch, pktlen %d seq %d"
4212 			           " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len));
4213 			PKTFREE(osh, pkt, FALSE);
4214 			return;
4215 		}
4216 	}
4217 
4218 	/* Process as per command */
4219 	switch (cmd) {
4220 	case SDPCM_TEST_ECHOREQ:
4221 		/* Rx->Tx turnaround ok (even on NDIS w/current implementation) */
4222 		*(uint8 *)(PKTDATA(osh, pkt)) = SDPCM_TEST_ECHORSP;
4223 		if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE) == 0) {
4224 			bus->pktgen_sent++;
4225 		} else {
4226 			bus->pktgen_fail++;
4227 			PKTFREE(osh, pkt, FALSE);
4228 		}
4229 		bus->pktgen_rcvd++;
4230 		break;
4231 
4232 	case SDPCM_TEST_ECHORSP:
4233 		if (bus->ext_loop) {
4234 			PKTFREE(osh, pkt, FALSE);
4235 			bus->pktgen_rcvd++;
4236 			break;
4237 		}
4238 
4239 		for (offset = 0; offset < len; offset++, data++) {
4240 			if (*data != SDPCM_TEST_FILL(offset, extra)) {
4241 				DHD_ERROR(("dhdsdio_testrcv: echo data mismatch: "
4242 				           "offset %d (len %d) expect 0x%02x rcvd 0x%02x\n",
4243 				           offset, len, SDPCM_TEST_FILL(offset, extra), *data));
4244 				break;
4245 			}
4246 		}
4247 		PKTFREE(osh, pkt, FALSE);
4248 		bus->pktgen_rcvd++;
4249 		break;
4250 
4251 	case SDPCM_TEST_DISCARD:
4252 		PKTFREE(osh, pkt, FALSE);
4253 		bus->pktgen_rcvd++;
4254 		break;
4255 
4256 	case SDPCM_TEST_BURST:
4257 	case SDPCM_TEST_SEND:
4258 	default:
4259 		DHD_INFO(("dhdsdio_testrcv: unsupported or unknown command, pktlen %d seq %d"
4260 		          " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len));
4261 		PKTFREE(osh, pkt, FALSE);
4262 		break;
4263 	}
4264 
4265 	/* For recv mode, stop at limie (and tell dongle to stop sending) */
4266 	if (bus->pktgen_mode == DHD_PKTGEN_RECV) {
4267 		if (bus->pktgen_total && (bus->pktgen_rcvd >= bus->pktgen_total)) {
4268 			bus->pktgen_count = 0;
4269 			dhdsdio_sdtest_set(bus, FALSE);
4270 		}
4271 	}
4272 }
4273 #endif /* SDTEST */
4274 
4275 extern bool
dhd_bus_watchdog(dhd_pub_t * dhdp)4276 dhd_bus_watchdog(dhd_pub_t *dhdp)
4277 {
4278 	dhd_bus_t *bus;
4279 
4280 	DHD_TIMER(("%s: Enter\n", __FUNCTION__));
4281 
4282 	bus = dhdp->bus;
4283 
4284 	if (bus->dhd->dongle_reset)
4285 		return FALSE;
4286 
4287 	/* Ignore the timer if simulating bus down */
4288 	if (bus->sleeping)
4289 		return FALSE;
4290 
4291 	dhd_os_sdlock(bus->dhd);
4292 
4293 	/* Poll period: check device if appropriate. */
4294 	if (bus->poll && (++bus->polltick >= bus->pollrate)) {
4295 		uint32 intstatus = 0;
4296 
4297 		/* Reset poll tick */
4298 		bus->polltick = 0;
4299 
4300 		/* Check device if no interrupts */
4301 		if (!bus->intr || (bus->intrcount == bus->lastintrs)) {
4302 
4303 			if (!bus->dpc_sched) {
4304 				uint8 devpend;
4305 				devpend = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0,
4306 				                          SDIOD_CCCR_INTPEND, NULL);
4307 				intstatus = devpend & (INTR_STATUS_FUNC1 | INTR_STATUS_FUNC2);
4308 			}
4309 
4310 			/* If there is something, make like the ISR and schedule the DPC */
4311 			if (intstatus) {
4312 				bus->pollcnt++;
4313 				bus->ipend = TRUE;
4314 				if (bus->intr) {
4315 					bcmsdh_intr_disable(bus->sdh);
4316 				}
4317 				bus->dpc_sched = TRUE;
4318 				dhd_sched_dpc(bus->dhd);
4319 
4320 			}
4321 		}
4322 
4323 		/* Update interrupt tracking */
4324 		bus->lastintrs = bus->intrcount;
4325 	}
4326 
4327 
4328 #ifdef SDTEST
4329 	/* Generate packets if configured */
4330 	if (bus->pktgen_count && (++bus->pktgen_tick >= bus->pktgen_freq)) {
4331 		/* Make sure backplane clock is on */
4332 		dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
4333 		bus->pktgen_tick = 0;
4334 		dhdsdio_pktgen(bus);
4335 	}
4336 #endif
4337 
4338 	/* On idle timeout clear activity flag and/or turn off clock */
4339 	if ((bus->idletime > 0) && (bus->clkstate == CLK_AVAIL)) {
4340 		if (++bus->idlecount >= bus->idletime) {
4341 			bus->idlecount = 0;
4342 			if (bus->activity) {
4343 				bus->activity = FALSE;
4344 			} else {
4345 				dhdsdio_clkctl(bus, CLK_NONE, FALSE);
4346 			}
4347 		}
4348 	}
4349 
4350 	dhd_os_sdunlock(bus->dhd);
4351 
4352 	return bus->ipend;
4353 }
4354 
4355 
4356 #ifdef DHD_DEBUG
4357 static void
dhd_dump_cis(uint fn,uint8 * cis)4358 dhd_dump_cis(uint fn, uint8 *cis)
4359 {
4360 	uint byte, tag, tdata;
4361 	DHD_INFO(("Function %d CIS:\n", fn));
4362 
4363 	for (tdata = byte = 0; byte < SBSDIO_CIS_SIZE_LIMIT; byte++) {
4364 		if ((byte % 16) == 0)
4365 			DHD_INFO(("    "));
4366 		DHD_INFO(("%02x ", cis[byte]));
4367 		if ((byte % 16) == 15)
4368 			DHD_INFO(("\n"));
4369 		if (!tdata--) {
4370 			tag = cis[byte];
4371 			if (tag == 0xff)
4372 				break;
4373 			else if (!tag)
4374 				tdata = 0;
4375 			else if ((byte + 1) < SBSDIO_CIS_SIZE_LIMIT)
4376 				tdata = cis[byte + 1] + 1;
4377 			else
4378 				DHD_INFO(("]"));
4379 		}
4380 	}
4381 	if ((byte % 16) != 15)
4382 		DHD_INFO(("\n"));
4383 }
4384 #endif /* DHD_DEBUG */
4385 
4386 static bool
dhdsdio_chipmatch(uint16 chipid)4387 dhdsdio_chipmatch(uint16 chipid)
4388 {
4389 	if (chipid == BCM4325_CHIP_ID)
4390 		return TRUE;
4391 	if (chipid == BCM4329_CHIP_ID)
4392 		return TRUE;
4393 	if (chipid == BCM4315_CHIP_ID)
4394 		return TRUE;
4395 	if (chipid == BCM4319_CHIP_ID)
4396 		return TRUE;
4397 	return FALSE;
4398 }
4399 
4400 static void *
dhdsdio_probe(uint16 venid,uint16 devid,uint16 bus_no,uint16 slot,uint16 func,uint bustype,void * regsva,osl_t * osh,void * sdh)4401 dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot,
4402 	uint16 func, uint bustype, void *regsva, osl_t * osh, void *sdh)
4403 {
4404 	int ret;
4405 	dhd_bus_t *bus;
4406 
4407 	/* Init global variables at run-time, not as part of the declaration.
4408 	 * This is required to support init/de-init of the driver. Initialization
4409 	 * of globals as part of the declaration results in non-deterministic
4410 	 * behavior since the value of the globals may be different on the
4411 	 * first time that the driver is initialized vs subsequent initializations.
4412 	 */
4413 	dhd_txbound = DHD_TXBOUND;
4414 	dhd_rxbound = DHD_RXBOUND;
4415 	dhd_alignctl = TRUE;
4416 	sd1idle = TRUE;
4417 	dhd_readahead = TRUE;
4418 	retrydata = FALSE;
4419 	dhd_doflow = FALSE;
4420 	dhd_dongle_memsize = 0;
4421 	dhd_txminmax = DHD_TXMINMAX;
4422 
4423 	forcealign = TRUE;
4424 
4425 
4426 	dhd_common_init();
4427 
4428 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4429 	DHD_INFO(("%s: venid 0x%04x devid 0x%04x\n", __FUNCTION__, venid, devid));
4430 
4431 	/* We make assumptions about address window mappings */
4432 	ASSERT((uintptr)regsva == SI_ENUM_BASE);
4433 
4434 	/* BCMSDH passes venid and devid based on CIS parsing -- but low-power start
4435 	 * means early parse could fail, so here we should get either an ID
4436 	 * we recognize OR (-1) indicating we must request power first.
4437 	 */
4438 	/* Check the Vendor ID */
4439 	switch (venid) {
4440 		case 0x0000:
4441 		case VENDOR_BROADCOM:
4442 			break;
4443 		default:
4444 			DHD_ERROR(("%s: unknown vendor: 0x%04x\n",
4445 			           __FUNCTION__, venid));
4446 			return NULL;
4447 	}
4448 
4449 	/* Check the Device ID and make sure it's one that we support */
4450 	switch (devid) {
4451 		case BCM4325_D11DUAL_ID:		/* 4325 802.11a/g id */
4452 		case BCM4325_D11G_ID:			/* 4325 802.11g 2.4Ghz band id */
4453 		case BCM4325_D11A_ID:			/* 4325 802.11a 5Ghz band id */
4454 			DHD_INFO(("%s: found 4325 Dongle\n", __FUNCTION__));
4455 			break;
4456 		case BCM4329_D11NDUAL_ID:		/* 4329 802.11n dualband device */
4457 		case BCM4329_D11N2G_ID:		/* 4329 802.11n 2.4G device */
4458 		case BCM4329_D11N5G_ID:		/* 4329 802.11n 5G device */
4459 		case 0x4329:
4460 			DHD_INFO(("%s: found 4329 Dongle\n", __FUNCTION__));
4461 			break;
4462 		case BCM4315_D11DUAL_ID:		/* 4315 802.11a/g id */
4463 		case BCM4315_D11G_ID:			/* 4315 802.11g id */
4464 		case BCM4315_D11A_ID:			/* 4315 802.11a id */
4465 			DHD_INFO(("%s: found 4315 Dongle\n", __FUNCTION__));
4466 			break;
4467 		case BCM4319_D11N_ID:			/* 4319 802.11n id */
4468 		case BCM4319_D11N2G_ID:			/* 4319 802.11n2g id */
4469 		case BCM4319_D11N5G_ID:			/* 4319 802.11n5g id */
4470 			DHD_INFO(("%s: found 4319 Dongle\n", __FUNCTION__));
4471 			break;
4472 		case 0:
4473 			DHD_INFO(("%s: allow device id 0, will check chip internals\n",
4474 			          __FUNCTION__));
4475 			break;
4476 
4477 		default:
4478 			DHD_ERROR(("%s: skipping 0x%04x/0x%04x, not a dongle\n",
4479 			           __FUNCTION__, venid, devid));
4480 			return NULL;
4481 	}
4482 
4483 	if (osh == NULL) {
4484 		/* Ask the OS interface part for an OSL handle */
4485 		if (!(osh = dhd_osl_attach(sdh, DHD_BUS))) {
4486 			DHD_ERROR(("%s: osl_attach failed!\n", __FUNCTION__));
4487 			return NULL;
4488 		}
4489 	}
4490 
4491 	/* Allocate private bus interface state */
4492 	if (!(bus = MALLOC(osh, sizeof(dhd_bus_t)))) {
4493 		DHD_ERROR(("%s: MALLOC of dhd_bus_t failed\n", __FUNCTION__));
4494 		goto fail;
4495 	}
4496 	bzero(bus, sizeof(dhd_bus_t));
4497 	bus->sdh = sdh;
4498 	bus->cl_devid = (uint16)devid;
4499 	bus->bus = DHD_BUS;
4500 	bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1;
4501 	bus->usebufpool = FALSE; /* Use bufpool if allocated, else use locally malloced rxbuf */
4502 
4503 	/* attempt to attach to the dongle */
4504 	if (!(dhdsdio_probe_attach(bus, osh, sdh, regsva, devid))) {
4505 		DHD_ERROR(("%s: dhdsdio_probe_attach failed\n", __FUNCTION__));
4506 		goto fail;
4507 	}
4508 
4509 	/* Attach to the dhd/OS/network interface */
4510 	if (!(bus->dhd = dhd_attach(osh, bus, SDPCM_RESERVE))) {
4511 		DHD_ERROR(("%s: dhd_attach failed\n", __FUNCTION__));
4512 		goto fail;
4513 	}
4514 
4515 	/* Allocate buffers */
4516 	if (!(dhdsdio_probe_malloc(bus, osh, sdh))) {
4517 		DHD_ERROR(("%s: dhdsdio_probe_malloc failed\n", __FUNCTION__));
4518 		goto fail;
4519 	}
4520 
4521 	if (!(dhdsdio_probe_init(bus, osh, sdh))) {
4522 		DHD_ERROR(("%s: dhdsdio_probe_init failed\n", __FUNCTION__));
4523 		goto fail;
4524 	}
4525 
4526 	/* Register interrupt callback, but mask it (not operational yet). */
4527 	DHD_INTR(("%s: disable SDIO interrupts (not interested yet)\n", __FUNCTION__));
4528 	bcmsdh_intr_disable(sdh);
4529 	if ((ret = bcmsdh_intr_reg(sdh, dhdsdio_isr, bus)) != 0) {
4530 		DHD_ERROR(("%s: FAILED: bcmsdh_intr_reg returned %d\n",
4531 		           __FUNCTION__, ret));
4532 		goto fail;
4533 	}
4534 	DHD_INTR(("%s: registered SDIO interrupt function ok\n", __FUNCTION__));
4535 
4536 	DHD_INFO(("%s: completed!!\n", __FUNCTION__));
4537 
4538 
4539 	/* if firmware path present try to download and bring up bus */
4540 	if ((ret = dhd_bus_start(bus->dhd)) == -1) {
4541 		DHD_TRACE(("%s: warning : check if firmware was provided\n", __FUNCTION__));
4542 	}
4543 	else if (ret == BCME_NOTUP)  {
4544 		DHD_ERROR(("%s: dongle is not responding\n", __FUNCTION__));
4545 		goto fail;
4546 	}
4547 	/* Ok, have the per-port tell the stack we're open for business */
4548 	if (dhd_net_attach(bus->dhd, 0) != 0) {
4549 		DHD_ERROR(("%s: Net attach failed!!\n", __FUNCTION__));
4550 		goto fail;
4551 	}
4552 
4553 	return bus;
4554 
4555 fail:
4556 	dhdsdio_release(bus, osh);
4557 	return NULL;
4558 }
4559 
4560 
4561 static bool
dhdsdio_probe_attach(struct dhd_bus * bus,osl_t * osh,void * sdh,void * regsva,uint16 devid)4562 dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva,
4563                     uint16 devid)
4564 {
4565 	uint8 clkctl = 0;
4566 	int err = 0;
4567 
4568 	bus->alp_only = TRUE;
4569 
4570 	/* Return the window to backplane enumeration space for core access */
4571 	if (dhdsdio_set_siaddr_window(bus, SI_ENUM_BASE)) {
4572 		DHD_ERROR(("%s: FAILED to return to SI_ENUM_BASE\n", __FUNCTION__));
4573 	}
4574 
4575 #ifdef DHD_DEBUG
4576 	printf("F1 signature read @0x18000000=0x%4x\n",
4577 	       bcmsdh_reg_read(bus->sdh, SI_ENUM_BASE, 4));
4578 
4579 
4580 #endif /* DHD_DEBUG */
4581 
4582 
4583 	/* Force PLL off until si_attach() programs PLL control regs */
4584 
4585 
4586 
4587 	bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, DHD_INIT_CLKCTL1, &err);
4588 	if (!err)
4589 		clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
4590 
4591 	if (err || ((clkctl & ~SBSDIO_AVBITS) != DHD_INIT_CLKCTL1)) {
4592 		DHD_ERROR(("dhdsdio_probe: ChipClkCSR access: err %d wrote 0x%02x read 0x%02x\n",
4593 		           err, DHD_INIT_CLKCTL1, clkctl));
4594 		goto fail;
4595 	}
4596 
4597 
4598 #ifdef DHD_DEBUG
4599 	if (DHD_INFO_ON()) {
4600 		uint fn, numfn;
4601 		uint8 *cis[SDIOD_MAX_IOFUNCS];
4602 		int err = 0;
4603 
4604 		numfn = bcmsdh_query_iofnum(sdh);
4605 		ASSERT(numfn <= SDIOD_MAX_IOFUNCS);
4606 
4607 		/* Make sure ALP is available before trying to read CIS */
4608 		SPINWAIT(((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
4609 		                                    SBSDIO_FUNC1_CHIPCLKCSR, NULL)),
4610 		          !SBSDIO_ALPAV(clkctl)), PMU_MAX_TRANSITION_DLY);
4611 
4612 		/* Now request ALP be put on the bus */
4613 		bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
4614 		                 DHD_INIT_CLKCTL2, &err);
4615 		OSL_DELAY(65);
4616 
4617 		for (fn = 0; fn <= numfn; fn++) {
4618 			if (!(cis[fn] = MALLOC(osh, SBSDIO_CIS_SIZE_LIMIT))) {
4619 				DHD_INFO(("dhdsdio_probe: fn %d cis malloc failed\n", fn));
4620 				break;
4621 			}
4622 			bzero(cis[fn], SBSDIO_CIS_SIZE_LIMIT);
4623 
4624 			if ((err = bcmsdh_cis_read(sdh, fn, cis[fn], SBSDIO_CIS_SIZE_LIMIT))) {
4625 				DHD_INFO(("dhdsdio_probe: fn %d cis read err %d\n", fn, err));
4626 				MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT);
4627 				break;
4628 			}
4629 			dhd_dump_cis(fn, cis[fn]);
4630 		}
4631 
4632 		while (fn-- > 0) {
4633 			ASSERT(cis[fn]);
4634 			MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT);
4635 		}
4636 
4637 		if (err) {
4638 			DHD_ERROR(("dhdsdio_probe: failure reading or parsing CIS\n"));
4639 			goto fail;
4640 		}
4641 	}
4642 #endif /* DHD_DEBUG */
4643 
4644 	/* si_attach() will provide an SI handle and scan the backplane */
4645 	if (!(bus->sih = si_attach((uint)devid, osh, regsva, DHD_BUS, sdh,
4646 	                           &bus->vars, &bus->varsz))) {
4647 		DHD_ERROR(("%s: si_attach failed!\n", __FUNCTION__));
4648 		goto fail;
4649 	}
4650 
4651 	bcmsdh_chipinfo(sdh, bus->sih->chip, bus->sih->chiprev);
4652 
4653 	if (!dhdsdio_chipmatch((uint16)bus->sih->chip)) {
4654 		DHD_ERROR(("%s: unsupported chip: 0x%04x\n",
4655 		           __FUNCTION__, bus->sih->chip));
4656 		goto fail;
4657 	}
4658 
4659 	si_sdiod_drive_strength_init(bus->sih, osh, dhd_sdiod_drive_strength);
4660 
4661 
4662 	/* Get info on the ARM and SOCRAM cores... */
4663 	if (!DHD_NOPMU(bus)) {
4664 		if ((si_setcore(bus->sih, ARM7S_CORE_ID, 0)) ||
4665 		    (si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) {
4666 			bus->armrev = si_corerev(bus->sih);
4667 		} else {
4668 			DHD_ERROR(("%s: failed to find ARM core!\n", __FUNCTION__));
4669 			goto fail;
4670 		}
4671 		if (!(bus->orig_ramsize = si_socram_size(bus->sih))) {
4672 			DHD_ERROR(("%s: failed to find SOCRAM memory!\n", __FUNCTION__));
4673 			goto fail;
4674 		}
4675 		bus->ramsize = bus->orig_ramsize;
4676 		if (dhd_dongle_memsize)
4677 			dhd_dongle_setmemsize(bus, dhd_dongle_memsize);
4678 
4679 		DHD_ERROR(("DHD: dongle ram size is set to %d(orig %d)\n",
4680 			bus->ramsize, bus->orig_ramsize));
4681 	}
4682 
4683 	/* ...but normally deal with the SDPCMDEV core */
4684 	if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0)) &&
4685 	    !(bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0))) {
4686 		DHD_ERROR(("%s: failed to find SDIODEV core!\n", __FUNCTION__));
4687 		goto fail;
4688 	}
4689 	bus->sdpcmrev = si_corerev(bus->sih);
4690 
4691 	/* Set core control so an SDIO reset does a backplane reset */
4692 	OR_REG(osh, &bus->regs->corecontrol, CC_BPRESEN);
4693 
4694 	pktq_init(&bus->txq, (PRIOMASK + 1), QLEN);
4695 
4696 	/* Locate an appropriately-aligned portion of hdrbuf */
4697 	bus->rxhdr = (uint8 *)ROUNDUP((uintptr)&bus->hdrbuf[0], DHD_SDALIGN);
4698 
4699 	/* Set the poll and/or interrupt flags */
4700 	bus->intr = (bool)dhd_intr;
4701 	if ((bus->poll = (bool)dhd_poll))
4702 		bus->pollrate = 1;
4703 
4704 	return TRUE;
4705 
4706 fail:
4707 	return FALSE;
4708 }
4709 
4710 static bool
dhdsdio_probe_malloc(dhd_bus_t * bus,osl_t * osh,void * sdh)4711 dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh)
4712 {
4713 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4714 
4715 #ifndef DHD_USE_STATIC_BUF
4716 	if (bus->dhd->maxctl) {
4717 		bus->rxblen = ROUNDUP((bus->dhd->maxctl + SDPCM_HDRLEN), ALIGNMENT) + DHD_SDALIGN;
4718 		if (!(bus->rxbuf = MALLOC(osh, bus->rxblen))) {
4719 			DHD_ERROR(("%s: MALLOC of %d-byte rxbuf failed\n",
4720 			           __FUNCTION__, bus->rxblen));
4721 			goto fail;
4722 		}
4723 	}
4724 
4725 	/* Allocate buffer to receive glomed packet */
4726 	if (!(bus->databuf = MALLOC(osh, MAX_DATA_BUF))) {
4727 		DHD_ERROR(("%s: MALLOC of %d-byte databuf failed\n",
4728 			__FUNCTION__, MAX_DATA_BUF));
4729 		/* release rxbuf which was already located as above */
4730 		if (!bus->rxblen) MFREE(osh, bus->rxbuf, bus->rxblen);
4731 		goto fail;
4732 	}
4733 #else
4734 	if (bus->dhd->maxctl) {
4735 		bus->rxblen = ROUNDUP((bus->dhd->maxctl + SDPCM_HDRLEN), ALIGNMENT) + DHD_SDALIGN;
4736 		if (!(bus->rxbuf = dhd_os_prealloc(DHD_PREALLOC_RXBUF, bus->rxblen))) {
4737 			DHD_ERROR(("%s: MALLOC of %d-byte rxbuf failed\n",
4738 			           __FUNCTION__, bus->rxblen));
4739 			goto fail;
4740 		}
4741 	}
4742 	/* Allocate buffer to receive glomed packet */
4743 	if (!(bus->databuf = dhd_os_prealloc(DHD_PREALLOC_DATABUF, MAX_DATA_BUF))) {
4744 		DHD_ERROR(("%s: MALLOC of %d-byte databuf failed\n",
4745 			__FUNCTION__, MAX_DATA_BUF));
4746 		goto fail;
4747 	}
4748 #endif /* DHD_USE_STATIC_BUF */
4749 
4750 	/* Align the buffer */
4751 	if ((uintptr)bus->databuf % DHD_SDALIGN)
4752 		bus->dataptr = bus->databuf + (DHD_SDALIGN - ((uintptr)bus->databuf % DHD_SDALIGN));
4753 	else
4754 		bus->dataptr = bus->databuf;
4755 
4756 	return TRUE;
4757 
4758 fail:
4759 	return FALSE;
4760 }
4761 
4762 
4763 static bool
dhdsdio_probe_init(dhd_bus_t * bus,osl_t * osh,void * sdh)4764 dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh)
4765 {
4766 	int32 fnum;
4767 
4768 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4769 
4770 #ifdef SDTEST
4771 	dhdsdio_pktgen_init(bus);
4772 #endif /* SDTEST */
4773 
4774 	/* Disable F2 to clear any intermediate frame state on the dongle */
4775 	bcmsdh_cfg_write(sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL);
4776 
4777 	bus->dhd->busstate = DHD_BUS_DOWN;
4778 	bus->sleeping = FALSE;
4779 	bus->rxflow = FALSE;
4780 	bus->prev_rxlim_hit = 0;
4781 
4782 
4783 	/* Done with backplane-dependent accesses, can drop clock... */
4784 	bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
4785 
4786 	/* ...and initialize clock/power states */
4787 	bus->clkstate = CLK_SDONLY;
4788 	bus->idletime = (int32)dhd_idletime;
4789 	bus->idleclock = DHD_IDLE_ACTIVE;
4790 
4791 	/* Query the SD clock speed */
4792 	if (bcmsdh_iovar_op(sdh, "sd_divisor", NULL, 0,
4793 	                    &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) {
4794 		DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_divisor"));
4795 		bus->sd_divisor = -1;
4796 	} else {
4797 		DHD_INFO(("%s: Initial value for %s is %d\n",
4798 		          __FUNCTION__, "sd_divisor", bus->sd_divisor));
4799 	}
4800 
4801 	/* Query the SD bus mode */
4802 	if (bcmsdh_iovar_op(sdh, "sd_mode", NULL, 0,
4803 	                    &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) {
4804 		DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_mode"));
4805 		bus->sd_mode = -1;
4806 	} else {
4807 		DHD_INFO(("%s: Initial value for %s is %d\n",
4808 		          __FUNCTION__, "sd_mode", bus->sd_mode));
4809 	}
4810 
4811 	/* Query the F2 block size, set roundup accordingly */
4812 	fnum = 2;
4813 	if (bcmsdh_iovar_op(sdh, "sd_blocksize", &fnum, sizeof(int32),
4814 	                    &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) {
4815 		bus->blocksize = 0;
4816 		DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize"));
4817 	} else {
4818 		DHD_INFO(("%s: Initial value for %s is %d\n",
4819 		          __FUNCTION__, "sd_blocksize", bus->blocksize));
4820 	}
4821 	bus->roundup = MIN(max_roundup, bus->blocksize);
4822 
4823 	/* Query if bus module supports packet chaining, default to use if supported */
4824 	if (bcmsdh_iovar_op(sdh, "sd_rxchain", NULL, 0,
4825 	                    &bus->sd_rxchain, sizeof(int32), FALSE) != BCME_OK) {
4826 		bus->sd_rxchain = FALSE;
4827 	} else {
4828 		DHD_INFO(("%s: bus module (through bcmsdh API) %s chaining\n",
4829 		          __FUNCTION__, (bus->sd_rxchain ? "supports" : "does not support")));
4830 	}
4831 	bus->use_rxchain = (bool)bus->sd_rxchain;
4832 
4833 	return TRUE;
4834 }
4835 
4836 bool
dhd_bus_download_firmware(struct dhd_bus * bus,osl_t * osh,char * fw_path,char * nv_path)4837 dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh,
4838                           char *fw_path, char *nv_path)
4839 {
4840 	bool ret;
4841 	bus->fw_path = fw_path;
4842 	bus->nv_path = nv_path;
4843 
4844 	ret = dhdsdio_download_firmware(bus, osh, bus->sdh);
4845 
4846 	return ret;
4847 }
4848 
4849 static bool
dhdsdio_download_firmware(struct dhd_bus * bus,osl_t * osh,void * sdh)4850 dhdsdio_download_firmware(struct dhd_bus *bus, osl_t *osh, void *sdh)
4851 {
4852 	bool ret;
4853 
4854 	/* Download the firmware */
4855 	dhd_os_wake_lock(bus->dhd);
4856 	dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
4857 
4858 	ret = _dhdsdio_download_firmware(bus) == 0;
4859 
4860 	dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
4861 	dhd_os_wake_unlock(bus->dhd);
4862 	return ret;
4863 }
4864 
4865 /* Detach and free everything */
4866 static void
dhdsdio_release(dhd_bus_t * bus,osl_t * osh)4867 dhdsdio_release(dhd_bus_t *bus, osl_t *osh)
4868 {
4869 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4870 
4871 	if (bus) {
4872 		ASSERT(osh);
4873 
4874 
4875 		if (bus->dhd) {
4876 
4877 			dhdsdio_release_dongle(bus, osh);
4878 
4879 			dhd_detach(bus->dhd);
4880 			bus->dhd = NULL;
4881 		}
4882 
4883 		dhdsdio_release_malloc(bus, osh);
4884 
4885 		/* De-register interrupt handler */
4886 		bcmsdh_intr_dereg(bus->sdh);
4887 
4888 
4889 		MFREE(osh, bus, sizeof(dhd_bus_t));
4890 	}
4891 
4892 	if (osh)
4893 		dhd_osl_detach(osh);
4894 
4895 	DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
4896 }
4897 
4898 static void
dhdsdio_release_malloc(dhd_bus_t * bus,osl_t * osh)4899 dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh)
4900 {
4901 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4902 
4903 	if (bus->dhd && bus->dhd->dongle_reset)
4904 		return;
4905 
4906 	if (bus->rxbuf) {
4907 #ifndef DHD_USE_STATIC_BUF
4908 		MFREE(osh, bus->rxbuf, bus->rxblen);
4909 #endif
4910 		bus->rxctl = bus->rxbuf = NULL;
4911 		bus->rxlen = 0;
4912 	}
4913 
4914 	if (bus->databuf) {
4915 #ifndef DHD_USE_STATIC_BUF
4916 		MFREE(osh, bus->databuf, MAX_DATA_BUF);
4917 #endif
4918 		bus->databuf = NULL;
4919 	}
4920 }
4921 
4922 
4923 static void
dhdsdio_release_dongle(dhd_bus_t * bus,osl_t * osh)4924 dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh)
4925 {
4926 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4927 
4928 	if (bus->dhd && bus->dhd->dongle_reset)
4929 		return;
4930 
4931 	if (bus->sih) {
4932 		dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
4933 #if !defined(BCMLXSDMMC)
4934 		si_watchdog(bus->sih, 4);
4935 #endif /* !defined(BCMLXSDMMC) */
4936 		dhdsdio_clkctl(bus, CLK_NONE, FALSE);
4937 		si_detach(bus->sih);
4938 		if (bus->vars && bus->varsz)
4939 			MFREE(osh, bus->vars, bus->varsz);
4940 		bus->vars = NULL;
4941 	}
4942 
4943 	DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
4944 }
4945 
4946 static void
dhdsdio_disconnect(void * ptr)4947 dhdsdio_disconnect(void *ptr)
4948 {
4949 	dhd_bus_t *bus = (dhd_bus_t *)ptr;
4950 
4951 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4952 
4953 	if (bus) {
4954 		ASSERT(bus->dhd);
4955 		dhdsdio_release(bus, bus->dhd->osh);
4956 	}
4957 
4958 	DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
4959 }
4960 
4961 
4962 /* Register/Unregister functions are called by the main DHD entry
4963  * point (e.g. module insertion) to link with the bus driver, in
4964  * order to look for or await the device.
4965  */
4966 
4967 static bcmsdh_driver_t dhd_sdio = {
4968 	dhdsdio_probe,
4969 	dhdsdio_disconnect
4970 };
4971 
4972 int
dhd_bus_register(void)4973 dhd_bus_register(void)
4974 {
4975 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4976 
4977 	return bcmsdh_register(&dhd_sdio);
4978 }
4979 
4980 void
dhd_bus_unregister(void)4981 dhd_bus_unregister(void)
4982 {
4983 	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4984 
4985 	bcmsdh_unregister();
4986 }
4987 
4988 #ifdef BCMEMBEDIMAGE
4989 static int
dhdsdio_download_code_array(struct dhd_bus * bus)4990 dhdsdio_download_code_array(struct dhd_bus *bus)
4991 {
4992 	int bcmerror = -1;
4993 	int offset = 0;
4994 
4995 	DHD_INFO(("%s: download embedded firmware...\n", __FUNCTION__));
4996 
4997 	/* Download image */
4998 	while ((offset + MEMBLOCK) < sizeof(dlarray)) {
4999 		bcmerror = dhdsdio_membytes(bus, TRUE, offset, dlarray + offset, MEMBLOCK);
5000 		if (bcmerror) {
5001 			DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
5002 			        __FUNCTION__, bcmerror, MEMBLOCK, offset));
5003 			goto err;
5004 		}
5005 
5006 		offset += MEMBLOCK;
5007 	}
5008 
5009 	if (offset < sizeof(dlarray)) {
5010 		bcmerror = dhdsdio_membytes(bus, TRUE, offset,
5011 			dlarray + offset, sizeof(dlarray) - offset);
5012 		if (bcmerror) {
5013 			DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
5014 			        __FUNCTION__, bcmerror, sizeof(dlarray) - offset, offset));
5015 			goto err;
5016 		}
5017 	}
5018 
5019 #ifdef DHD_DEBUG
5020 	/* Upload and compare the downloaded code */
5021 	{
5022 		unsigned char *ularray;
5023 
5024 		ularray = MALLOC(bus->dhd->osh, bus->ramsize);
5025 		/* Upload image to verify downloaded contents. */
5026 		offset = 0;
5027 		memset(ularray, 0xaa, bus->ramsize);
5028 		while ((offset + MEMBLOCK) < sizeof(dlarray)) {
5029 			bcmerror = dhdsdio_membytes(bus, FALSE, offset, ularray + offset, MEMBLOCK);
5030 			if (bcmerror) {
5031 				DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n",
5032 					__FUNCTION__, bcmerror, MEMBLOCK, offset));
5033 				goto err;
5034 			}
5035 
5036 			offset += MEMBLOCK;
5037 		}
5038 
5039 		if (offset < sizeof(dlarray)) {
5040 			bcmerror = dhdsdio_membytes(bus, FALSE, offset,
5041 				ularray + offset, sizeof(dlarray) - offset);
5042 			if (bcmerror) {
5043 				DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n",
5044 					__FUNCTION__, bcmerror, sizeof(dlarray) - offset, offset));
5045 				goto err;
5046 			}
5047 		}
5048 
5049 		if (memcmp(dlarray, ularray, sizeof(dlarray))) {
5050 			DHD_ERROR(("%s: Downloaded image is corrupted.\n", __FUNCTION__));
5051 			ASSERT(0);
5052 			goto err;
5053 		} else
5054 			DHD_ERROR(("%s: Download, Upload and compare succeeded.\n", __FUNCTION__));
5055 
5056 		MFREE(bus->dhd->osh, ularray, bus->ramsize);
5057 	}
5058 #endif /* DHD_DEBUG */
5059 
5060 err:
5061 	return bcmerror;
5062 }
5063 #endif /* BCMEMBEDIMAGE */
5064 
5065 static int
dhdsdio_download_code_file(struct dhd_bus * bus,char * fw_path)5066 dhdsdio_download_code_file(struct dhd_bus *bus, char *fw_path)
5067 {
5068 	int bcmerror = -1;
5069 	int offset = 0;
5070 	uint len;
5071 	void *image = NULL;
5072 	uint8 *memblock = NULL, *memptr;
5073 
5074 	DHD_INFO(("%s: download firmware %s\n", __FUNCTION__, fw_path));
5075 
5076 	image = dhd_os_open_image(fw_path);
5077 	if (image == NULL)
5078 		goto err;
5079 
5080 	memptr = memblock = MALLOC(bus->dhd->osh, MEMBLOCK + DHD_SDALIGN);
5081 	if (memblock == NULL) {
5082 		DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, MEMBLOCK));
5083 		goto err;
5084 	}
5085 	if ((uint32)(uintptr)memblock % DHD_SDALIGN)
5086 		memptr += (DHD_SDALIGN - ((uint32)(uintptr)memblock % DHD_SDALIGN));
5087 
5088 	/* Download image */
5089 	while ((len = dhd_os_get_image_block((char*)memptr, MEMBLOCK, image))) {
5090 		bcmerror = dhdsdio_membytes(bus, TRUE, offset, memptr, len);
5091 		if (bcmerror) {
5092 			DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
5093 			        __FUNCTION__, bcmerror, MEMBLOCK, offset));
5094 			goto err;
5095 		}
5096 
5097 		offset += MEMBLOCK;
5098 	}
5099 
5100 err:
5101 	if (memblock)
5102 		MFREE(bus->dhd->osh, memblock, MEMBLOCK + DHD_SDALIGN);
5103 
5104 	if (image)
5105 		dhd_os_close_image(image);
5106 
5107 	return bcmerror;
5108 }
5109 
5110 /*
5111  * ProcessVars:Takes a buffer of "<var>=<value>\n" lines read from a file and ending in a NUL.
5112  * Removes carriage returns, empty lines, comment lines, and converts newlines to NULs.
5113  * Shortens buffer as needed and pads with NULs.  End of buffer is marked by two NULs.
5114 */
5115 
5116 static uint
process_nvram_vars(char * varbuf,uint len)5117 process_nvram_vars(char *varbuf, uint len)
5118 {
5119 	char *dp;
5120 	bool findNewline;
5121 	int column;
5122 	uint buf_len, n;
5123 
5124 	dp = varbuf;
5125 
5126 	findNewline = FALSE;
5127 	column = 0;
5128 
5129 	for (n = 0; n < len; n++) {
5130 		if (varbuf[n] == 0)
5131 			break;
5132 		if (varbuf[n] == '\r')
5133 			continue;
5134 		if (findNewline && varbuf[n] != '\n')
5135 			continue;
5136 		findNewline = FALSE;
5137 		if (varbuf[n] == '#') {
5138 			findNewline = TRUE;
5139 			continue;
5140 		}
5141 		if (varbuf[n] == '\n') {
5142 			if (column == 0)
5143 				continue;
5144 			*dp++ = 0;
5145 			column = 0;
5146 			continue;
5147 		}
5148 		*dp++ = varbuf[n];
5149 		column++;
5150 	}
5151 	buf_len = dp - varbuf;
5152 
5153 	while (dp < varbuf + n)
5154 		*dp++ = 0;
5155 
5156 	return buf_len;
5157 }
5158 
5159 /*
5160 	EXAMPLE: nvram_array
5161 	nvram_arry format:
5162 	name=value
5163 	Use carriage return at the end of each assignment, and an empty string with
5164 	carriage return at the end of array.
5165 
5166 	For example:
5167 	unsigned char  nvram_array[] = {"name1=value1\n", "name2=value2\n", "\n"};
5168 	Hex values start with 0x, and mac addr format: xx:xx:xx:xx:xx:xx.
5169 
5170 	Search "EXAMPLE: nvram_array" to see how the array is activated.
5171 */
5172 
5173 void
dhd_bus_set_nvram_params(struct dhd_bus * bus,const char * nvram_params)5174 dhd_bus_set_nvram_params(struct dhd_bus * bus, const char *nvram_params)
5175 {
5176 	bus->nvram_params = nvram_params;
5177 }
5178 
5179 static int
dhdsdio_download_nvram(struct dhd_bus * bus)5180 dhdsdio_download_nvram(struct dhd_bus *bus)
5181 {
5182 	int bcmerror = -1;
5183 	uint len;
5184 	void * image = NULL;
5185 	char * memblock = NULL;
5186 	char *bufp;
5187 	char *nv_path;
5188 	bool nvram_file_exists;
5189 
5190 	nv_path = bus->nv_path;
5191 
5192 	nvram_file_exists = ((nv_path != NULL) && (nv_path[0] != '\0'));
5193 	if (!nvram_file_exists && (bus->nvram_params == NULL))
5194 		return (0);
5195 
5196 	if (nvram_file_exists) {
5197 		image = dhd_os_open_image(nv_path);
5198 		if (image == NULL)
5199 			goto err;
5200 	}
5201 
5202 	memblock = MALLOC(bus->dhd->osh, MEMBLOCK);
5203 	if (memblock == NULL) {
5204 		DHD_ERROR(("%s: Failed to allocate memory %d bytes\n",
5205 		           __FUNCTION__, MEMBLOCK));
5206 		goto err;
5207 	}
5208 
5209 	/* Download variables */
5210 	if (nvram_file_exists) {
5211 		len = dhd_os_get_image_block(memblock, MEMBLOCK, image);
5212 	}
5213 	else {
5214 		len = strlen(bus->nvram_params);
5215 		ASSERT(len <= MEMBLOCK);
5216 		if (len > MEMBLOCK)
5217 			len = MEMBLOCK;
5218 		memcpy(memblock, bus->nvram_params, len);
5219 	}
5220 
5221 	if (len > 0 && len < MEMBLOCK) {
5222 		bufp = (char *)memblock;
5223 		bufp[len] = 0;
5224 		len = process_nvram_vars(bufp, len);
5225 		bufp += len;
5226 		*bufp++ = 0;
5227 		if (len)
5228 			bcmerror = dhdsdio_downloadvars(bus, memblock, len + 1);
5229 		if (bcmerror) {
5230 			DHD_ERROR(("%s: error downloading vars: %d\n",
5231 			           __FUNCTION__, bcmerror));
5232 		}
5233 	}
5234 	else {
5235 		DHD_ERROR(("%s: error reading nvram file: %d\n",
5236 		           __FUNCTION__, len));
5237 		bcmerror = BCME_SDIO_ERROR;
5238 	}
5239 
5240 err:
5241 	if (memblock)
5242 		MFREE(bus->dhd->osh, memblock, MEMBLOCK);
5243 
5244 	if (image)
5245 		dhd_os_close_image(image);
5246 
5247 	return bcmerror;
5248 }
5249 
5250 static int
_dhdsdio_download_firmware(struct dhd_bus * bus)5251 _dhdsdio_download_firmware(struct dhd_bus *bus)
5252 {
5253 	int bcmerror = -1;
5254 
5255 	bool embed = FALSE;	/* download embedded firmware */
5256 	bool dlok = FALSE;	/* download firmware succeeded */
5257 
5258 	/* Out immediately if no image to download */
5259 	if ((bus->fw_path == NULL) || (bus->fw_path[0] == '\0')) {
5260 #ifdef BCMEMBEDIMAGE
5261 		embed = TRUE;
5262 #else
5263 		return bcmerror;
5264 #endif
5265 	}
5266 
5267 	/* Keep arm in reset */
5268 	if (dhdsdio_download_state(bus, TRUE)) {
5269 		DHD_ERROR(("%s: error placing ARM core in reset\n", __FUNCTION__));
5270 		goto err;
5271 	}
5272 
5273 	/* External image takes precedence if specified */
5274 	if ((bus->fw_path != NULL) && (bus->fw_path[0] != '\0')) {
5275 		if (dhdsdio_download_code_file(bus, bus->fw_path)) {
5276 			DHD_ERROR(("%s: dongle image file download failed\n", __FUNCTION__));
5277 #ifdef BCMEMBEDIMAGE
5278 			embed = TRUE;
5279 #else
5280 			goto err;
5281 #endif
5282 		}
5283 		else {
5284 			embed = FALSE;
5285 			dlok = TRUE;
5286 		}
5287 	}
5288 #ifdef BCMEMBEDIMAGE
5289 	if (embed) {
5290 		if (dhdsdio_download_code_array(bus)) {
5291 			DHD_ERROR(("%s: dongle image array download failed\n", __FUNCTION__));
5292 			goto err;
5293 		}
5294 		else {
5295 			dlok = TRUE;
5296 		}
5297 	}
5298 #endif
5299 	if (!dlok) {
5300 		DHD_ERROR(("%s: dongle image download failed\n", __FUNCTION__));
5301 		goto err;
5302 	}
5303 
5304 	/* EXAMPLE: nvram_array */
5305 	/* If a valid nvram_arry is specified as above, it can be passed down to dongle */
5306 	/* dhd_bus_set_nvram_params(bus, (char *)&nvram_array); */
5307 
5308 	/* External nvram takes precedence if specified */
5309 	if (dhdsdio_download_nvram(bus)) {
5310 		DHD_ERROR(("%s: dongle nvram file download failed\n", __FUNCTION__));
5311 	}
5312 
5313 	/* Take arm out of reset */
5314 	if (dhdsdio_download_state(bus, FALSE)) {
5315 		DHD_ERROR(("%s: error getting out of ARM core reset\n", __FUNCTION__));
5316 		goto err;
5317 	}
5318 
5319 	bcmerror = 0;
5320 
5321 err:
5322 	return bcmerror;
5323 }
5324 
5325 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)5326 dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes,
5327 	void *pkt, bcmsdh_cmplt_fn_t complete, void *handle)
5328 {
5329 	int status;
5330 
5331 	/* 4329: GSPI check */
5332 	status = bcmsdh_recv_buf(bus->sdh, addr, fn, flags, buf, nbytes, pkt, complete, handle);
5333 	return status;
5334 }
5335 
5336 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)5337 dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes,
5338 	void *pkt, bcmsdh_cmplt_fn_t complete, void *handle)
5339 {
5340 	return (bcmsdh_send_buf(bus->sdh, addr, fn, flags, buf, nbytes, pkt, complete, handle));
5341 }
5342 
5343 uint
dhd_bus_chip(struct dhd_bus * bus)5344 dhd_bus_chip(struct dhd_bus *bus)
5345 {
5346 	ASSERT(bus->sih != NULL);
5347 	return bus->sih->chip;
5348 }
5349 
5350 void *
dhd_bus_pub(struct dhd_bus * bus)5351 dhd_bus_pub(struct dhd_bus *bus)
5352 {
5353 	return bus->dhd;
5354 }
5355 
5356 void *
dhd_bus_txq(struct dhd_bus * bus)5357 dhd_bus_txq(struct dhd_bus *bus)
5358 {
5359 	return &bus->txq;
5360 }
5361 
5362 uint
dhd_bus_hdrlen(struct dhd_bus * bus)5363 dhd_bus_hdrlen(struct dhd_bus *bus)
5364 {
5365 	return SDPCM_HDRLEN;
5366 }
5367 
5368 int
dhd_bus_devreset(dhd_pub_t * dhdp,uint8 flag)5369 dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag)
5370 {
5371 	int bcmerror = 0;
5372 	dhd_bus_t *bus;
5373 
5374 	bus = dhdp->bus;
5375 
5376 	if (flag == TRUE) {
5377 		if (!bus->dhd->dongle_reset) {
5378 #if !defined(IGNORE_ETH0_DOWN)
5379 			/* Force flow control as protection when stop come before ifconfig_down */
5380 			dhd_txflowcontrol(bus->dhd, 0, ON);
5381 #endif /* !defined(IGNORE_ETH0_DOWN) */
5382 			/* save country settinng if was pre-setup with priv ioctl */
5383 			dhdcdc_query_ioctl(bus->dhd, 0, WLC_GET_COUNTRY,
5384 				bus->dhd->country_code, sizeof(bus->dhd->country_code));
5385 			/* Expect app to have torn down any connection before calling */
5386 			/* Stop the bus, disable F2 */
5387 			dhd_bus_stop(bus, FALSE);
5388 
5389 			/* Clean tx/rx buffer pointers, detach from the dongle */
5390 			dhdsdio_release_dongle(bus, bus->dhd->osh);
5391 
5392 			bus->dhd->dongle_reset = TRUE;
5393 			bus->dhd->up = FALSE;
5394 
5395 			DHD_TRACE(("%s:  WLAN OFF DONE\n", __FUNCTION__));
5396 			/* App can now remove power from device */
5397 		} else
5398 			bcmerror = BCME_SDIO_ERROR;
5399 	} else {
5400 		/* App must have restored power to device before calling */
5401 
5402 		DHD_TRACE(("\n\n%s: == WLAN ON ==\n", __FUNCTION__));
5403 
5404 		if (bus->dhd->dongle_reset) {
5405 			/* Turn on WLAN */
5406 			/* Reset SD client */
5407 			bcmsdh_reset(bus->sdh);
5408 
5409 			/* Attempt to re-attach & download */
5410 			if (dhdsdio_probe_attach(bus, bus->dhd->osh, bus->sdh,
5411 			                        (uint32 *)SI_ENUM_BASE,
5412 			                        bus->cl_devid)) {
5413 				/* Attempt to download binary to the dongle */
5414 				if (dhdsdio_probe_init(bus, bus->dhd->osh, bus->sdh) &&
5415 					dhdsdio_download_firmware(bus, bus->dhd->osh, bus->sdh)) {
5416 
5417 					/* Re-init bus, enable F2 transfer */
5418 					dhd_bus_init((dhd_pub_t *) bus->dhd, FALSE);
5419 
5420 #if defined(OOB_INTR_ONLY)
5421 					dhd_enable_oob_intr(bus, TRUE);
5422 #endif /* defined(OOB_INTR_ONLY) */
5423 
5424 					bus->dhd->dongle_reset = FALSE;
5425 					bus->dhd->up = TRUE;
5426 
5427 #if !defined(IGNORE_ETH0_DOWN)
5428 					/* Restore flow control  */
5429 					dhd_txflowcontrol(bus->dhd, 0, OFF);
5430 #endif
5431 
5432 					DHD_TRACE(("%s: WLAN ON DONE\n", __FUNCTION__));
5433 				} else
5434 					bcmerror = BCME_SDIO_ERROR;
5435 			} else
5436 				bcmerror = BCME_SDIO_ERROR;
5437 		} else {
5438 			bcmerror = BCME_NOTDOWN;
5439 			DHD_ERROR(("%s: Set DEVRESET=FALSE invoked when device is on\n",
5440 				__FUNCTION__));
5441 			bcmerror = BCME_SDIO_ERROR;
5442 		}
5443 	}
5444 	return bcmerror;
5445 }
5446