/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

Large files are truncated 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. #include <typedefs.h>
  27. #include <osl.h>
  28. #include <bcmsdh.h>
  29. #ifdef BCMEMBEDIMAGE
  30. #include BCMEMBEDIMAGE
  31. #endif /* BCMEMBEDIMAGE */
  32. #include <bcmdefs.h>
  33. #include <bcmutils.h>
  34. #include <bcmendian.h>
  35. #include <bcmdevs.h>
  36. #include <siutils.h>
  37. #include <hndpmu.h>
  38. #include <hndsoc.h>
  39. #include <bcmsdpcm.h>
  40. #if defined(DHD_DEBUG)
  41. #include <hndrte_armtrap.h>
  42. #include <hndrte_cons.h>
  43. #endif /* defined(DHD_DEBUG) */
  44. #include <sbchipc.h>
  45. #include <sbhnddma.h>
  46. #include <sdio.h>
  47. #include <sbsdio.h>
  48. #include <sbsdpcmdev.h>
  49. #include <bcmsdpcm.h>
  50. #include <bcmsdbus.h>
  51. #include <proto/ethernet.h>
  52. #include <proto/802.1d.h>
  53. #include <proto/802.11.h>
  54. #include <dngl_stats.h>
  55. #include <dhd.h>
  56. #include <dhd_bus.h>
  57. #include <dhd_proto.h>
  58. #include <dhd_dbg.h>
  59. #include <dhdioctl.h>
  60. #include <sdiovar.h>
  61. #ifndef DHDSDIO_MEM_DUMP_FNAME
  62. #define DHDSDIO_MEM_DUMP_FNAME "mem_dump"
  63. #endif
  64. #define QLEN 256 /* bulk rx and tx queue lengths */
  65. #define FCHI (QLEN - 10)
  66. #define FCLOW (FCHI / 2)
  67. #define PRIOMASK 7
  68. #define TXRETRIES 2 /* # of retries for tx frames */
  69. #define DHD_RXBOUND 50 /* Default for max rx frames in one scheduling */
  70. #define DHD_TXBOUND 20 /* Default for max tx frames in one scheduling */
  71. #define DHD_TXMINMAX 1 /* Max tx frames if rx still pending */
  72. #define MEMBLOCK 2048 /* Block size used for downloading of dongle image */
  73. #define MAX_NVRAMBUF_SIZE 4096 /* max nvram buf size */
  74. #define MAX_DATA_BUF (32 * 1024) /* Must be large enough to hold biggest possible glom */
  75. #ifndef DHD_FIRSTREAD
  76. #define DHD_FIRSTREAD 32
  77. #endif
  78. #if !ISPOWEROF2(DHD_FIRSTREAD)
  79. #error DHD_FIRSTREAD is not a power of 2!
  80. #endif
  81. /* Total length of frame header for dongle protocol */
  82. #define SDPCM_HDRLEN (SDPCM_FRAMETAG_LEN + SDPCM_SWHEADER_LEN)
  83. #ifdef SDTEST
  84. #define SDPCM_RESERVE (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN)
  85. #else
  86. #define SDPCM_RESERVE (SDPCM_HDRLEN + DHD_SDALIGN)
  87. #endif
  88. /* Space for header read, limit for data packets */
  89. #ifndef MAX_HDR_READ
  90. #define MAX_HDR_READ 32
  91. #endif
  92. #if !ISPOWEROF2(MAX_HDR_READ)
  93. #error MAX_HDR_READ is not a power of 2!
  94. #endif
  95. #define MAX_RX_DATASZ 2048
  96. /* Maximum milliseconds to wait for F2 to come up */
  97. #define DHD_WAIT_F2RDY 3000
  98. /* Bump up limit on waiting for HT to account for first startup;
  99. * if the image is doing a CRC calculation before programming the PMU
  100. * for HT availability, it could take a couple hundred ms more, so
  101. * max out at a 1 second (1000000us).
  102. */
  103. #if (PMU_MAX_TRANSITION_DLY <= 1000000)
  104. #undef PMU_MAX_TRANSITION_DLY
  105. #define PMU_MAX_TRANSITION_DLY 1000000
  106. #endif
  107. /* Value for ChipClockCSR during initial setup */
  108. #define DHD_INIT_CLKCTL1 (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ)
  109. #define DHD_INIT_CLKCTL2 (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP)
  110. /* Flags for SDH calls */
  111. #define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED)
  112. /* Packet free applicable unconditionally for sdio and sdspi. Conditional if
  113. * bufpool was present for gspi bus.
  114. */
  115. #define PKTFREE2() if ((bus->bus != SPI_BUS) || bus->usebufpool) \
  116. PKTFREE(bus->dhd->osh, pkt, FALSE);
  117. DHD_SPINWAIT_SLEEP_INIT(sdioh_spinwait_sleep);
  118. #if defined(OOB_INTR_ONLY)
  119. extern void bcmsdh_set_irq(int flag);
  120. #endif /* defined(OOB_INTR_ONLY) */
  121. #ifdef PROP_TXSTATUS
  122. extern void dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success);
  123. #endif
  124. #ifdef DHD_DEBUG
  125. /* Device console log buffer state */
  126. #define CONSOLE_LINE_MAX 192
  127. #define CONSOLE_BUFFER_MAX 2024
  128. typedef struct dhd_console {
  129. uint count; /* Poll interval msec counter */
  130. uint log_addr; /* Log struct address (fixed) */
  131. hndrte_log_t log; /* Log struct (host copy) */
  132. uint bufsize; /* Size of log buffer */
  133. uint8 *buf; /* Log buffer (host copy) */
  134. uint last; /* Last buffer read index */
  135. } dhd_console_t;
  136. #endif /* DHD_DEBUG */
  137. /* Private data for SDIO bus interaction */
  138. typedef struct dhd_bus {
  139. dhd_pub_t *dhd;
  140. bcmsdh_info_t *sdh; /* Handle for BCMSDH calls */
  141. si_t *sih; /* Handle for SI calls */
  142. char *vars; /* Variables (from CIS and/or other) */
  143. uint varsz; /* Size of variables buffer */
  144. uint32 sbaddr; /* Current SB window pointer (-1, invalid) */
  145. sdpcmd_regs_t *regs; /* Registers for SDIO core */
  146. uint sdpcmrev; /* SDIO core revision */
  147. uint armrev; /* CPU core revision */
  148. uint ramrev; /* SOCRAM core revision */
  149. uint32 ramsize; /* Size of RAM in SOCRAM (bytes) */
  150. uint32 orig_ramsize; /* Size of RAM in SOCRAM (bytes) */
  151. uint32 bus; /* gSPI or SDIO bus */
  152. uint32 hostintmask; /* Copy of Host Interrupt Mask */
  153. uint32 intstatus; /* Intstatus bits (events) pending */
  154. bool dpc_sched; /* Indicates DPC schedule (intrpt rcvd) */
  155. bool fcstate; /* State of dongle flow-control */
  156. uint16 cl_devid; /* cached devid for dhdsdio_probe_attach() */
  157. char *fw_path; /* module_param: path to firmware image */
  158. char *nv_path; /* module_param: path to nvram vars file */
  159. const char *nvram_params; /* user specified nvram params. */
  160. uint blocksize; /* Block size of SDIO transfers */
  161. uint roundup; /* Max roundup limit */
  162. struct pktq txq; /* Queue length used for flow-control */
  163. uint8 flowcontrol; /* per prio flow control bitmask */
  164. uint8 tx_seq; /* Transmit sequence number (next) */
  165. uint8 tx_max; /* Maximum transmit sequence allowed */
  166. uint8 hdrbuf[MAX_HDR_READ + DHD_SDALIGN];
  167. uint8 *rxhdr; /* Header of current rx frame (in hdrbuf) */
  168. uint16 nextlen; /* Next Read Len from last header */
  169. uint8 rx_seq; /* Receive sequence number (expected) */
  170. bool rxskip; /* Skip receive (awaiting NAK ACK) */
  171. void *glomd; /* Packet containing glomming descriptor */
  172. void *glom; /* Packet chain for glommed superframe */
  173. uint glomerr; /* Glom packet read errors */
  174. uint8 *rxbuf; /* Buffer for receiving control packets */
  175. uint rxblen; /* Allocated length of rxbuf */
  176. uint8 *rxctl; /* Aligned pointer into rxbuf */
  177. uint8 *databuf; /* Buffer for receiving big glom packet */
  178. uint8 *dataptr; /* Aligned pointer into databuf */
  179. uint rxlen; /* Length of valid data in buffer */
  180. uint8 sdpcm_ver; /* Bus protocol reported by dongle */
  181. bool intr; /* Use interrupts */
  182. bool poll; /* Use polling */
  183. bool ipend; /* Device interrupt is pending */
  184. bool intdis; /* Interrupts disabled by isr */
  185. uint intrcount; /* Count of device interrupt callbacks */
  186. uint lastintrs; /* Count as of last watchdog timer */
  187. uint spurious; /* Count of spurious interrupts */
  188. uint pollrate; /* Ticks between device polls */
  189. uint polltick; /* Tick counter */
  190. uint pollcnt; /* Count of active polls */
  191. #ifdef DHD_DEBUG
  192. dhd_console_t console; /* Console output polling support */
  193. uint console_addr; /* Console address from shared struct */
  194. #endif /* DHD_DEBUG */
  195. uint regfails; /* Count of R_REG/W_REG failures */
  196. uint clkstate; /* State of sd and backplane clock(s) */
  197. bool activity; /* Activity flag for clock down */
  198. int32 idletime; /* Control for activity timeout */
  199. int32 idlecount; /* Activity timeout counter */
  200. int32 idleclock; /* How to set bus driver when idle */
  201. int32 sd_divisor; /* Speed control to bus driver */
  202. int32 sd_mode; /* Mode control to bus driver */
  203. int32 sd_rxchain; /* If bcmsdh api accepts PKT chains */
  204. bool use_rxchain; /* If dhd should use PKT chains */
  205. bool sleeping; /* Is SDIO bus sleeping? */
  206. bool rxflow_mode; /* Rx flow control mode */
  207. bool rxflow; /* Is rx flow control on */
  208. uint prev_rxlim_hit; /* Is prev rx limit exceeded (per dpc schedule) */
  209. bool alp_only; /* Don't use HT clock (ALP only) */
  210. /* Field to decide if rx of control frames happen in rxbuf or lb-pool */
  211. bool usebufpool;
  212. #ifdef SDTEST
  213. /* external loopback */
  214. bool ext_loop;
  215. uint8 loopid;
  216. /* pktgen configuration */
  217. uint pktgen_freq; /* Ticks between bursts */
  218. uint pktgen_count; /* Packets to send each burst */
  219. uint pktgen_print; /* Bursts between count displays */
  220. uint pktgen_total; /* Stop after this many */
  221. uint pktgen_minlen; /* Minimum packet data len */
  222. uint pktgen_maxlen; /* Maximum packet data len */
  223. uint pktgen_mode; /* Configured mode: tx, rx, or echo */
  224. uint pktgen_stop; /* Number of tx failures causing stop */
  225. /* active pktgen fields */
  226. uint pktgen_tick; /* Tick counter for bursts */
  227. uint pktgen_ptick; /* Burst counter for printing */
  228. uint pktgen_sent; /* Number of test packets generated */
  229. uint pktgen_rcvd; /* Number of test packets received */
  230. uint pktgen_fail; /* Number of failed send attempts */
  231. uint16 pktgen_len; /* Length of next packet to send */
  232. #define PKTGEN_RCV_IDLE (0)
  233. #define PKTGEN_RCV_ONGOING (1)
  234. uint16 pktgen_rcv_state; /* receive state */
  235. uint pktgen_rcvd_rcvsession; /* test pkts rcvd per rcv session. */
  236. #endif /* SDTEST */
  237. /* Some additional counters */
  238. uint tx_sderrs; /* Count of tx attempts with sd errors */
  239. uint fcqueued; /* Tx packets that got queued */
  240. uint rxrtx; /* Count of rtx requests (NAK to dongle) */
  241. uint rx_toolong; /* Receive frames too long to receive */
  242. uint rxc_errors; /* SDIO errors when reading control frames */
  243. uint rx_hdrfail; /* SDIO errors on header reads */
  244. uint rx_badhdr; /* Bad received headers (roosync?) */
  245. uint rx_badseq; /* Mismatched rx sequence number */
  246. uint fc_rcvd; /* Number of flow-control events received */
  247. uint fc_xoff; /* Number which turned on flow-control */
  248. uint fc_xon; /* Number which turned off flow-control */
  249. uint rxglomfail; /* Failed deglom attempts */
  250. uint rxglomframes; /* Number of glom frames (superframes) */
  251. uint rxglompkts; /* Number of packets from glom frames */
  252. uint f2rxhdrs; /* Number of header reads */
  253. uint f2rxdata; /* Number of frame data reads */
  254. uint f2txdata; /* Number of f2 frame writes */
  255. uint f1regdata; /* Number of f1 register accesses */
  256. uint8 *ctrl_frame_buf;
  257. uint32 ctrl_frame_len;
  258. bool ctrl_frame_stat;
  259. uint32 rxint_mode; /* rx interrupt mode */
  260. } dhd_bus_t;
  261. /* clkstate */
  262. #define CLK_NONE 0
  263. #define CLK_SDONLY 1
  264. #define CLK_PENDING 2 /* Not used yet */
  265. #define CLK_AVAIL 3
  266. #define DHD_NOPMU(dhd) (FALSE)
  267. #ifdef DHD_DEBUG
  268. static int qcount[NUMPRIO];
  269. static int tx_packets[NUMPRIO];
  270. #endif /* DHD_DEBUG */
  271. /* Deferred transmit */
  272. const uint dhd_deferred_tx = 1;
  273. extern uint dhd_watchdog_ms;
  274. extern void dhd_os_wd_timer(void *bus, uint wdtick);
  275. /* Tx/Rx bounds */
  276. uint dhd_txbound;
  277. uint dhd_rxbound;
  278. uint dhd_txminmax = DHD_TXMINMAX;
  279. /* override the RAM size if possible */
  280. #define DONGLE_MIN_MEMSIZE (128 *1024)
  281. int dhd_dongle_memsize;
  282. static bool dhd_doflow;
  283. static bool dhd_alignctl;
  284. static bool sd1idle;
  285. static bool retrydata;
  286. #define RETRYCHAN(chan) (((chan) == SDPCM_EVENT_CHANNEL) || retrydata)
  287. static const uint watermark = 8;
  288. static const uint firstread = DHD_FIRSTREAD;
  289. #define HDATLEN (firstread - (SDPCM_HDRLEN))
  290. /* Retry count for register access failures */
  291. static const uint retry_limit = 20;
  292. /* Force even SD lengths (some host controllers mess up on odd bytes) */
  293. static bool forcealign;
  294. /* Flag to indicate if we should download firmware on driver load */
  295. uint dhd_download_fw_on_driverload = TRUE;
  296. #define ALIGNMENT 4
  297. #if defined(OOB_INTR_ONLY) && defined(HW_OOB)
  298. extern void bcmsdh_enable_hw_oob_intr(void *sdh, bool enable);
  299. #endif
  300. #if defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD)
  301. #error OOB_INTR_ONLY is NOT working with SDIO_ISR_THREAD
  302. #endif /* defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD) */
  303. #define PKTALIGN(osh, p, len, align) \
  304. do { \
  305. uint datalign; \
  306. datalign = (uintptr)PKTDATA((osh), (p)); \
  307. datalign = ROUNDUP(datalign, (align)) - datalign; \
  308. ASSERT(datalign < (align)); \
  309. ASSERT(PKTLEN((osh), (p)) >= ((len) + datalign)); \
  310. if (datalign) \
  311. PKTPULL((osh), (p), datalign); \
  312. PKTSETLEN((osh), (p), (len)); \
  313. } while (0)
  314. /* Limit on rounding up frames */
  315. static const uint max_roundup = 512;
  316. /* Try doing readahead */
  317. static bool dhd_readahead;
  318. /* To check if there's window offered */
  319. #define DATAOK(bus) \
  320. (((uint8)(bus->tx_max - bus->tx_seq) > 1) && \
  321. (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0))
  322. /* To check if there's window offered for ctrl frame */
  323. #define TXCTLOK(bus) \
  324. (((uint8)(bus->tx_max - bus->tx_seq) != 0) && \
  325. (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0))
  326. /* Macros to get register read/write status */
  327. /* NOTE: these assume a local dhdsdio_bus_t *bus! */
  328. #define R_SDREG(regvar, regaddr, retryvar) \
  329. do { \
  330. retryvar = 0; \
  331. do { \
  332. regvar = R_REG(bus->dhd->osh, regaddr); \
  333. } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \
  334. if(retryvar > 1) \
  335. DHD_ERROR(("%s: regvar[ %d ], retryvar[ %d ], regfails[ %d ], bcmsdh_regfail[ %d ] \n",__FUNCTION__,regvar, retryvar ,bus->regfails, bcmsdh_regfail(bus->sdh))); \
  336. if (retryvar) { \
  337. bus->regfails += (retryvar-1); \
  338. if (retryvar > retry_limit) { \
  339. DHD_ERROR(("%s: FAILED" #regvar "READ, LINE %d\n", \
  340. __FUNCTION__, __LINE__)); \
  341. regvar = 0; \
  342. } \
  343. } \
  344. } while (0)
  345. #define W_SDREG(regval, regaddr, retryvar) \
  346. do { \
  347. retryvar = 0; \
  348. do { \
  349. W_REG(bus->dhd->osh, regaddr, regval); \
  350. } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \
  351. if (retryvar) { \
  352. bus->regfails += (retryvar-1); \
  353. if (retryvar > retry_limit) \
  354. DHD_ERROR(("%s: FAILED REGISTER WRITE, LINE %d\n", \
  355. __FUNCTION__, __LINE__)); \
  356. } \
  357. } while (0)
  358. #define BUS_WAKE(bus) \
  359. do { \
  360. if ((bus)->sleeping) \
  361. dhdsdio_bussleep((bus), FALSE); \
  362. } while (0);
  363. /*
  364. * pktavail interrupts from dongle to host can be managed in 3 different ways
  365. * whenever there is a packet available in dongle to transmit to host.
  366. *
  367. * Mode 0: Dongle writes the software host mailbox and host is interrupted.
  368. * Mode 1: (sdiod core rev >= 4)
  369. * Device sets a new bit in the intstatus whenever there is a packet
  370. * available in fifo. Host can't clear this specific status bit until all the
  371. * packets are read from the FIFO. No need to ack dongle intstatus.
  372. * Mode 2: (sdiod core rev >= 4)
  373. * Device sets a bit in the intstatus, and host acks this by writing
  374. * one to this bit. Dongle won't generate anymore packet interrupts
  375. * until host reads all the packets from the dongle and reads a zero to
  376. * figure that there are no more packets. No need to disable host ints.
  377. * Need to ack the intstatus.
  378. */
  379. #define SDIO_DEVICE_HMB_RXINT 0 /* default old way */
  380. #define SDIO_DEVICE_RXDATAINT_MODE_0 1 /* from sdiod rev 4 */
  381. #define SDIO_DEVICE_RXDATAINT_MODE_1 2 /* from sdiod rev 4 */
  382. #define FRAME_AVAIL_MASK(bus) \
  383. ((bus->rxint_mode == SDIO_DEVICE_HMB_RXINT) ? I_HMB_FRAME_IND : I_XMTDATA_AVAIL)
  384. #define DHD_BUS SDIO_BUS
  385. #define PKT_AVAILABLE(bus, intstatus) ((intstatus) & (FRAME_AVAIL_MASK(bus)))
  386. #define HOSTINTMASK (I_HMB_SW_MASK | I_CHIPACTIVE)
  387. #define GSPI_PR55150_BAILOUT
  388. #ifdef SDTEST
  389. static void dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq);
  390. static void dhdsdio_sdtest_set(dhd_bus_t *bus, uint8 count);
  391. #endif
  392. #ifdef DHD_DEBUG
  393. static int dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size);
  394. static int dhd_serialconsole(dhd_bus_t *bus, bool get, bool enable, int *bcmerror);
  395. #endif /* DHD_DEBUG */
  396. static int dhdsdio_download_state(dhd_bus_t *bus, bool enter);
  397. static void dhdsdio_release(dhd_bus_t *bus, osl_t *osh);
  398. static void dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh);
  399. static void dhdsdio_disconnect(void *ptr);
  400. static bool dhdsdio_chipmatch(uint16 chipid);
  401. static bool dhdsdio_probe_attach(dhd_bus_t *bus, osl_t *osh, void *sdh,
  402. void * regsva, uint16 devid);
  403. static bool dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh);
  404. static bool dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh);
  405. static void dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation,
  406. bool reset_flag);
  407. static void dhd_dongle_setmemsize(struct dhd_bus *bus, int mem_size);
  408. static int dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags,
  409. uint8 *buf, uint nbytes,
  410. void *pkt, bcmsdh_cmplt_fn_t complete, void *handle);
  411. static int dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags,
  412. uint8 *buf, uint nbytes,
  413. void *pkt, bcmsdh_cmplt_fn_t complete, void *handle);
  414. static bool dhdsdio_download_firmware(dhd_bus_t *bus, osl_t *osh, void *sdh);
  415. static int _dhdsdio_download_firmware(dhd_bus_t *bus);
  416. static int dhdsdio_download_code_file(dhd_bus_t *bus, char *image_path);
  417. static int dhdsdio_download_nvram(dhd_bus_t *bus);
  418. #ifdef BCMEMBEDIMAGE
  419. static int dhdsdio_download_code_array(dhd_bus_t *bus);
  420. #endif
  421. #ifdef WLMEDIA_HTSF
  422. #include <htsf.h>
  423. extern uint32 dhd_get_htsf(void *dhd, int ifidx);
  424. #endif /* WLMEDIA_HTSF */
  425. extern int chip_is_b1;
  426. static void
  427. dhd_dongle_setmemsize(struct dhd_bus *bus, int mem_size)
  428. {
  429. int32 min_size = DONGLE_MIN_MEMSIZE;
  430. /* Restrict the memsize to user specified limit */
  431. DHD_ERROR(("user: Restrict the dongle ram size to %d, min accepted %d\n",
  432. dhd_dongle_memsize, min_size));
  433. if ((dhd_dongle_memsize > min_size) &&
  434. (dhd_dongle_memsize < (int32)bus->orig_ramsize))
  435. bus->ramsize = dhd_dongle_memsize;
  436. }
  437. static int
  438. dhdsdio_set_siaddr_window(dhd_bus_t *bus, uint32 address)
  439. {
  440. int err = 0;
  441. bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW,
  442. (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err);
  443. if (!err)
  444. bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID,
  445. (address >> 16) & SBSDIO_SBADDRMID_MASK, &err);
  446. if (!err)
  447. bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH,
  448. (address >> 24) & SBSDIO_SBADDRHIGH_MASK, &err);
  449. return err;
  450. }
  451. /* Turn backplane clock on or off */
  452. static int
  453. dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok)
  454. {
  455. int err;
  456. uint8 clkctl, clkreq, devctl;
  457. bcmsdh_info_t *sdh;
  458. DHD_TRACE(("%s: Enter\n", __FUNCTION__));
  459. #if defined(OOB_INTR_ONLY)
  460. pendok = FALSE;
  461. #endif
  462. clkctl = 0;
  463. sdh = bus->sdh;
  464. if (on) {
  465. /* Request HT Avail */
  466. clkreq = bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ;
  467. bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
  468. if (err) {
  469. DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err));
  470. return BCME_ERROR;
  471. }
  472. if (pendok &&
  473. ((bus->sih->buscoretype == PCMCIA_CORE_ID) && (bus->sih->buscorerev == 9))) {
  474. uint32 dummy, retries;
  475. R_SDREG(dummy, &bus->regs->clockctlstatus, retries);
  476. }
  477. /* Check current status */
  478. clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
  479. if (err) {
  480. DHD_ERROR(("%s: HT Avail read error: %d\n", __FUNCTION__, err));
  481. return BCME_ERROR;
  482. }
  483. /* Go to pending and await interrupt if appropriate */
  484. if (!SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) {
  485. /* Allow only clock-available interrupt */
  486. devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
  487. if (err) {
  488. DHD_ERROR(("%s: Devctl access error setting CA: %d\n",
  489. __FUNCTION__, err));
  490. return BCME_ERROR;
  491. }
  492. devctl |= SBSDIO_DEVCTL_CA_INT_ONLY;
  493. bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
  494. DHD_INFO(("CLKCTL: set PENDING\n"));
  495. bus->clkstate = CLK_PENDING;
  496. return BCME_OK;
  497. } else if (bus->clkstate == CLK_PENDING) {
  498. /* Cancel CA-only interrupt filter */
  499. devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
  500. devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
  501. bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
  502. }
  503. /* Otherwise, wait here (polling) for HT Avail */
  504. if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
  505. SPINWAIT_SLEEP(sdioh_spinwait_sleep,
  506. ((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
  507. SBSDIO_FUNC1_CHIPCLKCSR, &err)),
  508. !SBSDIO_CLKAV(clkctl, bus->alp_only)), PMU_MAX_TRANSITION_DLY);
  509. }
  510. if (err) {
  511. DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err));
  512. return BCME_ERROR;
  513. }
  514. if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
  515. DHD_ERROR(("%s: HT Avail timeout (%d): clkctl 0x%02x\n",
  516. __FUNCTION__, PMU_MAX_TRANSITION_DLY, clkctl));
  517. return BCME_ERROR;
  518. }
  519. /* Mark clock available */
  520. bus->clkstate = CLK_AVAIL;
  521. DHD_INFO(("CLKCTL: turned ON\n"));
  522. #if defined(DHD_DEBUG)
  523. if (bus->alp_only == TRUE) {
  524. #if !defined(BCMLXSDMMC)
  525. if (!SBSDIO_ALPONLY(clkctl)) {
  526. DHD_ERROR(("%s: HT Clock, when ALP Only\n", __FUNCTION__));
  527. }
  528. #endif /* !defined(BCMLXSDMMC) */
  529. } else {
  530. if (SBSDIO_ALPONLY(clkctl)) {
  531. DHD_ERROR(("%s: HT Clock should be on.\n", __FUNCTION__));
  532. }
  533. }
  534. #endif /* defined (DHD_DEBUG) */
  535. bus->activity = TRUE;
  536. } else {
  537. clkreq = 0;
  538. if (bus->clkstate == CLK_PENDING) {
  539. /* Cancel CA-only interrupt filter */
  540. devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
  541. devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
  542. bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
  543. }
  544. bus->clkstate = CLK_SDONLY;
  545. bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
  546. DHD_INFO(("CLKCTL: turned OFF\n"));
  547. if (err) {
  548. DHD_ERROR(("%s: Failed access turning clock off: %d\n",
  549. __FUNCTION__, err));
  550. return BCME_ERROR;
  551. }
  552. }
  553. return BCME_OK;
  554. }
  555. /* Change idle/active SD state */
  556. static int
  557. dhdsdio_sdclk(dhd_bus_t *bus, bool on)
  558. {
  559. int err;
  560. int32 iovalue;
  561. DHD_TRACE(("%s: Enter\n", __FUNCTION__));
  562. if (on) {
  563. if (bus->idleclock == DHD_IDLE_STOP) {
  564. /* Turn on clock and restore mode */
  565. iovalue = 1;
  566. err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0,
  567. &iovalue, sizeof(iovalue), TRUE);
  568. if (err) {
  569. DHD_ERROR(("%s: error enabling sd_clock: %d\n",
  570. __FUNCTION__, err));
  571. return BCME_ERROR;
  572. }
  573. iovalue = bus->sd_mode;
  574. err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
  575. &iovalue, sizeof(iovalue), TRUE);
  576. if (err) {
  577. DHD_ERROR(("%s: error changing sd_mode: %d\n",
  578. __FUNCTION__, err));
  579. return BCME_ERROR;
  580. }
  581. } else if (bus->idleclock != DHD_IDLE_ACTIVE) {
  582. /* Restore clock speed */
  583. iovalue = bus->sd_divisor;
  584. err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
  585. &iovalue, sizeof(iovalue), TRUE);
  586. if (err) {
  587. DHD_ERROR(("%s: error restoring sd_divisor: %d\n",
  588. __FUNCTION__, err));
  589. return BCME_ERROR;
  590. }
  591. }
  592. bus->clkstate = CLK_SDONLY;
  593. } else {
  594. /* Stop or slow the SD clock itself */
  595. if ((bus->sd_divisor == -1) || (bus->sd_mode == -1)) {
  596. DHD_TRACE(("%s: can't idle clock, divisor %d mode %d\n",
  597. __FUNCTION__, bus->sd_divisor, bus->sd_mode));
  598. return BCME_ERROR;
  599. }
  600. if (bus->idleclock == DHD_IDLE_STOP) {
  601. if (sd1idle) {
  602. /* Change to SD1 mode and turn off clock */
  603. iovalue = 1;
  604. err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
  605. &iovalue, sizeof(iovalue), TRUE);
  606. if (err) {
  607. DHD_ERROR(("%s: error changing sd_clock: %d\n",
  608. __FUNCTION__, err));
  609. return BCME_ERROR;
  610. }
  611. }
  612. iovalue = 0;
  613. err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0,
  614. &iovalue, sizeof(iovalue), TRUE);
  615. if (err) {
  616. DHD_ERROR(("%s: error disabling sd_clock: %d\n",
  617. __FUNCTION__, err));
  618. return BCME_ERROR;
  619. }
  620. } else if (bus->idleclock != DHD_IDLE_ACTIVE) {
  621. /* Set divisor to idle value */
  622. iovalue = bus->idleclock;
  623. err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
  624. &iovalue, sizeof(iovalue), TRUE);
  625. if (err) {
  626. DHD_ERROR(("%s: error changing sd_divisor: %d\n",
  627. __FUNCTION__, err));
  628. return BCME_ERROR;
  629. }
  630. }
  631. bus->clkstate = CLK_NONE;
  632. }
  633. return BCME_OK;
  634. }
  635. /* Transition SD and backplane clock readiness */
  636. static int
  637. dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok)
  638. {
  639. int ret = BCME_OK;
  640. #ifdef DHD_DEBUG
  641. uint oldstate = bus->clkstate;
  642. #endif /* DHD_DEBUG */
  643. DHD_TRACE(("%s: Enter\n", __FUNCTION__));
  644. /* Early exit if we're already there */
  645. if (bus->clkstate == target) {
  646. if (target == CLK_AVAIL) {
  647. dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
  648. bus->activity = TRUE;
  649. }
  650. return ret;
  651. }
  652. switch (target) {
  653. case CLK_AVAIL:
  654. /* Make sure SD clock is available */
  655. if (bus->clkstate == CLK_NONE)
  656. dhdsdio_sdclk(bus, TRUE);
  657. /* Now request HT Avail on the backplane */
  658. ret = dhdsdio_htclk(bus, TRUE, pendok);
  659. if (ret == BCME_OK) {
  660. dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
  661. bus->activity = TRUE;
  662. }
  663. break;
  664. case CLK_SDONLY:
  665. /* Remove HT request, or bring up SD clock */
  666. if (bus->clkstate == CLK_NONE)
  667. ret = dhdsdio_sdclk(bus, TRUE);
  668. else if (bus->clkstate == CLK_AVAIL)
  669. ret = dhdsdio_htclk(bus, FALSE, FALSE);
  670. else
  671. DHD_ERROR(("dhdsdio_clkctl: request for %d -> %d\n",
  672. bus->clkstate, target));
  673. if (ret == BCME_OK) {
  674. dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
  675. }
  676. break;
  677. case CLK_NONE:
  678. /* Make sure to remove HT request */
  679. if (bus->clkstate == CLK_AVAIL)
  680. ret = dhdsdio_htclk(bus, FALSE, FALSE);
  681. /* Now remove the SD clock */
  682. ret = dhdsdio_sdclk(bus, FALSE);
  683. #ifdef DHD_DEBUG
  684. if (dhd_console_ms == 0)
  685. #endif /* DHD_DEBUG */
  686. if (bus->poll == 0)
  687. dhd_os_wd_timer(bus->dhd, 0);
  688. break;
  689. }
  690. #ifdef DHD_DEBUG
  691. DHD_INFO(("dhdsdio_clkctl: %d -> %d\n", oldstate, bus->clkstate));
  692. #endif /* DHD_DEBUG */
  693. return ret;
  694. }
  695. static int
  696. dhdsdio_bussleep(dhd_bus_t *bus, bool sleep)
  697. {
  698. bcmsdh_info_t *sdh = bus->sdh;
  699. sdpcmd_regs_t *regs = bus->regs;
  700. uint retries = 0;
  701. DHD_INFO(("dhdsdio_bussleep: request %s (currently %s)\n",
  702. (sleep ? "SLEEP" : "WAKE"),
  703. (bus->sleeping ? "SLEEP" : "WAKE")));
  704. /* Done if we're already in the requested state */
  705. if (sleep == bus->sleeping)
  706. return BCME_OK;
  707. /* Going to sleep: set the alarm and turn off the lights... */
  708. if (sleep) {
  709. /* Don't sleep if something is pending */
  710. if (bus->dpc_sched || bus->rxskip || pktq_len(&bus->txq))
  711. return BCME_BUSY;
  712. /* Disable SDIO interrupts (no longer interested) */
  713. bcmsdh_intr_disable(bus->sdh);
  714. /* Make sure the controller has the bus up */
  715. dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
  716. /* Tell device to start using OOB wakeup */
  717. W_SDREG(SMB_USE_OOB, &regs->tosbmailbox, retries);
  718. if (retries > retry_limit)
  719. DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
  720. /* Turn off our contribution to the HT clock request */
  721. dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
  722. bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
  723. SBSDIO_FORCE_HW_CLKREQ_OFF, NULL);
  724. /* Isolate the bus */
  725. if (bus->sih->chip != BCM4329_CHIP_ID && bus->sih->chip != BCM4319_CHIP_ID) {
  726. bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL,
  727. SBSDIO_DEVCTL_PADS_ISO, NULL);
  728. }
  729. /* Change state */
  730. bus->sleeping = TRUE;
  731. } else {
  732. /* Waking up: bus power up is ok, set local state */
  733. bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
  734. 0, NULL);
  735. /* Force pad isolation off if possible (in case power never toggled) */
  736. bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, 0, NULL);
  737. /* Make sure the controller has the bus up */
  738. dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
  739. /* Send misc interrupt to indicate OOB not needed */
  740. W_SDREG(0, &regs->tosbmailboxdata, retries);
  741. if (retries <= retry_limit)
  742. W_SDREG(SMB_DEV_INT, &regs->tosbmailbox, retries);
  743. if (retries > retry_limit)
  744. DHD_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n"));
  745. /* Make sure we have SD bus access */
  746. dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
  747. /* Change state */
  748. bus->sleeping = FALSE;
  749. /* Enable interrupts again */
  750. if (bus->intr && (bus->dhd->busstate == DHD_BUS_DATA)) {
  751. bus->intdis = FALSE;
  752. bcmsdh_intr_enable(bus->sdh);
  753. }
  754. }
  755. return BCME_OK;
  756. }
  757. #if defined(OOB_INTR_ONLY)
  758. void
  759. dhd_enable_oob_intr(struct dhd_bus *bus, bool enable)
  760. {
  761. #if defined(HW_OOB)
  762. bcmsdh_enable_hw_oob_intr(bus->sdh, enable);
  763. #else
  764. sdpcmd_regs_t *regs = bus->regs;
  765. uint retries = 0;
  766. dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
  767. if (enable == TRUE) {
  768. /* Tell device to start using OOB wakeup */
  769. W_SDREG(SMB_USE_OOB, &regs->tosbmailbox, retries);
  770. if (retries > retry_limit)
  771. DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
  772. } else {
  773. /* Send misc interrupt to indicate OOB not needed */
  774. W_SDREG(0, &regs->tosbmailboxdata, retries);
  775. if (retries <= retry_limit)
  776. W_SDREG(SMB_DEV_INT, &regs->tosbmailbox, retries);
  777. }
  778. /* Turn off our contribution to the HT clock request */
  779. dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
  780. #endif /* !defined(HW_OOB) */
  781. }
  782. #endif /* defined(OOB_INTR_ONLY) */
  783. /* Writes a HW/SW header into the packet and sends it. */
  784. /* Assumes: (a) header space already there, (b) caller holds lock */
  785. static int
  786. dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt)
  787. {
  788. int ret;
  789. osl_t *osh;
  790. uint8 *frame;
  791. uint16 len, pad1 = 0;
  792. uint32 swheader;
  793. uint retries = 0;
  794. bcmsdh_info_t *sdh;
  795. void *new;
  796. int i;
  797. #ifdef WLMEDIA_HTSF
  798. char *p;
  799. htsfts_t *htsf_ts;
  800. #endif
  801. DHD_TRACE(("%s: Enter\n", __FUNCTION__));
  802. sdh = bus->sdh;
  803. osh = bus->dhd->osh;
  804. if (bus->dhd->dongle_reset) {
  805. ret = BCME_NOTREADY;
  806. goto done;
  807. }
  808. frame = (uint8*)PKTDATA(osh, pkt);
  809. #ifdef WLMEDIA_HTSF
  810. if (PKTLEN(osh, pkt) >= 100) {
  811. p = PKTDATA(osh, pkt);
  812. htsf_ts = (htsfts_t*) (p + HTSF_HOSTOFFSET + 12);
  813. if (htsf_ts->magic == HTSFMAGIC) {
  814. htsf_ts->c20 = get_cycles();
  815. htsf_ts->t20 = dhd_get_htsf(bus->dhd->info, 0);
  816. }
  817. }
  818. #endif /* WLMEDIA_HTSF */
  819. /* Add alignment padding, allocate new packet if needed */
  820. if ((pad1 = ((uintptr)frame % DHD_SDALIGN))) {
  821. if (PKTHEADROOM(osh, pkt) < pad1) {
  822. DHD_INFO(("%s: insufficient headroom %d for %d pad1\n",
  823. __FUNCTION__, (int)PKTHEADROOM(osh, pkt), pad1));
  824. bus->dhd->tx_realloc++;
  825. new = PKTGET(osh, (PKTLEN(osh, pkt) + DHD_SDALIGN), TRUE);
  826. if (!new) {
  827. DHD_ERROR(("%s: couldn't allocate new %d-byte packet\n",
  828. __FUNCTION__, PKTLEN(osh, pkt) + DHD_SDALIGN));
  829. ret = BCME_NOMEM;
  830. goto done;
  831. }
  832. PKTALIGN(osh, new, PKTLEN(osh, pkt), DHD_SDALIGN);
  833. bcopy(PKTDATA(osh, pkt), PKTDATA(osh, new), PKTLEN(osh, pkt));
  834. if (free_pkt)
  835. PKTFREE(osh, pkt, TRUE);
  836. /* free the pkt if canned one is not used */
  837. free_pkt = TRUE;
  838. pkt = new;
  839. frame = (uint8*)PKTDATA(osh, pkt);
  840. ASSERT(((uintptr)frame % DHD_SDALIGN) == 0);
  841. pad1 = 0;
  842. } else {
  843. PKTPUSH(osh, pkt, pad1);
  844. frame = (uint8*)PKTDATA(osh, pkt);
  845. ASSERT((pad1 + SDPCM_HDRLEN) <= (int) PKTLEN(osh, pkt));
  846. bzero(frame, pad1 + SDPCM_HDRLEN);
  847. }
  848. }
  849. ASSERT(pad1 < DHD_SDALIGN);
  850. /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
  851. len = (uint16)PKTLEN(osh, pkt);
  852. *(uint16*)frame = htol16(len);
  853. *(((uint16*)frame) + 1) = htol16(~len);
  854. /* Software tag: channel, sequence number, data offset */
  855. swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) | bus->tx_seq |
  856. (((pad1 + SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
  857. htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN);
  858. htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
  859. #ifdef DHD_DEBUG
  860. if (PKTPRIO(pkt) < ARRAYSIZE(tx_packets)) {
  861. tx_packets[PKTPRIO(pkt)]++;
  862. }
  863. if (DHD_BYTES_ON() &&
  864. (((DHD_CTL_ON() && (chan == SDPCM_CONTROL_CHANNEL)) ||
  865. (DHD_DATA_ON() && (chan != SDPCM_CONTROL_CHANNEL))))) {
  866. prhex("Tx Frame", frame, len);
  867. } else if (DHD_HDRS_ON()) {
  868. prhex("TxHdr", frame, MIN(len, 16));
  869. }
  870. #endif
  871. /* Raise len to next SDIO block to eliminate tail command */
  872. if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
  873. uint16 pad2 = bus->blocksize - (len % bus->blocksize);
  874. if ((pad2 <= bus->roundup) && (pad2 < bus->blocksize))
  875. #ifdef NOTUSED
  876. if (pad2 <= PKTTAILROOM(osh, pkt))
  877. #endif /* NOTUSED */
  878. len += pad2;
  879. } else if (len % DHD_SDALIGN) {
  880. len += DHD_SDALIGN - (len % DHD_SDALIGN);
  881. }
  882. /* Some controllers have trouble with odd bytes -- round to even */
  883. if (forcealign && (len & (ALIGNMENT - 1))) {
  884. #ifdef NOTUSED
  885. if (PKTTAILROOM(osh, pkt))
  886. #endif
  887. len = ROUNDUP(len, ALIGNMENT);
  888. #ifdef NOTUSED
  889. else
  890. DHD_ERROR(("%s: sending unrounded %d-byte packet\n", __FUNCTION__, len));
  891. #endif
  892. }
  893. do {
  894. ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
  895. frame, len, pkt, NULL, NULL);
  896. bus->f2txdata++;
  897. ASSERT(ret != BCME_PENDING);
  898. if (ret < 0) {
  899. /* On failure, abort the command and terminate the frame */
  900. DHD_INFO(("%s: sdio error %d, abort command and terminate frame.\n",
  901. __FUNCTION__, ret));
  902. bus->tx_sderrs++;
  903. bcmsdh_abort(sdh, SDIO_FUNC_2);
  904. bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
  905. SFC_WF_TERM, NULL);
  906. bus->f1regdata++;
  907. for (i = 0; i < 3; i++) {
  908. uint8 hi, lo;
  909. hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
  910. SBSDIO_FUNC1_WFRAMEBCHI, NULL);
  911. lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
  912. SBSDIO_FUNC1_WFRAMEBCLO, NULL);
  913. bus->f1regdata += 2;
  914. if ((hi == 0) && (lo == 0))
  915. break;
  916. }
  917. }
  918. if (ret == 0) {
  919. bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
  920. }
  921. } while ((ret < 0) && retrydata && retries++ < TXRETRIES);
  922. done:
  923. /* restore pkt buffer pointer before calling tx complete routine */
  924. PKTPULL(osh, pkt, SDPCM_HDRLEN + pad1);
  925. #ifdef PROP_TXSTATUS
  926. if (bus->dhd->wlfc_state) {
  927. dhd_os_sdunlock(bus->dhd);
  928. dhd_wlfc_txcomplete(bus->dhd, pkt, ret == 0);
  929. dhd_os_sdlock(bus->dhd);
  930. } else {
  931. #endif /* PROP_TXSTATUS */
  932. dhd_txcomplete(bus->dhd, pkt, ret != 0);
  933. if (free_pkt)
  934. PKTFREE(osh, pkt, TRUE);
  935. #ifdef PROP_TXSTATUS
  936. }
  937. #endif
  938. return ret;
  939. }
  940. int
  941. dhd_bus_txdata(struct dhd_bus *bus, void *pkt)
  942. {
  943. int ret = BCME_ERROR;
  944. osl_t *osh;
  945. uint datalen, prec;
  946. DHD_TRACE(("%s: Enter\n", __FUNCTION__));
  947. osh = bus->dhd->osh;
  948. datalen = PKTLEN(osh, pkt);
  949. #ifdef SDTEST
  950. /* Push the test header if doing loopback */
  951. if (bus->ext_loop) {
  952. uint8* data;
  953. PKTPUSH(osh, pkt, SDPCM_TEST_HDRLEN);
  954. data = PKTDATA(osh, pkt);
  955. *data++ = SDPCM_TEST_ECHOREQ;
  956. *data++ = (uint8)bus->loopid++;
  957. *data++ = (datalen >> 0);
  958. *data++ = (datalen >> 8);
  959. datalen += SDPCM_TEST_HDRLEN;
  960. }
  961. #endif /* SDTEST */
  962. /* Add space for the header */
  963. PKTPUSH(osh, pkt, SDPCM_HDRLEN);
  964. ASSERT(ISALIGNED((uintptr)PKTDATA(osh, pkt), 2));
  965. prec = PRIO2PREC((PKTPRIO(pkt) & PRIOMASK));
  966. #ifndef DHDTHREAD
  967. /* Lock: we're about to use shared data/code (and SDIO) */
  968. dhd_os_sdlock(bus->dhd);
  969. #endif /* DHDTHREAD */
  970. /* Check for existing queue, current flow-control, pending event, or pending clock */
  971. if (dhd_deferred_tx || bus->fcstate || pktq_len(&bus->txq) || bus->dpc_sched ||
  972. (!DATAOK(bus)) || (bus->flowcontrol & NBITVAL(prec)) ||
  973. (bus->clkstate != CLK_AVAIL)) {
  974. DHD_TRACE(("%s: deferring pktq len %d\n", __FUNCTION__,
  975. pktq_len(&bus->txq)));
  976. bus->fcqueued++;
  977. /* Priority based enq */
  978. dhd_os_sdlock_txq(bus->dhd);
  979. if (dhd_prec_enq(bus->dhd, &bus->txq, pkt, prec) == FALSE) {
  980. PKTPULL(osh, pkt, SDPCM_HDRLEN);
  981. #ifndef DHDTHREAD
  982. /* Need to also release txqlock before releasing sdlock.
  983. * This thread still has txqlock and releases sdlock.
  984. * Deadlock happens when dpc() grabs sdlock first then
  985. * attempts to grab txqlock.
  986. */
  987. dhd_os_sdunlock_txq(bus->dhd);
  988. dhd_os_sdunlock(bus->dhd);
  989. #endif
  990. #ifdef PROP_TXSTATUS
  991. if (bus->dhd->wlfc_state)
  992. dhd_wlfc_txcomplete(bus->dhd, pkt, FALSE);
  993. else
  994. #endif
  995. dhd_txcomplete(bus->dhd, pkt, FALSE);
  996. #ifndef DHDTHREAD
  997. dhd_os_sdlock(bus->dhd);
  998. dhd_os_sdlock_txq(bus->dhd);
  999. #endif
  1000. #ifdef PROP_TXSTATUS
  1001. /* let the caller decide whether to free the packet */
  1002. if (!bus->dhd->wlfc_state)
  1003. #endif
  1004. PKTFREE(osh, pkt, TRUE);
  1005. ret = BCME_NORESOURCE;
  1006. }
  1007. else
  1008. ret = BCME_OK;
  1009. dhd_os_sdunlock_txq(bus->dhd);
  1010. if ((pktq_len(&bus->txq) >= FCHI) && dhd_doflow)
  1011. dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON);
  1012. #ifdef DHD_DEBUG
  1013. if (pktq_plen(&bus->txq, prec) > qcount[prec])
  1014. qcount[prec] = pktq_plen(&bus->txq, prec);
  1015. #endif
  1016. /* Schedule DPC if needed to send queued packet(s) */
  1017. if (dhd_deferred_tx && !bus->dpc_sched) {
  1018. bus->dpc_sched = TRUE;
  1019. dhd_sched_dpc(bus->dhd);
  1020. }
  1021. } else {
  1022. #ifdef DHDTHREAD
  1023. /* Lock: we're about to use shared data/code (and SDIO) */
  1024. dhd_os_sdlock(bus->dhd);
  1025. #endif /* DHDTHREAD */
  1026. /* Otherwise, send it now */
  1027. BUS_WAKE(bus);
  1028. /* Make sure back plane ht clk is on, no pending allowed */
  1029. dhdsdio_clkctl(bus, CLK_AVAIL, TRUE);
  1030. #ifndef SDTEST
  1031. ret = dhdsdio_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, TRUE);
  1032. #else
  1033. ret = dhdsdio_txpkt(bus, pkt,
  1034. (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL), TRUE);
  1035. #endif
  1036. if (ret)
  1037. bus->dhd->tx_errors++;
  1038. else
  1039. bus->dhd->dstats.tx_bytes += datalen;
  1040. if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
  1041. bus->activity = FALSE;
  1042. dhdsdio_clkctl(bus, CLK_NONE, TRUE);
  1043. }
  1044. #ifdef DHDTHREAD
  1045. dhd_os_sdunlock(bus->dhd);
  1046. #endif /* DHDTHREAD */
  1047. }
  1048. #ifndef DHDTHREAD
  1049. dhd_os_sdunlock(bus->dhd);
  1050. #endif /* DHDTHREAD */
  1051. return ret;
  1052. }
  1053. static uint
  1054. dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes)
  1055. {
  1056. void *pkt;
  1057. uint32 intstatus = 0;
  1058. uint retries = 0;
  1059. int ret = 0, prec_out;
  1060. uint cnt = 0;
  1061. uint datalen;
  1062. uint8 tx_prec_map;
  1063. dhd_pub_t *dhd = bus->dhd;
  1064. sdpcmd_regs_t *regs = bus->regs;
  1065. DHD_TRACE(("%s: Enter\n", __FUNCTION__));
  1066. tx_prec_map = ~bus->flowcontrol;
  1067. /* Send frames until the limit or some other event */
  1068. for (cnt = 0; (cnt < maxframes) && DATAOK(bus); cnt++) {
  1069. dhd_os_sdlock_txq(bus->dhd);
  1070. if ((pkt = pktq_mdeq(&bus->txq, tx_prec_map, &prec_out)) == NULL) {
  1071. dhd_os_sdunlock_txq(bus->dhd);
  1072. break;
  1073. }
  1074. dhd_os_sdunlock_txq(bus->dhd);
  1075. datalen = PKTLEN(bus->dhd->osh, pkt) - SDPCM_HDRLEN;
  1076. #ifndef SDTEST
  1077. ret = dhdsdio_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, TRUE);
  1078. #else
  1079. ret = dhdsdio_txpkt(bus, pkt,
  1080. (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL), TRUE);
  1081. #endif
  1082. if (ret)
  1083. bus->dhd->tx_errors++;
  1084. else
  1085. bus->dhd->dstats.tx_bytes += datalen;
  1086. /* In poll mode, need to check for other events */
  1087. if (!bus->intr && cnt)
  1088. {
  1089. /* Check device status, signal pending interrupt */
  1090. R_SDREG(intstatus, &regs->intstatus, retries);
  1091. bus->f2txdata++;
  1092. if (bcmsdh_regfail(bus->sdh))
  1093. break;
  1094. if (intstatus & bus->hostintmask)
  1095. bus->ipend = TRUE;
  1096. }
  1097. }
  1098. /* Deflow-control stack if needed */
  1099. if (dhd_doflow && dhd->up && (dhd->busstate == DHD_BUS_DATA) &&
  1100. dhd->txoff && (pktq_len(&bus->txq) < FCLOW))
  1101. dhd_txflowcontrol(dhd, ALL_INTERFACES, OFF);
  1102. return cnt;
  1103. }
  1104. int
  1105. dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen)
  1106. {
  1107. uint8 *frame;
  1108. uint16 len;
  1109. uint32 swheader;
  1110. uint retries = 0;
  1111. bcmsdh_info_t *sdh = bus->sdh;
  1112. uint8 doff = 0;
  1113. int ret = -1;
  1114. int i;
  1115. DHD_TRACE(("%s: Enter\n", __FUNCTION__));
  1116. if (bus->dhd->dongle_reset)
  1117. return -EIO;
  1118. /* Back the pointer to make a room for bus header */
  1119. frame = msg - SDPCM_HDRLEN;
  1120. len = (msglen += SDPCM_HDRLEN);
  1121. /* Add alignment padding (optional for ctl frames) */
  1122. if (dhd_alignctl) {
  1123. if ((doff = ((uintptr)frame % DHD_SDALIGN))) {
  1124. frame -= doff;
  1125. len += doff;
  1126. msglen += doff;
  1127. bzero(frame, doff + SDPCM_HDRLEN);
  1128. }
  1129. ASSERT(doff < DHD_SDALIGN);
  1130. }
  1131. doff += SDPCM_HDRLEN;
  1132. /* Round send length to next SDIO block */
  1133. if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
  1134. uint16 pad = bus->blocksize - (len % bus->blocksize);
  1135. if ((pad <= bus->roundup) && (pad < bus->blocksize))
  1136. len += pad;
  1137. } else if (len % DHD_SDALIGN) {
  1138. len += DHD_SDALIGN - (len % DHD_SDALIGN);
  1139. }
  1140. /* Satisfy length-alignment requirements */
  1141. if (forcealign && (len & (ALIGNMENT - 1)))
  1142. len = ROUNDUP(len, ALIGNMENT);
  1143. ASSERT(ISALIGNED((uintptr)frame, 2));
  1144. /* Need to lock here to protect txseq and SDIO tx calls */
  1145. dhd_os_sdlock(bus->dhd);
  1146. BUS_WAKE(bus);
  1147. /* Make sure backplane clock is on */
  1148. dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
  1149. /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
  1150. *(uint16*)frame = htol16((uint16)msglen);
  1151. *(((uint16*)frame) + 1) = htol16(~msglen);
  1152. /* Software tag: channel, sequence number, data offset */
  1153. swheader = ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK)
  1154. | bus->tx_seq | ((doff << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
  1155. htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN);
  1156. htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
  1157. if (!TXCTLOK(bus)) {
  1158. DHD_INFO(("%s: No bus credit bus->tx_max %d, bus->tx_seq %d\n",
  1159. __FUNCTION__, bus->tx_max, bus->tx_seq));
  1160. bus->ctrl_frame_stat = TRUE;
  1161. /* Send from dpc */
  1162. bus->ctrl_frame_buf = frame;
  1163. bus->ctrl_frame_len = len;
  1164. dhd_wait_for_event(bus->dhd, &bus->ctrl_frame_stat);
  1165. if (bus->ctrl_frame_stat == FALSE) {
  1166. DHD_INFO(("%s: ctrl_frame_stat == FALSE\n", __FUNCTION__));
  1167. ret = 0;
  1168. } else {
  1169. bus->dhd->txcnt_timeout++;
  1170. if (!bus->dhd->hang_was_sent)
  1171. DHD_ERROR(("%s: ctrl_frame_stat == TRUE txcnt_timeout=%d\n",
  1172. __FUNCTION__, bus->dhd->txcnt_timeout));
  1173. ret = -1;
  1174. bus->ctrl_frame_stat = FALSE;
  1175. goto done;
  1176. }
  1177. }
  1178. bus->dhd->txcnt_timeout = 0;
  1179. if (ret == -1) {
  1180. #ifdef DHD_DEBUG
  1181. if (DHD_BYTES_ON() && DHD_CTL_ON()) {
  1182. prhex("Tx Frame", frame, len);
  1183. } else if (DHD_HDRS_ON()) {
  1184. prhex("TxHdr", frame, MIN(len, 16));
  1185. }
  1186. #endif
  1187. do {
  1188. ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
  1189. frame, len, NULL, NULL, NULL);
  1190. ASSERT(ret != BCME_PENDING);
  1191. if (ret < 0) {
  1192. /* On failure, abort the command and terminate the frame */
  1193. DHD_INFO(("%s: sdio error %d, abort command and terminate frame.\n",
  1194. __FUNCTION__, ret));
  1195. bus->tx_sderrs++;
  1196. bcmsdh_abort(sdh, SDIO_FUNC_2);
  1197. bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
  1198. SFC_WF_TERM, NULL);
  1199. bus->f1regdata++;
  1200. for (i = 0; i < 3; i++) {
  1201. uint8 hi, lo;
  1202. hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
  1203. SBSDIO_FUNC1_WFRAMEBCHI, NULL);
  1204. lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
  1205. SBSDIO_FUNC1_WFRAMEBCLO, NULL);
  1206. bus->f1regdata += 2;
  1207. if ((hi == 0) && (lo == 0))
  1208. break;
  1209. }
  1210. }
  1211. if (ret == 0) {
  1212. bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
  1213. }
  1214. } while ((ret < 0) && retries++ < TXRETRIES);
  1215. }
  1216. done:
  1217. if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
  1218. bus->activity = FALSE;
  1219. dhdsdio_clkctl(bus, CLK_NONE, TRUE);
  1220. }
  1221. dhd_os_sdunlock(bus->dhd);
  1222. if (ret)
  1223. bus->dhd->tx_ctlerrs++;
  1224. else
  1225. bus->dhd->tx_ctlpkts++;
  1226. if (bus->dhd->txcnt_timeout >= MAX_CNTL_TIMEOUT)
  1227. return -ETIMEDOUT;
  1228. return ret ? -EIO : 0;
  1229. }
  1230. int
  1231. dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen)
  1232. {
  1233. int timeleft;
  1234. uint rxlen = 0;
  1235. bool pending = FALSE;
  1236. DHD_TRACE(("%s: Enter\n", __FUNCTION__));
  1237. if (bus->dhd->dongle_reset)
  1238. return -EIO;
  1239. /* Wait until control frame is available */
  1240. timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->rxlen, &pending);
  1241. dhd_os_sdlock(bus->dhd);
  1242. rxlen = bus->rxlen;
  1243. bcopy(bus->rxctl, msg, MIN(msglen, rxlen));
  1244. bus->rxlen = 0;
  1245. dhd_os_sdunlock(bus->dhd);
  1246. if (rxlen) {
  1247. DHD_CTL(("%s: resumed on rxctl frame, got %d expected %d\n",
  1248. __FUNCTION__, rxlen, msglen));
  1249. } else if (timeleft == 0) {
  1250. DHD_ERROR(("%s: resumed on timeout\n", __FUNCTION__));
  1251. #ifdef DHD_DEBUG
  1252. dhd_os_sdlock(bus->dhd);
  1253. dhdsdio_checkdied(bus, NULL, 0);
  1254. dhd_os_sdunlock(bus->dhd);
  1255. #endif /* DHD_DEBUG */
  1256. } else if (pending == TRUE) {
  1257. /* signal pending */
  1258. DHD_ERROR(("%s: signal pending\n", __FUNCTION__));
  1259. return -EINTR;
  1260. } else {
  1261. DHD_CTL(("%s: resumed for unknown reason?\n", __FUNCTION__));
  1262. #ifdef DHD_DEBUG
  1263. dhd_os_sdlock(bus->dhd);
  1264. dhdsdio_checkdied(bus, NULL, 0);
  1265. dhd_os_sdunlock(bus->dhd);
  1266. #endif /* DHD_DEBUG */
  1267. }
  1268. if (timeleft == 0) {
  1269. bus->dhd->rxcnt_timeout++;
  1270. DHD_ERROR(("%s: rxcnt_timeout=%d\n", __FUNCTION__, bus->dhd->rxcnt_timeout));
  1271. }
  1272. else
  1273. bus->dhd->rxcnt_timeout = 0;
  1274. if (rxlen)
  1275. bus->dhd->rx_ctlpkts++;
  1276. else
  1277. bus->dhd->rx_ctlerrs++;
  1278. if (bus->dhd->rxcnt_timeout >= MAX_CNTL_TIMEOUT)
  1279. return -ETIMEDOUT;
  1280. return rxlen ? (int)rxlen : -EIO;
  1281. }
  1282. /* IOVar table */
  1283. enum {
  1284. IOV_INTR = 1,
  1285. IOV_POLLRATE,
  1286. IOV_SDREG,
  1287. IOV_SBREG,
  1288. IOV_SDCIS,
  1289. IOV_MEMBYTES,
  1290. IOV_MEMSIZE,
  1291. #ifdef DHD_DEBUG
  1292. IOV_CHECKDIED,
  1293. IOV_SERIALCONS,
  1294. #endif /* DHD_DEBUG */
  1295. IOV_DOWNLOAD,
  1296. IOV_SOCRAM_STATE,
  1297. IOV_FORCEEVEN,
  1298. IOV_SDIOD_DRIVE,
  1299. IOV_READAHEAD,
  1300. IOV_SDRXCHAIN,
  1301. IOV_ALIGNCTL,
  1302. IOV_SDALIGN,
  1303. IOV_DEVRESET,
  1304. IOV_CPU,
  1305. #ifdef SDTEST
  1306. IOV_PKTGEN,
  1307. IOV_EXTLOOP,
  1308. #endif /* SDTEST */
  1309. IOV_SPROM,
  1310. IOV_TXBOUND,
  1311. IOV_RXBOUND,
  1312. IOV_TXMINMAX,
  1313. IOV_IDLETIME,
  1314. IOV_IDLECLOCK,
  1315. IOV_SD1IDLE,
  1316. IOV_SLEEP,
  1317. IOV_DONGLEISOLATION,
  1318. IOV_VARS,
  1319. #ifdef SOFTAP
  1320. IOV_FWPATH
  1321. #endif
  1322. };
  1323. const bcm_iovar_t dhdsdio_iovars[] = {
  1324. {"intr", IOV_INTR, 0, IOVT_BOOL, 0 },
  1325. {"sleep", IOV_SLEEP, 0, IOVT_BOOL, 0 },
  1326. {"pollrate", IOV_POLLRATE, 0, IOVT_UINT32, 0 },
  1327. {"idletime", IOV_IDLETIME, 0, IOVT_INT32, 0 },
  1328. {"idleclock", IOV_IDLECLOCK, 0, IOVT_INT32, 0 },
  1329. {"sd1idle", IOV_SD1IDLE, 0, IOVT_BOOL, 0 },
  1330. {"membytes", IOV_MEMBYTES, 0, IOVT_BUFFER, 2 * sizeof(int) },
  1331. {"memsize", IOV_MEMSIZE, 0, IOVT_UINT32, 0 },
  1332. {"download", IOV_DOWNLOAD, 0, IOVT_BOOL, 0 },
  1333. {"socram_state", IOV_SOCRAM_STATE, 0, IOVT_BOOL, 0 },
  1334. {"vars", IOV_VARS, 0, IOVT_BUFFER, 0 },
  1335. {"sdiod_drive", IOV_SDIOD_DRIVE, 0, IOVT_UINT32, 0 },
  1336. {"readahead", IOV_READAHEAD, 0, IOVT_BOOL, 0 },
  1337. {"sdrxchain", IOV_SDRXCHAIN, 0, IOVT_BOOL, 0 },
  1338. {"alignctl", IOV_ALIGNCTL, 0, IOVT_BOOL, 0 },
  1339. {"sdalign", IOV_SDALIGN, 0, IOVT_BOOL, 0 },
  1340. {"devreset", IOV_DEVRESET, 0, IOVT_BOOL, 0 },
  1341. #ifdef DHD_DEBUG
  1342. {"sdreg", IOV_SDREG, 0, IOVT_BUFFER, sizeof(sdreg_t) },
  1343. {"sbreg", IOV_SBREG, 0, IOVT_BUFFER, sizeof(sdreg_t) },
  1344. {"sd_cis", IOV_SDCIS, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN },
  1345. {"forcealign", IOV_FORCEEVEN, 0, IOVT_BOOL, 0 },
  1346. {"txbound", IOV_TXBOUND, 0, IOVT_UINT32, 0 },
  1347. {"rxbound", IOV_RXBOUND, 0, IOVT_UINT32, 0 },
  1348. {"txminmax", IOV_TXMINMAX, 0, IOVT_UINT32, 0 },
  1349. {"cpu", IOV_CPU, 0, IOVT_BOOL, 0 },
  1350. #ifdef DHD_DEBUG
  1351. {"checkdied", IOV_CHECKDIED, 0, IOVT_BUFFER, 0 },
  1352. {"serial", IOV_SERIALCONS, 0, IOVT_UINT32, 0 },
  1353. #endif /* DHD_DEBUG */
  1354. #endif /* DHD_DEBUG */
  1355. #ifdef SDTEST
  1356. {"extloop", IOV_EXTLOOP, 0, IOVT_BOOL, 0 },
  1357. {"pktgen", IOV_PKTGEN, 0, IOVT_BUFFER, sizeof(dhd_pktgen_t) },
  1358. #endif /* SDTEST */
  1359. {"dngl_isolation", IOV_DONGLEISOLATION, 0, IOVT_UINT32, 0 },
  1360. #ifdef SOFTAP
  1361. {"fwpath", IOV_FWPATH, 0, IOVT_BUFFER, 0 },
  1362. #endif
  1363. {NULL, 0, 0, 0, 0 }
  1364. };
  1365. static void
  1366. dhd_dump_pct(struct bcmstrbuf *strbuf, char *desc, uint num, uint div)
  1367. {
  1368. uint q1, q2;
  1369. if (!div) {
  1370. bcm_bprintf(strbuf, "%s N/A", desc);
  1371. } else {
  1372. q1 = num / div;
  1373. q2 = (100 * (num - (q1 * div))) / div;
  1374. bcm_bprintf(strbuf, "%s %d.%02d", desc, q1, q2);
  1375. }
  1376. }
  1377. void
  1378. dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf)
  1379. {
  1380. dhd_bus_t *bus = dhdp->bus;
  1381. bcm_bprintf(strbuf, "Bus SDIO structure:\n");
  1382. bcm_bprintf(strbuf, "hostintmask 0x%08x intstatus 0x%08x sdpcm_ver %d\n",
  1383. bus->hostintmask, bus->intstatus, bus->sdpcm_ver);
  1384. bcm_bprintf(strbuf, "fcstate %d qlen %d tx_seq %d, max %d, rxskip %d rxlen %d rx_seq %d\n",
  1385. bus->fcstate, pktq_len(&bus->txq), bus->tx_seq, bus->tx_max, bus->rxskip,
  1386. bus->rxlen, bus->rx_seq);
  1387. bcm_bprintf(strbuf, "intr %d intrcount %d lastintrs %d spurious %d\n",
  1388. bus->intr, bus->intrcount, bus->lastintrs, bus->spurious);
  1389. bcm_bprintf(strbuf, "pollrate %d pollcnt %d regfails %d\n",
  1390. bus->pollrate, bus->pollcnt, bus->regfails);
  1391. bcm_bprintf(strbuf, "\nAdditional counters:\n");
  1392. bcm_bprintf(strbuf, "tx_sderrs %d fcqueued %d rxrtx %d rx_toolong %d rxc_errors %d\n",
  1393. bus->tx_sderrs, bus->fcqueued, bus->rxrtx, bus->rx_toolong,
  1394. bus->rxc_errors);
  1395. bcm_bprintf(strbuf, "rx_hdrfail %d badhdr %d badseq %d\n",
  1396. bus->rx_hdrfail, bus->rx_badhdr, bus->rx_badseq);
  1397. bcm_bprintf(strbuf, "fc_rcvd %d, fc_xoff %d, fc_xon %d\n",
  1398. bus->fc_rcvd, bus->fc_xoff, bus->fc_xon);
  1399. bcm_bprintf(strbuf, "rxglomfail %d, rxglomframes %d, rxglompkts %d\n",
  1400. bus->rxglomfail, bus->rxglomframes, bus->rxglompkts);
  1401. bcm_bprintf(strbuf, "f2rx (hdrs/data) %d (%d/%d), f2tx %d f1regs %d\n",
  1402. (bus->f2rxhdrs + bus->f2rxdata), bus->f2rxhdrs, bus->f2rxdata,
  1403. bus->f2txdata, bus->f1regdata);
  1404. {
  1405. dhd_dump_pct(strbuf, "\nRx: pkts/f2rd", bus->dhd->rx_packets,
  1406. (bus->f2rxhdrs + bus->f2rxdata));
  1407. dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->rx_packets, bus->f1regdata);
  1408. dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->rx_packets,
  1409. (bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata));
  1410. dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->rx_packets, bus->intrcount);
  1411. bcm_bprintf(strbuf, "\n");
  1412. dhd_dump_pct(strbuf, "Rx: glom pct", (100