2 * DHD Bus Module for SDIO
4 * Copyright (C) 1999-2011, Broadcom Corporation
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:
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.
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.
24 * $Id: dhd_sdio.c,v 1.274.2.40 2011-02-09 22:42:44 Exp $
32 #include BCMEMBEDIMAGE
33 #endif /* BCMEMBEDIMAGE */
37 #include <bcmendian.h>
44 #if defined(DHD_DEBUG)
45 #include <hndrte_armtrap.h>
46 #include <hndrte_cons.h>
47 #endif /* defined(DHD_DEBUG) */
53 #include <sbsdpcmdev.h>
57 #include <proto/ethernet.h>
58 #include <proto/802.1d.h>
59 #include <proto/802.11.h>
61 #include <dngl_stats.h>
64 #include <dhd_proto.h>
69 #ifndef DHDSDIO_MEM_DUMP_FNAME
70 #define DHDSDIO_MEM_DUMP_FNAME "mem_dump"
73 #define QLEN 256 /* bulk rx and tx queue lengths */
74 #define FCHI (QLEN - 10)
75 #define FCLOW (FCHI / 2)
78 #define TXRETRIES 2 /* # of retries for tx frames */
80 #if defined(CONFIG_MACH_SANDGATE2G)
81 #define DHD_RXBOUND 250 /* Default for max rx frames in one scheduling */
83 #define DHD_RXBOUND 50 /* Default for max rx frames in one scheduling */
84 #endif /* defined(CONFIG_MACH_SANDGATE2G) */
86 #define DHD_TXBOUND 20 /* Default for max tx frames in one scheduling */
88 #define DHD_TXMINMAX 1 /* Max tx frames if rx still pending */
90 #define MEMBLOCK 2048 /* Block size used for downloading of dongle image */
91 #define MAX_NVRAMBUF_SIZE 4096 /* max nvram buf size */
92 #define MAX_DATA_BUF (32 * 1024) /* Must be large enough to hold biggest possible glom */
94 /* Packet alignment for most efficient SDIO (can change based on platform) */
96 #define DHD_SDALIGN 32
98 #if !ISPOWEROF2(DHD_SDALIGN)
99 #error DHD_SDALIGN is not a power of 2!
102 #ifndef DHD_FIRSTREAD
103 #define DHD_FIRSTREAD 32
105 #if !ISPOWEROF2(DHD_FIRSTREAD)
106 #error DHD_FIRSTREAD is not a power of 2!
109 /* Total length of frame header for dongle protocol */
110 #define SDPCM_HDRLEN (SDPCM_FRAMETAG_LEN + SDPCM_SWHEADER_LEN)
112 #define SDPCM_RESERVE (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN)
114 #define SDPCM_RESERVE (SDPCM_HDRLEN + DHD_SDALIGN)
117 /* Space for header read, limit for data packets */
119 #define MAX_HDR_READ 32
121 #if !ISPOWEROF2(MAX_HDR_READ)
122 #error MAX_HDR_READ is not a power of 2!
125 #define MAX_RX_DATASZ 2048
127 /* Maximum milliseconds to wait for F2 to come up */
128 #define DHD_WAIT_F2RDY 3000
130 /* Bump up limit on waiting for HT to account for first startup;
131 * if the image is doing a CRC calculation before programming the PMU
132 * for HT availability, it could take a couple hundred ms more, so
133 * max out at a 1 second (1000000us).
135 #if (PMU_MAX_TRANSITION_DLY <= 1000000)
136 #undef PMU_MAX_TRANSITION_DLY
137 #define PMU_MAX_TRANSITION_DLY 1000000
140 /* Value for ChipClockCSR during initial setup */
141 #define DHD_INIT_CLKCTL1 (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ)
142 #define DHD_INIT_CLKCTL2 (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP)
144 /* Flags for SDH calls */
145 #define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED)
147 /* Packet free applicable unconditionally for sdio and sdspi. Conditional if
148 * bufpool was present for gspi bus.
150 #define PKTFREE2() if ((bus->bus != SPI_BUS) || bus->usebufpool) \
151 PKTFREE(bus->dhd->osh, pkt, FALSE);
152 DHD_SPINWAIT_SLEEP_INIT(sdioh_spinwait_sleep);
153 #if defined(OOB_INTR_ONLY)
154 extern void bcmsdh_set_irq(int flag);
155 #endif /* defined(OOB_INTR_ONLY) */
157 extern void dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success);
161 /* Device console log buffer state */
162 typedef struct dhd_console {
163 uint count; /* Poll interval msec counter */
164 uint log_addr; /* Log struct address (fixed) */
165 hndrte_log_t log; /* Log struct (host copy) */
166 uint bufsize; /* Size of log buffer */
167 uint8 *buf; /* Log buffer (host copy) */
168 uint last; /* Last buffer read index */
170 #endif /* DHD_DEBUG */
172 /* Private data for SDIO bus interaction */
173 typedef struct dhd_bus {
176 bcmsdh_info_t *sdh; /* Handle for BCMSDH calls */
177 si_t *sih; /* Handle for SI calls */
178 char *vars; /* Variables (from CIS and/or other) */
179 uint varsz; /* Size of variables buffer */
180 uint32 sbaddr; /* Current SB window pointer (-1, invalid) */
182 sdpcmd_regs_t *regs; /* Registers for SDIO core */
183 uint sdpcmrev; /* SDIO core revision */
184 uint armrev; /* CPU core revision */
185 uint ramrev; /* SOCRAM core revision */
186 uint32 ramsize; /* Size of RAM in SOCRAM (bytes) */
187 uint32 orig_ramsize; /* Size of RAM in SOCRAM (bytes) */
189 uint32 bus; /* gSPI or SDIO bus */
190 uint32 hostintmask; /* Copy of Host Interrupt Mask */
191 uint32 intstatus; /* Intstatus bits (events) pending */
192 bool dpc_sched; /* Indicates DPC schedule (intrpt rcvd) */
193 bool fcstate; /* State of dongle flow-control */
195 uint16 cl_devid; /* cached devid for dhdsdio_probe_attach() */
196 char *fw_path; /* module_param: path to firmware image */
197 char *nv_path; /* module_param: path to nvram vars file */
198 const char *nvram_params; /* user specified nvram params. */
200 uint blocksize; /* Block size of SDIO transfers */
201 uint roundup; /* Max roundup limit */
203 struct pktq txq; /* Queue length used for flow-control */
204 uint8 flowcontrol; /* per prio flow control bitmask */
205 uint8 tx_seq; /* Transmit sequence number (next) */
206 uint8 tx_max; /* Maximum transmit sequence allowed */
208 uint8 hdrbuf[MAX_HDR_READ + DHD_SDALIGN];
209 uint8 *rxhdr; /* Header of current rx frame (in hdrbuf) */
210 uint16 nextlen; /* Next Read Len from last header */
211 uint8 rx_seq; /* Receive sequence number (expected) */
212 bool rxskip; /* Skip receive (awaiting NAK ACK) */
214 void *glomd; /* Packet containing glomming descriptor */
215 void *glom; /* Packet chain for glommed superframe */
216 uint glomerr; /* Glom packet read errors */
218 uint8 *rxbuf; /* Buffer for receiving control packets */
219 uint rxblen; /* Allocated length of rxbuf */
220 uint8 *rxctl; /* Aligned pointer into rxbuf */
221 uint8 *databuf; /* Buffer for receiving big glom packet */
222 uint8 *dataptr; /* Aligned pointer into databuf */
223 uint rxlen; /* Length of valid data in buffer */
225 uint8 sdpcm_ver; /* Bus protocol reported by dongle */
227 bool intr; /* Use interrupts */
228 bool poll; /* Use polling */
229 bool ipend; /* Device interrupt is pending */
230 bool intdis; /* Interrupts disabled by isr */
231 uint intrcount; /* Count of device interrupt callbacks */
232 uint lastintrs; /* Count as of last watchdog timer */
233 uint spurious; /* Count of spurious interrupts */
234 uint pollrate; /* Ticks between device polls */
235 uint polltick; /* Tick counter */
236 uint pollcnt; /* Count of active polls */
239 dhd_console_t console; /* Console output polling support */
240 uint console_addr; /* Console address from shared struct */
241 #endif /* DHD_DEBUG */
243 uint regfails; /* Count of R_REG/W_REG failures */
245 uint clkstate; /* State of sd and backplane clock(s) */
246 bool activity; /* Activity flag for clock down */
247 int32 idletime; /* Control for activity timeout */
248 int32 idlecount; /* Activity timeout counter */
249 int32 idleclock; /* How to set bus driver when idle */
250 int32 sd_divisor; /* Speed control to bus driver */
251 int32 sd_mode; /* Mode control to bus driver */
252 int32 sd_rxchain; /* If bcmsdh api accepts PKT chains */
253 bool use_rxchain; /* If dhd should use PKT chains */
254 bool sleeping; /* Is SDIO bus sleeping? */
255 bool rxflow_mode; /* Rx flow control mode */
256 bool rxflow; /* Is rx flow control on */
257 uint prev_rxlim_hit; /* Is prev rx limit exceeded (per dpc schedule) */
258 bool alp_only; /* Don't use HT clock (ALP only) */
259 /* Field to decide if rx of control frames happen in rxbuf or lb-pool */
263 /* external loopback */
267 /* pktgen configuration */
268 uint pktgen_freq; /* Ticks between bursts */
269 uint pktgen_count; /* Packets to send each burst */
270 uint pktgen_print; /* Bursts between count displays */
271 uint pktgen_total; /* Stop after this many */
272 uint pktgen_minlen; /* Minimum packet data len */
273 uint pktgen_maxlen; /* Maximum packet data len */
274 uint pktgen_mode; /* Configured mode: tx, rx, or echo */
275 uint pktgen_stop; /* Number of tx failures causing stop */
277 /* active pktgen fields */
278 uint pktgen_tick; /* Tick counter for bursts */
279 uint pktgen_ptick; /* Burst counter for printing */
280 uint pktgen_sent; /* Number of test packets generated */
281 uint pktgen_rcvd; /* Number of test packets received */
282 uint pktgen_fail; /* Number of failed send attempts */
283 uint16 pktgen_len; /* Length of next packet to send */
284 #define PKTGEN_RCV_IDLE (0)
285 #define PKTGEN_RCV_ONGOING (1)
286 uint16 pktgen_rcv_state; /* receive state */
287 uint pktgen_rcvd_rcvsession; /* test pkts rcvd per rcv session. */
290 /* Some additional counters */
291 uint tx_sderrs; /* Count of tx attempts with sd errors */
292 uint fcqueued; /* Tx packets that got queued */
293 uint rxrtx; /* Count of rtx requests (NAK to dongle) */
294 uint rx_toolong; /* Receive frames too long to receive */
295 uint rxc_errors; /* SDIO errors when reading control frames */
296 uint rx_hdrfail; /* SDIO errors on header reads */
297 uint rx_badhdr; /* Bad received headers (roosync?) */
298 uint rx_badseq; /* Mismatched rx sequence number */
299 uint fc_rcvd; /* Number of flow-control events received */
300 uint fc_xoff; /* Number which turned on flow-control */
301 uint fc_xon; /* Number which turned off flow-control */
302 uint rxglomfail; /* Failed deglom attempts */
303 uint rxglomframes; /* Number of glom frames (superframes) */
304 uint rxglompkts; /* Number of packets from glom frames */
305 uint f2rxhdrs; /* Number of header reads */
306 uint f2rxdata; /* Number of frame data reads */
307 uint f2txdata; /* Number of f2 frame writes */
308 uint f1regdata; /* Number of f1 register accesses */
310 uint8 *ctrl_frame_buf;
311 uint32 ctrl_frame_len;
312 bool ctrl_frame_stat;
313 uint32 rxint_mode; /* rx interrupt mode */
319 #define CLK_PENDING 2 /* Not used yet */
322 #define DHD_NOPMU(dhd) (FALSE)
325 static int qcount[NUMPRIO];
326 static int tx_packets[NUMPRIO];
327 #endif /* DHD_DEBUG */
329 /* Deferred transmit */
330 const uint dhd_deferred_tx = 1;
332 extern uint dhd_watchdog_ms;
333 extern void dhd_os_wd_timer(void *bus, uint wdtick);
338 uint dhd_txminmax = DHD_TXMINMAX;
340 /* override the RAM size if possible */
341 #define DONGLE_MIN_MEMSIZE (128 *1024)
342 int dhd_dongle_memsize;
344 static bool dhd_doflow;
345 static bool dhd_alignctl;
349 static bool retrydata;
350 #define RETRYCHAN(chan) (((chan) == SDPCM_EVENT_CHANNEL) || retrydata)
352 static const uint watermark = 8;
353 static const uint firstread = DHD_FIRSTREAD;
355 #define HDATLEN (firstread - (SDPCM_HDRLEN))
357 /* Retry count for register access failures */
358 static const uint retry_limit = 2;
360 /* Force even SD lengths (some host controllers mess up on odd bytes) */
361 static bool forcealign;
363 /* Flag to indicate if we should download firmware on driver load */
364 uint dhd_download_fw_on_driverload = FALSE;
368 #if defined(OOB_INTR_ONLY) && defined(HW_OOB)
369 extern void bcmsdh_enable_hw_oob_intr(void *sdh, bool enable);
372 #if defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD)
373 #error OOB_INTR_ONLY is NOT working with SDIO_ISR_THREAD
374 #endif /* defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD) */
375 #define PKTALIGN(osh, p, len, align) \
378 datalign = (uintptr)PKTDATA((osh), (p)); \
379 datalign = ROUNDUP(datalign, (align)) - datalign; \
380 ASSERT(datalign < (align)); \
381 ASSERT(PKTLEN((osh), (p)) >= ((len) + datalign)); \
383 PKTPULL((osh), (p), datalign); \
384 PKTSETLEN((osh), (p), (len)); \
387 /* Limit on rounding up frames */
388 static const uint max_roundup = 512;
390 /* Try doing readahead */
391 static bool dhd_readahead;
394 /* To check if there's window offered */
395 #define DATAOK(bus) \
396 (((uint8)(bus->tx_max - bus->tx_seq) > 1) && \
397 (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0))
399 /* To check if there's window offered for ctrl frame */
400 #define TXCTLOK(bus) \
401 (((uint8)(bus->tx_max - bus->tx_seq) != 0) && \
402 (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0))
404 /* Macros to get register read/write status */
405 /* NOTE: these assume a local dhdsdio_bus_t *bus! */
406 #define R_SDREG(regvar, regaddr, retryvar) \
410 regvar = R_REG(bus->dhd->osh, regaddr); \
411 } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \
413 bus->regfails += (retryvar-1); \
414 if (retryvar > retry_limit) { \
415 DHD_ERROR(("%s: FAILED" #regvar "READ, LINE %d\n", \
416 __FUNCTION__, __LINE__)); \
422 #define W_SDREG(regval, regaddr, retryvar) \
426 W_REG(bus->dhd->osh, regaddr, regval); \
427 } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \
429 bus->regfails += (retryvar-1); \
430 if (retryvar > retry_limit) \
431 DHD_ERROR(("%s: FAILED REGISTER WRITE, LINE %d\n", \
432 __FUNCTION__, __LINE__)); \
438 * pktavail interrupts from dongle to host can be managed in 3 different ways
439 * whenever there is a packet available in dongle to transmit to host.
441 * Mode 0: Dongle writes the software host mailbox and host is interrupted.
442 * Mode 1: (sdiod core rev >= 4)
443 * Device sets a new bit in the intstatus whenever there is a packet
444 * available in fifo. Host can't clear this specific status bit until all the
445 * packets are read from the FIFO. No need to ack dongle intstatus.
446 * Mode 2: (sdiod core rev >= 4)
447 * Device sets a bit in the intstatus, and host acks this by writing
448 * one to this bit. Dongle won't generate anymore packet interrupts
449 * until host reads all the packets from the dongle and reads a zero to
450 * figure that there are no more packets. No need to disable host ints.
451 * Need to ack the intstatus.
454 #define SDIO_DEVICE_HMB_RXINT 0 /* default old way */
455 #define SDIO_DEVICE_RXDATAINT_MODE_0 1 /* from sdiod rev 4 */
456 #define SDIO_DEVICE_RXDATAINT_MODE_1 2 /* from sdiod rev 4 */
459 #define FRAME_AVAIL_MASK(bus) \
460 ((bus->rxint_mode == SDIO_DEVICE_HMB_RXINT) ? I_HMB_FRAME_IND : I_XMTDATA_AVAIL)
462 #define DHD_BUS SDIO_BUS
464 #define PKT_AVAILABLE(bus, intstatus) ((intstatus) & (FRAME_AVAIL_MASK(bus)))
466 #define HOSTINTMASK (I_HMB_SW_MASK | I_CHIPACTIVE)
468 #define GSPI_PR55150_BAILOUT
472 static void dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq);
473 static void dhdsdio_sdtest_set(dhd_bus_t *bus, uint8 count);
477 static int dhdsdio_checkdied(dhd_bus_t *bus, uint8 *data, uint size);
478 static int dhdsdio_mem_dump(dhd_bus_t *bus);
479 static int dhd_serialconsole(dhd_bus_t *bus, bool get, bool enable, int *bcmerror);
480 #endif /* DHD_DEBUG */
481 static int dhdsdio_download_state(dhd_bus_t *bus, bool enter);
483 static void dhdsdio_release(dhd_bus_t *bus, osl_t *osh);
484 static void dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh);
485 static void dhdsdio_disconnect(void *ptr);
486 static bool dhdsdio_chipmatch(uint16 chipid);
487 static bool dhdsdio_probe_attach(dhd_bus_t *bus, osl_t *osh, void *sdh,
488 void * regsva, uint16 devid);
489 static bool dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh);
490 static bool dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh);
491 static void dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation,
494 static void dhd_dongle_setmemsize(struct dhd_bus *bus, int mem_size);
495 static int dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags,
496 uint8 *buf, uint nbytes,
497 void *pkt, bcmsdh_cmplt_fn_t complete, void *handle);
498 static int dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags,
499 uint8 *buf, uint nbytes,
500 void *pkt, bcmsdh_cmplt_fn_t complete, void *handle);
502 static bool dhdsdio_download_firmware(dhd_bus_t *bus, osl_t *osh, void *sdh);
503 static int _dhdsdio_download_firmware(dhd_bus_t *bus);
505 static int dhdsdio_download_code_file(dhd_bus_t *bus, char *image_path);
506 static int dhdsdio_download_nvram(dhd_bus_t *bus);
508 static int dhdsdio_download_code_array(dhd_bus_t *bus);
513 extern uint32 dhd_get_htsf(void *dhd, int ifidx);
514 #endif /* WLMEDIA_HTSF */
517 dhd_dongle_setmemsize(struct dhd_bus *bus, int mem_size)
519 int32 min_size = DONGLE_MIN_MEMSIZE;
520 /* Restrict the memsize to user specified limit */
521 DHD_ERROR(("user: Restrict the dongle ram size to %d, min accepted %d\n",
522 dhd_dongle_memsize, min_size));
523 if ((dhd_dongle_memsize > min_size) &&
524 (dhd_dongle_memsize < (int32)bus->orig_ramsize))
525 bus->ramsize = dhd_dongle_memsize;
529 dhdsdio_set_siaddr_window(dhd_bus_t *bus, uint32 address)
532 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW,
533 (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err);
535 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID,
536 (address >> 16) & SBSDIO_SBADDRMID_MASK, &err);
538 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH,
539 (address >> 24) & SBSDIO_SBADDRHIGH_MASK, &err);
544 /* Turn backplane clock on or off */
546 dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok)
549 uint8 clkctl, clkreq, devctl;
552 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
554 #if defined(OOB_INTR_ONLY)
562 /* Request HT Avail */
563 clkreq = bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ;
568 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
570 DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err));
575 ((bus->sih->buscoretype == PCMCIA_CORE_ID) && (bus->sih->buscorerev == 9))) {
576 uint32 dummy, retries;
577 R_SDREG(dummy, &bus->regs->clockctlstatus, retries);
580 /* Check current status */
581 clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
583 DHD_ERROR(("%s: HT Avail read error: %d\n", __FUNCTION__, err));
587 /* Go to pending and await interrupt if appropriate */
588 if (!SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) {
589 /* Allow only clock-available interrupt */
590 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
592 DHD_ERROR(("%s: Devctl access error setting CA: %d\n",
597 devctl |= SBSDIO_DEVCTL_CA_INT_ONLY;
598 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
599 DHD_INFO(("CLKCTL: set PENDING\n"));
600 bus->clkstate = CLK_PENDING;
602 } else if (bus->clkstate == CLK_PENDING) {
603 /* Cancel CA-only interrupt filter */
604 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
605 devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
606 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
609 /* Otherwise, wait here (polling) for HT Avail */
610 if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
611 SPINWAIT_SLEEP(sdioh_spinwait_sleep,
612 ((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
613 SBSDIO_FUNC1_CHIPCLKCSR, &err)),
614 !SBSDIO_CLKAV(clkctl, bus->alp_only)), PMU_MAX_TRANSITION_DLY);
617 DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err));
620 if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
621 DHD_ERROR(("%s: HT Avail timeout (%d): clkctl 0x%02x\n",
622 __FUNCTION__, PMU_MAX_TRANSITION_DLY, clkctl));
627 /* Mark clock available */
628 bus->clkstate = CLK_AVAIL;
629 DHD_INFO(("CLKCTL: turned ON\n"));
631 #if defined(DHD_DEBUG)
632 if (bus->alp_only == TRUE) {
633 #if !defined(BCMLXSDMMC)
634 if (!SBSDIO_ALPONLY(clkctl)) {
635 DHD_ERROR(("%s: HT Clock, when ALP Only\n", __FUNCTION__));
637 #endif /* !defined(BCMLXSDMMC) */
639 if (SBSDIO_ALPONLY(clkctl)) {
640 DHD_ERROR(("%s: HT Clock should be on.\n", __FUNCTION__));
643 #endif /* defined (DHD_DEBUG) */
645 bus->activity = TRUE;
649 if (bus->clkstate == CLK_PENDING) {
650 /* Cancel CA-only interrupt filter */
651 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
652 devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
653 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
656 bus->clkstate = CLK_SDONLY;
657 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
658 DHD_INFO(("CLKCTL: turned OFF\n"));
660 DHD_ERROR(("%s: Failed access turning clock off: %d\n",
668 /* Change idle/active SD state */
670 dhdsdio_sdclk(dhd_bus_t *bus, bool on)
675 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
678 if (bus->idleclock == DHD_IDLE_STOP) {
679 /* Turn on clock and restore mode */
681 err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0,
682 &iovalue, sizeof(iovalue), TRUE);
684 DHD_ERROR(("%s: error enabling sd_clock: %d\n",
689 iovalue = bus->sd_mode;
690 err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
691 &iovalue, sizeof(iovalue), TRUE);
693 DHD_ERROR(("%s: error changing sd_mode: %d\n",
697 } else if (bus->idleclock != DHD_IDLE_ACTIVE) {
698 /* Restore clock speed */
699 iovalue = bus->sd_divisor;
700 err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
701 &iovalue, sizeof(iovalue), TRUE);
703 DHD_ERROR(("%s: error restoring sd_divisor: %d\n",
708 bus->clkstate = CLK_SDONLY;
710 /* Stop or slow the SD clock itself */
711 if ((bus->sd_divisor == -1) || (bus->sd_mode == -1)) {
712 DHD_TRACE(("%s: can't idle clock, divisor %d mode %d\n",
713 __FUNCTION__, bus->sd_divisor, bus->sd_mode));
716 if (bus->idleclock == DHD_IDLE_STOP) {
718 /* Change to SD1 mode and turn off clock */
720 err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
721 &iovalue, sizeof(iovalue), TRUE);
723 DHD_ERROR(("%s: error changing sd_clock: %d\n",
730 err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0,
731 &iovalue, sizeof(iovalue), TRUE);
733 DHD_ERROR(("%s: error disabling sd_clock: %d\n",
737 } else if (bus->idleclock != DHD_IDLE_ACTIVE) {
738 /* Set divisor to idle value */
739 iovalue = bus->idleclock;
740 err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
741 &iovalue, sizeof(iovalue), TRUE);
743 DHD_ERROR(("%s: error changing sd_divisor: %d\n",
748 bus->clkstate = CLK_NONE;
754 /* Transition SD and backplane clock readiness */
756 dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok)
760 uint oldstate = bus->clkstate;
761 #endif /* DHD_DEBUG */
763 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
765 /* Early exit if we're already there */
766 if (bus->clkstate == target) {
767 if (target == CLK_AVAIL) {
768 dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
769 bus->activity = TRUE;
776 /* Make sure SD clock is available */
777 if (bus->clkstate == CLK_NONE)
778 dhdsdio_sdclk(bus, TRUE);
779 /* Now request HT Avail on the backplane */
780 ret = dhdsdio_htclk(bus, TRUE, pendok);
781 if (ret == BCME_OK) {
782 dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
783 bus->activity = TRUE;
788 /* Remove HT request, or bring up SD clock */
789 if (bus->clkstate == CLK_NONE)
790 ret = dhdsdio_sdclk(bus, TRUE);
791 else if (bus->clkstate == CLK_AVAIL)
792 ret = dhdsdio_htclk(bus, FALSE, FALSE);
794 DHD_ERROR(("dhdsdio_clkctl: request for %d -> %d\n",
795 bus->clkstate, target));
796 if (ret == BCME_OK) {
797 dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
802 /* Make sure to remove HT request */
803 if (bus->clkstate == CLK_AVAIL)
804 ret = dhdsdio_htclk(bus, FALSE, FALSE);
805 /* Now remove the SD clock */
806 ret = dhdsdio_sdclk(bus, FALSE);
808 if (dhd_console_ms == 0)
809 #endif /* DHD_DEBUG */
810 dhd_os_wd_timer(bus->dhd, 0);
814 DHD_INFO(("dhdsdio_clkctl: %d -> %d\n", oldstate, bus->clkstate));
815 #endif /* DHD_DEBUG */
821 dhdsdio_bussleep(dhd_bus_t *bus, bool sleep)
823 bcmsdh_info_t *sdh = bus->sdh;
824 sdpcmd_regs_t *regs = bus->regs;
827 DHD_INFO(("dhdsdio_bussleep: request %s (currently %s)\n",
828 (sleep ? "SLEEP" : "WAKE"),
829 (bus->sleeping ? "SLEEP" : "WAKE")));
831 /* Done if we're already in the requested state */
832 if (sleep == bus->sleeping)
835 /* Going to sleep: set the alarm and turn off the lights... */
837 /* Don't sleep if something is pending */
838 if (bus->dpc_sched || bus->rxskip || pktq_len(&bus->txq))
842 /* Disable SDIO interrupts (no longer interested) */
843 bcmsdh_intr_disable(bus->sdh);
845 /* Make sure the controller has the bus up */
846 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
848 /* Tell device to start using OOB wakeup */
849 W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries);
850 if (retries > retry_limit)
851 DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
853 /* Turn off our contribution to the HT clock request */
854 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
856 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
857 SBSDIO_FORCE_HW_CLKREQ_OFF, NULL);
859 /* Isolate the bus */
860 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL,
861 SBSDIO_DEVCTL_PADS_ISO, NULL);
864 bus->sleeping = TRUE;
867 /* Waking up: bus power up is ok, set local state */
869 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
872 /* Force pad isolation off if possible (in case power never toggled) */
873 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, 0, NULL);
876 /* Make sure the controller has the bus up */
877 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
879 /* Send misc interrupt to indicate OOB not needed */
880 W_SDREG(0, ®s->tosbmailboxdata, retries);
881 if (retries <= retry_limit)
882 W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries);
884 if (retries > retry_limit)
885 DHD_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n"));
887 /* Make sure we have SD bus access */
888 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
891 bus->sleeping = FALSE;
893 /* Enable interrupts again */
894 if (bus->intr && (bus->dhd->busstate == DHD_BUS_DATA)) {
896 bcmsdh_intr_enable(bus->sdh);
903 #if defined(OOB_INTR_ONLY)
905 dhd_enable_oob_intr(struct dhd_bus *bus, bool enable)
908 bcmsdh_enable_hw_oob_intr(bus->sdh, enable);
910 sdpcmd_regs_t *regs = bus->regs;
913 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
914 if (enable == TRUE) {
916 /* Tell device to start using OOB wakeup */
917 W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries);
918 if (retries > retry_limit)
919 DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
922 /* Send misc interrupt to indicate OOB not needed */
923 W_SDREG(0, ®s->tosbmailboxdata, retries);
924 if (retries <= retry_limit)
925 W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries);
928 /* Turn off our contribution to the HT clock request */
929 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
930 #endif /* !defined(HW_OOB) */
932 #endif /* defined(OOB_INTR_ONLY) */
934 #define BUS_WAKE(bus) \
936 if ((bus)->sleeping) \
937 dhdsdio_bussleep((bus), FALSE); \
941 /* Writes a HW/SW header into the packet and sends it. */
942 /* Assumes: (a) header space already there, (b) caller holds lock */
944 dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt)
949 uint16 len, pad1 = 0;
961 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
966 if (bus->dhd->dongle_reset) {
971 frame = (uint8*)PKTDATA(osh, pkt);
974 if (PKTLEN(osh, pkt) >= 100) {
975 p = PKTDATA(osh, pkt);
976 htsf_ts = (htsfts_t*) (p + HTSF_HOSTOFFSET + 12);
977 if (htsf_ts->magic == HTSFMAGIC) {
978 htsf_ts->c20 = get_cycles();
979 htsf_ts->t20 = dhd_get_htsf(bus->dhd->info, 0);
982 #endif /* WLMEDIA_HTSF */
984 /* Add alignment padding, allocate new packet if needed */
985 if ((pad1 = ((uintptr)frame % DHD_SDALIGN))) {
986 if (PKTHEADROOM(osh, pkt) < pad1) {
987 DHD_INFO(("%s: insufficient headroom %d for %d pad1\n",
988 __FUNCTION__, (int)PKTHEADROOM(osh, pkt), pad1));
989 bus->dhd->tx_realloc++;
990 new = PKTGET(osh, (PKTLEN(osh, pkt) + DHD_SDALIGN), TRUE);
992 DHD_ERROR(("%s: couldn't allocate new %d-byte packet\n",
993 __FUNCTION__, PKTLEN(osh, pkt) + DHD_SDALIGN));
998 PKTALIGN(osh, new, PKTLEN(osh, pkt), DHD_SDALIGN);
999 bcopy(PKTDATA(osh, pkt), PKTDATA(osh, new), PKTLEN(osh, pkt));
1001 PKTFREE(osh, pkt, TRUE);
1002 /* free the pkt if canned one is not used */
1005 frame = (uint8*)PKTDATA(osh, pkt);
1006 ASSERT(((uintptr)frame % DHD_SDALIGN) == 0);
1009 PKTPUSH(osh, pkt, pad1);
1010 frame = (uint8*)PKTDATA(osh, pkt);
1012 ASSERT((pad1 + SDPCM_HDRLEN) <= (int) PKTLEN(osh, pkt));
1013 bzero(frame, pad1 + SDPCM_HDRLEN);
1016 ASSERT(pad1 < DHD_SDALIGN);
1018 /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
1019 len = (uint16)PKTLEN(osh, pkt);
1020 *(uint16*)frame = htol16(len);
1021 *(((uint16*)frame) + 1) = htol16(~len);
1023 /* Software tag: channel, sequence number, data offset */
1024 swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) | bus->tx_seq |
1025 (((pad1 + SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
1026 htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN);
1027 htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
1030 if (PKTPRIO(pkt) < ARRAYSIZE(tx_packets)) {
1031 tx_packets[PKTPRIO(pkt)]++;
1033 if (DHD_BYTES_ON() &&
1034 (((DHD_CTL_ON() && (chan == SDPCM_CONTROL_CHANNEL)) ||
1035 (DHD_DATA_ON() && (chan != SDPCM_CONTROL_CHANNEL))))) {
1036 prhex("Tx Frame", frame, len);
1037 } else if (DHD_HDRS_ON()) {
1038 prhex("TxHdr", frame, MIN(len, 16));
1042 /* Raise len to next SDIO block to eliminate tail command */
1043 if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
1044 uint16 pad2 = bus->blocksize - (len % bus->blocksize);
1045 if ((pad2 <= bus->roundup) && (pad2 < bus->blocksize))
1047 if (pad2 <= PKTTAILROOM(osh, pkt))
1048 #endif /* NOTUSED */
1050 } else if (len % DHD_SDALIGN) {
1051 len += DHD_SDALIGN - (len % DHD_SDALIGN);
1054 /* Some controllers have trouble with odd bytes -- round to even */
1055 if (forcealign && (len & (ALIGNMENT - 1))) {
1057 if (PKTTAILROOM(osh, pkt))
1059 len = ROUNDUP(len, ALIGNMENT);
1062 DHD_ERROR(("%s: sending unrounded %d-byte packet\n", __FUNCTION__, len));
1067 ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
1068 frame, len, pkt, NULL, NULL);
1070 ASSERT(ret != BCME_PENDING);
1073 /* On failure, abort the command and terminate the frame */
1074 DHD_INFO(("%s: sdio error %d, abort command and terminate frame.\n",
1075 __FUNCTION__, ret));
1078 bcmsdh_abort(sdh, SDIO_FUNC_2);
1079 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
1083 for (i = 0; i < 3; i++) {
1085 hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
1086 SBSDIO_FUNC1_WFRAMEBCHI, NULL);
1087 lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
1088 SBSDIO_FUNC1_WFRAMEBCLO, NULL);
1089 bus->f1regdata += 2;
1090 if ((hi == 0) && (lo == 0))
1096 bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
1098 } while ((ret < 0) && retrydata && retries++ < TXRETRIES);
1101 /* restore pkt buffer pointer before calling tx complete routine */
1102 PKTPULL(osh, pkt, SDPCM_HDRLEN + pad1);
1103 #ifdef PROP_TXSTATUS
1104 if (bus->dhd->wlfc_state) {
1105 dhd_os_sdunlock(bus->dhd);
1106 dhd_wlfc_txcomplete(bus->dhd, pkt, ret == 0);
1107 dhd_os_sdlock(bus->dhd);
1109 #endif /* PROP_TXSTATUS */
1110 dhd_txcomplete(bus->dhd, pkt, ret != 0);
1112 PKTFREE(osh, pkt, TRUE);
1114 #ifdef PROP_TXSTATUS
1121 dhd_bus_txdata(struct dhd_bus *bus, void *pkt)
1123 int ret = BCME_ERROR;
1127 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1129 osh = bus->dhd->osh;
1130 datalen = PKTLEN(osh, pkt);
1133 /* Push the test header if doing loopback */
1134 if (bus->ext_loop) {
1136 PKTPUSH(osh, pkt, SDPCM_TEST_HDRLEN);
1137 data = PKTDATA(osh, pkt);
1138 *data++ = SDPCM_TEST_ECHOREQ;
1139 *data++ = (uint8)bus->loopid++;
1140 *data++ = (datalen >> 0);
1141 *data++ = (datalen >> 8);
1142 datalen += SDPCM_TEST_HDRLEN;
1146 /* Add space for the header */
1147 PKTPUSH(osh, pkt, SDPCM_HDRLEN);
1148 ASSERT(ISALIGNED((uintptr)PKTDATA(osh, pkt), 2));
1150 prec = PRIO2PREC((PKTPRIO(pkt) & PRIOMASK));
1152 /* Lock: we're about to use shared data/code (and SDIO) */
1153 dhd_os_sdlock(bus->dhd);
1154 #endif /* DHDTHREAD */
1156 /* Check for existing queue, current flow-control, pending event, or pending clock */
1157 if (dhd_deferred_tx || bus->fcstate || pktq_len(&bus->txq) || bus->dpc_sched ||
1158 (!DATAOK(bus)) || (bus->flowcontrol & NBITVAL(prec)) ||
1159 (bus->clkstate != CLK_AVAIL)) {
1160 DHD_TRACE(("%s: deferring pktq len %d\n", __FUNCTION__,
1161 pktq_len(&bus->txq)));
1164 /* Priority based enq */
1165 dhd_os_sdlock_txq(bus->dhd);
1166 if (dhd_prec_enq(bus->dhd, &bus->txq, pkt, prec) == FALSE) {
1167 PKTPULL(osh, pkt, SDPCM_HDRLEN);
1169 /* Need to also release txqlock before releasing sdlock.
1170 * This thread still has txqlock and releases sdlock.
1171 * Deadlock happens when dpc() grabs sdlock first then
1172 * attempts to grab txqlock.
1174 dhd_os_sdunlock_txq(bus->dhd);
1175 dhd_os_sdunlock(bus->dhd);
1177 #ifdef PROP_TXSTATUS
1178 if (bus->dhd->wlfc_state)
1179 dhd_wlfc_txcomplete(bus->dhd, pkt, FALSE);
1182 dhd_txcomplete(bus->dhd, pkt, FALSE);
1184 dhd_os_sdlock(bus->dhd);
1185 dhd_os_sdlock_txq(bus->dhd);
1187 #ifdef PROP_TXSTATUS
1188 /* let the caller decide whether to free the packet */
1189 if (!bus->dhd->wlfc_state)
1191 PKTFREE(osh, pkt, TRUE);
1192 ret = BCME_NORESOURCE;
1196 dhd_os_sdunlock_txq(bus->dhd);
1198 if ((pktq_len(&bus->txq) >= FCHI) && dhd_doflow)
1199 dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON);
1202 if (pktq_plen(&bus->txq, prec) > qcount[prec])
1203 qcount[prec] = pktq_plen(&bus->txq, prec);
1205 /* Schedule DPC if needed to send queued packet(s) */
1206 if (dhd_deferred_tx && !bus->dpc_sched) {
1207 bus->dpc_sched = TRUE;
1208 dhd_sched_dpc(bus->dhd);
1212 /* Lock: we're about to use shared data/code (and SDIO) */
1213 dhd_os_sdlock(bus->dhd);
1214 #endif /* DHDTHREAD */
1216 /* Otherwise, send it now */
1218 /* Make sure back plane ht clk is on, no pending allowed */
1219 dhdsdio_clkctl(bus, CLK_AVAIL, TRUE);
1221 ret = dhdsdio_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, TRUE);
1223 ret = dhdsdio_txpkt(bus, pkt,
1224 (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL), TRUE);
1227 bus->dhd->tx_errors++;
1229 bus->dhd->dstats.tx_bytes += datalen;
1231 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
1232 bus->activity = FALSE;
1233 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
1237 dhd_os_sdunlock(bus->dhd);
1238 #endif /* DHDTHREAD */
1242 dhd_os_sdunlock(bus->dhd);
1243 #endif /* DHDTHREAD */
1249 dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes)
1252 uint32 intstatus = 0;
1254 int ret = 0, prec_out;
1259 dhd_pub_t *dhd = bus->dhd;
1260 sdpcmd_regs_t *regs = bus->regs;
1262 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1264 tx_prec_map = ~bus->flowcontrol;
1266 /* Send frames until the limit or some other event */
1267 for (cnt = 0; (cnt < maxframes) && DATAOK(bus); cnt++) {
1268 dhd_os_sdlock_txq(bus->dhd);
1269 if ((pkt = pktq_mdeq(&bus->txq, tx_prec_map, &prec_out)) == NULL) {
1270 dhd_os_sdunlock_txq(bus->dhd);
1273 dhd_os_sdunlock_txq(bus->dhd);
1274 datalen = PKTLEN(bus->dhd->osh, pkt) - SDPCM_HDRLEN;
1277 ret = dhdsdio_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, TRUE);
1279 ret = dhdsdio_txpkt(bus, pkt,
1280 (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL), TRUE);
1283 bus->dhd->tx_errors++;
1285 bus->dhd->dstats.tx_bytes += datalen;
1287 /* In poll mode, need to check for other events */
1288 if (!bus->intr && cnt)
1290 /* Check device status, signal pending interrupt */
1291 R_SDREG(intstatus, ®s->intstatus, retries);
1293 if (bcmsdh_regfail(bus->sdh))
1295 if (intstatus & bus->hostintmask)
1300 /* Deflow-control stack if needed */
1301 if (dhd_doflow && dhd->up && (dhd->busstate == DHD_BUS_DATA) &&
1302 dhd->txoff && (pktq_len(&bus->txq) < FCLOW))
1303 dhd_txflowcontrol(dhd, ALL_INTERFACES, OFF);
1309 dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen)
1315 bcmsdh_info_t *sdh = bus->sdh;
1320 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1322 if (bus->dhd->dongle_reset)
1325 /* Back the pointer to make a room for bus header */
1326 frame = msg - SDPCM_HDRLEN;
1327 len = (msglen += SDPCM_HDRLEN);
1329 /* Add alignment padding (optional for ctl frames) */
1331 if ((doff = ((uintptr)frame % DHD_SDALIGN))) {
1335 bzero(frame, doff + SDPCM_HDRLEN);
1337 ASSERT(doff < DHD_SDALIGN);
1339 doff += SDPCM_HDRLEN;
1341 /* Round send length to next SDIO block */
1342 if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
1343 uint16 pad = bus->blocksize - (len % bus->blocksize);
1344 if ((pad <= bus->roundup) && (pad < bus->blocksize))
1346 } else if (len % DHD_SDALIGN) {
1347 len += DHD_SDALIGN - (len % DHD_SDALIGN);
1350 /* Satisfy length-alignment requirements */
1351 if (forcealign && (len & (ALIGNMENT - 1)))
1352 len = ROUNDUP(len, ALIGNMENT);
1354 ASSERT(ISALIGNED((uintptr)frame, 2));
1357 /* Need to lock here to protect txseq and SDIO tx calls */
1358 dhd_os_sdlock(bus->dhd);
1362 /* Make sure backplane clock is on */
1363 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
1365 /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
1366 *(uint16*)frame = htol16((uint16)msglen);
1367 *(((uint16*)frame) + 1) = htol16(~msglen);
1369 /* Software tag: channel, sequence number, data offset */
1370 swheader = ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK)
1371 | bus->tx_seq | ((doff << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
1372 htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN);
1373 htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
1375 if (!TXCTLOK(bus)) {
1376 DHD_INFO(("%s: No bus credit bus->tx_max %d, bus->tx_seq %d\n",
1377 __FUNCTION__, bus->tx_max, bus->tx_seq));
1378 bus->ctrl_frame_stat = TRUE;
1380 bus->ctrl_frame_buf = frame;
1381 bus->ctrl_frame_len = len;
1383 dhd_wait_for_event(bus->dhd, &bus->ctrl_frame_stat);
1385 if (bus->ctrl_frame_stat == FALSE) {
1386 DHD_INFO(("%s: ctrl_frame_stat == FALSE\n", __FUNCTION__));
1389 DHD_ERROR(("%s: ctrl_frame_stat == TRUE\n", __FUNCTION__));
1391 bus->ctrl_frame_stat = FALSE;
1398 if (DHD_BYTES_ON() && DHD_CTL_ON()) {
1399 prhex("Tx Frame", frame, len);
1400 } else if (DHD_HDRS_ON()) {
1401 prhex("TxHdr", frame, MIN(len, 16));
1406 ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
1407 frame, len, NULL, NULL, NULL);
1408 ASSERT(ret != BCME_PENDING);
1411 /* On failure, abort the command and terminate the frame */
1412 DHD_INFO(("%s: sdio error %d, abort command and terminate frame.\n",
1413 __FUNCTION__, ret));
1416 bcmsdh_abort(sdh, SDIO_FUNC_2);
1418 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
1422 for (i = 0; i < 3; i++) {
1424 hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
1425 SBSDIO_FUNC1_WFRAMEBCHI, NULL);
1426 lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
1427 SBSDIO_FUNC1_WFRAMEBCLO, NULL);
1428 bus->f1regdata += 2;
1429 if ((hi == 0) && (lo == 0))
1435 bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
1437 } while ((ret < 0) && retries++ < TXRETRIES);
1441 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
1442 bus->activity = FALSE;
1443 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
1446 dhd_os_sdunlock(bus->dhd);
1449 bus->dhd->tx_ctlerrs++;
1451 bus->dhd->tx_ctlpkts++;
1453 return ret ? -EIO : 0;
1457 dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen)
1463 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1465 if (bus->dhd->dongle_reset)
1468 /* Wait until control frame is available */
1469 timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->rxlen, &pending);
1471 dhd_os_sdlock(bus->dhd);
1473 bcopy(bus->rxctl, msg, MIN(msglen, rxlen));
1475 dhd_os_sdunlock(bus->dhd);
1478 DHD_CTL(("%s: resumed on rxctl frame, got %d expected %d\n",
1479 __FUNCTION__, rxlen, msglen));
1480 } else if (timeleft == 0) {
1481 DHD_ERROR(("%s: resumed on timeout\n", __FUNCTION__));
1483 dhd_os_sdlock(bus->dhd);
1484 dhdsdio_checkdied(bus, NULL, 0);
1485 dhd_os_sdunlock(bus->dhd);
1486 #endif /* DHD_DEBUG */
1487 } else if (pending == TRUE) {
1488 DHD_CTL(("%s: canceled\n", __FUNCTION__));
1489 return -ERESTARTSYS;
1491 DHD_CTL(("%s: resumed for unknown reason?\n", __FUNCTION__));
1493 dhd_os_sdlock(bus->dhd);
1494 dhdsdio_checkdied(bus, NULL, 0);
1495 dhd_os_sdunlock(bus->dhd);
1496 #endif /* DHD_DEBUG */
1500 bus->dhd->rx_ctlpkts++;
1502 bus->dhd->rx_ctlerrs++;
1504 return rxlen ? (int)rxlen : -ETIMEDOUT;
1542 IOV_DONGLEISOLATION,
1549 const bcm_iovar_t dhdsdio_iovars[] = {
1550 {"intr", IOV_INTR, 0, IOVT_BOOL, 0 },
1551 {"sleep", IOV_SLEEP, 0, IOVT_BOOL, 0 },
1552 {"pollrate", IOV_POLLRATE, 0, IOVT_UINT32, 0 },
1553 {"idletime", IOV_IDLETIME, 0, IOVT_INT32, 0 },
1554 {"idleclock", IOV_IDLECLOCK, 0, IOVT_INT32, 0 },
1555 {"sd1idle", IOV_SD1IDLE, 0, IOVT_BOOL, 0 },
1556 {"membytes", IOV_MEMBYTES, 0, IOVT_BUFFER, 2 * sizeof(int) },
1557 {"memsize", IOV_MEMSIZE, 0, IOVT_UINT32, 0 },
1558 {"download", IOV_DOWNLOAD, 0, IOVT_BOOL, 0 },
1559 {"socram_state", IOV_SOCRAM_STATE, 0, IOVT_BOOL, 0 },
1560 {"vars", IOV_VARS, 0, IOVT_BUFFER, 0 },
1561 {"sdiod_drive", IOV_SDIOD_DRIVE, 0, IOVT_UINT32, 0 },
1562 {"readahead", IOV_READAHEAD, 0, IOVT_BOOL, 0 },
1563 {"sdrxchain", IOV_SDRXCHAIN, 0, IOVT_BOOL, 0 },
1564 {"alignctl", IOV_ALIGNCTL, 0, IOVT_BOOL, 0 },
1565 {"sdalign", IOV_SDALIGN, 0, IOVT_BOOL, 0 },
1566 {"devreset", IOV_DEVRESET, 0, IOVT_BOOL, 0 },
1568 {"sdreg", IOV_SDREG, 0, IOVT_BUFFER, sizeof(sdreg_t) },
1569 {"sbreg", IOV_SBREG, 0, IOVT_BUFFER, sizeof(sdreg_t) },
1570 {"sd_cis", IOV_SDCIS, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN },
1571 {"forcealign", IOV_FORCEEVEN, 0, IOVT_BOOL, 0 },
1572 {"txbound", IOV_TXBOUND, 0, IOVT_UINT32, 0 },
1573 {"rxbound", IOV_RXBOUND, 0, IOVT_UINT32, 0 },
1574 {"txminmax", IOV_TXMINMAX, 0, IOVT_UINT32, 0 },
1575 {"cpu", IOV_CPU, 0, IOVT_BOOL, 0 },
1577 {"checkdied", IOV_CHECKDIED, 0, IOVT_BUFFER, 0 },
1578 #endif /* DHD_DEBUG */
1579 #endif /* DHD_DEBUG */
1581 {"extloop", IOV_EXTLOOP, 0, IOVT_BOOL, 0 },
1582 {"pktgen", IOV_PKTGEN, 0, IOVT_BUFFER, sizeof(dhd_pktgen_t) },
1584 {"dngl_isolation", IOV_DONGLEISOLATION, 0, IOVT_UINT32, 0 },
1586 {"fwpath", IOV_FWPATH, 0, IOVT_BUFFER, 0 },
1592 dhd_dump_pct(struct bcmstrbuf *strbuf, char *desc, uint num, uint div)
1597 bcm_bprintf(strbuf, "%s N/A", desc);
1600 q2 = (100 * (num - (q1 * div))) / div;
1601 bcm_bprintf(strbuf, "%s %d.%02d", desc, q1, q2);
1606 dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf)
1608 dhd_bus_t *bus = dhdp->bus;
1610 bcm_bprintf(strbuf, "Bus SDIO structure:\n");
1611 bcm_bprintf(strbuf, "hostintmask 0x%08x intstatus 0x%08x sdpcm_ver %d\n",
1612 bus->hostintmask, bus->intstatus, bus->sdpcm_ver);
1613 bcm_bprintf(strbuf, "fcstate %d qlen %d tx_seq %d, max %d, rxskip %d rxlen %d rx_seq %d\n",
1614 bus->fcstate, pktq_len(&bus->txq), bus->tx_seq, bus->tx_max, bus->rxskip,
1615 bus->rxlen, bus->rx_seq);
1616 bcm_bprintf(strbuf, "intr %d intrcount %d lastintrs %d spurious %d\n",
1617 bus->intr, bus->intrcount, bus->lastintrs, bus->spurious);
1618 bcm_bprintf(strbuf, "pollrate %d pollcnt %d regfails %d\n",
1619 bus->pollrate, bus->pollcnt, bus->regfails);
1621 bcm_bprintf(strbuf, "\nAdditional counters:\n");
1622 bcm_bprintf(strbuf, "tx_sderrs %d fcqueued %d rxrtx %d rx_toolong %d rxc_errors %d\n",
1623 bus->tx_sderrs, bus->fcqueued, bus->rxrtx, bus->rx_toolong,
1625 bcm_bprintf(strbuf, "rx_hdrfail %d badhdr %d badseq %d\n",
1626 bus->rx_hdrfail, bus->rx_badhdr, bus->rx_badseq);
1627 bcm_bprintf(strbuf, "fc_rcvd %d, fc_xoff %d, fc_xon %d\n",
1628 bus->fc_rcvd, bus->fc_xoff, bus->fc_xon);
1629 bcm_bprintf(strbuf, "rxglomfail %d, rxglomframes %d, rxglompkts %d\n",
1630 bus->rxglomfail, bus->rxglomframes, bus->rxglompkts);
1631 bcm_bprintf(strbuf, "f2rx (hdrs/data) %d (%d/%d), f2tx %d f1regs %d\n",
1632 (bus->f2rxhdrs + bus->f2rxdata), bus->f2rxhdrs, bus->f2rxdata,
1633 bus->f2txdata, bus->f1regdata);
1635 dhd_dump_pct(strbuf, "\nRx: pkts/f2rd", bus->dhd->rx_packets,
1636 (bus->f2rxhdrs + bus->f2rxdata));
1637 dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->rx_packets, bus->f1regdata);
1638 dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->rx_packets,
1639 (bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata));
1640 dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->rx_packets, bus->intrcount);
1641 bcm_bprintf(strbuf, "\n");
1643 dhd_dump_pct(strbuf, "Rx: glom pct", (100 * bus->rxglompkts),
1644 bus->dhd->rx_packets);
1645 dhd_dump_pct(strbuf, ", pkts/glom", bus->rxglompkts, bus->rxglomframes);
1646 bcm_bprintf(strbuf, "\n");
1648 dhd_dump_pct(strbuf, "Tx: pkts/f2wr", bus->dhd->tx_packets, bus->f2txdata);
1649 dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->tx_packets, bus->f1regdata);
1650 dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->tx_packets,
1651 (bus->f2txdata + bus->f1regdata));
1652 dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->tx_packets, bus->intrcount);
1653 bcm_bprintf(strbuf, "\n");
1655 dhd_dump_pct(strbuf, "Total: pkts/f2rw",
1656 (bus->dhd->tx_packets + bus->dhd->rx_packets),
1657 (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata));
1658 dhd_dump_pct(strbuf, ", pkts/f1sd",
1659 (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->f1regdata);
1660 dhd_dump_pct(strbuf, ", pkts/sd",
1661 (bus->dhd->tx_packets + bus->dhd->rx_packets),
1662 (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata));
1663 dhd_dump_pct(strbuf, ", pkts/int",
1664 (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->intrcount);
1665 bcm_bprintf(strbuf, "\n\n");
1669 if (bus->pktgen_count) {
1670 bcm_bprintf(strbuf, "pktgen config and count:\n");
1671 bcm_bprintf(strbuf, "freq %d count %d print %d total %d min %d len %d\n",
1672 bus->pktgen_freq, bus->pktgen_count, bus->pktgen_print,
1673 bus->pktgen_total, bus->pktgen_minlen, bus->pktgen_maxlen);
1674 bcm_bprintf(strbuf, "send attempts %d rcvd %d fail %d\n",
1675 bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail);
1679 bcm_bprintf(strbuf, "dpc_sched %d host interrupt%spending\n",
1680 bus->dpc_sched, (bcmsdh_intr_pending(bus->sdh) ? " " : " not "));
1681 bcm_bprintf(strbuf, "blocksize %d roundup %d\n", bus->blocksize, bus->roundup);
1682 #endif /* DHD_DEBUG */
1683 bcm_bprintf(strbuf, "clkstate %d activity %d idletime %d idlecount %d sleeping %d\n",
1684 bus->clkstate, bus->activity, bus->idletime, bus->idlecount, bus->sleeping);
1688 dhd_bus_clearcounts(dhd_pub_t *dhdp)
1690 dhd_bus_t *bus = (dhd_bus_t *)dhdp->bus;
1692 bus->intrcount = bus->lastintrs = bus->spurious = bus->regfails = 0;
1693 bus->rxrtx = bus->rx_toolong = bus->rxc_errors = 0;
1694 bus->rx_hdrfail = bus->rx_badhdr = bus->rx_badseq = 0;
1695 bus->tx_sderrs = bus->fc_rcvd = bus->fc_xoff = bus->fc_xon = 0;
1696 bus->rxglomfail = bus->rxglomframes = bus->rxglompkts = 0;
1697 bus->f2rxhdrs = bus->f2rxdata = bus->f2txdata = bus->f1regdata = 0;
1702 dhdsdio_pktgen_get(dhd_bus_t *bus, uint8 *arg)
1704 dhd_pktgen_t pktgen;
1706 pktgen.version = DHD_PKTGEN_VERSION;
1707 pktgen.freq = bus->pktgen_freq;
1708 pktgen.count = bus->pktgen_count;
1709 pktgen.print = bus->pktgen_print;
1710 pktgen.total = bus->pktgen_total;
1711 pktgen.minlen = bus->pktgen_minlen;
1712 pktgen.maxlen = bus->pktgen_maxlen;
1713 pktgen.numsent = bus->pktgen_sent;
1714 pktgen.numrcvd = bus->pktgen_rcvd;
1715 pktgen.numfail = bus->pktgen_fail;
1716 pktgen.mode = bus->pktgen_mode;
1717 pktgen.stop = bus->pktgen_stop;
1719 bcopy(&pktgen, arg, sizeof(pktgen));
1725 dhdsdio_pktgen_set(dhd_bus_t *bus, uint8 *arg)
1727 dhd_pktgen_t pktgen;
1728 uint oldcnt, oldmode;
1730 bcopy(arg, &pktgen, sizeof(pktgen));
1731 if (pktgen.version != DHD_PKTGEN_VERSION)
1734 oldcnt = bus->pktgen_count;
1735 oldmode = bus->pktgen_mode;
1737 bus->pktgen_freq = pktgen.freq;
1738 bus->pktgen_count = pktgen.count;
1739 bus->pktgen_print = pktgen.print;
1740 bus->pktgen_total = pktgen.total;
1741 bus->pktgen_minlen = pktgen.minlen;
1742 bus->pktgen_maxlen = pktgen.maxlen;
1743 bus->pktgen_mode = pktgen.mode;
1744 bus->pktgen_stop = pktgen.stop;
1746 bus->pktgen_tick = bus->pktgen_ptick = 0;
1747 bus->pktgen_len = MAX(bus->pktgen_len, bus->pktgen_minlen);
1748 bus->pktgen_len = MIN(bus->pktgen_len, bus->pktgen_maxlen);
1750 /* Clear counts for a new pktgen (mode change, or was stopped) */
1751 if (bus->pktgen_count && (!oldcnt || oldmode != bus->pktgen_mode))
1752 bus->pktgen_sent = bus->pktgen_rcvd = bus->pktgen_fail = 0;
1759 dhdsdio_membytes(dhd_bus_t *bus, bool write, uint32 address, uint8 *data, uint size)
1765 /* Determine initial transfer parameters */
1766 sdaddr = address & SBSDIO_SB_OFT_ADDR_MASK;
1767 if ((sdaddr + size) & SBSDIO_SBWINDOW_MASK)
1768 dsize = (SBSDIO_SB_OFT_ADDR_LIMIT - sdaddr);
1772 /* Set the backplane window to include the start address */
1773 if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) {
1774 DHD_ERROR(("%s: window change failed\n", __FUNCTION__));
1778 /* Do the transfer(s) */
1780 DHD_INFO(("%s: %s %d bytes at offset 0x%08x in window 0x%08x\n",
1781 __FUNCTION__, (write ? "write" : "read"), dsize, sdaddr,
1782 (address & SBSDIO_SBWINDOW_MASK)));
1783 if ((bcmerror = bcmsdh_rwdata(bus->sdh, write, sdaddr, data, dsize))) {
1784 DHD_ERROR(("%s: membytes transfer failed\n", __FUNCTION__));
1788 /* Adjust for next transfer (if any) */
1789 if ((size -= dsize)) {
1792 if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) {
1793 DHD_ERROR(("%s: window change failed\n", __FUNCTION__));
1797 dsize = MIN(SBSDIO_SB_OFT_ADDR_LIMIT, size);
1803 /* Return the window to backplane enumeration space for core access */
1804 if (dhdsdio_set_siaddr_window(bus, bcmsdh_cur_sbwad(bus->sdh))) {
1805 DHD_ERROR(("%s: FAILED to set window back to 0x%x\n", __FUNCTION__,
1806 bcmsdh_cur_sbwad(bus->sdh)));
1814 dhdsdio_readshared(dhd_bus_t *bus, sdpcm_shared_t *sh)
1819 /* Read last word in memory to determine address of sdpcm_shared structure */
1820 if ((rv = dhdsdio_membytes(bus, FALSE, bus->ramsize - 4, (uint8 *)&addr, 4)) < 0)
1823 addr = ltoh32(addr);
1825 DHD_INFO(("sdpcm_shared address 0x%08X\n", addr));
1828 * Check if addr is valid.
1829 * NVRAM length at the end of memory should have been overwritten.
1831 if (addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff)) {
1832 DHD_ERROR(("%s: address (0x%08x) of sdpcm_shared invalid\n", __FUNCTION__, addr));
1836 /* Read hndrte_shared structure */
1837 if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)sh, sizeof(sdpcm_shared_t))) < 0)
1841 sh->flags = ltoh32(sh->flags);
1842 sh->trap_addr = ltoh32(sh->trap_addr);
1843 sh->assert_exp_addr = ltoh32(sh->assert_exp_addr);
1844 sh->assert_file_addr = ltoh32(sh->assert_file_addr);
1845 sh->assert_line = ltoh32(sh->assert_line);
1846 sh->console_addr = ltoh32(sh->console_addr);
1847 sh->msgtrace_addr = ltoh32(sh->msgtrace_addr);
1849 if ((sh->flags & SDPCM_SHARED_VERSION_MASK) != SDPCM_SHARED_VERSION) {
1850 DHD_ERROR(("%s: sdpcm_shared version %d in dhd "
1851 "is different than sdpcm_shared version %d in dongle\n",
1852 __FUNCTION__, SDPCM_SHARED_VERSION,
1853 sh->flags & SDPCM_SHARED_VERSION_MASK));
1860 #define CONSOLE_LINE_MAX 192
1863 dhdsdio_readconsole(dhd_bus_t *bus)
1865 dhd_console_t *c = &bus->console;
1866 uint8 line[CONSOLE_LINE_MAX], ch;
1867 uint32 n, idx, addr;
1870 /* Don't do anything until FWREADY updates console address */
1871 if (bus->console_addr == 0)
1874 /* Read console log struct */
1875 addr = bus->console_addr + OFFSETOF(hndrte_cons_t, log);
1876 if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)&c->log, sizeof(c->log))) < 0)
1879 /* Allocate console buffer (one time only) */
1880 if (c->buf == NULL) {
1881 c->bufsize = ltoh32(c->log.buf_size);
1882 if ((c->buf = MALLOC(bus->dhd->osh, c->bufsize)) == NULL)
1886 idx = ltoh32(c->log.idx);
1888 /* Protect against corrupt value */
1889 if (idx > c->bufsize)
1892 /* Skip reading the console buffer if the index pointer has not moved */
1896 /* Read the console buffer */
1897 addr = ltoh32(c->log.buf);
1898 if ((rv = dhdsdio_membytes(bus, FALSE, addr, c->buf, c->bufsize)) < 0)
1901 while (c->last != idx) {
1902 for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) {
1903 if (c->last == idx) {
1904 /* This would output a partial line. Instead, back up
1905 * the buffer pointer and output this line next time around.
1910 c->last = c->bufsize - n;
1913 ch = c->buf[c->last];
1914 c->last = (c->last + 1) % c->bufsize;
1921 if (line[n - 1] == '\r')
1924 printf("CONSOLE: %s\n", line);
1933 dhdsdio_checkdied(dhd_bus_t *bus, uint8 *data, uint size)
1937 char *mbuffer = NULL;
1938 uint maxstrlen = 256;
1941 sdpcm_shared_t sdpcm_shared;
1942 struct bcmstrbuf strbuf;
1944 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1948 * Called after a rx ctrl timeout. "data" is NULL.
1949 * allocate memory to trace the trap or assert.
1952 mbuffer = data = MALLOC(bus->dhd->osh, msize);
1953 if (mbuffer == NULL) {
1954 DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, msize));
1955 bcmerror = BCME_NOMEM;
1960 if ((str = MALLOC(bus->dhd->osh, maxstrlen)) == NULL) {
1961 DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, maxstrlen));
1962 bcmerror = BCME_NOMEM;
1966 if ((bcmerror = dhdsdio_readshared(bus, &sdpcm_shared)) < 0)
1969 bcm_binit(&strbuf, data, size);
1971 bcm_bprintf(&strbuf, "msgtrace address : 0x%08X\nconsole address : 0x%08X\n",
1972 sdpcm_shared.msgtrace_addr, sdpcm_shared.console_addr);
1974 if ((sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT) == 0) {
1975 /* NOTE: Misspelled assert is intentional - DO NOT FIX.
1976 * (Avoids conflict with real asserts for programmatic parsing of output.)
1978 bcm_bprintf(&strbuf, "Assrt not built in dongle\n");
1981 if ((sdpcm_shared.flags & (SDPCM_SHARED_ASSERT|SDPCM_SHARED_TRAP)) == 0) {
1982 /* NOTE: Misspelled assert is intentional - DO NOT FIX.
1983 * (Avoids conflict with real asserts for programmatic parsing of output.)
1985 bcm_bprintf(&strbuf, "No trap%s in dongle",
1986 (sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT)
1989 if (sdpcm_shared.flags & SDPCM_SHARED_ASSERT) {
1990 /* Download assert */
1991 bcm_bprintf(&strbuf, "Dongle assert");
1992 if (sdpcm_shared.assert_exp_addr != 0) {
1994 if ((bcmerror = dhdsdio_membytes(bus, FALSE,
1995 sdpcm_shared.assert_exp_addr,
1996 (uint8 *)str, maxstrlen)) < 0)
1999 str[maxstrlen - 1] = '\0';
2000 bcm_bprintf(&strbuf, " expr \"%s\"", str);
2003 if (sdpcm_shared.assert_file_addr != 0) {
2005 if ((bcmerror = dhdsdio_membytes(bus, FALSE,
2006 sdpcm_shared.assert_file_addr,
2007 (uint8 *)str, maxstrlen)) < 0)
2010 str[maxstrlen - 1] = '\0';
2011 bcm_bprintf(&strbuf, " file \"%s\"", str);
2014 bcm_bprintf(&strbuf, " line %d ", sdpcm_shared.assert_line);
2017 if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) {
2018 if ((bcmerror = dhdsdio_membytes(bus, FALSE,
2019 sdpcm_shared.trap_addr,
2020 (uint8*)&tr, sizeof(trap_t))) < 0)
2023 bcm_bprintf(&strbuf,
2024 "Dongle trap type 0x%x @ epc 0x%x, cpsr 0x%x, spsr 0x%x, sp 0x%x,"
2025 "lp 0x%x, rpc 0x%x Trap offset 0x%x, "
2026 "r0 0x%x, r1 0x%x, r2 0x%x, r3 0x%x, r4 0x%x, r5 0x%x, r6 0x%x, r7 0x%x\n",
2027 ltoh32(tr.type), ltoh32(tr.epc), ltoh32(tr.cpsr), ltoh32(tr.spsr),
2028 ltoh32(tr.r13), ltoh32(tr.r14), ltoh32(tr.pc),
2029 ltoh32(sdpcm_shared.trap_addr),
2030 ltoh32(tr.r0), ltoh32(tr.r1), ltoh32(tr.r2), ltoh32(tr.r3),
2031 ltoh32(tr.r4), ltoh32(tr.r5), ltoh32(tr.r6), ltoh32(tr.r7));
2035 if (sdpcm_shared.flags & (SDPCM_SHARED_ASSERT | SDPCM_SHARED_TRAP)) {
2036 DHD_ERROR(("%s: %s\n", __FUNCTION__, strbuf.origbuf));
2040 if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) {
2041 /* Mem dump to a file on device */
2042 dhdsdio_mem_dump(bus);
2044 #endif /* DHD_DEBUG */
2048 MFREE(bus->dhd->osh, mbuffer, msize);
2050 MFREE(bus->dhd->osh, str, maxstrlen);
2056 dhdsdio_mem_dump(dhd_bus_t *bus)
2059 int size; /* Full mem size */
2060 int start = 0; /* Start address */
2061 int read_size = 0; /* Read size of each iteration */
2062 uint8 *buf = NULL, *databuf = NULL;
2064 /* Get full mem size */
2065 size = bus->ramsize;
2066 buf = MALLOC(bus->dhd->osh, size);
2068 printf("%s: Out of memory (%d bytes)\n", __FUNCTION__, size);
2072 /* Read mem content */
2073 printf("Dump dongle memory");
2077 read_size = MIN(MEMBLOCK, size);
2078 if ((ret = dhdsdio_membytes(bus, FALSE, start, databuf, read_size)))
2080 printf("%s: Error membytes %d\n", __FUNCTION__, ret);
2082 MFREE(bus->dhd->osh, buf, size);
2088 /* Decrement size and increment start address */
2091 databuf += read_size;
2095 /* free buf before return !!! */
2096 if (write_to_file(bus->dhd, buf, bus->ramsize))
2098 printf("%s: Error writing to files\n", __FUNCTION__);
2102 /* buf free handled in write_to_file, not here */
2105 #endif /* defined(DHD_DEBUG) */
2108 dhdsdio_downloadvars(dhd_bus_t *bus, void *arg, int len)
2110 int bcmerror = BCME_OK;
2112 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2114 /* Basic sanity checks */
2116 bcmerror = BCME_NOTDOWN;
2120 bcmerror = BCME_BUFTOOSHORT;
2124 /* Free the old ones and replace with passed variables */
2126 MFREE(bus->dhd->osh, bus->vars, bus->varsz);
2128 bus->vars = MALLOC(bus->dhd->osh, len);
2129 bus->varsz = bus->vars ? len : 0;
2130 if (bus->vars == NULL) {
2131 bcmerror = BCME_NOMEM;
2135 /* Copy the passed variables, which should include the terminating double-null */
2136 bcopy(arg, bus->vars, bus->varsz);
2143 #define CC_PLL_CHIPCTRL_SERIAL_ENAB (1 << 24)
2145 dhd_serialconsole(dhd_bus_t *bus, bool set, bool enable, int *bcmerror)
2151 addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr);
2152 data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data);
2155 bcmsdh_reg_write(bus->sdh, addr, 4, 1);
2156 if (bcmsdh_regfail(bus->sdh)) {
2157 *bcmerror = BCME_SDIO_ERROR;
2160 int_val = bcmsdh_reg_read(bus->sdh, data, 4);
2161 if (bcmsdh_regfail(bus->sdh)) {
2162 *bcmerror = BCME_SDIO_ERROR;
2166 return (int_val & CC_PLL_CHIPCTRL_SERIAL_ENAB);
2168 int_val |= CC_PLL_CHIPCTRL_SERIAL_ENAB;
2170 int_val &= ~CC_PLL_CHIPCTRL_SERIAL_ENAB;
2171 bcmsdh_reg_write(bus->sdh, data, 4, int_val);
2172 if (bcmsdh_regfail(bus->sdh)) {
2173 *bcmerror = BCME_SDIO_ERROR;
2176 if (bus->sih->chip == BCM4330_CHIP_ID) {
2178 addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol);
2179 chipcontrol = bcmsdh_reg_read(bus->sdh, addr, 4);
2180 chipcontrol &= ~0x8;
2183 chipcontrol &= ~0x3;
2185 bcmsdh_reg_write(bus->sdh, addr, 4, chipcontrol);
2188 return (int_val & CC_PLL_CHIPCTRL_SERIAL_ENAB);
2193 dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const char *name,
2194 void *params, int plen, void *arg, int len, int val_size)
2200 DHD_TRACE(("%s: Enter, action %d name %s params %p plen %d arg %p len %d val_size %d\n",
2201 __FUNCTION__, actionid, name, params, plen, arg, len, val_size));
2203 if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0)
2206 if (plen >= (int)sizeof(int_val))
2207 bcopy(params, &int_val, sizeof(int_val));
2209 bool_val = (int_val != 0) ? TRUE : FALSE;
2212 /* Some ioctls use the bus */
2213 dhd_os_sdlock(bus->dhd);
2215 /* Check if dongle is in reset. If so, only allow DEVRESET iovars */
2216 if (bus->dhd->dongle_reset && !(actionid == IOV_SVAL(IOV_DEVRESET) ||
2217 actionid == IOV_GVAL(IOV_DEVRESET))) {
2218 bcmerror = BCME_NOTREADY;
2222 /* Handle sleep stuff before any clock mucking */
2223 if (vi->varid == IOV_SLEEP) {
2224 if (IOV_ISSET(actionid)) {
2225 bcmerror = dhdsdio_bussleep(bus, bool_val);
2227 int_val = (int32)bus->sleeping;
2228 bcopy(&int_val, arg, val_size);
2233 /* Request clock to allow SDIO accesses */
2234 if (!bus->dhd->dongle_reset) {
2236 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
2240 case IOV_GVAL(IOV_INTR):
2241 int_val = (int32)bus->intr;
2242 bcopy(&int_val, arg, val_size);
2245 case IOV_SVAL(IOV_INTR):
2246 bus->intr = bool_val;
2247 bus->intdis = FALSE;
2250 DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__));
2251 bcmsdh_intr_enable(bus->sdh);
2253 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
2254 bcmsdh_intr_disable(bus->sdh);
2259 case IOV_GVAL(IOV_POLLRATE):
2260 int_val = (int32)bus->pollrate;
2261 bcopy(&int_val, arg, val_size);
2264 case IOV_SVAL(IOV_POLLRATE):
2265 bus->pollrate = (uint)int_val;
2266 bus->poll = (bus->pollrate != 0);
2269 case IOV_GVAL(IOV_IDLETIME):
2270 int_val = bus->idletime;
2271 bcopy(&int_val, arg, val_size);
2274 case IOV_SVAL(IOV_IDLETIME):
2275 if ((int_val < 0) && (int_val != DHD_IDLE_IMMEDIATE)) {
2276 bcmerror = BCME_BADARG;
2278 bus->idletime = int_val;
2282 case IOV_GVAL(IOV_IDLECLOCK):
2283 int_val = (int32)bus->idleclock;
2284 bcopy(&int_val, arg, val_size);
2287 case IOV_SVAL(IOV_IDLECLOCK):
2288 bus->idleclock = int_val;
2291 case IOV_GVAL(IOV_SD1IDLE):
2292 int_val = (int32)sd1idle;
2293 bcopy(&int_val, arg, val_size);
2296 case IOV_SVAL(IOV_SD1IDLE):
2301 case IOV_SVAL(IOV_MEMBYTES):
2302 case IOV_GVAL(IOV_MEMBYTES):
2308 bool set = (actionid == IOV_SVAL(IOV_MEMBYTES));
2310 ASSERT(plen >= 2*sizeof(int));
2312 address = (uint32)int_val;
2313 bcopy((char *)params + sizeof(int_val), &int_val, sizeof(int_val));
2314 size = (uint)int_val;
2316 /* Do some validation */
2317 dsize = set ? plen - (2 * sizeof(int)) : len;
2319 DHD_ERROR(("%s: error on %s membytes, addr 0x%08x size %d dsize %d\n",
2320 __FUNCTION__, (set ? "set" : "get"), address, size, dsize));
2321 bcmerror = BCME_BADARG;
2325 DHD_INFO(("%s: Request to %s %d bytes at address 0x%08x\n", __FUNCTION__,
2326 (set ? "write" : "read"), size, address));
2328 /* If we know about SOCRAM, check for a fit */
2329 if ((bus->orig_ramsize) &&
2330 ((address > bus->orig_ramsize) || (address + size > bus->orig_ramsize)))
2332 uint8 enable, protect;
2333 si_socdevram(bus->sih, FALSE, &enable, &protect);
2334 if (!enable || protect) {
2335 DHD_ERROR(("%s: ramsize 0x%08x doesn't have %d bytes at 0x%08x\n",
2336 __FUNCTION__, bus->orig_ramsize, size, address));
2337 DHD_ERROR(("%s: socram enable %d, protect %d\n",
2338 __FUNCTION__, enable, protect));
2339 bcmerror = BCME_BADARG;
2342 if (enable && (bus->sih->chip == BCM4330_CHIP_ID)) {
2343 uint32 devramsize = si_socdevram_size(bus->sih);
2344 if ((address < SOCDEVRAM_4330_ARM_ADDR) ||
2345 (address + size > (SOCDEVRAM_4330_ARM_ADDR + devramsize))) {
2346 DHD_ERROR(("%s: bad address 0x%08x, size 0x%08x\n",
2347 __FUNCTION__, address, size));
2348 DHD_ERROR(("%s: socram range 0x%08x,size 0x%08x\n",
2349 __FUNCTION__, SOCDEVRAM_4330_ARM_ADDR, devramsize));
2350 bcmerror = BCME_BADARG;
2353 /* move it such that address is real now */
2354 address -= SOCDEVRAM_4330_ARM_ADDR;
2355 address += SOCDEVRAM_4330_BP_ADDR;
2356 DHD_INFO(("%s: Request to %s %d bytes @ Mapped address 0x%08x\n",
2357 __FUNCTION__, (set ? "write" : "read"), size, address));
2361 /* Generate the actual data pointer */
2362 data = set ? (uint8*)params + 2 * sizeof(int): (uint8*)arg;
2364 /* Call to do the transfer */
2365 bcmerror = dhdsdio_membytes(bus, set, address, data, size);
2370 case IOV_GVAL(IOV_MEMSIZE):
2371 int_val = (int32)bus->ramsize;
2372 bcopy(&int_val, arg, val_size);
2375 case IOV_GVAL(IOV_SDIOD_DRIVE):
2376 int_val = (int32)dhd_sdiod_drive_strength;
2377 bcopy(&int_val, arg, val_size);
2380 case IOV_SVAL(IOV_SDIOD_DRIVE):
2381 dhd_sdiod_drive_strength = int_val;
2382 si_sdiod_drive_strength_init(bus->sih, bus->dhd->osh, dhd_sdiod_drive_strength);
2385 case IOV_SVAL(IOV_DOWNLOAD):
2386 bcmerror = dhdsdio_download_state(bus, bool_val);
2389 case IOV_SVAL(IOV_SOCRAM_STATE):
2390 bcmerror = dhdsdio_download_state(bus, bool_val);
2393 case IOV_SVAL(IOV_VARS):
2394 bcmerror = dhdsdio_downloadvars(bus, arg, len);
2397 case IOV_GVAL(IOV_READAHEAD):
2398 int_val = (int32)dhd_readahead;
2399 bcopy(&int_val, arg, val_size);
2402 case IOV_SVAL(IOV_READAHEAD):
2403 if (bool_val && !dhd_readahead)
2405 dhd_readahead = bool_val;
2408 case IOV_GVAL(IOV_SDRXCHAIN):
2409 int_val = (int32)bus->use_rxchain;
2410 bcopy(&int_val, arg, val_size);
2413 case IOV_SVAL(IOV_SDRXCHAIN):
2414 if (bool_val && !bus->sd_rxchain)
2415 bcmerror = BCME_UNSUPPORTED;
2417 bus->use_rxchain = bool_val;
2419 case IOV_GVAL(IOV_ALIGNCTL):
2420 int_val = (int32)dhd_alignctl;
2421 bcopy(&int_val, arg, val_size);
2424 case IOV_SVAL(IOV_ALIGNCTL):
2425 dhd_alignctl = bool_val;
2428 case IOV_GVAL(IOV_SDALIGN):
2429 int_val = DHD_SDALIGN;
2430 bcopy(&int_val, arg, val_size);
2434 case IOV_GVAL(IOV_VARS):
2435 if (bus->varsz < (uint)len)
2436 bcopy(bus->vars, arg, bus->varsz);
2438 bcmerror = BCME_BUFTOOSHORT;
2440 #endif /* DHD_DEBUG */
2443 case IOV_GVAL(IOV_SDREG):
2448 sd_ptr = (sdreg_t *)params;
2450 addr = (uintptr)bus->regs + sd_ptr->offset;
2451 size = sd_ptr->func;
2452 int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size);
2453 if (bcmsdh_regfail(bus->sdh))
2454 bcmerror = BCME_SDIO_ERROR;
2455 bcopy(&int_val, arg, sizeof(int32));
2459 case IOV_SVAL(IOV_SDREG):
2464 sd_ptr = (sdreg_t *)params;
2466 addr = (uintptr)bus->regs + sd_ptr->offset;
2467 size = sd_ptr->func;
2468 bcmsdh_reg_write(bus->sdh, addr, size, sd_ptr->value);
2469 if (bcmsdh_regfail(bus->sdh))
2470 bcmerror = BCME_SDIO_ERROR;
2474 /* Same as above, but offset is not backplane (not SDIO core) */
2475 case IOV_GVAL(IOV_SBREG):
2480 bcopy(params, &sdreg, sizeof(sdreg));
2482 addr = SI_ENUM_BASE + sdreg.offset;
2484 int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size);
2485 if (bcmsdh_regfail(bus->sdh))
2486 bcmerror = BCME_SDIO_ERROR;
2487 bcopy(&int_val, arg, sizeof(int32));
2491 case IOV_SVAL(IOV_SBREG):
2496 bcopy(params, &sdreg, sizeof(sdreg));
2498 addr = SI_ENUM_BASE + sdreg.offset;
2500 bcmsdh_reg_write(bus->sdh, addr, size, sdreg.value);
2501 if (bcmsdh_regfail(bus->sdh))
2502 bcmerror = BCME_SDIO_ERROR;
2506 case IOV_GVAL(IOV_SDCIS):
2510 bcmstrcat(arg, "\nFunc 0\n");
2511 bcmsdh_cis_read(bus->sdh, 0x10, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
2512 bcmstrcat(arg, "\nFunc 1\n");
2513 bcmsdh_cis_read(bus->sdh, 0x11, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
2514 bcmstrcat(arg, "\nFunc 2\n");
2515 bcmsdh_cis_read(bus->sdh, 0x12, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
2519 case IOV_GVAL(IOV_FORCEEVEN):
2520 int_val = (int32)forcealign;
2521 bcopy(&int_val, arg, val_size);
2524 case IOV_SVAL(IOV_FORCEEVEN):
2525 forcealign = bool_val;
2528 case IOV_GVAL(IOV_TXBOUND):
2529 int_val = (int32)dhd_txbound;
2530 bcopy(&int_val, arg, val_size);
2533 case IOV_SVAL(IOV_TXBOUND):
2534 dhd_txbound = (uint)int_val;
2537 case IOV_GVAL(IOV_RXBOUND):
2538 int_val = (int32)dhd_rxbound;
2539 bcopy(&int_val, arg, val_size);
2542 case IOV_SVAL(IOV_RXBOUND):
2543 dhd_rxbound = (uint)int_val;
2546 case IOV_GVAL(IOV_TXMINMAX):
2547 int_val = (int32)dhd_txminmax;
2548 bcopy(&int_val, arg, val_size);
2551 case IOV_SVAL(IOV_TXMINMAX):
2552 dhd_txminmax = (uint)int_val;
2555 case IOV_GVAL(IOV_SERIALCONS):
2556 int_val = dhd_serialconsole(bus, FALSE, 0, &bcmerror);
2560 bcopy(&int_val, arg, val_size);
2563 case IOV_SVAL(IOV_SERIALCONS):
2564 dhd_serialconsole(bus, TRUE, bool_val, &bcmerror);
2569 #endif /* DHD_DEBUG */
2573 case IOV_GVAL(IOV_EXTLOOP):
2574 int_val = (int32)bus->ext_loop;
2575 bcopy(&int_val, arg, val_size);
2578 case IOV_SVAL(IOV_EXTLOOP):
2579 bus->ext_loop = bool_val;
2582 case IOV_GVAL(IOV_PKTGEN):
2583 bcmerror = dhdsdio_pktgen_get(bus, arg);
2586 case IOV_SVAL(IOV_PKTGEN):
2587 bcmerror = dhdsdio_pktgen_set(bus, arg);
2592 case IOV_GVAL(IOV_DONGLEISOLATION):
2593 int_val = bus->dhd->dongle_isolation;
2594 bcopy(&int_val, arg, val_size);
2597 case IOV_SVAL(IOV_DONGLEISOLATION):
2598 bus->dhd->dongle_isolation = bool_val;
2601 case IOV_SVAL(IOV_DEVRESET):
2602 DHD_TRACE(("%s: Called set IOV_DEVRESET=%d dongle_reset=%d busstate=%d\n",
2603 __FUNCTION__, bool_val, bus->dhd->dongle_reset,
2604 bus->dhd->busstate));
2606 ASSERT(bus->dhd->osh);
2607 /* ASSERT(bus->cl_devid); */
2609 dhd_bus_devreset(bus->dhd, (uint8)bool_val);
2613 case IOV_GVAL(IOV_FWPATH):
2617 fw_path_len = strlen(bus->fw_path);
2618 DHD_INFO(("[softap] get fwpath, l=%d\n", len));
2620 if (fw_path_len > len-1) {
2621 bcmerror = BCME_BUFTOOSHORT;
2626 bcopy(bus->fw_path, arg, fw_path_len);
2627 ((uchar*)arg)[fw_path_len] = 0;
2632 case IOV_SVAL(IOV_FWPATH):
2633 DHD_INFO(("[softap] set fwpath, idx=%d\n", int_val));
2637 bus->fw_path = fw_path; /* ordinary one */
2640 bus->fw_path = fw_path2;
2643 bcmerror = BCME_BADARG;
2647 DHD_INFO(("[softap] new fw path: %s\n", (bus->fw_path[0] ? bus->fw_path : "NULL")));
2651 case IOV_GVAL(IOV_DEVRESET):
2652 DHD_TRACE(("%s: Called get IOV_DEVRESET\n", __FUNCTION__));
2654 /* Get its status */
2655 int_val = (bool) bus->dhd->dongle_reset;
2656 bcopy(&int_val, arg, val_size);
2661 bcmerror = BCME_UNSUPPORTED;
2666 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
2667 bus->activity = FALSE;
2668 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
2671 dhd_os_sdunlock(bus->dhd);
2673 if (actionid == IOV_SVAL(IOV_DEVRESET) && bool_val == FALSE)
2674 dhd_preinit_ioctls((dhd_pub_t *) bus->dhd);
2680 dhdsdio_write_vars(dhd_bus_t *bus)
2688 uint8 *nvram_ularray;
2689 #endif /* DHD_DEBUG */
2691 /* Even if there are no vars are to be written, we still need to set the ramsize. */
2692 varsize = bus->varsz ? ROUNDUP(bus->varsz, 4) : 0;
2693 varaddr = (bus->ramsize - 4) - varsize;
2696 if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 7)) {
2697 if (((varaddr & 0x3C) == 0x3C) && (varsize > 4)) {
2698 DHD_ERROR(("PR85623WAR in place\n"));
2704 vbuffer = (uint8 *)MALLOC(bus->dhd->osh, varsize);
2708 bzero(vbuffer, varsize);
2709 bcopy(bus->vars, vbuffer, bus->varsz);
2711 /* Write the vars list */
2712 bcmerror = dhdsdio_membytes(bus, TRUE, varaddr, vbuffer, varsize);
2714 /* Verify NVRAM bytes */
2715 DHD_INFO(("Compare NVRAM dl & ul; varsize=%d\n", varsize));
2716 nvram_ularray = (uint8*)MALLOC(bus->dhd->osh, varsize);
2720 /* Upload image to verify downloaded contents. */
2721 memset(nvram_ularray, 0xaa, varsize);
2723 /* Read the vars list to temp buffer for comparison */
2724 bcmerror = dhdsdio_membytes(bus, FALSE, varaddr, nvram_ularray, varsize);
2726 DHD_ERROR(("%s: error %d on reading %d nvram bytes at 0x%08x\n",
2727 __FUNCTION__, bcmerror, varsize, varaddr));
2729 /* Compare the org NVRAM with the one read from RAM */
2730 if (memcmp(vbuffer, nvram_ularray, varsize)) {
2731 DHD_ERROR(("%s: Downloaded NVRAM image is corrupted.\n", __FUNCTION__));
2733 DHD_ERROR(("%s: Download, Upload and compare of NVRAM succeeded.\n",
2736 MFREE(bus->dhd->osh, nvram_ularray, varsize);
2737 #endif /* DHD_DEBUG */
2739 MFREE(bus->dhd->osh, vbuffer, varsize);
2742 /* adjust to the user specified RAM */
2743 DHD_INFO(("Physical memory size: %d, usable memory size: %d\n",
2744 bus->orig_ramsize, bus->ramsize));
2745 DHD_INFO(("Vars are at %d, orig varsize is %d\n",
2747 varsize = ((bus->orig_ramsize - 4) - varaddr);
2750 * Determine the length token:
2751 * Varsize, converted to words, in lower 16-bits, checksum in upper 16-bits.
2756 varsizew = varsize / 4;
2757 varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF);
2758 varsizew = htol32(varsizew);
2761 DHD_INFO(("New varsize is %d, length token=0x%08x\n", varsize, varsizew));
2763 /* Write the length token to the last word */
2764 bcmerror = dhdsdio_membytes(bus, TRUE, (bus->orig_ramsize - 4),
2765 (uint8*)&varsizew, 4);
2771 dhdsdio_download_state(dhd_bus_t *bus, bool enter)
2776 /* To enter download state, disable ARM and reset SOCRAM.
2777 * To exit download state, simply reset ARM (default is RAM boot).
2780 bus->alp_only = TRUE;
2782 if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) &&
2783 !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) {
2784 DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__));
2785 bcmerror = BCME_ERROR;
2789 si_core_disable(bus->sih, 0);
2790 if (bcmsdh_regfail(bus->sdh)) {
2791 bcmerror = BCME_SDIO_ERROR;
2795 if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) {
2796 DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__));
2797 bcmerror = BCME_ERROR;
2801 si_core_reset(bus->sih, 0, 0);
2802 if (bcmsdh_regfail(bus->sdh)) {
2803 DHD_ERROR(("%s: Failure trying reset SOCRAM core?\n", __FUNCTION__));
2804 bcmerror = BCME_SDIO_ERROR;
2808 /* Clear the top bit of memory */
2811 if (dhdsdio_membytes(bus, TRUE, bus->ramsize - 4, (uint8*)&zeros, 4) < 0) {
2812 bcmerror = BCME_SDIO_ERROR;
2817 if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) {
2818 DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__));
2819 bcmerror = BCME_ERROR;
2823 if (!si_iscoreup(bus->sih)) {
2824 DHD_ERROR(("%s: SOCRAM core is down after reset?\n", __FUNCTION__));
2825 bcmerror = BCME_ERROR;
2829 if ((bcmerror = dhdsdio_write_vars(bus))) {
2830 DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__));
2834 if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) &&
2835 !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) {
2836 DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__));
2837 bcmerror = BCME_ERROR;
2840 W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries);
2843 if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) &&
2844 !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) {
2845 DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__));
2846 bcmerror = BCME_ERROR;
2850 si_core_reset(bus->sih, 0, 0);
2851 if (bcmsdh_regfail(bus->sdh)) {
2852 DHD_ERROR(("%s: Failure trying to reset ARM core?\n", __FUNCTION__));
2853 bcmerror = BCME_SDIO_ERROR;
2857 /* Allow HT Clock now that the ARM is running. */
2858 bus->alp_only = FALSE;
2860 bus->dhd->busstate = DHD_BUS_LOAD;
2864 /* Always return to SDIOD core */
2865 if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0))
2866 si_setcore(bus->sih, SDIOD_CORE_ID, 0);
2872 dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name,
2873 void *params, int plen, void *arg, int len, bool set)
2875 dhd_bus_t *bus = dhdp->bus;
2876 const bcm_iovar_t *vi = NULL;
2881 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2886 /* Get MUST have return space */
2887 ASSERT(set || (arg && len));
2889 /* Set does NOT take qualifiers */
2890 ASSERT(!set || (!params && !plen));
2892 /* Look up var locally; if not found pass to host driver */
2893 if ((vi = bcm_iovar_lookup(dhdsdio_iovars, name)) == NULL) {
2894 dhd_os_sdlock(bus->dhd);
2898 /* Turn on clock in case SD command needs backplane */
2899 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
2901 bcmerror = bcmsdh_iovar_op(bus->sdh, name, params, plen, arg, len, set);
2903 /* Check for bus configuration changes of interest */
2905 /* If it was divisor change, read the new one */
2906 if (set && strcmp(name, "sd_divisor") == 0) {
2907 if (bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
2908 &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) {
2909 bus->sd_divisor = -1;
2910 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, name));
2912 DHD_INFO(("%s: noted %s update, value now %d\n",
2913 __FUNCTION__, name, bus->sd_divisor));
2916 /* If it was a mode change, read the new one */
2917 if (set && strcmp(name, "sd_mode") == 0) {
2918 if (bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
2919 &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) {
2921 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, name));
2923 DHD_INFO(("%s: noted %s update, value now %d\n",
2924 __FUNCTION__, name, bus->sd_mode));
2927 /* Similar check for blocksize change */
2928 if (set && strcmp(name, "sd_blocksize") == 0) {
2930 if (bcmsdh_iovar_op(bus->sdh, "sd_blocksize", &fnum, sizeof(int32),
2931 &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) {
2933 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize"));
2935 DHD_INFO(("%s: noted %s update, value now %d\n",
2936 __FUNCTION__, "sd_blocksize", bus->blocksize));
2939 bus->roundup = MIN(max_roundup, bus->blocksize);
2941 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
2942 bus->activity = FALSE;
2943 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
2946 dhd_os_sdunlock(bus->dhd);
2950 DHD_CTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__,
2951 name, (set ? "set" : "get"), len, plen));
2953 /* set up 'params' pointer in case this is a set command so that
2954 * the convenience int and bool code can be common to set and get
2956 if (params == NULL) {
2961 if (vi->type == IOVT_VOID)
2963 else if (vi->type == IOVT_BUFFER)
2966 /* all other types are integer sized */
2967 val_size = sizeof(int);
2969 actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
2970 bcmerror = dhdsdio_doiovar(bus, vi, actionid, name, params, plen, arg, len, val_size);
2977 dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex)
2980 uint32 local_hostintmask;
2987 osh = bus->dhd->osh;
2988 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2990 bcmsdh_waitlockfree(NULL);
2993 dhd_os_sdlock(bus->dhd);
2997 /* Change our idea of bus state */
2998 bus->dhd->busstate = DHD_BUS_DOWN;
3000 /* Enable clock for device interrupts */
3001 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
3003 /* Disable and clear interrupts at the chip level also */
3004 W_SDREG(0, &bus->regs->hostintmask, retries);
3005 local_hostintmask = bus->hostintmask;
3006 bus->hostintmask = 0;
3008 /* Force clocks on backplane to be sure F2 interrupt propagates */
3009 saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
3011 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
3012 (saveclk | SBSDIO_FORCE_HT), &err);
3015 DHD_ERROR(("%s: Failed to force clock for F2: err %d\n", __FUNCTION__, err));
3018 /* Turn off the bus (F2), free any pending packets */
3019 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
3020 bcmsdh_intr_disable(bus->sdh);
3021 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL);
3023 /* Clear any pending interrupts now that F2 is disabled */
3024 W_SDREG(local_hostintmask, &bus->regs->intstatus, retries);
3026 /* Turn off the backplane clock (only) */
3027 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
3029 /* Clear the data packet queues */
3030 pktq_flush(osh, &bus->txq, TRUE, NULL, 0);
3032 /* Clear any held glomming stuff */
3034 PKTFREE(osh, bus->glomd, FALSE);
3037 PKTFREE(osh, bus->glom, FALSE);
3039 bus->glom = bus->glomd = NULL;
3041 /* Clear rx control and wake any waiters */
3043 dhd_os_ioctl_resp_wake(bus->dhd);
3045 /* Reset some F2 state stuff */
3046 bus->rxskip = FALSE;
3047 bus->tx_seq = bus->rx_seq = 0;
3050 dhd_os_sdunlock(bus->dhd);
3054 dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex)
3056 dhd_bus_t *bus = dhdp->bus;
3059 uint8 ready, enable;
3063 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3070 dhd_os_sdlock(bus->dhd);
3072 /* Make sure backplane clock is on, needed to generate F2 interrupt */
3073 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
3074 if (bus->clkstate != CLK_AVAIL) {
3075 DHD_ERROR(("%s: clock state is wrong. state = %d\n", __FUNCTION__, bus->clkstate));
3080 /* Force clocks on backplane to be sure F2 interrupt propagates */
3081 saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
3083 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
3084 (saveclk | SBSDIO_FORCE_HT), &err);
3087 DHD_ERROR(("%s: Failed to force clock for F2: err %d\n", __FUNCTION__, err));
3091 /* Enable function 2 (frame transfers) */
3092 W_SDREG((SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT),
3093 &bus->regs->tosbmailboxdata, retries);
3094 enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2);
3096 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL);
3098 /* Give the dongle some time to do its thing and set IOR2 */
3099 dhd_timeout_start(&tmo, DHD_WAIT_F2RDY * 1000);
3102 while (ready != enable && !dhd_timeout_expired(&tmo))
3103 ready = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IORDY, NULL);
3106 DHD_INFO(("%s: enable 0x%02x, ready 0x%02x (waited %uus)\n",
3107 __FUNCTION__, enable, ready, tmo.elapsed));
3110 /* If F2 successfully enabled, set core and enable interrupts */
3111 if (ready == enable) {
3112 /* Make sure we're talking to the core. */
3113 if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0)))
3114 bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0);
3115 ASSERT(bus->regs != NULL);
3117 /* Set up the interrupt mask and enable interrupts */
3118 bus->hostintmask = HOSTINTMASK;
3119 /* corerev 4 could use the newer interrupt logic to detect the frames */
3120 if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 4) &&
3121 (bus->rxint_mode != SDIO_DEVICE_HMB_RXINT)) {
3122 bus->hostintmask &= ~I_HMB_FRAME_IND;
3123 bus->hostintmask |= I_XMTDATA_AVAIL;
3125 W_SDREG(bus->hostintmask, &bus->regs->hostintmask, retries);
3127 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, (uint8)watermark, &err);
3129 /* Set bus state according to enable result */
3130 dhdp->busstate = DHD_BUS_DATA;
3132 /* bcmsdh_intr_unmask(bus->sdh); */
3134 bus->intdis = FALSE;
3136 DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__));
3137 bcmsdh_intr_enable(bus->sdh);
3139 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
3140 bcmsdh_intr_disable(bus->sdh);
3147 /* Disable F2 again */
3148 enable = SDIO_FUNC_ENABLE_1;
3149 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL);
3152 /* Restore previous clock setting */
3153 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err);
3156 /* If we didn't come up, turn off backplane clock */
3157 if (dhdp->busstate != DHD_BUS_DATA)
3158 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
3162 dhd_os_sdunlock(bus->dhd);
3168 dhdsdio_rxfail(dhd_bus_t *bus, bool abort, bool rtx)
3170 bcmsdh_info_t *sdh = bus->sdh;
3171 sdpcmd_regs_t *regs = bus->regs;
3177 DHD_ERROR(("%s: %sterminate frame%s\n", __FUNCTION__,
3178 (abort ? "abort command, " : ""), (rtx ? ", send NAK" : "")));
3181 bcmsdh_abort(sdh, SDIO_FUNC_2);
3184 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, SFC_RF_TERM, &err);
3187 /* Wait until the packet has been flushed (device/FIFO stable) */
3188 for (lastrbc = retries = 0xffff; retries > 0; retries--) {
3189 hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCHI, NULL);
3190 lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCLO, NULL);
3191 bus->f1regdata += 2;
3193 if ((hi == 0) && (lo == 0))
3196 if ((hi > (lastrbc >> 8)) && (lo > (lastrbc & 0x00ff))) {
3197 DHD_ERROR(("%s: count growing: last 0x%04x now 0x%04x\n",
3198 __FUNCTION__, lastrbc, ((hi << 8) + lo)));
3200 lastrbc = (hi << 8) + lo;
3204 DHD_ERROR(("%s: count never zeroed: last 0x%04x\n", __FUNCTION__, lastrbc));
3206 DHD_INFO(("%s: flush took %d iterations\n", __FUNCTION__, (0xffff - retries)));
3211 W_SDREG(SMB_NAK, ®s->tosbmailbox, retries);
3213 if (retries <= retry_limit) {
3218 /* Clear partial in any case */
3221 /* If we can't reach the device, signal failure */
3222 if (err || bcmsdh_regfail(sdh))
3223 bus->dhd->busstate = DHD_BUS_DOWN;
3227 dhdsdio_read_control(dhd_bus_t *bus, uint8 *hdr, uint len, uint doff)
3229 bcmsdh_info_t *sdh = bus->sdh;
3234 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3236 /* Control data already received in aligned rxctl */
3237 if ((bus->bus == SPI_BUS) && (!bus->usebufpool))
3241 /* Set rxctl for frame (w/optional alignment) */
3242 bus->rxctl = bus->rxbuf;
3244 bus->rxctl += firstread;
3245 if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN)))
3246 bus->rxctl += (DHD_SDALIGN - pad);
3247 bus->rxctl -= firstread;
3249 ASSERT(bus->rxctl >= bus->rxbuf);
3251 /* Copy the already-read portion over */
3252 bcopy(hdr, bus->rxctl, firstread);
3253 if (len <= firstread)
3256 /* Copy the full data pkt in gSPI case and process ioctl. */
3257 if (bus->bus == SPI_BUS) {
3258 bcopy(hdr, bus->rxctl, len);
3262 /* Raise rdlen to next SDIO block to avoid tail command */
3263 rdlen = len - firstread;
3264 if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
3265 pad = bus->blocksize - (rdlen % bus->blocksize);
3266 if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
3267 ((len + pad) < bus->dhd->maxctl))
3269 } else if (rdlen % DHD_SDALIGN) {
3270 rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
3273 /* Satisfy length-alignment requirements */
3274 if (forcealign && (rdlen & (ALIGNMENT - 1)))
3275 rdlen = ROUNDUP(rdlen, ALIGNMENT);
3277 /* Drop if the read is too big or it exceeds our maximum */
3278 if ((rdlen + firstread) > bus->dhd->maxctl) {
3279 DHD_ERROR(("%s: %d-byte control read exceeds %d-byte buffer\n",
3280 __FUNCTION__, rdlen, bus->dhd->maxctl));
3281 bus->dhd->rx_errors++;
3282 dhdsdio_rxfail(bus, FALSE, FALSE);
3286 if ((len - doff) > bus->dhd->maxctl) {
3287 DHD_ERROR(("%s: %d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n",
3288 __FUNCTION__, len, (len - doff), bus->dhd->maxctl));
3289 bus->dhd->rx_errors++; bus->rx_toolong++;
3290 dhdsdio_rxfail(bus, FALSE, FALSE);
3295 /* Read remainder of frame body into the rxctl buffer */
3296 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
3297 (bus->rxctl + firstread), rdlen, NULL, NULL, NULL);
3299 ASSERT(sdret != BCME_PENDING);
3301 /* Control frame failures need retransmission */
3303 DHD_ERROR(("%s: read %d control bytes failed: %d\n", __FUNCTION__, rdlen, sdret));
3304 bus->rxc_errors++; /* dhd.rx_ctlerrs is higher level */
3305 dhdsdio_rxfail(bus, TRUE, TRUE);
3312 if (DHD_BYTES_ON() && DHD_CTL_ON()) {
3313 prhex("RxCtrl", bus->rxctl, len);
3317 /* Point to valid data and indicate its length */
3319 bus->rxlen = len - doff;
3322 /* Awake any waiters */
3323 dhd_os_ioctl_resp_wake(bus->dhd);
3327 dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq)
3329 uint16 dlen, totlen;
3330 uint8 *dptr, num = 0;
3332 uint16 sublen, check;
3333 void *pfirst, *plast, *pnext, *save_pfirst;
3334 osl_t *osh = bus->dhd->osh;
3337 uint8 chan, seq, doff, sfdoff;
3341 bool usechain = bus->use_rxchain;
3343 /* If packets, issue read(s) and send up packet chain */
3344 /* Return sequence numbers consumed? */
3346 DHD_TRACE(("dhdsdio_rxglom: start: glomd %p glom %p\n", bus->glomd, bus->glom));
3348 /* If there's a descriptor, generate the packet chain */
3350 dhd_os_sdlock_rxq(bus->dhd);
3352 pfirst = plast = pnext = NULL;
3353 dlen = (uint16)PKTLEN(osh, bus->glomd);
3354 dptr = PKTDATA(osh, bus->glomd);
3355 if (!dlen || (dlen & 1)) {
3356 DHD_ERROR(("%s: bad glomd len (%d), ignore descriptor\n",
3357 __FUNCTION__, dlen));
3361 for (totlen = num = 0; dlen; num++) {
3362 /* Get (and move past) next length */
3363 sublen = ltoh16_ua(dptr);
3364 dlen -= sizeof(uint16);
3365 dptr += sizeof(uint16);
3366 if ((sublen < SDPCM_HDRLEN) ||
3367 ((num == 0) && (sublen < (2 * SDPCM_HDRLEN)))) {
3368 DHD_ERROR(("%s: descriptor len %d bad: %d\n",
3369 __FUNCTION__, num, sublen));
3373 if (sublen % DHD_SDALIGN) {
3374 DHD_ERROR(("%s: sublen %d not a multiple of %d\n",
3375 __FUNCTION__, sublen, DHD_SDALIGN));
3380 /* For last frame, adjust read len so total is a block multiple */
3382 sublen += (ROUNDUP(totlen, bus->blocksize) - totlen);
3383 totlen = ROUNDUP(totlen, bus->blocksize);
3386 /* Allocate/chain packet for next subframe */
3387 if ((pnext = PKTGET(osh, sublen + DHD_SDALIGN, FALSE)) == NULL) {
3388 DHD_ERROR(("%s: PKTGET failed, num %d len %d\n",
3389 __FUNCTION__, num, sublen));
3392 ASSERT(!PKTLINK(pnext));
3395 pfirst = plast = pnext;
3398 PKTSETNEXT(osh, plast, pnext);
3402 /* Adhere to start alignment requirements */
3403 PKTALIGN(osh, pnext, sublen, DHD_SDALIGN);
3406 /* If all allocations succeeded, save packet chain in bus structure */
3408 DHD_GLOM(("%s: allocated %d-byte packet chain for %d subframes\n",
3409 __FUNCTION__, totlen, num));
3410 if (DHD_GLOM_ON() && bus->nextlen) {
3411 if (totlen != bus->nextlen) {
3412 DHD_GLOM(("%s: glomdesc mismatch: nextlen %d glomdesc %d "
3413 "rxseq %d\n", __FUNCTION__, bus->nextlen,
3418 pfirst = pnext = NULL;
3421 PKTFREE(osh, pfirst, FALSE);
3426 /* Done with descriptor packet */
3427 PKTFREE(osh, bus->glomd, FALSE);
3431 dhd_os_sdunlock_rxq(bus->dhd);
3434 /* Ok -- either we just generated a packet chain, or had one from before */
3436 if (DHD_GLOM_ON()) {
3437 DHD_GLOM(("%s: attempt superframe read, packet chain:\n", __FUNCTION__));
3438 for (pnext = bus->glom; pnext; pnext = PKTNEXT(osh, pnext)) {
3439 DHD_GLOM((" %p: %p len 0x%04x (%d)\n",
3440 pnext, (uint8*)PKTDATA(osh, pnext),
3441 PKTLEN(osh, pnext), PKTLEN(osh, pnext)));
3446 dlen = (uint16)pkttotlen(osh, pfirst);
3448 /* Do an SDIO read for the superframe. Configurable iovar to
3449 * read directly into the chained packet, or allocate a large
3450 * packet and and copy into the chain.
3453 errcode = dhd_bcmsdh_recv_buf(bus,
3454 bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2,
3455 F2SYNC, (uint8*)PKTDATA(osh, pfirst),
3456 dlen, pfirst, NULL, NULL);
3457 } else if (bus->dataptr) {
3458 errcode = dhd_bcmsdh_recv_buf(bus,
3459 bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2,
3460 F2SYNC, bus->dataptr,
3461 dlen, NULL, NULL, NULL);
3462 sublen = (uint16)pktfrombuf(osh, pfirst, 0, dlen, bus->dataptr);
3463 if (sublen != dlen) {
3464 DHD_ERROR(("%s: FAILED TO COPY, dlen %d sublen %d\n",
3465 __FUNCTION__, dlen, sublen));
3470 DHD_ERROR(("COULDN'T ALLOC %d-BYTE GLOM, FORCE FAILURE\n", dlen));
3474 ASSERT(errcode != BCME_PENDING);
3476 /* On failure, kill the superframe, allow a couple retries */
3478 DHD_ERROR(("%s: glom read of %d bytes failed: %d\n",
3479 __FUNCTION__, dlen, errcode));
3480 bus->dhd->rx_errors++;
3482 if (bus->glomerr++ < 3) {
3483 dhdsdio_rxfail(bus, TRUE, TRUE);
3486 dhdsdio_rxfail(bus, TRUE, FALSE);
3487 dhd_os_sdlock_rxq(bus->dhd);
3488 PKTFREE(osh, bus->glom, FALSE);
3489 dhd_os_sdunlock_rxq(bus->dhd);
3497 if (DHD_GLOM_ON()) {
3498 prhex("SUPERFRAME", PKTDATA(osh, pfirst),
3499 MIN(PKTLEN(osh, pfirst), 48));
3504 /* Validate the superframe header */
3505 dptr = (uint8 *)PKTDATA(osh, pfirst);
3506 sublen = ltoh16_ua(dptr);
3507 check = ltoh16_ua(dptr + sizeof(uint16));
3509 chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
3510 seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
3511 bus->nextlen = dptr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
3512 if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
3513 DHD_INFO(("%s: got frame w/nextlen too large (%d) seq %d\n",
3514 __FUNCTION__, bus->nextlen, seq));
3517 doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
3518 txmax = SDPCM_WINDOW_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
3521 if ((uint16)~(sublen^check)) {
3522 DHD_ERROR(("%s (superframe): HW hdr error: len/check 0x%04x/0x%04x\n",
3523 __FUNCTION__, sublen, check));
3525 } else if (ROUNDUP(sublen, bus->blocksize) != dlen) {
3526 DHD_ERROR(("%s (superframe): len 0x%04x, rounded 0x%04x, expect 0x%04x\n",
3527 __FUNCTION__, sublen, ROUNDUP(sublen, bus->blocksize), dlen));
3529 } else if (SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]) != SDPCM_GLOM_CHANNEL) {
3530 DHD_ERROR(("%s (superframe): bad channel %d\n", __FUNCTION__,
3531 SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN])));
3533 } else if (SDPCM_GLOMDESC(&dptr[SDPCM_FRAMETAG_LEN])) {
3534 DHD_ERROR(("%s (superframe): got second descriptor?\n", __FUNCTION__));
3536 } else if ((doff < SDPCM_HDRLEN) ||
3537 (doff > (PKTLEN(osh, pfirst) - SDPCM_HDRLEN))) {
3538 DHD_ERROR(("%s (superframe): Bad data offset %d: HW %d pkt %d min %d\n",
3539 __FUNCTION__, doff, sublen, PKTLEN(osh, pfirst), SDPCM_HDRLEN));
3543 /* Check sequence number of superframe SW header */
3545 DHD_INFO(("%s: (superframe) rx_seq %d, expected %d\n",
3546 __FUNCTION__, seq, rxseq));
3551 /* Check window for sanity */
3552 if ((uint8)(txmax - bus->tx_seq) > 0x40) {
3553 DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
3554 __FUNCTION__, txmax, bus->tx_seq));
3555 txmax = bus->tx_seq + 2;
3557 bus->tx_max = txmax;
3559 /* Remove superframe header, remember offset */
3560 PKTPULL(osh, pfirst, doff);
3563 /* Validate all the subframe headers */
3564 for (num = 0, pnext = pfirst; pnext && !errcode;
3565 num++, pnext = PKTNEXT(osh, pnext)) {
3566 dptr = (uint8 *)PKTDATA(osh, pnext);
3567 dlen = (uint16)PKTLEN(osh, pnext);
3568 sublen = ltoh16_ua(dptr);
3569 check = ltoh16_ua(dptr + sizeof(uint16));
3570 chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
3571 doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
3573 if (DHD_GLOM_ON()) {
3574 prhex("subframe", dptr, 32);
3578 if ((uint16)~(sublen^check)) {
3579 DHD_ERROR(("%s (subframe %d): HW hdr error: "
3580 "len/check 0x%04x/0x%04x\n",
3581 __FUNCTION__, num, sublen, check));
3583 } else if ((sublen > dlen) || (sublen < SDPCM_HDRLEN)) {
3584 DHD_ERROR(("%s (subframe %d): length mismatch: "
3585 "len 0x%04x, expect 0x%04x\n",
3586 __FUNCTION__, num, sublen, dlen));
3588 } else if ((chan != SDPCM_DATA_CHANNEL) &&
3589 (chan != SDPCM_EVENT_CHANNEL)) {
3590 DHD_ERROR(("%s (subframe %d): bad channel %d\n",
3591 __FUNCTION__, num, chan));
3593 } else if ((doff < SDPCM_HDRLEN) || (doff > sublen)) {
3594 DHD_ERROR(("%s (subframe %d): Bad data offset %d: HW %d min %d\n",
3595 __FUNCTION__, num, doff, sublen, SDPCM_HDRLEN));
3601 /* Terminate frame on error, request a couple retries */
3602 if (bus->glomerr++ < 3) {
3603 /* Restore superframe header space */
3604 PKTPUSH(osh, pfirst, sfdoff);
3605 dhdsdio_rxfail(bus, TRUE, TRUE);
3608 dhdsdio_rxfail(bus, TRUE, FALSE);
3609 dhd_os_sdlock_rxq(bus->dhd);
3610 PKTFREE(osh, bus->glom, FALSE);
3611 dhd_os_sdunlock_rxq(bus->dhd);
3619 /* Basic SD framing looks ok - process each packet (header) */
3620 save_pfirst = pfirst;
3624 dhd_os_sdlock_rxq(bus->dhd);
3625 for (num = 0; pfirst; rxseq++, pfirst = pnext) {
3626 pnext = PKTNEXT(osh, pfirst);
3627 PKTSETNEXT(osh, pfirst, NULL);
3629 dptr = (uint8 *)PKTDATA(osh, pfirst);
3630 sublen = ltoh16_ua(dptr);
3631 chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
3632 seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
3633 doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
3635 DHD_GLOM(("%s: Get subframe %d, %p(%p/%d), sublen %d chan %d seq %d\n",
3636 __FUNCTION__, num, pfirst, PKTDATA(osh, pfirst),
3637 PKTLEN(osh, pfirst), sublen, chan, seq));
3639 ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL));
3642 DHD_GLOM(("%s: rx_seq %d, expected %d\n",
3643 __FUNCTION__, seq, rxseq));
3649 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
3650 prhex("Rx Subframe Data", dptr, dlen);
3654 PKTSETLEN(osh, pfirst, sublen);
3655 PKTPULL(osh, pfirst, doff);
3657 if (PKTLEN(osh, pfirst) == 0) {
3658 PKTFREE(bus->dhd->osh, pfirst, FALSE);
3660 PKTSETNEXT(osh, plast, pnext);
3662 ASSERT(save_pfirst == pfirst);
3663 save_pfirst = pnext;
3666 } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pfirst) != 0) {
3667 DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__));
3668 bus->dhd->rx_errors++;
3669 PKTFREE(osh, pfirst, FALSE);
3671 PKTSETNEXT(osh, plast, pnext);
3673 ASSERT(save_pfirst == pfirst);
3674 save_pfirst = pnext;
3679 /* this packet will go up, link back into chain and count it */
3680 PKTSETNEXT(osh, pfirst, pnext);
3685 if (DHD_GLOM_ON()) {
3686 DHD_GLOM(("%s subframe %d to stack, %p(%p/%d) nxt/lnk %p/%p\n",
3687 __FUNCTION__, num, pfirst,
3688 PKTDATA(osh, pfirst), PKTLEN(osh, pfirst),
3689 PKTNEXT(osh, pfirst), PKTLINK(pfirst)));
3690 prhex("", (uint8 *)PKTDATA(osh, pfirst),
3691 MIN(PKTLEN(osh, pfirst), 32));
3693 #endif /* DHD_DEBUG */
3695 dhd_os_sdunlock_rxq(bus->dhd);
3697 dhd_os_sdunlock(bus->dhd);
3698 dhd_rx_frame(bus->dhd, ifidx, save_pfirst, num, 0);
3699 dhd_os_sdlock(bus->dhd);
3702 bus->rxglomframes++;
3703 bus->rxglompkts += num;
3708 /* Return TRUE if there may be more frames to read */
3710 dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished)
3712 osl_t *osh = bus->dhd->osh;
3713 bcmsdh_info_t *sdh = bus->sdh;
3715 uint16 len, check; /* Extracted hardware header fields */
3716 uint8 chan, seq, doff; /* Extracted software header fields */
3717 uint8 fcbits; /* Extracted fcbits from software header */
3720 void *pkt; /* Packet for event or data frames */
3721 uint16 pad; /* Number of pad bytes to read */
3722 uint16 rdlen; /* Total number of bytes to read */
3723 uint8 rxseq; /* Next sequence number to expect */
3724 uint rxleft = 0; /* Remaining number of frames allowed */
3725 int sdret; /* Return code from bcmsdh calls */
3726 uint8 txmax; /* Maximum tx sequence offered */
3727 bool len_consistent; /* Result of comparing readahead len and len from hw-hdr */
3730 uint rxcount = 0; /* Total frames read */
3732 #if defined(DHD_DEBUG) || defined(SDTEST)
3733 bool sdtest = FALSE; /* To limit message spew from test mode */
3736 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3741 /* Allow pktgen to override maxframes */
3742 if (bus->pktgen_count && (bus->pktgen_mode == DHD_PKTGEN_RECV)) {
3743 maxframes = bus->pktgen_count;
3748 /* Not finished unless we encounter no more frames indication */
3752 for (rxseq = bus->rx_seq, rxleft = maxframes;
3753 !bus->rxskip && rxleft && bus->dhd->busstate != DHD_BUS_DOWN;
3754 rxseq++, rxleft--) {
3756 /* Handle glomming separately */
3757 if (bus->glom || bus->glomd) {
3759 DHD_GLOM(("%s: calling rxglom: glomd %p, glom %p\n",
3760 __FUNCTION__, bus->glomd, bus->glom));
3761 cnt = dhdsdio_rxglom(bus, rxseq);
3762 DHD_GLOM(("%s: rxglom returned %d\n", __FUNCTION__, cnt));
3764 rxleft = (rxleft > cnt) ? (rxleft - cnt) : 1;
3768 /* Try doing single read if we can */
3769 if (dhd_readahead && bus->nextlen) {
3770 uint16 nextlen = bus->nextlen;
3773 if (bus->bus == SPI_BUS) {
3774 rdlen = len = nextlen;
3777 rdlen = len = nextlen << 4;
3779 /* Pad read to blocksize for efficiency */
3780 if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
3781 pad = bus->blocksize - (rdlen % bus->blocksize);
3782 if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
3783 ((rdlen + pad + firstread) < MAX_RX_DATASZ))
3785 } else if (rdlen % DHD_SDALIGN) {
3786 rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
3790 /* We use bus->rxctl buffer in WinXP for initial control pkt receives.
3791 * Later we use buffer-poll for data as well as control packets.
3792 * This is required because dhd receives full frame in gSPI unlike SDIO.
3793 * After the frame is received we have to distinguish whether it is data
3794 * or non-data frame.
3796 /* Allocate a packet buffer */
3797 dhd_os_sdlock_rxq(bus->dhd);
3798 if (!(pkt = PKTGET(osh, rdlen + DHD_SDALIGN, FALSE))) {
3799 if (bus->bus == SPI_BUS) {
3800 bus->usebufpool = FALSE;
3801 bus->rxctl = bus->rxbuf;
3803 bus->rxctl += firstread;
3804 if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN)))
3805 bus->rxctl += (DHD_SDALIGN - pad);
3806 bus->rxctl -= firstread;
3808 ASSERT(bus->rxctl >= bus->rxbuf);
3810 /* Read the entire frame */
3811 sdret = dhd_bcmsdh_recv_buf(bus,
3812 bcmsdh_cur_sbwad(sdh),
3814 F2SYNC, rxbuf, rdlen,
3817 ASSERT(sdret != BCME_PENDING);
3820 /* Control frame failures need retransmission */
3822 DHD_ERROR(("%s: read %d control bytes failed: %d\n",
3823 __FUNCTION__, rdlen, sdret));
3824 /* dhd.rx_ctlerrs is higher level */
3826 dhd_os_sdunlock_rxq(bus->dhd);
3827 dhdsdio_rxfail(bus, TRUE,
3828 (bus->bus == SPI_BUS) ? FALSE : TRUE);
3832 /* Give up on data, request rtx of events */
3833 DHD_ERROR(("%s (nextlen): PKTGET failed: len %d rdlen %d "
3834 "expected rxseq %d\n",
3835 __FUNCTION__, len, rdlen, rxseq));
3836 /* Just go try again w/normal header read */
3837 dhd_os_sdunlock_rxq(bus->dhd);
3841 if (bus->bus == SPI_BUS)
3842 bus->usebufpool = TRUE;
3844 ASSERT(!PKTLINK(pkt));
3845 PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN);
3846 rxbuf = (uint8 *)PKTDATA(osh, pkt);
3847 /* Read the entire frame */
3848 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh),
3850 F2SYNC, rxbuf, rdlen,
3853 ASSERT(sdret != BCME_PENDING);
3856 DHD_ERROR(("%s (nextlen): read %d bytes failed: %d\n",
3857 __FUNCTION__, rdlen, sdret));
3858 PKTFREE(bus->dhd->osh, pkt, FALSE);
3859 bus->dhd->rx_errors++;
3860 dhd_os_sdunlock_rxq(bus->dhd);
3861 /* Force retry w/normal header read. Don't attempt NAK for
3864 dhdsdio_rxfail(bus, TRUE,
3865 (bus->bus == SPI_BUS) ? FALSE : TRUE);
3869 dhd_os_sdunlock_rxq(bus->dhd);
3871 /* Now check the header */
3872 bcopy(rxbuf, bus->rxhdr, SDPCM_HDRLEN);
3874 /* Extract hardware header fields */
3875 len = ltoh16_ua(bus->rxhdr);
3876 check = ltoh16_ua(bus->rxhdr + sizeof(uint16));
3878 /* All zeros means readahead info was bad */
3880 DHD_INFO(("%s (nextlen): read zeros in HW header???\n",
3882 dhd_os_sdlock_rxq(bus->dhd);
3884 dhd_os_sdunlock_rxq(bus->dhd);
3885 GSPI_PR55150_BAILOUT;
3889 /* Validate check bytes */
3890 if ((uint16)~(len^check)) {
3891 DHD_ERROR(("%s (nextlen): HW hdr error: nextlen/len/check"
3892 " 0x%04x/0x%04x/0x%04x\n", __FUNCTION__, nextlen,
3894 dhd_os_sdlock_rxq(bus->dhd);
3896 dhd_os_sdunlock_rxq(bus->dhd);
3898 dhdsdio_rxfail(bus, FALSE, FALSE);
3899 GSPI_PR55150_BAILOUT;
3903 /* Validate frame length */
3904 if (len < SDPCM_HDRLEN) {
3905 DHD_ERROR(("%s (nextlen): HW hdr length invalid: %d\n",
3906 __FUNCTION__, len));
3907 dhd_os_sdlock_rxq(bus->dhd);
3909 dhd_os_sdunlock_rxq(bus->dhd);
3910 GSPI_PR55150_BAILOUT;
3914 /* Check for consistency with readahead info */
3915 len_consistent = (nextlen != (ROUNDUP(len, 16) >> 4));
3916 if (len_consistent) {
3917 /* Mismatch, force retry w/normal header (may be >4K) */
3918 DHD_ERROR(("%s (nextlen): mismatch, nextlen %d len %d rnd %d; "
3919 "expected rxseq %d\n",
3920 __FUNCTION__, nextlen, len, ROUNDUP(len, 16), rxseq));
3921 dhd_os_sdlock_rxq(bus->dhd);
3923 dhd_os_sdunlock_rxq(bus->dhd);
3924 dhdsdio_rxfail(bus, TRUE, (bus->bus == SPI_BUS) ? FALSE : TRUE);
3925 GSPI_PR55150_BAILOUT;
3930 /* Extract software header fields */
3931 chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
3932 seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
3933 doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
3934 txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
3937 bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
3938 if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
3939 DHD_INFO(("%s (nextlen): got frame w/nextlen too large"
3940 " (%d), seq %d\n", __FUNCTION__, bus->nextlen,
3945 bus->dhd->rx_readahead_cnt ++;
3946 /* Handle Flow Control */
3947 fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
3950 if (~bus->flowcontrol & fcbits) {
3954 if (bus->flowcontrol & ~fcbits) {
3961 bus->flowcontrol = fcbits;
3964 /* Check and update sequence number */
3966 DHD_INFO(("%s (nextlen): rx_seq %d, expected %d\n",
3967 __FUNCTION__, seq, rxseq));
3972 /* Check window for sanity */
3973 if ((uint8)(txmax - bus->tx_seq) > 0x40) {
3974 DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
3975 __FUNCTION__, txmax, bus->tx_seq));
3976 txmax = bus->tx_seq + 2;
3978 bus->tx_max = txmax;
3981 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
3982 prhex("Rx Data", rxbuf, len);
3983 } else if (DHD_HDRS_ON()) {
3984 prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN);
3988 if (chan == SDPCM_CONTROL_CHANNEL) {
3989 if (bus->bus == SPI_BUS) {
3990 dhdsdio_read_control(bus, rxbuf, len, doff);
3991 if (bus->usebufpool) {
3992 dhd_os_sdlock_rxq(bus->dhd);
3993 PKTFREE(bus->dhd->osh, pkt, FALSE);
3994 dhd_os_sdunlock_rxq(bus->dhd);
3998 DHD_ERROR(("%s (nextlen): readahead on control"
3999 " packet %d?\n", __FUNCTION__, seq));
4000 /* Force retry w/normal header read */
4002 dhdsdio_rxfail(bus, FALSE, TRUE);
4003 dhd_os_sdlock_rxq(bus->dhd);
4005 dhd_os_sdunlock_rxq(bus->dhd);
4010 if ((bus->bus == SPI_BUS) && !bus->usebufpool) {
4011 DHD_ERROR(("Received %d bytes on %d channel. Running out of "
4012 "rx pktbuf's or not yet malloced.\n", len, chan));
4016 /* Validate data offset */
4017 if ((doff < SDPCM_HDRLEN) || (doff > len)) {
4018 DHD_ERROR(("%s (nextlen): bad data offset %d: HW len %d min %d\n",
4019 __FUNCTION__, doff, len, SDPCM_HDRLEN));
4020 dhd_os_sdlock_rxq(bus->dhd);
4022 dhd_os_sdunlock_rxq(bus->dhd);
4024 dhdsdio_rxfail(bus, FALSE, FALSE);
4028 /* All done with this one -- now deliver the packet */
4031 /* gSPI frames should not be handled in fractions */
4032 if (bus->bus == SPI_BUS) {
4036 /* Read frame header (hardware and software) */
4037 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
4038 bus->rxhdr, firstread, NULL, NULL, NULL);
4040 ASSERT(sdret != BCME_PENDING);
4043 DHD_ERROR(("%s: RXHEADER FAILED: %d\n", __FUNCTION__, sdret));
4045 dhdsdio_rxfail(bus, TRUE, TRUE);
4050 if (DHD_BYTES_ON() || DHD_HDRS_ON()) {
4051 prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN);
4055 /* Extract hardware header fields */
4056 len = ltoh16_ua(bus->rxhdr);
4057 check = ltoh16_ua(bus->rxhdr + sizeof(uint16));
4059 /* All zeros means no more frames */
4065 /* Validate check bytes */
4066 if ((uint16)~(len^check)) {
4067 DHD_ERROR(("%s: HW hdr error: len/check 0x%04x/0x%04x\n",
4068 __FUNCTION__, len, check));
4070 dhdsdio_rxfail(bus, FALSE, FALSE);
4074 /* Validate frame length */
4075 if (len < SDPCM_HDRLEN) {
4076 DHD_ERROR(("%s: HW hdr length invalid: %d\n", __FUNCTION__, len));
4080 /* Extract software header fields */
4081 chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
4082 seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
4083 doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
4084 txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
4086 /* Validate data offset */
4087 if ((doff < SDPCM_HDRLEN) || (doff > len)) {
4088 DHD_ERROR(("%s: Bad data offset %d: HW len %d, min %d seq %d\n",
4089 __FUNCTION__, doff, len, SDPCM_HDRLEN, seq));
4092 dhdsdio_rxfail(bus, FALSE, FALSE);
4096 /* Save the readahead length if there is one */
4097 bus->nextlen = bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
4098 if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
4099 DHD_INFO(("%s (nextlen): got frame w/nextlen too large (%d), seq %d\n",
4100 __FUNCTION__, bus->nextlen, seq));
4104 /* Handle Flow Control */
4105 fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
4108 if (~bus->flowcontrol & fcbits) {
4112 if (bus->flowcontrol & ~fcbits) {
4119 bus->flowcontrol = fcbits;
4122 /* Check and update sequence number */
4124 DHD_INFO(("%s: rx_seq %d, expected %d\n", __FUNCTION__, seq, rxseq));
4129 /* Check window for sanity */
4130 if ((uint8)(txmax - bus->tx_seq) > 0x40) {
4131 DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
4132 __FUNCTION__, txmax, bus->tx_seq));
4133 txmax = bus->tx_seq + 2;
4135 bus->tx_max = txmax;
4137 /* Call a separate function for control frames */
4138 if (chan == SDPCM_CONTROL_CHANNEL) {
4139 dhdsdio_read_control(bus, bus->rxhdr, len, doff);
4143 ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL) ||
4144 (chan == SDPCM_TEST_CHANNEL) || (chan == SDPCM_GLOM_CHANNEL));
4146 /* Length to read */
4147 rdlen = (len > firstread) ? (len - firstread) : 0;
4149 /* May pad read to blocksize for efficiency */
4150 if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
4151 pad = bus->blocksize - (rdlen % bus->blocksize);
4152 if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
4153 ((rdlen + pad + firstread) < MAX_RX_DATASZ))
4155 } else if (rdlen % DHD_SDALIGN) {
4156 rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
4159 /* Satisfy length-alignment requirements */
4160 if (forcealign && (rdlen & (ALIGNMENT - 1)))
4161 rdlen = ROUNDUP(rdlen, ALIGNMENT);
4163 if ((rdlen + firstread) > MAX_RX_DATASZ) {
4164 /* Too long -- skip this frame */
4165 DHD_ERROR(("%s: too long: len %d rdlen %d\n", __FUNCTION__, len, rdlen));
4166 bus->dhd->rx_errors++; bus->rx_toolong++;
4167 dhdsdio_rxfail(bus, FALSE, FALSE);
4171 dhd_os_sdlock_rxq(bus->dhd);
4172 if (!(pkt = PKTGET(osh, (rdlen + firstread + DHD_SDALIGN), FALSE))) {
4173 /* Give up on data, request rtx of events */
4174 DHD_ERROR(("%s: PKTGET failed: rdlen %d chan %d\n",
4175 __FUNCTION__, rdlen, chan));
4176 bus->dhd->rx_dropped++;
4177 dhd_os_sdunlock_rxq(bus->dhd);
4178 dhdsdio_rxfail(bus, FALSE, RETRYCHAN(chan));
4181 dhd_os_sdunlock_rxq(bus->dhd);
4183 ASSERT(!PKTLINK(pkt));
4185 /* Leave room for what we already read, and align remainder */
4186 ASSERT(firstread < (PKTLEN(osh, pkt)));
4187 PKTPULL(osh, pkt, firstread);
4188 PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN);
4190 /* Read the remaining frame data */
4191 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
4192 ((uint8 *)PKTDATA(osh, pkt)), rdlen, pkt, NULL, NULL);
4194 ASSERT(sdret != BCME_PENDING);
4197 DHD_ERROR(("%s: read %d %s bytes failed: %d\n", __FUNCTION__, rdlen,
4198 ((chan == SDPCM_EVENT_CHANNEL) ? "event" :
4199 ((chan == SDPCM_DATA_CHANNEL) ? "data" : "test")), sdret));
4200 dhd_os_sdlock_rxq(bus->dhd);
4201 PKTFREE(bus->dhd->osh, pkt, FALSE);
4202 dhd_os_sdunlock_rxq(bus->dhd);
4203 bus->dhd->rx_errors++;
4204 dhdsdio_rxfail(bus, TRUE, RETRYCHAN(chan));
4208 /* Copy the already-read portion */
4209 PKTPUSH(osh, pkt, firstread);
4210 bcopy(bus->rxhdr, PKTDATA(osh, pkt), firstread);
4213 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
4214 prhex("Rx Data", PKTDATA(osh, pkt), len);
4219 /* Save superframe descriptor and allocate packet frame */
4220 if (chan == SDPCM_GLOM_CHANNEL) {
4221 if (SDPCM_GLOMDESC(&bus->rxhdr[SDPCM_FRAMETAG_LEN])) {
4222 DHD_GLOM(("%s: got glom descriptor, %d bytes:\n",
4223 __FUNCTION__, len));
4225 if (DHD_GLOM_ON()) {
4226 prhex("Glom Data", PKTDATA(osh, pkt), len);
4229 PKTSETLEN(osh, pkt, len);
4230 ASSERT(doff == SDPCM_HDRLEN);
4231 PKTPULL(osh, pkt, SDPCM_HDRLEN);
4234 DHD_ERROR(("%s: glom superframe w/o descriptor!\n", __FUNCTION__));
4235 dhdsdio_rxfail(bus, FALSE, FALSE);
4240 /* Fill in packet len and prio, deliver upward */
4241 PKTSETLEN(osh, pkt, len);
4242 PKTPULL(osh, pkt, doff);
4245 /* Test channel packets are processed separately */
4246 if (chan == SDPCM_TEST_CHANNEL) {
4247 dhdsdio_testrcv(bus, pkt, seq);
4252 if (PKTLEN(osh, pkt) == 0) {
4253 dhd_os_sdlock_rxq(bus->dhd);
4254 PKTFREE(bus->dhd->osh, pkt, FALSE);
4255 dhd_os_sdunlock_rxq(bus->dhd);
4257 } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pkt) != 0) {
4258 DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__));
4259 dhd_os_sdlock_rxq(bus->dhd);
4260 PKTFREE(bus->dhd->osh, pkt, FALSE);
4261 dhd_os_sdunlock_rxq(bus->dhd);
4262 bus->dhd->rx_errors++;
4267 /* Unlock during rx call */
4268 dhd_os_sdunlock(bus->dhd);
4269 dhd_rx_frame(bus->dhd, ifidx, pkt, 1, chan);
4270 dhd_os_sdlock(bus->dhd);
4272 rxcount = maxframes - rxleft;
4274 /* Message if we hit the limit */
4275 if (!rxleft && !sdtest)
4276 DHD_DATA(("%s: hit rx limit of %d frames\n", __FUNCTION__, maxframes));
4278 #endif /* DHD_DEBUG */
4279 DHD_DATA(("%s: processed %d frames\n", __FUNCTION__, rxcount));
4280 /* Back off rxseq if awaiting rtx, update rx_seq */
4283 bus->rx_seq = rxseq;
4289 dhdsdio_hostmail(dhd_bus_t *bus)
4291 sdpcmd_regs_t *regs = bus->regs;
4292 uint32 intstatus = 0;
4297 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4299 /* Read mailbox data and ack that we did so */
4300 R_SDREG(hmb_data, ®s->tohostmailboxdata, retries);
4301 if (retries <= retry_limit)
4302 W_SDREG(SMB_INT_ACK, ®s->tosbmailbox, retries);
4303 bus->f1regdata += 2;
4305 /* Dongle recomposed rx frames, accept them again */
4306 if (hmb_data & HMB_DATA_NAKHANDLED) {
4307 DHD_INFO(("Dongle reports NAK handled, expect rtx of %d\n", bus->rx_seq));
4309 DHD_ERROR(("%s: unexpected NAKHANDLED!\n", __FUNCTION__));
4311 bus->rxskip = FALSE;
4312 intstatus |= FRAME_AVAIL_MASK(bus);
4316 * DEVREADY does not occur with gSPI.
4318 if (hmb_data & (HMB_DATA_DEVREADY | HMB_DATA_FWREADY)) {
4319 bus->sdpcm_ver = (hmb_data & HMB_DATA_VERSION_MASK) >> HMB_DATA_VERSION_SHIFT;
4320 if (bus->sdpcm_ver != SDPCM_PROT_VERSION)
4321 DHD_ERROR(("Version mismatch, dongle reports %d, expecting %d\n",
4322 bus->sdpcm_ver, SDPCM_PROT_VERSION));
4324 DHD_INFO(("Dongle ready, protocol version %d\n", bus->sdpcm_ver));
4325 /* make sure for the SDIO_DEVICE_RXDATAINT_MODE_1 corecontrol is proper */
4326 if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev >= 4) &&
4327 (bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_1)) {
4330 val = R_REG(bus->dhd->osh, &bus->regs->corecontrol);
4331 val &= ~CC_XMTDATAAVAIL_MODE;
4332 val |= CC_XMTDATAAVAIL_CTRL;
4333 W_REG(bus->dhd->osh, &bus->regs->corecontrol, val);
4335 val = R_REG(bus->dhd->osh, &bus->regs->corecontrol);
4339 /* Retrieve console state address now that firmware should have updated it */
4341 sdpcm_shared_t shared;
4342 if (dhdsdio_readshared(bus, &shared) == 0)
4343 bus->console_addr = shared.console_addr;
4345 #endif /* DHD_DEBUG */
4349 * Flow Control has been moved into the RX headers and this out of band
4350 * method isn't used any more. Leave this here for possibly remaining backward
4351 * compatible with older dongles
4353 if (hmb_data & HMB_DATA_FC) {
4354 fcbits = (hmb_data & HMB_DATA_FCDATA_MASK) >> HMB_DATA_FCDATA_SHIFT;
4356 if (fcbits & ~bus->flowcontrol)
4358 if (bus->flowcontrol & ~fcbits)
4362 bus->flowcontrol = fcbits;
4366 /* Shouldn't be any others */
4367 if (hmb_data & ~(HMB_DATA_DEVREADY |
4369 HMB_DATA_NAKHANDLED |
4372 HMB_DATA_FCDATA_MASK |
4373 HMB_DATA_VERSION_MASK)) {
4374 DHD_ERROR(("Unknown mailbox data content: 0x%02x\n", hmb_data));
4381 dhdsdio_dpc(dhd_bus_t *bus)
4383 bcmsdh_info_t *sdh = bus->sdh;
4384 sdpcmd_regs_t *regs = bus->regs;
4385 uint32 intstatus, newstatus = 0;
4387 uint rxlimit = dhd_rxbound; /* Rx frames to read before resched */
4388 uint txlimit = dhd_txbound; /* Tx frames to send before resched */
4389 uint framecnt = 0; /* Temporary counter of tx/rx frames */
4390 bool rxdone = TRUE; /* Flag for no more read data */
4391 bool resched = FALSE; /* Flag indicating resched wanted */
4393 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4395 if (bus->dhd->busstate == DHD_BUS_DOWN) {
4396 DHD_ERROR(("%s: Bus down, ret\n", __FUNCTION__));
4401 /* Start with leftover status bits */
4402 intstatus = bus->intstatus;
4404 dhd_os_sdlock(bus->dhd);
4406 /* If waiting for HTAVAIL, check status */
4407 if (bus->clkstate == CLK_PENDING) {
4409 uint8 clkctl, devctl = 0;
4412 /* Check for inconsistent device control */
4413 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
4415 DHD_ERROR(("%s: error reading DEVCTL: %d\n", __FUNCTION__, err));
4416 bus->dhd->busstate = DHD_BUS_DOWN;
4418 ASSERT(devctl & SBSDIO_DEVCTL_CA_INT_ONLY);
4420 #endif /* DHD_DEBUG */
4422 /* Read CSR, if clock on switch to AVAIL, else ignore */
4423 clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
4425 DHD_ERROR(("%s: error reading CSR: %d\n", __FUNCTION__, err));
4426 bus->dhd->busstate = DHD_BUS_DOWN;
4429 DHD_INFO(("DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n", devctl, clkctl));
4431 if (SBSDIO_HTAV(clkctl)) {
4432 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
4434 DHD_ERROR(("%s: error reading DEVCTL: %d\n",
4435 __FUNCTION__, err));
4436 bus->dhd->busstate = DHD_BUS_DOWN;
4438 devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
4439 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
4441 DHD_ERROR(("%s: error writing DEVCTL: %d\n",
4442 __FUNCTION__, err));
4443 bus->dhd->busstate = DHD_BUS_DOWN;
4445 bus->clkstate = CLK_AVAIL;
4453 /* Make sure backplane clock is on */
4454 dhdsdio_clkctl(bus, CLK_AVAIL, TRUE);
4455 if (bus->clkstate != CLK_AVAIL)
4458 /* Pending interrupt indicates new device status */
4461 R_SDREG(newstatus, ®s->intstatus, retries);
4463 if (bcmsdh_regfail(bus->sdh))
4465 newstatus &= bus->hostintmask;
4466 bus->fcstate = !!(newstatus & I_HMB_FC_STATE);
4469 if ((bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_0) &&
4470 (newstatus == I_XMTDATA_AVAIL)) {
4473 W_SDREG(newstatus, ®s->intstatus, retries);
4477 /* Merge new bits with previous */
4478 intstatus |= newstatus;
4481 /* Handle flow-control change: read new state in case our ack
4482 * crossed another change interrupt. If change still set, assume
4483 * FC ON for safety, let next loop through do the debounce.
4485 if (intstatus & I_HMB_FC_CHANGE) {
4486 intstatus &= ~I_HMB_FC_CHANGE;
4487 W_SDREG(I_HMB_FC_CHANGE, ®s->intstatus, retries);
4488 R_SDREG(newstatus, ®s->intstatus, retries);
4489 bus->f1regdata += 2;
4490 bus->fcstate = !!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE));
4491 intstatus |= (newstatus & bus->hostintmask);
4494 /* Just being here means nothing more to do for chipactive */
4495 if (intstatus & I_CHIPACTIVE) {
4496 /* ASSERT(bus->clkstate == CLK_AVAIL); */
4497 intstatus &= ~I_CHIPACTIVE;
4500 /* Handle host mailbox indication */
4501 if (intstatus & I_HMB_HOST_INT) {
4502 intstatus &= ~I_HMB_HOST_INT;
4503 intstatus |= dhdsdio_hostmail(bus);
4506 /* Generally don't ask for these, can get CRC errors... */
4507 if (intstatus & I_WR_OOSYNC) {
4508 DHD_ERROR(("Dongle reports WR_OOSYNC\n"));
4509 intstatus &= ~I_WR_OOSYNC;
4512 if (intstatus & I_RD_OOSYNC) {
4513 DHD_ERROR(("Dongle reports RD_OOSYNC\n"));
4514 intstatus &= ~I_RD_OOSYNC;
4517 if (intstatus & I_SBINT) {
4518 DHD_ERROR(("Dongle reports SBINT\n"));
4519 intstatus &= ~I_SBINT;
4522 /* Would be active due to wake-wlan in gSPI */
4523 if (intstatus & I_CHIPACTIVE) {
4524 DHD_INFO(("Dongle reports CHIPACTIVE\n"));
4525 intstatus &= ~I_CHIPACTIVE;
4528 /* Ignore frame indications if rxskip is set */
4530 intstatus &= ~FRAME_AVAIL_MASK(bus);
4533 /* On frame indication, read available frames */
4534 if (PKT_AVAILABLE(bus, intstatus)) {
4535 framecnt = dhdsdio_readframes(bus, rxlimit, &rxdone);
4536 if (rxdone || bus->rxskip)
4537 intstatus &= ~FRAME_AVAIL_MASK(bus);
4538 rxlimit -= MIN(framecnt, rxlimit);
4541 /* Keep still-pending events for next scheduling */
4542 bus->intstatus = intstatus;
4545 /* Re-enable interrupts to detect new device events (mailbox, rx frame)
4546 * or clock availability. (Allows tx loop to check ipend if desired.)
4547 * (Unless register access seems hosed, as we may not be able to ACK...)
4549 if (bus->intr && bus->intdis && !bcmsdh_regfail(sdh)) {
4550 DHD_INTR(("%s: enable SDIO interrupts, rxdone %d framecnt %d\n",
4551 __FUNCTION__, rxdone, framecnt));
4552 bus->intdis = FALSE;
4553 #if defined(OOB_INTR_ONLY)
4554 bcmsdh_oob_intr_set(1);
4555 #endif /* (OOB_INTR_ONLY) */
4556 bcmsdh_intr_enable(sdh);
4559 if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL)) {
4562 ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
4563 (uint8 *)bus->ctrl_frame_buf, (uint32)bus->ctrl_frame_len,
4565 ASSERT(ret != BCME_PENDING);
4568 /* On failure, abort the command and terminate the frame */
4569 DHD_INFO(("%s: sdio error %d, abort command and terminate frame.\n",
4570 __FUNCTION__, ret));
4573 bcmsdh_abort(sdh, SDIO_FUNC_2);
4575 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
4579 for (i = 0; i < 3; i++) {
4581 hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
4582 SBSDIO_FUNC1_WFRAMEBCHI, NULL);
4583 lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
4584 SBSDIO_FUNC1_WFRAMEBCLO, NULL);
4585 bus->f1regdata += 2;
4586 if ((hi == 0) && (lo == 0))
4591 bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
4594 bus->ctrl_frame_stat = FALSE;
4595 dhd_wait_event_wakeup(bus->dhd);
4597 /* Send queued frames (limit 1 if rx may still be pending) */
4598 else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate &&
4599 pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit && DATAOK(bus)) {
4600 framecnt = rxdone ? txlimit : MIN(txlimit, dhd_txminmax);
4601 framecnt = dhdsdio_sendfromq(bus, framecnt);
4602 txlimit -= framecnt;
4604 /* Resched the DPC if ctrl cmd is pending on bus credit */
4605 if (bus->ctrl_frame_stat)
4608 /* Resched if events or tx frames are pending, else await next interrupt */
4609 /* On failed register access, all bets are off: no resched or interrupts */
4610 if ((bus->dhd->busstate == DHD_BUS_DOWN) || bcmsdh_regfail(sdh)) {
4611 DHD_ERROR(("%s: failed backplane access over SDIO, halting operation %d \n",
4612 __FUNCTION__, bcmsdh_regfail(sdh)));
4613 bus->dhd->busstate = DHD_BUS_DOWN;
4615 } else if (bus->clkstate == CLK_PENDING) {
4616 /* Awaiting I_CHIPACTIVE; don't resched */
4617 } else if (bus->intstatus || bus->ipend ||
4618 (!bus->fcstate && pktq_mlen(&bus->txq, ~bus->flowcontrol) && DATAOK(bus)) ||
4619 PKT_AVAILABLE(bus, bus->intstatus)) { /* Read multiple frames */
4623 bus->dpc_sched = resched;
4625 /* If we're done for now, turn off clock request. */
4626 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && (bus->clkstate != CLK_PENDING)) {
4627 bus->activity = FALSE;
4628 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
4631 dhd_os_sdunlock(bus->dhd);
4636 dhd_bus_dpc(struct dhd_bus *bus)
4640 /* Call the DPC directly. */
4641 DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__));
4642 resched = dhdsdio_dpc(bus);
4648 dhdsdio_isr(void *arg)
4650 dhd_bus_t *bus = (dhd_bus_t*)arg;
4653 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4656 DHD_ERROR(("%s : bus is null pointer , exit \n", __FUNCTION__));
4661 if (bus->dhd->busstate == DHD_BUS_DOWN) {
4662 DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__));
4666 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4668 /* Count the interrupt call */
4672 /* Shouldn't get this interrupt if we're sleeping? */
4673 if (bus->sleeping) {
4674 DHD_ERROR(("INTERRUPT WHILE SLEEPING??\n"));
4678 /* Disable additional interrupts (is this needed now)? */
4680 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
4682 DHD_ERROR(("dhdsdio_isr() w/o interrupt configured!\n"));
4685 bcmsdh_intr_disable(sdh);
4688 #if defined(SDIO_ISR_THREAD)
4689 DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__));
4690 DHD_OS_WAKE_LOCK(bus->dhd);
4691 while (dhdsdio_dpc(bus));
4692 DHD_OS_WAKE_UNLOCK(bus->dhd);
4694 bus->dpc_sched = TRUE;
4695 dhd_sched_dpc(bus->dhd);
4702 dhdsdio_pktgen_init(dhd_bus_t *bus)
4704 /* Default to specified length, or full range */
4705 if (dhd_pktgen_len) {
4706 bus->pktgen_maxlen = MIN(dhd_pktgen_len, MAX_PKTGEN_LEN);
4707 bus->pktgen_minlen = bus->pktgen_maxlen;
4709 bus->pktgen_maxlen = MAX_PKTGEN_LEN;
4710 bus->pktgen_minlen = 0;
4712 bus->pktgen_len = (uint16)bus->pktgen_minlen;
4714 /* Default to per-watchdog burst with 10s print time */
4715 bus->pktgen_freq = 1;
4716 bus->pktgen_print = 10000 / dhd_watchdog_ms;
4717 bus->pktgen_count = (dhd_pktgen * dhd_watchdog_ms + 999) / 1000;
4719 /* Default to echo mode */
4720 bus->pktgen_mode = DHD_PKTGEN_ECHO;
4721 bus->pktgen_stop = 1;
4725 dhdsdio_pktgen(dhd_bus_t *bus)
4731 osl_t *osh = bus->dhd->osh;
4734 /* Display current count if appropriate */
4735 if (bus->pktgen_print && (++bus->pktgen_ptick >= bus->pktgen_print)) {
4736 bus->pktgen_ptick = 0;
4737 printf("%s: send attempts %d rcvd %d\n",
4738 __FUNCTION__, bus->pktgen_sent, bus->pktgen_rcvd);
4741 /* For recv mode, just make sure dongle has started sending */
4742 if (bus->pktgen_mode == DHD_PKTGEN_RECV) {
4743 if (bus->pktgen_rcv_state == PKTGEN_RCV_IDLE) {
4744 bus->pktgen_rcv_state = PKTGEN_RCV_ONGOING;
4745 dhdsdio_sdtest_set(bus, (uint8)bus->pktgen_total);
4750 /* Otherwise, generate or request the specified number of packets */
4751 for (pktcount = 0; pktcount < bus->pktgen_count; pktcount++) {
4752 /* Stop if total has been reached */
4753 if (bus->pktgen_total && (bus->pktgen_sent >= bus->pktgen_total)) {
4754 bus->pktgen_count = 0;
4758 /* Allocate an appropriate-sized packet */
4759 len = bus->pktgen_len;
4760 if (!(pkt = PKTGET(osh, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN),
4762 DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__));
4765 PKTALIGN(osh, pkt, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN), DHD_SDALIGN);
4766 data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
4768 /* Write test header cmd and extra based on mode */
4769 switch (bus->pktgen_mode) {
4770 case DHD_PKTGEN_ECHO:
4771 *data++ = SDPCM_TEST_ECHOREQ;
4772 *data++ = (uint8)bus->pktgen_sent;
4775 case DHD_PKTGEN_SEND:
4776 *data++ = SDPCM_TEST_DISCARD;
4777 *data++ = (uint8)bus->pktgen_sent;
4780 case DHD_PKTGEN_RXBURST:
4781 *data++ = SDPCM_TEST_BURST;
4782 *data++ = (uint8)bus->pktgen_count;
4786 DHD_ERROR(("Unrecognized pktgen mode %d\n", bus->pktgen_mode));
4787 PKTFREE(osh, pkt, TRUE);
4788 bus->pktgen_count = 0;
4792 /* Write test header length field */
4793 *data++ = (len >> 0);
4794 *data++ = (len >> 8);
4796 /* Then fill in the remainder -- N/A for burst, but who cares... */
4797 for (fillbyte = 0; fillbyte < len; fillbyte++)
4798 *data++ = SDPCM_TEST_FILL(fillbyte, (uint8)bus->pktgen_sent);
4801 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
4802 data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
4803 prhex("dhdsdio_pktgen: Tx Data", data, PKTLEN(osh, pkt) - SDPCM_HDRLEN);
4808 if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE)) {
4810 if (bus->pktgen_stop && bus->pktgen_stop == bus->pktgen_fail)
4811 bus->pktgen_count = 0;
4815 /* Bump length if not fixed, wrap at max */
4816 if (++bus->pktgen_len > bus->pktgen_maxlen)
4817 bus->pktgen_len = (uint16)bus->pktgen_minlen;
4819 /* Special case for burst mode: just send one request! */
4820 if (bus->pktgen_mode == DHD_PKTGEN_RXBURST)
4826 dhdsdio_sdtest_set(dhd_bus_t *bus, uint8 count)
4830 osl_t *osh = bus->dhd->osh;
4832 /* Allocate the packet */
4833 if (!(pkt = PKTGET(osh, SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN, TRUE))) {
4834 DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__));
4837 PKTALIGN(osh, pkt, (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN), DHD_SDALIGN);
4838 data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
4840 /* Fill in the test header */
4841 *data++ = SDPCM_TEST_SEND;
4843 *data++ = (bus->pktgen_maxlen >> 0);
4844 *data++ = (bus->pktgen_maxlen >> 8);
4847 if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE))
4853 dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq)
4855 osl_t *osh = bus->dhd->osh;
4864 /* Check for min length */
4865 if ((pktlen = PKTLEN(osh, pkt)) < SDPCM_TEST_HDRLEN) {
4866 DHD_ERROR(("dhdsdio_restrcv: toss runt frame, pktlen %d\n", pktlen));
4867 PKTFREE(osh, pkt, FALSE);
4871 /* Extract header fields */
4872 data = PKTDATA(osh, pkt);
4875 len = *data++; len += *data++ << 8;
4876 DHD_TRACE(("%s:cmd:%d, xtra:%d,len:%d\n", __FUNCTION__, cmd, extra, len));
4877 /* Check length for relevant commands */
4878 if (cmd == SDPCM_TEST_DISCARD || cmd == SDPCM_TEST_ECHOREQ || cmd == SDPCM_TEST_ECHORSP) {
4879 if (pktlen != len + SDPCM_TEST_HDRLEN) {
4880 DHD_ERROR(("dhdsdio_testrcv: frame length mismatch, pktlen %d seq %d"
4881 " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len));
4882 PKTFREE(osh, pkt, FALSE);
4887 /* Process as per command */
4889 case SDPCM_TEST_ECHOREQ:
4890 /* Rx->Tx turnaround ok (even on NDIS w/current implementation) */
4891 *(uint8 *)(PKTDATA(osh, pkt)) = SDPCM_TEST_ECHORSP;
4892 if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE) == 0) {
4896 PKTFREE(osh, pkt, FALSE);
4901 case SDPCM_TEST_ECHORSP:
4902 if (bus->ext_loop) {
4903 PKTFREE(osh, pkt, FALSE);
4908 for (offset = 0; offset < len; offset++, data++) {
4909 if (*data != SDPCM_TEST_FILL(offset, extra)) {
4910 DHD_ERROR(("dhdsdio_testrcv: echo data mismatch: "
4911 "offset %d (len %d) expect 0x%02x rcvd 0x%02x\n",
4912 offset, len, SDPCM_TEST_FILL(offset, extra), *data));
4916 PKTFREE(osh, pkt, FALSE);
4920 case SDPCM_TEST_DISCARD:
4924 uint8 testval = extra;
4925 for (i = 0; i < len; i++) {
4926 if (*prn != testval) {
4927 DHD_ERROR(("DIErr@Pkt#:%d,Ix:%d, expected:0x%x, got:0x%x\n",
4928 i, bus->pktgen_rcvd_rcvsession, testval, *prn));
4933 PKTFREE(osh, pkt, FALSE);
4937 case SDPCM_TEST_BURST:
4938 case SDPCM_TEST_SEND:
4940 DHD_INFO(("dhdsdio_testrcv: unsupported or unknown command, pktlen %d seq %d"
4941 " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len));
4942 PKTFREE(osh, pkt, FALSE);
4946 /* For recv mode, stop at limit (and tell dongle to stop sending) */
4947 if (bus->pktgen_mode == DHD_PKTGEN_RECV) {
4948 if (bus->pktgen_rcv_state != PKTGEN_RCV_IDLE) {
4949 bus->pktgen_rcvd_rcvsession++;
4951 if (bus->pktgen_total &&
4952 (bus->pktgen_rcvd_rcvsession >= bus->pktgen_total)) {
4953 bus->pktgen_count = 0;
4954 DHD_ERROR(("Pktgen:rcv test complete!\n"));
4955 bus->pktgen_rcv_state = PKTGEN_RCV_IDLE;
4956 dhdsdio_sdtest_set(bus, FALSE);
4957 bus->pktgen_rcvd_rcvsession = 0;
4965 dhd_disable_intr(dhd_pub_t *dhdp)
4969 bcmsdh_intr_disable(bus->sdh);
4973 dhd_bus_watchdog(dhd_pub_t *dhdp)
4977 DHD_TIMER(("%s: Enter\n", __FUNCTION__));
4981 if (bus->dhd->dongle_reset)
4984 /* Ignore the timer if simulating bus down */
4988 if (dhdp->busstate == DHD_BUS_DOWN)
4991 /* Poll period: check device if appropriate. */
4992 if (bus->poll && (++bus->polltick >= bus->pollrate)) {
4993 uint32 intstatus = 0;
4995 /* Reset poll tick */
4998 /* Check device if no interrupts */
4999 if (!bus->intr || (bus->intrcount == bus->lastintrs)) {
5001 if (!bus->dpc_sched) {
5003 devpend = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0,
5004 SDIOD_CCCR_INTPEND, NULL);
5005 intstatus = devpend & (INTR_STATUS_FUNC1 | INTR_STATUS_FUNC2);
5008 /* If there is something, make like the ISR and schedule the DPC */
5013 bcmsdh_intr_disable(bus->sdh);
5015 bus->dpc_sched = TRUE;
5016 dhd_sched_dpc(bus->dhd);
5021 /* Update interrupt tracking */
5022 bus->lastintrs = bus->intrcount;
5026 /* Poll for console output periodically */
5027 if (dhdp->busstate == DHD_BUS_DATA && dhd_console_ms != 0) {
5028 bus->console.count += dhd_watchdog_ms;
5029 if (bus->console.count >= dhd_console_ms) {
5030 bus->console.count -= dhd_console_ms;
5031 /* Make sure backplane clock is on */
5032 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
5033 if (dhdsdio_readconsole(bus) < 0)
5034 dhd_console_ms = 0; /* On error, stop trying */
5037 #endif /* DHD_DEBUG */
5040 /* Generate packets if configured */
5041 if (bus->pktgen_count && (++bus->pktgen_tick >= bus->pktgen_freq)) {
5042 /* Make sure backplane clock is on */
5043 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
5044 bus->pktgen_tick = 0;
5045 dhdsdio_pktgen(bus);
5049 /* On idle timeout clear activity flag and/or turn off clock */
5050 if ((bus->idletime > 0) && (bus->clkstate == CLK_AVAIL)) {
5051 if (++bus->idlecount >= bus->idletime) {
5053 if (bus->activity) {
5054 bus->activity = FALSE;
5055 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
5065 dhd_bus_console_in(dhd_pub_t *dhdp, uchar *msg, uint msglen)
5067 dhd_bus_t *bus = dhdp->bus;
5072 /* Address could be zero if CONSOLE := 0 in dongle Makefile */
5073 if (bus->console_addr == 0)
5074 return BCME_UNSUPPORTED;
5076 /* Exclusive bus access */
5077 dhd_os_sdlock(bus->dhd);
5079 /* Don't allow input if dongle is in reset */
5080 if (bus->dhd->dongle_reset) {
5081 dhd_os_sdunlock(bus->dhd);
5082 return BCME_NOTREADY;
5085 /* Request clock to allow SDIO accesses */
5087 /* No pend allowed since txpkt is called later, ht clk has to be on */
5088 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
5090 /* Zero cbuf_index */
5091 addr = bus->console_addr + OFFSETOF(hndrte_cons_t, cbuf_idx);
5093 if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0)
5096 /* Write message into cbuf */
5097 addr = bus->console_addr + OFFSETOF(hndrte_cons_t, cbuf);
5098 if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)msg, msglen)) < 0)
5101 /* Write length into vcons_in */
5102 addr = bus->console_addr + OFFSETOF(hndrte_cons_t, vcons_in);
5103 val = htol32(msglen);
5104 if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0)
5107 /* Bump dongle by sending an empty packet on the event channel.
5108 * sdpcm_sendup (RX) checks for virtual console input.
5110 if ((pkt = PKTGET(bus->dhd->osh, 4 + SDPCM_RESERVE, TRUE)) != NULL)
5111 dhdsdio_txpkt(bus, pkt, SDPCM_EVENT_CHANNEL, TRUE);
5114 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
5115 bus->activity = FALSE;
5116 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
5119 dhd_os_sdunlock(bus->dhd);
5123 #endif /* DHD_DEBUG */
5127 dhd_dump_cis(uint fn, uint8 *cis)
5129 uint byte, tag, tdata;
5130 DHD_INFO(("Function %d CIS:\n", fn));
5132 for (tdata = byte = 0; byte < SBSDIO_CIS_SIZE_LIMIT; byte++) {
5133 if ((byte % 16) == 0)
5135 DHD_INFO(("%02x ", cis[byte]));
5136 if ((byte % 16) == 15)
5144 else if ((byte + 1) < SBSDIO_CIS_SIZE_LIMIT)
5145 tdata = cis[byte + 1] + 1;
5150 if ((byte % 16) != 15)
5153 #endif /* DHD_DEBUG */
5156 dhdsdio_chipmatch(uint16 chipid)
5158 if (chipid == BCM4325_CHIP_ID)
5160 if (chipid == BCM4329_CHIP_ID)
5162 if (chipid == BCM4315_CHIP_ID)
5164 if (chipid == BCM4319_CHIP_ID)
5166 if (chipid == BCM4336_CHIP_ID)
5168 if (chipid == BCM4330_CHIP_ID)
5170 if (chipid == BCM43237_CHIP_ID)
5172 if (chipid == BCM43362_CHIP_ID)
5174 if (chipid == BCM43239_CHIP_ID)
5180 dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot,
5181 uint16 func, uint bustype, void *regsva, osl_t * osh, void *sdh)
5186 #ifdef GET_CUSTOM_MAC_ENABLE
5187 struct ether_addr ea_addr;
5188 #endif /* GET_CUSTOM_MAC_ENABLE */
5190 /* Init global variables at run-time, not as part of the declaration.
5191 * This is required to support init/de-init of the driver. Initialization
5192 * of globals as part of the declaration results in non-deterministic
5193 * behavior since the value of the globals may be different on the
5194 * first time that the driver is initialized vs subsequent initializations.
5196 dhd_txbound = DHD_TXBOUND;
5197 dhd_rxbound = DHD_RXBOUND;
5198 dhd_alignctl = TRUE;
5200 dhd_readahead = TRUE;
5203 dhd_dongle_memsize = 0;
5204 dhd_txminmax = DHD_TXMINMAX;
5209 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5210 DHD_INFO(("%s: venid 0x%04x devid 0x%04x\n", __FUNCTION__, venid, devid));
5212 /* We make assumptions about address window mappings */
5213 ASSERT((uintptr)regsva == SI_ENUM_BASE);
5215 /* BCMSDH passes venid and devid based on CIS parsing -- but low-power start
5216 * means early parse could fail, so here we should get either an ID
5217 * we recognize OR (-1) indicating we must request power first.
5219 /* Check the Vendor ID */
5222 case VENDOR_BROADCOM:
5225 DHD_ERROR(("%s: unknown vendor: 0x%04x\n",
5226 __FUNCTION__, venid));
5230 /* Check the Device ID and make sure it's one that we support */
5232 case BCM4325_D11DUAL_ID: /* 4325 802.11a/g id */
5233 case BCM4325_D11G_ID: /* 4325 802.11g 2.4Ghz band id */
5234 case BCM4325_D11A_ID: /* 4325 802.11a 5Ghz band id */
5235 DHD_INFO(("%s: found 4325 Dongle\n", __FUNCTION__));
5237 case BCM4329_D11N_ID: /* 4329 802.11n dualband device */
5238 case BCM4329_D11N2G_ID: /* 4329 802.11n 2.4G device */
5239 case BCM4329_D11N5G_ID: /* 4329 802.11n 5G device */
5241 DHD_INFO(("%s: found 4329 Dongle\n", __FUNCTION__));
5243 case BCM4315_D11DUAL_ID: /* 4315 802.11a/g id */
5244 case BCM4315_D11G_ID: /* 4315 802.11g id */
5245 case BCM4315_D11A_ID: /* 4315 802.11a id */
5246 DHD_INFO(("%s: found 4315 Dongle\n", __FUNCTION__));
5248 case BCM4319_D11N_ID: /* 4319 802.11n id */
5249 case BCM4319_D11N2G_ID: /* 4319 802.11n2g id */
5250 case BCM4319_D11N5G_ID: /* 4319 802.11n5g id */
5251 DHD_INFO(("%s: found 4319 Dongle\n", __FUNCTION__));
5254 DHD_INFO(("%s: allow device id 0, will check chip internals\n",
5259 DHD_ERROR(("%s: skipping 0x%04x/0x%04x, not a dongle\n",
5260 __FUNCTION__, venid, devid));
5265 /* Ask the OS interface part for an OSL handle */
5266 if (!(osh = dhd_osl_attach(sdh, DHD_BUS))) {
5267 DHD_ERROR(("%s: osl_attach failed!\n", __FUNCTION__));
5272 /* Allocate private bus interface state */
5273 if (!(bus = MALLOC(osh, sizeof(dhd_bus_t)))) {
5274 DHD_ERROR(("%s: MALLOC of dhd_bus_t failed\n", __FUNCTION__));
5277 bzero(bus, sizeof(dhd_bus_t));
5279 bus->cl_devid = (uint16)devid;
5281 bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1;
5282 bus->usebufpool = FALSE; /* Use bufpool if allocated, else use locally malloced rxbuf */
5284 /* attach the common module */
5285 if (!(cmn = dhd_common_init(osh))) {
5286 DHD_ERROR(("%s: dhd_common_init failed\n", __FUNCTION__));
5290 /* attempt to attach to the dongle */
5291 if (!(dhdsdio_probe_attach(bus, osh, sdh, regsva, devid))) {
5292 DHD_ERROR(("%s: dhdsdio_probe_attach failed\n", __FUNCTION__));
5293 dhd_common_deinit(NULL, cmn);
5297 /* Attach to the dhd/OS/network interface */
5298 if (!(bus->dhd = dhd_attach(osh, bus, SDPCM_RESERVE))) {
5299 DHD_ERROR(("%s: dhd_attach failed\n", __FUNCTION__));
5303 bus->dhd->cmn = cmn;
5304 cmn->dhd = bus->dhd;
5306 /* Allocate buffers */
5307 if (!(dhdsdio_probe_malloc(bus, osh, sdh))) {
5308 DHD_ERROR(("%s: dhdsdio_probe_malloc failed\n", __FUNCTION__));
5312 if (!(dhdsdio_probe_init(bus, osh, sdh))) {
5313 DHD_ERROR(("%s: dhdsdio_probe_init failed\n", __FUNCTION__));
5318 /* Register interrupt callback, but mask it (not operational yet). */
5319 DHD_INTR(("%s: disable SDIO interrupts (not interested yet)\n", __FUNCTION__));
5320 bcmsdh_intr_disable(sdh);
5321 if ((ret = bcmsdh_intr_reg(sdh, dhdsdio_isr, bus)) != 0) {
5322 DHD_ERROR(("%s: FAILED: bcmsdh_intr_reg returned %d\n",
5323 __FUNCTION__, ret));
5326 DHD_INTR(("%s: registered SDIO interrupt function ok\n", __FUNCTION__));
5328 DHD_INFO(("%s: SDIO interrupt function is NOT registered due to polling mode\n",
5332 DHD_INFO(("%s: completed!!\n", __FUNCTION__));
5334 #ifdef GET_CUSTOM_MAC_ENABLE
5335 /* Read MAC address from external customer place */
5336 memset(&ea_addr, 0, sizeof(ea_addr));
5337 ret = dhd_custom_get_mac_address(ea_addr.octet);
5339 memcpy(bus->dhd->mac.octet, (void *)&ea_addr, ETHER_ADDR_LEN);
5341 #endif /* GET_CUSTOM_MAC_ENABLE */
5343 /* if firmware path present try to download and bring up bus */
5344 if (dhd_download_fw_on_driverload && (ret = dhd_bus_start(bus->dhd)) != 0) {
5345 DHD_ERROR(("%s: dhd_bus_start failed\n", __FUNCTION__));
5346 if (ret == BCME_NOTUP)
5349 /* Ok, have the per-port tell the stack we're open for business */
5350 if (dhd_net_attach(bus->dhd, 0) != 0) {
5351 DHD_ERROR(("%s: Net attach failed!!\n", __FUNCTION__));
5358 dhdsdio_release(bus, osh);
5363 dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva,
5369 bus->alp_only = TRUE;
5371 /* Return the window to backplane enumeration space for core access */
5372 if (dhdsdio_set_siaddr_window(bus, SI_ENUM_BASE)) {
5373 DHD_ERROR(("%s: FAILED to return to SI_ENUM_BASE\n", __FUNCTION__));
5377 DHD_ERROR(("F1 signature read @0x18000000=0x%4x\n",
5378 bcmsdh_reg_read(bus->sdh, SI_ENUM_BASE, 4)));
5380 #endif /* DHD_DEBUG */
5383 /* Force PLL off until si_attach() programs PLL control regs */
5387 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, DHD_INIT_CLKCTL1, &err);
5389 clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
5391 if (err || ((clkctl & ~SBSDIO_AVBITS) != DHD_INIT_CLKCTL1)) {
5392 DHD_ERROR(("dhdsdio_probe: ChipClkCSR access: err %d wrote 0x%02x read 0x%02x\n",
5393 err, DHD_INIT_CLKCTL1, clkctl));
5399 if (DHD_INFO_ON()) {
5401 uint8 *cis[SDIOD_MAX_IOFUNCS];
5404 numfn = bcmsdh_query_iofnum(sdh);
5405 ASSERT(numfn <= SDIOD_MAX_IOFUNCS);
5407 /* Make sure ALP is available before trying to read CIS */
5408 SPINWAIT(((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
5409 SBSDIO_FUNC1_CHIPCLKCSR, NULL)),
5410 !SBSDIO_ALPAV(clkctl)), PMU_MAX_TRANSITION_DLY);
5412 /* Now request ALP be put on the bus */
5413 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
5414 DHD_INIT_CLKCTL2, &err);
5417 for (fn = 0; fn <= numfn; fn++) {
5418 if (!(cis[fn] = MALLOC(osh, SBSDIO_CIS_SIZE_LIMIT))) {
5419 DHD_INFO(("dhdsdio_probe: fn %d cis malloc failed\n", fn));
5422 bzero(cis[fn], SBSDIO_CIS_SIZE_LIMIT);
5424 if ((err = bcmsdh_cis_read(sdh, fn, cis[fn], SBSDIO_CIS_SIZE_LIMIT))) {
5425 DHD_INFO(("dhdsdio_probe: fn %d cis read err %d\n", fn, err));
5426 MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT);
5429 dhd_dump_cis(fn, cis[fn]);
5434 MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT);
5438 DHD_ERROR(("dhdsdio_probe: failure reading or parsing CIS\n"));
5442 #endif /* DHD_DEBUG */
5444 /* si_attach() will provide an SI handle and scan the backplane */
5445 if (!(bus->sih = si_attach((uint)devid, osh, regsva, DHD_BUS, sdh,
5446 &bus->vars, &bus->varsz))) {
5447 DHD_ERROR(("%s: si_attach failed!\n", __FUNCTION__));
5451 bcmsdh_chipinfo(sdh, bus->sih->chip, bus->sih->chiprev);
5453 if (!dhdsdio_chipmatch((uint16)bus->sih->chip)) {
5454 DHD_ERROR(("%s: unsupported chip: 0x%04x\n",
5455 __FUNCTION__, bus->sih->chip));
5460 si_sdiod_drive_strength_init(bus->sih, osh, dhd_sdiod_drive_strength);
5463 /* Get info on the ARM and SOCRAM cores... */
5464 if (!DHD_NOPMU(bus)) {
5465 if ((si_setcore(bus->sih, ARM7S_CORE_ID, 0)) ||
5466 (si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) {
5467 bus->armrev = si_corerev(bus->sih);
5469 DHD_ERROR(("%s: failed to find ARM core!\n", __FUNCTION__));
5472 if (!(bus->orig_ramsize = si_socram_size(bus->sih))) {
5473 DHD_ERROR(("%s: failed to find SOCRAM memory!\n", __FUNCTION__));
5476 bus->ramsize = bus->orig_ramsize;
5477 if (dhd_dongle_memsize)
5478 dhd_dongle_setmemsize(bus, dhd_dongle_memsize);
5480 DHD_ERROR(("DHD: dongle ram size is set to %d(orig %d)\n",
5481 bus->ramsize, bus->orig_ramsize));
5484 /* ...but normally deal with the SDPCMDEV core */
5485 if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0)) &&
5486 !(bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0))) {
5487 DHD_ERROR(("%s: failed to find SDIODEV core!\n", __FUNCTION__));
5490 bus->sdpcmrev = si_corerev(bus->sih);
5492 /* Set core control so an SDIO reset does a backplane reset */
5493 OR_REG(osh, &bus->regs->corecontrol, CC_BPRESEN);
5494 bus->rxint_mode = SDIO_DEVICE_HMB_RXINT;
5496 if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev >= 4) &&
5497 (bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_1))
5501 val = R_REG(osh, &bus->regs->corecontrol);
5502 val &= ~CC_XMTDATAAVAIL_MODE;
5503 val |= CC_XMTDATAAVAIL_CTRL;
5504 W_REG(osh, &bus->regs->corecontrol, val);
5508 pktq_init(&bus->txq, (PRIOMASK + 1), QLEN);
5510 /* Locate an appropriately-aligned portion of hdrbuf */
5511 bus->rxhdr = (uint8 *)ROUNDUP((uintptr)&bus->hdrbuf[0], DHD_SDALIGN);
5513 /* Set the poll and/or interrupt flags */
5514 bus->intr = (bool)dhd_intr;
5515 if ((bus->poll = (bool)dhd_poll))
5521 if (bus->sih != NULL)
5522 si_detach(bus->sih);
5527 dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh)
5529 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5531 if (bus->dhd->maxctl) {
5532 bus->rxblen = ROUNDUP((bus->dhd->maxctl + SDPCM_HDRLEN), ALIGNMENT) + DHD_SDALIGN;
5533 if (!(bus->rxbuf = DHD_OS_PREALLOC(osh, DHD_PREALLOC_RXBUF, bus->rxblen))) {
5534 DHD_ERROR(("%s: MALLOC of %d-byte rxbuf failed\n",
5535 __FUNCTION__, bus->rxblen));
5539 /* Allocate buffer to receive glomed packet */
5540 if (!(bus->databuf = DHD_OS_PREALLOC(osh, DHD_PREALLOC_DATABUF, MAX_DATA_BUF))) {
5541 DHD_ERROR(("%s: MALLOC of %d-byte databuf failed\n",
5542 __FUNCTION__, MAX_DATA_BUF));
5543 /* release rxbuf which was already located as above */
5545 DHD_OS_PREFREE(osh, bus->rxbuf, bus->rxblen);
5549 /* Align the buffer */
5550 if ((uintptr)bus->databuf % DHD_SDALIGN)
5551 bus->dataptr = bus->databuf + (DHD_SDALIGN - ((uintptr)bus->databuf % DHD_SDALIGN));
5553 bus->dataptr = bus->databuf;
5562 dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh)
5566 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5569 dhdsdio_pktgen_init(bus);
5572 /* Disable F2 to clear any intermediate frame state on the dongle */
5573 bcmsdh_cfg_write(sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL);
5575 bus->dhd->busstate = DHD_BUS_DOWN;
5576 bus->sleeping = FALSE;
5577 bus->rxflow = FALSE;
5578 bus->prev_rxlim_hit = 0;
5581 /* Done with backplane-dependent accesses, can drop clock... */
5582 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
5584 /* ...and initialize clock/power states */
5585 bus->clkstate = CLK_SDONLY;
5586 bus->idletime = (int32)dhd_idletime;
5587 bus->idleclock = DHD_IDLE_ACTIVE;
5589 /* Query the SD clock speed */
5590 if (bcmsdh_iovar_op(sdh, "sd_divisor", NULL, 0,
5591 &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) {
5592 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_divisor"));
5593 bus->sd_divisor = -1;
5595 DHD_INFO(("%s: Initial value for %s is %d\n",
5596 __FUNCTION__, "sd_divisor", bus->sd_divisor));
5599 /* Query the SD bus mode */
5600 if (bcmsdh_iovar_op(sdh, "sd_mode", NULL, 0,
5601 &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) {
5602 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_mode"));
5605 DHD_INFO(("%s: Initial value for %s is %d\n",
5606 __FUNCTION__, "sd_mode", bus->sd_mode));
5609 /* Query the F2 block size, set roundup accordingly */
5611 if (bcmsdh_iovar_op(sdh, "sd_blocksize", &fnum, sizeof(int32),
5612 &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) {
5614 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize"));
5616 DHD_INFO(("%s: Initial value for %s is %d\n",
5617 __FUNCTION__, "sd_blocksize", bus->blocksize));
5619 bus->roundup = MIN(max_roundup, bus->blocksize);
5621 /* Query if bus module supports packet chaining, default to use if supported */
5622 if (bcmsdh_iovar_op(sdh, "sd_rxchain", NULL, 0,
5623 &bus->sd_rxchain, sizeof(int32), FALSE) != BCME_OK) {
5624 bus->sd_rxchain = FALSE;
5626 DHD_INFO(("%s: bus module (through bcmsdh API) %s chaining\n",
5627 __FUNCTION__, (bus->sd_rxchain ? "supports" : "does not support")));
5629 bus->use_rxchain = (bool)bus->sd_rxchain;
5635 dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh,
5636 char *pfw_path, char *pnv_path)
5639 bus->fw_path = pfw_path;
5640 bus->nv_path = pnv_path;
5642 ret = dhdsdio_download_firmware(bus, osh, bus->sdh);
5649 dhdsdio_download_firmware(struct dhd_bus *bus, osl_t *osh, void *sdh)
5653 /* Download the firmware */
5654 DHD_OS_WAKE_LOCK(bus->dhd);
5655 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
5657 ret = _dhdsdio_download_firmware(bus) == 0;
5659 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
5660 DHD_OS_WAKE_UNLOCK(bus->dhd);
5664 /* Detach and free everything */
5666 dhdsdio_release(dhd_bus_t *bus, osl_t *osh)
5668 bool dongle_isolation = FALSE;
5669 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5674 /* De-register interrupt handler */
5675 bcmsdh_intr_disable(bus->sdh);
5676 bcmsdh_intr_dereg(bus->sdh);
5679 dhd_common_deinit(bus->dhd, NULL);
5680 dongle_isolation = bus->dhd->dongle_isolation;
5681 dhd_detach(bus->dhd);
5682 dhdsdio_release_dongle(bus, osh, dongle_isolation, TRUE);
5687 dhdsdio_release_malloc(bus, osh);
5690 if (bus->console.buf != NULL)
5691 MFREE(osh, bus->console.buf, bus->console.bufsize);
5694 MFREE(osh, bus, sizeof(dhd_bus_t));
5698 dhd_osl_detach(osh);
5700 DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
5704 dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh)
5706 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5708 if (bus->dhd && bus->dhd->dongle_reset)
5712 #ifndef DHD_USE_STATIC_BUF
5713 MFREE(osh, bus->rxbuf, bus->rxblen);
5715 bus->rxctl = bus->rxbuf = NULL;
5720 #ifndef DHD_USE_STATIC_BUF
5721 MFREE(osh, bus->databuf, MAX_DATA_BUF);
5723 bus->databuf = NULL;
5726 if (bus->vars && bus->varsz) {
5727 MFREE(osh, bus->vars, bus->varsz);
5735 dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation, bool reset_flag)
5737 DHD_TRACE(("%s: Enter bus->dhd %p bus->dhd->dongle_reset %d \n", __FUNCTION__,
5738 bus->dhd, bus->dhd->dongle_reset));
5740 if ((bus->dhd && bus->dhd->dongle_reset) && reset_flag)
5745 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
5747 #if !defined(BCMLXSDMMC)
5748 if (dongle_isolation == FALSE)
5749 si_watchdog(bus->sih, 4);
5750 #endif /* !defined(BCMLXSDMMC) */
5752 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
5754 si_detach(bus->sih);
5755 if (bus->vars && bus->varsz)
5756 MFREE(osh, bus->vars, bus->varsz);
5760 DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
5764 dhdsdio_disconnect(void *ptr)
5766 dhd_bus_t *bus = (dhd_bus_t *)ptr;
5768 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5772 dhdsdio_release(bus, bus->dhd->osh);
5775 DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
5779 /* Register/Unregister functions are called by the main DHD entry
5780 * point (e.g. module insertion) to link with the bus driver, in
5781 * order to look for or await the device.
5784 static bcmsdh_driver_t dhd_sdio = {
5790 dhd_bus_register(void)
5792 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5794 return bcmsdh_register(&dhd_sdio);
5798 dhd_bus_unregister(void)
5800 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5802 bcmsdh_unregister();
5805 #ifdef BCMEMBEDIMAGE
5807 dhdsdio_download_code_array(struct dhd_bus *bus)
5811 unsigned char *ularray = NULL;
5813 DHD_INFO(("%s: download embedded firmware...\n", __FUNCTION__));
5815 /* Download image */
5816 while ((offset + MEMBLOCK) < sizeof(dlarray)) {
5817 bcmerror = dhdsdio_membytes(bus, TRUE, offset,
5818 (uint8 *) (dlarray + offset), MEMBLOCK);
5820 DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
5821 __FUNCTION__, bcmerror, MEMBLOCK, offset));
5828 if (offset < sizeof(dlarray)) {
5829 bcmerror = dhdsdio_membytes(bus, TRUE, offset,
5830 (uint8 *) (dlarray + offset), sizeof(dlarray) - offset);
5832 DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
5833 __FUNCTION__, bcmerror, sizeof(dlarray) - offset, offset));
5839 /* Upload and compare the downloaded code */
5841 ularray = MALLOC(bus->dhd->osh, bus->ramsize);
5842 /* Upload image to verify downloaded contents. */
5844 memset(ularray, 0xaa, bus->ramsize);
5845 while ((offset + MEMBLOCK) < sizeof(dlarray)) {
5846 bcmerror = dhdsdio_membytes(bus, FALSE, offset, ularray + offset, MEMBLOCK);
5848 DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n",
5849 __FUNCTION__, bcmerror, MEMBLOCK, offset));
5856 if (offset < sizeof(dlarray)) {
5857 bcmerror = dhdsdio_membytes(bus, FALSE, offset,
5858 ularray + offset, sizeof(dlarray) - offset);
5860 DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n",
5861 __FUNCTION__, bcmerror, sizeof(dlarray) - offset, offset));
5866 if (memcmp(dlarray, ularray, sizeof(dlarray))) {
5867 DHD_ERROR(("%s: Downloaded image is corrupted (%s, %s, %s).\n",
5868 __FUNCTION__, dlimagename, dlimagever, dlimagedate));
5871 DHD_ERROR(("%s: Download, Upload and compare succeeded (%s, %s, %s).\n",
5872 __FUNCTION__, dlimagename, dlimagever, dlimagedate));
5875 #endif /* DHD_DEBUG */
5879 MFREE(bus->dhd->osh, ularray, bus->ramsize);
5882 #endif /* BCMEMBEDIMAGE */
5885 dhdsdio_download_code_file(struct dhd_bus *bus, char *pfw_path)
5891 uint8 *memblock = NULL, *memptr;
5893 DHD_INFO(("%s: download firmware %s\n", __FUNCTION__, pfw_path));
5895 image = dhd_os_open_image(pfw_path);
5899 memptr = memblock = MALLOC(bus->dhd->osh, MEMBLOCK + DHD_SDALIGN);
5900 if (memblock == NULL) {
5901 DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, MEMBLOCK));
5904 if ((uint32)(uintptr)memblock % DHD_SDALIGN)
5905 memptr += (DHD_SDALIGN - ((uint32)(uintptr)memblock % DHD_SDALIGN));
5907 /* Download image */
5908 while ((len = dhd_os_get_image_block((char*)memptr, MEMBLOCK, image))) {
5909 bcmerror = dhdsdio_membytes(bus, TRUE, offset, memptr, len);
5911 DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
5912 __FUNCTION__, bcmerror, MEMBLOCK, offset));
5921 MFREE(bus->dhd->osh, memblock, MEMBLOCK + DHD_SDALIGN);
5924 dhd_os_close_image(image);
5930 EXAMPLE: nvram_array
5933 Use carriage return at the end of each assignment, and an empty string with
5934 carriage return at the end of array.
5937 unsigned char nvram_array[] = {"name1=value1\n", "name2=value2\n", "\n"};
5938 Hex values start with 0x, and mac addr format: xx:xx:xx:xx:xx:xx.
5940 Search "EXAMPLE: nvram_array" to see how the array is activated.
5944 dhd_bus_set_nvram_params(struct dhd_bus * bus, const char *nvram_params)
5946 bus->nvram_params = nvram_params;
5950 dhdsdio_download_nvram(struct dhd_bus *bus)
5954 void * image = NULL;
5955 char * memblock = NULL;
5958 bool nvram_file_exists;
5960 pnv_path = bus->nv_path;
5962 nvram_file_exists = ((pnv_path != NULL) && (pnv_path[0] != '\0'));
5963 if (!nvram_file_exists && (bus->nvram_params == NULL))
5966 if (nvram_file_exists) {
5967 image = dhd_os_open_image(pnv_path);
5972 memblock = MALLOC(bus->dhd->osh, MAX_NVRAMBUF_SIZE);
5973 if (memblock == NULL) {
5974 DHD_ERROR(("%s: Failed to allocate memory %d bytes\n",
5975 __FUNCTION__, MAX_NVRAMBUF_SIZE));
5979 /* Download variables */
5980 if (nvram_file_exists) {
5981 len = dhd_os_get_image_block(memblock, MAX_NVRAMBUF_SIZE, image);
5984 len = strlen(bus->nvram_params);
5985 ASSERT(len <= MAX_NVRAMBUF_SIZE);
5986 memcpy(memblock, bus->nvram_params, len);
5988 if (len > 0 && len < MAX_NVRAMBUF_SIZE) {
5989 bufp = (char *)memblock;
5991 len = process_nvram_vars(bufp, len);
5993 len += 4 - (len % 4);
5998 bcmerror = dhdsdio_downloadvars(bus, memblock, len + 1);
6000 DHD_ERROR(("%s: error downloading vars: %d\n",
6001 __FUNCTION__, bcmerror));
6005 DHD_ERROR(("%s: error reading nvram file: %d\n",
6006 __FUNCTION__, len));
6007 bcmerror = BCME_SDIO_ERROR;
6012 MFREE(bus->dhd->osh, memblock, MAX_NVRAMBUF_SIZE);
6015 dhd_os_close_image(image);
6021 _dhdsdio_download_firmware(struct dhd_bus *bus)
6025 bool embed = FALSE; /* download embedded firmware */
6026 bool dlok = FALSE; /* download firmware succeeded */
6028 /* Out immediately if no image to download */
6029 if ((bus->fw_path == NULL) || (bus->fw_path[0] == '\0')) {
6030 #ifdef BCMEMBEDIMAGE
6037 /* Keep arm in reset */
6038 if (dhdsdio_download_state(bus, TRUE)) {
6039 DHD_ERROR(("%s: error placing ARM core in reset\n", __FUNCTION__));
6043 /* External image takes precedence if specified */
6044 if ((bus->fw_path != NULL) && (bus->fw_path[0] != '\0')) {
6045 if (dhdsdio_download_code_file(bus, bus->fw_path)) {
6046 DHD_ERROR(("%s: dongle image file download failed\n", __FUNCTION__));
6047 #ifdef BCMEMBEDIMAGE
6058 #ifdef BCMEMBEDIMAGE
6060 if (dhdsdio_download_code_array(bus)) {
6061 DHD_ERROR(("%s: dongle image array download failed\n", __FUNCTION__));
6070 DHD_ERROR(("%s: dongle image download failed\n", __FUNCTION__));
6074 /* EXAMPLE: nvram_array */
6075 /* If a valid nvram_arry is specified as above, it can be passed down to dongle */
6076 /* dhd_bus_set_nvram_params(bus, (char *)&nvram_array); */
6078 /* External nvram takes precedence if specified */
6079 if (dhdsdio_download_nvram(bus)) {
6080 DHD_ERROR(("%s: dongle nvram file download failed\n", __FUNCTION__));
6084 /* Take arm out of reset */
6085 if (dhdsdio_download_state(bus, FALSE)) {
6086 DHD_ERROR(("%s: error getting out of ARM core reset\n", __FUNCTION__));
6097 dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes,
6098 void *pkt, bcmsdh_cmplt_fn_t complete, void *handle)
6102 status = bcmsdh_recv_buf(bus->sdh, addr, fn, flags, buf, nbytes, pkt, complete, handle);
6108 dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes,
6109 void *pkt, bcmsdh_cmplt_fn_t complete, void *handle)
6111 return (bcmsdh_send_buf(bus->sdh, addr, fn, flags, buf, nbytes, pkt, complete, handle));
6115 dhd_bus_chip(struct dhd_bus *bus)
6117 ASSERT(bus->sih != NULL);
6118 return bus->sih->chip;
6122 dhd_bus_pub(struct dhd_bus *bus)
6128 dhd_bus_txq(struct dhd_bus *bus)
6134 dhd_bus_hdrlen(struct dhd_bus *bus)
6136 return SDPCM_HDRLEN;
6140 dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag)
6148 if (!bus->dhd->dongle_reset) {
6149 dhd_os_sdlock(dhdp);
6150 dhd_os_wd_timer(dhdp, 0);
6151 #if !defined(IGNORE_ETH0_DOWN)
6152 /* Force flow control as protection when stop come before ifconfig_down */
6153 dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON);
6154 #endif /* !defined(IGNORE_ETH0_DOWN) */
6155 /* Expect app to have torn down any connection before calling */
6156 /* Stop the bus, disable F2 */
6157 dhd_bus_stop(bus, FALSE);
6159 #if defined(OOB_INTR_ONLY)
6160 /* Clean up any pending IRQ */
6161 bcmsdh_set_irq(FALSE);
6162 #endif /* defined(OOB_INTR_ONLY) */
6164 /* Clean tx/rx buffer pointers, detach from the dongle */
6165 dhdsdio_release_dongle(bus, bus->dhd->osh, TRUE, TRUE);
6167 bus->dhd->dongle_reset = TRUE;
6168 bus->dhd->up = FALSE;
6169 dhd_os_sdunlock(dhdp);
6171 DHD_TRACE(("%s: WLAN OFF DONE\n", __FUNCTION__));
6172 /* App can now remove power from device */
6174 bcmerror = BCME_SDIO_ERROR;
6176 /* App must have restored power to device before calling */
6178 DHD_TRACE(("\n\n%s: == WLAN ON ==\n", __FUNCTION__));
6180 if (bus->dhd->dongle_reset) {
6182 dhd_os_sdlock(dhdp);
6184 /* Reset SD client */
6185 bcmsdh_reset(bus->sdh);
6187 /* Attempt to re-attach & download */
6188 if (dhdsdio_probe_attach(bus, bus->dhd->osh, bus->sdh,
6189 (uint32 *)SI_ENUM_BASE,
6191 /* Attempt to download binary to the dongle */
6192 if (dhdsdio_probe_init(bus, bus->dhd->osh, bus->sdh) &&
6193 dhdsdio_download_firmware(bus, bus->dhd->osh, bus->sdh)) {
6195 /* Re-init bus, enable F2 transfer */
6196 bcmerror = dhd_bus_init((dhd_pub_t *) bus->dhd, FALSE);
6197 if (bcmerror == BCME_OK) {
6198 #if defined(OOB_INTR_ONLY)
6199 bcmsdh_set_irq(TRUE);
6200 dhd_enable_oob_intr(bus, TRUE);
6201 #endif /* defined(OOB_INTR_ONLY) */
6203 bus->dhd->dongle_reset = FALSE;
6204 bus->dhd->up = TRUE;
6206 #if !defined(IGNORE_ETH0_DOWN)
6207 /* Restore flow control */
6208 dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF);
6210 dhd_os_wd_timer(dhdp, dhd_watchdog_ms);
6212 DHD_TRACE(("%s: WLAN ON DONE\n", __FUNCTION__));
6214 dhd_bus_stop(bus, FALSE);
6215 dhdsdio_release_dongle(bus, bus->dhd->osh,
6219 bcmerror = BCME_SDIO_ERROR;
6221 bcmerror = BCME_SDIO_ERROR;
6223 dhd_os_sdunlock(dhdp);
6225 DHD_INFO(("%s called when dongle is not in reset\n",
6227 DHD_INFO(("Will call dhd_bus_start instead\n"));
6228 sdioh_start(NULL, 1);
6229 if ((bcmerror = dhd_bus_start(dhdp)) != 0)
6230 DHD_ERROR(("%s: dhd_bus_start fail with %d\n",
6231 __FUNCTION__, bcmerror));
6238 dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint size)
6243 return dhdsdio_membytes(bus, set, address, data, size);