PageRenderTime 96ms CodeModel.GetById 27ms RepoModel.GetById 1ms app.codeStats 0ms

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

https://bitbucket.org/cyanogenmod/android_kernel_asus_tf300t
C | 6359 lines | 4798 code | 999 blank | 562 comment | 1138 complexity | 3c52bd19fa50b30dca420548ef79f3e5 MD5 | raw file
Possible License(s): LGPL-2.0, AGPL-1.0, GPL-2.0
  1. /*
  2. * DHD Bus Module for SDIO
  3. *
  4. * Copyright (C) 1999-2011, Broadcom Corporation
  5. *
  6. * Unless you and Broadcom execute a separate written software license
  7. * agreement governing use of this software, this software is licensed to you
  8. * under the terms of the GNU General Public License version 2 (the "GPL"),
  9. * available at http://www.broadcom.com/licenses/GPLv2.php, with the
  10. * following added to such license:
  11. *
  12. * As a special exception, the copyright holders of this software give you
  13. * permission to link this software with independent modules, and to copy and
  14. * distribute the resulting executable under terms of your choice, provided that
  15. * you also meet, for each linked independent module, the terms and conditions of
  16. * the license of that module. An independent module is a module which is not
  17. * derived from this software. The special exception does not apply to any
  18. * modifications of the software.
  19. *
  20. * Notwithstanding the above, under no circumstances may you combine this
  21. * software in any way with any other Broadcom software provided under a license
  22. * other than the GPL, without Broadcom's express prior written consent.
  23. *
  24. * $Id: dhd_sdio.c 326662 2012-04-10 06:38:08Z $
  25. */
  26. #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 * bus->rxglompkts),
  1413. bus->dhd->rx_packets);
  1414. dhd_dump_pct(strbuf, ", pkts/glom", bus->rxglompkts, bus->rxglomframes);
  1415. bcm_bprintf(strbuf, "\n");
  1416. dhd_dump_pct(strbuf, "Tx: pkts/f2wr", bus->dhd->tx_packets, bus->f2txdata);
  1417. dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->tx_packets, bus->f1regdata);
  1418. dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->tx_packets,
  1419. (bus->f2txdata + bus->f1regdata));
  1420. dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->tx_packets, bus->intrcount);
  1421. bcm_bprintf(strbuf, "\n");
  1422. dhd_dump_pct(strbuf, "Total: pkts/f2rw",
  1423. (bus->dhd->tx_packets + bus->dhd->rx_packets),
  1424. (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata));
  1425. dhd_dump_pct(strbuf, ", pkts/f1sd",
  1426. (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->f1regdata);
  1427. dhd_dump_pct(strbuf, ", pkts/sd",
  1428. (bus->dhd->tx_packets + bus->dhd->rx_packets),
  1429. (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata));
  1430. dhd_dump_pct(strbuf, ", pkts/int",
  1431. (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->intrcount);
  1432. bcm_bprintf(strbuf, "\n\n");
  1433. }
  1434. #ifdef SDTEST
  1435. if (bus->pktgen_count) {
  1436. bcm_bprintf(strbuf, "pktgen config and count:\n");
  1437. bcm_bprintf(strbuf, "freq %d count %d print %d total %d min %d len %d\n",
  1438. bus->pktgen_freq, bus->pktgen_count, bus->pktgen_print,
  1439. bus->pktgen_total, bus->pktgen_minlen, bus->pktgen_maxlen);
  1440. bcm_bprintf(strbuf, "send attempts %d rcvd %d fail %d\n",
  1441. bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail);
  1442. }
  1443. #endif /* SDTEST */
  1444. #ifdef DHD_DEBUG
  1445. bcm_bprintf(strbuf, "dpc_sched %d host interrupt%spending\n",
  1446. bus->dpc_sched, (bcmsdh_intr_pending(bus->sdh) ? " " : " not "));
  1447. bcm_bprintf(strbuf, "blocksize %d roundup %d\n", bus->blocksize, bus->roundup);
  1448. #endif /* DHD_DEBUG */
  1449. bcm_bprintf(strbuf, "clkstate %d activity %d idletime %d idlecount %d sleeping %d\n",
  1450. bus->clkstate, bus->activity, bus->idletime, bus->idlecount, bus->sleeping);
  1451. }
  1452. void
  1453. dhd_bus_clearcounts(dhd_pub_t *dhdp)
  1454. {
  1455. dhd_bus_t *bus = (dhd_bus_t *)dhdp->bus;
  1456. bus->intrcount = bus->lastintrs = bus->spurious = bus->regfails = 0;
  1457. bus->rxrtx = bus->rx_toolong = bus->rxc_errors = 0;
  1458. bus->rx_hdrfail = bus->rx_badhdr = bus->rx_badseq = 0;
  1459. bus->tx_sderrs = bus->fc_rcvd = bus->fc_xoff = bus->fc_xon = 0;
  1460. bus->rxglomfail = bus->rxglomframes = bus->rxglompkts = 0;
  1461. bus->f2rxhdrs = bus->f2rxdata = bus->f2txdata = bus->f1regdata = 0;
  1462. }
  1463. #ifdef SDTEST
  1464. static int
  1465. dhdsdio_pktgen_get(dhd_bus_t *bus, uint8 *arg)
  1466. {
  1467. dhd_pktgen_t pktgen;
  1468. pktgen.version = DHD_PKTGEN_VERSION;
  1469. pktgen.freq = bus->pktgen_freq;
  1470. pktgen.count = bus->pktgen_count;
  1471. pktgen.print = bus->pktgen_print;
  1472. pktgen.total = bus->pktgen_total;
  1473. pktgen.minlen = bus->pktgen_minlen;
  1474. pktgen.maxlen = bus->pktgen_maxlen;
  1475. pktgen.numsent = bus->pktgen_sent;
  1476. pktgen.numrcvd = bus->pktgen_rcvd;
  1477. pktgen.numfail = bus->pktgen_fail;
  1478. pktgen.mode = bus->pktgen_mode;
  1479. pktgen.stop = bus->pktgen_stop;
  1480. bcopy(&pktgen, arg, sizeof(pktgen));
  1481. return 0;
  1482. }
  1483. static int
  1484. dhdsdio_pktgen_set(dhd_bus_t *bus, uint8 *arg)
  1485. {
  1486. dhd_pktgen_t pktgen;
  1487. uint oldcnt, oldmode;
  1488. bcopy(arg, &pktgen, sizeof(pktgen));
  1489. if (pktgen.version != DHD_PKTGEN_VERSION)
  1490. return BCME_BADARG;
  1491. oldcnt = bus->pktgen_count;
  1492. oldmode = bus->pktgen_mode;
  1493. bus->pktgen_freq = pktgen.freq;
  1494. bus->pktgen_count = pktgen.count;
  1495. bus->pktgen_print = pktgen.print;
  1496. bus->pktgen_total = pktgen.total;
  1497. bus->pktgen_minlen = pktgen.minlen;
  1498. bus->pktgen_maxlen = pktgen.maxlen;
  1499. bus->pktgen_mode = pktgen.mode;
  1500. bus->pktgen_stop = pktgen.stop;
  1501. bus->pktgen_tick = bus->pktgen_ptick = 0;
  1502. bus->pktgen_len = MAX(bus->pktgen_len, bus->pktgen_minlen);
  1503. bus->pktgen_len = MIN(bus->pktgen_len, bus->pktgen_maxlen);
  1504. /* Clear counts for a new pktgen (mode change, or was stopped) */
  1505. if (bus->pktgen_count && (!oldcnt || oldmode != bus->pktgen_mode))
  1506. bus->pktgen_sent = bus->pktgen_rcvd = bus->pktgen_fail = 0;
  1507. return 0;
  1508. }
  1509. #endif /* SDTEST */
  1510. static int
  1511. dhdsdio_membytes(dhd_bus_t *bus, bool write, uint32 address, uint8 *data, uint size)
  1512. {
  1513. int bcmerror = 0;
  1514. uint32 sdaddr;
  1515. uint dsize;
  1516. /* Determine initial transfer parameters */
  1517. sdaddr = address & SBSDIO_SB_OFT_ADDR_MASK;
  1518. if ((sdaddr + size) & SBSDIO_SBWINDOW_MASK)
  1519. dsize = (SBSDIO_SB_OFT_ADDR_LIMIT - sdaddr);
  1520. else
  1521. dsize = size;
  1522. /* Set the backplane window to include the start address */
  1523. if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) {
  1524. DHD_ERROR(("%s: window change failed\n", __FUNCTION__));
  1525. goto xfer_done;
  1526. }
  1527. /* Do the transfer(s) */
  1528. while (size) {
  1529. DHD_INFO(("%s: %s %d bytes at offset 0x%08x in window 0x%08x\n",
  1530. __FUNCTION__, (write ? "write" : "read"), dsize, sdaddr,
  1531. (address & SBSDIO_SBWINDOW_MASK)));
  1532. if ((bcmerror = bcmsdh_rwdata(bus->sdh, write, sdaddr, data, dsize))) {
  1533. DHD_ERROR(("%s: membytes transfer failed\n", __FUNCTION__));
  1534. break;
  1535. }
  1536. /* Adjust for next transfer (if any) */
  1537. if ((size -= dsize)) {
  1538. data += dsize;
  1539. address += dsize;
  1540. if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) {
  1541. DHD_ERROR(("%s: window change failed\n", __FUNCTION__));
  1542. break;
  1543. }
  1544. sdaddr = 0;
  1545. dsize = MIN(SBSDIO_SB_OFT_ADDR_LIMIT, size);
  1546. }
  1547. }
  1548. xfer_done:
  1549. /* Return the window to backplane enumeration space for core access */
  1550. if (dhdsdio_set_siaddr_window(bus, bcmsdh_cur_sbwad(bus->sdh))) {
  1551. DHD_ERROR(("%s: FAILED to set window back to 0x%x\n", __FUNCTION__,
  1552. bcmsdh_cur_sbwad(bus->sdh)));
  1553. }
  1554. return bcmerror;
  1555. }
  1556. #ifdef DHD_DEBUG
  1557. static int
  1558. dhdsdio_readshared(dhd_bus_t *bus, sdpcm_shared_t *sh)
  1559. {
  1560. uint32 addr;
  1561. int rv;
  1562. /* Read last word in memory to determine address of sdpcm_shared structure */
  1563. if ((rv = dhdsdio_membytes(bus, FALSE, bus->ramsize - 4, (uint8 *)&addr, 4)) < 0)
  1564. return rv;
  1565. addr = ltoh32(addr);
  1566. DHD_INFO(("sdpcm_shared address 0x%08X\n", addr));
  1567. /*
  1568. * Check if addr is valid.
  1569. * NVRAM length at the end of memory should have been overwritten.
  1570. */
  1571. if (addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff)) {
  1572. DHD_ERROR(("%s: address (0x%08x) of sdpcm_shared invalid\n", __FUNCTION__, addr));
  1573. return BCME_ERROR;
  1574. }
  1575. /* Read hndrte_shared structure */
  1576. if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)sh, sizeof(sdpcm_shared_t))) < 0)
  1577. return rv;
  1578. /* Endianness */
  1579. sh->flags = ltoh32(sh->flags);
  1580. sh->trap_addr = ltoh32(sh->trap_addr);
  1581. sh->assert_exp_addr = ltoh32(sh->assert_exp_addr);
  1582. sh->assert_file_addr = ltoh32(sh->assert_file_addr);
  1583. sh->assert_line = ltoh32(sh->assert_line);
  1584. sh->console_addr = ltoh32(sh->console_addr);
  1585. sh->msgtrace_addr = ltoh32(sh->msgtrace_addr);
  1586. if ((sh->flags & SDPCM_SHARED_VERSION_MASK) == 3 && SDPCM_SHARED_VERSION == 1)
  1587. return BCME_OK;
  1588. if ((sh->flags & SDPCM_SHARED_VERSION_MASK) != SDPCM_SHARED_VERSION) {
  1589. DHD_ERROR(("%s: sdpcm_shared version %d in dhd "
  1590. "is different than sdpcm_shared version %d in dongle\n",
  1591. __FUNCTION__, SDPCM_SHARED_VERSION,
  1592. sh->flags & SDPCM_SHARED_VERSION_MASK));
  1593. return BCME_ERROR;
  1594. }
  1595. return BCME_OK;
  1596. }
  1597. static int
  1598. dhdsdio_readconsole(dhd_bus_t *bus)
  1599. {
  1600. dhd_console_t *c = &bus->console;
  1601. uint8 line[CONSOLE_LINE_MAX], ch;
  1602. uint32 n, idx, addr;
  1603. int rv;
  1604. /* Don't do anything until FWREADY updates console address */
  1605. if (bus->console_addr == 0)
  1606. return 0;
  1607. /* Read console log struct */
  1608. addr = bus->console_addr + OFFSETOF(hndrte_cons_t, log);
  1609. if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)&c->log, sizeof(c->log))) < 0)
  1610. return rv;
  1611. /* Allocate console buffer (one time only) */
  1612. if (c->buf == NULL) {
  1613. c->bufsize = ltoh32(c->log.buf_size);
  1614. if ((c->buf = MALLOC(bus->dhd->osh, c->bufsize)) == NULL)
  1615. return BCME_NOMEM;
  1616. }
  1617. idx = ltoh32(c->log.idx);
  1618. /* Protect against corrupt value */
  1619. if (idx > c->bufsize)
  1620. return BCME_ERROR;
  1621. /* Skip reading the console buffer if the index pointer has not moved */
  1622. if (idx == c->last)
  1623. return BCME_OK;
  1624. /* Read the console buffer */
  1625. addr = ltoh32(c->log.buf);
  1626. if ((rv = dhdsdio_membytes(bus, FALSE, addr, c->buf, c->bufsize)) < 0)
  1627. return rv;
  1628. while (c->last != idx) {
  1629. for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) {
  1630. if (c->last == idx) {
  1631. /* This would output a partial line. Instead, back up
  1632. * the buffer pointer and output this line next time around.
  1633. */
  1634. if (c->last >= n)
  1635. c->last -= n;
  1636. else
  1637. c->last = c->bufsize - n;
  1638. goto break2;
  1639. }
  1640. ch = c->buf[c->last];
  1641. c->last = (c->last + 1) % c->bufsize;
  1642. if (ch == '\n')
  1643. break;
  1644. line[n] = ch;
  1645. }
  1646. if (n > 0) {
  1647. if (line[n - 1] == '\r')
  1648. n--;
  1649. line[n] = 0;
  1650. printf("CONSOLE: %s\n", line);
  1651. }
  1652. }
  1653. break2:
  1654. return BCME_OK;
  1655. }
  1656. static int
  1657. dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size)
  1658. {
  1659. int bcmerror = 0;
  1660. uint msize = 512;
  1661. char *mbuffer = NULL;
  1662. char *console_buffer = NULL;
  1663. uint maxstrlen = 256;
  1664. char *str = NULL;
  1665. trap_t tr;
  1666. sdpcm_shared_t sdpcm_shared;
  1667. struct bcmstrbuf strbuf;
  1668. uint32 console_ptr, console_size, console_index;
  1669. uint8 line[CONSOLE_LINE_MAX], ch;
  1670. uint32 n, i, addr;
  1671. int rv;
  1672. DHD_TRACE(("%s: Enter\n", __FUNCTION__));
  1673. if (data == NULL) {
  1674. /*
  1675. * Called after a rx ctrl timeout. "data" is NULL.
  1676. * allocate memory to trace the trap or assert.
  1677. */
  1678. size = msize;
  1679. mbuffer = data = MALLOC(bus->dhd->osh, msize);
  1680. if (mbuffer == NULL) {
  1681. DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, msize));
  1682. bcmerror = BCME_NOMEM;
  1683. goto done;
  1684. }
  1685. }
  1686. if ((str = MALLOC(bus->dhd->osh, maxstrlen)) == NULL) {
  1687. DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, maxstrlen));
  1688. bcmerror = BCME_NOMEM;
  1689. goto done;
  1690. }
  1691. if ((bcmerror = dhdsdio_readshared(bus, &sdpcm_shared)) < 0)
  1692. goto done;
  1693. bcm_binit(&strbuf, data, size);
  1694. bcm_bprintf(&strbuf, "msgtrace address : 0x%08X\nconsole address : 0x%08X\n",
  1695. sdpcm_shared.msgtrace_addr, sdpcm_shared.console_addr);
  1696. if ((sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT) == 0) {
  1697. /* NOTE: Misspelled assert is intentional - DO NOT FIX.
  1698. * (Avoids conflict with real asserts for programmatic parsing of output.)
  1699. */
  1700. bcm_bprintf(&strbuf, "Assrt not built in dongle\n");
  1701. }
  1702. if ((sdpcm_shared.flags & (SDPCM_SHARED_ASSERT|SDPCM_SHARED_TRAP)) == 0) {
  1703. /* NOTE: Misspelled assert is intentional - DO NOT FIX.
  1704. * (Avoids conflict with real asserts for programmatic parsing of output.)
  1705. */
  1706. bcm_bprintf(&strbuf, "No trap%s in dongle",
  1707. (sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT)
  1708. ?"/assrt" :"");
  1709. } else {
  1710. if (sdpcm_shared.flags & SDPCM_SHARED_ASSERT) {
  1711. /* Download assert */
  1712. bcm_bprintf(&strbuf, "Dongle assert");
  1713. if (sdpcm_shared.assert_exp_addr != 0) {
  1714. str[0] = '\0';
  1715. if ((bcmerror = dhdsdio_membytes(bus, FALSE,
  1716. sdpcm_shared.assert_exp_addr,
  1717. (uint8 *)str, maxstrlen)) < 0)
  1718. goto done;
  1719. str[maxstrlen - 1] = '\0';
  1720. bcm_bprintf(&strbuf, " expr \"%s\"", str);
  1721. }
  1722. if (sdpcm_shared.assert_file_addr != 0) {
  1723. str[0] = '\0';
  1724. if ((bcmerror = dhdsdio_membytes(bus, FALSE,
  1725. sdpcm_shared.assert_file_addr,
  1726. (uint8 *)str, maxstrlen)) < 0)
  1727. goto done;
  1728. str[maxstrlen - 1] = '\0';
  1729. bcm_bprintf(&strbuf, " file \"%s\"", str);
  1730. }
  1731. bcm_bprintf(&strbuf, " line %d ", sdpcm_shared.assert_line);
  1732. }
  1733. if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) {
  1734. if ((bcmerror = dhdsdio_membytes(bus, FALSE,
  1735. sdpcm_shared.trap_addr,
  1736. (uint8*)&tr, sizeof(trap_t))) < 0)
  1737. goto done;
  1738. bcm_bprintf(&strbuf,
  1739. "Dongle trap type 0x%x @ epc 0x%x, cpsr 0x%x, spsr 0x%x, sp 0x%x,"
  1740. "lp 0x%x, rpc 0x%x Trap offset 0x%x, "
  1741. "r0 0x%x, r1 0x%x, r2 0x%x, r3 0x%x, "
  1742. "r4 0x%x, r5 0x%x, r6 0x%x, r7 0x%x\n\n",
  1743. ltoh32(tr.type), ltoh32(tr.epc), ltoh32(tr.cpsr), ltoh32(tr.spsr),
  1744. ltoh32(tr.r13), ltoh32(tr.r14), ltoh32(tr.pc),
  1745. ltoh32(sdpcm_shared.trap_addr),
  1746. ltoh32(tr.r0), ltoh32(tr.r1), ltoh32(tr.r2), ltoh32(tr.r3),
  1747. ltoh32(tr.r4), ltoh32(tr.r5), ltoh32(tr.r6), ltoh32(tr.r7));
  1748. addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log);
  1749. if ((rv = dhdsdio_membytes(bus, FALSE, addr,
  1750. (uint8 *)&console_ptr, sizeof(console_ptr))) < 0)
  1751. goto printbuf;
  1752. addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log.buf_size);
  1753. if ((rv = dhdsdio_membytes(bus, FALSE, addr,
  1754. (uint8 *)&console_size, sizeof(console_size))) < 0)
  1755. goto printbuf;
  1756. addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log.idx);
  1757. if ((rv = dhdsdio_membytes(bus, FALSE, addr,
  1758. (uint8 *)&console_index, sizeof(console_index))) < 0)
  1759. goto printbuf;
  1760. console_ptr = ltoh32(console_ptr);
  1761. console_size = ltoh32(console_size);
  1762. console_index = ltoh32(console_index);
  1763. if (console_size > CONSOLE_BUFFER_MAX ||
  1764. !(console_buffer = MALLOC(bus->dhd->osh, console_size)))
  1765. goto printbuf;
  1766. if ((rv = dhdsdio_membytes(bus, FALSE, console_ptr,
  1767. (uint8 *)console_buffer, console_size)) < 0)
  1768. goto printbuf;
  1769. for (i = 0, n = 0; i < console_size; i += n + 1) {
  1770. for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) {
  1771. ch = console_buffer[(console_index + i + n) % console_size];
  1772. if (ch == '\n')
  1773. break;
  1774. line[n] = ch;
  1775. }
  1776. if (n > 0) {
  1777. if (line[n - 1] == '\r')
  1778. n--;
  1779. line[n] = 0;
  1780. /* Don't use DHD_ERROR macro since we print
  1781. * a lot of information quickly. The macro
  1782. * will truncate a lot of the printfs
  1783. */
  1784. if (dhd_msg_level & DHD_ERROR_VAL) {
  1785. printf("CONSOLE: %s\n", line);
  1786. DHD_BLOG(line, strlen(line) + 1);
  1787. }
  1788. }
  1789. }
  1790. }
  1791. }
  1792. printbuf:
  1793. if (sdpcm_shared.flags & (SDPCM_SHARED_ASSERT | SDPCM_SHARED_TRAP)) {
  1794. DHD_ERROR(("%s: %s\n", __FUNCTION__, strbuf.origbuf));
  1795. }
  1796. done:
  1797. if (mbuffer)
  1798. MFREE(bus->dhd->osh, mbuffer, msize);
  1799. if (str)
  1800. MFREE(bus->dhd->osh, str, maxstrlen);
  1801. if (console_buffer)
  1802. MFREE(bus->dhd->osh, console_buffer, console_size);
  1803. return bcmerror;
  1804. }
  1805. #endif /* #ifdef DHD_DEBUG */
  1806. int
  1807. dhdsdio_downloadvars(dhd_bus_t *bus, void *arg, int len)
  1808. {
  1809. int bcmerror = BCME_OK;
  1810. DHD_TRACE(("%s: Enter\n", __FUNCTION__));
  1811. /* Basic sanity checks */
  1812. if (bus->dhd->up) {
  1813. bcmerror = BCME_NOTDOWN;
  1814. goto err;
  1815. }
  1816. if (!len) {
  1817. bcmerror = BCME_BUFTOOSHORT;
  1818. goto err;
  1819. }
  1820. /* Free the old ones and replace with passed variables */
  1821. if (bus->vars)
  1822. MFREE(bus->dhd->osh, bus->vars, bus->varsz);
  1823. bus->vars = MALLOC(bus->dhd->osh, len);
  1824. bus->varsz = bus->vars ? len : 0;
  1825. if (bus->vars == NULL) {
  1826. bcmerror = BCME_NOMEM;
  1827. goto err;
  1828. }
  1829. /* Copy the passed variables, which should include the terminating double-null */
  1830. bcopy(arg, bus->vars, bus->varsz);
  1831. err:
  1832. return bcmerror;
  1833. }
  1834. #ifdef DHD_DEBUG
  1835. #define CC_PLL_CHIPCTRL_SERIAL_ENAB (1 << 24)
  1836. static int
  1837. dhd_serialconsole(dhd_bus_t *bus, bool set, bool enable, int *bcmerror)
  1838. {
  1839. int int_val;
  1840. uint32 addr, data;
  1841. addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr);
  1842. data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data);
  1843. *bcmerror = 0;
  1844. bcmsdh_reg_write(bus->sdh, addr, 4, 1);
  1845. if (bcmsdh_regfail(bus->sdh)) {
  1846. *bcmerror = BCME_SDIO_ERROR;
  1847. return -1;
  1848. }
  1849. int_val = bcmsdh_reg_read(bus->sdh, data, 4);
  1850. if (bcmsdh_regfail(bus->sdh)) {
  1851. *bcmerror = BCME_SDIO_ERROR;
  1852. return -1;
  1853. }
  1854. if (!set)
  1855. return (int_val & CC_PLL_CHIPCTRL_SERIAL_ENAB);
  1856. if (enable)
  1857. int_val |= CC_PLL_CHIPCTRL_SERIAL_ENAB;
  1858. else
  1859. int_val &= ~CC_PLL_CHIPCTRL_SERIAL_ENAB;
  1860. bcmsdh_reg_write(bus->sdh, data, 4, int_val);
  1861. if (bcmsdh_regfail(bus->sdh)) {
  1862. *bcmerror = BCME_SDIO_ERROR;
  1863. return -1;
  1864. }
  1865. if (bus->sih->chip == BCM4330_CHIP_ID) {
  1866. uint32 chipcontrol;
  1867. addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol);
  1868. chipcontrol = bcmsdh_reg_read(bus->sdh, addr, 4);
  1869. chipcontrol &= ~0x8;
  1870. if (enable) {
  1871. chipcontrol |= 0x8;
  1872. chipcontrol &= ~0x3;
  1873. }
  1874. bcmsdh_reg_write(bus->sdh, addr, 4, chipcontrol);
  1875. }
  1876. return (int_val & CC_PLL_CHIPCTRL_SERIAL_ENAB);
  1877. }
  1878. #endif
  1879. static int
  1880. dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const char *name,
  1881. void *params, int plen, void *arg, int len, int val_size)
  1882. {
  1883. int bcmerror = 0;
  1884. int32 int_val = 0;
  1885. bool bool_val = 0;
  1886. DHD_TRACE(("%s: Enter, action %d name %s params %p plen %d arg %p len %d val_size %d\n",
  1887. __FUNCTION__, actionid, name, params, plen, arg, len, val_size));
  1888. if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0)
  1889. goto exit;
  1890. if (plen >= (int)sizeof(int_val))
  1891. bcopy(params, &int_val, sizeof(int_val));
  1892. bool_val = (int_val != 0) ? TRUE : FALSE;
  1893. /* Some ioctls use the bus */
  1894. dhd_os_sdlock(bus->dhd);
  1895. /* Check if dongle is in reset. If so, only allow DEVRESET iovars */
  1896. if (bus->dhd->dongle_reset && !(actionid == IOV_SVAL(IOV_DEVRESET) ||
  1897. actionid == IOV_GVAL(IOV_DEVRESET))) {
  1898. bcmerror = BCME_NOTREADY;
  1899. goto exit;
  1900. }
  1901. /* Handle sleep stuff before any clock mucking */
  1902. if (vi->varid == IOV_SLEEP) {
  1903. if (IOV_ISSET(actionid)) {
  1904. bcmerror = dhdsdio_bussleep(bus, bool_val);
  1905. } else {
  1906. int_val = (int32)bus->sleeping;
  1907. bcopy(&int_val, arg, val_size);
  1908. }
  1909. goto exit;
  1910. }
  1911. /* Request clock to allow SDIO accesses */
  1912. if (!bus->dhd->dongle_reset) {
  1913. BUS_WAKE(bus);
  1914. dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
  1915. }
  1916. switch (actionid) {
  1917. case IOV_GVAL(IOV_INTR):
  1918. int_val = (int32)bus->intr;
  1919. bcopy(&int_val, arg, val_size);
  1920. break;
  1921. case IOV_SVAL(IOV_INTR):
  1922. bus->intr = bool_val;
  1923. bus->intdis = FALSE;
  1924. if (bus->dhd->up) {
  1925. if (bus->intr) {
  1926. DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__));
  1927. bcmsdh_intr_enable(bus->sdh);
  1928. } else {
  1929. DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
  1930. bcmsdh_intr_disable(bus->sdh);
  1931. }
  1932. }
  1933. break;
  1934. case IOV_GVAL(IOV_POLLRATE):
  1935. int_val = (int32)bus->pollrate;
  1936. bcopy(&int_val, arg, val_size);
  1937. break;
  1938. case IOV_SVAL(IOV_POLLRATE):
  1939. bus->pollrate = (uint)int_val;
  1940. bus->poll = (bus->pollrate != 0);
  1941. break;
  1942. case IOV_GVAL(IOV_IDLETIME):
  1943. int_val = bus->idletime;
  1944. bcopy(&int_val, arg, val_size);
  1945. break;
  1946. case IOV_SVAL(IOV_IDLETIME):
  1947. if ((int_val < 0) && (int_val != DHD_IDLE_IMMEDIATE)) {
  1948. bcmerror = BCME_BADARG;
  1949. } else {
  1950. bus->idletime = int_val;
  1951. }
  1952. break;
  1953. case IOV_GVAL(IOV_IDLECLOCK):
  1954. int_val = (int32)bus->idleclock;
  1955. bcopy(&int_val, arg, val_size);
  1956. break;
  1957. case IOV_SVAL(IOV_IDLECLOCK):
  1958. bus->idleclock = int_val;
  1959. break;
  1960. case IOV_GVAL(IOV_SD1IDLE):
  1961. int_val = (int32)sd1idle;
  1962. bcopy(&int_val, arg, val_size);
  1963. break;
  1964. case IOV_SVAL(IOV_SD1IDLE):
  1965. sd1idle = bool_val;
  1966. break;
  1967. case IOV_SVAL(IOV_MEMBYTES):
  1968. case IOV_GVAL(IOV_MEMBYTES):
  1969. {
  1970. uint32 address;
  1971. uint size, dsize;
  1972. uint8 *data;
  1973. bool set = (actionid == IOV_SVAL(IOV_MEMBYTES));
  1974. ASSERT(plen >= 2*sizeof(int));
  1975. address = (uint32)int_val;
  1976. bcopy((char *)params + sizeof(int_val), &int_val, sizeof(int_val));
  1977. size = (uint)int_val;
  1978. /* Do some validation */
  1979. dsize = set ? plen - (2 * sizeof(int)) : len;
  1980. if (dsize < size) {
  1981. DHD_ERROR(("%s: error on %s membytes, addr 0x%08x size %d dsize %d\n",
  1982. __FUNCTION__, (set ? "set" : "get"), address, size, dsize));
  1983. bcmerror = BCME_BADARG;
  1984. break;
  1985. }
  1986. DHD_INFO(("%s: Request to %s %d bytes at address 0x%08x\n", __FUNCTION__,
  1987. (set ? "write" : "read"), size, address));
  1988. /* If we know about SOCRAM, check for a fit */
  1989. if ((bus->orig_ramsize) &&
  1990. ((address > bus->orig_ramsize) || (address + size > bus->orig_ramsize)))
  1991. {
  1992. uint8 enable, protect;
  1993. si_socdevram(bus->sih, FALSE, &enable, &protect);
  1994. if (!enable || protect) {
  1995. DHD_ERROR(("%s: ramsize 0x%08x doesn't have %d bytes at 0x%08x\n",
  1996. __FUNCTION__, bus->orig_ramsize, size, address));
  1997. DHD_ERROR(("%s: socram enable %d, protect %d\n",
  1998. __FUNCTION__, enable, protect));
  1999. bcmerror = BCME_BADARG;
  2000. break;
  2001. }
  2002. if (enable && (bus->sih->chip == BCM4330_CHIP_ID)) {
  2003. uint32 devramsize = si_socdevram_size(bus->sih);
  2004. if ((address < SOCDEVRAM_4330_ARM_ADDR) ||
  2005. (address + size > (SOCDEVRAM_4330_ARM_ADDR + devramsize))) {
  2006. DHD_ERROR(("%s: bad address 0x%08x, size 0x%08x\n",
  2007. __FUNCTION__, address, size));
  2008. DHD_ERROR(("%s: socram range 0x%08x,size 0x%08x\n",
  2009. __FUNCTION__, SOCDEVRAM_4330_ARM_ADDR, devramsize));
  2010. bcmerror = BCME_BADARG;
  2011. break;
  2012. }
  2013. /* move it such that address is real now */
  2014. address -= SOCDEVRAM_4330_ARM_ADDR;
  2015. address += SOCDEVRAM_4330_BP_ADDR;
  2016. DHD_INFO(("%s: Request to %s %d bytes @ Mapped address 0x%08x\n",
  2017. __FUNCTION__, (set ? "write" : "read"), size, address));
  2018. }
  2019. }
  2020. /* Generate the actual data pointer */
  2021. data = set ? (uint8*)params + 2 * sizeof(int): (uint8*)arg;
  2022. /* Call to do the transfer */
  2023. bcmerror = dhdsdio_membytes(bus, set, address, data, size);
  2024. break;
  2025. }
  2026. case IOV_GVAL(IOV_MEMSIZE):
  2027. int_val = (int32)bus->ramsize;
  2028. bcopy(&int_val, arg, val_size);
  2029. break;
  2030. case IOV_GVAL(IOV_SDIOD_DRIVE):
  2031. int_val = (int32)dhd_sdiod_drive_strength;
  2032. bcopy(&int_val, arg, val_size);
  2033. break;
  2034. case IOV_SVAL(IOV_SDIOD_DRIVE):
  2035. dhd_sdiod_drive_strength = int_val;
  2036. si_sdiod_drive_strength_init(bus->sih, bus->dhd->osh, dhd_sdiod_drive_strength);
  2037. break;
  2038. case IOV_SVAL(IOV_DOWNLOAD):
  2039. bcmerror = dhdsdio_download_state(bus, bool_val);
  2040. break;
  2041. case IOV_SVAL(IOV_SOCRAM_STATE):
  2042. bcmerror = dhdsdio_download_state(bus, bool_val);
  2043. break;
  2044. case IOV_SVAL(IOV_VARS):
  2045. bcmerror = dhdsdio_downloadvars(bus, arg, len);
  2046. break;
  2047. case IOV_GVAL(IOV_READAHEAD):
  2048. int_val = (int32)dhd_readahead;
  2049. bcopy(&int_val, arg, val_size);
  2050. break;
  2051. case IOV_SVAL(IOV_READAHEAD):
  2052. if (bool_val && !dhd_readahead)
  2053. bus->nextlen = 0;
  2054. dhd_readahead = bool_val;
  2055. break;
  2056. case IOV_GVAL(IOV_SDRXCHAIN):
  2057. int_val = (int32)bus->use_rxchain;
  2058. bcopy(&int_val, arg, val_size);
  2059. break;
  2060. case IOV_SVAL(IOV_SDRXCHAIN):
  2061. if (bool_val && !bus->sd_rxchain)
  2062. bcmerror = BCME_UNSUPPORTED;
  2063. else
  2064. bus->use_rxchain = bool_val;
  2065. break;
  2066. case IOV_GVAL(IOV_ALIGNCTL):
  2067. int_val = (int32)dhd_alignctl;
  2068. bcopy(&int_val, arg, val_size);
  2069. break;
  2070. case IOV_SVAL(IOV_ALIGNCTL):
  2071. dhd_alignctl = bool_val;
  2072. break;
  2073. case IOV_GVAL(IOV_SDALIGN):
  2074. int_val = DHD_SDALIGN;
  2075. bcopy(&int_val, arg, val_size);
  2076. break;
  2077. #ifdef DHD_DEBUG
  2078. case IOV_GVAL(IOV_VARS):
  2079. if (bus->varsz < (uint)len)
  2080. bcopy(bus->vars, arg, bus->varsz);
  2081. else
  2082. bcmerror = BCME_BUFTOOSHORT;
  2083. break;
  2084. #endif /* DHD_DEBUG */
  2085. #ifdef DHD_DEBUG
  2086. case IOV_GVAL(IOV_SDREG):
  2087. {
  2088. sdreg_t *sd_ptr;
  2089. uint32 addr, size;
  2090. sd_ptr = (sdreg_t *)params;
  2091. addr = (uintptr)bus->regs + sd_ptr->offset;
  2092. size = sd_ptr->func;
  2093. int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size);
  2094. if (bcmsdh_regfail(bus->sdh))
  2095. bcmerror = BCME_SDIO_ERROR;
  2096. bcopy(&int_val, arg, sizeof(int32));
  2097. break;
  2098. }
  2099. case IOV_SVAL(IOV_SDREG):
  2100. {
  2101. sdreg_t *sd_ptr;
  2102. uint32 addr, size;
  2103. sd_ptr = (sdreg_t *)params;
  2104. addr = (uintptr)bus->regs + sd_ptr->offset;
  2105. size = sd_ptr->func;
  2106. bcmsdh_reg_write(bus->sdh, addr, size, sd_ptr->value);
  2107. if (bcmsdh_regfail(bus->sdh))
  2108. bcmerror = BCME_SDIO_ERROR;
  2109. break;
  2110. }
  2111. /* Same as above, but offset is not backplane (not SDIO core) */
  2112. case IOV_GVAL(IOV_SBREG):
  2113. {
  2114. sdreg_t sdreg;
  2115. uint32 addr, size;
  2116. bcopy(params, &sdreg, sizeof(sdreg));
  2117. addr = SI_ENUM_BASE + sdreg.offset;
  2118. size = sdreg.func;
  2119. int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size);
  2120. if (bcmsdh_regfail(bus->sdh))
  2121. bcmerror = BCME_SDIO_ERROR;
  2122. bcopy(&int_val, arg, sizeof(int32));
  2123. break;
  2124. }
  2125. case IOV_SVAL(IOV_SBREG):
  2126. {
  2127. sdreg_t sdreg;
  2128. uint32 addr, size;
  2129. bcopy(params, &sdreg, sizeof(sdreg));
  2130. addr = SI_ENUM_BASE + sdreg.offset;
  2131. size = sdreg.func;
  2132. bcmsdh_reg_write(bus->sdh, addr, size, sdreg.value);
  2133. if (bcmsdh_regfail(bus->sdh))
  2134. bcmerror = BCME_SDIO_ERROR;
  2135. break;
  2136. }
  2137. case IOV_GVAL(IOV_SDCIS):
  2138. {
  2139. *(char *)arg = 0;
  2140. bcmstrcat(arg, "\nFunc 0\n");
  2141. bcmsdh_cis_read(bus->sdh, 0x10, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
  2142. bcmstrcat(arg, "\nFunc 1\n");
  2143. bcmsdh_cis_read(bus->sdh, 0x11, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
  2144. bcmstrcat(arg, "\nFunc 2\n");
  2145. bcmsdh_cis_read(bus->sdh, 0x12, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
  2146. break;
  2147. }
  2148. case IOV_GVAL(IOV_FORCEEVEN):
  2149. int_val = (int32)forcealign;
  2150. bcopy(&int_val, arg, val_size);
  2151. break;
  2152. case IOV_SVAL(IOV_FORCEEVEN):
  2153. forcealign = bool_val;
  2154. break;
  2155. case IOV_GVAL(IOV_TXBOUND):
  2156. int_val = (int32)dhd_txbound;
  2157. bcopy(&int_val, arg, val_size);
  2158. break;
  2159. case IOV_SVAL(IOV_TXBOUND):
  2160. dhd_txbound = (uint)int_val;
  2161. break;
  2162. case IOV_GVAL(IOV_RXBOUND):
  2163. int_val = (int32)dhd_rxbound;
  2164. bcopy(&int_val, arg, val_size);
  2165. break;
  2166. case IOV_SVAL(IOV_RXBOUND):
  2167. dhd_rxbound = (uint)int_val;
  2168. break;
  2169. case IOV_GVAL(IOV_TXMINMAX):
  2170. int_val = (int32)dhd_txminmax;
  2171. bcopy(&int_val, arg, val_size);
  2172. break;
  2173. case IOV_SVAL(IOV_TXMINMAX):
  2174. dhd_txminmax = (uint)int_val;
  2175. break;
  2176. case IOV_GVAL(IOV_SERIALCONS):
  2177. int_val = dhd_serialconsole(bus, FALSE, 0, &bcmerror);
  2178. if (bcmerror != 0)
  2179. break;
  2180. bcopy(&int_val, arg, val_size);
  2181. break;
  2182. case IOV_SVAL(IOV_SERIALCONS):
  2183. dhd_serialconsole(bus, TRUE, bool_val, &bcmerror);
  2184. break;
  2185. #endif /* DHD_DEBUG */
  2186. #ifdef SDTEST
  2187. case IOV_GVAL(IOV_EXTLOOP):
  2188. int_val = (int32)bus->ext_loop;
  2189. bcopy(&int_val, arg, val_size);
  2190. break;
  2191. case IOV_SVAL(IOV_EXTLOOP):
  2192. bus->ext_loop = bool_val;
  2193. break;
  2194. case IOV_GVAL(IOV_PKTGEN):
  2195. bcmerror = dhdsdio_pktgen_get(bus, arg);
  2196. break;
  2197. case IOV_SVAL(IOV_PKTGEN):
  2198. bcmerror = dhdsdio_pktgen_set(bus, arg);
  2199. break;
  2200. #endif /* SDTEST */
  2201. case IOV_GVAL(IOV_DONGLEISOLATION):
  2202. int_val = bus->dhd->dongle_isolation;
  2203. bcopy(&int_val, arg, val_size);
  2204. break;
  2205. case IOV_SVAL(IOV_DONGLEISOLATION):
  2206. bus->dhd->dongle_isolation = bool_val;
  2207. break;
  2208. case IOV_SVAL(IOV_DEVRESET):
  2209. DHD_TRACE(("%s: Called set IOV_DEVRESET=%d dongle_reset=%d busstate=%d\n",
  2210. __FUNCTION__, bool_val, bus->dhd->dongle_reset,
  2211. bus->dhd->busstate));
  2212. ASSERT(bus->dhd->osh);
  2213. /* ASSERT(bus->cl_devid); */
  2214. dhd_bus_devreset(bus->dhd, (uint8)bool_val);
  2215. break;
  2216. #ifdef SOFTAP
  2217. case IOV_GVAL(IOV_FWPATH):
  2218. {
  2219. uint32 fw_path_len;
  2220. fw_path_len = strlen(bus->fw_path);
  2221. DHD_INFO(("[softap] get fwpath, l=%d\n", len));
  2222. if (fw_path_len > len-1) {
  2223. bcmerror = BCME_BUFTOOSHORT;
  2224. break;
  2225. }
  2226. if (fw_path_len) {
  2227. bcopy(bus->fw_path, arg, fw_path_len);
  2228. ((uchar*)arg)[fw_path_len] = 0;
  2229. }
  2230. break;
  2231. }
  2232. case IOV_SVAL(IOV_FWPATH):
  2233. DHD_INFO(("[softap] set fwpath, idx=%d\n", int_val));
  2234. switch (int_val) {
  2235. case 1:
  2236. bus->fw_path = fw_path; /* ordinary one */
  2237. break;
  2238. case 2:
  2239. bus->fw_path = fw_path2;
  2240. break;
  2241. default:
  2242. bcmerror = BCME_BADARG;
  2243. break;
  2244. }
  2245. DHD_INFO(("[softap] new fw path: %s\n", (bus->fw_path[0] ? bus->fw_path : "NULL")));
  2246. break;
  2247. #endif /* SOFTAP */
  2248. case IOV_GVAL(IOV_DEVRESET):
  2249. DHD_TRACE(("%s: Called get IOV_DEVRESET\n", __FUNCTION__));
  2250. /* Get its status */
  2251. int_val = (bool) bus->dhd->dongle_reset;
  2252. bcopy(&int_val, arg, val_size);
  2253. break;
  2254. default:
  2255. bcmerror = BCME_UNSUPPORTED;
  2256. break;
  2257. }
  2258. exit:
  2259. if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
  2260. bus->activity = FALSE;
  2261. dhdsdio_clkctl(bus, CLK_NONE, TRUE);
  2262. }
  2263. dhd_os_sdunlock(bus->dhd);
  2264. if (actionid == IOV_SVAL(IOV_DEVRESET) && bool_val == FALSE)
  2265. dhd_preinit_ioctls((dhd_pub_t *) bus->dhd);
  2266. return bcmerror;
  2267. }
  2268. static int
  2269. dhdsdio_write_vars(dhd_bus_t *bus)
  2270. {
  2271. int bcmerror = 0;
  2272. uint32 varsize;
  2273. uint32 varaddr;
  2274. uint8 *vbuffer;
  2275. uint32 varsizew;
  2276. #ifdef DHD_DEBUG
  2277. uint8 *nvram_ularray;
  2278. #endif /* DHD_DEBUG */
  2279. /* Even if there are no vars are to be written, we still need to set the ramsize. */
  2280. varsize = bus->varsz ? ROUNDUP(bus->varsz, 4) : 0;
  2281. varaddr = (bus->ramsize - 4) - varsize;
  2282. if (bus->vars) {
  2283. if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 7)) {
  2284. if (((varaddr & 0x3C) == 0x3C) && (varsize > 4)) {
  2285. DHD_ERROR(("PR85623WAR in place\n"));
  2286. varsize += 4;
  2287. varaddr -= 4;
  2288. }
  2289. }
  2290. vbuffer = (uint8 *)MALLOC(bus->dhd->osh, varsize);
  2291. if (!vbuffer)
  2292. return BCME_NOMEM;
  2293. bzero(vbuffer, varsize);
  2294. bcopy(bus->vars, vbuffer, bus->varsz);
  2295. /* Write the vars list */
  2296. bcmerror = dhdsdio_membytes(bus, TRUE, varaddr, vbuffer, varsize);
  2297. #ifdef DHD_DEBUG
  2298. /* Verify NVRAM bytes */
  2299. DHD_INFO(("Compare NVRAM dl & ul; varsize=%d\n", varsize));
  2300. nvram_ularray = (uint8*)MALLOC(bus->dhd->osh, varsize);
  2301. if (!nvram_ularray)
  2302. return BCME_NOMEM;
  2303. /* Upload image to verify downloaded contents. */
  2304. memset(nvram_ularray, 0xaa, varsize);
  2305. /* Read the vars list to temp buffer for comparison */
  2306. bcmerror = dhdsdio_membytes(bus, FALSE, varaddr, nvram_ularray, varsize);
  2307. if (bcmerror) {
  2308. DHD_ERROR(("%s: error %d on reading %d nvram bytes at 0x%08x\n",
  2309. __FUNCTION__, bcmerror, varsize, varaddr));
  2310. }
  2311. /* Compare the org NVRAM with the one read from RAM */
  2312. if (memcmp(vbuffer, nvram_ularray, varsize)) {
  2313. DHD_ERROR(("%s: Downloaded NVRAM image is corrupted.\n", __FUNCTION__));
  2314. } else
  2315. DHD_ERROR(("%s: Download, Upload and compare of NVRAM succeeded.\n",
  2316. __FUNCTION__));
  2317. MFREE(bus->dhd->osh, nvram_ularray, varsize);
  2318. #endif /* DHD_DEBUG */
  2319. MFREE(bus->dhd->osh, vbuffer, varsize);
  2320. }
  2321. /* adjust to the user specified RAM */
  2322. DHD_INFO(("Physical memory size: %d, usable memory size: %d\n",
  2323. bus->orig_ramsize, bus->ramsize));
  2324. DHD_INFO(("Vars are at %d, orig varsize is %d\n",
  2325. varaddr, varsize));
  2326. varsize = ((bus->orig_ramsize - 4) - varaddr);
  2327. /*
  2328. * Determine the length token:
  2329. * Varsize, converted to words, in lower 16-bits, checksum in upper 16-bits.
  2330. */
  2331. if (bcmerror) {
  2332. varsizew = 0;
  2333. } else {
  2334. varsizew = varsize / 4;
  2335. varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF);
  2336. varsizew = htol32(varsizew);
  2337. }
  2338. DHD_INFO(("New varsize is %d, length token=0x%08x\n", varsize, varsizew));
  2339. /* Write the length token to the last word */
  2340. bcmerror = dhdsdio_membytes(bus, TRUE, (bus->orig_ramsize - 4),
  2341. (uint8*)&varsizew, 4);
  2342. return bcmerror;
  2343. }
  2344. static int
  2345. dhdsdio_download_state(dhd_bus_t *bus, bool enter)
  2346. {
  2347. uint retries;
  2348. int bcmerror = 0;
  2349. if (!bus->sih)
  2350. return BCME_ERROR;
  2351. /* To enter download state, disable ARM and reset SOCRAM.
  2352. * To exit download state, simply reset ARM (default is RAM boot).
  2353. */
  2354. if (enter) {
  2355. bus->alp_only = TRUE;
  2356. if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) &&
  2357. !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) {
  2358. DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__));
  2359. bcmerror = BCME_ERROR;
  2360. goto fail;
  2361. }
  2362. si_core_disable(bus->sih, 0);
  2363. if (bcmsdh_regfail(bus->sdh)) {
  2364. bcmerror = BCME_SDIO_ERROR;
  2365. goto fail;
  2366. }
  2367. if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) {
  2368. DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__));
  2369. bcmerror = BCME_ERROR;
  2370. goto fail;
  2371. }
  2372. si_core_reset(bus->sih, 0, 0);
  2373. if (bcmsdh_regfail(bus->sdh)) {
  2374. DHD_ERROR(("%s: Failure trying reset SOCRAM core?\n", __FUNCTION__));
  2375. bcmerror = BCME_SDIO_ERROR;
  2376. goto fail;
  2377. }
  2378. /* Clear the top bit of memory */
  2379. if (bus->ramsize) {
  2380. uint32 zeros = 0;
  2381. if (dhdsdio_membytes(bus, TRUE, bus->ramsize - 4, (uint8*)&zeros, 4) < 0) {
  2382. bcmerror = BCME_SDIO_ERROR;
  2383. goto fail;
  2384. }
  2385. }
  2386. } else {
  2387. if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) {
  2388. DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__));
  2389. bcmerror = BCME_ERROR;
  2390. goto fail;
  2391. }
  2392. if (!si_iscoreup(bus->sih)) {
  2393. DHD_ERROR(("%s: SOCRAM core is down after reset?\n", __FUNCTION__));
  2394. bcmerror = BCME_ERROR;
  2395. goto fail;
  2396. }
  2397. if ((bcmerror = dhdsdio_write_vars(bus))) {
  2398. DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__));
  2399. goto fail;
  2400. }
  2401. if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) &&
  2402. !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) {
  2403. DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__));
  2404. bcmerror = BCME_ERROR;
  2405. goto fail;
  2406. }
  2407. W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries);
  2408. if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) &&
  2409. !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) {
  2410. DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__));
  2411. bcmerror = BCME_ERROR;
  2412. goto fail;
  2413. }
  2414. si_core_reset(bus->sih, 0, 0);
  2415. if (bcmsdh_regfail(bus->sdh)) {
  2416. DHD_ERROR(("%s: Failure trying to reset ARM core?\n", __FUNCTION__));
  2417. bcmerror = BCME_SDIO_ERROR;
  2418. goto fail;
  2419. }
  2420. /* Allow HT Clock now that the ARM is running. */
  2421. bus->alp_only = FALSE;
  2422. bus->dhd->busstate = DHD_BUS_LOAD;
  2423. }
  2424. fail:
  2425. /* Always return to SDIOD core */
  2426. if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0))
  2427. si_setcore(bus->sih, SDIOD_CORE_ID, 0);
  2428. return bcmerror;
  2429. }
  2430. int
  2431. dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name,
  2432. void *params, int plen, void *arg, int len, bool set)
  2433. {
  2434. dhd_bus_t *bus = dhdp->bus;
  2435. const bcm_iovar_t *vi = NULL;
  2436. int bcmerror = 0;
  2437. int val_size;
  2438. uint32 actionid;
  2439. DHD_TRACE(("%s: Enter\n", __FUNCTION__));
  2440. ASSERT(name);
  2441. ASSERT(len >= 0);
  2442. /* Get MUST have return space */
  2443. ASSERT(set || (arg && len));
  2444. /* Set does NOT take qualifiers */
  2445. ASSERT(!set || (!params && !plen));
  2446. /* Look up var locally; if not found pass to host driver */
  2447. if ((vi = bcm_iovar_lookup(dhdsdio_iovars, name)) == NULL) {
  2448. dhd_os_sdlock(bus->dhd);
  2449. BUS_WAKE(bus);
  2450. /* Turn on clock in case SD command needs backplane */
  2451. dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
  2452. bcmerror = bcmsdh_iovar_op(bus->sdh, name, params, plen, arg, len, set);
  2453. /* Check for bus configuration changes of interest */
  2454. /* If it was divisor change, read the new one */
  2455. if (set && strcmp(name, "sd_divisor") == 0) {
  2456. if (bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
  2457. &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) {
  2458. bus->sd_divisor = -1;
  2459. DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, name));
  2460. } else {
  2461. DHD_INFO(("%s: noted %s update, value now %d\n",
  2462. __FUNCTION__, name, bus->sd_divisor));
  2463. }
  2464. }
  2465. /* If it was a mode change, read the new one */
  2466. if (set && strcmp(name, "sd_mode") == 0) {
  2467. if (bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
  2468. &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) {
  2469. bus->sd_mode = -1;
  2470. DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, name));
  2471. } else {
  2472. DHD_INFO(("%s: noted %s update, value now %d\n",
  2473. __FUNCTION__, name, bus->sd_mode));
  2474. }
  2475. }
  2476. /* Similar check for blocksize change */
  2477. if (set && strcmp(name, "sd_blocksize") == 0) {
  2478. int32 fnum = 2;
  2479. if (bcmsdh_iovar_op(bus->sdh, "sd_blocksize", &fnum, sizeof(int32),
  2480. &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) {
  2481. bus->blocksize = 0;
  2482. DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize"));
  2483. } else {
  2484. DHD_INFO(("%s: noted %s update, value now %d\n",
  2485. __FUNCTION__, "sd_blocksize", bus->blocksize));
  2486. }
  2487. }
  2488. bus->roundup = MIN(max_roundup, bus->blocksize);
  2489. if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
  2490. bus->activity = FALSE;
  2491. dhdsdio_clkctl(bus, CLK_NONE, TRUE);
  2492. }
  2493. dhd_os_sdunlock(bus->dhd);
  2494. goto exit;
  2495. }
  2496. DHD_CTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__,
  2497. name, (set ? "set" : "get"), len, plen));
  2498. /* set up 'params' pointer in case this is a set command so that
  2499. * the convenience int and bool code can be common to set and get
  2500. */
  2501. if (params == NULL) {
  2502. params = arg;
  2503. plen = len;
  2504. }
  2505. if (vi->type == IOVT_VOID)
  2506. val_size = 0;
  2507. else if (vi->type == IOVT_BUFFER)
  2508. val_size = len;
  2509. else
  2510. /* all other types are integer sized */
  2511. val_size = sizeof(int);
  2512. actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
  2513. bcmerror = dhdsdio_doiovar(bus, vi, actionid, name, params, plen, arg, len, val_size);
  2514. exit:
  2515. return bcmerror;
  2516. }
  2517. void
  2518. dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex)
  2519. {
  2520. osl_t *osh;
  2521. uint32 local_hostintmask;
  2522. uint8 saveclk;
  2523. uint retries;
  2524. int err;
  2525. if (!bus->dhd)
  2526. return;
  2527. osh = bus->dhd->osh;
  2528. DHD_TRACE(("%s: Enter\n", __FUNCTION__));
  2529. bcmsdh_waitlockfree(NULL);
  2530. if (enforce_mutex)
  2531. dhd_os_sdlock(bus->dhd);
  2532. BUS_WAKE(bus);
  2533. /* Change our idea of bus state */
  2534. bus->dhd->busstate = DHD_BUS_DOWN;
  2535. /* Enable clock for device interrupts */
  2536. dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
  2537. /* Disable and clear interrupts at the chip level also */
  2538. W_SDREG(0, &bus->regs->hostintmask, retries);
  2539. local_hostintmask = bus->hostintmask;
  2540. bus->hostintmask = 0;
  2541. /* Force clocks on backplane to be sure F2 interrupt propagates */
  2542. saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
  2543. if (!err) {
  2544. bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
  2545. (saveclk | SBSDIO_FORCE_HT), &err);
  2546. }
  2547. if (err) {
  2548. DHD_ERROR(("%s: Failed to force clock for F2: err %d\n", __FUNCTION__, err));
  2549. }
  2550. /* Turn off the bus (F2), free any pending packets */
  2551. DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
  2552. bcmsdh_intr_disable(bus->sdh);
  2553. bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL);
  2554. /* Clear any pending interrupts now that F2 is disabled */
  2555. W_SDREG(local_hostintmask, &bus->regs->intstatus, retries);
  2556. /* Turn off the backplane clock (only) */
  2557. dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
  2558. /* Clear the data packet queues */
  2559. pktq_flush(osh, &bus->txq, TRUE, NULL, 0);
  2560. /* Clear any held glomming stuff */
  2561. if (bus->glomd)
  2562. PKTFREE(osh, bus->glomd, FALSE);
  2563. if (bus->glom)
  2564. PKTFREE(osh, bus->glom, FALSE);
  2565. bus->glom = bus->glomd = NULL;
  2566. /* Clear rx control and wake any waiters */
  2567. bus->rxlen = 0;
  2568. dhd_os_ioctl_resp_wake(bus->dhd);
  2569. /* Reset some F2 state stuff */
  2570. bus->rxskip = FALSE;
  2571. bus->tx_seq = bus->rx_seq = 0;
  2572. /* Set to a safe default. It gets updated when we
  2573. * receive a packet from the fw but when we reset,
  2574. * we need a safe default to be able to send the
  2575. * initial mac address.
  2576. */
  2577. bus->tx_max = 4;
  2578. if (enforce_mutex)
  2579. dhd_os_sdunlock(bus->dhd);
  2580. }
  2581. int
  2582. dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex)
  2583. {
  2584. dhd_bus_t *bus = dhdp->bus;
  2585. dhd_timeout_t tmo;
  2586. uint retries = 0;
  2587. uint8 ready, enable;
  2588. int err, ret = 0;
  2589. uint8 saveclk;
  2590. DHD_TRACE(("%s: Enter\n", __FUNCTION__));
  2591. ASSERT(bus->dhd);
  2592. if (!bus->dhd)
  2593. return 0;
  2594. if (enforce_mutex)
  2595. dhd_os_sdlock(bus->dhd);
  2596. /* Make sure backplane clock is on, needed to generate F2 interrupt */
  2597. dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
  2598. if (bus->clkstate != CLK_AVAIL) {
  2599. DHD_ERROR(("%s: clock state is wrong. state = %d\n", __FUNCTION__, bus->clkstate));
  2600. goto exit;
  2601. }
  2602. /* Force clocks on backplane to be sure F2 interrupt propagates */
  2603. saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
  2604. if (!err) {
  2605. bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
  2606. (saveclk | SBSDIO_FORCE_HT), &err);
  2607. }
  2608. if (err) {
  2609. DHD_ERROR(("%s: Failed to force clock for F2: err %d\n", __FUNCTION__, err));
  2610. goto exit;
  2611. }
  2612. /* Enable function 2 (frame transfers) */
  2613. W_SDREG((SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT),
  2614. &bus->regs->tosbmailboxdata, retries);
  2615. enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2);
  2616. bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL);
  2617. /* Give the dongle some time to do its thing and set IOR2 */
  2618. dhd_timeout_start(&tmo, DHD_WAIT_F2RDY * 1000);
  2619. ready = 0;
  2620. do {
  2621. ready = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IORDY, NULL);
  2622. } while (ready != enable && !dhd_timeout_expired(&tmo));
  2623. DHD_INFO(("%s: enable 0x%02x, ready 0x%02x (waited %uus)\n",
  2624. __FUNCTION__, enable, ready, tmo.elapsed));
  2625. /* If F2 successfully enabled, set core and enable interrupts */
  2626. if (ready == enable) {
  2627. /* Make sure we're talking to the core. */
  2628. if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0)))
  2629. bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0);
  2630. ASSERT(bus->regs != NULL);
  2631. /* Set up the interrupt mask and enable interrupts */
  2632. bus->hostintmask = HOSTINTMASK;
  2633. /* corerev 4 could use the newer interrupt logic to detect the frames */
  2634. if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 4) &&
  2635. (bus->rxint_mode != SDIO_DEVICE_HMB_RXINT)) {
  2636. bus->hostintmask &= ~I_HMB_FRAME_IND;
  2637. bus->hostintmask |= I_XMTDATA_AVAIL;
  2638. }
  2639. W_SDREG(bus->hostintmask, &bus->regs->hostintmask, retries);
  2640. bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, (uint8)watermark, &err);
  2641. /* Set bus state according to enable result */
  2642. dhdp->busstate = DHD_BUS_DATA;
  2643. /* bcmsdh_intr_unmask(bus->sdh); */
  2644. bus->intdis = FALSE;
  2645. if (bus->intr) {
  2646. DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__));
  2647. bcmsdh_intr_enable(bus->sdh);
  2648. } else {
  2649. DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
  2650. bcmsdh_intr_disable(bus->sdh);
  2651. }
  2652. }
  2653. else {
  2654. /* Disable F2 again */
  2655. enable = SDIO_FUNC_ENABLE_1;
  2656. bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL);
  2657. }
  2658. /* Restore previous clock setting */
  2659. bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err);
  2660. /* If we didn't come up, turn off backplane clock */
  2661. if (dhdp->busstate != DHD_BUS_DATA)
  2662. dhdsdio_clkctl(bus, CLK_NONE, FALSE);
  2663. exit:
  2664. if (enforce_mutex)
  2665. dhd_os_sdunlock(bus->dhd);
  2666. return ret;
  2667. }
  2668. static void
  2669. dhdsdio_rxfail(dhd_bus_t *bus, bool abort, bool rtx)
  2670. {
  2671. bcmsdh_info_t *sdh = bus->sdh;
  2672. sdpcmd_regs_t *regs = bus->regs;
  2673. uint retries = 0;
  2674. uint16 lastrbc;
  2675. uint8 hi, lo;
  2676. int err;
  2677. DHD_ERROR(("%s: %sterminate frame%s\n", __FUNCTION__,
  2678. (abort ? "abort command, " : ""), (rtx ? ", send NAK" : "")));
  2679. if (abort) {
  2680. bcmsdh_abort(sdh, SDIO_FUNC_2);
  2681. }
  2682. bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, SFC_RF_TERM, &err);
  2683. bus->f1regdata++;
  2684. /* Wait until the packet has been flushed (device/FIFO stable) */
  2685. for (lastrbc = retries = 0xffff; retries > 0; retries--) {
  2686. hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCHI, NULL);
  2687. lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCLO, NULL);
  2688. bus->f1regdata += 2;
  2689. if ((hi == 0) && (lo == 0))
  2690. break;
  2691. if ((hi > (lastrbc >> 8)) && (lo > (lastrbc & 0x00ff))) {
  2692. DHD_ERROR(("%s: count growing: last 0x%04x now 0x%04x\n",
  2693. __FUNCTION__, lastrbc, ((hi << 8) + lo)));
  2694. }
  2695. lastrbc = (hi << 8) + lo;
  2696. }
  2697. if (!retries) {
  2698. DHD_ERROR(("%s: count never zeroed: last 0x%04x\n", __FUNCTION__, lastrbc));
  2699. } else {
  2700. DHD_INFO(("%s: flush took %d iterations\n", __FUNCTION__, (0xffff - retries)));
  2701. }
  2702. if (rtx) {
  2703. bus->rxrtx++;
  2704. W_SDREG(SMB_NAK, &regs->tosbmailbox, retries);
  2705. bus->f1regdata++;
  2706. if (retries <= retry_limit) {
  2707. bus->rxskip = TRUE;
  2708. }
  2709. }
  2710. /* Clear partial in any case */
  2711. bus->nextlen = 0;
  2712. /* If we can't reach the device, signal failure */
  2713. if (err || bcmsdh_regfail(sdh))
  2714. bus->dhd->busstate = DHD_BUS_DOWN;
  2715. }
  2716. static void
  2717. dhdsdio_read_control(dhd_bus_t *bus, uint8 *hdr, uint len, uint doff)
  2718. {
  2719. bcmsdh_info_t *sdh = bus->sdh;
  2720. uint rdlen, pad;
  2721. int sdret;
  2722. DHD_TRACE(("%s: Enter\n", __FUNCTION__));
  2723. /* Control data already received in aligned rxctl */
  2724. if ((bus->bus == SPI_BUS) && (!bus->usebufpool))
  2725. goto gotpkt;
  2726. ASSERT(bus->rxbuf);
  2727. /* Set rxctl for frame (w/optional alignment) */
  2728. bus->rxctl = bus->rxbuf;
  2729. if (dhd_alignctl) {
  2730. bus->rxctl += firstread;
  2731. if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN)))
  2732. bus->rxctl += (DHD_SDALIGN - pad);
  2733. bus->rxctl -= firstread;
  2734. }
  2735. ASSERT(bus->rxctl >= bus->rxbuf);
  2736. /* Copy the already-read portion over */
  2737. bcopy(hdr, bus->rxctl, firstread);
  2738. if (len <= firstread)
  2739. goto gotpkt;
  2740. /* Copy the full data pkt in gSPI case and process ioctl. */
  2741. if (bus->bus == SPI_BUS) {
  2742. bcopy(hdr, bus->rxctl, len);
  2743. goto gotpkt;
  2744. }
  2745. /* Raise rdlen to next SDIO block to avoid tail command */
  2746. rdlen = len - firstread;
  2747. if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
  2748. pad = bus->blocksize - (rdlen % bus->blocksize);
  2749. if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
  2750. ((len + pad) < bus->dhd->maxctl))
  2751. rdlen += pad;
  2752. } else if (rdlen % DHD_SDALIGN) {
  2753. rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
  2754. }
  2755. /* Satisfy length-alignment requirements */
  2756. if (forcealign && (rdlen & (ALIGNMENT - 1)))
  2757. rdlen = ROUNDUP(rdlen, ALIGNMENT);
  2758. /* Drop if the read is too big or it exceeds our maximum */
  2759. if ((rdlen + firstread) > bus->dhd->maxctl) {
  2760. DHD_ERROR(("%s: %d-byte control read exceeds %d-byte buffer\n",
  2761. __FUNCTION__, rdlen, bus->dhd->maxctl));
  2762. bus->dhd->rx_errors++;
  2763. dhdsdio_rxfail(bus, FALSE, FALSE);
  2764. goto done;
  2765. }
  2766. if ((len - doff) > bus->dhd->maxctl) {
  2767. DHD_ERROR(("%s: %d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n",
  2768. __FUNCTION__, len, (len - doff), bus->dhd->maxctl));
  2769. bus->dhd->rx_errors++; bus->rx_toolong++;
  2770. dhdsdio_rxfail(bus, FALSE, FALSE);
  2771. goto done;
  2772. }
  2773. /* Read remainder of frame body into the rxctl buffer */
  2774. sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
  2775. (bus->rxctl + firstread), rdlen, NULL, NULL, NULL);
  2776. bus->f2rxdata++;
  2777. ASSERT(sdret != BCME_PENDING);
  2778. /* Control frame failures need retransmission */
  2779. if (sdret < 0) {
  2780. DHD_ERROR(("%s: read %d control bytes failed: %d\n", __FUNCTION__, rdlen, sdret));
  2781. bus->rxc_errors++; /* dhd.rx_ctlerrs is higher level */
  2782. dhdsdio_rxfail(bus, TRUE, TRUE);
  2783. goto done;
  2784. }
  2785. gotpkt:
  2786. #ifdef DHD_DEBUG
  2787. if (DHD_BYTES_ON() && DHD_CTL_ON()) {
  2788. prhex("RxCtrl", bus->rxctl, len);
  2789. }
  2790. #endif
  2791. /* Point to valid data and indicate its length */
  2792. bus->rxctl += doff;
  2793. bus->rxlen = len - doff;
  2794. done:
  2795. /* Awake any waiters */
  2796. dhd_os_ioctl_resp_wake(bus->dhd);
  2797. }
  2798. static uint8
  2799. dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq)
  2800. {
  2801. uint16 dlen, totlen;
  2802. uint8 *dptr, num = 0;
  2803. uint16 sublen, check;
  2804. void *pfirst, *plast, *pnext, *save_pfirst;
  2805. osl_t *osh = bus->dhd->osh;
  2806. int errcode;
  2807. uint8 chan, seq, doff, sfdoff;
  2808. uint8 txmax;
  2809. int ifidx = 0;
  2810. bool usechain = bus->use_rxchain;
  2811. /* If packets, issue read(s) and send up packet chain */
  2812. /* Return sequence numbers consumed? */
  2813. DHD_TRACE(("dhdsdio_rxglom: start: glomd %p glom %p\n", bus->glomd, bus->glom));
  2814. /* If there's a descriptor, generate the packet chain */
  2815. if (bus->glomd) {
  2816. dhd_os_sdlock_rxq(bus->dhd);
  2817. pfirst = plast = pnext = NULL;
  2818. dlen = (uint16)PKTLEN(osh, bus->glomd);
  2819. dptr = PKTDATA(osh, bus->glomd);
  2820. if (!dlen || (dlen & 1)) {
  2821. DHD_ERROR(("%s: bad glomd len (%d), ignore descriptor\n",
  2822. __FUNCTION__, dlen));
  2823. dlen = 0;
  2824. }
  2825. for (totlen = num = 0; dlen; num++) {
  2826. /* Get (and move past) next length */
  2827. sublen = ltoh16_ua(dptr);
  2828. dlen -= sizeof(uint16);
  2829. dptr += sizeof(uint16);
  2830. if ((sublen < SDPCM_HDRLEN) ||
  2831. ((num == 0) && (sublen < (2 * SDPCM_HDRLEN)))) {
  2832. DHD_ERROR(("%s: descriptor len %d bad: %d\n",
  2833. __FUNCTION__, num, sublen));
  2834. pnext = NULL;
  2835. break;
  2836. }
  2837. if (sublen % DHD_SDALIGN) {
  2838. DHD_ERROR(("%s: sublen %d not a multiple of %d\n",
  2839. __FUNCTION__, sublen, DHD_SDALIGN));
  2840. usechain = FALSE;
  2841. }
  2842. totlen += sublen;
  2843. /* For last frame, adjust read len so total is a block multiple */
  2844. if (!dlen) {
  2845. sublen += (ROUNDUP(totlen, bus->blocksize) - totlen);
  2846. totlen = ROUNDUP(totlen, bus->blocksize);
  2847. }
  2848. /* Allocate/chain packet for next subframe */
  2849. if ((pnext = PKTGET(osh, sublen + DHD_SDALIGN, FALSE)) == NULL) {
  2850. DHD_ERROR(("%s: PKTGET failed, num %d len %d\n",
  2851. __FUNCTION__, num, sublen));
  2852. break;
  2853. }
  2854. ASSERT(!PKTLINK(pnext));
  2855. if (!pfirst) {
  2856. ASSERT(!plast);
  2857. pfirst = plast = pnext;
  2858. } else {
  2859. ASSERT(plast);
  2860. PKTSETNEXT(osh, plast, pnext);
  2861. plast = pnext;
  2862. }
  2863. /* Adhere to start alignment requirements */
  2864. PKTALIGN(osh, pnext, sublen, DHD_SDALIGN);
  2865. }
  2866. /* If all allocations succeeded, save packet chain in bus structure */
  2867. if (pnext) {
  2868. DHD_GLOM(("%s: allocated %d-byte packet chain for %d subframes\n",
  2869. __FUNCTION__, totlen, num));
  2870. if (DHD_GLOM_ON() && bus->nextlen) {
  2871. if (totlen != bus->nextlen) {
  2872. DHD_GLOM(("%s: glomdesc mismatch: nextlen %d glomdesc %d "
  2873. "rxseq %d\n", __FUNCTION__, bus->nextlen,
  2874. totlen, rxseq));
  2875. }
  2876. }
  2877. bus->glom = pfirst;
  2878. pfirst = pnext = NULL;
  2879. } else {
  2880. if (pfirst)
  2881. PKTFREE(osh, pfirst, FALSE);
  2882. bus->glom = NULL;
  2883. num = 0;
  2884. }
  2885. /* Done with descriptor packet */
  2886. PKTFREE(osh, bus->glomd, FALSE);
  2887. bus->glomd = NULL;
  2888. bus->nextlen = 0;
  2889. dhd_os_sdunlock_rxq(bus->dhd);
  2890. }
  2891. /* Ok -- either we just generated a packet chain, or had one from before */
  2892. if (bus->glom) {
  2893. if (DHD_GLOM_ON()) {
  2894. DHD_GLOM(("%s: attempt superframe read, packet chain:\n", __FUNCTION__));
  2895. for (pnext = bus->glom; pnext; pnext = PKTNEXT(osh, pnext)) {
  2896. DHD_GLOM((" %p: %p len 0x%04x (%d)\n",
  2897. pnext, (uint8*)PKTDATA(osh, pnext),
  2898. PKTLEN(osh, pnext), PKTLEN(osh, pnext)));
  2899. }
  2900. }
  2901. pfirst = bus->glom;
  2902. dlen = (uint16)pkttotlen(osh, pfirst);
  2903. /* Do an SDIO read for the superframe. Configurable iovar to
  2904. * read directly into the chained packet, or allocate a large
  2905. * packet and and copy into the chain.
  2906. */
  2907. if (usechain) {
  2908. errcode = dhd_bcmsdh_recv_buf(bus,
  2909. bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2,
  2910. F2SYNC, (uint8*)PKTDATA(osh, pfirst),
  2911. dlen, pfirst, NULL, NULL);
  2912. } else if (bus->dataptr) {
  2913. errcode = dhd_bcmsdh_recv_buf(bus,
  2914. bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2,
  2915. F2SYNC, bus->dataptr,
  2916. dlen, NULL, NULL, NULL);
  2917. sublen = (uint16)pktfrombuf(osh, pfirst, 0, dlen, bus->dataptr);
  2918. if (sublen != dlen) {
  2919. DHD_ERROR(("%s: FAILED TO COPY, dlen %d sublen %d\n",
  2920. __FUNCTION__, dlen, sublen));
  2921. errcode = -1;
  2922. }
  2923. pnext = NULL;
  2924. } else {
  2925. DHD_ERROR(("COULDN'T ALLOC %d-BYTE GLOM, FORCE FAILURE\n", dlen));
  2926. errcode = -1;
  2927. }
  2928. bus->f2rxdata++;
  2929. ASSERT(errcode != BCME_PENDING);
  2930. /* On failure, kill the superframe, allow a couple retries */
  2931. if (errcode < 0) {
  2932. DHD_ERROR(("%s: glom read of %d bytes failed: %d\n",
  2933. __FUNCTION__, dlen, errcode));
  2934. bus->dhd->rx_errors++;
  2935. if (bus->glomerr++ < 3) {
  2936. dhdsdio_rxfail(bus, TRUE, TRUE);
  2937. } else {
  2938. bus->glomerr = 0;
  2939. dhdsdio_rxfail(bus, TRUE, FALSE);
  2940. dhd_os_sdlock_rxq(bus->dhd);
  2941. PKTFREE(osh, bus->glom, FALSE);
  2942. dhd_os_sdunlock_rxq(bus->dhd);
  2943. bus->rxglomfail++;
  2944. bus->glom = NULL;
  2945. }
  2946. return 0;
  2947. }
  2948. #ifdef DHD_DEBUG
  2949. if (DHD_GLOM_ON()) {
  2950. prhex("SUPERFRAME", PKTDATA(osh, pfirst),
  2951. MIN(PKTLEN(osh, pfirst), 48));
  2952. }
  2953. #endif
  2954. /* Validate the superframe header */
  2955. dptr = (uint8 *)PKTDATA(osh, pfirst);
  2956. sublen = ltoh16_ua(dptr);
  2957. check = ltoh16_ua(dptr + sizeof(uint16));
  2958. chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
  2959. seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
  2960. bus->nextlen = dptr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
  2961. if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
  2962. DHD_INFO(("%s: got frame w/nextlen too large (%d) seq %d\n",
  2963. __FUNCTION__, bus->nextlen, seq));
  2964. bus->nextlen = 0;
  2965. }
  2966. doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
  2967. txmax = SDPCM_WINDOW_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
  2968. errcode = 0;
  2969. if ((uint16)~(sublen^check)) {
  2970. DHD_ERROR(("%s (superframe): HW hdr error: len/check 0x%04x/0x%04x\n",
  2971. __FUNCTION__, sublen, check));
  2972. errcode = -1;
  2973. } else if (ROUNDUP(sublen, bus->blocksize) != dlen) {
  2974. DHD_ERROR(("%s (superframe): len 0x%04x, rounded 0x%04x, expect 0x%04x\n",
  2975. __FUNCTION__, sublen, ROUNDUP(sublen, bus->blocksize), dlen));
  2976. errcode = -1;
  2977. } else if (SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]) != SDPCM_GLOM_CHANNEL) {
  2978. DHD_ERROR(("%s (superframe): bad channel %d\n", __FUNCTION__,
  2979. SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN])));
  2980. errcode = -1;
  2981. } else if (SDPCM_GLOMDESC(&dptr[SDPCM_FRAMETAG_LEN])) {
  2982. DHD_ERROR(("%s (superframe): got second descriptor?\n", __FUNCTION__));
  2983. errcode = -1;
  2984. } else if ((doff < SDPCM_HDRLEN) ||
  2985. (doff > (PKTLEN(osh, pfirst) - SDPCM_HDRLEN))) {
  2986. DHD_ERROR(("%s (superframe): Bad data offset %d: HW %d pkt %d min %d\n",
  2987. __FUNCTION__, doff, sublen, PKTLEN(osh, pfirst), SDPCM_HDRLEN));
  2988. errcode = -1;
  2989. }
  2990. /* Check sequence number of superframe SW header */
  2991. if (rxseq != seq) {
  2992. DHD_INFO(("%s: (superframe) rx_seq %d, expected %d\n",
  2993. __FUNCTION__, seq, rxseq));
  2994. bus->rx_badseq++;
  2995. rxseq = seq;
  2996. }
  2997. /* Check window for sanity */
  2998. if ((uint8)(txmax - bus->tx_seq) > 0x40) {
  2999. DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
  3000. __FUNCTION__, txmax, bus->tx_seq));
  3001. txmax = bus->tx_max;
  3002. }
  3003. bus->tx_max = txmax;
  3004. /* Remove superframe header, remember offset */
  3005. PKTPULL(osh, pfirst, doff);
  3006. sfdoff = doff;
  3007. /* Validate all the subframe headers */
  3008. for (num = 0, pnext = pfirst; pnext && !errcode;
  3009. num++, pnext = PKTNEXT(osh, pnext)) {
  3010. dptr = (uint8 *)PKTDATA(osh, pnext);
  3011. dlen = (uint16)PKTLEN(osh, pnext);
  3012. sublen = ltoh16_ua(dptr);
  3013. check = ltoh16_ua(dptr + sizeof(uint16));
  3014. chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
  3015. doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
  3016. #ifdef DHD_DEBUG
  3017. if (DHD_GLOM_ON()) {
  3018. prhex("subframe", dptr, 32);
  3019. }
  3020. #endif
  3021. if ((uint16)~(sublen^check)) {
  3022. DHD_ERROR(("%s (subframe %d): HW hdr error: "
  3023. "len/check 0x%04x/0x%04x\n",
  3024. __FUNCTION__, num, sublen, check));
  3025. errcode = -1;
  3026. } else if ((sublen > dlen) || (sublen < SDPCM_HDRLEN)) {
  3027. DHD_ERROR(("%s (subframe %d): length mismatch: "
  3028. "len 0x%04x, expect 0x%04x\n",
  3029. __FUNCTION__, num, sublen, dlen));
  3030. errcode = -1;
  3031. } else if ((chan != SDPCM_DATA_CHANNEL) &&
  3032. (chan != SDPCM_EVENT_CHANNEL)) {
  3033. DHD_ERROR(("%s (subframe %d): bad channel %d\n",
  3034. __FUNCTION__, num, chan));
  3035. errcode = -1;
  3036. } else if ((doff < SDPCM_HDRLEN) || (doff > sublen)) {
  3037. DHD_ERROR(("%s (subframe %d): Bad data offset %d: HW %d min %d\n",
  3038. __FUNCTION__, num, doff, sublen, SDPCM_HDRLEN));
  3039. errcode = -1;
  3040. }
  3041. }
  3042. if (errcode) {
  3043. /* Terminate frame on error, request a couple retries */
  3044. if (bus->glomerr++ < 3) {
  3045. /* Restore superframe header space */
  3046. PKTPUSH(osh, pfirst, sfdoff);
  3047. dhdsdio_rxfail(bus, TRUE, TRUE);
  3048. } else {
  3049. bus->glomerr = 0;
  3050. dhdsdio_rxfail(bus, TRUE, FALSE);
  3051. dhd_os_sdlock_rxq(bus->dhd);
  3052. PKTFREE(osh, bus->glom, FALSE);
  3053. dhd_os_sdunlock_rxq(bus->dhd);
  3054. bus->rxglomfail++;
  3055. bus->glom = NULL;
  3056. }
  3057. bus->nextlen = 0;
  3058. return 0;
  3059. }
  3060. /* Basic SD framing looks ok - process each packet (header) */
  3061. save_pfirst = pfirst;
  3062. bus->glom = NULL;
  3063. plast = NULL;
  3064. dhd_os_sdlock_rxq(bus->dhd);
  3065. for (num = 0; pfirst; rxseq++, pfirst = pnext) {
  3066. pnext = PKTNEXT(osh, pfirst);
  3067. PKTSETNEXT(osh, pfirst, NULL);
  3068. dptr = (uint8 *)PKTDATA(osh, pfirst);
  3069. sublen = ltoh16_ua(dptr);
  3070. chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
  3071. seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
  3072. doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
  3073. DHD_GLOM(("%s: Get subframe %d, %p(%p/%d), sublen %d chan %d seq %d\n",
  3074. __FUNCTION__, num, pfirst, PKTDATA(osh, pfirst),
  3075. PKTLEN(osh, pfirst), sublen, chan, seq));
  3076. ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL));
  3077. if (rxseq != seq) {
  3078. DHD_GLOM(("%s: rx_seq %d, expected %d\n",
  3079. __FUNCTION__, seq, rxseq));
  3080. bus->rx_badseq++;
  3081. rxseq = seq;
  3082. }
  3083. #ifdef DHD_DEBUG
  3084. if (DHD_BYTES_ON() && DHD_DATA_ON()) {
  3085. prhex("Rx Subframe Data", dptr, dlen);
  3086. }
  3087. #endif
  3088. PKTSETLEN(osh, pfirst, sublen);
  3089. PKTPULL(osh, pfirst, doff);
  3090. if (PKTLEN(osh, pfirst) == 0) {
  3091. PKTFREE(bus->dhd->osh, pfirst, FALSE);
  3092. if (plast) {
  3093. PKTSETNEXT(osh, plast, pnext);
  3094. } else {
  3095. ASSERT(save_pfirst == pfirst);
  3096. save_pfirst = pnext;
  3097. }
  3098. continue;
  3099. } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pfirst) != 0) {
  3100. DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__));
  3101. bus->dhd->rx_errors++;
  3102. PKTFREE(osh, pfirst, FALSE);
  3103. if (plast) {
  3104. PKTSETNEXT(osh, plast, pnext);
  3105. } else {
  3106. ASSERT(save_pfirst == pfirst);
  3107. save_pfirst = pnext;
  3108. }
  3109. continue;
  3110. }
  3111. /* this packet will go up, link back into chain and count it */
  3112. PKTSETNEXT(osh, pfirst, pnext);
  3113. plast = pfirst;
  3114. num++;
  3115. #ifdef DHD_DEBUG
  3116. if (DHD_GLOM_ON()) {
  3117. DHD_GLOM(("%s subframe %d to stack, %p(%p/%d) nxt/lnk %p/%p\n",
  3118. __FUNCTION__, num, pfirst,
  3119. PKTDATA(osh, pfirst), PKTLEN(osh, pfirst),
  3120. PKTNEXT(osh, pfirst), PKTLINK(pfirst)));
  3121. prhex("", (uint8 *)PKTDATA(osh, pfirst),
  3122. MIN(PKTLEN(osh, pfirst), 32));
  3123. }
  3124. #endif /* DHD_DEBUG */
  3125. }
  3126. dhd_os_sdunlock_rxq(bus->dhd);
  3127. if (num) {
  3128. dhd_os_sdunlock(bus->dhd);
  3129. dhd_rx_frame(bus->dhd, ifidx, save_pfirst, num, 0);
  3130. dhd_os_sdlock(bus->dhd);
  3131. }
  3132. bus->rxglomframes++;
  3133. bus->rxglompkts += num;
  3134. }
  3135. return num;
  3136. }
  3137. /* Return TRUE if there may be more frames to read */
  3138. static uint
  3139. dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished)
  3140. {
  3141. osl_t *osh = bus->dhd->osh;
  3142. bcmsdh_info_t *sdh = bus->sdh;
  3143. uint16 len, check; /* Extracted hardware header fields */
  3144. uint8 chan, seq, doff; /* Extracted software header fields */
  3145. uint8 fcbits; /* Extracted fcbits from software header */
  3146. uint8 delta;
  3147. void *pkt; /* Packet for event or data frames */
  3148. uint16 pad; /* Number of pad bytes to read */
  3149. uint16 rdlen; /* Total number of bytes to read */
  3150. uint8 rxseq; /* Next sequence number to expect */
  3151. uint rxleft = 0; /* Remaining number of frames allowed */
  3152. int sdret; /* Return code from bcmsdh calls */
  3153. uint8 txmax; /* Maximum tx sequence offered */
  3154. bool len_consistent; /* Result of comparing readahead len and len from hw-hdr */
  3155. uint8 *rxbuf;
  3156. int ifidx = 0;
  3157. uint rxcount = 0; /* Total frames read */
  3158. #if defined(DHD_DEBUG) || defined(SDTEST)
  3159. bool sdtest = FALSE; /* To limit message spew from test mode */
  3160. #endif
  3161. DHD_TRACE(("%s: Enter\n", __FUNCTION__));
  3162. ASSERT(maxframes);
  3163. #ifdef SDTEST
  3164. /* Allow pktgen to override maxframes */
  3165. if (bus->pktgen_count && (bus->pktgen_mode == DHD_PKTGEN_RECV)) {
  3166. maxframes = bus->pktgen_count;
  3167. sdtest = TRUE;
  3168. }
  3169. #endif
  3170. /* Not finished unless we encounter no more frames indication */
  3171. *finished = FALSE;
  3172. for (rxseq = bus->rx_seq, rxleft = maxframes;
  3173. !bus->rxskip && rxleft && bus->dhd->busstate != DHD_BUS_DOWN;
  3174. rxseq++, rxleft--) {
  3175. #ifdef DHDTHREAD
  3176. /* tx more to improve rx performance */
  3177. if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate &&
  3178. pktq_mlen(&bus->txq, ~bus->flowcontrol) && DATAOK(bus)) {
  3179. dhdsdio_sendfromq(bus, dhd_txbound);
  3180. }
  3181. #endif /* DHDTHREAD */
  3182. /* Handle glomming separately */
  3183. if (bus->glom || bus->glomd) {
  3184. uint8 cnt;
  3185. DHD_GLOM(("%s: calling rxglom: glomd %p, glom %p\n",
  3186. __FUNCTION__, bus->glomd, bus->glom));
  3187. cnt = dhdsdio_rxglom(bus, rxseq);
  3188. DHD_GLOM(("%s: rxglom returned %d\n", __FUNCTION__, cnt));
  3189. rxseq += cnt - 1;
  3190. rxleft = (rxleft > cnt) ? (rxleft - cnt) : 1;
  3191. continue;
  3192. }
  3193. /* Try doing single read if we can */
  3194. if (dhd_readahead && bus->nextlen) {
  3195. uint16 nextlen = bus->nextlen;
  3196. bus->nextlen = 0;
  3197. if (bus->bus == SPI_BUS) {
  3198. rdlen = len = nextlen;
  3199. }
  3200. else {
  3201. rdlen = len = nextlen << 4;
  3202. /* Pad read to blocksize for efficiency */
  3203. if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
  3204. pad = bus->blocksize - (rdlen % bus->blocksize);
  3205. if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
  3206. ((rdlen + pad + firstread) < MAX_RX_DATASZ))
  3207. rdlen += pad;
  3208. } else if (rdlen % DHD_SDALIGN) {
  3209. rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
  3210. }
  3211. }
  3212. /* We use bus->rxctl buffer in WinXP for initial control pkt receives.
  3213. * Later we use buffer-poll for data as well as control packets.
  3214. * This is required because dhd receives full frame in gSPI unlike SDIO.
  3215. * After the frame is received we have to distinguish whether it is data
  3216. * or non-data frame.
  3217. */
  3218. /* Allocate a packet buffer */
  3219. dhd_os_sdlock_rxq(bus->dhd);
  3220. if (!(pkt = PKTGET(osh, rdlen + DHD_SDALIGN, FALSE))) {
  3221. if (bus->bus == SPI_BUS) {
  3222. bus->usebufpool = FALSE;
  3223. bus->rxctl = bus->rxbuf;
  3224. if (dhd_alignctl) {
  3225. bus->rxctl += firstread;
  3226. if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN)))
  3227. bus->rxctl += (DHD_SDALIGN - pad);
  3228. bus->rxctl -= firstread;
  3229. }
  3230. ASSERT(bus->rxctl >= bus->rxbuf);
  3231. rxbuf = bus->rxctl;
  3232. /* Read the entire frame */
  3233. sdret = dhd_bcmsdh_recv_buf(bus,
  3234. bcmsdh_cur_sbwad(sdh),
  3235. SDIO_FUNC_2,
  3236. F2SYNC, rxbuf, rdlen,
  3237. NULL, NULL, NULL);
  3238. bus->f2rxdata++;
  3239. ASSERT(sdret != BCME_PENDING);
  3240. /* Control frame failures need retransmission */
  3241. if (sdret < 0) {
  3242. DHD_ERROR(("%s: read %d control bytes failed: %d\n",
  3243. __FUNCTION__, rdlen, sdret));
  3244. /* dhd.rx_ctlerrs is higher level */
  3245. bus->rxc_errors++;
  3246. dhd_os_sdunlock_rxq(bus->dhd);
  3247. dhdsdio_rxfail(bus, TRUE,
  3248. (bus->bus == SPI_BUS) ? FALSE : TRUE);
  3249. continue;
  3250. }
  3251. } else {
  3252. /* Give up on data, request rtx of events */
  3253. DHD_ERROR(("%s (nextlen): PKTGET failed: len %d rdlen %d "
  3254. "expected rxseq %d\n",
  3255. __FUNCTION__, len, rdlen, rxseq));
  3256. /* Just go try again w/normal header read */
  3257. dhd_os_sdunlock_rxq(bus->dhd);
  3258. continue;
  3259. }
  3260. } else {
  3261. if (bus->bus == SPI_BUS)
  3262. bus->usebufpool = TRUE;
  3263. ASSERT(!PKTLINK(pkt));
  3264. PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN);
  3265. rxbuf = (uint8 *)PKTDATA(osh, pkt);
  3266. /* Read the entire frame */
  3267. sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh),
  3268. SDIO_FUNC_2,
  3269. F2SYNC, rxbuf, rdlen,
  3270. pkt, NULL, NULL);
  3271. bus->f2rxdata++;
  3272. ASSERT(sdret != BCME_PENDING);
  3273. if (sdret < 0) {
  3274. DHD_ERROR(("%s (nextlen): read %d bytes failed: %d\n",
  3275. __FUNCTION__, rdlen, sdret));
  3276. PKTFREE(bus->dhd->osh, pkt, FALSE);
  3277. bus->dhd->rx_errors++;
  3278. dhd_os_sdunlock_rxq(bus->dhd);
  3279. /* Force retry w/normal header read. Don't attempt NAK for
  3280. * gSPI
  3281. */
  3282. dhdsdio_rxfail(bus, TRUE,
  3283. (bus->bus == SPI_BUS) ? FALSE : TRUE);
  3284. continue;
  3285. }
  3286. }
  3287. dhd_os_sdunlock_rxq(bus->dhd);
  3288. /* Now check the header */
  3289. bcopy(rxbuf, bus->rxhdr, SDPCM_HDRLEN);
  3290. /* Extract hardware header fields */
  3291. len = ltoh16_ua(bus->rxhdr);
  3292. check = ltoh16_ua(bus->rxhdr + sizeof(uint16));
  3293. /* All zeros means readahead info was bad */
  3294. if (!(len|check)) {
  3295. DHD_INFO(("%s (nextlen): read zeros in HW header???\n",
  3296. __FUNCTION__));
  3297. dhd_os_sdlock_rxq(bus->dhd);
  3298. PKTFREE2();
  3299. dhd_os_sdunlock_rxq(bus->dhd);
  3300. GSPI_PR55150_BAILOUT;
  3301. continue;
  3302. }
  3303. /* Validate check bytes */
  3304. if ((uint16)~(len^check)) {
  3305. DHD_ERROR(("%s (nextlen): HW hdr error: nextlen/len/check"
  3306. " 0x%04x/0x%04x/0x%04x\n", __FUNCTION__, nextlen,
  3307. len, check));
  3308. dhd_os_sdlock_rxq(bus->dhd);
  3309. PKTFREE2();
  3310. dhd_os_sdunlock_rxq(bus->dhd);
  3311. bus->rx_badhdr++;
  3312. dhdsdio_rxfail(bus, FALSE, FALSE);
  3313. GSPI_PR55150_BAILOUT;
  3314. continue;
  3315. }
  3316. /* Validate frame length */
  3317. if (len < SDPCM_HDRLEN) {
  3318. DHD_ERROR(("%s (nextlen): HW hdr length invalid: %d\n",
  3319. __FUNCTION__, len));
  3320. dhd_os_sdlock_rxq(bus->dhd);
  3321. PKTFREE2();
  3322. dhd_os_sdunlock_rxq(bus->dhd);
  3323. GSPI_PR55150_BAILOUT;
  3324. continue;
  3325. }
  3326. /* Check for consistency with readahead info */
  3327. len_consistent = (nextlen != (ROUNDUP(len, 16) >> 4));
  3328. if (len_consistent) {
  3329. /* Mismatch, force retry w/normal header (may be >4K) */
  3330. DHD_ERROR(("%s (nextlen): mismatch, nextlen %d len %d rnd %d; "
  3331. "expected rxseq %d\n",
  3332. __FUNCTION__, nextlen, len, ROUNDUP(len, 16), rxseq));
  3333. dhd_os_sdlock_rxq(bus->dhd);
  3334. PKTFREE2();
  3335. dhd_os_sdunlock_rxq(bus->dhd);
  3336. dhdsdio_rxfail(bus, TRUE, (bus->bus == SPI_BUS) ? FALSE : TRUE);
  3337. GSPI_PR55150_BAILOUT;
  3338. continue;
  3339. }
  3340. /* Extract software header fields */
  3341. chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
  3342. seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
  3343. doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
  3344. txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
  3345. bus->nextlen =
  3346. bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
  3347. if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
  3348. DHD_INFO(("%s (nextlen): got frame w/nextlen too large"
  3349. " (%d), seq %d\n", __FUNCTION__, bus->nextlen,
  3350. seq));
  3351. bus->nextlen = 0;
  3352. }
  3353. bus->dhd->rx_readahead_cnt ++;
  3354. /* Handle Flow Control */
  3355. fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
  3356. delta = 0;
  3357. if (~bus->flowcontrol & fcbits) {
  3358. bus->fc_xoff++;
  3359. delta = 1;
  3360. }
  3361. if (bus->flowcontrol & ~fcbits) {
  3362. bus->fc_xon++;
  3363. delta = 1;
  3364. }
  3365. if (delta) {
  3366. bus->fc_rcvd++;
  3367. bus->flowcontrol = fcbits;
  3368. }
  3369. /* Check and update sequence number */
  3370. if (rxseq != seq) {
  3371. DHD_INFO(("%s (nextlen): rx_seq %d, expected %d\n",
  3372. __FUNCTION__, seq, rxseq));
  3373. bus->rx_badseq++;
  3374. rxseq = seq;
  3375. }
  3376. /* Check window for sanity */
  3377. if ((uint8)(txmax - bus->tx_seq) > 0x40) {
  3378. DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
  3379. __FUNCTION__, txmax, bus->tx_seq));
  3380. txmax = bus->tx_max;
  3381. }
  3382. bus->tx_max = txmax;
  3383. #ifdef DHD_DEBUG
  3384. if (DHD_BYTES_ON() && DHD_DATA_ON()) {
  3385. prhex("Rx Data", rxbuf, len);
  3386. } else if (DHD_HDRS_ON()) {
  3387. prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN);
  3388. }
  3389. #endif
  3390. if (chan == SDPCM_CONTROL_CHANNEL) {
  3391. if (bus->bus == SPI_BUS) {
  3392. dhdsdio_read_control(bus, rxbuf, len, doff);
  3393. if (bus->usebufpool) {
  3394. dhd_os_sdlock_rxq(bus->dhd);
  3395. PKTFREE(bus->dhd->osh, pkt, FALSE);
  3396. dhd_os_sdunlock_rxq(bus->dhd);
  3397. }
  3398. continue;
  3399. } else {
  3400. DHD_ERROR(("%s (nextlen): readahead on control"
  3401. " packet %d?\n", __FUNCTION__, seq));
  3402. /* Force retry w/normal header read */
  3403. bus->nextlen = 0;
  3404. dhdsdio_rxfail(bus, FALSE, TRUE);
  3405. dhd_os_sdlock_rxq(bus->dhd);
  3406. PKTFREE2();
  3407. dhd_os_sdunlock_rxq(bus->dhd);
  3408. continue;
  3409. }
  3410. }
  3411. if ((bus->bus == SPI_BUS) && !bus->usebufpool) {
  3412. DHD_ERROR(("Received %d bytes on %d channel. Running out of "
  3413. "rx pktbuf's or not yet malloced.\n", len, chan));
  3414. continue;
  3415. }
  3416. /* Validate data offset */
  3417. if ((doff < SDPCM_HDRLEN) || (doff > len)) {
  3418. DHD_ERROR(("%s (nextlen): bad data offset %d: HW len %d min %d\n",
  3419. __FUNCTION__, doff, len, SDPCM_HDRLEN));
  3420. dhd_os_sdlock_rxq(bus->dhd);
  3421. PKTFREE2();
  3422. dhd_os_sdunlock_rxq(bus->dhd);
  3423. ASSERT(0);
  3424. dhdsdio_rxfail(bus, FALSE, FALSE);
  3425. continue;
  3426. }
  3427. /* All done with this one -- now deliver the packet */
  3428. goto deliver;
  3429. }
  3430. /* gSPI frames should not be handled in fractions */
  3431. if (bus->bus == SPI_BUS) {
  3432. break;
  3433. }
  3434. /* Read frame header (hardware and software) */
  3435. sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
  3436. bus->rxhdr, firstread, NULL, NULL, NULL);
  3437. bus->f2rxhdrs++;
  3438. ASSERT(sdret != BCME_PENDING);
  3439. if (sdret < 0) {
  3440. DHD_ERROR(("%s: RXHEADER FAILED: %d\n", __FUNCTION__, sdret));
  3441. bus->rx_hdrfail++;
  3442. dhdsdio_rxfail(bus, TRUE, TRUE);
  3443. continue;
  3444. }
  3445. #ifdef DHD_DEBUG
  3446. if (DHD_BYTES_ON() || DHD_HDRS_ON()) {
  3447. prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN);
  3448. }
  3449. #endif
  3450. /* Extract hardware header fields */
  3451. len = ltoh16_ua(bus->rxhdr);
  3452. check = ltoh16_ua(bus->rxhdr + sizeof(uint16));
  3453. /* All zeros means no more frames */
  3454. if (!(len|check)) {
  3455. *finished = TRUE;
  3456. break;
  3457. }
  3458. /* Validate check bytes */
  3459. if ((uint16)~(len^check)) {
  3460. DHD_ERROR(("%s: HW hdr error: len/check 0x%04x/0x%04x\n",
  3461. __FUNCTION__, len, check));
  3462. bus->rx_badhdr++;
  3463. dhdsdio_rxfail(bus, FALSE, FALSE);
  3464. continue;
  3465. }
  3466. /* Validate frame length */
  3467. if (len < SDPCM_HDRLEN) {
  3468. DHD_ERROR(("%s: HW hdr length invalid: %d\n", __FUNCTION__, len));
  3469. continue;
  3470. }
  3471. /* Extract software header fields */
  3472. chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
  3473. seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
  3474. doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
  3475. txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
  3476. /* Validate data offset */
  3477. if ((doff < SDPCM_HDRLEN) || (doff > len)) {
  3478. DHD_ERROR(("%s: Bad data offset %d: HW len %d, min %d seq %d\n",
  3479. __FUNCTION__, doff, len, SDPCM_HDRLEN, seq));
  3480. bus->rx_badhdr++;
  3481. ASSERT(0);
  3482. dhdsdio_rxfail(bus, FALSE, FALSE);
  3483. continue;
  3484. }
  3485. /* Save the readahead length if there is one */
  3486. bus->nextlen = bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
  3487. if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
  3488. DHD_INFO(("%s (nextlen): got frame w/nextlen too large (%d), seq %d\n",
  3489. __FUNCTION__, bus->nextlen, seq));
  3490. bus->nextlen = 0;
  3491. }
  3492. /* Handle Flow Control */
  3493. fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
  3494. delta = 0;
  3495. if (~bus->flowcontrol & fcbits) {
  3496. bus->fc_xoff++;
  3497. delta = 1;
  3498. }
  3499. if (bus->flowcontrol & ~fcbits) {
  3500. bus->fc_xon++;
  3501. delta = 1;
  3502. }
  3503. if (delta) {
  3504. bus->fc_rcvd++;
  3505. bus->flowcontrol = fcbits;
  3506. }
  3507. /* Check and update sequence number */
  3508. if (rxseq != seq) {
  3509. DHD_INFO(("%s: rx_seq %d, expected %d\n", __FUNCTION__, seq, rxseq));
  3510. bus->rx_badseq++;
  3511. rxseq = seq;
  3512. }
  3513. /* Check window for sanity */
  3514. if ((uint8)(txmax - bus->tx_seq) > 0x40) {
  3515. DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
  3516. __FUNCTION__, txmax, bus->tx_seq));
  3517. txmax = bus->tx_max;
  3518. }
  3519. bus->tx_max = txmax;
  3520. /* Call a separate function for control frames */
  3521. if (chan == SDPCM_CONTROL_CHANNEL) {
  3522. dhdsdio_read_control(bus, bus->rxhdr, len, doff);
  3523. continue;
  3524. }
  3525. ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL) ||
  3526. (chan == SDPCM_TEST_CHANNEL) || (chan == SDPCM_GLOM_CHANNEL));
  3527. /* Length to read */
  3528. rdlen = (len > firstread) ? (len - firstread) : 0;
  3529. /* May pad read to blocksize for efficiency */
  3530. if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
  3531. pad = bus->blocksize - (rdlen % bus->blocksize);
  3532. if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
  3533. ((rdlen + pad + firstread) < MAX_RX_DATASZ))
  3534. rdlen += pad;
  3535. } else if (rdlen % DHD_SDALIGN) {
  3536. rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
  3537. }
  3538. /* Satisfy length-alignment requirements */
  3539. if (forcealign && (rdlen & (ALIGNMENT - 1)))
  3540. rdlen = ROUNDUP(rdlen, ALIGNMENT);
  3541. if ((rdlen + firstread) > MAX_RX_DATASZ) {
  3542. /* Too long -- skip this frame */
  3543. DHD_ERROR(("%s: too long: len %d rdlen %d\n", __FUNCTION__, len, rdlen));
  3544. bus->dhd->rx_errors++; bus->rx_toolong++;
  3545. dhdsdio_rxfail(bus, FALSE, FALSE);
  3546. continue;
  3547. }
  3548. dhd_os_sdlock_rxq(bus->dhd);
  3549. if (!(pkt = PKTGET(osh, (rdlen + firstread + DHD_SDALIGN), FALSE))) {
  3550. /* Give up on data, request rtx of events */
  3551. DHD_ERROR(("%s: PKTGET failed: rdlen %d chan %d\n",
  3552. __FUNCTION__, rdlen, chan));
  3553. bus->dhd->rx_dropped++;
  3554. dhd_os_sdunlock_rxq(bus->dhd);
  3555. dhdsdio_rxfail(bus, FALSE, RETRYCHAN(chan));
  3556. continue;
  3557. }
  3558. dhd_os_sdunlock_rxq(bus->dhd);
  3559. ASSERT(!PKTLINK(pkt));
  3560. /* Leave room for what we already read, and align remainder */
  3561. ASSERT(firstread < (PKTLEN(osh, pkt)));
  3562. PKTPULL(osh, pkt, firstread);
  3563. PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN);
  3564. /* Read the remaining frame data */
  3565. sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
  3566. ((uint8 *)PKTDATA(osh, pkt)), rdlen, pkt, NULL, NULL);
  3567. bus->f2rxdata++;
  3568. ASSERT(sdret != BCME_PENDING);
  3569. if (sdret < 0) {
  3570. DHD_ERROR(("%s: read %d %s bytes failed: %d\n", __FUNCTION__, rdlen,
  3571. ((chan == SDPCM_EVENT_CHANNEL) ? "event" :
  3572. ((chan == SDPCM_DATA_CHANNEL) ? "data" : "test")), sdret));
  3573. dhd_os_sdlock_rxq(bus->dhd);
  3574. PKTFREE(bus->dhd->osh, pkt, FALSE);
  3575. dhd_os_sdunlock_rxq(bus->dhd);
  3576. bus->dhd->rx_errors++;
  3577. dhdsdio_rxfail(bus, TRUE, RETRYCHAN(chan));
  3578. continue;
  3579. }
  3580. /* Copy the already-read portion */
  3581. PKTPUSH(osh, pkt, firstread);
  3582. bcopy(bus->rxhdr, PKTDATA(osh, pkt), firstread);
  3583. #ifdef DHD_DEBUG
  3584. if (DHD_BYTES_ON() && DHD_DATA_ON()) {
  3585. prhex("Rx Data", PKTDATA(osh, pkt), len);
  3586. }
  3587. #endif
  3588. deliver:
  3589. /* Save superframe descriptor and allocate packet frame */
  3590. if (chan == SDPCM_GLOM_CHANNEL) {
  3591. if (SDPCM_GLOMDESC(&bus->rxhdr[SDPCM_FRAMETAG_LEN])) {
  3592. DHD_GLOM(("%s: got glom descriptor, %d bytes:\n",
  3593. __FUNCTION__, len));
  3594. #ifdef DHD_DEBUG
  3595. if (DHD_GLOM_ON()) {
  3596. prhex("Glom Data", PKTDATA(osh, pkt), len);
  3597. }
  3598. #endif
  3599. PKTSETLEN(osh, pkt, len);
  3600. ASSERT(doff == SDPCM_HDRLEN);
  3601. PKTPULL(osh, pkt, SDPCM_HDRLEN);
  3602. bus->glomd = pkt;
  3603. } else {
  3604. DHD_ERROR(("%s: glom superframe w/o descriptor!\n", __FUNCTION__));
  3605. dhdsdio_rxfail(bus, FALSE, FALSE);
  3606. }
  3607. continue;
  3608. }
  3609. /* Fill in packet len and prio, deliver upward */
  3610. PKTSETLEN(osh, pkt, len);
  3611. PKTPULL(osh, pkt, doff);
  3612. #ifdef SDTEST
  3613. /* Test channel packets are processed separately */
  3614. if (chan == SDPCM_TEST_CHANNEL) {
  3615. dhdsdio_testrcv(bus, pkt, seq);
  3616. continue;
  3617. }
  3618. #endif /* SDTEST */
  3619. if (PKTLEN(osh, pkt) == 0) {
  3620. dhd_os_sdlock_rxq(bus->dhd);
  3621. PKTFREE(bus->dhd->osh, pkt, FALSE);
  3622. dhd_os_sdunlock_rxq(bus->dhd);
  3623. continue;
  3624. } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pkt) != 0) {
  3625. DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__));
  3626. dhd_os_sdlock_rxq(bus->dhd);
  3627. PKTFREE(bus->dhd->osh, pkt, FALSE);
  3628. dhd_os_sdunlock_rxq(bus->dhd);
  3629. bus->dhd->rx_errors++;
  3630. continue;
  3631. }
  3632. /* Unlock during rx call */
  3633. dhd_os_sdunlock(bus->dhd);
  3634. dhd_rx_frame(bus->dhd, ifidx, pkt, 1, chan);
  3635. dhd_os_sdlock(bus->dhd);
  3636. }
  3637. rxcount = maxframes - rxleft;
  3638. #ifdef DHD_DEBUG
  3639. /* Message if we hit the limit */
  3640. if (!rxleft && !sdtest)
  3641. DHD_DATA(("%s: hit rx limit of %d frames\n", __FUNCTION__, maxframes));
  3642. else
  3643. #endif /* DHD_DEBUG */
  3644. DHD_DATA(("%s: processed %d frames\n", __FUNCTION__, rxcount));
  3645. /* Back off rxseq if awaiting rtx, update rx_seq */
  3646. if (bus->rxskip)
  3647. rxseq--;
  3648. bus->rx_seq = rxseq;
  3649. return rxcount;
  3650. }
  3651. static uint32
  3652. dhdsdio_hostmail(dhd_bus_t *bus)
  3653. {
  3654. sdpcmd_regs_t *regs = bus->regs;
  3655. uint32 intstatus = 0;
  3656. uint32 hmb_data;
  3657. uint8 fcbits;
  3658. uint retries = 0;
  3659. DHD_TRACE(("%s: Enter\n", __FUNCTION__));
  3660. /* Read mailbox data and ack that we did so */
  3661. R_SDREG(hmb_data, &regs->tohostmailboxdata, retries);
  3662. if (retries <= retry_limit)
  3663. W_SDREG(SMB_INT_ACK, &regs->tosbmailbox, retries);
  3664. bus->f1regdata += 2;
  3665. /* Dongle recomposed rx frames, accept them again */
  3666. if (hmb_data & HMB_DATA_NAKHANDLED) {
  3667. DHD_INFO(("Dongle reports NAK handled, expect rtx of %d\n", bus->rx_seq));
  3668. if (!bus->rxskip) {
  3669. DHD_ERROR(("%s: unexpected NAKHANDLED!\n", __FUNCTION__));
  3670. }
  3671. bus->rxskip = FALSE;
  3672. intstatus |= FRAME_AVAIL_MASK(bus);
  3673. }
  3674. /*
  3675. * DEVREADY does not occur with gSPI.
  3676. */
  3677. if (hmb_data & (HMB_DATA_DEVREADY | HMB_DATA_FWREADY)) {
  3678. bus->sdpcm_ver = (hmb_data & HMB_DATA_VERSION_MASK) >> HMB_DATA_VERSION_SHIFT;
  3679. if (bus->sdpcm_ver != SDPCM_PROT_VERSION)
  3680. DHD_ERROR(("Version mismatch, dongle reports %d, expecting %d\n",
  3681. bus->sdpcm_ver, SDPCM_PROT_VERSION));
  3682. else
  3683. DHD_INFO(("Dongle ready, protocol version %d\n", bus->sdpcm_ver));
  3684. /* make sure for the SDIO_DEVICE_RXDATAINT_MODE_1 corecontrol is proper */
  3685. if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev >= 4) &&
  3686. (bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_1)) {
  3687. uint32 val;
  3688. val = R_REG(bus->dhd->osh, &bus->regs->corecontrol);
  3689. val &= ~CC_XMTDATAAVAIL_MODE;
  3690. val |= CC_XMTDATAAVAIL_CTRL;
  3691. W_REG(bus->dhd->osh, &bus->regs->corecontrol, val);
  3692. val = R_REG(bus->dhd->osh, &bus->regs->corecontrol);
  3693. }
  3694. #ifdef DHD_DEBUG
  3695. /* Retrieve console state address now that firmware should have updated it */
  3696. {
  3697. sdpcm_shared_t shared;
  3698. if (dhdsdio_readshared(bus, &shared) == 0)
  3699. bus->console_addr = shared.console_addr;
  3700. }
  3701. #endif /* DHD_DEBUG */
  3702. }
  3703. /*
  3704. * Flow Control has been moved into the RX headers and this out of band
  3705. * method isn't used any more. Leave this here for possibly remaining backward
  3706. * compatible with older dongles
  3707. */
  3708. if (hmb_data & HMB_DATA_FC) {
  3709. fcbits = (hmb_data & HMB_DATA_FCDATA_MASK) >> HMB_DATA_FCDATA_SHIFT;
  3710. if (fcbits & ~bus->flowcontrol)
  3711. bus->fc_xoff++;
  3712. if (bus->flowcontrol & ~fcbits)
  3713. bus->fc_xon++;
  3714. bus->fc_rcvd++;
  3715. bus->flowcontrol = fcbits;
  3716. }
  3717. #ifdef DHD_DEBUG
  3718. /* At least print a message if FW halted */
  3719. if (hmb_data & HMB_DATA_FWHALT) {
  3720. DHD_ERROR(("INTERNAL ERROR: FIRMWARE HALTED\n"));
  3721. dhdsdio_checkdied(bus, NULL, 0);
  3722. }
  3723. #endif /* DHD_DEBUG */
  3724. /* Shouldn't be any others */
  3725. if (hmb_data & ~(HMB_DATA_DEVREADY |
  3726. HMB_DATA_FWHALT |
  3727. HMB_DATA_NAKHANDLED |
  3728. HMB_DATA_FC |
  3729. HMB_DATA_FWREADY |
  3730. HMB_DATA_FCDATA_MASK |
  3731. HMB_DATA_VERSION_MASK)) {
  3732. DHD_ERROR(("Unknown mailbox data content: 0x%02x\n", hmb_data));
  3733. }
  3734. return intstatus;
  3735. }
  3736. static bool
  3737. dhdsdio_dpc(dhd_bus_t *bus)
  3738. {
  3739. bcmsdh_info_t *sdh = bus->sdh;
  3740. sdpcmd_regs_t *regs = bus->regs;
  3741. uint32 intstatus, newstatus = 0;
  3742. uint retries = 0;
  3743. uint rxlimit = dhd_rxbound; /* Rx frames to read before resched */
  3744. uint txlimit = dhd_txbound; /* Tx frames to send before resched */
  3745. uint framecnt = 0; /* Temporary counter of tx/rx frames */
  3746. bool rxdone = TRUE; /* Flag for no more read data */
  3747. bool resched = FALSE; /* Flag indicating resched wanted */
  3748. DHD_TRACE(("%s: Enter\n", __FUNCTION__));
  3749. if (bus->dhd->busstate == DHD_BUS_DOWN) {
  3750. DHD_ERROR(("%s: Bus down, ret\n", __FUNCTION__));
  3751. bus->intstatus = 0;
  3752. return 0;
  3753. }
  3754. /* Start with leftover status bits */
  3755. intstatus = bus->intstatus;
  3756. dhd_os_sdlock(bus->dhd);
  3757. /* If waiting for HTAVAIL, check status */
  3758. if (bus->clkstate == CLK_PENDING) {
  3759. int err;
  3760. uint8 clkctl, devctl = 0;
  3761. #ifdef DHD_DEBUG
  3762. /* Check for inconsistent device control */
  3763. devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
  3764. if (err) {
  3765. DHD_ERROR(("%s: error reading DEVCTL: %d\n", __FUNCTION__, err));
  3766. bus->dhd->busstate = DHD_BUS_DOWN;
  3767. } else {
  3768. ASSERT(devctl & SBSDIO_DEVCTL_CA_INT_ONLY);
  3769. }
  3770. #endif /* DHD_DEBUG */
  3771. /* Read CSR, if clock on switch to AVAIL, else ignore */
  3772. clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
  3773. if (err) {
  3774. DHD_ERROR(("%s: error reading CSR: %d\n", __FUNCTION__, err));
  3775. bus->dhd->busstate = DHD_BUS_DOWN;
  3776. }
  3777. DHD_INFO(("DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n", devctl, clkctl));
  3778. if (SBSDIO_HTAV(clkctl)) {
  3779. devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
  3780. if (err) {
  3781. DHD_ERROR(("%s: error reading DEVCTL: %d\n",
  3782. __FUNCTION__, err));
  3783. bus->dhd->busstate = DHD_BUS_DOWN;
  3784. }
  3785. devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
  3786. bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
  3787. if (err) {
  3788. DHD_ERROR(("%s: error writing DEVCTL: %d\n",
  3789. __FUNCTION__, err));
  3790. bus->dhd->busstate = DHD_BUS_DOWN;
  3791. }
  3792. bus->clkstate = CLK_AVAIL;
  3793. } else {
  3794. goto clkwait;
  3795. }
  3796. }
  3797. BUS_WAKE(bus);
  3798. /* Make sure backplane clock is on */
  3799. dhdsdio_clkctl(bus, CLK_AVAIL, TRUE);
  3800. if (bus->clkstate != CLK_AVAIL)
  3801. goto clkwait;
  3802. /* Pending interrupt indicates new device status */
  3803. if (bus->ipend) {
  3804. bus->ipend = FALSE;
  3805. R_SDREG(newstatus, &regs->intstatus, retries);
  3806. bus->f1regdata++;
  3807. if (bcmsdh_regfail(bus->sdh))
  3808. newstatus = 0;
  3809. newstatus &= bus->hostintmask;
  3810. bus->fcstate = !!(newstatus & I_HMB_FC_STATE);
  3811. if (newstatus) {
  3812. bus->f1regdata++;
  3813. if ((bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_0) &&
  3814. (newstatus == I_XMTDATA_AVAIL)) {
  3815. }
  3816. else
  3817. W_SDREG(newstatus, &regs->intstatus, retries);
  3818. }
  3819. }
  3820. /* Merge new bits with previous */
  3821. intstatus |= newstatus;
  3822. bus->intstatus = 0;
  3823. /* Handle flow-control change: read new state in case our ack
  3824. * crossed another change interrupt. If change still set, assume
  3825. * FC ON for safety, let next loop through do the debounce.
  3826. */
  3827. if (intstatus & I_HMB_FC_CHANGE) {
  3828. intstatus &= ~I_HMB_FC_CHANGE;
  3829. W_SDREG(I_HMB_FC_CHANGE, &regs->intstatus, retries);
  3830. R_SDREG(newstatus, &regs->intstatus, retries);
  3831. bus->f1regdata += 2;
  3832. bus->fcstate = !!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE));
  3833. intstatus |= (newstatus & bus->hostintmask);
  3834. }
  3835. /* Just being here means nothing more to do for chipactive */
  3836. if (intstatus & I_CHIPACTIVE) {
  3837. /* ASSERT(bus->clkstate == CLK_AVAIL); */
  3838. intstatus &= ~I_CHIPACTIVE;
  3839. }
  3840. /* Handle host mailbox indication */
  3841. if (intstatus & I_HMB_HOST_INT) {
  3842. intstatus &= ~I_HMB_HOST_INT;
  3843. intstatus |= dhdsdio_hostmail(bus);
  3844. }
  3845. /* Generally don't ask for these, can get CRC errors... */
  3846. if (intstatus & I_WR_OOSYNC) {
  3847. DHD_ERROR(("Dongle reports WR_OOSYNC\n"));
  3848. intstatus &= ~I_WR_OOSYNC;
  3849. }
  3850. if (intstatus & I_RD_OOSYNC) {
  3851. DHD_ERROR(("Dongle reports RD_OOSYNC\n"));
  3852. intstatus &= ~I_RD_OOSYNC;
  3853. }
  3854. if (intstatus & I_SBINT) {
  3855. DHD_ERROR(("Dongle reports SBINT\n"));
  3856. intstatus &= ~I_SBINT;
  3857. }
  3858. /* Would be active due to wake-wlan in gSPI */
  3859. if (intstatus & I_CHIPACTIVE) {
  3860. DHD_INFO(("Dongle reports CHIPACTIVE\n"));
  3861. intstatus &= ~I_CHIPACTIVE;
  3862. }
  3863. /* Ignore frame indications if rxskip is set */
  3864. if (bus->rxskip) {
  3865. intstatus &= ~FRAME_AVAIL_MASK(bus);
  3866. }
  3867. /* On frame indication, read available frames */
  3868. if (PKT_AVAILABLE(bus, intstatus)) {
  3869. framecnt = dhdsdio_readframes(bus, rxlimit, &rxdone);
  3870. if (rxdone || bus->rxskip)
  3871. intstatus &= ~FRAME_AVAIL_MASK(bus);
  3872. rxlimit -= MIN(framecnt, rxlimit);
  3873. }
  3874. /* Keep still-pending events for next scheduling */
  3875. bus->intstatus = intstatus;
  3876. clkwait:
  3877. /* Re-enable interrupts to detect new device events (mailbox, rx frame)
  3878. * or clock availability. (Allows tx loop to check ipend if desired.)
  3879. * (Unless register access seems hosed, as we may not be able to ACK...)
  3880. */
  3881. if (bus->intr && bus->intdis && !bcmsdh_regfail(sdh)) {
  3882. DHD_INTR(("%s: enable SDIO interrupts, rxdone %d framecnt %d\n",
  3883. __FUNCTION__, rxdone, framecnt));
  3884. bus->intdis = FALSE;
  3885. #if defined(OOB_INTR_ONLY)
  3886. bcmsdh_oob_intr_set(1);
  3887. #endif /* (OOB_INTR_ONLY) */
  3888. bcmsdh_intr_enable(sdh);
  3889. }
  3890. #if defined(OOB_INTR_ONLY) && !defined(HW_OOB)
  3891. /* In case of SW-OOB(using edge trigger),
  3892. * Check interrupt status in the dongle again after enable irq on the host.
  3893. * and rechedule dpc if interrupt is pended in the dongle.
  3894. * There is a chance to miss OOB interrupt while irq is disabled on the host.
  3895. * No need to do this with HW-OOB(level trigger)
  3896. */
  3897. R_SDREG(newstatus, &regs->intstatus, retries);
  3898. if (bcmsdh_regfail(bus->sdh))
  3899. newstatus = 0;
  3900. if (newstatus & bus->hostintmask) {
  3901. bus->ipend = TRUE;
  3902. resched = TRUE;
  3903. }
  3904. #endif /* defined(OOB_INTR_ONLY) && !defined(HW_OOB) */
  3905. if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL)) {
  3906. int ret, i;
  3907. uint8* frame_seq = bus->ctrl_frame_buf + SDPCM_FRAMETAG_LEN;
  3908. if (*frame_seq != bus->tx_seq) {
  3909. DHD_INFO(("%s IOCTL frame seq lag detected!"
  3910. " frm_seq:%d != bus->tx_seq:%d, corrected\n",
  3911. __FUNCTION__, *frame_seq, bus->tx_seq));
  3912. *frame_seq = bus->tx_seq;
  3913. }
  3914. ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
  3915. (uint8 *)bus->ctrl_frame_buf, (uint32)bus->ctrl_frame_len,
  3916. NULL, NULL, NULL);
  3917. ASSERT(ret != BCME_PENDING);
  3918. if (ret < 0) {
  3919. /* On failure, abort the command and terminate the frame */
  3920. DHD_INFO(("%s: sdio error %d, abort command and terminate frame.\n",
  3921. __FUNCTION__, ret));
  3922. bus->tx_sderrs++;
  3923. bcmsdh_abort(sdh, SDIO_FUNC_2);
  3924. bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
  3925. SFC_WF_TERM, NULL);
  3926. bus->f1regdata++;
  3927. for (i = 0; i < 3; i++) {
  3928. uint8 hi, lo;
  3929. hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
  3930. SBSDIO_FUNC1_WFRAMEBCHI, NULL);
  3931. lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
  3932. SBSDIO_FUNC1_WFRAMEBCLO, NULL);
  3933. bus->f1regdata += 2;
  3934. if ((hi == 0) && (lo == 0))
  3935. break;
  3936. }
  3937. }
  3938. if (ret == 0) {
  3939. bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
  3940. }
  3941. bus->ctrl_frame_stat = FALSE;
  3942. dhd_wait_event_wakeup(bus->dhd);
  3943. }
  3944. /* Send queued frames (limit 1 if rx may still be pending) */
  3945. else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate &&
  3946. pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit && DATAOK(bus)) {
  3947. framecnt = rxdone ? txlimit : MIN(txlimit, dhd_txminmax);
  3948. framecnt = dhdsdio_sendfromq(bus, framecnt);
  3949. txlimit -= framecnt;
  3950. }
  3951. /* Resched the DPC if ctrl cmd is pending on bus credit */
  3952. if (bus->ctrl_frame_stat)
  3953. resched = TRUE;
  3954. /* Resched if events or tx frames are pending, else await next interrupt */
  3955. /* On failed register access, all bets are off: no resched or interrupts */
  3956. if ((bus->dhd->busstate == DHD_BUS_DOWN) || bcmsdh_regfail(sdh)) {
  3957. DHD_ERROR(("%s: failed backplane access over SDIO, halting operation %d \n",
  3958. __FUNCTION__, bcmsdh_regfail(sdh)));
  3959. bus->dhd->busstate = DHD_BUS_DOWN;
  3960. bus->intstatus = 0;
  3961. } else if (bus->clkstate == CLK_PENDING) {
  3962. /* Awaiting I_CHIPACTIVE; don't resched */
  3963. } else if (bus->intstatus || bus->ipend ||
  3964. (!bus->fcstate && pktq_mlen(&bus->txq, ~bus->flowcontrol) && DATAOK(bus)) ||
  3965. PKT_AVAILABLE(bus, bus->intstatus)) { /* Read multiple frames */
  3966. resched = TRUE;
  3967. }
  3968. bus->dpc_sched = resched;
  3969. /* If we're done for now, turn off clock request. */
  3970. if ((bus->idletime == DHD_IDLE_IMMEDIATE) && (bus->clkstate != CLK_PENDING)) {
  3971. bus->activity = FALSE;
  3972. dhdsdio_clkctl(bus, CLK_NONE, FALSE);
  3973. }
  3974. dhd_os_sdunlock(bus->dhd);
  3975. return resched;
  3976. }
  3977. bool
  3978. dhd_bus_dpc(struct dhd_bus *bus)
  3979. {
  3980. bool resched;
  3981. /* Call the DPC directly. */
  3982. DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__));
  3983. resched = dhdsdio_dpc(bus);
  3984. return resched;
  3985. }
  3986. void
  3987. dhdsdio_isr(void *arg)
  3988. {
  3989. dhd_bus_t *bus = (dhd_bus_t*)arg;
  3990. bcmsdh_info_t *sdh;
  3991. DHD_TRACE(("%s: Enter\n", __FUNCTION__));
  3992. if (!bus) {
  3993. DHD_ERROR(("%s : bus is null pointer , exit \n", __FUNCTION__));
  3994. return;
  3995. }
  3996. sdh = bus->sdh;
  3997. if (bus->dhd->busstate == DHD_BUS_DOWN) {
  3998. DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__));
  3999. return;
  4000. }
  4001. DHD_TRACE(("%s: Enter\n", __FUNCTION__));
  4002. /* Count the interrupt call */
  4003. bus->intrcount++;
  4004. bus->ipend = TRUE;
  4005. /* Shouldn't get this interrupt if we're sleeping? */
  4006. if (bus->sleeping) {
  4007. DHD_ERROR(("INTERRUPT WHILE SLEEPING??\n"));
  4008. return;
  4009. }
  4010. /* Disable additional interrupts (is this needed now)? */
  4011. if (bus->intr) {
  4012. DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
  4013. } else {
  4014. DHD_ERROR(("dhdsdio_isr() w/o interrupt configured!\n"));
  4015. }
  4016. bcmsdh_intr_disable(sdh);
  4017. bus->intdis = TRUE;
  4018. #if defined(SDIO_ISR_THREAD)
  4019. DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__));
  4020. DHD_OS_WAKE_LOCK(bus->dhd);
  4021. while (dhdsdio_dpc(bus));
  4022. DHD_OS_WAKE_UNLOCK(bus->dhd);
  4023. #else
  4024. bus->dpc_sched = TRUE;
  4025. dhd_sched_dpc(bus->dhd);
  4026. #endif
  4027. }
  4028. #ifdef SDTEST
  4029. static void
  4030. dhdsdio_pktgen_init(dhd_bus_t *bus)
  4031. {
  4032. /* Default to specified length, or full range */
  4033. if (dhd_pktgen_len) {
  4034. bus->pktgen_maxlen = MIN(dhd_pktgen_len, MAX_PKTGEN_LEN);
  4035. bus->pktgen_minlen = bus->pktgen_maxlen;
  4036. } else {
  4037. bus->pktgen_maxlen = MAX_PKTGEN_LEN;
  4038. bus->pktgen_minlen = 0;
  4039. }
  4040. bus->pktgen_len = (uint16)bus->pktgen_minlen;
  4041. /* Default to per-watchdog burst with 10s print time */
  4042. bus->pktgen_freq = 1;
  4043. bus->pktgen_print = 10000 / dhd_watchdog_ms;
  4044. bus->pktgen_count = (dhd_pktgen * dhd_watchdog_ms + 999) / 1000;
  4045. /* Default to echo mode */
  4046. bus->pktgen_mode = DHD_PKTGEN_ECHO;
  4047. bus->pktgen_stop = 1;
  4048. }
  4049. static void
  4050. dhdsdio_pktgen(dhd_bus_t *bus)
  4051. {
  4052. void *pkt;
  4053. uint8 *data;
  4054. uint pktcount;
  4055. uint fillbyte;
  4056. osl_t *osh = bus->dhd->osh;
  4057. uint16 len;
  4058. /* Display current count if appropriate */
  4059. if (bus->pktgen_print && (++bus->pktgen_ptick >= bus->pktgen_print)) {
  4060. bus->pktgen_ptick = 0;
  4061. printf("%s: send attempts %d rcvd %d\n",
  4062. __FUNCTION__, bus->pktgen_sent, bus->pktgen_rcvd);
  4063. }
  4064. /* For recv mode, just make sure dongle has started sending */
  4065. if (bus->pktgen_mode == DHD_PKTGEN_RECV) {
  4066. if (bus->pktgen_rcv_state == PKTGEN_RCV_IDLE) {
  4067. bus->pktgen_rcv_state = PKTGEN_RCV_ONGOING;
  4068. dhdsdio_sdtest_set(bus, (uint8)bus->pktgen_total);
  4069. }
  4070. return;
  4071. }
  4072. /* Otherwise, generate or request the specified number of packets */
  4073. for (pktcount = 0; pktcount < bus->pktgen_count; pktcount++) {
  4074. /* Stop if total has been reached */
  4075. if (bus->pktgen_total && (bus->pktgen_sent >= bus->pktgen_total)) {
  4076. bus->pktgen_count = 0;
  4077. break;
  4078. }
  4079. /* Allocate an appropriate-sized packet */
  4080. len = bus->pktgen_len;
  4081. if (!(pkt = PKTGET(osh, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN),
  4082. TRUE))) {;
  4083. DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__));
  4084. break;
  4085. }
  4086. PKTALIGN(osh, pkt, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN), DHD_SDALIGN);
  4087. data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
  4088. /* Write test header cmd and extra based on mode */
  4089. switch (bus->pktgen_mode) {
  4090. case DHD_PKTGEN_ECHO:
  4091. *data++ = SDPCM_TEST_ECHOREQ;
  4092. *data++ = (uint8)bus->pktgen_sent;
  4093. break;
  4094. case DHD_PKTGEN_SEND:
  4095. *data++ = SDPCM_TEST_DISCARD;
  4096. *data++ = (uint8)bus->pktgen_sent;
  4097. break;
  4098. case DHD_PKTGEN_RXBURST:
  4099. *data++ = SDPCM_TEST_BURST;
  4100. *data++ = (uint8)bus->pktgen_count;
  4101. break;
  4102. default:
  4103. DHD_ERROR(("Unrecognized pktgen mode %d\n", bus->pktgen_mode));
  4104. PKTFREE(osh, pkt, TRUE);
  4105. bus->pktgen_count = 0;
  4106. return;
  4107. }
  4108. /* Write test header length field */
  4109. *data++ = (len >> 0);
  4110. *data++ = (len >> 8);
  4111. /* Then fill in the remainder -- N/A for burst, but who cares... */
  4112. for (fillbyte = 0; fillbyte < len; fillbyte++)
  4113. *data++ = SDPCM_TEST_FILL(fillbyte, (uint8)bus->pktgen_sent);
  4114. #ifdef DHD_DEBUG
  4115. if (DHD_BYTES_ON() && DHD_DATA_ON()) {
  4116. data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
  4117. prhex("dhdsdio_pktgen: Tx Data", data, PKTLEN(osh, pkt) - SDPCM_HDRLEN);
  4118. }
  4119. #endif
  4120. /* Send it */
  4121. if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE)) {
  4122. bus->pktgen_fail++;
  4123. if (bus->pktgen_stop && bus->pktgen_stop == bus->pktgen_fail)
  4124. bus->pktgen_count = 0;
  4125. }
  4126. bus->pktgen_sent++;
  4127. /* Bump length if not fixed, wrap at max */
  4128. if (++bus->pktgen_len > bus->pktgen_maxlen)
  4129. bus->pktgen_len = (uint16)bus->pktgen_minlen;
  4130. /* Special case for burst mode: just send one request! */
  4131. if (bus->pktgen_mode == DHD_PKTGEN_RXBURST)
  4132. break;
  4133. }
  4134. }
  4135. static void
  4136. dhdsdio_sdtest_set(dhd_bus_t *bus, uint8 count)
  4137. {
  4138. void *pkt;
  4139. uint8 *data;
  4140. osl_t *osh = bus->dhd->osh;
  4141. /* Allocate the packet */
  4142. if (!(pkt = PKTGET(osh, SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN, TRUE))) {
  4143. DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__));
  4144. return;
  4145. }
  4146. PKTALIGN(osh, pkt, (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN), DHD_SDALIGN);
  4147. data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
  4148. /* Fill in the test header */
  4149. *data++ = SDPCM_TEST_SEND;
  4150. *data++ = count;
  4151. *data++ = (bus->pktgen_maxlen >> 0);
  4152. *data++ = (bus->pktgen_maxlen >> 8);
  4153. /* Send it */
  4154. if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE))
  4155. bus->pktgen_fail++;
  4156. }
  4157. static void
  4158. dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq)
  4159. {
  4160. osl_t *osh = bus->dhd->osh;
  4161. uint8 *data;
  4162. uint pktlen;
  4163. uint8 cmd;
  4164. uint8 extra;
  4165. uint16 len;
  4166. uint16 offset;
  4167. /* Check for min length */
  4168. if ((pktlen = PKTLEN(osh, pkt)) < SDPCM_TEST_HDRLEN) {
  4169. DHD_ERROR(("dhdsdio_restrcv: toss runt frame, pktlen %d\n", pktlen));
  4170. PKTFREE(osh, pkt, FALSE);
  4171. return;
  4172. }
  4173. /* Extract header fields */
  4174. data = PKTDATA(osh, pkt);
  4175. cmd = *data++;
  4176. extra = *data++;
  4177. len = *data++; len += *data++ << 8;
  4178. DHD_TRACE(("%s:cmd:%d, xtra:%d,len:%d\n", __FUNCTION__, cmd, extra, len));
  4179. /* Check length for relevant commands */
  4180. if (cmd == SDPCM_TEST_DISCARD || cmd == SDPCM_TEST_ECHOREQ || cmd == SDPCM_TEST_ECHORSP) {
  4181. if (pktlen != len + SDPCM_TEST_HDRLEN) {
  4182. DHD_ERROR(("dhdsdio_testrcv: frame length mismatch, pktlen %d seq %d"
  4183. " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len));
  4184. PKTFREE(osh, pkt, FALSE);
  4185. return;
  4186. }
  4187. }
  4188. /* Process as per command */
  4189. switch (cmd) {
  4190. case SDPCM_TEST_ECHOREQ:
  4191. /* Rx->Tx turnaround ok (even on NDIS w/current implementation) */
  4192. *(uint8 *)(PKTDATA(osh, pkt)) = SDPCM_TEST_ECHORSP;
  4193. if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE) == 0) {
  4194. bus->pktgen_sent++;
  4195. } else {
  4196. bus->pktgen_fail++;
  4197. PKTFREE(osh, pkt, FALSE);
  4198. }
  4199. bus->pktgen_rcvd++;
  4200. break;
  4201. case SDPCM_TEST_ECHORSP:
  4202. if (bus->ext_loop) {
  4203. PKTFREE(osh, pkt, FALSE);
  4204. bus->pktgen_rcvd++;
  4205. break;
  4206. }
  4207. for (offset = 0; offset < len; offset++, data++) {
  4208. if (*data != SDPCM_TEST_FILL(offset, extra)) {
  4209. DHD_ERROR(("dhdsdio_testrcv: echo data mismatch: "
  4210. "offset %d (len %d) expect 0x%02x rcvd 0x%02x\n",
  4211. offset, len, SDPCM_TEST_FILL(offset, extra), *data));
  4212. break;
  4213. }
  4214. }
  4215. PKTFREE(osh, pkt, FALSE);
  4216. bus->pktgen_rcvd++;
  4217. break;
  4218. case SDPCM_TEST_DISCARD:
  4219. {
  4220. int i = 0;
  4221. uint8 *prn = data;
  4222. uint8 testval = extra;
  4223. for (i = 0; i < len; i++) {
  4224. if (*prn != testval) {
  4225. DHD_ERROR(("DIErr@Pkt#:%d,Ix:%d, expected:0x%x, got:0x%x\n",
  4226. i, bus->pktgen_rcvd_rcvsession, testval, *prn));
  4227. prn++; testval++;
  4228. }
  4229. }
  4230. }
  4231. PKTFREE(osh, pkt, FALSE);
  4232. bus->pktgen_rcvd++;
  4233. break;
  4234. case SDPCM_TEST_BURST:
  4235. case SDPCM_TEST_SEND:
  4236. default:
  4237. DHD_INFO(("dhdsdio_testrcv: unsupported or unknown command, pktlen %d seq %d"
  4238. " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len));
  4239. PKTFREE(osh, pkt, FALSE);
  4240. break;
  4241. }
  4242. /* For recv mode, stop at limit (and tell dongle to stop sending) */
  4243. if (bus->pktgen_mode == DHD_PKTGEN_RECV) {
  4244. if (bus->pktgen_rcv_state != PKTGEN_RCV_IDLE) {
  4245. bus->pktgen_rcvd_rcvsession++;
  4246. if (bus->pktgen_total &&
  4247. (bus->pktgen_rcvd_rcvsession >= bus->pktgen_total)) {
  4248. bus->pktgen_count = 0;
  4249. DHD_ERROR(("Pktgen:rcv test complete!\n"));
  4250. bus->pktgen_rcv_state = PKTGEN_RCV_IDLE;
  4251. dhdsdio_sdtest_set(bus, FALSE);
  4252. bus->pktgen_rcvd_rcvsession = 0;
  4253. }
  4254. }
  4255. }
  4256. }
  4257. #endif /* SDTEST */
  4258. extern void
  4259. dhd_disable_intr(dhd_pub_t *dhdp)
  4260. {
  4261. dhd_bus_t *bus;
  4262. bus = dhdp->bus;
  4263. bcmsdh_intr_disable(bus->sdh);
  4264. }
  4265. extern bool
  4266. dhd_bus_watchdog(dhd_pub_t *dhdp)
  4267. {
  4268. dhd_bus_t *bus;
  4269. DHD_TIMER(("%s: Enter\n", __FUNCTION__));
  4270. bus = dhdp->bus;
  4271. if (bus->dhd->dongle_reset)
  4272. return FALSE;
  4273. /* Ignore the timer if simulating bus down */
  4274. if (bus->sleeping)
  4275. return FALSE;
  4276. if (dhdp->busstate == DHD_BUS_DOWN)
  4277. return FALSE;
  4278. /* Poll period: check device if appropriate. */
  4279. if (bus->poll && (++bus->polltick >= bus->pollrate)) {
  4280. uint32 intstatus = 0;
  4281. /* Reset poll tick */
  4282. bus->polltick = 0;
  4283. /* Check device if no interrupts */
  4284. if (!bus->intr || (bus->intrcount == bus->lastintrs)) {
  4285. if (!bus->dpc_sched) {
  4286. uint8 devpend;
  4287. devpend = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0,
  4288. SDIOD_CCCR_INTPEND, NULL);
  4289. intstatus = devpend & (INTR_STATUS_FUNC1 | INTR_STATUS_FUNC2);
  4290. }
  4291. /* If there is something, make like the ISR and schedule the DPC */
  4292. if (intstatus) {
  4293. bus->pollcnt++;
  4294. bus->ipend = TRUE;
  4295. if (bus->intr) {
  4296. bcmsdh_intr_disable(bus->sdh);
  4297. }
  4298. bus->dpc_sched = TRUE;
  4299. dhd_sched_dpc(bus->dhd);
  4300. }
  4301. }
  4302. /* Update interrupt tracking */
  4303. bus->lastintrs = bus->intrcount;
  4304. }
  4305. #ifdef DHD_DEBUG
  4306. /* Poll for console output periodically */
  4307. if (dhdp->busstate == DHD_BUS_DATA && dhd_console_ms != 0) {
  4308. bus->console.count += dhd_watchdog_ms;
  4309. if (bus->console.count >= dhd_console_ms) {
  4310. bus->console.count -= dhd_console_ms;
  4311. /* Make sure backplane clock is on */
  4312. dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
  4313. if (dhdsdio_readconsole(bus) < 0)
  4314. dhd_console_ms = 0; /* On error, stop trying */
  4315. }
  4316. }
  4317. #endif /* DHD_DEBUG */
  4318. #ifdef SDTEST
  4319. /* Generate packets if configured */
  4320. if (bus->pktgen_count && (++bus->pktgen_tick >= bus->pktgen_freq)) {
  4321. /* Make sure backplane clock is on */
  4322. dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
  4323. bus->pktgen_tick = 0;
  4324. dhdsdio_pktgen(bus);
  4325. }
  4326. #endif
  4327. /* On idle timeout clear activity flag and/or turn off clock */
  4328. if ((bus->idletime > 0) && (bus->clkstate == CLK_AVAIL)) {
  4329. if (++bus->idlecount >= bus->idletime) {
  4330. bus->idlecount = 0;
  4331. if (bus->activity) {
  4332. bus->activity = FALSE;
  4333. dhdsdio_clkctl(bus, CLK_NONE, FALSE);
  4334. }
  4335. }
  4336. }
  4337. return bus->ipend;
  4338. }
  4339. #ifdef DHD_DEBUG
  4340. extern int
  4341. dhd_bus_console_in(dhd_pub_t *dhdp, uchar *msg, uint msglen)
  4342. {
  4343. dhd_bus_t *bus = dhdp->bus;
  4344. uint32 addr, val;
  4345. int rv;
  4346. void *pkt;
  4347. /* Address could be zero if CONSOLE := 0 in dongle Makefile */
  4348. if (bus->console_addr == 0)
  4349. return BCME_UNSUPPORTED;
  4350. /* Exclusive bus access */
  4351. dhd_os_sdlock(bus->dhd);
  4352. /* Don't allow input if dongle is in reset */
  4353. if (bus->dhd->dongle_reset) {
  4354. dhd_os_sdunlock(bus->dhd);
  4355. return BCME_NOTREADY;
  4356. }
  4357. /* Request clock to allow SDIO accesses */
  4358. BUS_WAKE(bus);
  4359. /* No pend allowed since txpkt is called later, ht clk has to be on */
  4360. dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
  4361. /* Zero cbuf_index */
  4362. addr = bus->console_addr + OFFSETOF(hndrte_cons_t, cbuf_idx);
  4363. val = htol32(0);
  4364. if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0)
  4365. goto done;
  4366. /* Write message into cbuf */
  4367. addr = bus->console_addr + OFFSETOF(hndrte_cons_t, cbuf);
  4368. if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)msg, msglen)) < 0)
  4369. goto done;
  4370. /* Write length into vcons_in */
  4371. addr = bus->console_addr + OFFSETOF(hndrte_cons_t, vcons_in);
  4372. val = htol32(msglen);
  4373. if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0)
  4374. goto done;
  4375. /* Bump dongle by sending an empty packet on the event channel.
  4376. * sdpcm_sendup (RX) checks for virtual console input.
  4377. */
  4378. if ((pkt = PKTGET(bus->dhd->osh, 4 + SDPCM_RESERVE, TRUE)) != NULL)
  4379. dhdsdio_txpkt(bus, pkt, SDPCM_EVENT_CHANNEL, TRUE);
  4380. done:
  4381. if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
  4382. bus->activity = FALSE;
  4383. dhdsdio_clkctl(bus, CLK_NONE, TRUE);
  4384. }
  4385. dhd_os_sdunlock(bus->dhd);
  4386. return rv;
  4387. }
  4388. #endif /* DHD_DEBUG */
  4389. #ifdef DHD_DEBUG
  4390. static void
  4391. dhd_dump_cis(uint fn, uint8 *cis)
  4392. {
  4393. uint byte, tag, tdata;
  4394. DHD_INFO(("Function %d CIS:\n", fn));
  4395. for (tdata = byte = 0; byte < SBSDIO_CIS_SIZE_LIMIT; byte++) {
  4396. if ((byte % 16) == 0)
  4397. DHD_INFO((" "));
  4398. DHD_INFO(("%02x ", cis[byte]));
  4399. if ((byte % 16) == 15)
  4400. DHD_INFO(("\n"));
  4401. if (!tdata--) {
  4402. tag = cis[byte];
  4403. if (tag == 0xff)
  4404. break;
  4405. else if (!tag)
  4406. tdata = 0;
  4407. else if ((byte + 1) < SBSDIO_CIS_SIZE_LIMIT)
  4408. tdata = cis[byte + 1] + 1;
  4409. else
  4410. DHD_INFO(("]"));
  4411. }
  4412. }
  4413. if ((byte % 16) != 15)
  4414. DHD_INFO(("\n"));
  4415. }
  4416. #endif /* DHD_DEBUG */
  4417. static bool
  4418. dhdsdio_chipmatch(uint16 chipid)
  4419. {
  4420. if (chipid == BCM4325_CHIP_ID)
  4421. return TRUE;
  4422. if (chipid == BCM4329_CHIP_ID)
  4423. return TRUE;
  4424. if (chipid == BCM4315_CHIP_ID)
  4425. return TRUE;
  4426. if (chipid == BCM4319_CHIP_ID)
  4427. return TRUE;
  4428. if (chipid == BCM4330_CHIP_ID)
  4429. return TRUE;
  4430. if (chipid == BCM43239_CHIP_ID)
  4431. return TRUE;
  4432. if (chipid == BCM4336_CHIP_ID)
  4433. return TRUE;
  4434. if (chipid == BCM43237_CHIP_ID)
  4435. return TRUE;
  4436. if (chipid == BCM43362_CHIP_ID)
  4437. return TRUE;
  4438. return FALSE;
  4439. }
  4440. static void *
  4441. dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot,
  4442. uint16 func, uint bustype, void *regsva, osl_t * osh, void *sdh)
  4443. {
  4444. int ret;
  4445. dhd_bus_t *bus;
  4446. dhd_cmn_t *cmn;
  4447. #ifdef GET_CUSTOM_MAC_ENABLE
  4448. struct ether_addr ea_addr;
  4449. #endif /* GET_CUSTOM_MAC_ENABLE */
  4450. #ifdef PROP_TXSTATUS
  4451. uint up = 0;
  4452. #endif
  4453. /* Init global variables at run-time, not as part of the declaration.
  4454. * This is required to support init/de-init of the driver. Initialization
  4455. * of globals as part of the declaration results in non-deterministic
  4456. * behavior since the value of the globals may be different on the
  4457. * first time that the driver is initialized vs subsequent initializations.
  4458. */
  4459. dhd_txbound = DHD_TXBOUND;
  4460. dhd_rxbound = DHD_RXBOUND;
  4461. dhd_alignctl = TRUE;
  4462. sd1idle = TRUE;
  4463. dhd_readahead = TRUE;
  4464. retrydata = FALSE;
  4465. dhd_doflow = FALSE;
  4466. dhd_dongle_memsize = 0;
  4467. dhd_txminmax = DHD_TXMINMAX;
  4468. forcealign = TRUE;
  4469. DHD_TRACE(("%s: Enter\n", __FUNCTION__));
  4470. DHD_INFO(("%s: venid 0x%04x devid 0x%04x\n", __FUNCTION__, venid, devid));
  4471. /* We make assumptions about address window mappings */
  4472. ASSERT((uintptr)regsva == SI_ENUM_BASE);
  4473. /* BCMSDH passes venid and devid based on CIS parsing -- but low-power start
  4474. * means early parse could fail, so here we should get either an ID
  4475. * we recognize OR (-1) indicating we must request power first.
  4476. */
  4477. /* Check the Vendor ID */
  4478. switch (venid) {
  4479. case 0x0000:
  4480. case VENDOR_BROADCOM:
  4481. break;
  4482. default:
  4483. DHD_ERROR(("%s: unknown vendor: 0x%04x\n",
  4484. __FUNCTION__, venid));
  4485. return NULL;
  4486. }
  4487. /* Check the Device ID and make sure it's one that we support */
  4488. switch (devid) {
  4489. case BCM4325_D11DUAL_ID: /* 4325 802.11a/g id */
  4490. case BCM4325_D11G_ID: /* 4325 802.11g 2.4Ghz band id */
  4491. case BCM4325_D11A_ID: /* 4325 802.11a 5Ghz band id */
  4492. DHD_INFO(("%s: found 4325 Dongle\n", __FUNCTION__));
  4493. break;
  4494. case BCM4329_D11N_ID: /* 4329 802.11n dualband device */
  4495. case BCM4329_D11N2G_ID: /* 4329 802.11n 2.4G device */
  4496. case BCM4329_D11N5G_ID: /* 4329 802.11n 5G device */
  4497. case 0x4329:
  4498. DHD_INFO(("%s: found 4329 Dongle\n", __FUNCTION__));
  4499. break;
  4500. case BCM4315_D11DUAL_ID: /* 4315 802.11a/g id */
  4501. case BCM4315_D11G_ID: /* 4315 802.11g id */
  4502. case BCM4315_D11A_ID: /* 4315 802.11a id */
  4503. DHD_INFO(("%s: found 4315 Dongle\n", __FUNCTION__));
  4504. break;
  4505. case BCM4319_D11N_ID: /* 4319 802.11n id */
  4506. case BCM4319_D11N2G_ID: /* 4319 802.11n2g id */
  4507. case BCM4319_D11N5G_ID: /* 4319 802.11n5g id */
  4508. DHD_INFO(("%s: found 4319 Dongle\n", __FUNCTION__));
  4509. break;
  4510. case 0:
  4511. DHD_INFO(("%s: allow device id 0, will check chip internals\n",
  4512. __FUNCTION__));
  4513. break;
  4514. default:
  4515. DHD_ERROR(("%s: skipping 0x%04x/0x%04x, not a dongle\n",
  4516. __FUNCTION__, venid, devid));
  4517. return NULL;
  4518. }
  4519. if (osh == NULL) {
  4520. /* Ask the OS interface part for an OSL handle */
  4521. if (!(osh = dhd_osl_attach(sdh, DHD_BUS))) {
  4522. DHD_ERROR(("%s: osl_attach failed!\n", __FUNCTION__));
  4523. return NULL;
  4524. }
  4525. }
  4526. /* Allocate private bus interface state */
  4527. if (!(bus = MALLOC(osh, sizeof(dhd_bus_t)))) {
  4528. DHD_ERROR(("%s: MALLOC of dhd_bus_t failed\n", __FUNCTION__));
  4529. goto fail;
  4530. }
  4531. bzero(bus, sizeof(dhd_bus_t));
  4532. bus->sdh = sdh;
  4533. bus->cl_devid = (uint16)devid;
  4534. bus->bus = DHD_BUS;
  4535. bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1;
  4536. bus->usebufpool = FALSE; /* Use bufpool if allocated, else use locally malloced rxbuf */
  4537. /* attach the common module */
  4538. if (!(cmn = dhd_common_init(bus->cl_devid, osh))) {
  4539. DHD_ERROR(("%s: dhd_common_init failed\n", __FUNCTION__));
  4540. goto fail;
  4541. }
  4542. /* attempt to attach to the dongle */
  4543. if (!(dhdsdio_probe_attach(bus, osh, sdh, regsva, devid))) {
  4544. DHD_ERROR(("%s: dhdsdio_probe_attach failed\n", __FUNCTION__));
  4545. dhd_common_deinit(NULL, cmn);
  4546. goto fail;
  4547. }
  4548. /* Attach to the dhd/OS/network interface */
  4549. if (!(bus->dhd = dhd_attach(osh, bus, SDPCM_RESERVE))) {
  4550. DHD_ERROR(("%s: dhd_attach failed\n", __FUNCTION__));
  4551. goto fail;
  4552. }
  4553. bus->dhd->cmn = cmn;
  4554. cmn->dhd = bus->dhd;
  4555. /* Allocate buffers */
  4556. if (!(dhdsdio_probe_malloc(bus, osh, sdh))) {
  4557. DHD_ERROR(("%s: dhdsdio_probe_malloc failed\n", __FUNCTION__));
  4558. goto fail;
  4559. }
  4560. if (!(dhdsdio_probe_init(bus, osh, sdh))) {
  4561. DHD_ERROR(("%s: dhdsdio_probe_init failed\n", __FUNCTION__));
  4562. goto fail;
  4563. }
  4564. if (bus->intr) {
  4565. /* Register interrupt callback, but mask it (not operational yet). */
  4566. DHD_INTR(("%s: disable SDIO interrupts (not interested yet)\n", __FUNCTION__));
  4567. bcmsdh_intr_disable(sdh);
  4568. if ((ret = bcmsdh_intr_reg(sdh, dhdsdio_isr, bus)) != 0) {
  4569. DHD_ERROR(("%s: FAILED: bcmsdh_intr_reg returned %d\n",
  4570. __FUNCTION__, ret));
  4571. goto fail;
  4572. }
  4573. DHD_INTR(("%s: registered SDIO interrupt function ok\n", __FUNCTION__));
  4574. } else {
  4575. DHD_INFO(("%s: SDIO interrupt function is NOT registered due to polling mode\n",
  4576. __FUNCTION__));
  4577. }
  4578. DHD_INFO(("%s: completed!!\n", __FUNCTION__));
  4579. #ifdef GET_CUSTOM_MAC_ENABLE
  4580. /* Read MAC address from external customer place */
  4581. memset(&ea_addr, 0, sizeof(ea_addr));
  4582. ret = dhd_custom_get_mac_address(ea_addr.octet);
  4583. if (!ret) {
  4584. memcpy(bus->dhd->mac.octet, (void *)&ea_addr, ETHER_ADDR_LEN);
  4585. }
  4586. #endif /* GET_CUSTOM_MAC_ENABLE */
  4587. /* if firmware path present try to download and bring up bus */
  4588. if (dhd_download_fw_on_driverload && (ret = dhd_bus_start(bus->dhd)) != 0) {
  4589. DHD_ERROR(("%s: dhd_bus_start failed\n", __FUNCTION__));
  4590. if (ret == BCME_NOTUP)
  4591. goto fail;
  4592. }
  4593. /* Ok, have the per-port tell the stack we're open for business */
  4594. if (dhd_net_attach(bus->dhd, 0) != 0) {
  4595. DHD_ERROR(("%s: Net attach failed!!\n", __FUNCTION__));
  4596. goto fail;
  4597. }
  4598. #ifdef PROP_TXSTATUS
  4599. if (dhd_download_fw_on_driverload)
  4600. dhd_wl_ioctl_cmd(bus->dhd, WLC_UP, (char *)&up, sizeof(up), TRUE, 0);
  4601. #endif
  4602. return bus;
  4603. fail:
  4604. dhdsdio_release(bus, osh);
  4605. return NULL;
  4606. }
  4607. static bool
  4608. dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva,
  4609. uint16 devid)
  4610. {
  4611. int err = 0;
  4612. uint8 clkctl = 0;
  4613. bus->alp_only = TRUE;
  4614. /* Return the window to backplane enumeration space for core access */
  4615. if (dhdsdio_set_siaddr_window(bus, SI_ENUM_BASE)) {
  4616. DHD_ERROR(("%s: FAILED to return to SI_ENUM_BASE\n", __FUNCTION__));
  4617. }
  4618. #ifdef DHD_DEBUG
  4619. DHD_ERROR(("F1 signature read @0x18000000=0x%4x\n",
  4620. bcmsdh_reg_read(bus->sdh, SI_ENUM_BASE, 4)));
  4621. #endif /* DHD_DEBUG */
  4622. /* Force PLL off until si_attach() programs PLL control regs */
  4623. bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, DHD_INIT_CLKCTL1, &err);
  4624. if (!err)
  4625. clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
  4626. if (err || ((clkctl & ~SBSDIO_AVBITS) != DHD_INIT_CLKCTL1)) {
  4627. DHD_ERROR(("dhdsdio_probe: ChipClkCSR access: err %d wrote 0x%02x read 0x%02x\n",
  4628. err, DHD_INIT_CLKCTL1, clkctl));
  4629. goto fail;
  4630. }
  4631. #ifdef DHD_DEBUG
  4632. if (DHD_INFO_ON()) {
  4633. uint fn, numfn;
  4634. uint8 *cis[SDIOD_MAX_IOFUNCS];
  4635. int err = 0;
  4636. numfn = bcmsdh_query_iofnum(sdh);
  4637. ASSERT(numfn <= SDIOD_MAX_IOFUNCS);
  4638. /* Make sure ALP is available before trying to read CIS */
  4639. SPINWAIT(((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
  4640. SBSDIO_FUNC1_CHIPCLKCSR, NULL)),
  4641. !SBSDIO_ALPAV(clkctl)), PMU_MAX_TRANSITION_DLY);
  4642. /* Now request ALP be put on the bus */
  4643. bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
  4644. DHD_INIT_CLKCTL2, &err);
  4645. OSL_DELAY(65);
  4646. for (fn = 0; fn <= numfn; fn++) {
  4647. if (!(cis[fn] = MALLOC(osh, SBSDIO_CIS_SIZE_LIMIT))) {
  4648. DHD_INFO(("dhdsdio_probe: fn %d cis malloc failed\n", fn));
  4649. break;
  4650. }
  4651. bzero(cis[fn], SBSDIO_CIS_SIZE_LIMIT);
  4652. if ((err = bcmsdh_cis_read(sdh, fn, cis[fn], SBSDIO_CIS_SIZE_LIMIT))) {
  4653. DHD_INFO(("dhdsdio_probe: fn %d cis read err %d\n", fn, err));
  4654. MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT);
  4655. break;
  4656. }
  4657. dhd_dump_cis(fn, cis[fn]);
  4658. }
  4659. while (fn-- > 0) {
  4660. ASSERT(cis[fn]);
  4661. MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT);
  4662. }
  4663. if (err) {
  4664. DHD_ERROR(("dhdsdio_probe: failure reading or parsing CIS\n"));
  4665. goto fail;
  4666. }
  4667. }
  4668. #endif /* DHD_DEBUG */
  4669. /* si_attach() will provide an SI handle and scan the backplane */
  4670. if (!(bus->sih = si_attach((uint)devid, osh, regsva, DHD_BUS, sdh,
  4671. &bus->vars, &bus->varsz))) {
  4672. DHD_ERROR(("%s: si_attach failed!\n", __FUNCTION__));
  4673. goto fail;
  4674. }
  4675. bcmsdh_chipinfo(sdh, bus->sih->chip, bus->sih->chiprev);
  4676. if (!dhdsdio_chipmatch((uint16)bus->sih->chip)) {
  4677. DHD_ERROR(("%s: unsupported chip: 0x%04x\n",
  4678. __FUNCTION__, bus->sih->chip));
  4679. goto fail;
  4680. }
  4681. si_sdiod_drive_strength_init(bus->sih, osh, dhd_sdiod_drive_strength);
  4682. /* Get info on the ARM and SOCRAM cores... */
  4683. if (!DHD_NOPMU(bus)) {
  4684. if ((si_setcore(bus->sih, ARM7S_CORE_ID, 0)) ||
  4685. (si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) {
  4686. bus->armrev = si_corerev(bus->sih);
  4687. } else {
  4688. DHD_ERROR(("%s: failed to find ARM core!\n", __FUNCTION__));
  4689. goto fail;
  4690. }
  4691. if (!(bus->orig_ramsize = si_socram_size(bus->sih))) {
  4692. DHD_ERROR(("%s: failed to find SOCRAM memory!\n", __FUNCTION__));
  4693. goto fail;
  4694. }
  4695. bus->ramsize = bus->orig_ramsize;
  4696. if (dhd_dongle_memsize)
  4697. dhd_dongle_setmemsize(bus, dhd_dongle_memsize);
  4698. DHD_ERROR(("DHD: dongle ram size is set to %d(orig %d)\n",
  4699. bus->ramsize, bus->orig_ramsize));
  4700. }
  4701. /* ...but normally deal with the SDPCMDEV core */
  4702. if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0)) &&
  4703. !(bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0))) {
  4704. DHD_ERROR(("%s: failed to find SDIODEV core!\n", __FUNCTION__));
  4705. goto fail;
  4706. }
  4707. bus->sdpcmrev = si_corerev(bus->sih);
  4708. /* Set core control so an SDIO reset does a backplane reset */
  4709. OR_REG(osh, &bus->regs->corecontrol, CC_BPRESEN);
  4710. bus->rxint_mode = SDIO_DEVICE_HMB_RXINT;
  4711. if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev >= 4) &&
  4712. (bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_1))
  4713. {
  4714. uint32 val;
  4715. val = R_REG(osh, &bus->regs->corecontrol);
  4716. val &= ~CC_XMTDATAAVAIL_MODE;
  4717. val |= CC_XMTDATAAVAIL_CTRL;
  4718. W_REG(osh, &bus->regs->corecontrol, val);
  4719. }
  4720. pktq_init(&bus->txq, (PRIOMASK + 1), QLEN);
  4721. /* Locate an appropriately-aligned portion of hdrbuf */
  4722. bus->rxhdr = (uint8 *)ROUNDUP((uintptr)&bus->hdrbuf[0], DHD_SDALIGN);
  4723. /* Set the poll and/or interrupt flags */
  4724. bus->intr = (bool)dhd_intr;
  4725. if ((bus->poll = (bool)dhd_poll))
  4726. bus->pollrate = 1;
  4727. return TRUE;
  4728. fail:
  4729. if (bus->sih != NULL) {
  4730. si_detach(bus->sih);
  4731. bus->sih = NULL;
  4732. }
  4733. return FALSE;
  4734. }
  4735. static bool
  4736. dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh)
  4737. {
  4738. DHD_TRACE(("%s: Enter\n", __FUNCTION__));
  4739. if (bus->dhd->maxctl) {
  4740. bus->rxblen = ROUNDUP((bus->dhd->maxctl + SDPCM_HDRLEN), ALIGNMENT) + DHD_SDALIGN;
  4741. if (!(bus->rxbuf = DHD_OS_PREALLOC(osh, DHD_PREALLOC_RXBUF, bus->rxblen))) {
  4742. DHD_ERROR(("%s: MALLOC of %d-byte rxbuf failed\n",
  4743. __FUNCTION__, bus->rxblen));
  4744. goto fail;
  4745. }
  4746. }
  4747. /* Allocate buffer to receive glomed packet */
  4748. if (!(bus->databuf = DHD_OS_PREALLOC(osh, DHD_PREALLOC_DATABUF, MAX_DATA_BUF))) {
  4749. DHD_ERROR(("%s: MALLOC of %d-byte databuf failed\n",
  4750. __FUNCTION__, MAX_DATA_BUF));
  4751. /* release rxbuf which was already located as above */
  4752. if (!bus->rxblen)
  4753. DHD_OS_PREFREE(osh, bus->rxbuf, bus->rxblen);
  4754. goto fail;
  4755. }
  4756. /* Align the buffer */
  4757. if ((uintptr)bus->databuf % DHD_SDALIGN)
  4758. bus->dataptr = bus->databuf + (DHD_SDALIGN - ((uintptr)bus->databuf % DHD_SDALIGN));
  4759. else
  4760. bus->dataptr = bus->databuf;
  4761. return TRUE;
  4762. fail:
  4763. return FALSE;
  4764. }
  4765. static bool
  4766. dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh)
  4767. {
  4768. int32 fnum;
  4769. DHD_TRACE(("%s: Enter\n", __FUNCTION__));
  4770. #ifdef SDTEST
  4771. dhdsdio_pktgen_init(bus);
  4772. #endif /* SDTEST */
  4773. /* Disable F2 to clear any intermediate frame state on the dongle */
  4774. bcmsdh_cfg_write(sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL);
  4775. bus->dhd->busstate = DHD_BUS_DOWN;
  4776. bus->sleeping = FALSE;
  4777. bus->rxflow = FALSE;
  4778. bus->prev_rxlim_hit = 0;
  4779. /* Done with backplane-dependent accesses, can drop clock... */
  4780. bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
  4781. /* ...and initialize clock/power states */
  4782. bus->clkstate = CLK_SDONLY;
  4783. bus->idletime = (int32)dhd_idletime;
  4784. bus->idleclock = DHD_IDLE_ACTIVE;
  4785. /* Query the SD clock speed */
  4786. if (bcmsdh_iovar_op(sdh, "sd_divisor", NULL, 0,
  4787. &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) {
  4788. DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_divisor"));
  4789. bus->sd_divisor = -1;
  4790. } else {
  4791. DHD_INFO(("%s: Initial value for %s is %d\n",
  4792. __FUNCTION__, "sd_divisor", bus->sd_divisor));
  4793. }
  4794. /* Query the SD bus mode */
  4795. if (bcmsdh_iovar_op(sdh, "sd_mode", NULL, 0,
  4796. &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) {
  4797. DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_mode"));
  4798. bus->sd_mode = -1;
  4799. } else {
  4800. DHD_INFO(("%s: Initial value for %s is %d\n",
  4801. __FUNCTION__, "sd_mode", bus->sd_mode));
  4802. }
  4803. /* Query the F2 block size, set roundup accordingly */
  4804. fnum = 2;
  4805. if (bcmsdh_iovar_op(sdh, "sd_blocksize", &fnum, sizeof(int32),
  4806. &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) {
  4807. bus->blocksize = 0;
  4808. DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize"));
  4809. } else {
  4810. DHD_INFO(("%s: Initial value for %s is %d\n",
  4811. __FUNCTION__, "sd_blocksize", bus->blocksize));
  4812. }
  4813. bus->roundup = MIN(max_roundup, bus->blocksize);
  4814. /* Query if bus module supports packet chaining, default to use if supported */
  4815. if (bcmsdh_iovar_op(sdh, "sd_rxchain", NULL, 0,
  4816. &bus->sd_rxchain, sizeof(int32), FALSE) != BCME_OK) {
  4817. bus->sd_rxchain = FALSE;
  4818. } else {
  4819. DHD_INFO(("%s: bus module (through bcmsdh API) %s chaining\n",
  4820. __FUNCTION__, (bus->sd_rxchain ? "supports" : "does not support")));
  4821. }
  4822. bus->use_rxchain = (bool)bus->sd_rxchain;
  4823. return TRUE;
  4824. }
  4825. bool
  4826. dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh,
  4827. char *pfw_path, char *pnv_path)
  4828. {
  4829. bool ret;
  4830. bus->fw_path = pfw_path;
  4831. bus->nv_path = pnv_path;
  4832. ret = dhdsdio_download_firmware(bus, osh, bus->sdh);
  4833. return ret;
  4834. }
  4835. static bool
  4836. dhdsdio_download_firmware(struct dhd_bus *bus, osl_t *osh, void *sdh)
  4837. {
  4838. bool ret;
  4839. /* Download the firmware */
  4840. DHD_OS_WAKE_LOCK(bus->dhd);
  4841. dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
  4842. ret = _dhdsdio_download_firmware(bus) == 0;
  4843. dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
  4844. DHD_OS_WAKE_UNLOCK(bus->dhd);
  4845. return ret;
  4846. }
  4847. /* Detach and free everything */
  4848. static void
  4849. dhdsdio_release(dhd_bus_t *bus, osl_t *osh)
  4850. {
  4851. bool dongle_isolation = FALSE;
  4852. DHD_TRACE(("%s: Enter\n", __FUNCTION__));
  4853. if (bus) {
  4854. ASSERT(osh);
  4855. /* De-register interrupt handler */
  4856. bcmsdh_intr_disable(bus->sdh);
  4857. bcmsdh_intr_dereg(bus->sdh);
  4858. if (bus->dhd) {
  4859. dhd_common_deinit(bus->dhd, NULL);
  4860. dongle_isolation = bus->dhd->dongle_isolation;
  4861. dhd_detach(bus->dhd);
  4862. dhdsdio_release_dongle(bus, osh, dongle_isolation, TRUE);
  4863. dhd_free(bus->dhd);
  4864. bus->dhd = NULL;
  4865. }
  4866. dhdsdio_release_malloc(bus, osh);
  4867. #ifdef DHD_DEBUG
  4868. if (bus->console.buf != NULL)
  4869. MFREE(osh, bus->console.buf, bus->console.bufsize);
  4870. #endif
  4871. MFREE(osh, bus, sizeof(dhd_bus_t));
  4872. }
  4873. if (osh)
  4874. dhd_osl_detach(osh);
  4875. DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
  4876. }
  4877. static void
  4878. dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh)
  4879. {
  4880. DHD_TRACE(("%s: Enter\n", __FUNCTION__));
  4881. if (bus->dhd && bus->dhd->dongle_reset)
  4882. return;
  4883. if (bus->rxbuf) {
  4884. #ifndef CONFIG_DHD_USE_STATIC_BUF
  4885. MFREE(osh, bus->rxbuf, bus->rxblen);
  4886. #endif
  4887. bus->rxctl = bus->rxbuf = NULL;
  4888. bus->rxlen = 0;
  4889. }
  4890. if (bus->databuf) {
  4891. #ifndef CONFIG_DHD_USE_STATIC_BUF
  4892. MFREE(osh, bus->databuf, MAX_DATA_BUF);
  4893. #endif
  4894. bus->databuf = NULL;
  4895. }
  4896. if (bus->vars && bus->varsz) {
  4897. MFREE(osh, bus->vars, bus->varsz);
  4898. bus->vars = NULL;
  4899. }
  4900. }
  4901. static void
  4902. dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation, bool reset_flag)
  4903. {
  4904. DHD_TRACE(("%s: Enter bus->dhd %p bus->dhd->dongle_reset %d \n", __FUNCTION__,
  4905. bus->dhd, bus->dhd->dongle_reset));
  4906. if ((bus->dhd && bus->dhd->dongle_reset) && reset_flag)
  4907. return;
  4908. if (bus->sih) {
  4909. if (bus->dhd) {
  4910. dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
  4911. }
  4912. #if !defined(BCMLXSDMMC)
  4913. if (dongle_isolation == FALSE)
  4914. si_watchdog(bus->sih, 4);
  4915. #endif /* !defined(BCMLXSDMMC) */
  4916. if (bus->dhd) {
  4917. dhdsdio_clkctl(bus, CLK_NONE, FALSE);
  4918. }
  4919. si_detach(bus->sih);
  4920. bus->sih = NULL;
  4921. if (bus->vars && bus->varsz)
  4922. MFREE(osh, bus->vars, bus->varsz);
  4923. bus->vars = NULL;
  4924. }
  4925. DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
  4926. }
  4927. static void
  4928. dhdsdio_disconnect(void *ptr)
  4929. {
  4930. dhd_bus_t *bus = (dhd_bus_t *)ptr;
  4931. DHD_TRACE(("%s: Enter\n", __FUNCTION__));
  4932. if (bus) {
  4933. ASSERT(bus->dhd);
  4934. dhdsdio_release(bus, bus->dhd->osh);
  4935. }
  4936. DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
  4937. }
  4938. /* Register/Unregister functions are called by the main DHD entry
  4939. * point (e.g. module insertion) to link with the bus driver, in
  4940. * order to look for or await the device.
  4941. */
  4942. static bcmsdh_driver_t dhd_sdio = {
  4943. dhdsdio_probe,
  4944. dhdsdio_disconnect
  4945. };
  4946. int
  4947. dhd_bus_register(void)
  4948. {
  4949. DHD_TRACE(("%s: Enter\n", __FUNCTION__));
  4950. return bcmsdh_register(&dhd_sdio);
  4951. }
  4952. void
  4953. dhd_bus_unregister(void)
  4954. {
  4955. DHD_TRACE(("%s: Enter\n", __FUNCTION__));
  4956. bcmsdh_unregister();
  4957. }
  4958. #ifdef BCMEMBEDIMAGE
  4959. static int
  4960. dhdsdio_download_code_array(struct dhd_bus *bus)
  4961. {
  4962. int bcmerror = -1;
  4963. int offset = 0;
  4964. unsigned char *ularray = NULL;
  4965. DHD_INFO(("%s: download embedded firmware...\n", __FUNCTION__));
  4966. /* Download image */
  4967. while ((offset + MEMBLOCK) < sizeof(dlarray)) {
  4968. bcmerror = dhdsdio_membytes(bus, TRUE, offset,
  4969. (uint8 *) (dlarray + offset), MEMBLOCK);
  4970. if (bcmerror) {
  4971. DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
  4972. __FUNCTION__, bcmerror, MEMBLOCK, offset));
  4973. goto err;
  4974. }
  4975. offset += MEMBLOCK;
  4976. }
  4977. if (offset < sizeof(dlarray)) {
  4978. bcmerror = dhdsdio_membytes(bus, TRUE, offset,
  4979. (uint8 *) (dlarray + offset), sizeof(dlarray) - offset);
  4980. if (bcmerror) {
  4981. DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
  4982. __FUNCTION__, bcmerror, sizeof(dlarray) - offset, offset));
  4983. goto err;
  4984. }
  4985. }
  4986. #ifdef DHD_DEBUG
  4987. /* Upload and compare the downloaded code */
  4988. {
  4989. ularray = MALLOC(bus->dhd->osh, bus->ramsize);
  4990. /* Upload image to verify downloaded contents. */
  4991. offset = 0;
  4992. memset(ularray, 0xaa, bus->ramsize);
  4993. while ((offset + MEMBLOCK) < sizeof(dlarray)) {
  4994. bcmerror = dhdsdio_membytes(bus, FALSE, offset, ularray + offset, MEMBLOCK);
  4995. if (bcmerror) {
  4996. DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n",
  4997. __FUNCTION__, bcmerror, MEMBLOCK, offset));
  4998. goto err;
  4999. }
  5000. offset += MEMBLOCK;
  5001. }
  5002. if (offset < sizeof(dlarray)) {
  5003. bcmerror = dhdsdio_membytes(bus, FALSE, offset,
  5004. ularray + offset, sizeof(dlarray) - offset);
  5005. if (bcmerror) {
  5006. DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n",
  5007. __FUNCTION__, bcmerror, sizeof(dlarray) - offset, offset));
  5008. goto err;
  5009. }
  5010. }
  5011. if (memcmp(dlarray, ularray, sizeof(dlarray))) {
  5012. DHD_ERROR(("%s: Downloaded image is corrupted (%s, %s, %s).\n",
  5013. __FUNCTION__, dlimagename, dlimagever, dlimagedate));
  5014. goto err;
  5015. } else
  5016. DHD_ERROR(("%s: Download, Upload and compare succeeded (%s, %s, %s).\n",
  5017. __FUNCTION__, dlimagename, dlimagever, dlimagedate));
  5018. }
  5019. #endif /* DHD_DEBUG */
  5020. err:
  5021. if (ularray)
  5022. MFREE(bus->dhd->osh, ularray, bus->ramsize);
  5023. return bcmerror;
  5024. }
  5025. #endif /* BCMEMBEDIMAGE */
  5026. static int
  5027. dhdsdio_download_code_file(struct dhd_bus *bus, char *pfw_path)
  5028. {
  5029. int bcmerror = -1;
  5030. int offset = 0;
  5031. uint len;
  5032. void *image = NULL;
  5033. uint8 *memblock = NULL, *memptr;
  5034. DHD_INFO(("%s: download firmware %s\n", __FUNCTION__, pfw_path));
  5035. image = dhd_os_open_image(pfw_path);
  5036. if (image == NULL)
  5037. goto err;
  5038. memptr = memblock = MALLOC(bus->dhd->osh, MEMBLOCK + DHD_SDALIGN);
  5039. if (memblock == NULL) {
  5040. DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, MEMBLOCK));
  5041. goto err;
  5042. }
  5043. if ((uint32)(uintptr)memblock % DHD_SDALIGN)
  5044. memptr += (DHD_SDALIGN - ((uint32)(uintptr)memblock % DHD_SDALIGN));
  5045. /* Download image */
  5046. while ((len = dhd_os_get_image_block((char*)memptr, MEMBLOCK, image))) {
  5047. bcmerror = dhdsdio_membytes(bus, TRUE, offset, memptr, len);
  5048. if (bcmerror) {
  5049. DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
  5050. __FUNCTION__, bcmerror, MEMBLOCK, offset));
  5051. goto err;
  5052. }
  5053. offset += MEMBLOCK;
  5054. }
  5055. err:
  5056. if (memblock)
  5057. MFREE(bus->dhd->osh, memblock, MEMBLOCK + DHD_SDALIGN);
  5058. if (image)
  5059. dhd_os_close_image(image);
  5060. return bcmerror;
  5061. }
  5062. /*
  5063. EXAMPLE: nvram_array
  5064. nvram_arry format:
  5065. name=value
  5066. Use carriage return at the end of each assignment, and an empty string with
  5067. carriage return at the end of array.
  5068. For example:
  5069. unsigned char nvram_array[] = {"name1=value1\n", "name2=value2\n", "\n"};
  5070. Hex values start with 0x, and mac addr format: xx:xx:xx:xx:xx:xx.
  5071. Search "EXAMPLE: nvram_array" to see how the array is activated.
  5072. */
  5073. void
  5074. dhd_bus_set_nvram_params(struct dhd_bus * bus, const char *nvram_params)
  5075. {
  5076. bus->nvram_params = nvram_params;
  5077. }
  5078. static int
  5079. dhdsdio_download_nvram(struct dhd_bus *bus)
  5080. {
  5081. int bcmerror = -1;
  5082. uint len;
  5083. void * image = NULL;
  5084. char * memblock = NULL;
  5085. char *bufp;
  5086. char *pnv_path;
  5087. bool nvram_file_exists;
  5088. pnv_path = bus->nv_path;
  5089. nvram_file_exists = ((pnv_path != NULL) && (pnv_path[0] != '\0'));
  5090. if (!nvram_file_exists && (bus->nvram_params == NULL))
  5091. return (0);
  5092. if (nvram_file_exists) {
  5093. image = dhd_os_open_image(pnv_path);
  5094. if (image == NULL)
  5095. goto err;
  5096. }
  5097. memblock = MALLOC(bus->dhd->osh, MAX_NVRAMBUF_SIZE);
  5098. if (memblock == NULL) {
  5099. DHD_ERROR(("%s: Failed to allocate memory %d bytes\n",
  5100. __FUNCTION__, MAX_NVRAMBUF_SIZE));
  5101. goto err;
  5102. }
  5103. /* Download variables */
  5104. if (nvram_file_exists) {
  5105. len = dhd_os_get_image_block(memblock, MAX_NVRAMBUF_SIZE, image);
  5106. }
  5107. else {
  5108. len = strlen(bus->nvram_params);
  5109. ASSERT(len <= MAX_NVRAMBUF_SIZE);
  5110. memcpy(memblock, bus->nvram_params, len);
  5111. }
  5112. if (len > 0 && len < MAX_NVRAMBUF_SIZE) {
  5113. bufp = (char *)memblock;
  5114. bufp[len] = 0;
  5115. len = process_nvram_vars(bufp, len);
  5116. if (len % 4) {
  5117. len += 4 - (len % 4);
  5118. }
  5119. bufp += len;
  5120. *bufp++ = 0;
  5121. if (len)
  5122. bcmerror = dhdsdio_downloadvars(bus, memblock, len + 1);
  5123. if (bcmerror) {
  5124. DHD_ERROR(("%s: error downloading vars: %d\n",
  5125. __FUNCTION__, bcmerror));
  5126. }
  5127. }
  5128. else {
  5129. DHD_ERROR(("%s: error reading nvram file: %d\n",
  5130. __FUNCTION__, len));
  5131. bcmerror = BCME_SDIO_ERROR;
  5132. }
  5133. err:
  5134. if (memblock)
  5135. MFREE(bus->dhd->osh, memblock, MAX_NVRAMBUF_SIZE);
  5136. if (image)
  5137. dhd_os_close_image(image);
  5138. return bcmerror;
  5139. }
  5140. static int
  5141. _dhdsdio_download_firmware(struct dhd_bus *bus)
  5142. {
  5143. int bcmerror = -1;
  5144. char *p;
  5145. bool embed = FALSE; /* download embedded firmware */
  5146. bool dlok = FALSE; /* download firmware succeeded */
  5147. /* Out immediately if no image to download */
  5148. if ((bus->fw_path == NULL) || (bus->fw_path[0] == '\0')) {
  5149. #ifdef BCMEMBEDIMAGE
  5150. embed = TRUE;
  5151. #else
  5152. return 0;
  5153. #endif
  5154. }
  5155. /* Keep arm in reset */
  5156. if (dhdsdio_download_state(bus, TRUE)) {
  5157. DHD_ERROR(("%s: error placing ARM core in reset\n", __FUNCTION__));
  5158. goto err;
  5159. }
  5160. /* External image takes precedence if specified */
  5161. if ((bus->fw_path != NULL) && (bus->fw_path[0] != '\0')) {
  5162. /* replace bcm43xx with bcm4330 */
  5163. if ((p = strstr(bus->fw_path, "bcm43xx"))) {
  5164. if (bus->cl_devid == 0x4330) {
  5165. *(p + 5)='3';
  5166. *(p + 6)='0';
  5167. }
  5168. }
  5169. if(chip_is_b1){
  5170. strcpy(bus->fw_path, "/system/vendor/firmware/bcm4330/fw_bcmdhd_b1.bin");
  5171. }
  5172. printf("%s: fw_path = %s, nv_path=%s\n", __FUNCTION__, bus->fw_path, bus->nv_path);
  5173. if (dhdsdio_download_code_file(bus, bus->fw_path)) {
  5174. DHD_ERROR(("%s: dongle image file download failed\n", __FUNCTION__));
  5175. #ifdef BCMEMBEDIMAGE
  5176. embed = TRUE;
  5177. #else
  5178. goto err;
  5179. #endif
  5180. }
  5181. else {
  5182. embed = FALSE;
  5183. dlok = TRUE;
  5184. }
  5185. }
  5186. #ifdef BCMEMBEDIMAGE
  5187. if (embed) {
  5188. if (dhdsdio_download_code_array(bus)) {
  5189. DHD_ERROR(("%s: dongle image array download failed\n", __FUNCTION__));
  5190. goto err;
  5191. }
  5192. else {
  5193. dlok = TRUE;
  5194. }
  5195. }
  5196. #endif
  5197. if (!dlok) {
  5198. DHD_ERROR(("%s: dongle image download failed\n", __FUNCTION__));
  5199. goto err;
  5200. }
  5201. /* EXAMPLE: nvram_array */
  5202. /* If a valid nvram_arry is specified as above, it can be passed down to dongle */
  5203. /* dhd_bus_set_nvram_params(bus, (char *)&nvram_array); */
  5204. /* External nvram takes precedence if specified */
  5205. if (dhdsdio_download_nvram(bus)) {
  5206. DHD_ERROR(("%s: dongle nvram file download failed\n", __FUNCTION__));
  5207. goto err;
  5208. }
  5209. /* Take arm out of reset */
  5210. if (dhdsdio_download_state(bus, FALSE)) {
  5211. DHD_ERROR(("%s: error getting out of ARM core reset\n", __FUNCTION__));
  5212. goto err;
  5213. }
  5214. bcmerror = 0;
  5215. err:
  5216. return bcmerror;
  5217. }
  5218. static int
  5219. dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes,
  5220. void *pkt, bcmsdh_cmplt_fn_t complete, void *handle)
  5221. {
  5222. int status;
  5223. status = bcmsdh_recv_buf(bus->sdh, addr, fn, flags, buf, nbytes, pkt, complete, handle);
  5224. return status;
  5225. }
  5226. static int
  5227. dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes,
  5228. void *pkt, bcmsdh_cmplt_fn_t complete, void *handle)
  5229. {
  5230. return (bcmsdh_send_buf(bus->sdh, addr, fn, flags, buf, nbytes, pkt, complete, handle));
  5231. }
  5232. uint
  5233. dhd_bus_chip(struct dhd_bus *bus)
  5234. {
  5235. ASSERT(bus);
  5236. ASSERT(bus->sih != NULL);
  5237. return bus->sih->chip;
  5238. }
  5239. void *
  5240. dhd_bus_pub(struct dhd_bus *bus)
  5241. {
  5242. ASSERT(bus);
  5243. return bus->dhd;
  5244. }
  5245. void *
  5246. dhd_bus_txq(struct dhd_bus *bus)
  5247. {
  5248. return &bus->txq;
  5249. }
  5250. uint
  5251. dhd_bus_hdrlen(struct dhd_bus *bus)
  5252. {
  5253. return SDPCM_HDRLEN;
  5254. }
  5255. int
  5256. dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag)
  5257. {
  5258. int bcmerror = 0;
  5259. dhd_bus_t *bus;
  5260. bus = dhdp->bus;
  5261. if (flag == TRUE) {
  5262. if (!bus->dhd->dongle_reset) {
  5263. dhd_os_sdlock(dhdp);
  5264. dhd_os_wd_timer(dhdp, 0);
  5265. #if !defined(IGNORE_ETH0_DOWN)
  5266. /* Force flow control as protection when stop come before ifconfig_down */
  5267. dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON);
  5268. #endif /* !defined(IGNORE_ETH0_DOWN) */
  5269. #if !defined(OOB_INTR_ONLY)
  5270. /* to avoid supurious client interrupt during stop process */
  5271. bcmsdh_stop(bus->sdh);
  5272. #endif /* !defined(OOB_INTR_ONLY) */
  5273. /* Expect app to have torn down any connection before calling */
  5274. /* Stop the bus, disable F2 */
  5275. dhd_bus_stop(bus, FALSE);
  5276. #if defined(OOB_INTR_ONLY)
  5277. /* Clean up any pending IRQ */
  5278. bcmsdh_set_irq(FALSE);
  5279. #endif /* defined(OOB_INTR_ONLY) */
  5280. /* Clean tx/rx buffer pointers, detach from the dongle */
  5281. dhdsdio_release_dongle(bus, bus->dhd->osh, TRUE, TRUE);
  5282. bus->dhd->dongle_reset = TRUE;
  5283. bus->dhd->up = FALSE;
  5284. dhd_os_sdunlock(dhdp);
  5285. DHD_TRACE(("%s: WLAN OFF DONE\n", __FUNCTION__));
  5286. /* App can now remove power from device */
  5287. } else
  5288. bcmerror = BCME_SDIO_ERROR;
  5289. } else {
  5290. /* App must have restored power to device before calling */
  5291. DHD_TRACE(("\n\n%s: == WLAN ON ==\n", __FUNCTION__));
  5292. if (bus->dhd->dongle_reset) {
  5293. /* Turn on WLAN */
  5294. #ifdef DHDTHREAD
  5295. dhd_os_sdlock(dhdp);
  5296. #endif /* DHDTHREAD */
  5297. /* Reset SD client */
  5298. bcmsdh_reset(bus->sdh);
  5299. /* Attempt to re-attach & download */
  5300. if (dhdsdio_probe_attach(bus, bus->dhd->osh, bus->sdh,
  5301. (uint32 *)SI_ENUM_BASE,
  5302. bus->cl_devid)) {
  5303. /* Attempt to download binary to the dongle */
  5304. if (dhdsdio_probe_init(bus, bus->dhd->osh, bus->sdh) &&
  5305. dhdsdio_download_firmware(bus, bus->dhd->osh, bus->sdh)) {
  5306. /* Re-init bus, enable F2 transfer */
  5307. bcmerror = dhd_bus_init((dhd_pub_t *) bus->dhd, FALSE);
  5308. if (bcmerror == BCME_OK) {
  5309. #if defined(OOB_INTR_ONLY)
  5310. bcmsdh_set_irq(TRUE);
  5311. dhd_enable_oob_intr(bus, TRUE);
  5312. #endif /* defined(OOB_INTR_ONLY) */
  5313. bus->dhd->dongle_reset = FALSE;
  5314. bus->dhd->up = TRUE;
  5315. #if !defined(IGNORE_ETH0_DOWN)
  5316. /* Restore flow control */
  5317. dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF);
  5318. #endif
  5319. dhd_os_wd_timer(dhdp, dhd_watchdog_ms);
  5320. DHD_TRACE(("%s: WLAN ON DONE\n", __FUNCTION__));
  5321. } else {
  5322. dhd_bus_stop(bus, FALSE);
  5323. dhdsdio_release_dongle(bus, bus->dhd->osh,
  5324. TRUE, FALSE);
  5325. }
  5326. } else
  5327. bcmerror = BCME_SDIO_ERROR;
  5328. } else
  5329. bcmerror = BCME_SDIO_ERROR;
  5330. #ifdef DHDTHREAD
  5331. dhd_os_sdunlock(dhdp);
  5332. #endif /* DHDTHREAD */
  5333. } else {
  5334. bcmerror = BCME_SDIO_ERROR;
  5335. DHD_INFO(("%s called when dongle is not in reset\n",
  5336. __FUNCTION__));
  5337. DHD_INFO(("Will call dhd_bus_start instead\n"));
  5338. sdioh_start(NULL, 1);
  5339. if ((bcmerror = dhd_bus_start(dhdp)) != 0)
  5340. DHD_ERROR(("%s: dhd_bus_start fail with %d\n",
  5341. __FUNCTION__, bcmerror));
  5342. }
  5343. }
  5344. return bcmerror;
  5345. }
  5346. /* Get Chip ID version */
  5347. uint dhd_bus_chip_id(dhd_pub_t *dhdp)
  5348. {
  5349. dhd_bus_t *bus = dhdp->bus;
  5350. return bus->sih->chip;
  5351. }
  5352. int
  5353. dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint size)
  5354. {
  5355. dhd_bus_t *bus;
  5356. bus = dhdp->bus;
  5357. return dhdsdio_membytes(bus, set, address, data, size);
  5358. }