PageRenderTime 137ms CodeModel.GetById 35ms app.highlight 83ms 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

Large files files are truncated, but you can click here to view the full file

   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 

Large files files are truncated, but you can click here to view the full file