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