PageRenderTime 26ms CodeModel.GetById 19ms app.highlight 153ms RepoModel.GetById 1ms app.codeStats 1ms

/drivers/net/wireless/bcmdhd/dhd_sdio.c

https://bitbucket.org/cyanogenmod/android_kernel_asus_tf300t
C | 6359 lines | 4798 code | 999 blank | 562 comment | 1138 complexity | 3c52bd19fa50b30dca420548ef79f3e5 MD5 | raw file
Possible License(s): LGPL-2.0, AGPL-1.0, GPL-2.0
   1/*
   2 * DHD Bus Module for SDIO
   3 *
   4 * Copyright (C) 1999-2011, 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 326662 2012-04-10 06:38:08Z $
  25 */
  26
  27#include <typedefs.h>
  28#include <osl.h>
  29#include <bcmsdh.h>
  30
  31#ifdef BCMEMBEDIMAGE
  32#include BCMEMBEDIMAGE
  33#endif /* BCMEMBEDIMAGE */
  34
  35#include <bcmdefs.h>
  36#include <bcmutils.h>
  37#include <bcmendian.h>
  38#include <bcmdevs.h>
  39
  40#include <siutils.h>
  41#include <hndpmu.h>
  42#include <hndsoc.h>
  43#include <bcmsdpcm.h>
  44#if defined(DHD_DEBUG)
  45#include <hndrte_armtrap.h>
  46#include <hndrte_cons.h>
  47#endif /* defined(DHD_DEBUG) */
  48#include <sbchipc.h>
  49#include <sbhnddma.h>
  50
  51#include <sdio.h>
  52#include <sbsdio.h>
  53#include <sbsdpcmdev.h>
  54#include <bcmsdpcm.h>
  55#include <bcmsdbus.h>
  56
  57#include <proto/ethernet.h>
  58#include <proto/802.1d.h>
  59#include <proto/802.11.h>
  60
  61#include <dngl_stats.h>
  62#include <dhd.h>
  63#include <dhd_bus.h>
  64#include <dhd_proto.h>
  65#include <dhd_dbg.h>
  66#include <dhdioctl.h>
  67#include <sdiovar.h>
  68
  69#ifndef DHDSDIO_MEM_DUMP_FNAME
  70#define DHDSDIO_MEM_DUMP_FNAME         "mem_dump"
  71#endif
  72
  73#define QLEN		256	/* bulk rx and tx queue lengths */
  74#define FCHI		(QLEN - 10)
  75#define FCLOW		(FCHI / 2)
  76#define PRIOMASK	7
  77
  78#define TXRETRIES	2	/* # of retries for tx frames */
  79
  80#define DHD_RXBOUND	50	/* Default for max rx frames in one scheduling */
  81
  82#define DHD_TXBOUND	20	/* Default for max tx frames in one scheduling */
  83
  84#define DHD_TXMINMAX	1	/* Max tx frames if rx still pending */
  85
  86#define MEMBLOCK	2048		/* Block size used for downloading of dongle image */
  87#define MAX_NVRAMBUF_SIZE	4096	/* max nvram buf size */
  88#define MAX_DATA_BUF	(32 * 1024)	/* Must be large enough to hold biggest possible glom */
  89
  90#ifndef DHD_FIRSTREAD
  91#define DHD_FIRSTREAD   32
  92#endif
  93#if !ISPOWEROF2(DHD_FIRSTREAD)
  94#error DHD_FIRSTREAD is not a power of 2!
  95#endif
  96
  97/* Total length of frame header for dongle protocol */
  98#define SDPCM_HDRLEN	(SDPCM_FRAMETAG_LEN + SDPCM_SWHEADER_LEN)
  99#ifdef SDTEST
 100#define SDPCM_RESERVE	(SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN)
 101#else
 102#define SDPCM_RESERVE	(SDPCM_HDRLEN + DHD_SDALIGN)
 103#endif
 104
 105/* Space for header read, limit for data packets */
 106#ifndef MAX_HDR_READ
 107#define MAX_HDR_READ	32
 108#endif
 109#if !ISPOWEROF2(MAX_HDR_READ)
 110#error MAX_HDR_READ is not a power of 2!
 111#endif
 112
 113#define MAX_RX_DATASZ	2048
 114
 115/* Maximum milliseconds to wait for F2 to come up */
 116#define DHD_WAIT_F2RDY	3000
 117
 118/* Bump up limit on waiting for HT to account for first startup;
 119 * if the image is doing a CRC calculation before programming the PMU
 120 * for HT availability, it could take a couple hundred ms more, so
 121 * max out at a 1 second (1000000us).
 122 */
 123#if (PMU_MAX_TRANSITION_DLY <= 1000000)
 124#undef PMU_MAX_TRANSITION_DLY
 125#define PMU_MAX_TRANSITION_DLY 1000000
 126#endif
 127
 128/* Value for ChipClockCSR during initial setup */
 129#define DHD_INIT_CLKCTL1	(SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ)
 130#define DHD_INIT_CLKCTL2	(SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP)
 131
 132/* Flags for SDH calls */
 133#define F2SYNC	(SDIO_REQ_4BYTE | SDIO_REQ_FIXED)
 134
 135/* Packet free applicable unconditionally for sdio and sdspi.  Conditional if
 136 * bufpool was present for gspi bus.
 137 */
 138#define PKTFREE2()		if ((bus->bus != SPI_BUS) || bus->usebufpool) \
 139					PKTFREE(bus->dhd->osh, pkt, FALSE);
 140DHD_SPINWAIT_SLEEP_INIT(sdioh_spinwait_sleep);
 141#if defined(OOB_INTR_ONLY)
 142extern void bcmsdh_set_irq(int flag);
 143#endif /* defined(OOB_INTR_ONLY) */
 144#ifdef PROP_TXSTATUS
 145extern void dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success);
 146#endif
 147
 148#ifdef DHD_DEBUG
 149/* Device console log buffer state */
 150#define CONSOLE_LINE_MAX	192
 151#define CONSOLE_BUFFER_MAX	2024
 152typedef struct dhd_console {
 153	uint		count;			/* Poll interval msec counter */
 154	uint		log_addr;		/* Log struct address (fixed) */
 155	hndrte_log_t	log;			/* Log struct (host copy) */
 156	uint		bufsize;		/* Size of log buffer */
 157	uint8		*buf;			/* Log buffer (host copy) */
 158	uint		last;			/* Last buffer read index */
 159} dhd_console_t;
 160#endif /* DHD_DEBUG */
 161
 162/* Private data for SDIO bus interaction */
 163typedef struct dhd_bus {
 164	dhd_pub_t	*dhd;
 165
 166	bcmsdh_info_t	*sdh;			/* Handle for BCMSDH calls */
 167	si_t		*sih;			/* Handle for SI calls */
 168	char		*vars;			/* Variables (from CIS and/or other) */
 169	uint		varsz;			/* Size of variables buffer */
 170	uint32		sbaddr;			/* Current SB window pointer (-1, invalid) */
 171
 172	sdpcmd_regs_t	*regs;			/* Registers for SDIO core */
 173	uint		sdpcmrev;		/* SDIO core revision */
 174	uint		armrev;			/* CPU core revision */
 175	uint		ramrev;			/* SOCRAM core revision */
 176	uint32		ramsize;		/* Size of RAM in SOCRAM (bytes) */
 177	uint32		orig_ramsize;		/* Size of RAM in SOCRAM (bytes) */
 178
 179	uint32		bus;			/* gSPI or SDIO bus */
 180	uint32		hostintmask;		/* Copy of Host Interrupt Mask */
 181	uint32		intstatus;		/* Intstatus bits (events) pending */
 182	bool		dpc_sched;		/* Indicates DPC schedule (intrpt rcvd) */
 183	bool		fcstate;		/* State of dongle flow-control */
 184
 185	uint16		cl_devid;		/* cached devid for dhdsdio_probe_attach() */
 186	char		*fw_path; /* module_param: path to firmware image */
 187	char		*nv_path; /* module_param: path to nvram vars file */
 188	const char      *nvram_params;		/* user specified nvram params. */
 189
 190	uint		blocksize;		/* Block size of SDIO transfers */
 191	uint		roundup;		/* Max roundup limit */
 192
 193	struct pktq	txq;			/* Queue length used for flow-control */
 194	uint8		flowcontrol;		/* per prio flow control bitmask */
 195	uint8		tx_seq;			/* Transmit sequence number (next) */
 196	uint8		tx_max;			/* Maximum transmit sequence allowed */
 197
 198	uint8		hdrbuf[MAX_HDR_READ + DHD_SDALIGN];
 199	uint8		*rxhdr;			/* Header of current rx frame (in hdrbuf) */
 200	uint16		nextlen;		/* Next Read Len from last header */
 201	uint8		rx_seq;			/* Receive sequence number (expected) */
 202	bool		rxskip;			/* Skip receive (awaiting NAK ACK) */
 203
 204	void		*glomd;			/* Packet containing glomming descriptor */
 205	void		*glom;			/* Packet chain for glommed superframe */
 206	uint		glomerr;		/* Glom packet read errors */
 207
 208	uint8		*rxbuf;			/* Buffer for receiving control packets */
 209	uint		rxblen;			/* Allocated length of rxbuf */
 210	uint8		*rxctl;			/* Aligned pointer into rxbuf */
 211	uint8		*databuf;		/* Buffer for receiving big glom packet */
 212	uint8		*dataptr;		/* Aligned pointer into databuf */
 213	uint		rxlen;			/* Length of valid data in buffer */
 214
 215	uint8		sdpcm_ver;		/* Bus protocol reported by dongle */
 216
 217	bool		intr;			/* Use interrupts */
 218	bool		poll;			/* Use polling */
 219	bool		ipend;			/* Device interrupt is pending */
 220	bool		intdis;			/* Interrupts disabled by isr */
 221	uint 		intrcount;		/* Count of device interrupt callbacks */
 222	uint		lastintrs;		/* Count as of last watchdog timer */
 223	uint		spurious;		/* Count of spurious interrupts */
 224	uint		pollrate;		/* Ticks between device polls */
 225	uint		polltick;		/* Tick counter */
 226	uint		pollcnt;		/* Count of active polls */
 227
 228#ifdef DHD_DEBUG
 229	dhd_console_t	console;		/* Console output polling support */
 230	uint		console_addr;		/* Console address from shared struct */
 231#endif /* DHD_DEBUG */
 232
 233	uint		regfails;		/* Count of R_REG/W_REG failures */
 234
 235	uint		clkstate;		/* State of sd and backplane clock(s) */
 236	bool		activity;		/* Activity flag for clock down */
 237	int32		idletime;		/* Control for activity timeout */
 238	int32		idlecount;		/* Activity timeout counter */
 239	int32		idleclock;		/* How to set bus driver when idle */
 240	int32		sd_divisor;		/* Speed control to bus driver */
 241	int32		sd_mode;		/* Mode control to bus driver */
 242	int32		sd_rxchain;		/* If bcmsdh api accepts PKT chains */
 243	bool		use_rxchain;		/* If dhd should use PKT chains */
 244	bool		sleeping;		/* Is SDIO bus sleeping? */
 245	bool		rxflow_mode;	/* Rx flow control mode */
 246	bool		rxflow;			/* Is rx flow control on */
 247	uint		prev_rxlim_hit;		/* Is prev rx limit exceeded (per dpc schedule) */
 248	bool		alp_only;		/* Don't use HT clock (ALP only) */
 249	/* Field to decide if rx of control frames happen in rxbuf or lb-pool */
 250	bool		usebufpool;
 251
 252#ifdef SDTEST
 253	/* external loopback */
 254	bool		ext_loop;
 255	uint8		loopid;
 256
 257	/* pktgen configuration */
 258	uint		pktgen_freq;		/* Ticks between bursts */
 259	uint		pktgen_count;		/* Packets to send each burst */
 260	uint		pktgen_print;		/* Bursts between count displays */
 261	uint		pktgen_total;		/* Stop after this many */
 262	uint		pktgen_minlen;		/* Minimum packet data len */
 263	uint		pktgen_maxlen;		/* Maximum packet data len */
 264	uint		pktgen_mode;		/* Configured mode: tx, rx, or echo */
 265	uint		pktgen_stop;		/* Number of tx failures causing stop */
 266
 267	/* active pktgen fields */
 268	uint		pktgen_tick;		/* Tick counter for bursts */
 269	uint		pktgen_ptick;		/* Burst counter for printing */
 270	uint		pktgen_sent;		/* Number of test packets generated */
 271	uint		pktgen_rcvd;		/* Number of test packets received */
 272	uint		pktgen_fail;		/* Number of failed send attempts */
 273	uint16		pktgen_len;		/* Length of next packet to send */
 274#define PKTGEN_RCV_IDLE     (0)
 275#define PKTGEN_RCV_ONGOING  (1)
 276	uint16		pktgen_rcv_state;		/* receive state */
 277	uint		pktgen_rcvd_rcvsession;	/* test pkts rcvd per rcv session. */
 278#endif /* SDTEST */
 279
 280	/* Some additional counters */
 281	uint		tx_sderrs;		/* Count of tx attempts with sd errors */
 282	uint		fcqueued;		/* Tx packets that got queued */
 283	uint		rxrtx;			/* Count of rtx requests (NAK to dongle) */
 284	uint		rx_toolong;		/* Receive frames too long to receive */
 285	uint		rxc_errors;		/* SDIO errors when reading control frames */
 286	uint		rx_hdrfail;		/* SDIO errors on header reads */
 287	uint		rx_badhdr;		/* Bad received headers (roosync?) */
 288	uint		rx_badseq;		/* Mismatched rx sequence number */
 289	uint		fc_rcvd;		/* Number of flow-control events received */
 290	uint		fc_xoff;		/* Number which turned on flow-control */
 291	uint		fc_xon;			/* Number which turned off flow-control */
 292	uint		rxglomfail;		/* Failed deglom attempts */
 293	uint		rxglomframes;		/* Number of glom frames (superframes) */
 294	uint		rxglompkts;		/* Number of packets from glom frames */
 295	uint		f2rxhdrs;		/* Number of header reads */
 296	uint		f2rxdata;		/* Number of frame data reads */
 297	uint		f2txdata;		/* Number of f2 frame writes */
 298	uint		f1regdata;		/* Number of f1 register accesses */
 299
 300	uint8		*ctrl_frame_buf;
 301	uint32		ctrl_frame_len;
 302	bool		ctrl_frame_stat;
 303	uint32		rxint_mode;	/* rx interrupt mode */
 304} dhd_bus_t;
 305
 306/* clkstate */
 307#define CLK_NONE	0
 308#define CLK_SDONLY	1
 309#define CLK_PENDING	2	/* Not used yet */
 310#define CLK_AVAIL	3
 311
 312#define DHD_NOPMU(dhd)	(FALSE)
 313
 314#ifdef DHD_DEBUG
 315static int qcount[NUMPRIO];
 316static int tx_packets[NUMPRIO];
 317#endif /* DHD_DEBUG */
 318
 319/* Deferred transmit */
 320const uint dhd_deferred_tx = 1;
 321
 322extern uint dhd_watchdog_ms;
 323extern void dhd_os_wd_timer(void *bus, uint wdtick);
 324
 325/* Tx/Rx bounds */
 326uint dhd_txbound;
 327uint dhd_rxbound;
 328uint dhd_txminmax = DHD_TXMINMAX;
 329
 330/* override the RAM size if possible */
 331#define DONGLE_MIN_MEMSIZE (128 *1024)
 332int dhd_dongle_memsize;
 333
 334static bool dhd_doflow;
 335static bool dhd_alignctl;
 336
 337static bool sd1idle;
 338
 339static bool retrydata;
 340#define RETRYCHAN(chan) (((chan) == SDPCM_EVENT_CHANNEL) || retrydata)
 341
 342static const uint watermark = 8;
 343static const uint firstread = DHD_FIRSTREAD;
 344
 345#define HDATLEN (firstread - (SDPCM_HDRLEN))
 346
 347/* Retry count for register access failures */
 348static const uint retry_limit = 20;
 349
 350/* Force even SD lengths (some host controllers mess up on odd bytes) */
 351static bool forcealign;
 352
 353/* Flag to indicate if we should download firmware on driver load */
 354uint dhd_download_fw_on_driverload = TRUE;
 355
 356#define ALIGNMENT  4
 357
 358#if defined(OOB_INTR_ONLY) && defined(HW_OOB)
 359extern void bcmsdh_enable_hw_oob_intr(void *sdh, bool enable);
 360#endif
 361
 362#if defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD)
 363#error OOB_INTR_ONLY is NOT working with SDIO_ISR_THREAD
 364#endif /* defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD) */
 365#define PKTALIGN(osh, p, len, align)					\
 366	do {								\
 367		uint datalign;						\
 368		datalign = (uintptr)PKTDATA((osh), (p));		\
 369		datalign = ROUNDUP(datalign, (align)) - datalign;	\
 370		ASSERT(datalign < (align));				\
 371		ASSERT(PKTLEN((osh), (p)) >= ((len) + datalign));	\
 372		if (datalign)						\
 373			PKTPULL((osh), (p), datalign);			\
 374		PKTSETLEN((osh), (p), (len));				\
 375	} while (0)
 376
 377/* Limit on rounding up frames */
 378static const uint max_roundup = 512;
 379
 380/* Try doing readahead */
 381static bool dhd_readahead;
 382
 383/* To check if there's window offered */
 384#define DATAOK(bus) \
 385	(((uint8)(bus->tx_max - bus->tx_seq) > 1) && \
 386	(((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0))
 387
 388/* To check if there's window offered for ctrl frame */
 389#define TXCTLOK(bus) \
 390	(((uint8)(bus->tx_max - bus->tx_seq) != 0) && \
 391	(((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0))
 392
 393/* Macros to get register read/write status */
 394/* NOTE: these assume a local dhdsdio_bus_t *bus! */
 395#define R_SDREG(regvar, regaddr, retryvar) \
 396do { \
 397	retryvar = 0; \
 398	do { \
 399		regvar = R_REG(bus->dhd->osh, regaddr); \
 400	} while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \
 401	if(retryvar > 1)  \
 402		DHD_ERROR(("%s: regvar[ %d ], retryvar[ %d ], regfails[ %d ], bcmsdh_regfail[ %d ] \n",__FUNCTION__,regvar, retryvar ,bus->regfails, bcmsdh_regfail(bus->sdh))); \
 403	if (retryvar) { \
 404		bus->regfails += (retryvar-1); \
 405		if (retryvar > retry_limit) { \
 406			DHD_ERROR(("%s: FAILED" #regvar "READ, LINE %d\n", \
 407			           __FUNCTION__, __LINE__)); \
 408			regvar = 0; \
 409		} \
 410	} \
 411} while (0)
 412
 413#define W_SDREG(regval, regaddr, retryvar) \
 414do { \
 415	retryvar = 0; \
 416	do { \
 417		W_REG(bus->dhd->osh, regaddr, regval); \
 418	} while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \
 419	if (retryvar) { \
 420		bus->regfails += (retryvar-1); \
 421		if (retryvar > retry_limit) \
 422			DHD_ERROR(("%s: FAILED REGISTER WRITE, LINE %d\n", \
 423			           __FUNCTION__, __LINE__)); \
 424	} \
 425} while (0)
 426
 427#define BUS_WAKE(bus) \
 428	do { \
 429		if ((bus)->sleeping) \
 430			dhdsdio_bussleep((bus), FALSE); \
 431	} while (0);
 432
 433/*
 434 * pktavail interrupts from dongle to host can be managed in 3 different ways
 435 * whenever there is a packet available in dongle to transmit to host.
 436 *
 437 * Mode 0:	Dongle writes the software host mailbox and host is interrupted.
 438 * Mode 1:	(sdiod core rev >= 4)
 439 *		Device sets a new bit in the intstatus whenever there is a packet
 440 *		available in fifo.  Host can't clear this specific status bit until all the
 441 *		packets are read from the FIFO.  No need to ack dongle intstatus.
 442 * Mode 2:	(sdiod core rev >= 4)
 443 *		Device sets a bit in the intstatus, and host acks this by writing
 444 *		one to this bit.  Dongle won't generate anymore packet interrupts
 445 *		until host reads all the packets from the dongle and reads a zero to
 446 *		figure that there are no more packets.  No need to disable host ints.
 447 *		Need to ack the intstatus.
 448 */
 449
 450#define SDIO_DEVICE_HMB_RXINT		0	/* default old way */
 451#define SDIO_DEVICE_RXDATAINT_MODE_0	1	/* from sdiod rev 4 */
 452#define SDIO_DEVICE_RXDATAINT_MODE_1	2	/* from sdiod rev 4 */
 453
 454
 455#define FRAME_AVAIL_MASK(bus) 	\
 456	((bus->rxint_mode == SDIO_DEVICE_HMB_RXINT) ? I_HMB_FRAME_IND : I_XMTDATA_AVAIL)
 457
 458#define DHD_BUS			SDIO_BUS
 459
 460#define PKT_AVAILABLE(bus, intstatus)	((intstatus) & (FRAME_AVAIL_MASK(bus)))
 461
 462#define HOSTINTMASK		(I_HMB_SW_MASK | I_CHIPACTIVE)
 463
 464#define GSPI_PR55150_BAILOUT
 465
 466
 467#ifdef SDTEST
 468static void dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq);
 469static void dhdsdio_sdtest_set(dhd_bus_t *bus, uint8 count);
 470#endif
 471
 472#ifdef DHD_DEBUG
 473static int dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size);
 474static int dhd_serialconsole(dhd_bus_t *bus, bool get, bool enable, int *bcmerror);
 475#endif /* DHD_DEBUG */
 476
 477static int dhdsdio_download_state(dhd_bus_t *bus, bool enter);
 478
 479static void dhdsdio_release(dhd_bus_t *bus, osl_t *osh);
 480static void dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh);
 481static void dhdsdio_disconnect(void *ptr);
 482static bool dhdsdio_chipmatch(uint16 chipid);
 483static bool dhdsdio_probe_attach(dhd_bus_t *bus, osl_t *osh, void *sdh,
 484                                 void * regsva, uint16  devid);
 485static bool dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh);
 486static bool dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh);
 487static void dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation,
 488	bool reset_flag);
 489
 490static void dhd_dongle_setmemsize(struct dhd_bus *bus, int mem_size);
 491static int dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags,
 492	uint8 *buf, uint nbytes,
 493	void *pkt, bcmsdh_cmplt_fn_t complete, void *handle);
 494static int dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags,
 495	uint8 *buf, uint nbytes,
 496	void *pkt, bcmsdh_cmplt_fn_t complete, void *handle);
 497
 498static bool dhdsdio_download_firmware(dhd_bus_t *bus, osl_t *osh, void *sdh);
 499static int _dhdsdio_download_firmware(dhd_bus_t *bus);
 500
 501static int dhdsdio_download_code_file(dhd_bus_t *bus, char *image_path);
 502static int dhdsdio_download_nvram(dhd_bus_t *bus);
 503#ifdef BCMEMBEDIMAGE
 504static int dhdsdio_download_code_array(dhd_bus_t *bus);
 505#endif
 506
 507#ifdef WLMEDIA_HTSF
 508#include <htsf.h>
 509extern uint32 dhd_get_htsf(void *dhd, int ifidx);
 510#endif /* WLMEDIA_HTSF */
 511
 512extern int chip_is_b1;
 513
 514static void
 515dhd_dongle_setmemsize(struct dhd_bus *bus, int mem_size)
 516{
 517	int32 min_size =  DONGLE_MIN_MEMSIZE;
 518	/* Restrict the memsize to user specified limit */
 519	DHD_ERROR(("user: Restrict the dongle ram size to %d, min accepted %d\n",
 520		dhd_dongle_memsize, min_size));
 521	if ((dhd_dongle_memsize > min_size) &&
 522		(dhd_dongle_memsize < (int32)bus->orig_ramsize))
 523		bus->ramsize = dhd_dongle_memsize;
 524}
 525
 526static int
 527dhdsdio_set_siaddr_window(dhd_bus_t *bus, uint32 address)
 528{
 529	int err = 0;
 530	bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW,
 531	                 (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err);
 532	if (!err)
 533		bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID,
 534		                 (address >> 16) & SBSDIO_SBADDRMID_MASK, &err);
 535	if (!err)
 536		bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH,
 537		                 (address >> 24) & SBSDIO_SBADDRHIGH_MASK, &err);
 538	return err;
 539}
 540
 541
 542/* Turn backplane clock on or off */
 543static int
 544dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok)
 545{
 546	int err;
 547	uint8 clkctl, clkreq, devctl;
 548	bcmsdh_info_t *sdh;
 549
 550	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
 551
 552#if defined(OOB_INTR_ONLY)
 553	pendok = FALSE;
 554#endif
 555	clkctl = 0;
 556	sdh = bus->sdh;
 557
 558
 559	if (on) {
 560		/* Request HT Avail */
 561		clkreq = bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ;
 562
 563
 564
 565
 566		bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
 567		if (err) {
 568			DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err));
 569			return BCME_ERROR;
 570		}
 571
 572		if (pendok &&
 573		    ((bus->sih->buscoretype == PCMCIA_CORE_ID) && (bus->sih->buscorerev == 9))) {
 574			uint32 dummy, retries;
 575			R_SDREG(dummy, &bus->regs->clockctlstatus, retries);
 576		}
 577
 578		/* Check current status */
 579		clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
 580		if (err) {
 581			DHD_ERROR(("%s: HT Avail read error: %d\n", __FUNCTION__, err));
 582			return BCME_ERROR;
 583		}
 584
 585		/* Go to pending and await interrupt if appropriate */
 586		if (!SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) {
 587			/* Allow only clock-available interrupt */
 588			devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
 589			if (err) {
 590				DHD_ERROR(("%s: Devctl access error setting CA: %d\n",
 591				           __FUNCTION__, err));
 592				return BCME_ERROR;
 593			}
 594
 595			devctl |= SBSDIO_DEVCTL_CA_INT_ONLY;
 596			bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
 597			DHD_INFO(("CLKCTL: set PENDING\n"));
 598			bus->clkstate = CLK_PENDING;
 599			return BCME_OK;
 600		} else if (bus->clkstate == CLK_PENDING) {
 601			/* Cancel CA-only interrupt filter */
 602			devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
 603			devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
 604			bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
 605		}
 606
 607		/* Otherwise, wait here (polling) for HT Avail */
 608		if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
 609			SPINWAIT_SLEEP(sdioh_spinwait_sleep,
 610				((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
 611			                                    SBSDIO_FUNC1_CHIPCLKCSR, &err)),
 612			          !SBSDIO_CLKAV(clkctl, bus->alp_only)), PMU_MAX_TRANSITION_DLY);
 613		}
 614		if (err) {
 615			DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err));
 616			return BCME_ERROR;
 617		}
 618		if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
 619			DHD_ERROR(("%s: HT Avail timeout (%d): clkctl 0x%02x\n",
 620			           __FUNCTION__, PMU_MAX_TRANSITION_DLY, clkctl));
 621			return BCME_ERROR;
 622		}
 623
 624
 625		/* Mark clock available */
 626		bus->clkstate = CLK_AVAIL;
 627		DHD_INFO(("CLKCTL: turned ON\n"));
 628
 629#if defined(DHD_DEBUG)
 630		if (bus->alp_only == TRUE) {
 631#if !defined(BCMLXSDMMC)
 632			if (!SBSDIO_ALPONLY(clkctl)) {
 633				DHD_ERROR(("%s: HT Clock, when ALP Only\n", __FUNCTION__));
 634			}
 635#endif /* !defined(BCMLXSDMMC) */
 636		} else {
 637			if (SBSDIO_ALPONLY(clkctl)) {
 638				DHD_ERROR(("%s: HT Clock should be on.\n", __FUNCTION__));
 639			}
 640		}
 641#endif /* defined (DHD_DEBUG) */
 642
 643		bus->activity = TRUE;
 644	} else {
 645		clkreq = 0;
 646
 647		if (bus->clkstate == CLK_PENDING) {
 648			/* Cancel CA-only interrupt filter */
 649			devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
 650			devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
 651			bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
 652		}
 653
 654		bus->clkstate = CLK_SDONLY;
 655		bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
 656		DHD_INFO(("CLKCTL: turned OFF\n"));
 657		if (err) {
 658			DHD_ERROR(("%s: Failed access turning clock off: %d\n",
 659			           __FUNCTION__, err));
 660			return BCME_ERROR;
 661		}
 662	}
 663	return BCME_OK;
 664}
 665
 666/* Change idle/active SD state */
 667static int
 668dhdsdio_sdclk(dhd_bus_t *bus, bool on)
 669{
 670	int err;
 671	int32 iovalue;
 672
 673	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
 674
 675	if (on) {
 676		if (bus->idleclock == DHD_IDLE_STOP) {
 677			/* Turn on clock and restore mode */
 678			iovalue = 1;
 679			err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0,
 680			                      &iovalue, sizeof(iovalue), TRUE);
 681			if (err) {
 682				DHD_ERROR(("%s: error enabling sd_clock: %d\n",
 683				           __FUNCTION__, err));
 684				return BCME_ERROR;
 685			}
 686
 687			iovalue = bus->sd_mode;
 688			err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
 689			                      &iovalue, sizeof(iovalue), TRUE);
 690			if (err) {
 691				DHD_ERROR(("%s: error changing sd_mode: %d\n",
 692				           __FUNCTION__, err));
 693				return BCME_ERROR;
 694			}
 695		} else if (bus->idleclock != DHD_IDLE_ACTIVE) {
 696			/* Restore clock speed */
 697			iovalue = bus->sd_divisor;
 698			err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
 699			                      &iovalue, sizeof(iovalue), TRUE);
 700			if (err) {
 701				DHD_ERROR(("%s: error restoring sd_divisor: %d\n",
 702				           __FUNCTION__, err));
 703				return BCME_ERROR;
 704			}
 705		}
 706		bus->clkstate = CLK_SDONLY;
 707	} else {
 708		/* Stop or slow the SD clock itself */
 709		if ((bus->sd_divisor == -1) || (bus->sd_mode == -1)) {
 710			DHD_TRACE(("%s: can't idle clock, divisor %d mode %d\n",
 711			           __FUNCTION__, bus->sd_divisor, bus->sd_mode));
 712			return BCME_ERROR;
 713		}
 714		if (bus->idleclock == DHD_IDLE_STOP) {
 715			if (sd1idle) {
 716				/* Change to SD1 mode and turn off clock */
 717				iovalue = 1;
 718				err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
 719				                      &iovalue, sizeof(iovalue), TRUE);
 720				if (err) {
 721					DHD_ERROR(("%s: error changing sd_clock: %d\n",
 722					           __FUNCTION__, err));
 723					return BCME_ERROR;
 724				}
 725			}
 726
 727			iovalue = 0;
 728			err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0,
 729			                      &iovalue, sizeof(iovalue), TRUE);
 730			if (err) {
 731				DHD_ERROR(("%s: error disabling sd_clock: %d\n",
 732				           __FUNCTION__, err));
 733				return BCME_ERROR;
 734			}
 735		} else if (bus->idleclock != DHD_IDLE_ACTIVE) {
 736			/* Set divisor to idle value */
 737			iovalue = bus->idleclock;
 738			err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
 739			                      &iovalue, sizeof(iovalue), TRUE);
 740			if (err) {
 741				DHD_ERROR(("%s: error changing sd_divisor: %d\n",
 742				           __FUNCTION__, err));
 743				return BCME_ERROR;
 744			}
 745		}
 746		bus->clkstate = CLK_NONE;
 747	}
 748
 749	return BCME_OK;
 750}
 751
 752/* Transition SD and backplane clock readiness */
 753static int
 754dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok)
 755{
 756	int ret = BCME_OK;
 757#ifdef DHD_DEBUG
 758	uint oldstate = bus->clkstate;
 759#endif /* DHD_DEBUG */
 760
 761	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
 762
 763	/* Early exit if we're already there */
 764	if (bus->clkstate == target) {
 765		if (target == CLK_AVAIL) {
 766			dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
 767			bus->activity = TRUE;
 768		}
 769		return ret;
 770	}
 771
 772	switch (target) {
 773	case CLK_AVAIL:
 774		/* Make sure SD clock is available */
 775		if (bus->clkstate == CLK_NONE)
 776			dhdsdio_sdclk(bus, TRUE);
 777		/* Now request HT Avail on the backplane */
 778		ret = dhdsdio_htclk(bus, TRUE, pendok);
 779		if (ret == BCME_OK) {
 780			dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
 781			bus->activity = TRUE;
 782		}
 783		break;
 784
 785	case CLK_SDONLY:
 786		/* Remove HT request, or bring up SD clock */
 787		if (bus->clkstate == CLK_NONE)
 788			ret = dhdsdio_sdclk(bus, TRUE);
 789		else if (bus->clkstate == CLK_AVAIL)
 790			ret = dhdsdio_htclk(bus, FALSE, FALSE);
 791		else
 792			DHD_ERROR(("dhdsdio_clkctl: request for %d -> %d\n",
 793			           bus->clkstate, target));
 794		if (ret == BCME_OK) {
 795			dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
 796		}
 797		break;
 798
 799	case CLK_NONE:
 800		/* Make sure to remove HT request */
 801		if (bus->clkstate == CLK_AVAIL)
 802			ret = dhdsdio_htclk(bus, FALSE, FALSE);
 803		/* Now remove the SD clock */
 804		ret = dhdsdio_sdclk(bus, FALSE);
 805#ifdef DHD_DEBUG
 806		if (dhd_console_ms == 0)
 807#endif /* DHD_DEBUG */
 808		if (bus->poll == 0)
 809			dhd_os_wd_timer(bus->dhd, 0);
 810		break;
 811	}
 812#ifdef DHD_DEBUG
 813	DHD_INFO(("dhdsdio_clkctl: %d -> %d\n", oldstate, bus->clkstate));
 814#endif /* DHD_DEBUG */
 815
 816	return ret;
 817}
 818
 819static int
 820dhdsdio_bussleep(dhd_bus_t *bus, bool sleep)
 821{
 822	bcmsdh_info_t *sdh = bus->sdh;
 823	sdpcmd_regs_t *regs = bus->regs;
 824	uint retries = 0;
 825
 826	DHD_INFO(("dhdsdio_bussleep: request %s (currently %s)\n",
 827	          (sleep ? "SLEEP" : "WAKE"),
 828	          (bus->sleeping ? "SLEEP" : "WAKE")));
 829
 830	/* Done if we're already in the requested state */
 831	if (sleep == bus->sleeping)
 832		return BCME_OK;
 833
 834	/* Going to sleep: set the alarm and turn off the lights... */
 835	if (sleep) {
 836		/* Don't sleep if something is pending */
 837		if (bus->dpc_sched || bus->rxskip || pktq_len(&bus->txq))
 838			return BCME_BUSY;
 839
 840
 841		/* Disable SDIO interrupts (no longer interested) */
 842		bcmsdh_intr_disable(bus->sdh);
 843
 844		/* Make sure the controller has the bus up */
 845		dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
 846
 847		/* Tell device to start using OOB wakeup */
 848		W_SDREG(SMB_USE_OOB, &regs->tosbmailbox, retries);
 849		if (retries > retry_limit)
 850			DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
 851
 852		/* Turn off our contribution to the HT clock request */
 853		dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
 854
 855		bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
 856		                 SBSDIO_FORCE_HW_CLKREQ_OFF, NULL);
 857
 858		/* Isolate the bus */
 859		if (bus->sih->chip != BCM4329_CHIP_ID && bus->sih->chip != BCM4319_CHIP_ID) {
 860			bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL,
 861				SBSDIO_DEVCTL_PADS_ISO, NULL);
 862		}
 863
 864		/* Change state */
 865		bus->sleeping = TRUE;
 866
 867	} else {
 868		/* Waking up: bus power up is ok, set local state */
 869
 870		bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
 871		                 0, NULL);
 872
 873		/* Force pad isolation off if possible (in case power never toggled) */
 874		bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, 0, NULL);
 875
 876
 877		/* Make sure the controller has the bus up */
 878		dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
 879
 880		/* Send misc interrupt to indicate OOB not needed */
 881		W_SDREG(0, &regs->tosbmailboxdata, retries);
 882		if (retries <= retry_limit)
 883			W_SDREG(SMB_DEV_INT, &regs->tosbmailbox, retries);
 884
 885		if (retries > retry_limit)
 886			DHD_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n"));
 887
 888		/* Make sure we have SD bus access */
 889		dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
 890
 891		/* Change state */
 892		bus->sleeping = FALSE;
 893
 894		/* Enable interrupts again */
 895		if (bus->intr && (bus->dhd->busstate == DHD_BUS_DATA)) {
 896			bus->intdis = FALSE;
 897			bcmsdh_intr_enable(bus->sdh);
 898		}
 899	}
 900
 901	return BCME_OK;
 902}
 903
 904#if defined(OOB_INTR_ONLY)
 905void
 906dhd_enable_oob_intr(struct dhd_bus *bus, bool enable)
 907{
 908#if defined(HW_OOB)
 909	bcmsdh_enable_hw_oob_intr(bus->sdh, enable);
 910#else
 911	sdpcmd_regs_t *regs = bus->regs;
 912	uint retries = 0;
 913
 914	dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
 915	if (enable == TRUE) {
 916
 917		/* Tell device to start using OOB wakeup */
 918		W_SDREG(SMB_USE_OOB, &regs->tosbmailbox, retries);
 919		if (retries > retry_limit)
 920			DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
 921
 922	} else {
 923		/* Send misc interrupt to indicate OOB not needed */
 924		W_SDREG(0, &regs->tosbmailboxdata, retries);
 925		if (retries <= retry_limit)
 926			W_SDREG(SMB_DEV_INT, &regs->tosbmailbox, retries);
 927	}
 928
 929	/* Turn off our contribution to the HT clock request */
 930	dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
 931#endif /* !defined(HW_OOB) */
 932}
 933#endif /* defined(OOB_INTR_ONLY) */
 934
 935/* Writes a HW/SW header into the packet and sends it. */
 936/* Assumes: (a) header space already there, (b) caller holds lock */
 937static int
 938dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt)
 939{
 940	int ret;
 941	osl_t *osh;
 942	uint8 *frame;
 943	uint16 len, pad1 = 0;
 944	uint32 swheader;
 945	uint retries = 0;
 946	bcmsdh_info_t *sdh;
 947	void *new;
 948	int i;
 949#ifdef WLMEDIA_HTSF
 950	char *p;
 951	htsfts_t *htsf_ts;
 952#endif
 953
 954
 955	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
 956
 957	sdh = bus->sdh;
 958	osh = bus->dhd->osh;
 959
 960	if (bus->dhd->dongle_reset) {
 961		ret = BCME_NOTREADY;
 962		goto done;
 963	}
 964
 965	frame = (uint8*)PKTDATA(osh, pkt);
 966
 967#ifdef WLMEDIA_HTSF
 968	if (PKTLEN(osh, pkt) >= 100) {
 969		p = PKTDATA(osh, pkt);
 970		htsf_ts = (htsfts_t*) (p + HTSF_HOSTOFFSET + 12);
 971		if (htsf_ts->magic == HTSFMAGIC) {
 972			htsf_ts->c20 = get_cycles();
 973			htsf_ts->t20 = dhd_get_htsf(bus->dhd->info, 0);
 974		}
 975	}
 976#endif /* WLMEDIA_HTSF */
 977
 978	/* Add alignment padding, allocate new packet if needed */
 979	if ((pad1 = ((uintptr)frame % DHD_SDALIGN))) {
 980		if (PKTHEADROOM(osh, pkt) < pad1) {
 981			DHD_INFO(("%s: insufficient headroom %d for %d pad1\n",
 982			          __FUNCTION__, (int)PKTHEADROOM(osh, pkt), pad1));
 983			bus->dhd->tx_realloc++;
 984			new = PKTGET(osh, (PKTLEN(osh, pkt) + DHD_SDALIGN), TRUE);
 985			if (!new) {
 986				DHD_ERROR(("%s: couldn't allocate new %d-byte packet\n",
 987				           __FUNCTION__, PKTLEN(osh, pkt) + DHD_SDALIGN));
 988				ret = BCME_NOMEM;
 989				goto done;
 990			}
 991
 992			PKTALIGN(osh, new, PKTLEN(osh, pkt), DHD_SDALIGN);
 993			bcopy(PKTDATA(osh, pkt), PKTDATA(osh, new), PKTLEN(osh, pkt));
 994			if (free_pkt)
 995				PKTFREE(osh, pkt, TRUE);
 996			/* free the pkt if canned one is not used */
 997			free_pkt = TRUE;
 998			pkt = new;
 999			frame = (uint8*)PKTDATA(osh, pkt);
1000			ASSERT(((uintptr)frame % DHD_SDALIGN) == 0);
1001			pad1 = 0;
1002		} else {
1003			PKTPUSH(osh, pkt, pad1);
1004			frame = (uint8*)PKTDATA(osh, pkt);
1005
1006			ASSERT((pad1 + SDPCM_HDRLEN) <= (int) PKTLEN(osh, pkt));
1007			bzero(frame, pad1 + SDPCM_HDRLEN);
1008		}
1009	}
1010	ASSERT(pad1 < DHD_SDALIGN);
1011
1012	/* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
1013	len = (uint16)PKTLEN(osh, pkt);
1014	*(uint16*)frame = htol16(len);
1015	*(((uint16*)frame) + 1) = htol16(~len);
1016
1017	/* Software tag: channel, sequence number, data offset */
1018	swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) | bus->tx_seq |
1019	        (((pad1 + SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
1020	htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN);
1021	htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
1022
1023#ifdef DHD_DEBUG
1024	if (PKTPRIO(pkt) < ARRAYSIZE(tx_packets)) {
1025		tx_packets[PKTPRIO(pkt)]++;
1026	}
1027	if (DHD_BYTES_ON() &&
1028	    (((DHD_CTL_ON() && (chan == SDPCM_CONTROL_CHANNEL)) ||
1029	      (DHD_DATA_ON() && (chan != SDPCM_CONTROL_CHANNEL))))) {
1030		prhex("Tx Frame", frame, len);
1031	} else if (DHD_HDRS_ON()) {
1032		prhex("TxHdr", frame, MIN(len, 16));
1033	}
1034#endif
1035
1036	/* Raise len to next SDIO block to eliminate tail command */
1037	if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
1038		uint16 pad2 = bus->blocksize - (len % bus->blocksize);
1039		if ((pad2 <= bus->roundup) && (pad2 < bus->blocksize))
1040#ifdef NOTUSED
1041			if (pad2 <= PKTTAILROOM(osh, pkt))
1042#endif /* NOTUSED */
1043				len += pad2;
1044	} else if (len % DHD_SDALIGN) {
1045		len += DHD_SDALIGN - (len % DHD_SDALIGN);
1046	}
1047
1048	/* Some controllers have trouble with odd bytes -- round to even */
1049	if (forcealign && (len & (ALIGNMENT - 1))) {
1050#ifdef NOTUSED
1051		if (PKTTAILROOM(osh, pkt))
1052#endif
1053			len = ROUNDUP(len, ALIGNMENT);
1054#ifdef NOTUSED
1055		else
1056			DHD_ERROR(("%s: sending unrounded %d-byte packet\n", __FUNCTION__, len));
1057#endif
1058	}
1059
1060	do {
1061		ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
1062		                          frame, len, pkt, NULL, NULL);
1063		bus->f2txdata++;
1064		ASSERT(ret != BCME_PENDING);
1065
1066		if (ret < 0) {
1067			/* On failure, abort the command and terminate the frame */
1068			DHD_INFO(("%s: sdio error %d, abort command and terminate frame.\n",
1069			          __FUNCTION__, ret));
1070			bus->tx_sderrs++;
1071
1072			bcmsdh_abort(sdh, SDIO_FUNC_2);
1073			bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
1074			                 SFC_WF_TERM, NULL);
1075			bus->f1regdata++;
1076
1077			for (i = 0; i < 3; i++) {
1078				uint8 hi, lo;
1079				hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
1080				                     SBSDIO_FUNC1_WFRAMEBCHI, NULL);
1081				lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
1082				                     SBSDIO_FUNC1_WFRAMEBCLO, NULL);
1083				bus->f1regdata += 2;
1084				if ((hi == 0) && (lo == 0))
1085					break;
1086			}
1087
1088		}
1089		if (ret == 0) {
1090			bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
1091		}
1092	} while ((ret < 0) && retrydata && retries++ < TXRETRIES);
1093
1094done:
1095	/* restore pkt buffer pointer before calling tx complete routine */
1096	PKTPULL(osh, pkt, SDPCM_HDRLEN + pad1);
1097#ifdef PROP_TXSTATUS
1098	if (bus->dhd->wlfc_state) {
1099		dhd_os_sdunlock(bus->dhd);
1100		dhd_wlfc_txcomplete(bus->dhd, pkt, ret == 0);
1101		dhd_os_sdlock(bus->dhd);
1102	} else {
1103#endif /* PROP_TXSTATUS */
1104	dhd_txcomplete(bus->dhd, pkt, ret != 0);
1105	if (free_pkt)
1106		PKTFREE(osh, pkt, TRUE);
1107
1108#ifdef PROP_TXSTATUS
1109	}
1110#endif
1111	return ret;
1112}
1113
1114int
1115dhd_bus_txdata(struct dhd_bus *bus, void *pkt)
1116{
1117	int ret = BCME_ERROR;
1118	osl_t *osh;
1119	uint datalen, prec;
1120
1121	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1122
1123	osh = bus->dhd->osh;
1124	datalen = PKTLEN(osh, pkt);
1125
1126#ifdef SDTEST
1127	/* Push the test header if doing loopback */
1128	if (bus->ext_loop) {
1129		uint8* data;
1130		PKTPUSH(osh, pkt, SDPCM_TEST_HDRLEN);
1131		data = PKTDATA(osh, pkt);
1132		*data++ = SDPCM_TEST_ECHOREQ;
1133		*data++ = (uint8)bus->loopid++;
1134		*data++ = (datalen >> 0);
1135		*data++ = (datalen >> 8);
1136		datalen += SDPCM_TEST_HDRLEN;
1137	}
1138#endif /* SDTEST */
1139
1140	/* Add space for the header */
1141	PKTPUSH(osh, pkt, SDPCM_HDRLEN);
1142	ASSERT(ISALIGNED((uintptr)PKTDATA(osh, pkt), 2));
1143
1144	prec = PRIO2PREC((PKTPRIO(pkt) & PRIOMASK));
1145#ifndef DHDTHREAD
1146	/* Lock: we're about to use shared data/code (and SDIO) */
1147	dhd_os_sdlock(bus->dhd);
1148#endif /* DHDTHREAD */
1149
1150	/* Check for existing queue, current flow-control, pending event, or pending clock */
1151	if (dhd_deferred_tx || bus->fcstate || pktq_len(&bus->txq) || bus->dpc_sched ||
1152	    (!DATAOK(bus)) || (bus->flowcontrol & NBITVAL(prec)) ||
1153	    (bus->clkstate != CLK_AVAIL)) {
1154		DHD_TRACE(("%s: deferring pktq len %d\n", __FUNCTION__,
1155			pktq_len(&bus->txq)));
1156		bus->fcqueued++;
1157
1158		/* Priority based enq */
1159		dhd_os_sdlock_txq(bus->dhd);
1160		if (dhd_prec_enq(bus->dhd, &bus->txq, pkt, prec) == FALSE) {
1161			PKTPULL(osh, pkt, SDPCM_HDRLEN);
1162#ifndef DHDTHREAD
1163			/* Need to also release txqlock before releasing sdlock.
1164			 * This thread still has txqlock and releases sdlock.
1165			 * Deadlock happens when dpc() grabs sdlock first then
1166			 * attempts to grab txqlock.
1167			 */
1168			dhd_os_sdunlock_txq(bus->dhd);
1169			dhd_os_sdunlock(bus->dhd);
1170#endif
1171#ifdef PROP_TXSTATUS
1172			if (bus->dhd->wlfc_state)
1173				dhd_wlfc_txcomplete(bus->dhd, pkt, FALSE);
1174			else
1175#endif
1176			dhd_txcomplete(bus->dhd, pkt, FALSE);
1177#ifndef DHDTHREAD
1178			dhd_os_sdlock(bus->dhd);
1179			dhd_os_sdlock_txq(bus->dhd);
1180#endif
1181#ifdef PROP_TXSTATUS
1182			/* let the caller decide whether to free the packet */
1183		if (!bus->dhd->wlfc_state)
1184#endif
1185			PKTFREE(osh, pkt, TRUE);
1186			ret = BCME_NORESOURCE;
1187		}
1188		else
1189			ret = BCME_OK;
1190		dhd_os_sdunlock_txq(bus->dhd);
1191
1192		if ((pktq_len(&bus->txq) >= FCHI) && dhd_doflow)
1193			dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON);
1194
1195#ifdef DHD_DEBUG
1196		if (pktq_plen(&bus->txq, prec) > qcount[prec])
1197			qcount[prec] = pktq_plen(&bus->txq, prec);
1198#endif
1199		/* Schedule DPC if needed to send queued packet(s) */
1200		if (dhd_deferred_tx && !bus->dpc_sched) {
1201			bus->dpc_sched = TRUE;
1202			dhd_sched_dpc(bus->dhd);
1203		}
1204	} else {
1205#ifdef DHDTHREAD
1206		/* Lock: we're about to use shared data/code (and SDIO) */
1207		dhd_os_sdlock(bus->dhd);
1208#endif /* DHDTHREAD */
1209
1210		/* Otherwise, send it now */
1211		BUS_WAKE(bus);
1212		/* Make sure back plane ht clk is on, no pending allowed */
1213		dhdsdio_clkctl(bus, CLK_AVAIL, TRUE);
1214#ifndef SDTEST
1215		ret = dhdsdio_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, TRUE);
1216#else
1217		ret = dhdsdio_txpkt(bus, pkt,
1218		        (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL), TRUE);
1219#endif
1220		if (ret)
1221			bus->dhd->tx_errors++;
1222		else
1223			bus->dhd->dstats.tx_bytes += datalen;
1224
1225		if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
1226			bus->activity = FALSE;
1227			dhdsdio_clkctl(bus, CLK_NONE, TRUE);
1228		}
1229
1230#ifdef DHDTHREAD
1231		dhd_os_sdunlock(bus->dhd);
1232#endif /* DHDTHREAD */
1233	}
1234
1235#ifndef DHDTHREAD
1236	dhd_os_sdunlock(bus->dhd);
1237#endif /* DHDTHREAD */
1238
1239	return ret;
1240}
1241
1242static uint
1243dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes)
1244{
1245	void *pkt;
1246	uint32 intstatus = 0;
1247	uint retries = 0;
1248	int ret = 0, prec_out;
1249	uint cnt = 0;
1250	uint datalen;
1251	uint8 tx_prec_map;
1252
1253	dhd_pub_t *dhd = bus->dhd;
1254	sdpcmd_regs_t *regs = bus->regs;
1255
1256	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1257
1258	tx_prec_map = ~bus->flowcontrol;
1259
1260	/* Send frames until the limit or some other event */
1261	for (cnt = 0; (cnt < maxframes) && DATAOK(bus); cnt++) {
1262		dhd_os_sdlock_txq(bus->dhd);
1263		if ((pkt = pktq_mdeq(&bus->txq, tx_prec_map, &prec_out)) == NULL) {
1264			dhd_os_sdunlock_txq(bus->dhd);
1265			break;
1266		}
1267		dhd_os_sdunlock_txq(bus->dhd);
1268		datalen = PKTLEN(bus->dhd->osh, pkt) - SDPCM_HDRLEN;
1269
1270#ifndef SDTEST
1271		ret = dhdsdio_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, TRUE);
1272#else
1273		ret = dhdsdio_txpkt(bus, pkt,
1274		        (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL), TRUE);
1275#endif
1276		if (ret)
1277			bus->dhd->tx_errors++;
1278		else
1279			bus->dhd->dstats.tx_bytes += datalen;
1280
1281		/* In poll mode, need to check for other events */
1282		if (!bus->intr && cnt)
1283		{
1284			/* Check device status, signal pending interrupt */
1285			R_SDREG(intstatus, &regs->intstatus, retries);
1286			bus->f2txdata++;
1287			if (bcmsdh_regfail(bus->sdh))
1288				break;
1289			if (intstatus & bus->hostintmask)
1290				bus->ipend = TRUE;
1291		}
1292	}
1293
1294	/* Deflow-control stack if needed */
1295	if (dhd_doflow && dhd->up && (dhd->busstate == DHD_BUS_DATA) &&
1296	    dhd->txoff && (pktq_len(&bus->txq) < FCLOW))
1297		dhd_txflowcontrol(dhd, ALL_INTERFACES, OFF);
1298
1299	return cnt;
1300}
1301
1302int
1303dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen)
1304{
1305	uint8 *frame;
1306	uint16 len;
1307	uint32 swheader;
1308	uint retries = 0;
1309	bcmsdh_info_t *sdh = bus->sdh;
1310	uint8 doff = 0;
1311	int ret = -1;
1312	int i;
1313
1314	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1315
1316	if (bus->dhd->dongle_reset)
1317		return -EIO;
1318
1319	/* Back the pointer to make a room for bus header */
1320	frame = msg - SDPCM_HDRLEN;
1321	len = (msglen += SDPCM_HDRLEN);
1322
1323	/* Add alignment padding (optional for ctl frames) */
1324	if (dhd_alignctl) {
1325		if ((doff = ((uintptr)frame % DHD_SDALIGN))) {
1326			frame -= doff;
1327			len += doff;
1328			msglen += doff;
1329			bzero(frame, doff + SDPCM_HDRLEN);
1330		}
1331		ASSERT(doff < DHD_SDALIGN);
1332	}
1333	doff += SDPCM_HDRLEN;
1334
1335	/* Round send length to next SDIO block */
1336	if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
1337		uint16 pad = bus->blocksize - (len % bus->blocksize);
1338		if ((pad <= bus->roundup) && (pad < bus->blocksize))
1339			len += pad;
1340	} else if (len % DHD_SDALIGN) {
1341		len += DHD_SDALIGN - (len % DHD_SDALIGN);
1342	}
1343
1344	/* Satisfy length-alignment requirements */
1345	if (forcealign && (len & (ALIGNMENT - 1)))
1346		len = ROUNDUP(len, ALIGNMENT);
1347
1348	ASSERT(ISALIGNED((uintptr)frame, 2));
1349
1350
1351	/* Need to lock here to protect txseq and SDIO tx calls */
1352	dhd_os_sdlock(bus->dhd);
1353
1354	BUS_WAKE(bus);
1355
1356	/* Make sure backplane clock is on */
1357	dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
1358
1359	/* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
1360	*(uint16*)frame = htol16((uint16)msglen);
1361	*(((uint16*)frame) + 1) = htol16(~msglen);
1362
1363	/* Software tag: channel, sequence number, data offset */
1364	swheader = ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK)
1365	        | bus->tx_seq | ((doff << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
1366	htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN);
1367	htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
1368
1369	if (!TXCTLOK(bus)) {
1370		DHD_INFO(("%s: No bus credit bus->tx_max %d, bus->tx_seq %d\n",
1371			__FUNCTION__, bus->tx_max, bus->tx_seq));
1372		bus->ctrl_frame_stat = TRUE;
1373		/* Send from dpc */
1374		bus->ctrl_frame_buf = frame;
1375		bus->ctrl_frame_len = len;
1376		dhd_wait_for_event(bus->dhd, &bus->ctrl_frame_stat);
1377		if (bus->ctrl_frame_stat == FALSE) {
1378			DHD_INFO(("%s: ctrl_frame_stat == FALSE\n", __FUNCTION__));
1379			ret = 0;
1380		} else {
1381			bus->dhd->txcnt_timeout++;
1382			if (!bus->dhd->hang_was_sent)
1383				DHD_ERROR(("%s: ctrl_frame_stat == TRUE txcnt_timeout=%d\n",
1384					__FUNCTION__, bus->dhd->txcnt_timeout));
1385			ret = -1;
1386			bus->ctrl_frame_stat = FALSE;
1387			goto done;
1388		}
1389	}
1390
1391	bus->dhd->txcnt_timeout = 0;
1392
1393	if (ret == -1) {
1394#ifdef DHD_DEBUG
1395		if (DHD_BYTES_ON() && DHD_CTL_ON()) {
1396			prhex("Tx Frame", frame, len);
1397		} else if (DHD_HDRS_ON()) {
1398			prhex("TxHdr", frame, MIN(len, 16));
1399		}
1400#endif
1401
1402		do {
1403			ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
1404			                          frame, len, NULL, NULL, NULL);
1405			ASSERT(ret != BCME_PENDING);
1406
1407			if (ret < 0) {
1408			/* On failure, abort the command and terminate the frame */
1409				DHD_INFO(("%s: sdio error %d, abort command and terminate frame.\n",
1410				          __FUNCTION__, ret));
1411				bus->tx_sderrs++;
1412
1413				bcmsdh_abort(sdh, SDIO_FUNC_2);
1414
1415				bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
1416				                 SFC_WF_TERM, NULL);
1417				bus->f1regdata++;
1418
1419				for (i = 0; i < 3; i++) {
1420					uint8 hi, lo;
1421					hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
1422					                     SBSDIO_FUNC1_WFRAMEBCHI, NULL);
1423					lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
1424					                     SBSDIO_FUNC1_WFRAMEBCLO, NULL);
1425					bus->f1regdata += 2;
1426					if ((hi == 0) && (lo == 0))
1427						break;
1428				}
1429
1430			}
1431			if (ret == 0) {
1432				bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
1433			}
1434		} while ((ret < 0) && retries++ < TXRETRIES);
1435	}
1436
1437done:
1438	if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
1439		bus->activity = FALSE;
1440		dhdsdio_clkctl(bus, CLK_NONE, TRUE);
1441	}
1442
1443	dhd_os_sdunlock(bus->dhd);
1444
1445	if (ret)
1446		bus->dhd->tx_ctlerrs++;
1447	else
1448		bus->dhd->tx_ctlpkts++;
1449
1450	if (bus->dhd->txcnt_timeout >= MAX_CNTL_TIMEOUT)
1451		return -ETIMEDOUT;
1452
1453	return ret ? -EIO : 0;
1454}
1455
1456int
1457dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen)
1458{
1459	int timeleft;
1460	uint rxlen = 0;
1461	bool pending = FALSE;
1462
1463	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1464
1465	if (bus->dhd->dongle_reset)
1466		return -EIO;
1467
1468	/* Wait until control frame is available */
1469	timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->rxlen, &pending);
1470
1471	dhd_os_sdlock(bus->dhd);
1472	rxlen = bus->rxlen;
1473	bcopy(bus->rxctl, msg, MIN(msglen, rxlen));
1474	bus->rxlen = 0;
1475	dhd_os_sdunlock(bus->dhd);
1476
1477	if (rxlen) {
1478		DHD_CTL(("%s: resumed on rxctl frame, got %d expected %d\n",
1479		         __FUNCTION__, rxlen, msglen));
1480	} else if (timeleft == 0) {
1481		DHD_ERROR(("%s: resumed on timeout\n", __FUNCTION__));
1482#ifdef DHD_DEBUG
1483		dhd_os_sdlock(bus->dhd);
1484		dhdsdio_checkdied(bus, NULL, 0);
1485		dhd_os_sdunlock(bus->dhd);
1486#endif /* DHD_DEBUG */
1487	} else if (pending == TRUE) {
1488		/* signal pending */
1489		DHD_ERROR(("%s: signal pending\n", __FUNCTION__));
1490		return -EINTR;
1491	} else {
1492		DHD_CTL(("%s: resumed for unknown reason?\n", __FUNCTION__));
1493#ifdef DHD_DEBUG
1494		dhd_os_sdlock(bus->dhd);
1495		dhdsdio_checkdied(bus, NULL, 0);
1496		dhd_os_sdunlock(bus->dhd);
1497#endif /* DHD_DEBUG */
1498	}
1499	if (timeleft == 0) {
1500		bus->dhd->rxcnt_timeout++;
1501		DHD_ERROR(("%s: rxcnt_timeout=%d\n", __FUNCTION__, bus->dhd->rxcnt_timeout));
1502	}
1503	else
1504		bus->dhd->rxcnt_timeout = 0;
1505
1506	if (rxlen)
1507		bus->dhd->rx_ctlpkts++;
1508	else
1509		bus->dhd->rx_ctlerrs++;
1510
1511	if (bus->dhd->rxcnt_timeout >= MAX_CNTL_TIMEOUT)
1512		return -ETIMEDOUT;
1513
1514	return rxlen ? (int)rxlen : -EIO;
1515}
1516
1517/* IOVar table */
1518enum {
1519	IOV_INTR = 1,
1520	IOV_POLLRATE,
1521	IOV_SDREG,
1522	IOV_SBREG,
1523	IOV_SDCIS,
1524	IOV_MEMBYTES,
1525	IOV_MEMSIZE,
1526#ifdef DHD_DEBUG
1527	IOV_CHECKDIED,
1528	IOV_SERIALCONS,
1529#endif /* DHD_DEBUG */
1530	IOV_DOWNLOAD,
1531	IOV_SOCRAM_STATE,
1532	IOV_FORCEEVEN,
1533	IOV_SDIOD_DRIVE,
1534	IOV_READAHEAD,
1535	IOV_SDRXCHAIN,
1536	IOV_ALIGNCTL,
1537	IOV_SDALIGN,
1538	IOV_DEVRESET,
1539	IOV_CPU,
1540#ifdef SDTEST
1541	IOV_PKTGEN,
1542	IOV_EXTLOOP,
1543#endif /* SDTEST */
1544	IOV_SPROM,
1545	IOV_TXBOUND,
1546	IOV_RXBOUND,
1547	IOV_TXMINMAX,
1548	IOV_IDLETIME,
1549	IOV_IDLECLOCK,
1550	IOV_SD1IDLE,
1551	IOV_SLEEP,
1552	IOV_DONGLEISOLATION,
1553	IOV_VARS,
1554#ifdef SOFTAP
1555	IOV_FWPATH
1556#endif
1557};
1558
1559const bcm_iovar_t dhdsdio_iovars[] = {
1560	{"intr",	IOV_INTR,	0,	IOVT_BOOL,	0 },
1561	{"sleep",	IOV_SLEEP,	0,	IOVT_BOOL,	0 },
1562	{"pollrate",	IOV_POLLRATE,	0,	IOVT_UINT32,	0 },
1563	{"idletime",	IOV_IDLETIME,	0,	IOVT_INT32,	0 },
1564	{"idleclock",	IOV_IDLECLOCK,	0,	IOVT_INT32,	0 },
1565	{"sd1idle",	IOV_SD1IDLE,	0,	IOVT_BOOL,	0 },
1566	{"membytes",	IOV_MEMBYTES,	0,	IOVT_BUFFER,	2 * sizeof(int) },
1567	{"memsize",	IOV_MEMSIZE,	0,	IOVT_UINT32,	0 },
1568	{"download",	IOV_DOWNLOAD,	0,	IOVT_BOOL,	0 },
1569	{"socram_state",	IOV_SOCRAM_STATE,	0,	IOVT_BOOL,	0 },
1570	{"vars",	IOV_VARS,	0,	IOVT_BUFFER,	0 },
1571	{"sdiod_drive",	IOV_SDIOD_DRIVE, 0,	IOVT_UINT32,	0 },
1572	{"readahead",	IOV_READAHEAD,	0,	IOVT_BOOL,	0 },
1573	{"sdrxchain",	IOV_SDRXCHAIN,	0,	IOVT_BOOL,	0 },
1574	{"alignctl",	IOV_ALIGNCTL,	0,	IOVT_BOOL,	0 },
1575	{"sdalign",	IOV_SDALIGN,	0,	IOVT_BOOL,	0 },
1576	{"devreset",	IOV_DEVRESET,	0,	IOVT_BOOL,	0 },
1577#ifdef DHD_DEBUG
1578	{"sdreg",	IOV_SDREG,	0,	IOVT_BUFFER,	sizeof(sdreg_t) },
1579	{"sbreg",	IOV_SBREG,	0,	IOVT_BUFFER,	sizeof(sdreg_t) },
1580	{"sd_cis",	IOV_SDCIS,	0,	IOVT_BUFFER,	DHD_IOCTL_MAXLEN },
1581	{"forcealign",	IOV_FORCEEVEN,	0,	IOVT_BOOL,	0 },
1582	{"txbound",	IOV_TXBOUND,	0,	IOVT_UINT32,	0 },
1583	{"rxbound",	IOV_RXBOUND,	0,	IOVT_UINT32,	0 },
1584	{"txminmax",	IOV_TXMINMAX,	0,	IOVT_UINT32,	0 },
1585	{"cpu",		IOV_CPU,	0,	IOVT_BOOL,	0 },
1586#ifdef DHD_DEBUG
1587	{"checkdied",	IOV_CHECKDIED,	0,	IOVT_BUFFER,	0 },
1588	{"serial",	IOV_SERIALCONS,	0,	IOVT_UINT32,	0 },
1589#endif /* DHD_DEBUG  */
1590#endif /* DHD_DEBUG */
1591#ifdef SDTEST
1592	{"extloop",	IOV_EXTLOOP,	0,	IOVT_BOOL,	0 },
1593	{"pktgen",	IOV_PKTGEN,	0,	IOVT_BUFFER,	sizeof(dhd_pktgen_t) },
1594#endif /* SDTEST */
1595	{"dngl_isolation", IOV_DONGLEISOLATION,	0,	IOVT_UINT32,	0 },
1596#ifdef SOFTAP
1597	{"fwpath", IOV_FWPATH, 0, IOVT_BUFFER, 0 },
1598#endif
1599	{NULL, 0, 0, 0, 0 }
1600};
1601
1602static void
1603dhd_dump_pct(struct bcmstrbuf *strbuf, char *desc, uint num, uint div)
1604{
1605	uint q1, q2;
1606
1607	if (!div) {
1608		bcm_bprintf(strbuf, "%s N/A", desc);
1609	} else {
1610		q1 = num / div;
1611		q2 = (100 * (num - (q1 * div))) / div;
1612		bcm_bprintf(strbuf, "%s %d.%02d", desc, q1, q2);
1613	}
1614}
1615
1616void
1617dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf)
1618{
1619	dhd_bus_t *bus = dhdp->bus;
1620
1621	bcm_bprintf(strbuf, "Bus SDIO structure:\n");
1622	bcm_bprintf(strbuf, "hostintmask 0x%08x intstatus 0x%08x sdpcm_ver %d\n",
1623	            bus->hostintmask, bus->intstatus, bus->sdpcm_ver);
1624	bcm_bprintf(strbuf, "fcstate %d qlen %d tx_seq %d, max %d, rxskip %d rxlen %d rx_seq %d\n",
1625	            bus->fcstate, pktq_len(&bus->txq), bus->tx_seq, bus->tx_max, bus->rxskip,
1626	            bus->rxlen, bus->rx_seq);
1627	bcm_bprintf(strbuf, "intr %d intrcount %d lastintrs %d spurious %d\n",
1628	            bus->intr, bus->intrcount, bus->lastintrs, bus->spurious);
1629	bcm_bprintf(strbuf, "pollrate %d pollcnt %d regfails %d\n",
1630	            bus->pollrate, bus->pollcnt, bus->regfails);
1631
1632	bcm_bprintf(strbuf, "\nAdditional counters:\n");
1633	bcm_bprintf(strbuf, "tx_sderrs %d fcqueued %d rxrtx %d rx_toolong %d rxc_errors %d\n",
1634	            bus->tx_sderrs, bus->fcqueued, bus->rxrtx, bus->rx_toolong,
1635	            bus->rxc_errors);
1636	bcm_bprintf(strbuf, "rx_hdrfail %d badhdr %d badseq %d\n",
1637	            bus->rx_hdrfail, bus->rx_badhdr, bus->rx_badseq);
1638	bcm_bprintf(strbuf, "fc_rcvd %d, fc_xoff %d, fc_xon %d\n",
1639	            bus->fc_rcvd, bus->fc_xoff, bus->fc_xon);
1640	bcm_bprintf(strbuf, "rxglomfail %d, rxglomframes %d, rxglompkts %d\n",
1641	            bus->rxglomfail, bus->rxglomframes, bus->rxglompkts);
1642	bcm_bprintf(strbuf, "f2rx (hdrs/data) %d (%d/%d), f2tx %d f1regs %d\n",
1643	            (bus->f2rxhdrs + bus->f2rxdata), bus->f2rxhdrs, bus->f2rxdata,
1644	            bus->f2txdata, bus->f1regdata);
1645	{
1646		dhd_dump_pct(strbuf, "\nRx: pkts/f2rd", bus->dhd->rx_packets,
1647		             (bus->f2rxhdrs + bus->f2rxdata));
1648		dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->rx_packets, bus->f1regdata);
1649		dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->rx_packets,
1650		             (bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata));
1651		dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->rx_packets, bus->intrcount);
1652		bcm_bprintf(strbuf, "\n");
1653
1654		dhd_dump_pct(strbuf, "Rx: glom pct", (100 * bus->rxglompkts),
1655		             bus->dhd->rx_packets);
1656		dhd_dump_pct(strbuf, ", pkts/glom", bus->rxglompkts, bus->rxglomframes);
1657		bcm_bprintf(strbuf, "\n");
1658
1659		dhd_dump_pct(strbuf, "Tx: pkts/f2wr", bus->dhd->tx_packets, bus->f2txdata);
1660		dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->tx_packets, bus->f1regdata);
1661		dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->tx_packets,
1662		             (bus->f2txdata + bus->f1regdata));
1663		dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->tx_packets, bus->intrcount);
1664		bcm_bprintf(strbuf, "\n");
1665
1666		dhd_dump_pct(strbuf, "Total: pkts/f2rw",
1667		             (bus->dhd->tx_packets + bus->dhd->rx_packets),
1668		             (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata));
1669		dhd_dump_pct(strbuf, ", pkts/f1sd",
1670		             (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->f1regdata);
1671		dhd_dump_pct(strbuf, ", pkts/sd",
1672		             (bus->dhd->tx_packets + bus->dhd->rx_packets),
1673		             (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata));
1674		dhd_dump_pct(strbuf, ", pkts/int",
1675		             (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->intrcount);
1676		bcm_bprintf(strbuf, "\n\n");
1677	}
1678
1679#ifdef SDTEST
1680	if (bus->pktgen_count) {
1681		bcm_bprintf(strbuf, "pktgen config and count:\n");
1682		bcm_bprintf(strbuf, "freq %d count %d print %d total %d min %d len %d\n",
1683		            bus->pktgen_freq, bus->pktgen_count, bus->pktgen_print,
1684		            bus->pktgen_total, bus->pktgen_minlen, bus->pktgen_maxlen);
1685		bcm_bprintf(strbuf, "send attempts %d rcvd %d fail %d\n",
1686		            bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail);
1687	}
1688#endif /* SDTEST */
1689#ifdef DHD_DEBUG
1690	bcm_bprintf(strbuf, "dpc_sched %d host interrupt%spending\n",
1691	            bus->dpc_sched, (bcmsdh_intr_pending(bus->sdh) ? " " : " not "));
1692	bcm_bprintf(strbuf, "blocksize %d roundup %d\n", bus->blocksize, bus->roundup);
1693#endif /* DHD_DEBUG */
1694	bcm_bprintf(strbuf, "clkstate %d activity %d idletime %d idlecount %d sleeping %d\n",
1695	            bus->clkstate, bus->activity, bus->idletime, bus->idlecount, bus->sleeping);
1696}
1697
1698void
1699dhd_bus_clearcounts(dhd_pub_t *dhdp)
1700{
1701	dhd_bus_t *bus = (dhd_bus_t *)dhdp->bus;
1702
1703	bus->intrcount = bus->lastintrs = bus->spurious = bus->regfails = 0;
1704	bus->rxrtx = bus->rx_toolong = bus->rxc_errors = 0;
1705	bus->rx_hdrfail = bus->rx_badhdr = bus->rx_badseq = 0;
1706	bus->tx_sderrs = bus->fc_rcvd = bus->fc_xoff = bus->fc_xon = 0;
1707	bus->rxglomfail = bus->rxglomframes = bus->rxglompkts = 0;
1708	bus->f2rxhdrs = bus->f2rxdata = bus->f2txdata = bus->f1regdata = 0;
1709}
1710
1711#ifdef SDTEST
1712static int
1713dhdsdio_pktgen_get(dhd_bus_t *bus, uint8 *arg)
1714{
1715	dhd_pktgen_t pktgen;
1716
1717	pktgen.version = DHD_PKTGEN_VERSION;
1718	pktgen.freq = bus->pktgen_freq;
1719	pktgen.count = bus->pktgen_count;
1720	pktgen.print = bus->pktgen_print;
1721	pktgen.total = bus->pktgen_total;
1722	pktgen.minlen = bus->pktgen_minlen;
1723	pktgen.maxlen = bus->pktgen_maxlen;
1724	pktgen.numsent = bus->pktgen_sent;
1725	pktgen.numrcvd = bus->pktgen_rcvd;
1726	pktgen.numfail = bus->pktgen_fail;
1727	pktgen.mode = bus->pktgen_mode;
1728	pktgen.stop = bus->pktgen_stop;
1729
1730	bcopy(&pktgen, arg, sizeof(pktgen));
1731
1732	return 0;
1733}
1734
1735static int
1736dhdsdio_pktgen_set(dhd_bus_t *bus, uint8 *arg)
1737{
1738	dhd_pktgen_t pktgen;
1739	uint oldcnt, oldmode;
1740
1741	bcopy(arg, &pktgen, sizeof(pktgen));
1742	if (pktgen.version != DHD_PKTGEN_VERSION)
1743		return BCME_BADARG;
1744
1745	oldcnt = bus->pktgen_count;
1746	oldmode = bus->pktgen_mode;
1747
1748	bus->pktgen_freq = pktgen.freq;
1749	bus->pktgen_count = pktgen.count;
1750	bus->pktgen_print = pktgen.print;
1751	bus->pktgen_total = pktgen.total;
1752	bus->pktgen_minlen = pktgen.minlen;
1753	bus->pktgen_maxlen = pktgen.maxlen;
1754	bus->pktgen_mode = pktgen.mode;
1755	bus->pktgen_stop = pktgen.stop;
1756
1757	bus->pktgen_tick = bus->pktgen_ptick = 0;
1758	bus->pktgen_len = MAX(bus->pktgen_len, bus->pktgen_minlen);
1759	bus->pktgen_len = MIN(bus->pktgen_len, bus->pktgen_maxlen);
1760
1761	/* Clear counts for a new pktgen (mode change, or was stopped) */
1762	if (bus->pktgen_count && (!oldcnt || oldmode != bus->pktgen_mode))
1763		bus->pktgen_sent = bus->pktgen_rcvd = bus->pktgen_fail = 0;
1764
1765	return 0;
1766}
1767#endif /* SDTEST */
1768
1769static int
1770dhdsdio_membytes(dhd_bus_t *bus, bool write, uint32 address, uint8 *data, uint size)
1771{
1772	int bcmerror = 0;
1773	uint32 sdaddr;
1774	uint dsize;
1775
1776	/* Determine initial transfer parameters */
1777	sdaddr = address & SBSDIO_SB_OFT_ADDR_MASK;
1778	if ((sdaddr + size) & SBSDIO_SBWINDOW_MASK)
1779		dsize = (SBSDIO_SB_OFT_ADDR_LIMIT - sdaddr);
1780	else
1781		dsize = size;
1782
1783	/* Set the backplane window to include the start address */
1784	if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) {
1785		DHD_ERROR(("%s: window change failed\n", __FUNCTION__));
1786		goto xfer_done;
1787	}
1788
1789	/* Do the transfer(s) */
1790	while (size) {
1791		DHD_INFO(("%s: %s %d bytes at offset 0x%08x in window 0x%08x\n",
1792		          __FUNCTION__, (write ? "write" : "read"), dsize, sdaddr,
1793		          (address & SBSDIO_SBWINDOW_MASK)));
1794		if ((bcmerror = bcmsdh_rwdata(bus->sdh, write, sdaddr, data, dsize))) {
1795			DHD_ERROR(("%s: membytes transfer failed\n", __FUNCTION__));
1796			break;
1797		}
1798
1799		/* Adjust for next transfer (if any) */
1800		if ((size -= dsize)) {
1801			data += dsize;
1802			address += dsize;
1803			if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) {
1804				DHD_ERROR(("%s: window change failed\n", __FUNCTION__));
1805				break;
1806			}
1807			sdaddr = 0;
1808			dsize = MIN(SBSDIO_SB_OFT_ADDR_LIMIT, size);
1809		}
1810
1811	}
1812
1813xfer_done:
1814	/* Return the window to backplane enumeration space for core access */
1815	if (dhdsdio_set_siaddr_window(bus, bcmsdh_cur_sbwad(bus->sdh))) {
1816		DHD_ERROR(("%s: FAILED to set window back to 0x%x\n", __FUNCTION__,
1817			bcmsdh_cur_sbwad(bus->sdh)));
1818	}
1819
1820	return bcmerror;
1821}
1822
1823#ifdef DHD_DEBUG
1824static int
1825dhdsdio_readshared(dhd_bus_t *bus, sdpcm_shared_t *sh)
1826{
1827	uint32 addr;
1828	int rv;
1829
1830	/* Read last word in memory to determine address of sdpcm_shared structure */
1831	if ((rv = dhdsdio_membytes(bus, FALSE, bus->ramsize - 4, (uint8 *)&addr, 4)) < 0)
1832		return rv;
1833
1834	addr = ltoh32(addr);
1835
1836	DHD_INFO(("sdpcm_shared address 0x%08X\n", addr));
1837
1838	/*
1839	 * Check if addr is valid.
1840	 * NVRAM length at the end of memory should have been overwritten.
1841	 */
1842	if (addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff)) {
1843		DHD_ERROR(("%s: address (0x%08x) of sdpcm_shared invalid\n", __FUNCTION__, addr));
1844		return BCME_ERROR;
1845	}
1846
1847	/* Read hndrte_shared structure */
1848	if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)sh, sizeof(sdpcm_shared_t))) < 0)
1849		return rv;
1850
1851	/* Endianness */
1852	sh->flags = ltoh32(sh->flags);
1853	sh->trap_addr = ltoh32(sh->trap_addr);
1854	sh->assert_exp_addr = ltoh32(sh->assert_exp_addr);
1855	sh->assert_file_addr = ltoh32(sh->assert_file_addr);
1856	sh->assert_line = ltoh32(sh->assert_line);
1857	sh->console_addr = ltoh32(sh->console_addr);
1858	sh->msgtrace_addr = ltoh32(sh->msgtrace_addr);
1859
1860	if ((sh->flags & SDPCM_SHARED_VERSION_MASK) == 3 && SDPCM_SHARED_VERSION == 1)
1861		return BCME_OK;
1862
1863	if ((sh->flags & SDPCM_SHARED_VERSION_MASK) != SDPCM_SHARED_VERSION) {
1864		DHD_ERROR(("%s: sdpcm_shared version %d in dhd "
1865		           "is different than sdpcm_shared version %d in dongle\n",
1866		           __FUNCTION__, SDPCM_SHARED_VERSION,
1867		           sh->flags & SDPCM_SHARED_VERSION_MASK));
1868		return BCME_ERROR;
1869	}
1870
1871	return BCME_OK;
1872}
1873
1874
1875static int
1876dhdsdio_readconsole(dhd_bus_t *bus)
1877{
1878	dhd_console_t *c = &bus->console;
1879	uint8 line[CONSOLE_LINE_MAX], ch;
1880	uint32 n, idx, addr;
1881	int rv;
1882
1883	/* Don't do anything until FWREADY updates console address */
1884	if (bus->console_addr == 0)
1885		return 0;
1886
1887	/* Read console log struct */
1888	addr = bus->console_addr + OFFSETOF(hndrte_cons_t, log);
1889	if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)&c->log, sizeof(c->log))) < 0)
1890		return rv;
1891
1892	/* Allocate console buffer (one time only) */
1893	if (c->buf == NULL) {
1894		c->bufsize = ltoh32(c->log.buf_size);
1895		if ((c->buf = MALLOC(bus->dhd->osh, c->bufsize)) == NULL)
1896			return BCME_NOMEM;
1897	}
1898
1899	idx = ltoh32(c->log.idx);
1900
1901	/* Protect against corrupt value */
1902	if (idx > c->bufsize)
1903		return BCME_ERROR;
1904
1905	/* Skip reading the console buffer if the index pointer has not moved */
1906	if (idx == c->last)
1907		return BCME_OK;
1908
1909	/* Read the console buffer */
1910	addr = ltoh32(c->log.buf);
1911	if ((rv = dhdsdio_membytes(bus, FALSE, addr, c->buf, c->bufsize)) < 0)
1912		return rv;
1913
1914	while (c->last != idx) {
1915		for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) {
1916			if (c->last == idx) {
1917				/* This would output a partial line.  Instead, back up
1918				 * the buffer pointer and output this line next time around.
1919				 */
1920				if (c->last >= n)
1921					c->last -= n;
1922				else
1923					c->last = c->bufsize - n;
1924				goto break2;
1925			}
1926			ch = c->buf[c->last];
1927			c->last = (c->last + 1) % c->bufsize;
1928			if (ch == '\n')
1929				break;
1930			line[n] = ch;
1931		}
1932
1933		if (n > 0) {
1934			if (line[n - 1] == '\r')
1935				n--;
1936			line[n] = 0;
1937			printf("CONSOLE: %s\n", line);
1938		}
1939	}
1940break2:
1941
1942	return BCME_OK;
1943}
1944
1945static int
1946dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size)
1947{
1948	int bcmerror = 0;
1949	uint msize = 512;
1950	char *mbuffer = NULL;
1951	char *console_buffer = NULL;
1952	uint maxstrlen = 256;
1953	char *str = NULL;
1954	trap_t tr;
1955	sdpcm_shared_t sdpcm_shared;
1956	struct bcmstrbuf strbuf;
1957	uint32 console_ptr, console_size, console_index;
1958	uint8 line[CONSOLE_LINE_MAX], ch;
1959	uint32 n, i, addr;
1960	int rv;
1961
1962	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1963
1964	if (data == NULL) {
1965		/*
1966		 * Called after a rx ctrl timeout. "data" is NULL.
1967		 * allocate memory to trace the trap or assert.
1968		 */
1969		size = msize;
1970		mbuffer = data = MALLOC(bus->dhd->osh, msize);
1971		if (mbuffer == NULL) {
1972			DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, msize));
1973			bcmerror = BCME_NOMEM;
1974			goto done;
1975		}
1976	}
1977
1978	if ((str = MALLOC(bus->dhd->osh, maxstrlen)) == NULL) {
1979		DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, maxstrlen));
1980		bcmerror = BCME_NOMEM;
1981		goto done;
1982	}
1983
1984	if ((bcmerror = dhdsdio_readshared(bus, &sdpcm_shared)) < 0)
1985		goto done;
1986
1987	bcm_binit(&strbuf, data, size);
1988
1989	bcm_bprintf(&strbuf, "msgtrace address : 0x%08X\nconsole address  : 0x%08X\n",
1990	            sdpcm_shared.msgtrace_addr, sdpcm_shared.console_addr);
1991
1992	if ((sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT) == 0) {
1993		/* NOTE: Misspelled assert is intentional - DO NOT FIX.
1994		 * (Avoids conflict with real asserts for programmatic parsing of output.)
1995		 */
1996		bcm_bprintf(&strbuf, "Assrt not built in dongle\n");
1997	}
1998
1999	if ((sdpcm_shared.flags & (SDPCM_SHARED_ASSERT|SDPCM_SHARED_TRAP)) == 0) {
2000		/* NOTE: Misspelled assert is intentional - DO NOT FIX.
2001		 * (Avoids conflict with real asserts for programmatic parsing of output.)
2002		 */
2003		bcm_bprintf(&strbuf, "No trap%s in dongle",
2004		          (sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT)
2005		          ?"/assrt" :"");
2006	} else {
2007		if (sdpcm_shared.flags & SDPCM_SHARED_ASSERT) {
2008			/* Download assert */
2009			bcm_bprintf(&strbuf, "Dongle assert");
2010			if (sdpcm_shared.assert_exp_addr != 0) {
2011				str[0] = '\0';
2012				if ((bcmerror = dhdsdio_membytes(bus, FALSE,
2013				                                 sdpcm_shared.assert_exp_addr,
2014				                                 (uint8 *)str, maxstrlen)) < 0)
2015					goto done;
2016
2017				str[maxstrlen - 1] = '\0';
2018				bcm_bprintf(&strbuf, " expr \"%s\"", str);
2019			}
2020
2021			if (sdpcm_shared.assert_file_addr != 0) {
2022				str[0] = '\0';
2023				if ((bcmerror = dhdsdio_membytes(bus, FALSE,
2024				                                 sdpcm_shared.assert_file_addr,
2025				                                 (uint8 *)str, maxstrlen)) < 0)
2026					goto done;
2027
2028				str[maxstrlen - 1] = '\0';
2029				bcm_bprintf(&strbuf, " file \"%s\"", str);
2030			}
2031
2032			bcm_bprintf(&strbuf, " line %d ", sdpcm_shared.assert_line);
2033		}
2034
2035		if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) {
2036			if ((bcmerror = dhdsdio_membytes(bus, FALSE,
2037			                                 sdpcm_shared.trap_addr,
2038			                                 (uint8*)&tr, sizeof(trap_t))) < 0)
2039				goto done;
2040
2041			bcm_bprintf(&strbuf,
2042			"Dongle trap type 0x%x @ epc 0x%x, cpsr 0x%x, spsr 0x%x, sp 0x%x,"
2043			"lp 0x%x, rpc 0x%x Trap offset 0x%x, "
2044			"r0 0x%x, r1 0x%x, r2 0x%x, r3 0x%x, "
2045			"r4 0x%x, r5 0x%x, r6 0x%x, r7 0x%x\n\n",
2046			ltoh32(tr.type), ltoh32(tr.epc), ltoh32(tr.cpsr), ltoh32(tr.spsr),
2047			ltoh32(tr.r13), ltoh32(tr.r14), ltoh32(tr.pc),
2048			ltoh32(sdpcm_shared.trap_addr),
2049			ltoh32(tr.r0), ltoh32(tr.r1), ltoh32(tr.r2), ltoh32(tr.r3),
2050			ltoh32(tr.r4), ltoh32(tr.r5), ltoh32(tr.r6), ltoh32(tr.r7));
2051
2052			addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log);
2053			if ((rv = dhdsdio_membytes(bus, FALSE, addr,
2054				(uint8 *)&console_ptr, sizeof(console_ptr))) < 0)
2055				goto printbuf;
2056
2057			addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log.buf_size);
2058			if ((rv = dhdsdio_membytes(bus, FALSE, addr,
2059				(uint8 *)&console_size, sizeof(console_size))) < 0)
2060				goto printbuf;
2061
2062			addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log.idx);
2063			if ((rv = dhdsdio_membytes(bus, FALSE, addr,
2064				(uint8 *)&console_index, sizeof(console_index))) < 0)
2065				goto printbuf;
2066
2067			console_ptr = ltoh32(console_ptr);
2068			console_size = ltoh32(console_size);
2069			console_index = ltoh32(console_index);
2070
2071			if (console_size > CONSOLE_BUFFER_MAX ||
2072				!(console_buffer = MALLOC(bus->dhd->osh, console_size)))
2073				goto printbuf;
2074
2075			if ((rv = dhdsdio_membytes(bus, FALSE, console_ptr,
2076				(uint8 *)console_buffer, console_size)) < 0)
2077				goto printbuf;
2078
2079			for (i = 0, n = 0; i < console_size; i += n + 1) {
2080				for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) {
2081					ch = console_buffer[(console_index + i + n) % console_size];
2082					if (ch == '\n')
2083						break;
2084					line[n] = ch;
2085				}
2086
2087
2088				if (n > 0) {
2089					if (line[n - 1] == '\r')
2090						n--;
2091					line[n] = 0;
2092					/* Don't use DHD_ERROR macro since we print
2093					 * a lot of information quickly. The macro
2094					 * will truncate a lot of the printfs
2095					 */
2096
2097					if (dhd_msg_level & DHD_ERROR_VAL) {
2098						printf("CONSOLE: %s\n", line);
2099						DHD_BLOG(line, strlen(line) + 1);
2100					}
2101				}
2102			}
2103		}
2104	}
2105
2106printbuf:
2107	if (sdpcm_shared.flags & (SDPCM_SHARED_ASSERT | SDPCM_SHARED_TRAP)) {
2108		DHD_ERROR(("%s: %s\n", __FUNCTION__, strbuf.origbuf));
2109	}
2110
2111
2112done:
2113	if (mbuffer)
2114		MFREE(bus->dhd->osh, mbuffer, msize);
2115	if (str)
2116		MFREE(bus->dhd->osh, str, maxstrlen);
2117	if (console_buffer)
2118		MFREE(bus->dhd->osh, console_buffer, console_size);
2119
2120	return bcmerror;
2121}
2122#endif /* #ifdef DHD_DEBUG */
2123
2124
2125int
2126dhdsdio_downloadvars(dhd_bus_t *bus, void *arg, int len)
2127{
2128	int bcmerror = BCME_OK;
2129
2130	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2131
2132	/* Basic sanity checks */
2133	if (bus->dhd->up) {
2134		bcmerror = BCME_NOTDOWN;
2135		goto err;
2136	}
2137	if (!len) {
2138		bcmerror = BCME_BUFTOOSHORT;
2139		goto err;
2140	}
2141
2142	/* Free the old ones and replace with passed variables */
2143	if (bus->vars)
2144		MFREE(bus->dhd->osh, bus->vars, bus->varsz);
2145
2146	bus->vars = MALLOC(bus->dhd->osh, len);
2147	bus->varsz = bus->vars ? len : 0;
2148	if (bus->vars == NULL) {
2149		bcmerror = BCME_NOMEM;
2150		goto err;
2151	}
2152
2153	/* Copy the passed variables, which should include the terminating double-null */
2154	bcopy(arg, bus->vars, bus->varsz);
2155err:
2156	return bcmerror;
2157}
2158
2159#ifdef DHD_DEBUG
2160
2161#define CC_PLL_CHIPCTRL_SERIAL_ENAB	(1  << 24)
2162static int
2163dhd_serialconsole(dhd_bus_t *bus, bool set, bool enable, int *bcmerror)
2164{
2165	int int_val;
2166	uint32 addr, data;
2167
2168
2169	addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr);
2170	data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data);
2171	*bcmerror = 0;
2172
2173	bcmsdh_reg_write(bus->sdh, addr, 4, 1);
2174	if (bcmsdh_regfail(bus->sdh)) {
2175		*bcmerror = BCME_SDIO_ERROR;
2176		return -1;
2177	}
2178	int_val = bcmsdh_reg_read(bus->sdh, data, 4);
2179	if (bcmsdh_regfail(bus->sdh)) {
2180		*bcmerror = BCME_SDIO_ERROR;
2181		return -1;
2182	}
2183	if (!set)
2184		return (int_val & CC_PLL_CHIPCTRL_SERIAL_ENAB);
2185	if (enable)
2186		int_val |= CC_PLL_CHIPCTRL_SERIAL_ENAB;
2187	else
2188		int_val &= ~CC_PLL_CHIPCTRL_SERIAL_ENAB;
2189	bcmsdh_reg_write(bus->sdh, data, 4, int_val);
2190	if (bcmsdh_regfail(bus->sdh)) {
2191		*bcmerror = BCME_SDIO_ERROR;
2192		return -1;
2193	}
2194	if (bus->sih->chip == BCM4330_CHIP_ID) {
2195		uint32 chipcontrol;
2196		addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol);
2197		chipcontrol = bcmsdh_reg_read(bus->sdh, addr, 4);
2198		chipcontrol &= ~0x8;
2199		if (enable) {
2200			chipcontrol |=  0x8;
2201			chipcontrol &= ~0x3;
2202		}
2203		bcmsdh_reg_write(bus->sdh, addr, 4, chipcontrol);
2204	}
2205
2206	return (int_val & CC_PLL_CHIPCTRL_SERIAL_ENAB);
2207}
2208#endif 
2209
2210static int
2211dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const char *name,
2212                void *params, int plen, void *arg, int len, int val_size)
2213{
2214	int bcmerror = 0;
2215	int32 int_val = 0;
2216	bool bool_val = 0;
2217
2218	DHD_TRACE(("%s: Enter, action %d name %s params %p plen %d arg %p len %d val_size %d\n",
2219	           __FUNCTION__, actionid, name, params, plen, arg, len, val_size));
2220
2221	if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0)
2222		goto exit;
2223
2224	if (plen >= (int)sizeof(int_val))
2225		bcopy(params, &int_val, sizeof(int_val));
2226
2227	bool_val = (int_val != 0) ? TRUE : FALSE;
2228
2229
2230	/* Some ioctls use the bus */
2231	dhd_os_sdlock(bus->dhd);
2232
2233	/* Check if dongle is in reset. If so, only allow DEVRESET iovars */
2234	if (bus->dhd->dongle_reset && !(actionid == IOV_SVAL(IOV_DEVRESET) ||
2235	                                actionid == IOV_GVAL(IOV_DEVRESET))) {
2236		bcmerror = BCME_NOTREADY;
2237		goto exit;
2238	}
2239
2240	/* Handle sleep stuff before any clock mucking */
2241	if (vi->varid == IOV_SLEEP) {
2242		if (IOV_ISSET(actionid)) {
2243			bcmerror = dhdsdio_bussleep(bus, bool_val);
2244		} else {
2245			int_val = (int32)bus->sleeping;
2246			bcopy(&int_val, arg, val_size);
2247		}
2248		goto exit;
2249	}
2250
2251	/* Request clock to allow SDIO accesses */
2252	if (!bus->dhd->dongle_reset) {
2253		BUS_WAKE(bus);
2254		dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
2255	}
2256
2257	switch (actionid) {
2258	case IOV_GVAL(IOV_INTR):
2259		int_val = (int32)bus->intr;
2260		bcopy(&int_val, arg, val_size);
2261		break;
2262
2263	case IOV_SVAL(IOV_INTR):
2264		bus->intr = bool_val;
2265		bus->intdis = FALSE;
2266		if (bus->dhd->up) {
2267			if (bus->intr) {
2268				DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__));
2269				bcmsdh_intr_enable(bus->sdh);
2270			} else {
2271				DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
2272				bcmsdh_intr_disable(bus->sdh);
2273			}
2274		}
2275		break;
2276
2277	case IOV_GVAL(IOV_POLLRATE):
2278		int_val = (int32)bus->pollrate;
2279		bcopy(&int_val, arg, val_size);
2280		break;
2281
2282	case IOV_SVAL(IOV_POLLRATE):
2283		bus->pollrate = (uint)int_val;
2284		bus->poll = (bus->pollrate != 0);
2285		break;
2286
2287	case IOV_GVAL(IOV_IDLETIME):
2288		int_val = bus->idletime;
2289		bcopy(&int_val, arg, val_size);
2290		break;
2291
2292	case IOV_SVAL(IOV_IDLETIME):
2293		if ((int_val < 0) && (int_val != DHD_IDLE_IMMEDIATE)) {
2294			bcmerror = BCME_BADARG;
2295		} else {
2296			bus->idletime = int_val;
2297		}
2298		break;
2299
2300	case IOV_GVAL(IOV_IDLECLOCK):
2301		int_val = (int32)bus->idleclock;
2302		bcopy(&int_val, arg, val_size);
2303		break;
2304
2305	case IOV_SVAL(IOV_IDLECLOCK):
2306		bus->idleclock = int_val;
2307		break;
2308
2309	case IOV_GVAL(IOV_SD1IDLE):
2310		int_val = (int32)sd1idle;
2311		bcopy(&int_val, arg, val_size);
2312		break;
2313
2314	case IOV_SVAL(IOV_SD1IDLE):
2315		sd1idle = bool_val;
2316		break;
2317
2318
2319	case IOV_SVAL(IOV_MEMBYTES):
2320	case IOV_GVAL(IOV_MEMBYTES):
2321	{
2322		uint32 address;
2323		uint size, dsize;
2324		uint8 *data;
2325
2326		bool set = (actionid == IOV_SVAL(IOV_MEMBYTES));
2327
2328		ASSERT(plen >= 2*sizeof(int));
2329
2330		address = (uint32)int_val;
2331		bcopy((char *)params + sizeof(int_val), &int_val, sizeof(int_val));
2332		size = (uint)int_val;
2333
2334		/* Do some validation */
2335		dsize = set ? plen - (2 * sizeof(int)) : len;
2336		if (dsize < size) {
2337			DHD_ERROR(("%s: error on %s membytes, addr 0x%08x size %d dsize %d\n",
2338			           __FUNCTION__, (set ? "set" : "get"), address, size, dsize));
2339			bcmerror = BCME_BADARG;
2340			break;
2341		}
2342
2343		DHD_INFO(("%s: Request to %s %d bytes at address 0x%08x\n", __FUNCTION__,
2344		          (set ? "write" : "read"), size, address));
2345
2346		/* If we know about SOCRAM, check for a fit */
2347		if ((bus->orig_ramsize) &&
2348		    ((address > bus->orig_ramsize) || (address + size > bus->orig_ramsize)))
2349		{
2350			uint8 enable, protect;
2351			si_socdevram(bus->sih, FALSE, &enable, &protect);
2352			if (!enable || protect) {
2353				DHD_ERROR(("%s: ramsize 0x%08x doesn't have %d bytes at 0x%08x\n",
2354					__FUNCTION__, bus->orig_ramsize, size, address));
2355				DHD_ERROR(("%s: socram enable %d, protect %d\n",
2356					__FUNCTION__, enable, protect));
2357				bcmerror = BCME_BADARG;
2358				break;
2359			}
2360			if (enable && (bus->sih->chip == BCM4330_CHIP_ID)) {
2361				uint32 devramsize = si_socdevram_size(bus->sih);
2362				if ((address < SOCDEVRAM_4330_ARM_ADDR) ||
2363					(address + size > (SOCDEVRAM_4330_ARM_ADDR + devramsize))) {
2364					DHD_ERROR(("%s: bad address 0x%08x, size 0x%08x\n",
2365						__FUNCTION__, address, size));
2366					DHD_ERROR(("%s: socram range 0x%08x,size 0x%08x\n",
2367						__FUNCTION__, SOCDEVRAM_4330_ARM_ADDR, devramsize));
2368					bcmerror = BCME_BADARG;
2369					break;
2370				}
2371				/* move it such that address is real now */
2372				address -= SOCDEVRAM_4330_ARM_ADDR;
2373				address += SOCDEVRAM_4330_BP_ADDR;
2374				DHD_INFO(("%s: Request to %s %d bytes @ Mapped address 0x%08x\n",
2375					__FUNCTION__, (set ? "write" : "read"), size, address));
2376			}
2377		}
2378
2379		/* Generate the actual data pointer */
2380		data = set ? (uint8*)params + 2 * sizeof(int): (uint8*)arg;
2381
2382		/* Call to do the transfer */
2383		bcmerror = dhdsdio_membytes(bus, set, address, data, size);
2384
2385		break;
2386	}
2387
2388	case IOV_GVAL(IOV_MEMSIZE):
2389		int_val = (int32)bus->ramsize;
2390		bcopy(&int_val, arg, val_size);
2391		break;
2392
2393	case IOV_GVAL(IOV_SDIOD_DRIVE):
2394		int_val = (int32)dhd_sdiod_drive_strength;
2395		bcopy(&int_val, arg, val_size);
2396		break;
2397
2398	case IOV_SVAL(IOV_SDIOD_DRIVE):
2399		dhd_sdiod_drive_strength = int_val;
2400		si_sdiod_drive_strength_init(bus->sih, bus->dhd->osh, dhd_sdiod_drive_strength);
2401		break;
2402
2403	case IOV_SVAL(IOV_DOWNLOAD):
2404		bcmerror = dhdsdio_download_state(bus, bool_val);
2405		break;
2406
2407	case IOV_SVAL(IOV_SOCRAM_STATE):
2408		bcmerror = dhdsdio_download_state(bus, bool_val);
2409		break;
2410
2411	case IOV_SVAL(IOV_VARS):
2412		bcmerror = dhdsdio_downloadvars(bus, arg, len);
2413		break;
2414
2415	case IOV_GVAL(IOV_READAHEAD):
2416		int_val = (int32)dhd_readahead;
2417		bcopy(&int_val, arg, val_size);
2418		break;
2419
2420	case IOV_SVAL(IOV_READAHEAD):
2421		if (bool_val && !dhd_readahead)
2422			bus->nextlen = 0;
2423		dhd_readahead = bool_val;
2424		break;
2425
2426	case IOV_GVAL(IOV_SDRXCHAIN):
2427		int_val = (int32)bus->use_rxchain;
2428		bcopy(&int_val, arg, val_size);
2429		break;
2430
2431	case IOV_SVAL(IOV_SDRXCHAIN):
2432		if (bool_val && !bus->sd_rxchain)
2433			bcmerror = BCME_UNSUPPORTED;
2434		else
2435			bus->use_rxchain = bool_val;
2436		break;
2437	case IOV_GVAL(IOV_ALIGNCTL):
2438		int_val = (int32)dhd_alignctl;
2439		bcopy(&int_val, arg, val_size);
2440		break;
2441
2442	case IOV_SVAL(IOV_ALIGNCTL):
2443		dhd_alignctl = bool_val;
2444		break;
2445
2446	case IOV_GVAL(IOV_SDALIGN):
2447		int_val = DHD_SDALIGN;
2448		bcopy(&int_val, arg, val_size);
2449		break;
2450
2451#ifdef DHD_DEBUG
2452	case IOV_GVAL(IOV_VARS):
2453		if (bus->varsz < (uint)len)
2454			bcopy(bus->vars, arg, bus->varsz);
2455		else
2456			bcmerror = BCME_BUFTOOSHORT;
2457		break;
2458#endif /* DHD_DEBUG */
2459
2460#ifdef DHD_DEBUG
2461	case IOV_GVAL(IOV_SDREG):
2462	{
2463		sdreg_t *sd_ptr;
2464		uint32 addr, size;
2465
2466		sd_ptr = (sdreg_t *)params;
2467
2468		addr = (uintptr)bus->regs + sd_ptr->offset;
2469		size = sd_ptr->func;
2470		int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size);
2471		if (bcmsdh_regfail(bus->sdh))
2472			bcmerror = BCME_SDIO_ERROR;
2473		bcopy(&int_val, arg, sizeof(int32));
2474		break;
2475	}
2476
2477	case IOV_SVAL(IOV_SDREG):
2478	{
2479		sdreg_t *sd_ptr;
2480		uint32 addr, size;
2481
2482		sd_ptr = (sdreg_t *)params;
2483
2484		addr = (uintptr)bus->regs + sd_ptr->offset;
2485		size = sd_ptr->func;
2486		bcmsdh_reg_write(bus->sdh, addr, size, sd_ptr->value);
2487		if (bcmsdh_regfail(bus->sdh))
2488			bcmerror = BCME_SDIO_ERROR;
2489		break;
2490	}
2491
2492	/* Same as above, but offset is not backplane (not SDIO core) */
2493	case IOV_GVAL(IOV_SBREG):
2494	{
2495		sdreg_t sdreg;
2496		uint32 addr, size;
2497
2498		bcopy(params, &sdreg, sizeof(sdreg));
2499
2500		addr = SI_ENUM_BASE + sdreg.offset;
2501		size = sdreg.func;
2502		int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size);
2503		if (bcmsdh_regfail(bus->sdh))
2504			bcmerror = BCME_SDIO_ERROR;
2505		bcopy(&int_val, arg, sizeof(int32));
2506		break;
2507	}
2508
2509	case IOV_SVAL(IOV_SBREG):
2510	{
2511		sdreg_t sdreg;
2512		uint32 addr, size;
2513
2514		bcopy(params, &sdreg, sizeof(sdreg));
2515
2516		addr = SI_ENUM_BASE + sdreg.offset;
2517		size = sdreg.func;
2518		bcmsdh_reg_write(bus->sdh, addr, size, sdreg.value);
2519		if (bcmsdh_regfail(bus->sdh))
2520			bcmerror = BCME_SDIO_ERROR;
2521		break;
2522	}
2523
2524	case IOV_GVAL(IOV_SDCIS):
2525	{
2526		*(char *)arg = 0;
2527
2528		bcmstrcat(arg, "\nFunc 0\n");
2529		bcmsdh_cis_read(bus->sdh, 0x10, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
2530		bcmstrcat(arg, "\nFunc 1\n");
2531		bcmsdh_cis_read(bus->sdh, 0x11, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
2532		bcmstrcat(arg, "\nFunc 2\n");
2533		bcmsdh_cis_read(bus->sdh, 0x12, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
2534		break;
2535	}
2536
2537	case IOV_GVAL(IOV_FORCEEVEN):
2538		int_val = (int32)forcealign;
2539		bcopy(&int_val, arg, val_size);
2540		break;
2541
2542	case IOV_SVAL(IOV_FORCEEVEN):
2543		forcealign = bool_val;
2544		break;
2545
2546	case IOV_GVAL(IOV_TXBOUND):
2547		int_val = (int32)dhd_txbound;
2548		bcopy(&int_val, arg, val_size);
2549		break;
2550
2551	case IOV_SVAL(IOV_TXBOUND):
2552		dhd_txbound = (uint)int_val;
2553		break;
2554
2555	case IOV_GVAL(IOV_RXBOUND):
2556		int_val = (int32)dhd_rxbound;
2557		bcopy(&int_val, arg, val_size);
2558		break;
2559
2560	case IOV_SVAL(IOV_RXBOUND):
2561		dhd_rxbound = (uint)int_val;
2562		break;
2563
2564	case IOV_GVAL(IOV_TXMINMAX):
2565		int_val = (int32)dhd_txminmax;
2566		bcopy(&int_val, arg, val_size);
2567		break;
2568
2569	case IOV_SVAL(IOV_TXMINMAX):
2570		dhd_txminmax = (uint)int_val;
2571		break;
2572
2573	case IOV_GVAL(IOV_SERIALCONS):
2574		int_val = dhd_serialconsole(bus, FALSE, 0, &bcmerror);
2575		if (bcmerror != 0)
2576			break;
2577
2578		bcopy(&int_val, arg, val_size);
2579		break;
2580
2581	case IOV_SVAL(IOV_SERIALCONS):
2582		dhd_serialconsole(bus, TRUE, bool_val, &bcmerror);
2583		break;
2584
2585
2586
2587#endif /* DHD_DEBUG */
2588
2589
2590#ifdef SDTEST
2591	case IOV_GVAL(IOV_EXTLOOP):
2592		int_val = (int32)bus->ext_loop;
2593		bcopy(&int_val, arg, val_size);
2594		break;
2595
2596	case IOV_SVAL(IOV_EXTLOOP):
2597		bus->ext_loop = bool_val;
2598		break;
2599
2600	case IOV_GVAL(IOV_PKTGEN):
2601		bcmerror = dhdsdio_pktgen_get(bus, arg);
2602		break;
2603
2604	case IOV_SVAL(IOV_PKTGEN):
2605		bcmerror = dhdsdio_pktgen_set(bus, arg);
2606		break;
2607#endif /* SDTEST */
2608
2609
2610	case IOV_GVAL(IOV_DONGLEISOLATION):
2611		int_val = bus->dhd->dongle_isolation;
2612		bcopy(&int_val, arg, val_size);
2613		break;
2614
2615	case IOV_SVAL(IOV_DONGLEISOLATION):
2616		bus->dhd->dongle_isolation = bool_val;
2617		break;
2618
2619	case IOV_SVAL(IOV_DEVRESET):
2620		DHD_TRACE(("%s: Called set IOV_DEVRESET=%d dongle_reset=%d busstate=%d\n",
2621		           __FUNCTION__, bool_val, bus->dhd->dongle_reset,
2622		           bus->dhd->busstate));
2623
2624		ASSERT(bus->dhd->osh);
2625		/* ASSERT(bus->cl_devid); */
2626
2627		dhd_bus_devreset(bus->dhd, (uint8)bool_val);
2628
2629		break;
2630#ifdef SOFTAP
2631	case IOV_GVAL(IOV_FWPATH):
2632	{
2633		uint32  fw_path_len;
2634
2635		fw_path_len = strlen(bus->fw_path);
2636		DHD_INFO(("[softap] get fwpath, l=%d\n", len));
2637
2638		if (fw_path_len > len-1) {
2639			bcmerror = BCME_BUFTOOSHORT;
2640			break;
2641		}
2642
2643		if (fw_path_len) {
2644			bcopy(bus->fw_path, arg, fw_path_len);
2645			((uchar*)arg)[fw_path_len] = 0;
2646		}
2647		break;
2648	}
2649
2650	case IOV_SVAL(IOV_FWPATH):
2651		DHD_INFO(("[softap] set fwpath, idx=%d\n", int_val));
2652
2653		switch (int_val) {
2654		case 1:
2655			bus->fw_path = fw_path; /* ordinary one */
2656			break;
2657		case 2:
2658			bus->fw_path = fw_path2;
2659			break;
2660		default:
2661			bcmerror = BCME_BADARG;
2662			break;
2663		}
2664
2665		DHD_INFO(("[softap] new fw path: %s\n", (bus->fw_path[0] ? bus->fw_path : "NULL")));
2666		break;
2667
2668#endif /* SOFTAP */
2669	case IOV_GVAL(IOV_DEVRESET):
2670		DHD_TRACE(("%s: Called get IOV_DEVRESET\n", __FUNCTION__));
2671
2672		/* Get its status */
2673		int_val = (bool) bus->dhd->dongle_reset;
2674		bcopy(&int_val, arg, val_size);
2675
2676		break;
2677
2678	default:
2679		bcmerror = BCME_UNSUPPORTED;
2680		break;
2681	}
2682
2683exit:
2684	if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
2685		bus->activity = FALSE;
2686		dhdsdio_clkctl(bus, CLK_NONE, TRUE);
2687	}
2688
2689	dhd_os_sdunlock(bus->dhd);
2690
2691	if (actionid == IOV_SVAL(IOV_DEVRESET) && bool_val == FALSE)
2692		dhd_preinit_ioctls((dhd_pub_t *) bus->dhd);
2693
2694	return bcmerror;
2695}
2696
2697static int
2698dhdsdio_write_vars(dhd_bus_t *bus)
2699{
2700	int bcmerror = 0;
2701	uint32 varsize;
2702	uint32 varaddr;
2703	uint8 *vbuffer;
2704	uint32 varsizew;
2705#ifdef DHD_DEBUG
2706	uint8 *nvram_ularray;
2707#endif /* DHD_DEBUG */
2708
2709	/* Even if there are no vars are to be written, we still need to set the ramsize. */
2710	varsize = bus->varsz ? ROUNDUP(bus->varsz, 4) : 0;
2711	varaddr = (bus->ramsize - 4) - varsize;
2712
2713	if (bus->vars) {
2714		if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 7)) {
2715			if (((varaddr & 0x3C) == 0x3C) && (varsize > 4)) {
2716				DHD_ERROR(("PR85623WAR in place\n"));
2717				varsize += 4;
2718				varaddr -= 4;
2719			}
2720		}
2721
2722		vbuffer = (uint8 *)MALLOC(bus->dhd->osh, varsize);
2723		if (!vbuffer)
2724			return BCME_NOMEM;
2725
2726		bzero(vbuffer, varsize);
2727		bcopy(bus->vars, vbuffer, bus->varsz);
2728
2729		/* Write the vars list */
2730		bcmerror = dhdsdio_membytes(bus, TRUE, varaddr, vbuffer, varsize);
2731#ifdef DHD_DEBUG
2732		/* Verify NVRAM bytes */
2733		DHD_INFO(("Compare NVRAM dl & ul; varsize=%d\n", varsize));
2734		nvram_ularray = (uint8*)MALLOC(bus->dhd->osh, varsize);
2735		if (!nvram_ularray)
2736			return BCME_NOMEM;
2737
2738		/* Upload image to verify downloaded contents. */
2739		memset(nvram_ularray, 0xaa, varsize);
2740
2741		/* Read the vars list to temp buffer for comparison */
2742		bcmerror = dhdsdio_membytes(bus, FALSE, varaddr, nvram_ularray, varsize);
2743		if (bcmerror) {
2744				DHD_ERROR(("%s: error %d on reading %d nvram bytes at 0x%08x\n",
2745					__FUNCTION__, bcmerror, varsize, varaddr));
2746		}
2747		/* Compare the org NVRAM with the one read from RAM */
2748		if (memcmp(vbuffer, nvram_ularray, varsize)) {
2749			DHD_ERROR(("%s: Downloaded NVRAM image is corrupted.\n", __FUNCTION__));
2750		} else
2751			DHD_ERROR(("%s: Download, Upload and compare of NVRAM succeeded.\n",
2752			__FUNCTION__));
2753
2754		MFREE(bus->dhd->osh, nvram_ularray, varsize);
2755#endif /* DHD_DEBUG */
2756
2757		MFREE(bus->dhd->osh, vbuffer, varsize);
2758	}
2759
2760	/* adjust to the user specified RAM */
2761	DHD_INFO(("Physical memory size: %d, usable memory size: %d\n",
2762		bus->orig_ramsize, bus->ramsize));
2763	DHD_INFO(("Vars are at %d, orig varsize is %d\n",
2764		varaddr, varsize));
2765	varsize = ((bus->orig_ramsize - 4) - varaddr);
2766
2767	/*
2768	 * Determine the length token:
2769	 * Varsize, converted to words, in lower 16-bits, checksum in upper 16-bits.
2770	 */
2771	if (bcmerror) {
2772		varsizew = 0;
2773	} else {
2774		varsizew = varsize / 4;
2775		varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF);
2776		varsizew = htol32(varsizew);
2777	}
2778
2779	DHD_INFO(("New varsize is %d, length token=0x%08x\n", varsize, varsizew));
2780
2781	/* Write the length token to the last word */
2782	bcmerror = dhdsdio_membytes(bus, TRUE, (bus->orig_ramsize - 4),
2783		(uint8*)&varsizew, 4);
2784
2785	return bcmerror;
2786}
2787
2788static int
2789dhdsdio_download_state(dhd_bus_t *bus, bool enter)
2790{
2791	uint retries;
2792	int bcmerror = 0;
2793
2794	if (!bus->sih)
2795		return BCME_ERROR;
2796
2797	/* To enter download state, disable ARM and reset SOCRAM.
2798	 * To exit download state, simply reset ARM (default is RAM boot).
2799	 */
2800	if (enter) {
2801		bus->alp_only = TRUE;
2802
2803		if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) &&
2804		    !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) {
2805			DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__));
2806			bcmerror = BCME_ERROR;
2807			goto fail;
2808		}
2809
2810		si_core_disable(bus->sih, 0);
2811		if (bcmsdh_regfail(bus->sdh)) {
2812			bcmerror = BCME_SDIO_ERROR;
2813			goto fail;
2814		}
2815
2816		if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) {
2817			DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__));
2818			bcmerror = BCME_ERROR;
2819			goto fail;
2820		}
2821
2822		si_core_reset(bus->sih, 0, 0);
2823		if (bcmsdh_regfail(bus->sdh)) {
2824			DHD_ERROR(("%s: Failure trying reset SOCRAM core?\n", __FUNCTION__));
2825			bcmerror = BCME_SDIO_ERROR;
2826			goto fail;
2827		}
2828
2829		/* Clear the top bit of memory */
2830		if (bus->ramsize) {
2831			uint32 zeros = 0;
2832			if (dhdsdio_membytes(bus, TRUE, bus->ramsize - 4, (uint8*)&zeros, 4) < 0) {
2833				bcmerror = BCME_SDIO_ERROR;
2834				goto fail;
2835			}
2836		}
2837	} else {
2838		if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) {
2839			DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__));
2840			bcmerror = BCME_ERROR;
2841			goto fail;
2842		}
2843
2844		if (!si_iscoreup(bus->sih)) {
2845			DHD_ERROR(("%s: SOCRAM core is down after reset?\n", __FUNCTION__));
2846			bcmerror = BCME_ERROR;
2847			goto fail;
2848		}
2849
2850		if ((bcmerror = dhdsdio_write_vars(bus))) {
2851			DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__));
2852			goto fail;
2853		}
2854
2855		if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) &&
2856		    !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) {
2857			DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__));
2858			bcmerror = BCME_ERROR;
2859			goto fail;
2860		}
2861		W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries);
2862
2863
2864		if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) &&
2865		    !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) {
2866			DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__));
2867			bcmerror = BCME_ERROR;
2868			goto fail;
2869		}
2870
2871		si_core_reset(bus->sih, 0, 0);
2872		if (bcmsdh_regfail(bus->sdh)) {
2873			DHD_ERROR(("%s: Failure trying to reset ARM core?\n", __FUNCTION__));
2874			bcmerror = BCME_SDIO_ERROR;
2875			goto fail;
2876		}
2877
2878		/* Allow HT Clock now that the ARM is running. */
2879		bus->alp_only = FALSE;
2880
2881		bus->dhd->busstate = DHD_BUS_LOAD;
2882	}
2883
2884fail:
2885	/* Always return to SDIOD core */
2886	if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0))
2887		si_setcore(bus->sih, SDIOD_CORE_ID, 0);
2888
2889	return bcmerror;
2890}
2891
2892int
2893dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name,
2894                 void *params, int plen, void *arg, int len, bool set)
2895{
2896	dhd_bus_t *bus = dhdp->bus;
2897	const bcm_iovar_t *vi = NULL;
2898	int bcmerror = 0;
2899	int val_size;
2900	uint32 actionid;
2901
2902	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2903
2904	ASSERT(name);
2905	ASSERT(len >= 0);
2906
2907	/* Get MUST have return space */
2908	ASSERT(set || (arg && len));
2909
2910	/* Set does NOT take qualifiers */
2911	ASSERT(!set || (!params && !plen));
2912
2913	/* Look up var locally; if not found pass to host driver */
2914	if ((vi = bcm_iovar_lookup(dhdsdio_iovars, name)) == NULL) {
2915		dhd_os_sdlock(bus->dhd);
2916
2917		BUS_WAKE(bus);
2918
2919		/* Turn on clock in case SD command needs backplane */
2920		dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
2921
2922		bcmerror = bcmsdh_iovar_op(bus->sdh, name, params, plen, arg, len, set);
2923
2924		/* Check for bus configuration changes of interest */
2925
2926		/* If it was divisor change, read the new one */
2927		if (set && strcmp(name, "sd_divisor") == 0) {
2928			if (bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
2929			                    &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) {
2930				bus->sd_divisor = -1;
2931				DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, name));
2932			} else {
2933				DHD_INFO(("%s: noted %s update, value now %d\n",
2934				          __FUNCTION__, name, bus->sd_divisor));
2935			}
2936		}
2937		/* If it was a mode change, read the new one */
2938		if (set && strcmp(name, "sd_mode") == 0) {
2939			if (bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
2940			                    &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) {
2941				bus->sd_mode = -1;
2942				DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, name));
2943			} else {
2944				DHD_INFO(("%s: noted %s update, value now %d\n",
2945				          __FUNCTION__, name, bus->sd_mode));
2946			}
2947		}
2948		/* Similar check for blocksize change */
2949		if (set && strcmp(name, "sd_blocksize") == 0) {
2950			int32 fnum = 2;
2951			if (bcmsdh_iovar_op(bus->sdh, "sd_blocksize", &fnum, sizeof(int32),
2952			                    &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) {
2953				bus->blocksize = 0;
2954				DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize"));
2955			} else {
2956				DHD_INFO(("%s: noted %s update, value now %d\n",
2957				          __FUNCTION__, "sd_blocksize", bus->blocksize));
2958			}
2959		}
2960		bus->roundup = MIN(max_roundup, bus->blocksize);
2961
2962		if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
2963			bus->activity = FALSE;
2964			dhdsdio_clkctl(bus, CLK_NONE, TRUE);
2965		}
2966
2967		dhd_os_sdunlock(bus->dhd);
2968		goto exit;
2969	}
2970
2971	DHD_CTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__,
2972	         name, (set ? "set" : "get"), len, plen));
2973
2974	/* set up 'params' pointer in case this is a set command so that
2975	 * the convenience int and bool code can be common to set and get
2976	 */
2977	if (params == NULL) {
2978		params = arg;
2979		plen = len;
2980	}
2981
2982	if (vi->type == IOVT_VOID)
2983		val_size = 0;
2984	else if (vi->type == IOVT_BUFFER)
2985		val_size = len;
2986	else
2987		/* all other types are integer sized */
2988		val_size = sizeof(int);
2989
2990	actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
2991	bcmerror = dhdsdio_doiovar(bus, vi, actionid, name, params, plen, arg, len, val_size);
2992
2993exit:
2994	return bcmerror;
2995}
2996
2997void
2998dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex)
2999{
3000	osl_t *osh;
3001	uint32 local_hostintmask;
3002	uint8 saveclk;
3003	uint retries;
3004	int err;
3005	if (!bus->dhd)
3006		return;
3007
3008	osh = bus->dhd->osh;
3009	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3010
3011	bcmsdh_waitlockfree(NULL);
3012
3013	if (enforce_mutex)
3014		dhd_os_sdlock(bus->dhd);
3015
3016	BUS_WAKE(bus);
3017
3018	/* Change our idea of bus state */
3019	bus->dhd->busstate = DHD_BUS_DOWN;
3020
3021	/* Enable clock for device interrupts */
3022	dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
3023
3024	/* Disable and clear interrupts at the chip level also */
3025	W_SDREG(0, &bus->regs->hostintmask, retries);
3026	local_hostintmask = bus->hostintmask;
3027	bus->hostintmask = 0;
3028
3029	/* Force clocks on backplane to be sure F2 interrupt propagates */
3030	saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
3031	if (!err) {
3032		bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
3033		                 (saveclk | SBSDIO_FORCE_HT), &err);
3034	}
3035	if (err) {
3036		DHD_ERROR(("%s: Failed to force clock for F2: err %d\n", __FUNCTION__, err));
3037	}
3038
3039	/* Turn off the bus (F2), free any pending packets */
3040	DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
3041	bcmsdh_intr_disable(bus->sdh);
3042	bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL);
3043
3044	/* Clear any pending interrupts now that F2 is disabled */
3045	W_SDREG(local_hostintmask, &bus->regs->intstatus, retries);
3046
3047	/* Turn off the backplane clock (only) */
3048	dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
3049
3050	/* Clear the data packet queues */
3051	pktq_flush(osh, &bus->txq, TRUE, NULL, 0);
3052
3053	/* Clear any held glomming stuff */
3054	if (bus->glomd)
3055		PKTFREE(osh, bus->glomd, FALSE);
3056
3057	if (bus->glom)
3058		PKTFREE(osh, bus->glom, FALSE);
3059
3060	bus->glom = bus->glomd = NULL;
3061
3062	/* Clear rx control and wake any waiters */
3063	bus->rxlen = 0;
3064	dhd_os_ioctl_resp_wake(bus->dhd);
3065
3066	/* Reset some F2 state stuff */
3067	bus->rxskip = FALSE;
3068	bus->tx_seq = bus->rx_seq = 0;
3069
3070	/* Set to a safe default.  It gets updated when we
3071	 * receive a packet from the fw but when we reset,
3072	 * we need a safe default to be able to send the
3073	 * initial mac address.
3074	 */
3075	bus->tx_max = 4;
3076
3077	if (enforce_mutex)
3078		dhd_os_sdunlock(bus->dhd);
3079}
3080
3081
3082int
3083dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex)
3084{
3085	dhd_bus_t *bus = dhdp->bus;
3086	dhd_timeout_t tmo;
3087	uint retries = 0;
3088	uint8 ready, enable;
3089	int err, ret = 0;
3090	uint8 saveclk;
3091
3092	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3093
3094	ASSERT(bus->dhd);
3095	if (!bus->dhd)
3096		return 0;
3097
3098	if (enforce_mutex)
3099		dhd_os_sdlock(bus->dhd);
3100
3101	/* Make sure backplane clock is on, needed to generate F2 interrupt */
3102	dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
3103	if (bus->clkstate != CLK_AVAIL) {
3104		DHD_ERROR(("%s: clock state is wrong. state = %d\n", __FUNCTION__, bus->clkstate));
3105		goto exit;
3106	}
3107
3108
3109	/* Force clocks on backplane to be sure F2 interrupt propagates */
3110	saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
3111	if (!err) {
3112		bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
3113		                 (saveclk | SBSDIO_FORCE_HT), &err);
3114	}
3115	if (err) {
3116		DHD_ERROR(("%s: Failed to force clock for F2: err %d\n", __FUNCTION__, err));
3117		goto exit;
3118	}
3119
3120	/* Enable function 2 (frame transfers) */
3121	W_SDREG((SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT),
3122	        &bus->regs->tosbmailboxdata, retries);
3123	enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2);
3124
3125	bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL);
3126
3127	/* Give the dongle some time to do its thing and set IOR2 */
3128	dhd_timeout_start(&tmo, DHD_WAIT_F2RDY * 1000);
3129
3130	ready = 0;
3131	do {
3132		ready = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IORDY, NULL);
3133	} while (ready != enable && !dhd_timeout_expired(&tmo));
3134
3135	DHD_INFO(("%s: enable 0x%02x, ready 0x%02x (waited %uus)\n",
3136	          __FUNCTION__, enable, ready, tmo.elapsed));
3137
3138
3139	/* If F2 successfully enabled, set core and enable interrupts */
3140	if (ready == enable) {
3141		/* Make sure we're talking to the core. */
3142		if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0)))
3143			bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0);
3144		ASSERT(bus->regs != NULL);
3145
3146		/* Set up the interrupt mask and enable interrupts */
3147		bus->hostintmask = HOSTINTMASK;
3148		/* corerev 4 could use the newer interrupt logic to detect the frames */
3149		if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 4) &&
3150			(bus->rxint_mode != SDIO_DEVICE_HMB_RXINT)) {
3151			bus->hostintmask &= ~I_HMB_FRAME_IND;
3152			bus->hostintmask |= I_XMTDATA_AVAIL;
3153		}
3154		W_SDREG(bus->hostintmask, &bus->regs->hostintmask, retries);
3155
3156		bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, (uint8)watermark, &err);
3157
3158		/* Set bus state according to enable result */
3159		dhdp->busstate = DHD_BUS_DATA;
3160
3161		/* bcmsdh_intr_unmask(bus->sdh); */
3162
3163		bus->intdis = FALSE;
3164		if (bus->intr) {
3165			DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__));
3166			bcmsdh_intr_enable(bus->sdh);
3167		} else {
3168			DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
3169			bcmsdh_intr_disable(bus->sdh);
3170		}
3171
3172	}
3173
3174
3175	else {
3176		/* Disable F2 again */
3177		enable = SDIO_FUNC_ENABLE_1;
3178		bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL);
3179	}
3180
3181	/* Restore previous clock setting */
3182	bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err);
3183
3184
3185	/* If we didn't come up, turn off backplane clock */
3186	if (dhdp->busstate != DHD_BUS_DATA)
3187		dhdsdio_clkctl(bus, CLK_NONE, FALSE);
3188
3189exit:
3190	if (enforce_mutex)
3191		dhd_os_sdunlock(bus->dhd);
3192
3193	return ret;
3194}
3195
3196static void
3197dhdsdio_rxfail(dhd_bus_t *bus, bool abort, bool rtx)
3198{
3199	bcmsdh_info_t *sdh = bus->sdh;
3200	sdpcmd_regs_t *regs = bus->regs;
3201	uint retries = 0;
3202	uint16 lastrbc;
3203	uint8 hi, lo;
3204	int err;
3205
3206	DHD_ERROR(("%s: %sterminate frame%s\n", __FUNCTION__,
3207	           (abort ? "abort command, " : ""), (rtx ? ", send NAK" : "")));
3208
3209	if (abort) {
3210		bcmsdh_abort(sdh, SDIO_FUNC_2);
3211	}
3212
3213	bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, SFC_RF_TERM, &err);
3214	bus->f1regdata++;
3215
3216	/* Wait until the packet has been flushed (device/FIFO stable) */
3217	for (lastrbc = retries = 0xffff; retries > 0; retries--) {
3218		hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCHI, NULL);
3219		lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCLO, NULL);
3220		bus->f1regdata += 2;
3221
3222		if ((hi == 0) && (lo == 0))
3223			break;
3224
3225		if ((hi > (lastrbc >> 8)) && (lo > (lastrbc & 0x00ff))) {
3226			DHD_ERROR(("%s: count growing: last 0x%04x now 0x%04x\n",
3227			           __FUNCTION__, lastrbc, ((hi << 8) + lo)));
3228		}
3229		lastrbc = (hi << 8) + lo;
3230	}
3231
3232	if (!retries) {
3233		DHD_ERROR(("%s: count never zeroed: last 0x%04x\n", __FUNCTION__, lastrbc));
3234	} else {
3235		DHD_INFO(("%s: flush took %d iterations\n", __FUNCTION__, (0xffff - retries)));
3236	}
3237
3238	if (rtx) {
3239		bus->rxrtx++;
3240		W_SDREG(SMB_NAK, &regs->tosbmailbox, retries);
3241		bus->f1regdata++;
3242		if (retries <= retry_limit) {
3243			bus->rxskip = TRUE;
3244		}
3245	}
3246
3247	/* Clear partial in any case */
3248	bus->nextlen = 0;
3249
3250	/* If we can't reach the device, signal failure */
3251	if (err || bcmsdh_regfail(sdh))
3252		bus->dhd->busstate = DHD_BUS_DOWN;
3253}
3254
3255static void
3256dhdsdio_read_control(dhd_bus_t *bus, uint8 *hdr, uint len, uint doff)
3257{
3258	bcmsdh_info_t *sdh = bus->sdh;
3259	uint rdlen, pad;
3260
3261	int sdret;
3262
3263	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3264
3265	/* Control data already received in aligned rxctl */
3266	if ((bus->bus == SPI_BUS) && (!bus->usebufpool))
3267		goto gotpkt;
3268
3269	ASSERT(bus->rxbuf);
3270	/* Set rxctl for frame (w/optional alignment) */
3271	bus->rxctl = bus->rxbuf;
3272	if (dhd_alignctl) {
3273		bus->rxctl += firstread;
3274		if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN)))
3275			bus->rxctl += (DHD_SDALIGN - pad);
3276		bus->rxctl -= firstread;
3277	}
3278	ASSERT(bus->rxctl >= bus->rxbuf);
3279
3280	/* Copy the already-read portion over */
3281	bcopy(hdr, bus->rxctl, firstread);
3282	if (len <= firstread)
3283		goto gotpkt;
3284
3285	/* Copy the full data pkt in gSPI case and process ioctl. */
3286	if (bus->bus == SPI_BUS) {
3287		bcopy(hdr, bus->rxctl, len);
3288		goto gotpkt;
3289	}
3290
3291	/* Raise rdlen to next SDIO block to avoid tail command */
3292	rdlen = len - firstread;
3293	if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
3294		pad = bus->blocksize - (rdlen % bus->blocksize);
3295		if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
3296		    ((len + pad) < bus->dhd->maxctl))
3297			rdlen += pad;
3298	} else if (rdlen % DHD_SDALIGN) {
3299		rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
3300	}
3301
3302	/* Satisfy length-alignment requirements */
3303	if (forcealign && (rdlen & (ALIGNMENT - 1)))
3304		rdlen = ROUNDUP(rdlen, ALIGNMENT);
3305
3306	/* Drop if the read is too big or it exceeds our maximum */
3307	if ((rdlen + firstread) > bus->dhd->maxctl) {
3308		DHD_ERROR(("%s: %d-byte control read exceeds %d-byte buffer\n",
3309		           __FUNCTION__, rdlen, bus->dhd->maxctl));
3310		bus->dhd->rx_errors++;
3311		dhdsdio_rxfail(bus, FALSE, FALSE);
3312		goto done;
3313	}
3314
3315	if ((len - doff) > bus->dhd->maxctl) {
3316		DHD_ERROR(("%s: %d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n",
3317		           __FUNCTION__, len, (len - doff), bus->dhd->maxctl));
3318		bus->dhd->rx_errors++; bus->rx_toolong++;
3319		dhdsdio_rxfail(bus, FALSE, FALSE);
3320		goto done;
3321	}
3322
3323
3324	/* Read remainder of frame body into the rxctl buffer */
3325	sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
3326	                            (bus->rxctl + firstread), rdlen, NULL, NULL, NULL);
3327	bus->f2rxdata++;
3328	ASSERT(sdret != BCME_PENDING);
3329
3330	/* Control frame failures need retransmission */
3331	if (sdret < 0) {
3332		DHD_ERROR(("%s: read %d control bytes failed: %d\n", __FUNCTION__, rdlen, sdret));
3333		bus->rxc_errors++; /* dhd.rx_ctlerrs is higher level */
3334		dhdsdio_rxfail(bus, TRUE, TRUE);
3335		goto done;
3336	}
3337
3338gotpkt:
3339
3340#ifdef DHD_DEBUG
3341	if (DHD_BYTES_ON() && DHD_CTL_ON()) {
3342		prhex("RxCtrl", bus->rxctl, len);
3343	}
3344#endif
3345
3346	/* Point to valid data and indicate its length */
3347	bus->rxctl += doff;
3348	bus->rxlen = len - doff;
3349
3350done:
3351	/* Awake any waiters */
3352	dhd_os_ioctl_resp_wake(bus->dhd);
3353}
3354
3355static uint8
3356dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq)
3357{
3358	uint16 dlen, totlen;
3359	uint8 *dptr, num = 0;
3360
3361	uint16 sublen, check;
3362	void *pfirst, *plast, *pnext, *save_pfirst;
3363	osl_t *osh = bus->dhd->osh;
3364
3365	int errcode;
3366	uint8 chan, seq, doff, sfdoff;
3367	uint8 txmax;
3368
3369	int ifidx = 0;
3370	bool usechain = bus->use_rxchain;
3371
3372	/* If packets, issue read(s) and send up packet chain */
3373	/* Return sequence numbers consumed? */
3374
3375	DHD_TRACE(("dhdsdio_rxglom: start: glomd %p glom %p\n", bus->glomd, bus->glom));
3376
3377	/* If there's a descriptor, generate the packet chain */
3378	if (bus->glomd) {
3379		dhd_os_sdlock_rxq(bus->dhd);
3380
3381		pfirst = plast = pnext = NULL;
3382		dlen = (uint16)PKTLEN(osh, bus->glomd);
3383		dptr = PKTDATA(osh, bus->glomd);
3384		if (!dlen || (dlen & 1)) {
3385			DHD_ERROR(("%s: bad glomd len (%d), ignore descriptor\n",
3386			           __FUNCTION__, dlen));
3387			dlen = 0;
3388		}
3389
3390		for (totlen = num = 0; dlen; num++) {
3391			/* Get (and move past) next length */
3392			sublen = ltoh16_ua(dptr);
3393			dlen -= sizeof(uint16);
3394			dptr += sizeof(uint16);
3395			if ((sublen < SDPCM_HDRLEN) ||
3396			    ((num == 0) && (sublen < (2 * SDPCM_HDRLEN)))) {
3397				DHD_ERROR(("%s: descriptor len %d bad: %d\n",
3398				           __FUNCTION__, num, sublen));
3399				pnext = NULL;
3400				break;
3401			}
3402			if (sublen % DHD_SDALIGN) {
3403				DHD_ERROR(("%s: sublen %d not a multiple of %d\n",
3404				           __FUNCTION__, sublen, DHD_SDALIGN));
3405				usechain = FALSE;
3406			}
3407			totlen += sublen;
3408
3409			/* For last frame, adjust read len so total is a block multiple */
3410			if (!dlen) {
3411				sublen += (ROUNDUP(totlen, bus->blocksize) - totlen);
3412				totlen = ROUNDUP(totlen, bus->blocksize);
3413			}
3414
3415			/* Allocate/chain packet for next subframe */
3416			if ((pnext = PKTGET(osh, sublen + DHD_SDALIGN, FALSE)) == NULL) {
3417				DHD_ERROR(("%s: PKTGET failed, num %d len %d\n",
3418				           __FUNCTION__, num, sublen));
3419				break;
3420			}
3421			ASSERT(!PKTLINK(pnext));
3422			if (!pfirst) {
3423				ASSERT(!plast);
3424				pfirst = plast = pnext;
3425			} else {
3426				ASSERT(plast);
3427				PKTSETNEXT(osh, plast, pnext);
3428				plast = pnext;
3429			}
3430
3431			/* Adhere to start alignment requirements */
3432			PKTALIGN(osh, pnext, sublen, DHD_SDALIGN);
3433		}
3434
3435		/* If all allocations succeeded, save packet chain in bus structure */
3436		if (pnext) {
3437			DHD_GLOM(("%s: allocated %d-byte packet chain for %d subframes\n",
3438			          __FUNCTION__, totlen, num));
3439			if (DHD_GLOM_ON() && bus->nextlen) {
3440				if (totlen != bus->nextlen) {
3441					DHD_GLOM(("%s: glomdesc mismatch: nextlen %d glomdesc %d "
3442					          "rxseq %d\n", __FUNCTION__, bus->nextlen,
3443					          totlen, rxseq));
3444				}
3445			}
3446			bus->glom = pfirst;
3447			pfirst = pnext = NULL;
3448		} else {
3449			if (pfirst)
3450				PKTFREE(osh, pfirst, FALSE);
3451			bus->glom = NULL;
3452			num = 0;
3453		}
3454
3455		/* Done with descriptor packet */
3456		PKTFREE(osh, bus->glomd, FALSE);
3457		bus->glomd = NULL;
3458		bus->nextlen = 0;
3459
3460		dhd_os_sdunlock_rxq(bus->dhd);
3461	}
3462
3463	/* Ok -- either we just generated a packet chain, or had one from before */
3464	if (bus->glom) {
3465		if (DHD_GLOM_ON()) {
3466			DHD_GLOM(("%s: attempt superframe read, packet chain:\n", __FUNCTION__));
3467			for (pnext = bus->glom; pnext; pnext = PKTNEXT(osh, pnext)) {
3468				DHD_GLOM(("    %p: %p len 0x%04x (%d)\n",
3469				          pnext, (uint8*)PKTDATA(osh, pnext),
3470				          PKTLEN(osh, pnext), PKTLEN(osh, pnext)));
3471			}
3472		}
3473
3474		pfirst = bus->glom;
3475		dlen = (uint16)pkttotlen(osh, pfirst);
3476
3477		/* Do an SDIO read for the superframe.  Configurable iovar to
3478		 * read directly into the chained packet, or allocate a large
3479		 * packet and and copy into the chain.
3480		 */
3481		if (usechain) {
3482			errcode = dhd_bcmsdh_recv_buf(bus,
3483			                              bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2,
3484			                              F2SYNC, (uint8*)PKTDATA(osh, pfirst),
3485			                              dlen, pfirst, NULL, NULL);
3486		} else if (bus->dataptr) {
3487			errcode = dhd_bcmsdh_recv_buf(bus,
3488			                              bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2,
3489			                              F2SYNC, bus->dataptr,
3490			                              dlen, NULL, NULL, NULL);
3491			sublen = (uint16)pktfrombuf(osh, pfirst, 0, dlen, bus->dataptr);
3492			if (sublen != dlen) {
3493				DHD_ERROR(("%s: FAILED TO COPY, dlen %d sublen %d\n",
3494				           __FUNCTION__, dlen, sublen));
3495				errcode = -1;
3496			}
3497			pnext = NULL;
3498		} else {
3499			DHD_ERROR(("COULDN'T ALLOC %d-BYTE GLOM, FORCE FAILURE\n", dlen));
3500			errcode = -1;
3501		}
3502		bus->f2rxdata++;
3503		ASSERT(errcode != BCME_PENDING);
3504
3505		/* On failure, kill the superframe, allow a couple retries */
3506		if (errcode < 0) {
3507			DHD_ERROR(("%s: glom read of %d bytes failed: %d\n",
3508			           __FUNCTION__, dlen, errcode));
3509			bus->dhd->rx_errors++;
3510
3511			if (bus->glomerr++ < 3) {
3512				dhdsdio_rxfail(bus, TRUE, TRUE);
3513			} else {
3514				bus->glomerr = 0;
3515				dhdsdio_rxfail(bus, TRUE, FALSE);
3516				dhd_os_sdlock_rxq(bus->dhd);
3517				PKTFREE(osh, bus->glom, FALSE);
3518				dhd_os_sdunlock_rxq(bus->dhd);
3519				bus->rxglomfail++;
3520				bus->glom = NULL;
3521			}
3522			return 0;
3523		}
3524
3525#ifdef DHD_DEBUG
3526		if (DHD_GLOM_ON()) {
3527			prhex("SUPERFRAME", PKTDATA(osh, pfirst),
3528			      MIN(PKTLEN(osh, pfirst), 48));
3529		}
3530#endif
3531
3532
3533		/* Validate the superframe header */
3534		dptr = (uint8 *)PKTDATA(osh, pfirst);
3535		sublen = ltoh16_ua(dptr);
3536		check = ltoh16_ua(dptr + sizeof(uint16));
3537
3538		chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
3539		seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
3540		bus->nextlen = dptr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
3541		if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
3542			DHD_INFO(("%s: got frame w/nextlen too large (%d) seq %d\n",
3543			          __FUNCTION__, bus->nextlen, seq));
3544			bus->nextlen = 0;
3545		}
3546		doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
3547		txmax = SDPCM_WINDOW_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
3548
3549		errcode = 0;
3550		if ((uint16)~(sublen^check)) {
3551			DHD_ERROR(("%s (superframe): HW hdr error: len/check 0x%04x/0x%04x\n",
3552			           __FUNCTION__, sublen, check));
3553			errcode = -1;
3554		} else if (ROUNDUP(sublen, bus->blocksize) != dlen) {
3555			DHD_ERROR(("%s (superframe): len 0x%04x, rounded 0x%04x, expect 0x%04x\n",
3556			           __FUNCTION__, sublen, ROUNDUP(sublen, bus->blocksize), dlen));
3557			errcode = -1;
3558		} else if (SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]) != SDPCM_GLOM_CHANNEL) {
3559			DHD_ERROR(("%s (superframe): bad channel %d\n", __FUNCTION__,
3560			           SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN])));
3561			errcode = -1;
3562		} else if (SDPCM_GLOMDESC(&dptr[SDPCM_FRAMETAG_LEN])) {
3563			DHD_ERROR(("%s (superframe): got second descriptor?\n", __FUNCTION__));
3564			errcode = -1;
3565		} else if ((doff < SDPCM_HDRLEN) ||
3566		           (doff > (PKTLEN(osh, pfirst) - SDPCM_HDRLEN))) {
3567			DHD_ERROR(("%s (superframe): Bad data offset %d: HW %d pkt %d min %d\n",
3568			           __FUNCTION__, doff, sublen, PKTLEN(osh, pfirst), SDPCM_HDRLEN));
3569			errcode = -1;
3570		}
3571
3572		/* Check sequence number of superframe SW header */
3573		if (rxseq != seq) {
3574			DHD_INFO(("%s: (superframe) rx_seq %d, expected %d\n",
3575			          __FUNCTION__, seq, rxseq));
3576			bus->rx_badseq++;
3577			rxseq = seq;
3578		}
3579
3580		/* Check window for sanity */
3581		if ((uint8)(txmax - bus->tx_seq) > 0x40) {
3582			DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
3583			           __FUNCTION__, txmax, bus->tx_seq));
3584			txmax = bus->tx_max;
3585		}
3586		bus->tx_max = txmax;
3587
3588		/* Remove superframe header, remember offset */
3589		PKTPULL(osh, pfirst, doff);
3590		sfdoff = doff;
3591
3592		/* Validate all the subframe headers */
3593		for (num = 0, pnext = pfirst; pnext && !errcode;
3594		     num++, pnext = PKTNEXT(osh, pnext)) {
3595			dptr = (uint8 *)PKTDATA(osh, pnext);
3596			dlen = (uint16)PKTLEN(osh, pnext);
3597			sublen = ltoh16_ua(dptr);
3598			check = ltoh16_ua(dptr + sizeof(uint16));
3599			chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
3600			doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
3601#ifdef DHD_DEBUG
3602			if (DHD_GLOM_ON()) {
3603				prhex("subframe", dptr, 32);
3604			}
3605#endif
3606
3607			if ((uint16)~(sublen^check)) {
3608				DHD_ERROR(("%s (subframe %d): HW hdr error: "
3609				           "len/check 0x%04x/0x%04x\n",
3610				           __FUNCTION__, num, sublen, check));
3611				errcode = -1;
3612			} else if ((sublen > dlen) || (sublen < SDPCM_HDRLEN)) {
3613				DHD_ERROR(("%s (subframe %d): length mismatch: "
3614				           "len 0x%04x, expect 0x%04x\n",
3615				           __FUNCTION__, num, sublen, dlen));
3616				errcode = -1;
3617			} else if ((chan != SDPCM_DATA_CHANNEL) &&
3618			           (chan != SDPCM_EVENT_CHANNEL)) {
3619				DHD_ERROR(("%s (subframe %d): bad channel %d\n",
3620				           __FUNCTION__, num, chan));
3621				errcode = -1;
3622			} else if ((doff < SDPCM_HDRLEN) || (doff > sublen)) {
3623				DHD_ERROR(("%s (subframe %d): Bad data offset %d: HW %d min %d\n",
3624				           __FUNCTION__, num, doff, sublen, SDPCM_HDRLEN));
3625				errcode = -1;
3626			}
3627		}
3628
3629		if (errcode) {
3630			/* Terminate frame on error, request a couple retries */
3631			if (bus->glomerr++ < 3) {
3632				/* Restore superframe header space */
3633				PKTPUSH(osh, pfirst, sfdoff);
3634				dhdsdio_rxfail(bus, TRUE, TRUE);
3635			} else {
3636				bus->glomerr = 0;
3637				dhdsdio_rxfail(bus, TRUE, FALSE);
3638				dhd_os_sdlock_rxq(bus->dhd);
3639				PKTFREE(osh, bus->glom, FALSE);
3640				dhd_os_sdunlock_rxq(bus->dhd);
3641				bus->rxglomfail++;
3642				bus->glom = NULL;
3643			}
3644			bus->nextlen = 0;
3645			return 0;
3646		}
3647
3648		/* Basic SD framing looks ok - process each packet (header) */
3649		save_pfirst = pfirst;
3650		bus->glom = NULL;
3651		plast = NULL;
3652
3653		dhd_os_sdlock_rxq(bus->dhd);
3654		for (num = 0; pfirst; rxseq++, pfirst = pnext) {
3655			pnext = PKTNEXT(osh, pfirst);
3656			PKTSETNEXT(osh, pfirst, NULL);
3657
3658			dptr = (uint8 *)PKTDATA(osh, pfirst);
3659			sublen = ltoh16_ua(dptr);
3660			chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
3661			seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
3662			doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
3663
3664			DHD_GLOM(("%s: Get subframe %d, %p(%p/%d), sublen %d chan %d seq %d\n",
3665			          __FUNCTION__, num, pfirst, PKTDATA(osh, pfirst),
3666			          PKTLEN(osh, pfirst), sublen, chan, seq));
3667
3668			ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL));
3669
3670			if (rxseq != seq) {
3671				DHD_GLOM(("%s: rx_seq %d, expected %d\n",
3672				          __FUNCTION__, seq, rxseq));
3673				bus->rx_badseq++;
3674				rxseq = seq;
3675			}
3676
3677#ifdef DHD_DEBUG
3678			if (DHD_BYTES_ON() && DHD_DATA_ON()) {
3679				prhex("Rx Subframe Data", dptr, dlen);
3680			}
3681#endif
3682
3683			PKTSETLEN(osh, pfirst, sublen);
3684			PKTPULL(osh, pfirst, doff);
3685
3686			if (PKTLEN(osh, pfirst) == 0) {
3687				PKTFREE(bus->dhd->osh, pfirst, FALSE);
3688				if (plast) {
3689					PKTSETNEXT(osh, plast, pnext);
3690				} else {
3691					ASSERT(save_pfirst == pfirst);
3692					save_pfirst = pnext;
3693				}
3694				continue;
3695			} else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pfirst) != 0) {
3696				DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__));
3697				bus->dhd->rx_errors++;
3698				PKTFREE(osh, pfirst, FALSE);
3699				if (plast) {
3700					PKTSETNEXT(osh, plast, pnext);
3701				} else {
3702					ASSERT(save_pfirst == pfirst);
3703					save_pfirst = pnext;
3704				}
3705				continue;
3706			}
3707
3708			/* this packet will go up, link back into chain and count it */
3709			PKTSETNEXT(osh, pfirst, pnext);
3710			plast = pfirst;
3711			num++;
3712
3713#ifdef DHD_DEBUG
3714			if (DHD_GLOM_ON()) {
3715				DHD_GLOM(("%s subframe %d to stack, %p(%p/%d) nxt/lnk %p/%p\n",
3716				          __FUNCTION__, num, pfirst,
3717				          PKTDATA(osh, pfirst), PKTLEN(osh, pfirst),
3718				          PKTNEXT(osh, pfirst), PKTLINK(pfirst)));
3719				prhex("", (uint8 *)PKTDATA(osh, pfirst),
3720				      MIN(PKTLEN(osh, pfirst), 32));
3721			}
3722#endif /* DHD_DEBUG */
3723		}
3724		dhd_os_sdunlock_rxq(bus->dhd);
3725		if (num) {
3726			dhd_os_sdunlock(bus->dhd);
3727			dhd_rx_frame(bus->dhd, ifidx, save_pfirst, num, 0);
3728			dhd_os_sdlock(bus->dhd);
3729		}
3730
3731		bus->rxglomframes++;
3732		bus->rxglompkts += num;
3733	}
3734	return num;
3735}
3736
3737/* Return TRUE if there may be more frames to read */
3738static uint
3739dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished)
3740{
3741	osl_t *osh = bus->dhd->osh;
3742	bcmsdh_info_t *sdh = bus->sdh;
3743
3744	uint16 len, check;	/* Extracted hardware header fields */
3745	uint8 chan, seq, doff;	/* Extracted software header fields */
3746	uint8 fcbits;		/* Extracted fcbits from software header */
3747	uint8 delta;
3748
3749	void *pkt;	/* Packet for event or data frames */
3750	uint16 pad;	/* Number of pad bytes to read */
3751	uint16 rdlen;	/* Total number of bytes to read */
3752	uint8 rxseq;	/* Next sequence number to expect */
3753	uint rxleft = 0;	/* Remaining number of frames allowed */
3754	int sdret;	/* Return code from bcmsdh calls */
3755	uint8 txmax;	/* Maximum tx sequence offered */
3756	bool len_consistent; /* Result of comparing readahead len and len from hw-hdr */
3757	uint8 *rxbuf;
3758	int ifidx = 0;
3759	uint rxcount = 0; /* Total frames read */
3760
3761#if defined(DHD_DEBUG) || defined(SDTEST)
3762	bool sdtest = FALSE;	/* To limit message spew from test mode */
3763#endif
3764
3765	DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3766
3767	ASSERT(maxframes);
3768
3769#ifdef SDTEST
3770	/* Allow pktgen to override maxframes */
3771	if (bus->pktgen_count && (bus->pktgen_mode == DHD_PKTGEN_RECV)) {
3772		maxframes = bus->pktgen_count;
3773		sdtest = TRUE;
3774	}
3775#endif
3776
3777	/* Not finished unless we encounter no more frames indication */
3778	*finished = FALSE;
3779
3780
3781	for (rxseq = bus->rx_seq, rxleft = maxframes;
3782	     !bus->rxskip && rxleft && bus->dhd->busstate != DHD_BUS_DOWN;
3783	     rxseq++, rxleft--) {
3784
3785#ifdef DHDTHREAD
3786		/* tx more to improve rx performance */
3787		if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate &&
3788			pktq_mlen(&bus->txq, ~bus->flowcontrol) && DATAOK(bus)) {
3789			dhdsdio_sendfromq(bus, dhd_txbound);
3790		}
3791#endif /* DHDTHREAD */
3792
3793		/* Handle glomming separately */
3794		if (bus->glom || bus->glomd) {
3795			uint8 cnt;
3796			DHD_GLOM(("%s: calling rxglom: glomd %p, glom %p\n",
3797			          __FUNCTION__, bus->glomd, bus->glom));
3798			cnt = dhdsdio_rxglom(bus, rxseq);
3799			DHD_GLOM(("%s: rxglom returned %d\n", __FUNCTION__, cnt));
3800			rxseq += cnt - 1;
3801			rxleft = (rxleft > cnt) ? (rxleft - cnt) : 1;
3802			continue;
3803		}
3804
3805		/* Try doing single read if we can */
3806		if (dhd_readahead && bus->nextlen) {
3807			uint16 nextlen = bus->nextlen;
3808			bus->nextlen = 0;
3809
3810			if (bus->bus == SPI_BUS) {
3811				rdlen = len = nextlen;
3812			}
3813			else {
3814				rdlen = len = nextlen << 4;
3815
3816				/* Pad read to blocksize for efficiency */
3817				if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
3818					pad = bus->blocksize - (rdlen % bus->blocksize);
3819					if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
3820						((rdlen + pad + firstread) < MAX_RX_DATASZ))
3821						rdlen += pad;
3822				} else if (rdlen % DHD_SDALIGN) {
3823					rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
3824				}
3825			}
3826
3827			/* We use bus->rxctl buffer in WinXP for initial control pkt receives.
3828			 * Later we use buffer-poll for data as well as control packets.
3829			 * This is required because dhd receives full frame in gSPI unlike SDIO.
3830			 * After the frame is received we have to distinguish whether it is data
3831			 * or non-data frame.
3832			 */
3833			/* Allocate a packet buffer */
3834			dhd_os_sdlock_rxq(bus->dhd);
3835			if (!(pkt = PKTGET(osh, rdlen + DHD_SDALIGN, FALSE))) {
3836				if (bus->bus == SPI_BUS) {
3837					bus->usebufpool = FALSE;
3838					bus->rxctl = bus->rxbuf;
3839					if (dhd_alignctl) {
3840						bus->rxctl += firstread;
3841						if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN)))
3842							bus->rxctl += (DHD_SDALIGN - pad);
3843						bus->rxctl -= firstread;
3844					}
3845					ASSERT(bus->rxctl >= bus->rxbuf);
3846					rxbuf = bus->rxctl;
3847					/* Read the entire frame */
3848					sdret = dhd_bcmsdh_recv_buf(bus,
3849					                            bcmsdh_cur_sbwad(sdh),
3850					                            SDIO_FUNC_2,
3851					                            F2SYNC, rxbuf, rdlen,
3852					                            NULL, NULL, NULL);
3853					bus->f2rxdata++;
3854					ASSERT(sdret != BCME_PENDING);
3855
3856
3857					/* Control frame failures need retransmission */
3858					if (sdret < 0) {
3859						DHD_ERROR(("%s: read %d control bytes failed: %d\n",
3860						   __FUNCTION__, rdlen, sdret));
3861						/* dhd.rx_ctlerrs is higher level */
3862						bus->rxc_errors++;
3863						dhd_os_sdunlock_rxq(bus->dhd);
3864						dhdsdio_rxfail(bus, TRUE,
3865						    (bus->bus == SPI_BUS) ? FALSE : TRUE);
3866						continue;
3867					}
3868				} else {
3869					/* Give up on data, request rtx of events */
3870					DHD_ERROR(("%s (nextlen): PKTGET failed: len %d rdlen %d "
3871					           "expected rxseq %d\n",
3872					           __FUNCTION__, len, rdlen, rxseq));
3873					/* Just go try again w/normal header read */
3874					dhd_os_sdunlock_rxq(bus->dhd);
3875					continue;
3876				}
3877			} else {
3878				if (bus->bus == SPI_BUS)
3879					bus->usebufpool = TRUE;
3880
3881				ASSERT(!PKTLINK(pkt));
3882				PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN);
3883				rxbuf = (uint8 *)PKTDATA(osh, pkt);
3884				/* Read the entire frame */
3885				sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh),
3886				                            SDIO_FUNC_2,
3887				                            F2SYNC, rxbuf, rdlen,
3888				                            pkt, NULL, NULL);
3889				bus->f2rxdata++;
3890				ASSERT(sdret != BCME_PENDING);
3891
3892				if (sdret < 0) {
3893					DHD_ERROR(("%s (nextlen): read %d bytes failed: %d\n",
3894					   __FUNCTION__, rdlen, sdret));
3895					PKTFREE(bus->dhd->osh, pkt, FALSE);
3896					bus->dhd->rx_errors++;
3897					dhd_os_sdunlock_rxq(bus->dhd);
3898					/* Force retry w/normal header read.  Don't attempt NAK for
3899					 * gSPI
3900					 */
3901					dhdsdio_rxfail(bus, TRUE,
3902					      (bus->bus == SPI_BUS) ? FALSE : TRUE);
3903					continue;
3904				}
3905			}
3906			dhd_os_sdunlock_rxq(bus->dhd);
3907
3908			/* Now check the header */
3909			bcopy(rxbuf, bus->rxhdr, SDPCM_HDRLEN);
3910
3911			/* Extract hardware header fields */
3912			len = ltoh16_ua(bus->rxhdr);
3913			check = ltoh16_ua(bus->rxhdr + sizeof(uint16));
3914
3915			/* All zeros means readahead info was bad */
3916			if (!(len|check)) {
3917				DHD_INFO(("%s (nextlen): read zeros in HW header???\n",
3918				           __FUNCTION__));
3919				dhd_os_sdlock_rxq(bus->dhd);
3920				PKTFREE2();
3921				dhd_os_sdunlock_rxq(bus->dhd);
3922				GSPI_PR55150_BAILOUT;
3923				continue;
3924			}
3925
3926			/* Validate check bytes */
3927			if ((uint16)~(len^check)) {
3928				DHD_ERROR(("%s (nextlen): HW hdr error: nextlen/len/check"
3929				           " 0x%04x/0x%04x/0x%04x\n", __FUNCTION__, nextlen,
3930				           len, check));
3931				dhd_os_sdlock_rxq(bus->dhd);
3932				PKTFREE2();
3933				dhd_os_sdunlock_rxq(bus->dhd);
3934				bus->rx_badhdr++;
3935				dhdsdio_rxfail(bus, FALSE, FALSE);
3936				GSPI_PR55150_BAILOUT;
3937				continue;
3938			}
3939
3940			/* Validate frame length */
3941			if (len < SDPCM_HDRLEN) {
3942				DHD_ERROR(("%s (nextlen): HW hdr length invalid: %d\n",
3943				           __FUNCTION__, len));
3944				dhd_os_sdlock_rxq(bus->dhd);
3945				PKTFREE2();
3946				dhd_os_sdunlock_rxq(bus->dhd);
3947				GSPI_PR55150_BAILOUT;
3948				continue;
3949			}
3950
3951			/* Check for consistency with readahead info */
3952				len_consistent = (nextlen != (ROUNDUP(len, 16) >> 4));
3953			if (len_consistent) {
3954				/* Mismatch, force retry w/normal header (may be >4K) */
3955				DHD_ERROR(("%s (nextlen): mismatch, nextlen %d len %d rnd %d; "
3956				           "expected rxseq %d\n",
3957				           __FUNCTION__, nextlen, len, ROUNDUP(len, 16), rxseq));
3958				dhd_os_sdlock_rxq(bus->dhd);
3959				PKTFREE2();
3960				dhd_os_sdunlock_rxq(bus->dhd);
3961				dhdsdio_rxfail(bus, TRUE, (bus->bus == SPI_BUS) ? FALSE : TRUE);
3962				GSPI_PR55150_BAILOUT;
3963				continue;
3964			}
3965
3966
3967			/* Extract software header fields */
3968			chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
3969			seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
3970			doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
3971			txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
3972
3973				bus->nextlen =
3974				         bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
3975				if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
3976					DHD_INFO(("%s (nextlen): got frame w/nextlen too large"
3977					          " (%d), seq %d\n", __FUNCTION__, bus->nextlen,
3978					          seq));
3979					bus->nextlen = 0;
3980				}
3981
3982				bus->dhd->rx_readahead_cnt ++;
3983			/* Handle Flow Control */
3984			fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
3985
3986			delta = 0;
3987			if (~bus->flowcontrol & fcbits) {
3988				bus->fc_xoff++;
3989				delta = 1;
3990			}
3991			if (bus->flowcontrol & ~fcbits) {
3992				bus->fc_xon++;
3993				delta = 1;
3994			}
3995
3996			if (delta) {
3997				bus->fc_rcvd++;
3998				bus->flowcontrol = fcbits;
3999			}
4000
4001			/* Check and update sequence number */
4002			if (rxseq != seq) {
4003				DHD_INFO(("%s (nextlen): rx_seq %d, expected %d\n",
4004				          __FUNCTION__, seq, rxseq));
4005				bus->rx_badseq++;
4006				rxseq = seq;
4007			}
4008
4009			/* Check window for sanity */
4010			if ((uint8)(txmax - bus->tx_seq) > 0x40) {
4011					DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
4012						__FUNCTION__, txmax, bus->tx_seq));
4013					txmax = bus->tx_max;
4014			}
4015			bus->tx_max = txmax;
4016
4017#ifdef DHD_DEBUG
4018			if (DHD_BYTES_ON() && DHD_DATA_ON()) {
4019				prhex("Rx Data", rxbuf, len);
4020			} else if (DHD_HDRS_ON()) {
4021				prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN);
4022			}
4023#endif
4024
4025			if (chan == SDPCM_CONTROL_CHANNEL) {
4026				if (bus->bus == SPI_BUS) {
4027					dhdsdio_read_control(bus, rxbuf, len, doff);
4028					if (bus->usebufpool) {
4029						dhd_os_sdlock_rxq(bus->dhd);
4030						PKTFREE(bus->dhd->osh, pkt, FALSE);
4031						dhd_os_sdunlock_rxq(bus->dhd);
4032					}
4033					continue;
4034				} else {
4035					DHD_ERROR(("%s (nextlen): readahead on control"
4036					           " packet %d?\n", __FUNCTION__, seq));
4037					/* Force retry w/normal header read */
4038					bus->nextlen = 0;
4039					dhdsdio_rxfail(bus, FALSE, TRUE);
4040					dhd_os_sdlock_rxq(bus->dhd);
4041					PKTFREE2();
4042					dhd_os_sdunlock_rxq(bus->dhd);
4043					continue;
4044				}
4045			}
4046
4047			if ((bus->bus == SPI_BUS) && !bus->usebufpool) {
4048				DHD_ERROR(("Received %d bytes on %d channel. Running out of "
4049				           "rx pktbuf's or not yet malloced.\n", len, chan));
4050				continue;
4051			}
4052
4053			/* Validate data offset */
4054			if ((doff < SDPCM_HDRLEN) || (doff > len)) {
4055				DHD_ERROR(("%s (nextlen): bad data offset %d: HW len %d min %d\n",
4056				           __FUNCTION__, doff, len, SDPCM_HDRLEN));
4057				dhd_os_sdlock_rxq(bus->dhd);
4058				PKTFREE2();
4059				dhd_os_sdunlock_rxq(bus->dhd);
4060				ASSERT(0);
4061				dhdsdio_rxfail(bus, FALSE, FALSE);
4062				continue;
4063			}
4064
4065			/* All done with this one -- now deliver the packet */
4066			goto deliver;
4067		}
4068		/* gSPI frames should not be handled in fractions */
4069		if (bus->bus == SPI_BUS) {
4070			break;
4071		}
4072
4073		/* Read frame header (hardware and software) */
4074		sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
4075		                            bus->rxhdr, firstread, NULL, NULL, NULL);
4076		bus->f2rxhdrs++;
4077		ASSERT(sdret != BCME_PENDING);
4078
4079		if (sdret < 0) {
4080			DHD_ERROR(("%s: RXHEADER FAILED: %d\n", __FUNCTION__, sdret));
4081			bus->rx_hdrfail++;
4082			dhdsdio_rxfail(bus, TRUE, TRUE);
4083			continue;
4084		}
4085
4086#ifdef DHD_DEBUG
4087		if (DHD_BYTES_ON() || DHD_HDRS_ON()) {
4088			prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN);
4089		}
4090#endif
4091
4092		/* Extract hardware header fields */
4093		len = ltoh16_ua(bus->rxhdr);
4094		check = ltoh16_ua(bus->rxhdr + sizeof(uint16));
4095
4096		/* All zeros means no more frames */
4097		if (!(len|check)) {
4098			*finished = TRUE;
4099			break;
4100		}
4101
4102		/* Validate check bytes */
4103		if ((uint16)~(len^check)) {
4104			DHD_ERROR(("%s: HW hdr error: len/check 0x%04x/0x%04x\n",
4105			           __FUNCTION__, len, check));
4106			bus->rx_badhdr++;
4107			dhdsdio_rxfail(bus, FALSE, FALSE);
4108			continue;
4109		}
4110
4111		/* Validate frame length */
4112		if (len < SDPCM_HDRLEN) {
4113			DHD_ERROR(("%s: HW hdr length invalid: %d\n", __FUNCTION__, len));
4114			continue;
4115		}
4116
4117		/* Extract software header fields */
4118		chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
4119		seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
4120		doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
4121		txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
4122
4123		/* Validate data offset */
4124		if ((doff < SDPCM_HDRLEN) || (doff > len)) {
4125			DHD_ERROR(("%s: Bad data offset %d: HW len %d, min %d seq %d\n",
4126			           __FUNCTION__, doff, len, SDPCM_HDRLEN, seq));
4127			bus->rx_badhdr++;
4128			ASSERT(0);
4129			dhdsdio_rxfail(bus, FALSE, FALSE);
4130			continue;
4131		}
4132
4133		/* Save the readahead length if there is one */
4134		bus->nextlen = bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
4135		if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
4136			DHD_INFO(("%s (nextlen): got frame w/nextlen too large (%d), seq %d\n",
4137			          __FUNCTION__, bus->nextlen, seq));
4138			bus->nextlen = 0;
4139		}
4140
4141		/* Handle Flow Control */
4142		fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
4143
4144		delta = 0;
4145		if (~bus->flowcontrol & fcbits) {
4146			bus->fc_xoff++;
4147			delta = 1;
4148		}
4149		if (bus->flowcontrol & ~fcbits) {
4150			bus->fc_xon++;
4151			delta = 1;
4152		}
4153
4154		if (delta) {
4155			bus->fc_rcvd++;
4156			bus->flowcontrol = fcbits;
4157		}
4158
4159		/* Check and update sequence number */
4160		if (rxseq != seq) {
4161			DHD_INFO(("%s: rx_seq %d, expected %d\n", __FUNCTION__, seq, rxseq));
4162			bus->rx_badseq++;
4163			rxseq = seq;
4164		}
4165
4166		/* Check window for sanity */
4167		if ((uint8)(txmax - bus->tx_seq) > 0x40) {
4168			DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
4169			           __FUNCTION__, txmax, bus->tx_seq));
4170			txmax = bus->tx_max;
4171		}
4172		bus->tx_max = txmax;
4173
4174		/* Call a separate function for control frames */
4175		if (chan == SDPCM_CONTROL_CHANNEL) {
4176			dhdsdio_read_control(bus, bus->rxhdr, len, doff);
4177			continue;
4178		}
4179
4180		ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL) ||
4181		       (chan == SDPCM_TEST_CHANNEL) || (chan == SDPCM_GLOM_CHANNEL));
4182
4183		/* Length to read */
4184		rdlen = (len > firstread) ? (len - firstread) : 0;
4185
4186		/* May pad read to blocksize for efficiency */
4187		if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
4188			pad = bus->blocksize - (rdlen % bus->blocksize);
4189			if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
4190			    ((rdlen + pad + firstread) < MAX_RX_DATASZ))
4191				rdlen += pad;
4192		} else if (rdlen % DHD_SDALIGN) {
4193			rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
4194		}
4195
4196		/* Satisfy length-alignment requirements */
4197		if (forcealign && (rdlen & (ALIGNMENT - 1)))
4198			rdlen = ROUNDUP(rdlen, ALIGNMENT);
4199
4200		if ((rdlen + firstread) > MAX_RX_DATASZ) {
4201			/* Too long -- skip this frame */
4202			DHD_ERROR(("%s: too long: len %d rdlen %d\n", __FUNCTION__, len, rdlen));
4203			bus->dhd->rx_errors++; bus->rx_toolong++;
4204			dhdsdio_rxfail(bus, FALSE, FALSE);
4205			continue;
4206		}
4207
4208		dhd_os_sdlock_rxq(bus->dhd);
4209		if (!(pkt = PKTGET(osh, (rdlen + firstread + DHD_SDALIGN), FALSE))) {
4210			/* Give up on data, request rtx of events */
4211			DHD_ERROR(("%s: PKTGET failed: rdlen %d chan %d\n",
4212			           __FUNCTION__, rdlen, chan));
4213			bus->dhd->rx_dropped++;
4214			dhd_os_sdunlock_rxq(bus->dhd);
4215			dhdsdio_rxfail(bus, FALSE, RETRYCHAN(chan));
4216			continue;
4217		}
4218		dhd_os_sdunlock_rxq(bus->dhd);
4219
4220		ASSERT(!PKTLINK(pkt));
4221
4222		/* Leave room for what we already read, and align remainder */
4223		ASSERT(firstread < (PKTLEN(osh, pkt)));
4224		PKTPULL(osh, pkt, firstread);
4225		PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN);
4226
4227		/* Read the remaining frame data */
4228		sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
4229		                            ((uint8 *)PKTDATA(osh, pkt)), rdlen, pkt, NULL, NULL);
4230		bus->f2rxdata++;
4231		ASSERT(sdret != BCME_PENDING);
4232
4233		if (sdret < 0) {
4234			DHD_ERROR(("%s: read %d %s bytes failed: %d\n", __FUNCTION__, rdlen,
4235			           ((chan == SDPCM_EVENT_CHANNEL) ? "event" :
4236			            ((chan == SDPCM_DATA_CHANNEL) ? "data" : "test")), sdret));
4237			dhd_os_sdlock_rxq(bus->dhd);
4238			PKTFREE(bus->dhd->osh, pkt, FALSE);
4239			dhd_os_sdunlock_rxq(bus->dhd);
4240			bus->dhd->rx_errors++;
4241			dhdsdio_rxfail(bus, TRUE, RETRYCHAN(chan));
4242			continue;
4243		}
4244
4245		/* Copy the already-read portion */
4246		PKTPUSH(osh, pkt, firstread);
4247		bcopy(bus->rxhdr, PKTDATA(osh, pkt), firstread);
4248
4249#ifdef DHD_DEBUG
4250		if (DHD_BYTES_ON() && DHD_DATA_ON()) {
4251			prhex("Rx Data", PKTDATA(osh, pkt), len);
4252		}
4253#endif
4254
4255deliver:
4256		/* Save superframe descriptor and allocate packet frame */
4257		if (chan == SDPCM_GLOM_CHANNEL) {
4258			if (SDPCM_GLOMDESC(&bus->rxhdr[SDPCM_FRAMETAG_LEN])) {
4259				DHD_GLOM(("%s: got glom descriptor, %d bytes:\n",
4260				          __FUNCTION__, len));
4261#ifdef DHD_DEBUG
4262				if (DHD_GLOM_ON()) {
4263					prhex("Glom Data", PKTDATA(osh, pkt), len);
4264				}
4265#endif
4266				PKTSETLEN(osh, pkt, len);
4267				ASSERT(doff == SDPCM_HDRLEN);
4268				PKTPULL(osh, pkt, SDPCM_HDRLEN);
4269				bus->glomd = pkt;
4270			} else {
4271				DHD_ERROR(("%s: glom superframe w/o descriptor!\n", __FUNCTION__));
4272				dhdsdio_rxfail(bus, FALSE, FALSE);
4273			}
4274			continue;
4275		}
4276
4277		/* Fill in packet len and prio, deliver upward */
4278		PKTSETLEN(osh, pkt, len);
4279		PKTPULL(osh, pkt, doff);
4280
4281#ifdef SDTEST
4282		/* Test channel packets are processed separately */
4283		if (chan == SDPCM_TEST_CHANNEL) {
4284			dhdsdio_testrcv(bus, pkt, seq);
4285			con