2 * DHD Bus Module for SDIO
4 * Copyright (C) 1999-2013, 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 426658 2013-09-30 12:14:01Z $
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 bool dhd_mp_halting(dhd_pub_t *dhdp);
70 extern void bcmsdh_waitfor_iodrain(void *sdh);
71 extern void bcmsdh_reject_ioreqs(void *sdh, bool reject);
72 extern bool bcmsdh_fatal_error(void *sdh);
74 #ifndef DHDSDIO_MEM_DUMP_FNAME
75 #define DHDSDIO_MEM_DUMP_FNAME "mem_dump"
78 #define QLEN 256 /* bulk rx and tx queue lengths */
79 #define FCHI (QLEN - 10)
80 #define FCLOW (FCHI / 2)
83 #define TXRETRIES 2 /* # of retries for tx frames */
85 #define DHD_RXBOUND 50 /* Default for max rx frames in one scheduling */
89 #define DHD_TXBOUND 20 /* Default for max tx frames in one scheduling */
92 #define DHD_TXMINMAX 1 /* Max tx frames if rx still pending */
94 #define MEMBLOCK 2048 /* Block size used for downloading of dongle image */
95 #define MAX_NVRAMBUF_SIZE 4096 /* max nvram buf size */
96 #define MAX_DATA_BUF (32 * 1024) /* Must be large enough to hold biggest possible glom */
99 #define DHD_FIRSTREAD 32
101 #if !ISPOWEROF2(DHD_FIRSTREAD)
102 #error DHD_FIRSTREAD is not a power of 2!
105 #ifdef BCMSDIOH_TXGLOM
106 /* Total length of TX frame header for dongle protocol */
107 #define SDPCM_HDRLEN (SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN + SDPCM_SWHEADER_LEN)
108 /* Total length of RX frame for dongle protocol */
110 /* Total length of TX frame header for dongle protocol */
111 #define SDPCM_HDRLEN (SDPCM_FRAMETAG_LEN + SDPCM_SWHEADER_LEN)
114 #define SDPCM_HDRLEN_RX (SDPCM_FRAMETAG_LEN + SDPCM_SWHEADER_LEN)
117 #define SDPCM_RESERVE (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN)
119 #define SDPCM_RESERVE (SDPCM_HDRLEN + DHD_SDALIGN)
122 /* Space for header read, limit for data packets */
124 #define MAX_HDR_READ 32
126 #if !ISPOWEROF2(MAX_HDR_READ)
127 #error MAX_HDR_READ is not a power of 2!
130 #define MAX_RX_DATASZ 2048
132 /* Maximum milliseconds to wait for F2 to come up */
133 #define DHD_WAIT_F2RDY 3000
135 /* Bump up limit on waiting for HT to account for first startup;
136 * if the image is doing a CRC calculation before programming the PMU
137 * for HT availability, it could take a couple hundred ms more, so
138 * max out at a 1 second (1000000us).
140 #if (PMU_MAX_TRANSITION_DLY <= 1000000)
141 #undef PMU_MAX_TRANSITION_DLY
142 #define PMU_MAX_TRANSITION_DLY 1000000
145 /* Value for ChipClockCSR during initial setup */
146 #define DHD_INIT_CLKCTL1 (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ)
147 #define DHD_INIT_CLKCTL2 (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP)
149 /* Flags for SDH calls */
150 #define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED)
152 /* Packet free applicable unconditionally for sdio and sdspi. Conditional if
153 * bufpool was present for gspi bus.
155 #define PKTFREE2() if ((bus->bus != SPI_BUS) || bus->usebufpool) \
156 PKTFREE(bus->dhd->osh, pkt, FALSE);
157 DHD_SPINWAIT_SLEEP_INIT(sdioh_spinwait_sleep);
158 #if defined(OOB_INTR_ONLY)
159 extern void bcmsdh_set_irq(int flag);
162 extern void dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success);
163 extern void dhd_wlfc_trigger_pktcommit(dhd_pub_t *dhd);
164 #ifdef DHDTCPACK_SUPPRESS
165 extern int dhd_os_wlfc_block(dhd_pub_t *pub);
166 extern int dhd_os_wlfc_unblock(dhd_pub_t *pub);
167 #endif /* DHDTCPACK_SUPPRESS */
168 #endif /* PROP_TXSTATUS */
172 /* Device console log buffer state */
173 #define CONSOLE_LINE_MAX 192
174 #define CONSOLE_BUFFER_MAX 2024
175 typedef struct dhd_console {
176 uint count; /* Poll interval msec counter */
177 uint log_addr; /* Log struct address (fixed) */
178 hndrte_log_t log; /* Log struct (host copy) */
179 uint bufsize; /* Size of log buffer */
180 uint8 *buf; /* Log buffer (host copy) */
181 uint last; /* Last buffer read index */
183 #endif /* DHD_DEBUG */
185 #define REMAP_ENAB(bus) ((bus)->remap)
186 #define REMAP_ISADDR(bus, a) (((a) >= ((bus)->orig_ramsize)) && ((a) < ((bus)->ramsize)))
187 #define KSO_ENAB(bus) ((bus)->kso)
188 #define SR_ENAB(bus) ((bus)->_srenab)
189 #define SLPAUTO_ENAB(bus) ((SR_ENAB(bus)) && ((bus)->_slpauto))
190 #define MIN_RSRC_ADDR (SI_ENUM_BASE + 0x618)
191 #define MIN_RSRC_SR 0x3
192 #define CORE_CAPEXT_ADDR (SI_ENUM_BASE + 0x64c)
193 #define CORE_CAPEXT_SR_SUPPORTED_MASK (1 << 1)
194 #define RCTL_MACPHY_DISABLE_MASK (1 << 26)
195 #define RCTL_LOGIC_DISABLE_MASK (1 << 27)
197 #define OOB_WAKEUP_ENAB(bus) ((bus)->_oobwakeup)
198 #define GPIO_DEV_SRSTATE 16 /* Host gpio17 mapped to device gpio0 SR state */
199 #define GPIO_DEV_SRSTATE_TIMEOUT 320000 /* 320ms */
200 #define GPIO_DEV_WAKEUP 17 /* Host gpio17 mapped to device gpio1 wakeup */
201 #define CC_CHIPCTRL2_GPIO1_WAKEUP (1 << 0)
202 #define CC_CHIPCTRL3_SR_ENG_ENABLE (1 << 2)
203 #define OVERFLOW_BLKSZ512_WM 48
204 #define OVERFLOW_BLKSZ512_MES 80
206 #define CC_PMUCC3 (0x3)
207 /* Private data for SDIO bus interaction */
208 typedef struct dhd_bus {
211 bcmsdh_info_t *sdh; /* Handle for BCMSDH calls */
212 si_t *sih; /* Handle for SI calls */
213 char *vars; /* Variables (from CIS and/or other) */
214 uint varsz; /* Size of variables buffer */
215 uint32 sbaddr; /* Current SB window pointer (-1, invalid) */
217 sdpcmd_regs_t *regs; /* Registers for SDIO core */
218 uint sdpcmrev; /* SDIO core revision */
219 uint armrev; /* CPU core revision */
220 uint ramrev; /* SOCRAM core revision */
221 uint32 ramsize; /* Size of RAM in SOCRAM (bytes) */
222 uint32 orig_ramsize; /* Size of RAM in SOCRAM (bytes) */
223 uint32 srmemsize; /* Size of SRMEM */
225 uint32 bus; /* gSPI or SDIO bus */
226 uint32 hostintmask; /* Copy of Host Interrupt Mask */
227 uint32 intstatus; /* Intstatus bits (events) pending */
228 bool dpc_sched; /* Indicates DPC schedule (intrpt rcvd) */
229 bool fcstate; /* State of dongle flow-control */
231 uint16 cl_devid; /* cached devid for dhdsdio_probe_attach() */
232 char *fw_path; /* module_param: path to firmware image */
233 char *nv_path; /* module_param: path to nvram vars file */
234 const char *nvram_params; /* user specified nvram params. */
236 uint blocksize; /* Block size of SDIO transfers */
237 uint roundup; /* Max roundup limit */
239 struct pktq txq; /* Queue length used for flow-control */
240 uint8 flowcontrol; /* per prio flow control bitmask */
241 uint8 tx_seq; /* Transmit sequence number (next) */
242 uint8 tx_max; /* Maximum transmit sequence allowed */
244 uint8 hdrbuf[MAX_HDR_READ + DHD_SDALIGN];
245 uint8 *rxhdr; /* Header of current rx frame (in hdrbuf) */
246 uint16 nextlen; /* Next Read Len from last header */
247 uint8 rx_seq; /* Receive sequence number (expected) */
248 bool rxskip; /* Skip receive (awaiting NAK ACK) */
250 void *glomd; /* Packet containing glomming descriptor */
251 void *glom; /* Packet chain for glommed superframe */
252 uint glomerr; /* Glom packet read errors */
254 uint8 *rxbuf; /* Buffer for receiving control packets */
255 uint rxblen; /* Allocated length of rxbuf */
256 uint8 *rxctl; /* Aligned pointer into rxbuf */
257 uint8 *databuf; /* Buffer for receiving big glom packet */
258 uint8 *dataptr; /* Aligned pointer into databuf */
259 uint rxlen; /* Length of valid data in buffer */
261 uint8 sdpcm_ver; /* Bus protocol reported by dongle */
263 bool intr; /* Use interrupts */
264 bool poll; /* Use polling */
265 bool ipend; /* Device interrupt is pending */
266 bool intdis; /* Interrupts disabled by isr */
267 uint intrcount; /* Count of device interrupt callbacks */
268 uint lastintrs; /* Count as of last watchdog timer */
269 uint spurious; /* Count of spurious interrupts */
270 uint pollrate; /* Ticks between device polls */
271 uint polltick; /* Tick counter */
272 uint pollcnt; /* Count of active polls */
275 dhd_console_t console; /* Console output polling support */
276 uint console_addr; /* Console address from shared struct */
277 #endif /* DHD_DEBUG */
279 uint regfails; /* Count of R_REG/W_REG failures */
281 uint clkstate; /* State of sd and backplane clock(s) */
282 bool activity; /* Activity flag for clock down */
283 int32 idletime; /* Control for activity timeout */
284 int32 idlecount; /* Activity timeout counter */
285 int32 idleclock; /* How to set bus driver when idle */
286 int32 sd_divisor; /* Speed control to bus driver */
287 int32 sd_mode; /* Mode control to bus driver */
288 int32 sd_rxchain; /* If bcmsdh api accepts PKT chains */
289 bool use_rxchain; /* If dhd should use PKT chains */
290 bool sleeping; /* Is SDIO bus sleeping? */
291 uint rxflow_mode; /* Rx flow control mode */
292 bool rxflow; /* Is rx flow control on */
293 uint prev_rxlim_hit; /* Is prev rx limit exceeded (per dpc schedule) */
294 bool alp_only; /* Don't use HT clock (ALP only) */
295 /* Field to decide if rx of control frames happen in rxbuf or lb-pool */
299 /* external loopback */
303 /* pktgen configuration */
304 uint pktgen_freq; /* Ticks between bursts */
305 uint pktgen_count; /* Packets to send each burst */
306 uint pktgen_print; /* Bursts between count displays */
307 uint pktgen_total; /* Stop after this many */
308 uint pktgen_minlen; /* Minimum packet data len */
309 uint pktgen_maxlen; /* Maximum packet data len */
310 uint pktgen_mode; /* Configured mode: tx, rx, or echo */
311 uint pktgen_stop; /* Number of tx failures causing stop */
313 /* active pktgen fields */
314 uint pktgen_tick; /* Tick counter for bursts */
315 uint pktgen_ptick; /* Burst counter for printing */
316 uint pktgen_sent; /* Number of test packets generated */
317 uint pktgen_rcvd; /* Number of test packets received */
318 uint pktgen_prev_time; /* Time at which previous stats where printed */
319 uint pktgen_prev_sent; /* Number of test packets generated when
320 * previous stats were printed
322 uint pktgen_prev_rcvd; /* Number of test packets received when
323 * previous stats were printed
325 uint pktgen_fail; /* Number of failed send attempts */
326 uint16 pktgen_len; /* Length of next packet to send */
327 #define PKTGEN_RCV_IDLE (0)
328 #define PKTGEN_RCV_ONGOING (1)
329 uint16 pktgen_rcv_state; /* receive state */
330 uint pktgen_rcvd_rcvsession; /* test pkts rcvd per rcv session. */
333 /* Some additional counters */
334 uint tx_sderrs; /* Count of tx attempts with sd errors */
335 uint fcqueued; /* Tx packets that got queued */
336 uint rxrtx; /* Count of rtx requests (NAK to dongle) */
337 uint rx_toolong; /* Receive frames too long to receive */
338 uint rxc_errors; /* SDIO errors when reading control frames */
339 uint rx_hdrfail; /* SDIO errors on header reads */
340 uint rx_badhdr; /* Bad received headers (roosync?) */
341 uint rx_badseq; /* Mismatched rx sequence number */
342 uint fc_rcvd; /* Number of flow-control events received */
343 uint fc_xoff; /* Number which turned on flow-control */
344 uint fc_xon; /* Number which turned off flow-control */
345 uint rxglomfail; /* Failed deglom attempts */
346 uint rxglomframes; /* Number of glom frames (superframes) */
347 uint rxglompkts; /* Number of packets from glom frames */
348 uint f2rxhdrs; /* Number of header reads */
349 uint f2rxdata; /* Number of frame data reads */
350 uint f2txdata; /* Number of f2 frame writes */
351 uint f1regdata; /* Number of f1 register accesses */
353 uint8 *ctrl_frame_buf;
354 uint32 ctrl_frame_len;
355 bool ctrl_frame_stat;
356 uint32 rxint_mode; /* rx interrupt mode */
357 bool remap; /* Contiguous 1MB RAM: 512K socram + 512K devram
358 * Available with socram rev 16
359 * Remap region not DMA-able
368 uint32 dongle_ram_base;
369 #ifdef BCMSDIOH_TXGLOM
370 void *glom_pkt_arr[SDPCM_MAXGLOM_SIZE]; /* Array of pkts for glomming */
371 uint16 glom_cnt; /* Number of pkts in the glom array */
372 uint16 glom_total_len; /* Total length of pkts in glom array */
373 bool glom_enable; /* Flag to indicate whether tx glom is enabled/disabled */
374 uint8 glom_mode; /* Glom mode - 0-copy mode, 1 - Multi-descriptor mode */
375 uint32 glomsize; /* Glom size limitation */
382 #define CLK_PENDING 2 /* Not used yet */
385 #define DHD_NOPMU(dhd) (FALSE)
388 static int qcount[NUMPRIO];
389 static int tx_packets[NUMPRIO];
390 #endif /* DHD_DEBUG */
392 /* Deferred transmit */
393 const uint dhd_deferred_tx = 1;
395 extern uint dhd_watchdog_ms;
397 extern void dhd_os_wd_timer(void *bus, uint wdtick);
402 uint dhd_txminmax = DHD_TXMINMAX;
404 /* override the RAM size if possible */
405 #define DONGLE_MIN_RAMSIZE (128 *1024)
406 int dhd_dongle_ramsize;
408 uint dhd_doflow = TRUE;
409 uint dhd_dpcpoll = FALSE;
411 module_param(dhd_doflow, uint, 0644);
412 module_param(dhd_dpcpoll, uint, 0644);
414 static bool dhd_alignctl;
418 static bool retrydata;
419 #define RETRYCHAN(chan) (((chan) == SDPCM_EVENT_CHANNEL) || retrydata)
421 #if defined(SDIO_CRC_ERROR_FIX)
422 static uint watermark = 48;
423 static uint mesbusyctrl = 80;
425 static const uint watermark = 8;
426 static const uint mesbusyctrl = 0;
428 static const uint firstread = DHD_FIRSTREAD;
430 #define HDATLEN (firstread - (SDPCM_HDRLEN))
432 /* Retry count for register access failures */
433 static const uint retry_limit = 2;
435 /* Force even SD lengths (some host controllers mess up on odd bytes) */
436 static bool forcealign;
440 #if defined(OOB_INTR_ONLY) && defined(HW_OOB)
441 extern void bcmsdh_enable_hw_oob_intr(void *sdh, bool enable);
444 #if defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD)
445 #error OOB_INTR_ONLY is NOT working with SDIO_ISR_THREAD
446 #endif /* defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD) */
447 #define PKTALIGN(osh, p, len, align) \
450 datalign = (uintptr)PKTDATA((osh), (p)); \
451 datalign = ROUNDUP(datalign, (align)) - datalign; \
452 ASSERT(datalign < (align)); \
453 ASSERT(PKTLEN((osh), (p)) >= ((len) + datalign)); \
455 PKTPULL((osh), (p), datalign); \
456 PKTSETLEN((osh), (p), (len)); \
459 /* Limit on rounding up frames */
460 static const uint max_roundup = 512;
462 /* Try doing readahead */
463 static bool dhd_readahead;
465 /* To check if there's window offered */
466 #define DATAOK(bus) \
467 (((uint8)(bus->tx_max - bus->tx_seq) > 1) && \
468 (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0))
470 /* To check if there's window offered for ctrl frame */
471 #define TXCTLOK(bus) \
472 (((uint8)(bus->tx_max - bus->tx_seq) != 0) && \
473 (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0))
475 /* Number of pkts available in dongle for data RX */
476 #define DATABUFCNT(bus) \
477 ((uint8)(bus->tx_max - bus->tx_seq) - 1)
479 /* Macros to get register read/write status */
480 /* NOTE: these assume a local dhdsdio_bus_t *bus! */
481 #define R_SDREG(regvar, regaddr, retryvar) \
485 regvar = R_REG(bus->dhd->osh, regaddr); \
486 } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \
488 bus->regfails += (retryvar-1); \
489 if (retryvar > retry_limit) { \
490 DHD_ERROR(("%s: FAILED" #regvar "READ, LINE %d\n", \
491 __FUNCTION__, __LINE__)); \
497 #define W_SDREG(regval, regaddr, retryvar) \
501 W_REG(bus->dhd->osh, regaddr, regval); \
502 } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \
504 bus->regfails += (retryvar-1); \
505 if (retryvar > retry_limit) \
506 DHD_ERROR(("%s: FAILED REGISTER WRITE, LINE %d\n", \
507 __FUNCTION__, __LINE__)); \
511 #define BUS_WAKE(bus) \
513 bus->idlecount = 0; \
514 if ((bus)->sleeping) \
515 dhdsdio_bussleep((bus), FALSE); \
519 * pktavail interrupts from dongle to host can be managed in 3 different ways
520 * whenever there is a packet available in dongle to transmit to host.
522 * Mode 0: Dongle writes the software host mailbox and host is interrupted.
523 * Mode 1: (sdiod core rev >= 4)
524 * Device sets a new bit in the intstatus whenever there is a packet
525 * available in fifo. Host can't clear this specific status bit until all the
526 * packets are read from the FIFO. No need to ack dongle intstatus.
527 * Mode 2: (sdiod core rev >= 4)
528 * Device sets a bit in the intstatus, and host acks this by writing
529 * one to this bit. Dongle won't generate anymore packet interrupts
530 * until host reads all the packets from the dongle and reads a zero to
531 * figure that there are no more packets. No need to disable host ints.
532 * Need to ack the intstatus.
535 #define SDIO_DEVICE_HMB_RXINT 0 /* default old way */
536 #define SDIO_DEVICE_RXDATAINT_MODE_0 1 /* from sdiod rev 4 */
537 #define SDIO_DEVICE_RXDATAINT_MODE_1 2 /* from sdiod rev 4 */
540 #define FRAME_AVAIL_MASK(bus) \
541 ((bus->rxint_mode == SDIO_DEVICE_HMB_RXINT) ? I_HMB_FRAME_IND : I_XMTDATA_AVAIL)
543 #define DHD_BUS SDIO_BUS
545 #define PKT_AVAILABLE(bus, intstatus) ((intstatus) & (FRAME_AVAIL_MASK(bus)))
547 #define HOSTINTMASK (I_HMB_SW_MASK | I_CHIPACTIVE)
549 #define GSPI_PR55150_BAILOUT
552 static void dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq);
553 static void dhdsdio_sdtest_set(dhd_bus_t *bus, uint count);
557 static int dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size);
558 static int dhd_serialconsole(dhd_bus_t *bus, bool get, bool enable, int *bcmerror);
559 #endif /* DHD_DEBUG */
561 static int dhdsdio_devcap_set(dhd_bus_t *bus, uint8 cap);
562 static int dhdsdio_download_state(dhd_bus_t *bus, bool enter);
564 static void dhdsdio_release(dhd_bus_t *bus, osl_t *osh);
565 static void dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh);
566 static void dhdsdio_disconnect(void *ptr);
567 static bool dhdsdio_chipmatch(uint16 chipid);
568 static bool dhdsdio_probe_attach(dhd_bus_t *bus, osl_t *osh, void *sdh,
569 void * regsva, uint16 devid);
570 static bool dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh);
571 static bool dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh);
572 static void dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation,
575 static void dhd_dongle_setramsize(struct dhd_bus *bus, int mem_size);
576 static int dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags,
577 uint8 *buf, uint nbytes,
578 void *pkt, bcmsdh_cmplt_fn_t complete, void *handle);
579 static int dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags,
580 uint8 *buf, uint nbytes,
581 void *pkt, bcmsdh_cmplt_fn_t complete, void *handle);
582 #ifdef BCMSDIOH_TXGLOM
583 static void dhd_bcmsdh_glom_post(dhd_bus_t *bus, uint8 *frame, void *pkt, uint len);
584 static void dhd_bcmsdh_glom_clear(dhd_bus_t *bus);
587 static bool dhdsdio_download_firmware(dhd_bus_t *bus, osl_t *osh, void *sdh);
588 static int _dhdsdio_download_firmware(dhd_bus_t *bus);
590 static int dhdsdio_download_code_file(dhd_bus_t *bus, char *image_path);
591 static int dhdsdio_download_nvram(dhd_bus_t *bus);
593 static int dhdsdio_download_code_array(dhd_bus_t *bus);
595 static int dhdsdio_bussleep(dhd_bus_t *bus, bool sleep);
596 static int dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok);
597 static uint8 dhdsdio_sleepcsr_get(dhd_bus_t *bus);
601 extern uint32 dhd_get_htsf(void *dhd, int ifidx);
602 #endif /* WLMEDIA_HTSF */
605 dhd_overflow_war(struct dhd_bus *bus)
608 uint8 devctl, wm, mes;
610 /* See .ppt in PR for these recommended values */
611 if (bus->blocksize == 512) {
612 wm = OVERFLOW_BLKSZ512_WM;
613 mes = OVERFLOW_BLKSZ512_MES;
615 mes = bus->blocksize/4;
616 wm = bus->blocksize/4;
620 /* Update watermark */
621 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, wm, &err);
623 devctl = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
624 devctl |= SBSDIO_DEVCTL_F2WM_ENAB;
625 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
628 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL,
629 (mes | SBSDIO_MESBUSYCTRL_ENAB), &err);
631 DHD_INFO(("Apply overflow WAR: 0x%02x 0x%02x 0x%02x\n",
632 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err),
633 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, &err),
634 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL, &err)));
638 dhd_dongle_setramsize(struct dhd_bus *bus, int mem_size)
640 int32 min_size = DONGLE_MIN_RAMSIZE;
641 /* Restrict the ramsize to user specified limit */
642 DHD_ERROR(("user: Restrict the dongle ram size to %d, min accepted %d\n",
643 dhd_dongle_ramsize, min_size));
644 if ((dhd_dongle_ramsize > min_size) &&
645 (dhd_dongle_ramsize < (int32)bus->orig_ramsize))
646 bus->ramsize = dhd_dongle_ramsize;
650 dhdsdio_set_siaddr_window(dhd_bus_t *bus, uint32 address)
653 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW,
654 (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err);
656 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID,
657 (address >> 16) & SBSDIO_SBADDRMID_MASK, &err);
659 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH,
660 (address >> 24) & SBSDIO_SBADDRHIGH_MASK, &err);
667 dhdsdio_oobwakeup_init(dhd_bus_t *bus)
669 uint32 val, addr, data;
671 bcmsdh_gpioouten(bus->sdh, GPIO_DEV_WAKEUP);
673 addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr);
674 data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data);
676 /* Set device for gpio1 wakeup */
677 bcmsdh_reg_write(bus->sdh, addr, 4, 2);
678 val = bcmsdh_reg_read(bus->sdh, data, 4);
679 val |= CC_CHIPCTRL2_GPIO1_WAKEUP;
680 bcmsdh_reg_write(bus->sdh, data, 4, val);
682 bus->_oobwakeup = TRUE;
686 #endif /* USE_OOB_GPIO1 */
689 * Query if FW is in SR mode
692 dhdsdio_sr_cap(dhd_bus_t *bus)
695 uint32 core_capext, addr, data;
696 if (bus->sih->chip == BCM4324_CHIP_ID) {
697 addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr);
698 data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data);
699 bcmsdh_reg_write(bus->sdh, addr, 4, 3);
700 core_capext = bcmsdh_reg_read(bus->sdh, data, 4);
701 } else if (bus->sih->chip == BCM4330_CHIP_ID) {
703 } else if ((bus->sih->chip == BCM4335_CHIP_ID) ||
704 (bus->sih->chip == BCM4339_CHIP_ID) ||
705 (bus->sih->chip == BCM4350_CHIP_ID)) {
708 core_capext = bcmsdh_reg_read(bus->sdh, CORE_CAPEXT_ADDR, 4);
709 core_capext = (core_capext & CORE_CAPEXT_SR_SUPPORTED_MASK);
714 if (bus->sih->chip == BCM4324_CHIP_ID) {
715 /* FIX: Should change to query SR control register instead */
717 } else if ((bus->sih->chip == BCM4335_CHIP_ID) ||
718 (bus->sih->chip == BCM4339_CHIP_ID)) {
720 addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr);
721 data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data);
722 bcmsdh_reg_write(bus->sdh, addr, 4, CC_PMUCC3);
723 enabval = bcmsdh_reg_read(bus->sdh, data, 4);
725 if ((bus->sih->chip == BCM4350_CHIP_ID) ||
727 enabval &= CC_CHIPCTRL3_SR_ENG_ENABLE;
733 data = bcmsdh_reg_read(bus->sdh,
734 SI_ENUM_BASE + OFFSETOF(chipcregs_t, retention_ctl), 4);
735 if ((data & (RCTL_MACPHY_DISABLE_MASK | RCTL_LOGIC_DISABLE_MASK)) == 0)
743 dhdsdio_srwar_init(dhd_bus_t *bus)
745 bcmsdh_gpio_init(bus->sdh);
748 dhdsdio_oobwakeup_init(bus);
756 dhdsdio_sr_init(dhd_bus_t *bus)
761 if ((bus->sih->chip == BCM4334_CHIP_ID) && (bus->sih->chiprev == 2))
762 dhdsdio_srwar_init(bus);
764 val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, NULL);
765 val |= 1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT;
766 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL,
767 1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT, &err);
768 val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, NULL);
770 /* Add CMD14 Support */
771 dhdsdio_devcap_set(bus,
772 (SDIOD_CCCR_BRCM_CARDCAP_CMD14_SUPPORT | SDIOD_CCCR_BRCM_CARDCAP_CMD14_EXT));
774 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1,
775 SBSDIO_FUNC1_CHIPCLKCSR, SBSDIO_FORCE_HT, &err);
777 bus->_slpauto = dhd_slpauto ? TRUE : FALSE;
785 * FIX: Be sure KSO bit is enabled
786 * Currently, it's defaulting to 0 which should be 1.
789 dhdsdio_clk_kso_init(dhd_bus_t *bus)
798 * Enable KeepSdioOn (KSO) bit for normal operation
799 * Default is 0 (4334A0) so set it. Fixed in B0.
801 val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, NULL);
802 if (!(val & SBSDIO_FUNC1_SLEEPCSR_KSO_MASK)) {
803 val |= (SBSDIO_FUNC1_SLEEPCSR_KSO_EN << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT);
804 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, val, &err);
806 DHD_ERROR(("%s: SBSDIO_FUNC1_SLEEPCSR err: 0x%x\n", __FUNCTION__, err));
813 #define KSO_WAIT_US 50
814 #define MAX_KSO_ATTEMPTS (PMU_MAX_TRANSITION_DLY/KSO_WAIT_US)
816 dhdsdio_clk_kso_enab(dhd_bus_t *bus, bool on)
818 uint8 wr_val = 0, rd_val, cmp_val, bmask;
822 KSO_DBG(("%s> op:%s\n", __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR")));
824 wr_val |= (on << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT);
826 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, wr_val, &err);
829 cmp_val = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK | SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK;
834 /* Put device to sleep, turn off KSO */
836 bmask = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK;
840 rd_val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, &err);
841 if (((rd_val & bmask) == cmp_val) && !err)
844 KSO_DBG(("%s> KSO wr/rd retry:%d, ERR:%x \n", __FUNCTION__, try_cnt, err));
845 OSL_DELAY(KSO_WAIT_US);
847 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, wr_val, &err);
848 } while (try_cnt++ < MAX_KSO_ATTEMPTS);
852 KSO_DBG(("%s> op:%s, try_cnt:%d, rd_val:%x, ERR:%x \n",
853 __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"), try_cnt, rd_val, err));
855 if (try_cnt > MAX_KSO_ATTEMPTS) {
856 DHD_ERROR(("%s> op:%s, ERROR: try_cnt:%d, rd_val:%x, ERR:%x \n",
857 __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"), try_cnt, rd_val, err));
863 dhdsdio_clk_kso_iovar(dhd_bus_t *bus, bool on)
870 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
872 DHD_ERROR(("%s: KSO disable clk: 0x%x\n", __FUNCTION__,
873 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
874 SBSDIO_FUNC1_CHIPCLKCSR, &err)));
875 dhdsdio_clk_kso_enab(bus, FALSE);
877 DHD_ERROR(("%s: KSO enable\n", __FUNCTION__));
879 /* Make sure we have SD bus access */
880 if (bus->clkstate == CLK_NONE) {
881 DHD_ERROR(("%s: Request SD clk\n", __FUNCTION__));
882 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
885 dhdsdio_clk_kso_enab(bus, TRUE);
887 DHD_ERROR(("%s: sleepcsr: 0x%x\n", __FUNCTION__,
888 dhdsdio_sleepcsr_get(bus)));
898 dhdsdio_sleepcsr_get(dhd_bus_t *bus)
903 val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, &err);
905 DHD_TRACE(("Failed to read SLEEPCSR: %d\n", err));
911 dhdsdio_devcap_get(dhd_bus_t *bus)
913 return bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_BRCM_CARDCAP, NULL);
917 dhdsdio_devcap_set(dhd_bus_t *bus, uint8 cap)
921 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_BRCM_CARDCAP, cap, &err);
923 DHD_ERROR(("%s: devcap set err: 0x%x\n", __FUNCTION__, err));
929 dhdsdio_clk_devsleep_iovar(dhd_bus_t *bus, bool on)
938 /* Be sure we request clk before going to sleep
939 * so we can wake-up with clk request already set
940 * else device can go back to sleep immediately
942 if (!SLPAUTO_ENAB(bus))
943 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
945 val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
946 if ((val & SBSDIO_CSR_MASK) == 0) {
947 DHD_ERROR(("%s: No clock before enter sleep:0x%x\n",
950 /* Reset clock request */
951 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
952 SBSDIO_ALP_AVAIL_REQ, &err);
953 DHD_ERROR(("%s: clock before sleep:0x%x\n", __FUNCTION__,
954 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
955 SBSDIO_FUNC1_CHIPCLKCSR, &err)));
959 DHD_TRACE(("%s: clk before sleep: 0x%x\n", __FUNCTION__,
960 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
961 SBSDIO_FUNC1_CHIPCLKCSR, &err)));
962 err = dhdsdio_clk_kso_enab(bus, FALSE);
963 if (OOB_WAKEUP_ENAB(bus))
965 err = bcmsdh_gpioout(bus->sdh, GPIO_DEV_WAKEUP, FALSE); /* GPIO_1 is off */
969 /* Make sure we have SD bus access */
970 if (bus->clkstate == CLK_NONE) {
971 DHD_TRACE(("%s: Request SD clk\n", __FUNCTION__));
972 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
975 if ((bus->sih->chip == BCM4334_CHIP_ID) && (bus->sih->chiprev == 2)) {
976 SPINWAIT_SLEEP(sdioh_spinwait_sleep,
977 (bcmsdh_gpioin(bus->sdh, GPIO_DEV_SRSTATE) != TRUE),
978 GPIO_DEV_SRSTATE_TIMEOUT);
980 if (bcmsdh_gpioin(bus->sdh, GPIO_DEV_SRSTATE) == FALSE) {
981 DHD_ERROR(("ERROR: GPIO_DEV_SRSTATE still low!\n"));
984 if (OOB_WAKEUP_ENAB(bus))
986 err = bcmsdh_gpioout(bus->sdh, GPIO_DEV_WAKEUP, TRUE); /* GPIO_1 is on */
989 err = dhdsdio_clk_kso_enab(bus, TRUE);
992 } while ((err != 0) && (++retry < 3));
995 DHD_ERROR(("ERROR: kso set failed retry: %d\n", retry));
996 err = 0; /* continue anyway */
1002 /* Wait for device ready during transition to wake-up */
1003 SPINWAIT_SLEEP(sdioh_spinwait_sleep,
1004 (((csr = dhdsdio_sleepcsr_get(bus)) &
1005 SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK) !=
1006 (SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK)), (20000));
1008 DHD_TRACE(("%s: ExitSleep sleepcsr: 0x%x\n", __FUNCTION__, csr));
1010 if (!(csr & SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK)) {
1011 DHD_ERROR(("%s:ERROR: ExitSleep device NOT Ready! 0x%x\n",
1012 __FUNCTION__, csr));
1013 err = BCME_NODEVICE;
1016 SPINWAIT_SLEEP(sdioh_spinwait_sleep,
1017 (((csr = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
1018 SBSDIO_FUNC1_CHIPCLKCSR, &err)) & SBSDIO_HT_AVAIL) !=
1019 (SBSDIO_HT_AVAIL)), (10000));
1024 /* Update if successful */
1026 bus->kso = on ? FALSE : TRUE;
1028 DHD_ERROR(("%s: Sleep request failed: on:%d err:%d\n", __FUNCTION__, on, err));
1029 if (!on && retry > 2)
1036 /* Turn backplane clock on or off */
1038 dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok)
1040 #define HT_AVAIL_ERROR_MAX 10
1041 static int ht_avail_error = 0;
1043 uint8 clkctl, clkreq, devctl;
1046 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1055 if (SLPAUTO_ENAB(bus)) {
1056 bus->clkstate = (on ? CLK_AVAIL : CLK_SDONLY);
1061 /* Request HT Avail */
1062 clkreq = bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ;
1066 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
1069 if (ht_avail_error < HT_AVAIL_ERROR_MAX) {
1070 DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err));
1073 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
1074 else if (ht_avail_error == HT_AVAIL_ERROR_MAX) {
1075 dhd_os_send_hang_message(bus->dhd);
1077 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) */
1084 /* Check current status */
1085 clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
1087 DHD_ERROR(("%s: HT Avail read error: %d\n", __FUNCTION__, err));
1091 #if !defined(OOB_INTR_ONLY)
1092 /* Go to pending and await interrupt if appropriate */
1093 if (!SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) {
1094 /* Allow only clock-available interrupt */
1095 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
1097 DHD_ERROR(("%s: Devctl access error setting CA: %d\n",
1098 __FUNCTION__, err));
1102 devctl |= SBSDIO_DEVCTL_CA_INT_ONLY;
1103 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
1104 DHD_INFO(("CLKCTL: set PENDING\n"));
1105 bus->clkstate = CLK_PENDING;
1108 #endif /* !defined (OOB_INTR_ONLY) */
1110 if (bus->clkstate == CLK_PENDING) {
1111 /* Cancel CA-only interrupt filter */
1112 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
1113 devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
1114 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
1118 /* Otherwise, wait here (polling) for HT Avail */
1119 if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
1120 SPINWAIT_SLEEP(sdioh_spinwait_sleep,
1121 ((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
1122 SBSDIO_FUNC1_CHIPCLKCSR, &err)),
1123 !SBSDIO_CLKAV(clkctl, bus->alp_only)), PMU_MAX_TRANSITION_DLY);
1126 DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err));
1129 if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
1130 DHD_ERROR(("%s: HT Avail timeout (%d): clkctl 0x%02x\n",
1131 __FUNCTION__, PMU_MAX_TRANSITION_DLY, clkctl));
1135 /* Mark clock available */
1136 bus->clkstate = CLK_AVAIL;
1137 DHD_INFO(("CLKCTL: turned ON\n"));
1139 #if defined(DHD_DEBUG)
1140 if (bus->alp_only == TRUE) {
1141 #if !defined(BCMLXSDMMC)
1142 if (!SBSDIO_ALPONLY(clkctl)) {
1143 DHD_ERROR(("%s: HT Clock, when ALP Only\n", __FUNCTION__));
1145 #endif /* !defined(BCMLXSDMMC) */
1147 if (SBSDIO_ALPONLY(clkctl)) {
1148 DHD_ERROR(("%s: HT Clock should be on.\n", __FUNCTION__));
1151 #endif /* defined (DHD_DEBUG) */
1153 bus->activity = TRUE;
1154 #ifdef DHD_USE_IDLECOUNT
1156 #endif /* DHD_USE_IDLECOUNT */
1160 if (bus->clkstate == CLK_PENDING) {
1161 /* Cancel CA-only interrupt filter */
1162 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
1163 devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
1164 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
1167 bus->clkstate = CLK_SDONLY;
1168 if (!SR_ENAB(bus)) {
1169 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
1170 DHD_INFO(("CLKCTL: turned OFF\n"));
1172 DHD_ERROR(("%s: Failed access turning clock off: %d\n",
1173 __FUNCTION__, err));
1181 /* Change idle/active SD state */
1183 dhdsdio_sdclk(dhd_bus_t *bus, bool on)
1188 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1191 if (bus->idleclock == DHD_IDLE_STOP) {
1192 /* Turn on clock and restore mode */
1194 err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0,
1195 &iovalue, sizeof(iovalue), TRUE);
1197 DHD_ERROR(("%s: error enabling sd_clock: %d\n",
1198 __FUNCTION__, err));
1202 iovalue = bus->sd_mode;
1203 err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
1204 &iovalue, sizeof(iovalue), TRUE);
1206 DHD_ERROR(("%s: error changing sd_mode: %d\n",
1207 __FUNCTION__, err));
1210 } else if (bus->idleclock != DHD_IDLE_ACTIVE) {
1211 /* Restore clock speed */
1212 iovalue = bus->sd_divisor;
1213 err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
1214 &iovalue, sizeof(iovalue), TRUE);
1216 DHD_ERROR(("%s: error restoring sd_divisor: %d\n",
1217 __FUNCTION__, err));
1221 bus->clkstate = CLK_SDONLY;
1223 /* Stop or slow the SD clock itself */
1224 if ((bus->sd_divisor == -1) || (bus->sd_mode == -1)) {
1225 DHD_TRACE(("%s: can't idle clock, divisor %d mode %d\n",
1226 __FUNCTION__, bus->sd_divisor, bus->sd_mode));
1229 if (bus->idleclock == DHD_IDLE_STOP) {
1231 /* Change to SD1 mode and turn off clock */
1233 err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
1234 &iovalue, sizeof(iovalue), TRUE);
1236 DHD_ERROR(("%s: error changing sd_clock: %d\n",
1237 __FUNCTION__, err));
1243 err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0,
1244 &iovalue, sizeof(iovalue), TRUE);
1246 DHD_ERROR(("%s: error disabling sd_clock: %d\n",
1247 __FUNCTION__, err));
1250 } else if (bus->idleclock != DHD_IDLE_ACTIVE) {
1251 /* Set divisor to idle value */
1252 iovalue = bus->idleclock;
1253 err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
1254 &iovalue, sizeof(iovalue), TRUE);
1256 DHD_ERROR(("%s: error changing sd_divisor: %d\n",
1257 __FUNCTION__, err));
1261 bus->clkstate = CLK_NONE;
1267 /* Transition SD and backplane clock readiness */
1269 dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok)
1273 uint oldstate = bus->clkstate;
1274 #endif /* DHD_DEBUG */
1276 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1278 /* Early exit if we're already there */
1279 if (bus->clkstate == target) {
1280 if (target == CLK_AVAIL) {
1281 dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
1282 bus->activity = TRUE;
1283 #ifdef DHD_USE_IDLECOUNT
1285 #endif /* DHD_USE_IDLECOUNT */
1292 /* Make sure SD clock is available */
1293 if (bus->clkstate == CLK_NONE)
1294 dhdsdio_sdclk(bus, TRUE);
1295 /* Now request HT Avail on the backplane */
1296 ret = dhdsdio_htclk(bus, TRUE, pendok);
1297 if (ret == BCME_OK) {
1298 dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
1299 bus->activity = TRUE;
1300 #ifdef DHD_USE_IDLECOUNT
1302 #endif /* DHD_USE_IDLECOUNT */
1307 /* Remove HT request, or bring up SD clock */
1308 if (bus->clkstate == CLK_NONE)
1309 ret = dhdsdio_sdclk(bus, TRUE);
1310 else if (bus->clkstate == CLK_AVAIL)
1311 ret = dhdsdio_htclk(bus, FALSE, FALSE);
1313 DHD_ERROR(("dhdsdio_clkctl: request for %d -> %d\n",
1314 bus->clkstate, target));
1315 if (ret == BCME_OK) {
1316 dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
1321 /* Make sure to remove HT request */
1322 if (bus->clkstate == CLK_AVAIL)
1323 ret = dhdsdio_htclk(bus, FALSE, FALSE);
1324 /* Now remove the SD clock */
1325 ret = dhdsdio_sdclk(bus, FALSE);
1327 if (dhd_console_ms == 0)
1328 #endif /* DHD_DEBUG */
1330 dhd_os_wd_timer(bus->dhd, 0);
1334 DHD_INFO(("dhdsdio_clkctl: %d -> %d\n", oldstate, bus->clkstate));
1335 #endif /* DHD_DEBUG */
1341 dhdsdio_bussleep(dhd_bus_t *bus, bool sleep)
1344 bcmsdh_info_t *sdh = bus->sdh;
1345 sdpcmd_regs_t *regs = bus->regs;
1348 DHD_INFO(("dhdsdio_bussleep: request %s (currently %s)\n",
1349 (sleep ? "SLEEP" : "WAKE"),
1350 (bus->sleeping ? "SLEEP" : "WAKE")));
1352 /* Done if we're already in the requested state */
1353 if (sleep == bus->sleeping)
1356 /* Going to sleep: set the alarm and turn off the lights... */
1358 /* Don't sleep if something is pending */
1359 if (bus->dpc_sched || bus->rxskip || pktq_len(&bus->txq))
1363 if (!SLPAUTO_ENAB(bus)) {
1364 /* Disable SDIO interrupts (no longer interested) */
1365 bcmsdh_intr_disable(bus->sdh);
1367 /* Make sure the controller has the bus up */
1368 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
1370 /* Tell device to start using OOB wakeup */
1371 W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries);
1372 if (retries > retry_limit)
1373 DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
1375 /* Turn off our contribution to the HT clock request */
1376 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
1378 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
1379 SBSDIO_FORCE_HW_CLKREQ_OFF, NULL);
1381 /* Isolate the bus */
1382 if (bus->sih->chip != BCM4329_CHIP_ID &&
1383 bus->sih->chip != BCM4319_CHIP_ID) {
1384 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL,
1385 SBSDIO_DEVCTL_PADS_ISO, NULL);
1388 /* Leave interrupts enabled since device can exit sleep and
1391 W_SDREG(bus->hostintmask & ~I_CHIPACTIVE, &bus->regs->hostintmask, retries);
1392 err = dhdsdio_clk_devsleep_iovar(bus, TRUE /* sleep */);
1396 bus->sleeping = TRUE;
1399 /* Waking up: bus power up is ok, set local state */
1401 if (!SLPAUTO_ENAB(bus)) {
1402 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0, &err);
1404 /* Force pad isolation off if possible (in case power never toggled) */
1405 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, 0, NULL);
1408 /* Make sure the controller has the bus up */
1409 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
1411 /* Send misc interrupt to indicate OOB not needed */
1412 W_SDREG(0, ®s->tosbmailboxdata, retries);
1413 if (retries <= retry_limit)
1414 W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries);
1416 if (retries > retry_limit)
1417 DHD_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n"));
1419 /* Make sure we have SD bus access */
1420 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
1422 /* Enable interrupts again */
1423 if (bus->intr && (bus->dhd->busstate == DHD_BUS_DATA)) {
1424 bus->intdis = FALSE;
1425 bcmsdh_intr_enable(bus->sdh);
1428 err = dhdsdio_clk_devsleep_iovar(bus, FALSE /* wake */);
1429 W_SDREG(bus->hostintmask, &bus->regs->hostintmask, retries);
1434 bus->sleeping = FALSE;
1442 #if defined(OOB_INTR_ONLY)
1444 dhd_enable_oob_intr(struct dhd_bus *bus, bool enable)
1447 bcmsdh_enable_hw_oob_intr(bus->sdh, enable);
1449 sdpcmd_regs_t *regs = bus->regs;
1452 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
1453 if (enable == TRUE) {
1455 /* Tell device to start using OOB wakeup */
1456 W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries);
1457 if (retries > retry_limit)
1458 DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
1461 /* Send misc interrupt to indicate OOB not needed */
1462 W_SDREG(0, ®s->tosbmailboxdata, retries);
1463 if (retries <= retry_limit)
1464 W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries);
1467 /* Turn off our contribution to the HT clock request */
1468 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
1469 #endif /* !defined(HW_OOB) */
1473 #ifdef DHDTCPACK_SUPPRESS
1474 extern bool dhd_use_tcpack_suppress;
1476 /* Please be sure this function is called under dhd_os_tcpacklock() */
1477 void dhd_onoff_tcpack_sup(void *pub, bool on)
1479 dhd_pub_t *dhdp = (dhd_pub_t *)pub;
1481 if (dhd_use_tcpack_suppress != on) {
1483 DHD_ERROR(("dhd_onoff_tcpack_sup: %d -> %d\n", dhd_use_tcpack_suppress, on));
1484 dhd_use_tcpack_suppress = on;
1485 dhdp->tcp_ack_info_cnt = 0;
1486 bzero(dhdp->tcp_ack_info_tbl, sizeof(struct tcp_ack_info)*MAXTCPSTREAMS);
1489 DHD_ERROR(("dhd_onoff_tcpack_sup: alread %d\n", on));
1494 inline void dhd_tcpack_check_xmit(dhd_pub_t *dhdp, void *pkt)
1497 tcp_ack_info_t *tcp_ack_info = NULL;
1500 dhd_os_tcpacklock(dhdp);
1501 tbl_cnt = dhdp->tcp_ack_info_cnt;
1502 for (i = 0; i < tbl_cnt; i++) {
1503 tcp_ack_info = &dhdp->tcp_ack_info_tbl[i];
1504 if (tcp_ack_info->p_tcpackinqueue == pkt) {
1505 /* This pkt is being transmitted so remove the tcp_ack_info of it.
1506 * compact the array unless the last element,
1507 * then the pkt's array is removed.
1509 if (i < tbl_cnt-1) {
1510 memmove(&dhdp->tcp_ack_info_tbl[i],
1511 &dhdp->tcp_ack_info_tbl[i+1],
1512 sizeof(struct tcp_ack_info)*(tbl_cnt - (i+1)));
1514 bzero(&dhdp->tcp_ack_info_tbl[tbl_cnt-1], sizeof(struct tcp_ack_info));
1515 if (--dhdp->tcp_ack_info_cnt < 0) {
1516 DHD_ERROR(("dhdsdio_sendfromq:(ERROR) tcp_ack_info_cnt %d"
1517 " Stop using tcpack_suppress\n", dhdp->tcp_ack_info_cnt));
1518 dhd_onoff_tcpack_sup(dhdp, FALSE);
1523 dhd_os_tcpackunlock(dhdp);
1527 dhd_tcpack_suppress(dhd_pub_t *dhdp, void *pkt)
1534 uint32 cur_framelen;
1535 uint8 bdc_hdr_len = BDC_HEADER_LEN;
1536 uint8 wlfc_hdr_len = 0;
1537 uint8 *data = PKTDATA(dhdp->osh, pkt);
1538 cur_framelen = PKTLEN(dhdp->osh, pkt);
1540 #ifdef PROP_TXSTATUS
1541 /* In this case, BDC header is not pushed in dhd_sendpkt() */
1542 if (dhdp->wlfc_state) {
1547 if (cur_framelen < bdc_hdr_len + ETHER_HDR_LEN) {
1548 DHD_TRACE(("dhd_tcpack_suppress: Too short packet length %d\n", cur_framelen));
1552 /* Get rid of BDC header */
1553 eh_header = data + bdc_hdr_len;
1554 cur_framelen -= bdc_hdr_len;
1555 eh_type = eh_header[12] << 8 | eh_header[13];
1557 if (eh_type != ETHER_TYPE_IP) {
1558 DHD_TRACE(("dhd_tcpack_suppress: Not a IP packet 0x%x\n", eh_type));
1562 DHD_TRACE(("dhd_tcpack_suppress: IP pkt! 0x%x\n", eh_type));
1564 ip_header = eh_header + ETHER_HDR_LEN;
1565 cur_framelen -= ETHER_HDR_LEN;
1566 ip_hdr_len = 4 * (ip_header[0] & 0x0f);
1568 if ((ip_header[0] & 0xf0) != 0x40) {
1569 DHD_TRACE(("dhd_tcpack_suppress: Not IPv4!\n"));
1573 if (cur_framelen < ip_hdr_len) {
1574 DHD_ERROR(("dhd_tcpack_suppress: IP packet length %d wrong!\n", cur_framelen));
1579 if (ip_header[9] != 0x06) {
1580 DHD_TRACE(("dhd_tcpack_suppress: Not a TCP packet 0x%x\n", ip_header[9]));
1584 DHD_TRACE(("dhd_tcpack_suppress: TCP pkt!\n"));
1586 tcp_header = ip_header + ip_hdr_len;
1588 /* is it an ack ? */
1589 if (tcp_header[13] == 0x10) {
1590 #if defined(DHD_DEBUG)
1591 uint32 tcp_seq_num = tcp_header[4] << 24 | tcp_header[5] << 16 |
1592 tcp_header[6] << 8 | tcp_header[7];
1594 uint32 tcp_ack_num = tcp_header[8] << 24 | tcp_header[9] << 16 |
1595 tcp_header[10] << 8 | tcp_header[11];
1596 uint16 ip_tcp_ttllen = (ip_header[3] & 0xff) + (ip_header[2] << 8);
1597 uint32 tcp_hdr_len = 4*((tcp_header[12] & 0xf0) >> 4);
1598 DHD_TRACE(("dhd_tcpack_suppress: TCP ACK seq %ud ack %ud\n",
1599 tcp_seq_num, tcp_ack_num));
1603 if (ip_tcp_ttllen == ip_hdr_len + tcp_hdr_len) {
1605 tcp_ack_info_t *tcp_ack_info = NULL;
1606 DHD_TRACE(("dhd_tcpack_suppress: TCP ACK zero length\n"));
1607 /* Look for tcp_ack_info that has the same
1608 * ip src/dst addrs and tcp src/dst ports
1610 dhd_os_tcpacklock(dhdp);
1611 for (i = 0; i < dhdp->tcp_ack_info_cnt; i++) {
1612 if (dhdp->tcp_ack_info_tbl[i].p_tcpackinqueue &&
1613 !memcmp(&ip_header[12], dhdp->tcp_ack_info_tbl[i].ipaddrs, 8) &&
1614 !memcmp(tcp_header, dhdp->tcp_ack_info_tbl[i].tcpports, 4)) {
1615 tcp_ack_info = &dhdp->tcp_ack_info_tbl[i];
1620 if (i == dhdp->tcp_ack_info_cnt && i < MAXTCPSTREAMS)
1621 tcp_ack_info = &dhdp->tcp_ack_info_tbl[dhdp->tcp_ack_info_cnt++];
1623 if (!tcp_ack_info) {
1624 DHD_TRACE(("dhd_tcpack_suppress: No empty tcp ack info"
1625 "%d %d %d %d, %d %d %d %d\n",
1626 tcp_header[0], tcp_header[1], tcp_header[2], tcp_header[3],
1627 dhdp->tcp_ack_info_tbl[i].tcpports[0],
1628 dhdp->tcp_ack_info_tbl[i].tcpports[1],
1629 dhdp->tcp_ack_info_tbl[i].tcpports[2],
1630 dhdp->tcp_ack_info_tbl[i].tcpports[3]));
1631 dhd_os_tcpackunlock(dhdp);
1635 if (tcp_ack_info->p_tcpackinqueue) {
1636 if (tcp_ack_num > tcp_ack_info->tcpack_number) {
1637 void *prevpkt = tcp_ack_info->p_tcpackinqueue;
1638 uint8 pushed_len = SDPCM_HDRLEN +
1639 (BDC_HEADER_LEN - bdc_hdr_len) + wlfc_hdr_len;
1640 #ifdef PROP_TXSTATUS
1641 /* In case the prev pkt is delayenqueued
1642 * but not delayedequeued yet, it may not have
1643 * any additional header yet.
1645 dhd_os_wlfc_block(dhdp);
1646 if (dhdp->wlfc_state && (PKTLEN(dhdp->osh, prevpkt) ==
1647 tcp_ack_info->ip_tcp_ttllen + ETHER_HDR_LEN))
1650 if ((ip_tcp_ttllen == tcp_ack_info->ip_tcp_ttllen) &&
1651 (PKTLEN(dhdp->osh, pkt) ==
1652 PKTLEN(dhdp->osh, prevpkt) - pushed_len)) {
1653 bcopy(PKTDATA(dhdp->osh, pkt),
1654 PKTDATA(dhdp->osh, prevpkt) + pushed_len,
1655 PKTLEN(dhdp->osh, pkt));
1656 PKTFREE(dhdp->osh, pkt, FALSE);
1657 DHD_TRACE(("dhd_tcpack_suppress: pkt 0x%p"
1658 " TCP ACK replace %ud -> %ud\n", prevpkt,
1659 tcp_ack_info->tcpack_number, tcp_ack_num));
1660 tcp_ack_info->tcpack_number = tcp_ack_num;
1661 #ifdef PROP_TXSTATUS
1662 dhd_os_wlfc_unblock(dhdp);
1664 dhd_os_tcpackunlock(dhdp);
1667 DHD_TRACE(("dhd_tcpack_suppress: len mismatch"
1669 PKTLEN(dhdp->osh, pkt), ip_tcp_ttllen,
1670 PKTLEN(dhdp->osh, prevpkt),
1671 tcp_ack_info->ip_tcp_ttllen));
1672 #ifdef PROP_TXSTATUS
1673 dhd_os_wlfc_unblock(dhdp);
1678 void *prevpkt = tcp_ack_info->p_tcpackinqueue;
1680 DHD_TRACE(("dhd_tcpack_suppress: TCP ACK number reverse"
1681 " prev %ud (0x%p) new %ud (0x%p)\n",
1682 tcp_ack_info->tcpack_number,
1683 tcp_ack_info->p_tcpackinqueue,
1686 if (PKTLEN(dhdp->osh, pkt) == PKTLEN(dhdp->osh, prevpkt)) {
1687 PKTFREE(dhdp->osh, pkt, FALSE);
1688 dhd_os_tcpackunlock(dhdp);
1694 tcp_ack_info->p_tcpackinqueue = pkt;
1695 tcp_ack_info->tcpack_number = tcp_ack_num;
1696 tcp_ack_info->ip_tcp_ttllen = ip_tcp_ttllen;
1697 bcopy(&ip_header[12], tcp_ack_info->ipaddrs, 8);
1698 bcopy(tcp_header, tcp_ack_info->tcpports, 4);
1700 dhd_os_tcpackunlock(dhdp);
1702 DHD_TRACE(("dhd_tcpack_suppress: TCP ACK with DATA len %d\n",
1703 ip_tcp_ttllen - ip_hdr_len - tcp_hdr_len));
1707 #endif /* DHDTCPACK_SUPPRESS */
1708 /* Writes a HW/SW header into the packet and sends it. */
1709 /* Assumes: (a) header space already there, (b) caller holds lock */
1711 dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt, bool queue_only)
1716 uint16 len, pad1 = 0, act_len = 0;
1719 uint32 real_pad = 0;
1724 #ifdef BCMSDIOH_TXGLOM
1732 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1735 osh = bus->dhd->osh;
1737 #ifdef DHDTCPACK_SUPPRESS
1738 if (dhd_use_tcpack_suppress) {
1739 dhd_tcpack_check_xmit(bus->dhd, pkt);
1741 #endif /* DHDTCPACK_SUPPRESS */
1743 if (bus->dhd->dongle_reset) {
1744 ret = BCME_NOTREADY;
1748 frame = (uint8*)PKTDATA(osh, pkt);
1751 if (PKTLEN(osh, pkt) >= 100) {
1752 p = PKTDATA(osh, pkt);
1753 htsf_ts = (htsfts_t*) (p + HTSF_HOSTOFFSET + 12);
1754 if (htsf_ts->magic == HTSFMAGIC) {
1755 htsf_ts->c20 = get_cycles();
1756 htsf_ts->t20 = dhd_get_htsf(bus->dhd->info, 0);
1759 #endif /* WLMEDIA_HTSF */
1761 /* Add alignment padding, allocate new packet if needed */
1762 if ((pad1 = ((uintptr)frame % DHD_SDALIGN))) {
1763 if (PKTHEADROOM(osh, pkt) < pad1) {
1764 DHD_INFO(("%s: insufficient headroom %d for %d pad1\n",
1765 __FUNCTION__, (int)PKTHEADROOM(osh, pkt), pad1));
1766 bus->dhd->tx_realloc++;
1767 new = PKTGET(osh, (PKTLEN(osh, pkt) + DHD_SDALIGN), TRUE);
1769 DHD_ERROR(("%s: couldn't allocate new %d-byte packet\n",
1770 __FUNCTION__, PKTLEN(osh, pkt) + DHD_SDALIGN));
1775 PKTALIGN(osh, new, PKTLEN(osh, pkt), DHD_SDALIGN);
1776 bcopy(PKTDATA(osh, pkt), PKTDATA(osh, new), PKTLEN(osh, pkt));
1778 PKTFREE(osh, pkt, TRUE);
1779 /* free the pkt if canned one is not used */
1782 frame = (uint8*)PKTDATA(osh, pkt);
1783 ASSERT(((uintptr)frame % DHD_SDALIGN) == 0);
1786 PKTPUSH(osh, pkt, pad1);
1787 frame = (uint8*)PKTDATA(osh, pkt);
1789 ASSERT((pad1 + SDPCM_HDRLEN) <= (int) PKTLEN(osh, pkt));
1790 bzero(frame, pad1 + SDPCM_HDRLEN);
1793 ASSERT(pad1 < DHD_SDALIGN);
1795 /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
1796 len = (uint16)PKTLEN(osh, pkt);
1797 *(uint16*)frame = htol16(len);
1798 *(((uint16*)frame) + 1) = htol16(~len);
1800 #ifdef BCMSDIOH_TXGLOM
1801 if (bus->glom_enable) {
1802 uint32 hwheader1 = 0, hwheader2 = 0;
1805 /* Software tag: channel, sequence number, data offset */
1806 swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) |
1807 ((bus->tx_seq + bus->glom_cnt) % SDPCM_SEQUENCE_WRAP) |
1808 (((pad1 + SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
1809 htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN);
1810 htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN + sizeof(swheader));
1813 uint8 alignment = ALIGNMENT;
1814 if (forcealign && (len & (alignment - 1)))
1815 len = ROUNDUP(len, alignment);
1816 /* Hardware extention tag */
1817 /* 2byte frame length, 1byte-, 1byte frame flag,
1818 * 2byte-hdrlength, 2byte padlenght
1820 hwheader1 = (act_len - SDPCM_FRAMETAG_LEN) | (0 << 24);
1821 hwheader2 = (len - act_len) << 16;
1822 htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN);
1823 htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4);
1824 real_pad = len - act_len;
1825 if (PKTTAILROOM(osh, pkt) < real_pad) {
1826 DHD_INFO(("%s 1: insufficient tailroom %d for %d real_pad\n",
1827 __FUNCTION__, (int)PKTTAILROOM(osh, pkt), real_pad));
1828 if (PKTPADTAILROOM(osh, pkt, real_pad)) {
1829 DHD_ERROR(("CHK1: padding error size %d\n", real_pad));
1835 PKTSETLEN(osh, pkt, act_len);
1839 PKTSETLEN(osh, pkt, len);
1840 #endif /* BCMLXSDMMC */
1841 /* Post the frame pointer to sdio glom array */
1842 dhd_bcmsdh_glom_post(bus, frame, pkt, len);
1843 /* Save the pkt pointer in bus glom array */
1844 bus->glom_pkt_arr[bus->glom_cnt] = pkt;
1845 bus->glom_total_len += len;
1849 /* Raise len to next SDIO block to eliminate tail command */
1850 if (bus->roundup && bus->blocksize &&
1851 ((bus->glom_total_len + len) > bus->blocksize)) {
1852 uint16 pad2 = bus->blocksize -
1853 ((bus->glom_total_len + len) % bus->blocksize);
1854 if ((pad2 <= bus->roundup) && (pad2 < bus->blocksize)) {
1858 } else if ((bus->glom_total_len + len) % DHD_SDALIGN) {
1860 - ((bus->glom_total_len + len) % DHD_SDALIGN);
1862 if (forcealign && (len & (ALIGNMENT - 1))) {
1863 len = ROUNDUP(len, ALIGNMENT);
1866 /* Hardware extention tag */
1867 /* 2byte frame length, 1byte-, 1byte frame flag,
1868 * 2byte-hdrlength, 2byte padlenght
1870 hwheader1 = (act_len - SDPCM_FRAMETAG_LEN) | (1 << 24);
1871 hwheader2 = (len - act_len) << 16;
1872 htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN);
1873 htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4);
1874 real_pad = len - act_len;
1875 if (PKTTAILROOM(osh, pkt) < real_pad) {
1876 DHD_INFO(("%s 2: insufficient tailroom %d"
1877 " for %d real_pad\n",
1878 __FUNCTION__, (int)PKTTAILROOM(osh, pkt), real_pad));
1879 if (PKTPADTAILROOM(osh, pkt, real_pad)) {
1880 DHD_ERROR(("CHK2: padding error size %d."
1881 " %d more pkts are discarded together.\n",
1882 real_pad, bus->glom_cnt));
1883 /* Save the pkt pointer in bus glom array
1884 * Otherwise, this last pkt will not be
1885 * cleaned under "goto done"
1887 bus->glom_pkt_arr[bus->glom_cnt] = pkt;
1889 bus->glom_total_len += len;
1895 PKTSETLEN(osh, pkt, act_len);
1899 PKTSETLEN(osh, pkt, len);
1900 #endif /* BCMLXSDMMC */
1902 /* Post the frame pointer to sdio glom array */
1903 dhd_bcmsdh_glom_post(bus, frame, pkt, len);
1904 /* Save the pkt pointer in bus glom array */
1905 bus->glom_pkt_arr[bus->glom_cnt] = pkt;
1907 bus->glom_total_len += len;
1909 /* Update the total length on the first pkt */
1910 frame_tmp = (uint8*)PKTDATA(osh, bus->glom_pkt_arr[0]);
1911 *(uint16*)frame_tmp = htol16(bus->glom_total_len);
1912 *(((uint16*)frame_tmp) + 1) = htol16(~bus->glom_total_len);
1915 #endif /* BCMSDIOH_TXGLOM */
1918 /* Software tag: channel, sequence number, data offset */
1919 swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) | bus->tx_seq |
1920 (((pad1 + SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
1921 htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN);
1922 htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
1925 if (PKTPRIO(pkt) < ARRAYSIZE(tx_packets)) {
1926 tx_packets[PKTPRIO(pkt)]++;
1928 if (DHD_BYTES_ON() &&
1929 (((DHD_CTL_ON() && (chan == SDPCM_CONTROL_CHANNEL)) ||
1930 (DHD_DATA_ON() && (chan != SDPCM_CONTROL_CHANNEL))))) {
1931 prhex("Tx Frame", frame, len);
1932 } else if (DHD_HDRS_ON()) {
1933 prhex("TxHdr", frame, MIN(len, 16));
1937 /* Raise len to next SDIO block to eliminate tail command */
1938 if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
1939 uint16 pad2 = bus->blocksize - (len % bus->blocksize);
1940 if ((pad2 <= bus->roundup) && (pad2 < bus->blocksize))
1942 if (pad2 <= PKTTAILROOM(osh, pkt))
1943 #endif /* NOTUSED */
1945 } else if (len % DHD_SDALIGN) {
1946 len += DHD_SDALIGN - (len % DHD_SDALIGN);
1949 /* Some controllers have trouble with odd bytes -- round to even */
1950 if (forcealign && (len & (ALIGNMENT - 1))) {
1952 if (PKTTAILROOM(osh, pkt))
1954 len = ROUNDUP(len, ALIGNMENT);
1957 DHD_ERROR(("%s: sending unrounded %d-byte packet\n", __FUNCTION__, len));
1960 real_pad = len - act_len;
1961 if (PKTTAILROOM(osh, pkt) < real_pad) {
1962 DHD_INFO(("%s 3: insufficient tailroom %d for %d real_pad\n",
1963 __FUNCTION__, (int)PKTTAILROOM(osh, pkt), real_pad));
1964 if (PKTPADTAILROOM(osh, pkt, real_pad)) {
1965 DHD_ERROR(("CHK3: padding error size %d\n", real_pad));
1971 PKTSETLEN(osh, pkt, act_len);
1975 PKTSETLEN(osh, pkt, len);
1976 #endif /* BCMLXSDMMC */
1979 ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
1980 frame, len, pkt, NULL, NULL);
1982 ASSERT(ret != BCME_PENDING);
1984 if (ret == BCME_NODEVICE) {
1985 DHD_ERROR(("%s: Device asleep already\n", __FUNCTION__));
1986 } else if (ret < 0) {
1987 /* On failure, abort the command and terminate the frame */
1988 DHD_ERROR(("%s: sdio error %d, abort command and terminate frame.\n",
1989 __FUNCTION__, ret));
1992 bcmsdh_abort(sdh, SDIO_FUNC_2);
1993 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
1997 for (i = 0; i < 3; i++) {
1999 hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
2000 SBSDIO_FUNC1_WFRAMEBCHI, NULL);
2001 lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
2002 SBSDIO_FUNC1_WFRAMEBCLO, NULL);
2003 bus->f1regdata += 2;
2004 if ((hi == 0) && (lo == 0))
2009 #ifdef BCMSDIOH_TXGLOM
2010 if (bus->glom_enable) {
2011 bus->tx_seq = (bus->tx_seq + bus->glom_cnt) % SDPCM_SEQUENCE_WRAP;
2015 bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
2018 } while ((ret < 0) && retrydata && retries++ < TXRETRIES);
2022 #ifdef BCMSDIOH_TXGLOM
2023 if (bus->glom_enable && !queue_only) {
2024 dhd_bcmsdh_glom_clear(bus);
2025 pkt_cnt = bus->glom_cnt;
2031 /* restore pkt buffer pointer before calling tx complete routine */
2033 #ifdef BCMSDIOH_TXGLOM
2035 if (bus->glom_enable) {
2038 #endif /* BCMLXSDMMC */
2040 pkt = bus->glom_pkt_arr[bus->glom_cnt - pkt_cnt];
2042 frame = (uint8*)PKTDATA(osh, pkt);
2043 doff = ltoh32_ua(frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN);
2044 doff = (doff & SDPCM_DOFFSET_MASK) >> SDPCM_DOFFSET_SHIFT;
2046 pad2 = ltoh32_ua(frame + SDPCM_FRAMETAG_LEN + 4) >> 16;
2047 PKTSETLEN(osh, pkt, PKTLEN(osh, pkt) - pad2);
2048 #endif /* BCMLXSDMMC */
2049 PKTPULL(osh, pkt, doff);
2051 #endif /* BCMSDIOH_TXGLOM */
2055 PKTSETLEN(osh, pkt, act_len);
2056 #endif /* BCMLXSDMMC */
2057 PKTPULL(osh, pkt, SDPCM_HDRLEN + pad1);
2059 #ifdef PROP_TXSTATUS
2060 if (bus->dhd->wlfc_state) {
2061 dhd_os_sdunlock(bus->dhd);
2062 dhd_wlfc_txcomplete(bus->dhd, pkt, ret == 0);
2063 dhd_os_sdlock(bus->dhd);
2065 #endif /* PROP_TXSTATUS */
2067 if (chan != SDPCM_TEST_CHANNEL) {
2068 dhd_txcomplete(bus->dhd, pkt, ret != 0);
2071 dhd_txcomplete(bus->dhd, pkt, ret != 0);
2074 PKTFREE(osh, pkt, TRUE);
2076 #ifdef PROP_TXSTATUS
2082 #ifdef BCMSDIOH_TXGLOM
2083 /* Reset the glom array */
2084 if (bus->glom_enable && !queue_only) {
2086 bus->glom_total_len = 0;
2093 dhd_bus_txdata(struct dhd_bus *bus, void *pkt)
2095 int ret = BCME_ERROR;
2098 #if defined(DHD_TX_DUMP) || defined(DHD_8021X_DUMP)
2101 #endif /* DHD_TX_DUMP || DHD_8021X_DUMP */
2103 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2105 osh = bus->dhd->osh;
2106 datalen = PKTLEN(osh, pkt);
2109 /* Push the test header if doing loopback */
2110 if (bus->ext_loop) {
2112 PKTPUSH(osh, pkt, SDPCM_TEST_HDRLEN);
2113 data = PKTDATA(osh, pkt);
2114 *data++ = SDPCM_TEST_ECHOREQ;
2115 *data++ = (uint8)bus->loopid++;
2116 *data++ = (datalen >> 0);
2117 *data++ = (datalen >> 8);
2118 datalen += SDPCM_TEST_HDRLEN;
2122 #if defined(DHD_TX_DUMP) || defined(DHD_8021X_DUMP)
2123 dump_data = PKTDATA(osh, pkt);
2124 dump_data += 4; /* skip 4 bytes header */
2125 protocol = (dump_data[12] << 8) | dump_data[13];
2127 if (protocol == ETHER_TYPE_802_1X) {
2128 DHD_ERROR(("ETHER_TYPE_802_1X [TX]: ver %d, type %d, replay %d\n",
2129 dump_data[14], dump_data[15], dump_data[30]));
2131 #endif /* DHD_TX_DUMP || DHD_8021X_DUMP */
2133 #if defined(DHD_TX_DUMP) && defined(DHD_TX_FULL_DUMP)
2136 DHD_ERROR(("TX DUMP\n"));
2138 for (i = 0; i < (datalen - 4); i++) {
2139 DHD_ERROR(("%02X ", dump_data[i]));
2145 #endif /* DHD_TX_DUMP && DHD_TX_FULL_DUMP */
2147 /* Add space for the header */
2148 PKTPUSH(osh, pkt, SDPCM_HDRLEN);
2149 ASSERT(ISALIGNED((uintptr)PKTDATA(osh, pkt), 2));
2151 prec = PRIO2PREC((PKTPRIO(pkt) & PRIOMASK));
2153 /* Lock: we're about to use shared data/code (and SDIO) */
2154 dhd_os_sdlock(bus->dhd);
2155 #endif /* DHDTHREAD */
2157 /* Check for existing queue, current flow-control, pending event, or pending clock */
2158 if (dhd_deferred_tx || bus->fcstate || pktq_len(&bus->txq) || bus->dpc_sched ||
2159 (!DATAOK(bus)) || (bus->flowcontrol & NBITVAL(prec)) ||
2160 (bus->clkstate != CLK_AVAIL)) {
2161 DHD_TRACE(("%s: deferring pktq len %d\n", __FUNCTION__,
2162 pktq_len(&bus->txq)));
2165 /* Priority based enq */
2166 dhd_os_sdlock_txq(bus->dhd);
2167 if (dhd_prec_enq(bus->dhd, &bus->txq, pkt, prec) == FALSE) {
2168 PKTPULL(osh, pkt, SDPCM_HDRLEN);
2170 /* Need to also release txqlock before releasing sdlock.
2171 * This thread still has txqlock and releases sdlock.
2172 * Deadlock happens when dpc() grabs sdlock first then
2173 * attempts to grab txqlock.
2175 dhd_os_sdunlock_txq(bus->dhd);
2176 dhd_os_sdunlock(bus->dhd);
2178 #ifdef PROP_TXSTATUS
2179 if (bus->dhd->wlfc_state)
2180 dhd_wlfc_txcomplete(bus->dhd, pkt, FALSE);
2183 dhd_txcomplete(bus->dhd, pkt, FALSE);
2185 dhd_os_sdlock(bus->dhd);
2186 dhd_os_sdlock_txq(bus->dhd);
2188 #ifdef PROP_TXSTATUS
2189 /* let the caller decide whether to free the packet */
2190 if (!bus->dhd->wlfc_state)
2192 PKTFREE(osh, pkt, TRUE);
2193 ret = BCME_NORESOURCE;
2198 if ((pktq_len(&bus->txq) >= FCHI) && dhd_doflow)
2199 dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON);
2202 if (pktq_plen(&bus->txq, prec) > qcount[prec])
2203 qcount[prec] = pktq_plen(&bus->txq, prec);
2205 dhd_os_sdunlock_txq(bus->dhd);
2207 /* Schedule DPC if needed to send queued packet(s) */
2208 if (dhd_deferred_tx && !bus->dpc_sched) {
2209 bus->dpc_sched = TRUE;
2210 dhd_sched_dpc(bus->dhd);
2214 /* Lock: we're about to use shared data/code (and SDIO) */
2215 dhd_os_sdlock(bus->dhd);
2216 #endif /* DHDTHREAD */
2218 /* Otherwise, send it now */
2220 /* Make sure back plane ht clk is on, no pending allowed */
2221 dhdsdio_clkctl(bus, CLK_AVAIL, TRUE);
2223 ret = dhdsdio_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, TRUE, FALSE);
2225 ret = dhdsdio_txpkt(bus, pkt,
2226 (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL), TRUE, FALSE);
2229 bus->dhd->tx_errors++;
2231 bus->dhd->dstats.tx_bytes += datalen;
2233 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
2234 bus->activity = FALSE;
2235 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
2239 dhd_os_sdunlock(bus->dhd);
2240 #endif /* DHDTHREAD */
2244 dhd_os_sdunlock(bus->dhd);
2245 #endif /* DHDTHREAD */
2251 dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes)
2254 uint32 intstatus = 0;
2256 int ret = 0, prec_out;
2260 uint16 txpktqlen = 0;
2261 #ifdef BCMSDIOH_TXGLOM
2266 dhd_pub_t *dhd = bus->dhd;
2267 sdpcmd_regs_t *regs = bus->regs;
2269 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2271 if (!KSO_ENAB(bus)) {
2272 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
2273 return BCME_NODEVICE;
2276 tx_prec_map = ~bus->flowcontrol;
2278 /* Send frames until the limit or some other event */
2279 for (cnt = 0; (cnt < maxframes) && DATAOK(bus); cnt++) {
2280 #ifdef BCMSDIOH_TXGLOM
2281 if (bus->glom_enable) {
2282 void *pkttable[SDPCM_MAXGLOM_SIZE];
2283 dhd_os_sdlock_txq(bus->dhd);
2284 glom_cnt = MIN(DATABUFCNT(bus), bus->glomsize);
2285 glom_cnt = MIN(glom_cnt, pktq_mlen(&bus->txq, tx_prec_map));
2286 glom_cnt = MIN(glom_cnt, maxframes-cnt);
2288 /* Limiting the size to 2pkts in case of copy */
2289 if (bus->glom_mode == SDPCM_TXGLOM_CPY)
2290 glom_cnt = MIN(glom_cnt, 10);
2292 for (i = 0; i < glom_cnt; i++)
2293 pkttable[i] = pktq_mdeq(&bus->txq, tx_prec_map, &prec_out);
2295 txpktqlen = pktq_len(&bus->txq);
2296 dhd_os_sdunlock_txq(bus->dhd);
2301 for (i = 0; i < glom_cnt; i++) {
2302 uint datalen_tmp = 0;
2304 if ((pkt = pkttable[i]) == NULL) {
2305 /* This case should not happen */
2306 DHD_ERROR(("No pkts in the queue for glomming\n"));
2310 datalen_tmp = (PKTLEN(bus->dhd->osh, pkt) - SDPCM_HDRLEN);
2313 ret = dhdsdio_txpkt(bus,
2317 (i == (glom_cnt-1))? FALSE: TRUE);
2319 ret = dhdsdio_txpkt(bus,
2321 (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL),
2323 (i == (glom_cnt-1))? FALSE: TRUE);
2326 datalen += datalen_tmp;
2330 #endif /* BCMSDIOH_TXGLOM */
2332 dhd_os_sdlock_txq(bus->dhd);
2333 if ((pkt = pktq_mdeq(&bus->txq, tx_prec_map, &prec_out)) == NULL) {
2334 txpktqlen = pktq_len(&bus->txq);
2335 dhd_os_sdunlock_txq(bus->dhd);
2338 txpktqlen = pktq_len(&bus->txq);
2339 dhd_os_sdunlock_txq(bus->dhd);
2340 datalen = PKTLEN(bus->dhd->osh, pkt) - SDPCM_HDRLEN;
2343 ret = dhdsdio_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, TRUE, FALSE);
2345 ret = dhdsdio_txpkt(bus,
2347 (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL),
2354 bus->dhd->tx_errors++;
2356 bus->dhd->dstats.tx_bytes += datalen;
2358 /* In poll mode, need to check for other events */
2359 if (!bus->intr && cnt)
2361 /* Check device status, signal pending interrupt */
2362 R_SDREG(intstatus, ®s->intstatus, retries);
2364 if (bcmsdh_regfail(bus->sdh))
2366 if (intstatus & bus->hostintmask)
2371 /* Deflow-control stack if needed */
2372 if (dhd_doflow && dhd->up && (dhd->busstate == DHD_BUS_DATA) &&
2373 dhd->txoff && (txpktqlen < FCLOW))
2374 dhd_txflowcontrol(dhd, ALL_INTERFACES, OFF);
2380 dhdsdio_sendpendctl(dhd_bus_t *bus)
2382 bcmsdh_info_t *sdh = bus->sdh;
2384 uint8* frame_seq = bus->ctrl_frame_buf + SDPCM_FRAMETAG_LEN;
2386 #ifdef BCMSDIOH_TXGLOM
2387 if (bus->glom_enable)
2388 frame_seq += SDPCM_HWEXT_LEN;
2391 if (*frame_seq != bus->tx_seq) {
2392 DHD_INFO(("%s IOCTL frame seq lag detected!"
2393 " frm_seq:%d != bus->tx_seq:%d, corrected\n",
2394 __FUNCTION__, *frame_seq, bus->tx_seq));
2395 *frame_seq = bus->tx_seq;
2398 ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
2399 (uint8 *)bus->ctrl_frame_buf, (uint32)bus->ctrl_frame_len,
2401 ASSERT(ret != BCME_PENDING);
2402 if (ret == BCME_NODEVICE) {
2403 DHD_ERROR(("%s: Device asleep already\n", __FUNCTION__));
2404 } else if (ret < 0) {
2405 /* On failure, abort the command and terminate the frame */
2406 DHD_INFO(("%s: sdio error %d, abort command and terminate frame.\n",
2407 __FUNCTION__, ret));
2410 bcmsdh_abort(sdh, SDIO_FUNC_2);
2412 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
2416 for (i = 0; i < 3; i++) {
2418 hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
2419 SBSDIO_FUNC1_WFRAMEBCHI, NULL);
2420 lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
2421 SBSDIO_FUNC1_WFRAMEBCLO, NULL);
2422 bus->f1regdata += 2;
2423 if ((hi == 0) && (lo == 0))
2428 bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
2431 bus->ctrl_frame_stat = FALSE;
2432 dhd_wait_event_wakeup(bus->dhd);
2436 dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen)
2442 bcmsdh_info_t *sdh = bus->sdh;
2447 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2449 if (bus->dhd->dongle_reset)
2452 /* Back the pointer to make a room for bus header */
2453 frame = msg - SDPCM_HDRLEN;
2454 len = (msglen += SDPCM_HDRLEN);
2456 /* Add alignment padding (optional for ctl frames) */
2458 if ((doff = ((uintptr)frame % DHD_SDALIGN))) {
2462 bzero(frame, doff + SDPCM_HDRLEN);
2464 ASSERT(doff < DHD_SDALIGN);
2466 doff += SDPCM_HDRLEN;
2468 /* Round send length to next SDIO block */
2469 if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
2470 uint16 pad = bus->blocksize - (len % bus->blocksize);
2471 if ((pad <= bus->roundup) && (pad < bus->blocksize))
2473 } else if (len % DHD_SDALIGN) {
2474 len += DHD_SDALIGN - (len % DHD_SDALIGN);
2477 /* Satisfy length-alignment requirements */
2478 if (forcealign && (len & (ALIGNMENT - 1)))
2479 len = ROUNDUP(len, ALIGNMENT);
2481 ASSERT(ISALIGNED((uintptr)frame, 2));
2484 /* Need to lock here to protect txseq and SDIO tx calls */
2485 dhd_os_sdlock(bus->dhd);
2489 /* Make sure backplane clock is on */
2490 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
2492 /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
2493 *(uint16*)frame = htol16((uint16)msglen);
2494 *(((uint16*)frame) + 1) = htol16(~msglen);
2496 #ifdef BCMSDIOH_TXGLOM
2497 if (bus->glom_enable) {
2498 uint32 hwheader1, hwheader2;
2499 /* Software tag: channel, sequence number, data offset */
2500 swheader = ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK)
2502 | ((doff << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
2503 htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN);
2504 htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN
2505 + SDPCM_HWEXT_LEN + sizeof(swheader));
2507 hwheader1 = (msglen - SDPCM_FRAMETAG_LEN) | (1 << 24);
2508 hwheader2 = (len - (msglen)) << 16;
2509 htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN);
2510 htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4);
2512 *(uint16*)frame = htol16(len);
2513 *(((uint16*)frame) + 1) = htol16(~(len));
2515 #endif /* BCMSDIOH_TXGLOM */
2517 /* Software tag: channel, sequence number, data offset */
2518 swheader = ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK)
2519 | bus->tx_seq | ((doff << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
2520 htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN);
2521 htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
2523 if (!TXCTLOK(bus)) {
2524 DHD_INFO(("%s: No bus credit bus->tx_max %d, bus->tx_seq %d\n",
2525 __FUNCTION__, bus->tx_max, bus->tx_seq));
2526 bus->ctrl_frame_stat = TRUE;
2528 bus->ctrl_frame_buf = frame;
2529 bus->ctrl_frame_len = len;
2531 if (!bus->dpc_sched) {
2532 bus->dpc_sched = TRUE;
2533 dhd_sched_dpc(bus->dhd);
2535 if (bus->ctrl_frame_stat) {
2536 dhd_wait_for_event(bus->dhd, &bus->ctrl_frame_stat);
2539 if (bus->ctrl_frame_stat == FALSE) {
2540 DHD_INFO(("%s: ctrl_frame_stat == FALSE\n", __FUNCTION__));
2543 bus->dhd->txcnt_timeout++;
2544 if (!bus->dhd->hang_was_sent) {
2545 DHD_ERROR(("%s: ctrl_frame_stat == TRUE txcnt_timeout=%d\n",
2546 __FUNCTION__, bus->dhd->txcnt_timeout));
2549 bus->ctrl_frame_stat = FALSE;
2554 bus->dhd->txcnt_timeout = 0;
2555 bus->ctrl_frame_stat = TRUE;
2559 if (DHD_BYTES_ON() && DHD_CTL_ON()) {
2560 prhex("Tx Frame", frame, len);
2561 } else if (DHD_HDRS_ON()) {
2562 prhex("TxHdr", frame, MIN(len, 16));
2567 ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
2568 frame, len, NULL, NULL, NULL);
2569 ASSERT(ret != BCME_PENDING);
2571 if (ret == BCME_NODEVICE) {
2572 DHD_ERROR(("%s: Device asleep already\n", __FUNCTION__));
2573 } else if (ret < 0) {
2574 /* On failure, abort the command and terminate the frame */
2575 DHD_INFO(("%s: sdio error %d, abort command and terminate frame.\n",
2576 __FUNCTION__, ret));
2579 bcmsdh_abort(sdh, SDIO_FUNC_2);
2581 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
2585 for (i = 0; i < 3; i++) {
2587 hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
2588 SBSDIO_FUNC1_WFRAMEBCHI, NULL);
2589 lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
2590 SBSDIO_FUNC1_WFRAMEBCLO, NULL);
2591 bus->f1regdata += 2;
2592 if ((hi == 0) && (lo == 0))
2597 bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
2599 } while ((ret < 0) && retries++ < TXRETRIES);
2601 bus->ctrl_frame_stat = FALSE;
2604 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
2605 bus->activity = FALSE;
2606 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
2609 dhd_os_sdunlock(bus->dhd);
2612 bus->dhd->tx_ctlerrs++;
2614 bus->dhd->tx_ctlpkts++;
2616 if (bus->dhd->txcnt_timeout >= MAX_CNTL_TX_TIMEOUT)
2619 return ret ? -EIO : 0;
2623 dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen)
2629 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2631 if (bus->dhd->dongle_reset)
2634 /* Wait until control frame is available */
2635 timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->rxlen, &pending);
2637 dhd_os_sdlock(bus->dhd);
2639 bcopy(bus->rxctl, msg, MIN(msglen, rxlen));
2641 dhd_os_sdunlock(bus->dhd);
2644 DHD_CTL(("%s: resumed on rxctl frame, got %d expected %d\n",
2645 __FUNCTION__, rxlen, msglen));
2646 } else if (timeleft == 0) {
2648 uint32 status, retry = 0;
2649 R_SDREG(status, &bus->regs->intstatus, retry);
2650 DHD_ERROR(("%s: resumed on timeout, INT status=0x%08X\n",
2651 __FUNCTION__, status));
2653 DHD_ERROR(("%s: resumed on timeout\n", __FUNCTION__));
2654 #endif /* DHD_DEBUG */
2656 dhd_os_sdlock(bus->dhd);
2657 dhdsdio_checkdied(bus, NULL, 0);
2658 dhd_os_sdunlock(bus->dhd);
2659 #endif /* DHD_DEBUG */
2660 } else if (pending == TRUE) {
2661 /* signal pending */
2662 DHD_ERROR(("%s: signal pending\n", __FUNCTION__));
2666 DHD_CTL(("%s: resumed for unknown reason?\n", __FUNCTION__));
2668 dhd_os_sdlock(bus->dhd);
2669 dhdsdio_checkdied(bus, NULL, 0);
2670 dhd_os_sdunlock(bus->dhd);
2671 #endif /* DHD_DEBUG */
2673 if (timeleft == 0) {
2675 bus->dhd->rxcnt_timeout++;
2676 DHD_ERROR(("%s: rxcnt_timeout=%d, rxlen=%d\n", __FUNCTION__,
2677 bus->dhd->rxcnt_timeout, rxlen));
2680 bus->dhd->rxcnt_timeout = 0;
2683 bus->dhd->rx_ctlpkts++;
2685 bus->dhd->rx_ctlerrs++;
2687 if (bus->dhd->rxcnt_timeout >= MAX_CNTL_RX_TIMEOUT)
2690 if (bus->dhd->dongle_trap_occured)
2693 return rxlen ? (int)rxlen : -EIO;
2709 #endif /* DHD_DEBUG */
2710 IOV_SET_DOWNLOAD_STATE,
2720 #if defined(SDIO_CRC_ERROR_FIX)
2723 #endif /* SDIO_CRC_ERROR_FIX */
2736 IOV_DONGLEISOLATION,
2749 const bcm_iovar_t dhdsdio_iovars[] = {
2750 {"intr", IOV_INTR, 0, IOVT_BOOL, 0 },
2751 {"sleep", IOV_SLEEP, 0, IOVT_BOOL, 0 },
2752 {"pollrate", IOV_POLLRATE, 0, IOVT_UINT32, 0 },
2753 {"idletime", IOV_IDLETIME, 0, IOVT_INT32, 0 },
2754 {"idleclock", IOV_IDLECLOCK, 0, IOVT_INT32, 0 },
2755 {"sd1idle", IOV_SD1IDLE, 0, IOVT_BOOL, 0 },
2756 {"membytes", IOV_MEMBYTES, 0, IOVT_BUFFER, 2 * sizeof(int) },
2757 {"ramsize", IOV_RAMSIZE, 0, IOVT_UINT32, 0 },
2758 {"ramstart", IOV_RAMSTART, 0, IOVT_UINT32, 0 },
2759 {"dwnldstate", IOV_SET_DOWNLOAD_STATE, 0, IOVT_BOOL, 0 },
2760 {"socram_state", IOV_SOCRAM_STATE, 0, IOVT_BOOL, 0 },
2761 {"vars", IOV_VARS, 0, IOVT_BUFFER, 0 },
2762 {"sdiod_drive", IOV_SDIOD_DRIVE, 0, IOVT_UINT32, 0 },
2763 {"readahead", IOV_READAHEAD, 0, IOVT_BOOL, 0 },
2764 {"sdrxchain", IOV_SDRXCHAIN, 0, IOVT_BOOL, 0 },
2765 {"alignctl", IOV_ALIGNCTL, 0, IOVT_BOOL, 0 },
2766 {"sdalign", IOV_SDALIGN, 0, IOVT_BOOL, 0 },
2767 {"devreset", IOV_DEVRESET, 0, IOVT_BOOL, 0 },
2769 {"sdreg", IOV_SDREG, 0, IOVT_BUFFER, sizeof(sdreg_t) },
2770 {"sbreg", IOV_SBREG, 0, IOVT_BUFFER, sizeof(sdreg_t) },
2771 {"sd_cis", IOV_SDCIS, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN },
2772 {"forcealign", IOV_FORCEEVEN, 0, IOVT_BOOL, 0 },
2773 {"txbound", IOV_TXBOUND, 0, IOVT_UINT32, 0 },
2774 {"rxbound", IOV_RXBOUND, 0, IOVT_UINT32, 0 },
2775 {"txminmax", IOV_TXMINMAX, 0, IOVT_UINT32, 0 },
2776 {"cpu", IOV_CPU, 0, IOVT_BOOL, 0 },
2778 {"checkdied", IOV_CHECKDIED, 0, IOVT_BUFFER, 0 },
2779 {"serial", IOV_SERIALCONS, 0, IOVT_UINT32, 0 },
2780 #endif /* DHD_DEBUG */
2781 #endif /* DHD_DEBUG */
2783 {"extloop", IOV_EXTLOOP, 0, IOVT_BOOL, 0 },
2784 {"pktgen", IOV_PKTGEN, 0, IOVT_BUFFER, sizeof(dhd_pktgen_t) },
2786 #if defined(SDIO_CRC_ERROR_FIX)
2787 {"watermark", IOV_WATERMARK, 0, IOVT_UINT32, 0 },
2788 {"mesbusyctrl", IOV_MESBUSYCTRL, 0, IOVT_UINT32, 0 },
2789 #endif /* SDIO_CRC_ERROR_FIX */
2790 {"devcap", IOV_DEVCAP, 0, IOVT_UINT32, 0 },
2791 {"dngl_isolation", IOV_DONGLEISOLATION, 0, IOVT_UINT32, 0 },
2792 {"kso", IOV_KSO, 0, IOVT_UINT32, 0 },
2793 {"devsleep", IOV_DEVSLEEP, 0, IOVT_UINT32, 0 },
2795 {"fwpath", IOV_FWPATH, 0, IOVT_BUFFER, 0 },
2797 {"txglomsize", IOV_TXGLOMSIZE, 0, IOVT_UINT32, 0 },
2798 {"txglommode", IOV_TXGLOMMODE, 0, IOVT_UINT32, 0 },
2799 {"fw_hang_report", IOV_HANGREPORT, 0, IOVT_BOOL, 0 },
2804 dhd_dump_pct(struct bcmstrbuf *strbuf, char *desc, uint num, uint div)
2809 bcm_bprintf(strbuf, "%s N/A", desc);
2812 q2 = (100 * (num - (q1 * div))) / div;
2813 bcm_bprintf(strbuf, "%s %d.%02d", desc, q1, q2);
2818 dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf)
2820 dhd_bus_t *bus = dhdp->bus;
2822 bcm_bprintf(strbuf, "Bus SDIO structure:\n");
2823 bcm_bprintf(strbuf, "hostintmask 0x%08x intstatus 0x%08x sdpcm_ver %d\n",
2824 bus->hostintmask, bus->intstatus, bus->sdpcm_ver);
2825 bcm_bprintf(strbuf, "fcstate %d qlen %u tx_seq %d, max %d, rxskip %d rxlen %u rx_seq %d\n",
2826 bus->fcstate, pktq_len(&bus->txq), bus->tx_seq, bus->tx_max, bus->rxskip,
2827 bus->rxlen, bus->rx_seq);
2828 bcm_bprintf(strbuf, "intr %d intrcount %u lastintrs %u spurious %u\n",
2829 bus->intr, bus->intrcount, bus->lastintrs, bus->spurious);
2830 bcm_bprintf(strbuf, "pollrate %u pollcnt %u regfails %u\n",
2831 bus->pollrate, bus->pollcnt, bus->regfails);
2833 bcm_bprintf(strbuf, "\nAdditional counters:\n");
2834 bcm_bprintf(strbuf, "tx_sderrs %u fcqueued %u rxrtx %u rx_toolong %u rxc_errors %u\n",
2835 bus->tx_sderrs, bus->fcqueued, bus->rxrtx, bus->rx_toolong,
2837 bcm_bprintf(strbuf, "rx_hdrfail %u badhdr %u badseq %u\n",
2838 bus->rx_hdrfail, bus->rx_badhdr, bus->rx_badseq);
2839 bcm_bprintf(strbuf, "fc_rcvd %u, fc_xoff %u, fc_xon %u\n",
2840 bus->fc_rcvd, bus->fc_xoff, bus->fc_xon);
2841 bcm_bprintf(strbuf, "rxglomfail %u, rxglomframes %u, rxglompkts %u\n",
2842 bus->rxglomfail, bus->rxglomframes, bus->rxglompkts);
2843 bcm_bprintf(strbuf, "f2rx (hdrs/data) %u (%u/%u), f2tx %u f1regs %u\n",
2844 (bus->f2rxhdrs + bus->f2rxdata), bus->f2rxhdrs, bus->f2rxdata,
2845 bus->f2txdata, bus->f1regdata);
2847 dhd_dump_pct(strbuf, "\nRx: pkts/f2rd", bus->dhd->rx_packets,
2848 (bus->f2rxhdrs + bus->f2rxdata));
2849 dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->rx_packets, bus->f1regdata);
2850 dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->rx_packets,
2851 (bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata));
2852 dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->rx_packets, bus->intrcount);
2853 bcm_bprintf(strbuf, "\n");
2855 dhd_dump_pct(strbuf, "Rx: glom pct", (100 * bus->rxglompkts),
2856 bus->dhd->rx_packets);
2857 dhd_dump_pct(strbuf, ", pkts/glom", bus->rxglompkts, bus->rxglomframes);
2858 bcm_bprintf(strbuf, "\n");
2860 dhd_dump_pct(strbuf, "Tx: pkts/f2wr", bus->dhd->tx_packets, bus->f2txdata);
2861 dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->tx_packets, bus->f1regdata);
2862 dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->tx_packets,
2863 (bus->f2txdata + bus->f1regdata));
2864 dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->tx_packets, bus->intrcount);
2865 bcm_bprintf(strbuf, "\n");
2867 dhd_dump_pct(strbuf, "Total: pkts/f2rw",
2868 (bus->dhd->tx_packets + bus->dhd->rx_packets),
2869 (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata));
2870 dhd_dump_pct(strbuf, ", pkts/f1sd",
2871 (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->f1regdata);
2872 dhd_dump_pct(strbuf, ", pkts/sd",
2873 (bus->dhd->tx_packets + bus->dhd->rx_packets),
2874 (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata));
2875 dhd_dump_pct(strbuf, ", pkts/int",
2876 (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->intrcount);
2877 bcm_bprintf(strbuf, "\n\n");
2881 if (bus->pktgen_count) {
2882 bcm_bprintf(strbuf, "pktgen config and count:\n");
2883 bcm_bprintf(strbuf, "freq %u count %u print %u total %u min %u len %u\n",
2884 bus->pktgen_freq, bus->pktgen_count, bus->pktgen_print,
2885 bus->pktgen_total, bus->pktgen_minlen, bus->pktgen_maxlen);
2886 bcm_bprintf(strbuf, "send attempts %u rcvd %u fail %u\n",
2887 bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail);
2891 bcm_bprintf(strbuf, "dpc_sched %d host interrupt%spending\n",
2892 bus->dpc_sched, (bcmsdh_intr_pending(bus->sdh) ? " " : " not "));
2893 bcm_bprintf(strbuf, "blocksize %u roundup %u\n", bus->blocksize, bus->roundup);
2894 #endif /* DHD_DEBUG */
2895 bcm_bprintf(strbuf, "clkstate %d activity %d idletime %d idlecount %d sleeping %d\n",
2896 bus->clkstate, bus->activity, bus->idletime, bus->idlecount, bus->sleeping);
2900 dhd_bus_clearcounts(dhd_pub_t *dhdp)
2902 dhd_bus_t *bus = (dhd_bus_t *)dhdp->bus;
2904 bus->intrcount = bus->lastintrs = bus->spurious = bus->regfails = 0;
2905 bus->rxrtx = bus->rx_toolong = bus->rxc_errors = 0;
2906 bus->rx_hdrfail = bus->rx_badhdr = bus->rx_badseq = 0;
2907 bus->tx_sderrs = bus->fc_rcvd = bus->fc_xoff = bus->fc_xon = 0;
2908 bus->rxglomfail = bus->rxglomframes = bus->rxglompkts = 0;
2909 bus->f2rxhdrs = bus->f2rxdata = bus->f2txdata = bus->f1regdata = 0;
2914 dhdsdio_pktgen_get(dhd_bus_t *bus, uint8 *arg)
2916 dhd_pktgen_t pktgen;
2918 pktgen.version = DHD_PKTGEN_VERSION;
2919 pktgen.freq = bus->pktgen_freq;
2920 pktgen.count = bus->pktgen_count;
2921 pktgen.print = bus->pktgen_print;
2922 pktgen.total = bus->pktgen_total;
2923 pktgen.minlen = bus->pktgen_minlen;
2924 pktgen.maxlen = bus->pktgen_maxlen;
2925 pktgen.numsent = bus->pktgen_sent;
2926 pktgen.numrcvd = bus->pktgen_rcvd;
2927 pktgen.numfail = bus->pktgen_fail;
2928 pktgen.mode = bus->pktgen_mode;
2929 pktgen.stop = bus->pktgen_stop;
2931 bcopy(&pktgen, arg, sizeof(pktgen));
2937 dhdsdio_pktgen_set(dhd_bus_t *bus, uint8 *arg)
2939 dhd_pktgen_t pktgen;
2940 uint oldcnt, oldmode;
2942 bcopy(arg, &pktgen, sizeof(pktgen));
2943 if (pktgen.version != DHD_PKTGEN_VERSION)
2946 oldcnt = bus->pktgen_count;
2947 oldmode = bus->pktgen_mode;
2949 bus->pktgen_freq = pktgen.freq;
2950 bus->pktgen_count = pktgen.count;
2951 bus->pktgen_print = pktgen.print;
2952 bus->pktgen_total = pktgen.total;
2953 bus->pktgen_minlen = pktgen.minlen;
2954 bus->pktgen_maxlen = pktgen.maxlen;
2955 bus->pktgen_mode = pktgen.mode;
2956 bus->pktgen_stop = pktgen.stop;
2958 bus->pktgen_tick = bus->pktgen_ptick = 0;
2959 bus->pktgen_prev_time = jiffies;
2960 bus->pktgen_len = MAX(bus->pktgen_len, bus->pktgen_minlen);
2961 bus->pktgen_len = MIN(bus->pktgen_len, bus->pktgen_maxlen);
2963 /* Clear counts for a new pktgen (mode change, or was stopped) */
2964 if (bus->pktgen_count && (!oldcnt || oldmode != bus->pktgen_mode)) {
2965 bus->pktgen_sent = bus->pktgen_prev_sent = bus->pktgen_rcvd = 0;
2966 bus->pktgen_prev_rcvd = bus->pktgen_fail = 0;
2974 dhdsdio_devram_remap(dhd_bus_t *bus, bool val)
2976 uint8 enable, protect, remap;
2978 si_socdevram(bus->sih, FALSE, &enable, &protect, &remap);
2979 remap = val ? TRUE : FALSE;
2980 si_socdevram(bus->sih, TRUE, &enable, &protect, &remap);
2984 dhdsdio_membytes(dhd_bus_t *bus, bool write, uint32 address, uint8 *data, uint size)
2990 /* In remap mode, adjust address beyond socram and redirect
2991 * to devram at SOCDEVRAM_BP_ADDR since remap address > orig_ramsize
2992 * is not backplane accessible
2994 if (REMAP_ENAB(bus) && REMAP_ISADDR(bus, address)) {
2995 address -= bus->orig_ramsize;
2996 address += SOCDEVRAM_BP_ADDR;
2999 /* Determine initial transfer parameters */
3000 sdaddr = address & SBSDIO_SB_OFT_ADDR_MASK;
3001 if ((sdaddr + size) & SBSDIO_SBWINDOW_MASK)
3002 dsize = (SBSDIO_SB_OFT_ADDR_LIMIT - sdaddr);
3006 /* Set the backplane window to include the start address */
3007 if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) {
3008 DHD_ERROR(("%s: window change failed\n", __FUNCTION__));
3012 /* Do the transfer(s) */
3014 DHD_INFO(("%s: %s %d bytes at offset 0x%08x in window 0x%08x\n",
3015 __FUNCTION__, (write ? "write" : "read"), dsize, sdaddr,
3016 (address & SBSDIO_SBWINDOW_MASK)));
3017 if ((bcmerror = bcmsdh_rwdata(bus->sdh, write, sdaddr, data, dsize))) {
3018 DHD_ERROR(("%s: membytes transfer failed\n", __FUNCTION__));
3022 /* Adjust for next transfer (if any) */
3023 if ((size -= dsize)) {
3026 if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) {
3027 DHD_ERROR(("%s: window change failed\n", __FUNCTION__));
3031 dsize = MIN(SBSDIO_SB_OFT_ADDR_LIMIT, size);
3037 /* Return the window to backplane enumeration space for core access */
3038 if (dhdsdio_set_siaddr_window(bus, bcmsdh_cur_sbwad(bus->sdh))) {
3039 DHD_ERROR(("%s: FAILED to set window back to 0x%x\n", __FUNCTION__,
3040 bcmsdh_cur_sbwad(bus->sdh)));
3048 dhdsdio_readshared(dhd_bus_t *bus, sdpcm_shared_t *sh)
3054 shaddr = bus->dongle_ram_base + bus->ramsize - 4;
3057 /* Read last word in memory to determine address of sdpcm_shared structure */
3058 if ((rv = dhdsdio_membytes(bus, FALSE, shaddr, (uint8 *)&addr, 4)) < 0)
3061 addr = ltoh32(addr);
3063 DHD_INFO(("sdpcm_shared address 0x%08X\n", addr));
3066 * Check if addr is valid.
3067 * NVRAM length at the end of memory should have been overwritten.
3069 if (addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff)) {
3070 if ((bus->srmemsize > 0) && (i++ == 0)) {
3071 shaddr -= bus->srmemsize;
3073 DHD_ERROR(("%s: address (0x%08x) of sdpcm_shared invalid\n",
3074 __FUNCTION__, addr));
3081 /* Read hndrte_shared structure */
3082 if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)sh, sizeof(sdpcm_shared_t))) < 0)
3086 sh->flags = ltoh32(sh->flags);
3087 sh->trap_addr = ltoh32(sh->trap_addr);
3088 sh->assert_exp_addr = ltoh32(sh->assert_exp_addr);
3089 sh->assert_file_addr = ltoh32(sh->assert_file_addr);
3090 sh->assert_line = ltoh32(sh->assert_line);
3091 sh->console_addr = ltoh32(sh->console_addr);
3092 sh->msgtrace_addr = ltoh32(sh->msgtrace_addr);
3094 if ((sh->flags & SDPCM_SHARED_VERSION_MASK) == 3 && SDPCM_SHARED_VERSION == 1)
3097 if ((sh->flags & SDPCM_SHARED_VERSION_MASK) != SDPCM_SHARED_VERSION) {
3098 DHD_ERROR(("%s: sdpcm_shared version %d in dhd "
3099 "is different than sdpcm_shared version %d in dongle\n",
3100 __FUNCTION__, SDPCM_SHARED_VERSION,
3101 sh->flags & SDPCM_SHARED_VERSION_MASK));
3108 #define CONSOLE_LINE_MAX 192
3111 dhdsdio_readconsole(dhd_bus_t *bus)
3113 dhd_console_t *c = &bus->console;
3114 uint8 line[CONSOLE_LINE_MAX], ch;
3115 uint32 n, idx, addr;
3118 /* Don't do anything until FWREADY updates console address */
3119 if (bus->console_addr == 0)
3125 /* Read console log struct */
3126 addr = bus->console_addr + OFFSETOF(hndrte_cons_t, log);
3127 if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)&c->log, sizeof(c->log))) < 0)
3130 /* Allocate console buffer (one time only) */
3131 if (c->buf == NULL) {
3132 c->bufsize = ltoh32(c->log.buf_size);
3133 if ((c->buf = MALLOC(bus->dhd->osh, c->bufsize)) == NULL)
3137 idx = ltoh32(c->log.idx);
3139 /* Protect against corrupt value */
3140 if (idx > c->bufsize)
3143 /* Skip reading the console buffer if the index pointer has not moved */
3147 /* Read the console buffer */
3148 addr = ltoh32(c->log.buf);
3149 if ((rv = dhdsdio_membytes(bus, FALSE, addr, c->buf, c->bufsize)) < 0)
3152 while (c->last != idx) {
3153 for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) {
3154 if (c->last == idx) {
3155 /* This would output a partial line. Instead, back up
3156 * the buffer pointer and output this line next time around.
3161 c->last = c->bufsize - n;
3164 ch = c->buf[c->last];
3165 c->last = (c->last + 1) % c->bufsize;
3172 if (line[n - 1] == '\r')
3175 printf("CONSOLE: %s\n", line);
3184 dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size)
3188 char *mbuffer = NULL;
3189 char *console_buffer = NULL;
3190 uint maxstrlen = 256;
3193 sdpcm_shared_t sdpcm_shared;
3194 struct bcmstrbuf strbuf;
3195 uint32 console_ptr, console_size, console_index;
3196 uint8 line[CONSOLE_LINE_MAX], ch;
3200 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3202 if (DHD_NOCHECKDIED_ON())
3207 * Called after a rx ctrl timeout. "data" is NULL.
3208 * allocate memory to trace the trap or assert.
3211 mbuffer = data = MALLOC(bus->dhd->osh, msize);
3212 if (mbuffer == NULL) {
3213 DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, msize));
3214 bcmerror = BCME_NOMEM;
3219 if ((str = MALLOC(bus->dhd->osh, maxstrlen)) == NULL) {
3220 DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, maxstrlen));
3221 bcmerror = BCME_NOMEM;
3225 if ((bcmerror = dhdsdio_readshared(bus, &sdpcm_shared)) < 0)
3228 bcm_binit(&strbuf, data, size);
3230 bcm_bprintf(&strbuf, "msgtrace address : 0x%08X\nconsole address : 0x%08X\n",
3231 sdpcm_shared.msgtrace_addr, sdpcm_shared.console_addr);
3233 if ((sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT) == 0) {
3234 /* NOTE: Misspelled assert is intentional - DO NOT FIX.
3235 * (Avoids conflict with real asserts for programmatic parsing of output.)
3237 bcm_bprintf(&strbuf, "Assrt not built in dongle\n");
3240 if ((sdpcm_shared.flags & (SDPCM_SHARED_ASSERT|SDPCM_SHARED_TRAP)) == 0) {
3241 /* NOTE: Misspelled assert is intentional - DO NOT FIX.
3242 * (Avoids conflict with real asserts for programmatic parsing of output.)
3244 bcm_bprintf(&strbuf, "No trap%s in dongle",
3245 (sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT)
3248 if (sdpcm_shared.flags & SDPCM_SHARED_ASSERT) {
3249 /* Download assert */
3250 bcm_bprintf(&strbuf, "Dongle assert");
3251 if (sdpcm_shared.assert_exp_addr != 0) {
3253 if ((bcmerror = dhdsdio_membytes(bus, FALSE,
3254 sdpcm_shared.assert_exp_addr,
3255 (uint8 *)str, maxstrlen)) < 0)
3258 str[maxstrlen - 1] = '\0';
3259 bcm_bprintf(&strbuf, " expr \"%s\"", str);
3262 if (sdpcm_shared.assert_file_addr != 0) {
3264 if ((bcmerror = dhdsdio_membytes(bus, FALSE,
3265 sdpcm_shared.assert_file_addr,
3266 (uint8 *)str, maxstrlen)) < 0)
3269 str[maxstrlen - 1] = '\0';
3270 bcm_bprintf(&strbuf, " file \"%s\"", str);
3273 bcm_bprintf(&strbuf, " line %d ", sdpcm_shared.assert_line);
3276 if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) {
3277 bus->dhd->dongle_trap_occured = TRUE;
3278 if ((bcmerror = dhdsdio_membytes(bus, FALSE,
3279 sdpcm_shared.trap_addr,
3280 (uint8*)&tr, sizeof(trap_t))) < 0)
3283 bcm_bprintf(&strbuf,
3284 "Dongle trap type 0x%x @ epc 0x%x, cpsr 0x%x, spsr 0x%x, sp 0x%x,"
3285 "lp 0x%x, rpc 0x%x Trap offset 0x%x, "
3286 "r0 0x%x, r1 0x%x, r2 0x%x, r3 0x%x, "
3287 "r4 0x%x, r5 0x%x, r6 0x%x, r7 0x%x\n\n",
3288 ltoh32(tr.type), ltoh32(tr.epc), ltoh32(tr.cpsr), ltoh32(tr.spsr),
3289 ltoh32(tr.r13), ltoh32(tr.r14), ltoh32(tr.pc),
3290 ltoh32(sdpcm_shared.trap_addr),
3291 ltoh32(tr.r0), ltoh32(tr.r1), ltoh32(tr.r2), ltoh32(tr.r3),
3292 ltoh32(tr.r4), ltoh32(tr.r5), ltoh32(tr.r6), ltoh32(tr.r7));
3294 addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log);
3295 if ((rv = dhdsdio_membytes(bus, FALSE, addr,
3296 (uint8 *)&console_ptr, sizeof(console_ptr))) < 0)
3299 addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log.buf_size);
3300 if ((rv = dhdsdio_membytes(bus, FALSE, addr,
3301 (uint8 *)&console_size, sizeof(console_size))) < 0)
3304 addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log.idx);
3305 if ((rv = dhdsdio_membytes(bus, FALSE, addr,
3306 (uint8 *)&console_index, sizeof(console_index))) < 0)
3309 console_ptr = ltoh32(console_ptr);
3310 console_size = ltoh32(console_size);
3311 console_index = ltoh32(console_index);
3313 if (console_size > CONSOLE_BUFFER_MAX ||
3314 !(console_buffer = MALLOC(bus->dhd->osh, console_size)))
3317 if ((rv = dhdsdio_membytes(bus, FALSE, console_ptr,
3318 (uint8 *)console_buffer, console_size)) < 0)
3321 for (i = 0, n = 0; i < console_size; i += n + 1) {
3322 for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) {
3323 ch = console_buffer[(console_index + i + n) % console_size];
3331 if (line[n - 1] == '\r')
3334 /* Don't use DHD_ERROR macro since we print
3335 * a lot of information quickly. The macro
3336 * will truncate a lot of the printfs
3339 if (dhd_msg_level & DHD_ERROR_VAL)
3340 printf("CONSOLE: %s\n", line);
3347 if (sdpcm_shared.flags & (SDPCM_SHARED_ASSERT | SDPCM_SHARED_TRAP)) {
3348 DHD_ERROR(("%s: %s\n", __FUNCTION__, strbuf.origbuf));
3354 MFREE(bus->dhd->osh, mbuffer, msize);
3356 MFREE(bus->dhd->osh, str, maxstrlen);
3358 MFREE(bus->dhd->osh, console_buffer, console_size);
3362 #endif /* #ifdef DHD_DEBUG */
3366 dhdsdio_downloadvars(dhd_bus_t *bus, void *arg, int len)
3368 int bcmerror = BCME_OK;
3370 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3372 /* Basic sanity checks */
3374 bcmerror = BCME_NOTDOWN;
3378 bcmerror = BCME_BUFTOOSHORT;
3382 /* Free the old ones and replace with passed variables */
3384 MFREE(bus->dhd->osh, bus->vars, bus->varsz);
3386 bus->vars = MALLOC(bus->dhd->osh, len);
3387 bus->varsz = bus->vars ? len : 0;
3388 if (bus->vars == NULL) {
3389 bcmerror = BCME_NOMEM;
3393 /* Copy the passed variables, which should include the terminating double-null */
3394 bcopy(arg, bus->vars, bus->varsz);
3401 #define CC_PLL_CHIPCTRL_SERIAL_ENAB (1 << 24)
3402 #define CC_CHIPCTRL_JTAG_SEL (1 << 3)
3403 #define CC_CHIPCTRL_GPIO_SEL (0x3)
3404 #define CC_PLL_CHIPCTRL_SERIAL_ENAB_4334 (1 << 28)
3407 dhd_serialconsole(dhd_bus_t *bus, bool set, bool enable, int *bcmerror)
3410 uint32 addr, data, uart_enab = 0;
3411 uint32 jtag_sel = CC_CHIPCTRL_JTAG_SEL;
3412 uint32 gpio_sel = CC_CHIPCTRL_GPIO_SEL;
3414 addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr);
3415 data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data);
3418 bcmsdh_reg_write(bus->sdh, addr, 4, 1);
3419 if (bcmsdh_regfail(bus->sdh)) {
3420 *bcmerror = BCME_SDIO_ERROR;
3423 int_val = bcmsdh_reg_read(bus->sdh, data, 4);
3424 if (bcmsdh_regfail(bus->sdh)) {
3425 *bcmerror = BCME_SDIO_ERROR;
3428 if (bus->sih->chip == BCM4330_CHIP_ID) {
3429 uart_enab = CC_PLL_CHIPCTRL_SERIAL_ENAB;
3431 else if (bus->sih->chip == BCM4334_CHIP_ID ||
3432 bus->sih->chip == BCM43340_CHIP_ID ||
3433 bus->sih->chip == BCM43341_CHIP_ID ||
3436 /* Moved to PMU chipcontrol 1 from 4330 */
3437 int_val &= ~gpio_sel;
3438 int_val |= jtag_sel;
3440 int_val |= gpio_sel;
3441 int_val &= ~jtag_sel;
3443 uart_enab = CC_PLL_CHIPCTRL_SERIAL_ENAB_4334;
3447 return (int_val & uart_enab);
3449 int_val |= uart_enab;
3451 int_val &= ~uart_enab;
3452 bcmsdh_reg_write(bus->sdh, data, 4, int_val);
3453 if (bcmsdh_regfail(bus->sdh)) {
3454 *bcmerror = BCME_SDIO_ERROR;
3457 if (bus->sih->chip == BCM4330_CHIP_ID) {
3459 addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol);
3460 chipcontrol = bcmsdh_reg_read(bus->sdh, addr, 4);
3461 chipcontrol &= ~jtag_sel;
3463 chipcontrol |= jtag_sel;
3464 chipcontrol &= ~gpio_sel;
3466 bcmsdh_reg_write(bus->sdh, addr, 4, chipcontrol);
3469 return (int_val & uart_enab);
3474 dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const char *name,
3475 void *params, int plen, void *arg, int len, int val_size)
3481 DHD_TRACE(("%s: Enter, action %d name %s params %p plen %d arg %p len %d val_size %d\n",
3482 __FUNCTION__, actionid, name, params, plen, arg, len, val_size));
3484 if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0)
3487 if (plen >= (int)sizeof(int_val))
3488 bcopy(params, &int_val, sizeof(int_val));
3490 bool_val = (int_val != 0) ? TRUE : FALSE;
3493 /* Some ioctls use the bus */
3494 dhd_os_sdlock(bus->dhd);
3496 /* Check if dongle is in reset. If so, only allow DEVRESET iovars */
3497 if (bus->dhd->dongle_reset && !(actionid == IOV_SVAL(IOV_DEVRESET) ||
3498 actionid == IOV_GVAL(IOV_DEVRESET))) {
3499 bcmerror = BCME_NOTREADY;
3504 * Special handling for keepSdioOn: New SDIO Wake-up Mechanism
3506 if ((vi->varid == IOV_KSO) && (IOV_ISSET(actionid))) {
3507 dhdsdio_clk_kso_iovar(bus, bool_val);
3509 } else if ((vi->varid == IOV_DEVSLEEP) && (IOV_ISSET(actionid))) {
3511 dhdsdio_clk_devsleep_iovar(bus, bool_val);
3512 if (!SLPAUTO_ENAB(bus) && (bool_val == FALSE) && (bus->ipend)) {
3513 DHD_ERROR(("INT pending in devsleep 1, dpc_sched: %d\n",
3515 if (!bus->dpc_sched) {
3516 bus->dpc_sched = TRUE;
3517 dhd_sched_dpc(bus->dhd);
3524 /* Handle sleep stuff before any clock mucking */
3525 if (vi->varid == IOV_SLEEP) {
3526 if (IOV_ISSET(actionid)) {
3527 bcmerror = dhdsdio_bussleep(bus, bool_val);
3529 int_val = (int32)bus->sleeping;
3530 bcopy(&int_val, arg, val_size);
3535 /* Request clock to allow SDIO accesses */
3536 if (!bus->dhd->dongle_reset) {
3538 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
3542 case IOV_GVAL(IOV_INTR):
3543 int_val = (int32)bus->intr;
3544 bcopy(&int_val, arg, val_size);
3547 case IOV_SVAL(IOV_INTR):
3548 bus->intr = bool_val;
3549 bus->intdis = FALSE;
3552 DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__));
3553 bcmsdh_intr_enable(bus->sdh);
3555 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
3556 bcmsdh_intr_disable(bus->sdh);
3561 case IOV_GVAL(IOV_POLLRATE):
3562 int_val = (int32)bus->pollrate;
3563 bcopy(&int_val, arg, val_size);
3566 case IOV_SVAL(IOV_POLLRATE):
3567 bus->pollrate = (uint)int_val;
3568 bus->poll = (bus->pollrate != 0);
3571 case IOV_GVAL(IOV_IDLETIME):
3572 int_val = bus->idletime;
3573 bcopy(&int_val, arg, val_size);
3576 case IOV_SVAL(IOV_IDLETIME):
3577 if ((int_val < 0) && (int_val != DHD_IDLE_IMMEDIATE)) {
3578 bcmerror = BCME_BADARG;
3580 bus->idletime = int_val;
3584 case IOV_GVAL(IOV_IDLECLOCK):
3585 int_val = (int32)bus->idleclock;
3586 bcopy(&int_val, arg, val_size);
3589 case IOV_SVAL(IOV_IDLECLOCK):
3590 bus->idleclock = int_val;
3593 case IOV_GVAL(IOV_SD1IDLE):
3594 int_val = (int32)sd1idle;
3595 bcopy(&int_val, arg, val_size);
3598 case IOV_SVAL(IOV_SD1IDLE):
3603 case IOV_SVAL(IOV_MEMBYTES):
3604 case IOV_GVAL(IOV_MEMBYTES):
3610 bool set = (actionid == IOV_SVAL(IOV_MEMBYTES));
3612 ASSERT(plen >= 2*sizeof(int));
3614 address = (uint32)int_val;
3615 bcopy((char *)params + sizeof(int_val), &int_val, sizeof(int_val));
3616 size = (uint)int_val;
3618 /* Do some validation */
3619 dsize = set ? plen - (2 * sizeof(int)) : len;
3621 DHD_ERROR(("%s: error on %s membytes, addr 0x%08x size %d dsize %d\n",
3622 __FUNCTION__, (set ? "set" : "get"), address, size, dsize));
3623 bcmerror = BCME_BADARG;
3627 DHD_INFO(("%s: Request to %s %d bytes at address 0x%08x\n", __FUNCTION__,
3628 (set ? "write" : "read"), size, address));
3631 if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
3633 * If address is start of RAM (i.e. a downloaded image),
3634 * store the reset instruction to be written in 0
3636 if (address == bus->dongle_ram_base) {
3637 bus->resetinstr = *(((uint32*)params) + 2);
3640 /* If we know about SOCRAM, check for a fit */
3641 if ((bus->orig_ramsize) &&
3642 ((address > bus->orig_ramsize) || (address + size > bus->orig_ramsize)))
3644 uint8 enable, protect, remap;
3645 si_socdevram(bus->sih, FALSE, &enable, &protect, &remap);
3646 if (!enable || protect) {
3647 DHD_ERROR(("%s: ramsize 0x%08x doesn't have %d bytes at 0x%08x\n",
3648 __FUNCTION__, bus->orig_ramsize, size, address));
3649 DHD_ERROR(("%s: socram enable %d, protect %d\n",
3650 __FUNCTION__, enable, protect));
3651 bcmerror = BCME_BADARG;
3655 if (!REMAP_ENAB(bus) && (address >= SOCDEVRAM_ARM_ADDR)) {
3656 uint32 devramsize = si_socdevram_size(bus->sih);
3657 if ((address < SOCDEVRAM_ARM_ADDR) ||
3658 (address + size > (SOCDEVRAM_ARM_ADDR + devramsize))) {
3659 DHD_ERROR(("%s: bad address 0x%08x, size 0x%08x\n",
3660 __FUNCTION__, address, size));
3661 DHD_ERROR(("%s: socram range 0x%08x,size 0x%08x\n",
3662 __FUNCTION__, SOCDEVRAM_ARM_ADDR, devramsize));
3663 bcmerror = BCME_BADARG;
3666 /* move it such that address is real now */
3667 address -= SOCDEVRAM_ARM_ADDR;
3668 address += SOCDEVRAM_BP_ADDR;
3669 DHD_INFO(("%s: Request to %s %d bytes @ Mapped address 0x%08x\n",
3670 __FUNCTION__, (set ? "write" : "read"), size, address));
3671 } else if (REMAP_ENAB(bus) && REMAP_ISADDR(bus, address) && remap) {
3672 /* Can not access remap region while devram remap bit is set
3673 * ROM content would be returned in this case
3675 DHD_ERROR(("%s: Need to disable remap for address 0x%08x\n",
3676 __FUNCTION__, address));
3677 bcmerror = BCME_ERROR;
3683 /* Generate the actual data pointer */
3684 data = set ? (uint8*)params + 2 * sizeof(int): (uint8*)arg;
3686 /* Call to do the transfer */
3687 bcmerror = dhdsdio_membytes(bus, set, address, data, size);
3692 case IOV_GVAL(IOV_RAMSIZE):
3693 int_val = (int32)bus->ramsize;
3694 bcopy(&int_val, arg, val_size);
3697 case IOV_GVAL(IOV_RAMSTART):
3698 int_val = (int32)bus->dongle_ram_base;
3699 bcopy(&int_val, arg, val_size);
3702 case IOV_GVAL(IOV_SDIOD_DRIVE):
3703 int_val = (int32)dhd_sdiod_drive_strength;
3704 bcopy(&int_val, arg, val_size);
3707 case IOV_SVAL(IOV_SDIOD_DRIVE):
3708 dhd_sdiod_drive_strength = int_val;
3709 si_sdiod_drive_strength_init(bus->sih, bus->dhd->osh, dhd_sdiod_drive_strength);
3712 case IOV_SVAL(IOV_SET_DOWNLOAD_STATE):
3713 bcmerror = dhdsdio_download_state(bus, bool_val);
3716 case IOV_SVAL(IOV_SOCRAM_STATE):
3717 bcmerror = dhdsdio_download_state(bus, bool_val);
3720 case IOV_SVAL(IOV_VARS):
3721 bcmerror = dhdsdio_downloadvars(bus, arg, len);
3724 case IOV_GVAL(IOV_READAHEAD):
3725 int_val = (int32)dhd_readahead;
3726 bcopy(&int_val, arg, val_size);
3729 case IOV_SVAL(IOV_READAHEAD):
3730 if (bool_val && !dhd_readahead)
3732 dhd_readahead = bool_val;
3735 case IOV_GVAL(IOV_SDRXCHAIN):
3736 int_val = (int32)bus->use_rxchain;
3737 bcopy(&int_val, arg, val_size);
3740 case IOV_SVAL(IOV_SDRXCHAIN):
3741 if (bool_val && !bus->sd_rxchain)
3742 bcmerror = BCME_UNSUPPORTED;
3744 bus->use_rxchain = bool_val;
3746 case IOV_GVAL(IOV_ALIGNCTL):
3747 int_val = (int32)dhd_alignctl;
3748 bcopy(&int_val, arg, val_size);
3751 case IOV_SVAL(IOV_ALIGNCTL):
3752 dhd_alignctl = bool_val;
3755 case IOV_GVAL(IOV_SDALIGN):
3756 int_val = DHD_SDALIGN;
3757 bcopy(&int_val, arg, val_size);
3761 case IOV_GVAL(IOV_VARS):
3762 if (bus->varsz < (uint)len)
3763 bcopy(bus->vars, arg, bus->varsz);
3765 bcmerror = BCME_BUFTOOSHORT;
3767 #endif /* DHD_DEBUG */
3770 case IOV_GVAL(IOV_SDREG):
3775 sd_ptr = (sdreg_t *)params;
3777 addr = (uintptr)bus->regs + sd_ptr->offset;
3778 size = sd_ptr->func;
3779 int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size);
3780 if (bcmsdh_regfail(bus->sdh))
3781 bcmerror = BCME_SDIO_ERROR;
3782 bcopy(&int_val, arg, sizeof(int32));
3786 case IOV_SVAL(IOV_SDREG):
3791 sd_ptr = (sdreg_t *)params;
3793 addr = (uintptr)bus->regs + sd_ptr->offset;
3794 size = sd_ptr->func;
3795 bcmsdh_reg_write(bus->sdh, addr, size, sd_ptr->value);
3796 if (bcmsdh_regfail(bus->sdh))
3797 bcmerror = BCME_SDIO_ERROR;
3801 /* Same as above, but offset is not backplane (not SDIO core) */
3802 case IOV_GVAL(IOV_SBREG):
3807 bcopy(params, &sdreg, sizeof(sdreg));
3809 addr = SI_ENUM_BASE + sdreg.offset;
3811 int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size);
3812 if (bcmsdh_regfail(bus->sdh))
3813 bcmerror = BCME_SDIO_ERROR;
3814 bcopy(&int_val, arg, sizeof(int32));
3818 case IOV_SVAL(IOV_SBREG):
3823 bcopy(params, &sdreg, sizeof(sdreg));
3825 addr = SI_ENUM_BASE + sdreg.offset;
3827 bcmsdh_reg_write(bus->sdh, addr, size, sdreg.value);
3828 if (bcmsdh_regfail(bus->sdh))
3829 bcmerror = BCME_SDIO_ERROR;
3833 case IOV_GVAL(IOV_SDCIS):
3837 bcmstrcat(arg, "\nFunc 0\n");
3838 bcmsdh_cis_read(bus->sdh, 0x10, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
3839 bcmstrcat(arg, "\nFunc 1\n");
3840 bcmsdh_cis_read(bus->sdh, 0x11, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
3841 bcmstrcat(arg, "\nFunc 2\n");
3842 bcmsdh_cis_read(bus->sdh, 0x12, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
3846 case IOV_GVAL(IOV_FORCEEVEN):
3847 int_val = (int32)forcealign;
3848 bcopy(&int_val, arg, val_size);
3851 case IOV_SVAL(IOV_FORCEEVEN):
3852 forcealign = bool_val;
3855 case IOV_GVAL(IOV_TXBOUND):
3856 int_val = (int32)dhd_txbound;
3857 bcopy(&int_val, arg, val_size);
3860 case IOV_SVAL(IOV_TXBOUND):
3861 dhd_txbound = (uint)int_val;
3864 case IOV_GVAL(IOV_RXBOUND):
3865 int_val = (int32)dhd_rxbound;
3866 bcopy(&int_val, arg, val_size);
3869 case IOV_SVAL(IOV_RXBOUND):
3870 dhd_rxbound = (uint)int_val;
3873 case IOV_GVAL(IOV_TXMINMAX):
3874 int_val = (int32)dhd_txminmax;
3875 bcopy(&int_val, arg, val_size);
3878 case IOV_SVAL(IOV_TXMINMAX):
3879 dhd_txminmax = (uint)int_val;
3882 case IOV_GVAL(IOV_SERIALCONS):
3883 int_val = dhd_serialconsole(bus, FALSE, 0, &bcmerror);
3887 bcopy(&int_val, arg, val_size);
3890 case IOV_SVAL(IOV_SERIALCONS):
3891 dhd_serialconsole(bus, TRUE, bool_val, &bcmerror);
3896 #endif /* DHD_DEBUG */
3900 case IOV_GVAL(IOV_EXTLOOP):
3901 int_val = (int32)bus->ext_loop;
3902 bcopy(&int_val, arg, val_size);
3905 case IOV_SVAL(IOV_EXTLOOP):
3906 bus->ext_loop = bool_val;
3909 case IOV_GVAL(IOV_PKTGEN):
3910 bcmerror = dhdsdio_pktgen_get(bus, arg);
3913 case IOV_SVAL(IOV_PKTGEN):
3914 bcmerror = dhdsdio_pktgen_set(bus, arg);
3918 #if defined(SDIO_CRC_ERROR_FIX)
3919 case IOV_GVAL(IOV_WATERMARK):
3920 int_val = (int32)watermark;
3921 bcopy(&int_val, arg, val_size);
3924 case IOV_SVAL(IOV_WATERMARK):
3925 watermark = (uint)int_val;
3926 watermark = (watermark > SBSDIO_WATERMARK_MASK) ? SBSDIO_WATERMARK_MASK : watermark;
3927 DHD_ERROR(("Setting watermark as 0x%x.\n", watermark));
3928 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, (uint8)watermark, NULL);
3931 case IOV_GVAL(IOV_MESBUSYCTRL):
3932 int_val = (int32)mesbusyctrl;
3933 bcopy(&int_val, arg, val_size);
3936 case IOV_SVAL(IOV_MESBUSYCTRL):
3937 mesbusyctrl = (uint)int_val;
3938 mesbusyctrl = (mesbusyctrl > SBSDIO_MESBUSYCTRL_MASK)
3939 ? SBSDIO_MESBUSYCTRL_MASK : mesbusyctrl;
3940 DHD_ERROR(("Setting mesbusyctrl as 0x%x.\n", mesbusyctrl));
3941 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL,
3942 ((uint8)mesbusyctrl | 0x80), NULL);
3944 #endif /* SDIO_CRC_ERROR_FIX */
3947 case IOV_GVAL(IOV_DONGLEISOLATION):
3948 int_val = bus->dhd->dongle_isolation;
3949 bcopy(&int_val, arg, val_size);
3952 case IOV_SVAL(IOV_DONGLEISOLATION):
3953 bus->dhd->dongle_isolation = bool_val;
3956 case IOV_SVAL(IOV_DEVRESET):
3957 DHD_TRACE(("%s: Called set IOV_DEVRESET=%d dongle_reset=%d busstate=%d\n",
3958 __FUNCTION__, bool_val, bus->dhd->dongle_reset,
3959 bus->dhd->busstate));
3961 ASSERT(bus->dhd->osh);
3962 /* ASSERT(bus->cl_devid); */
3964 dhd_bus_devreset(bus->dhd, (uint8)bool_val);
3968 case IOV_GVAL(IOV_FWPATH):
3972 fw_path_len = strlen(bus->fw_path);
3973 DHD_INFO(("[softap] get fwpath, l=%d\n", len));
3975 if (fw_path_len > len-1) {
3976 bcmerror = BCME_BUFTOOSHORT;
3981 bcopy(bus->fw_path, arg, fw_path_len);
3982 ((uchar*)arg)[fw_path_len] = 0;
3987 case IOV_SVAL(IOV_FWPATH):
3988 DHD_INFO(("[softap] set fwpath, idx=%d\n", int_val));
3992 bus->fw_path = fw_path; /* ordinary one */
3995 bus->fw_path = fw_path2;
3998 bcmerror = BCME_BADARG;
4002 DHD_INFO(("[softap] new fw path: %s\n", (bus->fw_path[0] ? bus->fw_path : "NULL")));
4006 case IOV_GVAL(IOV_DEVRESET):
4007 DHD_TRACE(("%s: Called get IOV_DEVRESET\n", __FUNCTION__));
4009 /* Get its status */
4010 int_val = (bool) bus->dhd->dongle_reset;
4011 bcopy(&int_val, arg, val_size);
4015 case IOV_GVAL(IOV_KSO):
4016 int_val = dhdsdio_sleepcsr_get(bus);
4017 bcopy(&int_val, arg, val_size);
4020 case IOV_GVAL(IOV_DEVCAP):
4021 int_val = dhdsdio_devcap_get(bus);
4022 bcopy(&int_val, arg, val_size);
4025 case IOV_SVAL(IOV_DEVCAP):
4026 dhdsdio_devcap_set(bus, (uint8) int_val);
4029 #ifdef BCMSDIOH_TXGLOM
4030 case IOV_GVAL(IOV_TXGLOMSIZE):
4031 int_val = (int32)bus->glomsize;
4032 bcopy(&int_val, arg, val_size);
4035 case IOV_SVAL(IOV_TXGLOMSIZE):
4036 if (int_val > SDPCM_MAXGLOM_SIZE) {
4037 bcmerror = BCME_ERROR;
4039 bus->glomsize = (uint)int_val;
4042 case IOV_GVAL(IOV_TXGLOMMODE):
4043 int_val = (int32)bus->glom_mode;
4044 bcopy(&int_val, arg, val_size);
4047 case IOV_SVAL(IOV_TXGLOMMODE):
4048 if ((int_val != SDPCM_TXGLOM_CPY) && (int_val != SDPCM_TXGLOM_MDESC)) {
4049 bcmerror = BCME_RANGE;
4051 if ((bus->glom_mode = bcmsdh_set_mode(bus->sdh, (uint)int_val)) != int_val)
4052 bcmerror = BCME_ERROR;
4055 #endif /* BCMSDIOH_TXGLOM */
4056 case IOV_SVAL(IOV_HANGREPORT):
4057 bus->dhd->hang_report = bool_val;
4058 DHD_ERROR(("%s: Set hang_report as %d\n", __FUNCTION__, bus->dhd->hang_report));
4061 case IOV_GVAL(IOV_HANGREPORT):
4062 int_val = (int32)bus->dhd->hang_report;
4063 bcopy(&int_val, arg, val_size);
4066 bcmerror = BCME_UNSUPPORTED;
4071 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
4072 bus->activity = FALSE;
4073 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
4076 dhd_os_sdunlock(bus->dhd);
4082 dhdsdio_write_vars(dhd_bus_t *bus)
4085 uint32 varsize, phys_size;
4090 uint8 *nvram_ularray;
4091 #endif /* DHD_DEBUG */
4093 /* Even if there are no vars are to be written, we still need to set the ramsize. */
4094 varsize = bus->varsz ? ROUNDUP(bus->varsz, 4) : 0;
4095 varaddr = (bus->ramsize - 4) - varsize;
4097 varaddr += bus->dongle_ram_base;
4100 if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 7)) {
4101 if (((varaddr & 0x3C) == 0x3C) && (varsize > 4)) {
4102 DHD_ERROR(("PR85623WAR in place\n"));
4108 vbuffer = (uint8 *)MALLOC(bus->dhd->osh, varsize);
4112 bzero(vbuffer, varsize);
4113 bcopy(bus->vars, vbuffer, bus->varsz);
4115 /* Write the vars list */
4116 bcmerror = dhdsdio_membytes(bus, TRUE, varaddr, vbuffer, varsize);
4118 /* Verify NVRAM bytes */
4119 DHD_INFO(("Compare NVRAM dl & ul; varsize=%d\n", varsize));
4120 nvram_ularray = (uint8*)MALLOC(bus->dhd->osh, varsize);
4124 /* Upload image to verify downloaded contents. */
4125 memset(nvram_ularray, 0xaa, varsize);
4127 /* Read the vars list to temp buffer for comparison */
4128 bcmerror = dhdsdio_membytes(bus, FALSE, varaddr, nvram_ularray, varsize);
4130 DHD_ERROR(("%s: error %d on reading %d nvram bytes at 0x%08x\n",
4131 __FUNCTION__, bcmerror, varsize, varaddr));
4133 /* Compare the org NVRAM with the one read from RAM */
4134 if (memcmp(vbuffer, nvram_ularray, varsize)) {
4135 DHD_ERROR(("%s: Downloaded NVRAM image is corrupted.\n", __FUNCTION__));
4137 DHD_ERROR(("%s: Download, Upload and compare of NVRAM succeeded.\n",
4140 MFREE(bus->dhd->osh, nvram_ularray, varsize);
4141 #endif /* DHD_DEBUG */
4143 MFREE(bus->dhd->osh, vbuffer, varsize);
4146 phys_size = REMAP_ENAB(bus) ? bus->ramsize : bus->orig_ramsize;
4148 phys_size += bus->dongle_ram_base;
4150 /* adjust to the user specified RAM */
4151 DHD_INFO(("Physical memory size: %d, usable memory size: %d\n",
4152 phys_size, bus->ramsize));
4153 DHD_INFO(("Vars are at %d, orig varsize is %d\n",
4155 varsize = ((phys_size - 4) - varaddr);
4158 * Determine the length token:
4159 * Varsize, converted to words, in lower 16-bits, checksum in upper 16-bits.
4164 varsizew = varsize / 4;
4165 varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF);
4166 varsizew = htol32(varsizew);
4169 DHD_INFO(("New varsize is %d, length token=0x%08x\n", varsize, varsizew));
4171 /* Write the length token to the last word */
4172 bcmerror = dhdsdio_membytes(bus, TRUE, (phys_size - 4),
4173 (uint8*)&varsizew, 4);
4179 dhdsdio_download_state(dhd_bus_t *bus, bool enter)
4187 /* To enter download state, disable ARM and reset SOCRAM.
4188 * To exit download state, simply reset ARM (default is RAM boot).
4191 bus->alp_only = TRUE;
4193 if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) &&
4194 !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) {
4195 if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
4198 DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__));
4199 bcmerror = BCME_ERROR;
4205 si_core_disable(bus->sih, 0);
4206 if (bcmsdh_regfail(bus->sdh)) {
4207 bcmerror = BCME_SDIO_ERROR;
4211 if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) {
4212 DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__));
4213 bcmerror = BCME_ERROR;
4217 si_core_reset(bus->sih, 0, 0);
4218 if (bcmsdh_regfail(bus->sdh)) {
4219 DHD_ERROR(("%s: Failure trying reset SOCRAM core?\n",
4221 bcmerror = BCME_SDIO_ERROR;
4225 /* Disable remap for download */
4226 if (REMAP_ENAB(bus) && si_socdevram_remap_isenb(bus->sih))
4227 dhdsdio_devram_remap(bus, FALSE);
4229 /* Clear the top bit of memory */
4232 if (dhdsdio_membytes(bus, TRUE, bus->ramsize - 4,
4233 (uint8*)&zeros, 4) < 0) {
4234 bcmerror = BCME_SDIO_ERROR;
4242 * Read RAM base address [0x18_0000]
4243 * [next] Download firmware
4244 * [done at else] Populate the reset vector
4245 * [done at else] Remove ARM halt
4247 /* Halt ARM & remove reset */
4248 si_core_reset(bus->sih, SICF_CPUHALT, SICF_CPUHALT);
4251 if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
4252 if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) {
4253 DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__));
4254 bcmerror = BCME_ERROR;
4258 if (!si_iscoreup(bus->sih)) {
4259 DHD_ERROR(("%s: SOCRAM core is down after reset?\n", __FUNCTION__));
4260 bcmerror = BCME_ERROR;
4264 if ((bcmerror = dhdsdio_write_vars(bus))) {
4265 DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__));
4269 /* Enable remap before ARM reset but after vars.
4270 * No backplane access in remap mode
4272 if (REMAP_ENAB(bus) && !si_socdevram_remap_isenb(bus->sih))
4273 dhdsdio_devram_remap(bus, TRUE);
4275 if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) &&
4276 !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) {
4277 DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__));
4278 bcmerror = BCME_ERROR;
4281 W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries);
4284 if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) &&
4285 !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) {
4286 DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__));
4287 bcmerror = BCME_ERROR;
4291 /* cr4 has no socram, but tcm's */
4293 if ((bcmerror = dhdsdio_write_vars(bus))) {
4294 DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__));
4298 if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) &&
4299 !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) {
4300 DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__));
4301 bcmerror = BCME_ERROR;
4304 W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries);
4306 /* switch back to arm core again */
4307 if (!(si_setcore(bus->sih, ARMCR4_CORE_ID, 0))) {
4308 DHD_ERROR(("%s: Failed to find ARM CR4 core!\n", __FUNCTION__));
4309 bcmerror = BCME_ERROR;
4312 /* write address 0 with reset instruction */
4313 bcmerror = dhdsdio_membytes(bus, TRUE, 0,
4314 (uint8 *)&bus->resetinstr, sizeof(bus->resetinstr));
4316 /* now remove reset and halt and continue to run CR4 */
4319 si_core_reset(bus->sih, 0, 0);
4320 if (bcmsdh_regfail(bus->sdh)) {
4321 DHD_ERROR(("%s: Failure trying to reset ARM core?\n", __FUNCTION__));
4322 bcmerror = BCME_SDIO_ERROR;
4326 /* Allow HT Clock now that the ARM is running. */
4327 bus->alp_only = FALSE;
4329 bus->dhd->busstate = DHD_BUS_LOAD;
4333 /* Always return to SDIOD core */
4334 if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0))
4335 si_setcore(bus->sih, SDIOD_CORE_ID, 0);
4341 dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name,
4342 void *params, int plen, void *arg, int len, bool set)
4344 dhd_bus_t *bus = dhdp->bus;
4345 const bcm_iovar_t *vi = NULL;
4350 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4355 /* Get MUST have return space */
4356 ASSERT(set || (arg && len));
4358 /* Set does NOT take qualifiers */
4359 ASSERT(!set || (!params && !plen));
4361 /* Look up var locally; if not found pass to host driver */
4362 if ((vi = bcm_iovar_lookup(dhdsdio_iovars, name)) == NULL) {
4363 dhd_os_sdlock(bus->dhd);
4367 /* Turn on clock in case SD command needs backplane */
4368 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
4370 bcmerror = bcmsdh_iovar_op(bus->sdh, name, params, plen, arg, len, set);
4372 /* Check for bus configuration changes of interest */
4374 /* If it was divisor change, read the new one */
4375 if (set && strcmp(name, "sd_divisor") == 0) {
4376 if (bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
4377 &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) {
4378 bus->sd_divisor = -1;
4379 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, name));
4381 DHD_INFO(("%s: noted %s update, value now %d\n",
4382 __FUNCTION__, name, bus->sd_divisor));
4385 /* If it was a mode change, read the new one */
4386 if (set && strcmp(name, "sd_mode") == 0) {
4387 if (bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
4388 &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) {
4390 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, name));
4392 DHD_INFO(("%s: noted %s update, value now %d\n",
4393 __FUNCTION__, name, bus->sd_mode));
4396 /* Similar check for blocksize change */
4397 if (set && strcmp(name, "sd_blocksize") == 0) {
4399 if (bcmsdh_iovar_op(bus->sdh, "sd_blocksize", &fnum, sizeof(int32),
4400 &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) {
4402 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize"));
4404 DHD_INFO(("%s: noted %s update, value now %d\n",
4405 __FUNCTION__, "sd_blocksize", bus->blocksize));
4407 if ((bus->sih->chip == BCM4335_CHIP_ID) ||
4408 (bus->sih->chip == BCM4339_CHIP_ID))
4409 dhd_overflow_war(bus);
4412 bus->roundup = MIN(max_roundup, bus->blocksize);
4414 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
4415 bus->activity = FALSE;
4416 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
4419 dhd_os_sdunlock(bus->dhd);
4423 DHD_CTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__,
4424 name, (set ? "set" : "get"), len, plen));
4426 /* set up 'params' pointer in case this is a set command so that
4427 * the convenience int and bool code can be common to set and get
4429 if (params == NULL) {
4434 if (vi->type == IOVT_VOID)
4436 else if (vi->type == IOVT_BUFFER)
4439 /* all other types are integer sized */
4440 val_size = sizeof(int);
4442 actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
4443 bcmerror = dhdsdio_doiovar(bus, vi, actionid, name, params, plen, arg, len, val_size);
4450 dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex)
4453 uint32 local_hostintmask;
4460 osh = bus->dhd->osh;
4461 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4463 bcmsdh_waitlockfree(NULL);
4466 dhd_os_sdlock(bus->dhd);
4468 if ((bus->dhd->busstate == DHD_BUS_DOWN) || bus->dhd->hang_was_sent) {
4469 /* if Firmware already hangs disbale any interrupt */
4470 bus->dhd->busstate = DHD_BUS_DOWN;
4471 bus->hostintmask = 0;
4472 bcmsdh_intr_disable(bus->sdh);
4477 /* Change our idea of bus state */
4478 bus->dhd->busstate = DHD_BUS_DOWN;
4480 if (KSO_ENAB(bus)) {
4482 /* Enable clock for device interrupts */
4483 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
4485 /* Disable and clear interrupts at the chip level also */
4486 W_SDREG(0, &bus->regs->hostintmask, retries);
4487 local_hostintmask = bus->hostintmask;
4488 bus->hostintmask = 0;
4490 /* Force clocks on backplane to be sure F2 interrupt propagates */
4491 saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
4493 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
4494 (saveclk | SBSDIO_FORCE_HT), &err);
4497 DHD_ERROR(("%s: Failed to force clock for F2: err %d\n",
4498 __FUNCTION__, err));
4501 /* Turn off the bus (F2), free any pending packets */
4502 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
4503 bcmsdh_intr_disable(bus->sdh);
4504 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL);
4506 /* Clear any pending interrupts now that F2 is disabled */
4507 W_SDREG(local_hostintmask, &bus->regs->intstatus, retries);
4510 /* Turn off the backplane clock (only) */
4511 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
4514 /* Clear the data packet queues */
4515 pktq_flush(osh, &bus->txq, TRUE, NULL, 0);
4517 /* Clear any held glomming stuff */
4519 PKTFREE(osh, bus->glomd, FALSE);
4522 PKTFREE(osh, bus->glom, FALSE);
4524 bus->glom = bus->glomd = NULL;
4526 /* Clear rx control and wake any waiters */
4528 dhd_os_ioctl_resp_wake(bus->dhd);
4530 /* Reset some F2 state stuff */
4531 bus->rxskip = FALSE;
4532 bus->tx_seq = bus->rx_seq = 0;
4537 dhd_os_sdunlock(bus->dhd);
4540 #ifdef BCMSDIOH_TXGLOM
4542 dhd_txglom_enable(dhd_pub_t *dhdp, bool enable)
4544 dhd_bus_t *bus = dhdp->bus;
4550 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4554 memset(buf, 0, sizeof(buf));
4555 bcm_mkiovar("bus:rxglom",
4557 4, buf, sizeof(buf));
4558 ret = dhd_wl_ioctl_cmd(dhdp,
4560 sizeof(buf), TRUE, 0);
4562 bus->glom_enable = TRUE;
4565 bus->glom_enable = FALSE;
4568 #endif /* BCMSDIOH_TXGLOM */
4571 dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex)
4573 dhd_bus_t *bus = dhdp->bus;
4576 uint8 ready, enable;
4580 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4587 dhd_os_sdlock(bus->dhd);
4589 /* Make sure backplane clock is on, needed to generate F2 interrupt */
4590 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
4591 if (bus->clkstate != CLK_AVAIL) {
4592 DHD_ERROR(("%s: clock state is wrong. state = %d\n", __FUNCTION__, bus->clkstate));
4598 /* Force clocks on backplane to be sure F2 interrupt propagates */
4599 saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
4601 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
4602 (saveclk | SBSDIO_FORCE_HT), &err);
4605 DHD_ERROR(("%s: Failed to force clock for F2: err %d\n", __FUNCTION__, err));
4610 /* Enable function 2 (frame transfers) */
4611 W_SDREG((SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT),
4612 &bus->regs->tosbmailboxdata, retries);
4613 enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2);
4615 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL);
4617 /* Give the dongle some time to do its thing and set IOR2 */
4618 dhd_timeout_start(&tmo, DHD_WAIT_F2RDY * 1000);
4621 while (ready != enable && !dhd_timeout_expired(&tmo))
4622 ready = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IORDY, NULL);
4624 DHD_ERROR(("%s: enable 0x%02x, ready 0x%02x (waited %uus)\n",
4625 __FUNCTION__, enable, ready, tmo.elapsed));
4628 /* If F2 successfully enabled, set core and enable interrupts */
4629 if (ready == enable) {
4630 /* Make sure we're talking to the core. */
4631 if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0)))
4632 bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0);
4633 ASSERT(bus->regs != NULL);
4635 /* Set up the interrupt mask and enable interrupts */
4636 bus->hostintmask = HOSTINTMASK;
4637 /* corerev 4 could use the newer interrupt logic to detect the frames */
4638 if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 4) &&
4639 (bus->rxint_mode != SDIO_DEVICE_HMB_RXINT)) {
4640 bus->hostintmask &= ~I_HMB_FRAME_IND;
4641 bus->hostintmask |= I_XMTDATA_AVAIL;
4643 W_SDREG(bus->hostintmask, &bus->regs->hostintmask, retries);
4644 #ifdef SDIO_CRC_ERROR_FIX
4645 if (bus->blocksize < 512) {
4646 mesbusyctrl = watermark = bus->blocksize / 4;
4648 #endif /* SDIO_CRC_ERROR_FIX */
4649 if (!((bus->sih->chip == BCM4335_CHIP_ID) ||
4650 (bus->sih->chip == BCM4339_CHIP_ID))) {
4651 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK,
4652 (uint8)watermark, &err);
4654 #ifdef SDIO_CRC_ERROR_FIX
4655 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL,
4656 (uint8)mesbusyctrl|0x80, &err);
4657 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL,
4658 SBSDIO_DEVCTL_EN_F2_BLK_WATERMARK, NULL);
4659 #endif /* SDIO_CRC_ERROR_FIX */
4661 /* Set bus state according to enable result */
4662 dhdp->busstate = DHD_BUS_DATA;
4664 /* bcmsdh_intr_unmask(bus->sdh); */
4666 bus->intdis = FALSE;
4668 DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__));
4669 bcmsdh_intr_enable(bus->sdh);
4671 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
4672 bcmsdh_intr_disable(bus->sdh);
4679 /* Disable F2 again */
4680 enable = SDIO_FUNC_ENABLE_1;
4681 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL);
4684 if (dhdsdio_sr_cap(bus)) {
4685 dhdsdio_sr_init(bus);
4686 /* Masking the chip active interrupt permanantly */
4687 bus->hostintmask &= ~I_CHIPACTIVE;
4688 W_SDREG(bus->hostintmask, &bus->regs->hostintmask, retries);
4689 DHD_INFO(("%s: disable I_CHIPACTIVE in hostintmask[0x%08x]\n",
4690 __FUNCTION__, bus->hostintmask));
4693 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1,
4694 SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err);
4696 /* If we didn't come up, turn off backplane clock */
4697 if (dhdp->busstate != DHD_BUS_DATA)
4698 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
4702 dhd_os_sdunlock(bus->dhd);
4708 dhdsdio_rxfail(dhd_bus_t *bus, bool abort, bool rtx)
4710 bcmsdh_info_t *sdh = bus->sdh;
4711 sdpcmd_regs_t *regs = bus->regs;
4717 DHD_ERROR(("%s: %sterminate frame%s\n", __FUNCTION__,
4718 (abort ? "abort command, " : ""), (rtx ? ", send NAK" : "")));
4720 if (!KSO_ENAB(bus)) {
4721 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
4726 bcmsdh_abort(sdh, SDIO_FUNC_2);
4729 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, SFC_RF_TERM, &err);
4731 DHD_ERROR(("%s: SBSDIO_FUNC1_FRAMECTRL cmd err\n", __FUNCTION__));
4736 /* Wait until the packet has been flushed (device/FIFO stable) */
4737 for (lastrbc = retries = 0xffff; retries > 0; retries--) {
4738 hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCHI, NULL);
4739 lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCLO, &err);
4741 DHD_ERROR(("%s: SBSDIO_FUNC1_RFAMEBCLO cmd err\n", __FUNCTION__));
4745 bus->f1regdata += 2;
4747 if ((hi == 0) && (lo == 0))
4750 if ((hi > (lastrbc >> 8)) && (lo > (lastrbc & 0x00ff))) {
4751 DHD_ERROR(("%s: count growing: last 0x%04x now 0x%04x\n",
4752 __FUNCTION__, lastrbc, ((hi << 8) + lo)));
4754 lastrbc = (hi << 8) + lo;
4758 DHD_ERROR(("%s: count never zeroed: last 0x%04x\n", __FUNCTION__, lastrbc));
4760 DHD_INFO(("%s: flush took %d iterations\n", __FUNCTION__, (0xffff - retries)));
4765 W_SDREG(SMB_NAK, ®s->tosbmailbox, retries);
4767 if (retries <= retry_limit) {
4772 /* Clear partial in any case */
4776 /* If we can't reach the device, signal failure */
4777 if (err || bcmsdh_regfail(sdh))
4778 bus->dhd->busstate = DHD_BUS_DOWN;
4782 dhdsdio_read_control(dhd_bus_t *bus, uint8 *hdr, uint len, uint doff)
4784 bcmsdh_info_t *sdh = bus->sdh;
4789 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4791 /* Control data already received in aligned rxctl */
4792 if ((bus->bus == SPI_BUS) && (!bus->usebufpool))
4796 /* Set rxctl for frame (w/optional alignment) */
4797 bus->rxctl = bus->rxbuf;
4799 bus->rxctl += firstread;
4800 if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN)))
4801 bus->rxctl += (DHD_SDALIGN - pad);
4802 bus->rxctl -= firstread;
4804 ASSERT(bus->rxctl >= bus->rxbuf);
4806 /* Copy the already-read portion over */
4807 bcopy(hdr, bus->rxctl, firstread);
4808 if (len <= firstread)
4811 /* Copy the full data pkt in gSPI case and process ioctl. */
4812 if (bus->bus == SPI_BUS) {
4813 bcopy(hdr, bus->rxctl, len);
4817 /* Raise rdlen to next SDIO block to avoid tail command */
4818 rdlen = len - firstread;
4819 if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
4820 pad = bus->blocksize - (rdlen % bus->blocksize);
4821 if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
4822 ((len + pad) < bus->dhd->maxctl))
4824 } else if (rdlen % DHD_SDALIGN) {
4825 rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
4828 /* Satisfy length-alignment requirements */
4829 if (forcealign && (rdlen & (ALIGNMENT - 1)))
4830 rdlen = ROUNDUP(rdlen, ALIGNMENT);
4832 /* Drop if the read is too big or it exceeds our maximum */
4833 if ((rdlen + firstread) > bus->dhd->maxctl) {
4834 DHD_ERROR(("%s: %d-byte control read exceeds %d-byte buffer\n",
4835 __FUNCTION__, rdlen, bus->dhd->maxctl));
4836 bus->dhd->rx_errors++;
4837 dhdsdio_rxfail(bus, FALSE, FALSE);
4841 if ((len - doff) > bus->dhd->maxctl) {
4842 DHD_ERROR(("%s: %d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n",
4843 __FUNCTION__, len, (len - doff), bus->dhd->maxctl));
4844 bus->dhd->rx_errors++; bus->rx_toolong++;
4845 dhdsdio_rxfail(bus, FALSE, FALSE);
4850 /* Read remainder of frame body into the rxctl buffer */
4851 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
4852 (bus->rxctl + firstread), rdlen, NULL, NULL, NULL);
4854 ASSERT(sdret != BCME_PENDING);
4856 /* Control frame failures need retransmission */
4858 DHD_ERROR(("%s: read %d control bytes failed: %d\n", __FUNCTION__, rdlen, sdret));
4859 bus->rxc_errors++; /* dhd.rx_ctlerrs is higher level */
4860 dhdsdio_rxfail(bus, TRUE, TRUE);
4867 if (DHD_BYTES_ON() && DHD_CTL_ON()) {
4868 prhex("RxCtrl", bus->rxctl, len);
4872 /* Point to valid data and indicate its length */
4874 bus->rxlen = len - doff;
4877 /* Awake any waiters */
4878 dhd_os_ioctl_resp_wake(bus->dhd);
4881 dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf, uint reorder_info_len,
4882 void **pkt, uint32 *pkt_count);
4885 dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq)
4887 uint16 dlen, totlen;
4888 uint8 *dptr, num = 0;
4890 uint16 sublen, check;
4891 void *pfirst, *plast, *pnext;
4892 void * list_tail[DHD_MAX_IFS] = { NULL };
4893 void * list_head[DHD_MAX_IFS] = { NULL };
4895 osl_t *osh = bus->dhd->osh;
4898 uint8 chan, seq, doff, sfdoff;
4900 uchar reorder_info_buf[WLHOST_REORDERDATA_TOTLEN];
4901 uint reorder_info_len;
4904 bool usechain = bus->use_rxchain;
4906 /* If packets, issue read(s) and send up packet chain */
4907 /* Return sequence numbers consumed? */
4909 DHD_TRACE(("dhdsdio_rxglom: start: glomd %p glom %p\n", bus->glomd, bus->glom));
4911 /* If there's a descriptor, generate the packet chain */
4913 dhd_os_sdlock_rxq(bus->dhd);
4915 pfirst = plast = pnext = NULL;
4916 dlen = (uint16)PKTLEN(osh, bus->glomd);
4917 dptr = PKTDATA(osh, bus->glomd);
4918 if (!dlen || (dlen & 1)) {
4919 DHD_ERROR(("%s: bad glomd len (%d), ignore descriptor\n",
4920 __FUNCTION__, dlen));
4924 for (totlen = num = 0; dlen; num++) {
4925 /* Get (and move past) next length */
4926 sublen = ltoh16_ua(dptr);
4927 dlen -= sizeof(uint16);
4928 dptr += sizeof(uint16);
4929 if ((sublen < SDPCM_HDRLEN_RX) ||
4930 ((num == 0) && (sublen < (2 * SDPCM_HDRLEN_RX)))) {
4931 DHD_ERROR(("%s: descriptor len %d bad: %d\n",
4932 __FUNCTION__, num, sublen));
4936 if (sublen % DHD_SDALIGN) {
4937 DHD_ERROR(("%s: sublen %d not a multiple of %d\n",
4938 __FUNCTION__, sublen, DHD_SDALIGN));
4943 /* For last frame, adjust read len so total is a block multiple */
4945 sublen += (ROUNDUP(totlen, bus->blocksize) - totlen);
4946 totlen = ROUNDUP(totlen, bus->blocksize);
4949 /* Allocate/chain packet for next subframe */
4950 if ((pnext = PKTGET(osh, sublen + DHD_SDALIGN, FALSE)) == NULL) {
4951 DHD_ERROR(("%s: PKTGET failed, num %d len %d\n",
4952 __FUNCTION__, num, sublen));
4955 ASSERT(!PKTLINK(pnext));
4958 pfirst = plast = pnext;
4961 PKTSETNEXT(osh, plast, pnext);
4965 /* Adhere to start alignment requirements */
4966 PKTALIGN(osh, pnext, sublen, DHD_SDALIGN);
4969 /* If all allocations succeeded, save packet chain in bus structure */
4971 DHD_GLOM(("%s: allocated %d-byte packet chain for %d subframes\n",
4972 __FUNCTION__, totlen, num));
4973 if (DHD_GLOM_ON() && bus->nextlen) {
4974 if (totlen != bus->nextlen) {
4975 DHD_GLOM(("%s: glomdesc mismatch: nextlen %d glomdesc %d "
4976 "rxseq %d\n", __FUNCTION__, bus->nextlen,
4981 pfirst = pnext = NULL;
4984 PKTFREE(osh, pfirst, FALSE);
4989 /* Done with descriptor packet */
4990 PKTFREE(osh, bus->glomd, FALSE);
4994 dhd_os_sdunlock_rxq(bus->dhd);
4997 /* Ok -- either we just generated a packet chain, or had one from before */
4999 if (DHD_GLOM_ON()) {
5000 DHD_GLOM(("%s: attempt superframe read, packet chain:\n", __FUNCTION__));
5001 for (pnext = bus->glom; pnext; pnext = PKTNEXT(osh, pnext)) {
5002 DHD_GLOM((" %p: %p len 0x%04x (%d)\n",
5003 pnext, (uint8*)PKTDATA(osh, pnext),
5004 PKTLEN(osh, pnext), PKTLEN(osh, pnext)));
5009 dlen = (uint16)pkttotlen(osh, pfirst);
5011 /* Do an SDIO read for the superframe. Configurable iovar to
5012 * read directly into the chained packet, or allocate a large
5013 * packet and and copy into the chain.
5016 errcode = dhd_bcmsdh_recv_buf(bus,
5017 bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2,
5018 F2SYNC, (uint8*)PKTDATA(osh, pfirst),
5019 dlen, pfirst, NULL, NULL);
5020 } else if (bus->dataptr) {
5021 errcode = dhd_bcmsdh_recv_buf(bus,
5022 bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2,
5023 F2SYNC, bus->dataptr,
5024 dlen, NULL, NULL, NULL);
5025 sublen = (uint16)pktfrombuf(osh, pfirst, 0, dlen, bus->dataptr);
5026 if (sublen != dlen) {
5027 DHD_ERROR(("%s: FAILED TO COPY, dlen %d sublen %d\n",
5028 __FUNCTION__, dlen, sublen));
5033 DHD_ERROR(("COULDN'T ALLOC %d-BYTE GLOM, FORCE FAILURE\n", dlen));
5037 ASSERT(errcode != BCME_PENDING);
5039 /* On failure, kill the superframe, allow a couple retries */
5041 DHD_ERROR(("%s: glom read of %d bytes failed: %d\n",
5042 __FUNCTION__, dlen, errcode));
5043 bus->dhd->rx_errors++;
5045 if (bus->glomerr++ < 3) {
5046 dhdsdio_rxfail(bus, TRUE, TRUE);
5049 dhdsdio_rxfail(bus, TRUE, FALSE);
5050 dhd_os_sdlock_rxq(bus->dhd);
5051 PKTFREE(osh, bus->glom, FALSE);
5052 dhd_os_sdunlock_rxq(bus->dhd);
5060 if (DHD_GLOM_ON()) {
5061 prhex("SUPERFRAME", PKTDATA(osh, pfirst),
5062 MIN(PKTLEN(osh, pfirst), 48));
5067 /* Validate the superframe header */
5068 dptr = (uint8 *)PKTDATA(osh, pfirst);
5069 sublen = ltoh16_ua(dptr);
5070 check = ltoh16_ua(dptr + sizeof(uint16));
5072 chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
5073 seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
5074 bus->nextlen = dptr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
5075 if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
5076 DHD_INFO(("%s: got frame w/nextlen too large (%d) seq %d\n",
5077 __FUNCTION__, bus->nextlen, seq));
5080 doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
5081 txmax = SDPCM_WINDOW_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
5084 if ((uint16)~(sublen^check)) {
5085 DHD_ERROR(("%s (superframe): HW hdr error: len/check 0x%04x/0x%04x\n",
5086 __FUNCTION__, sublen, check));
5088 } else if (ROUNDUP(sublen, bus->blocksize) != dlen) {
5089 DHD_ERROR(("%s (superframe): len 0x%04x, rounded 0x%04x, expect 0x%04x\n",
5090 __FUNCTION__, sublen, ROUNDUP(sublen, bus->blocksize), dlen));
5092 } else if (SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]) != SDPCM_GLOM_CHANNEL) {
5093 DHD_ERROR(("%s (superframe): bad channel %d\n", __FUNCTION__,
5094 SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN])));
5096 } else if (SDPCM_GLOMDESC(&dptr[SDPCM_FRAMETAG_LEN])) {
5097 DHD_ERROR(("%s (superframe): got second descriptor?\n", __FUNCTION__));
5099 } else if ((doff < SDPCM_HDRLEN_RX) ||
5100 (doff > (PKTLEN(osh, pfirst) - SDPCM_HDRLEN_RX))) {
5101 DHD_ERROR(("%s (superframe): Bad data offset %d: HW %d pkt %d min %d\n",
5102 __FUNCTION__, doff, sublen, PKTLEN(osh, pfirst),
5107 /* Check sequence number of superframe SW header */
5109 DHD_INFO(("%s: (superframe) rx_seq %d, expected %d\n",
5110 __FUNCTION__, seq, rxseq));
5115 /* Check window for sanity */
5116 if ((uint8)(txmax - bus->tx_seq) > 0x40) {
5117 DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
5118 __FUNCTION__, txmax, bus->tx_seq));
5119 txmax = bus->tx_max;
5121 bus->tx_max = txmax;
5123 /* Remove superframe header, remember offset */
5124 PKTPULL(osh, pfirst, doff);
5127 /* Validate all the subframe headers */
5128 for (num = 0, pnext = pfirst; pnext && !errcode;
5129 num++, pnext = PKTNEXT(osh, pnext)) {
5130 dptr = (uint8 *)PKTDATA(osh, pnext);
5131 dlen = (uint16)PKTLEN(osh, pnext);
5132 sublen = ltoh16_ua(dptr);
5133 check = ltoh16_ua(dptr + sizeof(uint16));
5134 chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
5135 doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
5137 if (DHD_GLOM_ON()) {
5138 prhex("subframe", dptr, 32);
5142 if ((uint16)~(sublen^check)) {
5143 DHD_ERROR(("%s (subframe %d): HW hdr error: "
5144 "len/check 0x%04x/0x%04x\n",
5145 __FUNCTION__, num, sublen, check));
5147 } else if ((sublen > dlen) || (sublen < SDPCM_HDRLEN_RX)) {
5148 DHD_ERROR(("%s (subframe %d): length mismatch: "
5149 "len 0x%04x, expect 0x%04x\n",
5150 __FUNCTION__, num, sublen, dlen));
5152 } else if ((chan != SDPCM_DATA_CHANNEL) &&
5153 (chan != SDPCM_EVENT_CHANNEL)) {
5154 DHD_ERROR(("%s (subframe %d): bad channel %d\n",
5155 __FUNCTION__, num, chan));
5157 } else if ((doff < SDPCM_HDRLEN_RX) || (doff > sublen)) {
5158 DHD_ERROR(("%s (subframe %d): Bad data offset %d: HW %d min %d\n",
5159 __FUNCTION__, num, doff, sublen, SDPCM_HDRLEN_RX));
5165 /* Terminate frame on error, request a couple retries */
5166 if (bus->glomerr++ < 3) {
5167 /* Restore superframe header space */
5168 PKTPUSH(osh, pfirst, sfdoff);
5169 dhdsdio_rxfail(bus, TRUE, TRUE);
5172 dhdsdio_rxfail(bus, TRUE, FALSE);
5173 dhd_os_sdlock_rxq(bus->dhd);
5174 PKTFREE(osh, bus->glom, FALSE);
5175 dhd_os_sdunlock_rxq(bus->dhd);
5183 /* Basic SD framing looks ok - process each packet (header) */
5187 dhd_os_sdlock_rxq(bus->dhd);
5188 for (num = 0; pfirst; rxseq++, pfirst = pnext) {
5189 pnext = PKTNEXT(osh, pfirst);
5190 PKTSETNEXT(osh, pfirst, NULL);
5192 dptr = (uint8 *)PKTDATA(osh, pfirst);
5193 sublen = ltoh16_ua(dptr);
5194 chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
5195 seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
5196 doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
5198 DHD_GLOM(("%s: Get subframe %d, %p(%p/%d), sublen %d chan %d seq %d\n",
5199 __FUNCTION__, num, pfirst, PKTDATA(osh, pfirst),
5200 PKTLEN(osh, pfirst), sublen, chan, seq));
5202 ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL));
5205 DHD_GLOM(("%s: rx_seq %d, expected %d\n",
5206 __FUNCTION__, seq, rxseq));
5212 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
5213 prhex("Rx Subframe Data", dptr, dlen);
5217 PKTSETLEN(osh, pfirst, sublen);
5218 PKTPULL(osh, pfirst, doff);
5220 reorder_info_len = sizeof(reorder_info_buf);
5222 if (PKTLEN(osh, pfirst) == 0) {
5223 PKTFREE(bus->dhd->osh, pfirst, FALSE);
5225 } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pfirst, reorder_info_buf,
5226 &reorder_info_len) != 0) {
5227 DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__));
5228 bus->dhd->rx_errors++;
5229 PKTFREE(osh, pfirst, FALSE);
5232 if (reorder_info_len) {
5233 uint32 free_buf_count;
5237 /* Reordering info from the firmware */
5238 dhd_process_pkt_reorder_info(bus->dhd, reorder_info_buf,
5239 reorder_info_len, &ppfirst, &free_buf_count);
5241 if (free_buf_count == 0) {
5247 /* go to the end of the chain and attach the pnext there */
5249 while (PKTNEXT(osh, temp) != NULL) {
5250 temp = PKTNEXT(osh, temp);
5253 if (list_tail[ifidx] == NULL)
5254 list_head[ifidx] = ppfirst;
5256 PKTSETNEXT(osh, list_tail[ifidx], ppfirst);
5257 list_tail[ifidx] = pfirst;
5260 num += (uint8)free_buf_count;
5263 /* this packet will go up, link back into chain and count it */
5265 if (list_tail[ifidx] == NULL) {
5266 list_head[ifidx] = list_tail[ifidx] = pfirst;
5269 PKTSETNEXT(osh, list_tail[ifidx], pfirst);
5270 list_tail[ifidx] = pfirst;
5275 if (DHD_GLOM_ON()) {
5276 DHD_GLOM(("%s subframe %d to stack, %p(%p/%d) nxt/lnk %p/%p\n",
5277 __FUNCTION__, num, pfirst,
5278 PKTDATA(osh, pfirst), PKTLEN(osh, pfirst),
5279 PKTNEXT(osh, pfirst), PKTLINK(pfirst)));
5280 prhex("", (uint8 *)PKTDATA(osh, pfirst),
5281 MIN(PKTLEN(osh, pfirst), 32));
5283 #endif /* DHD_DEBUG */
5285 dhd_os_sdunlock_rxq(bus->dhd);
5287 for (idx = 0; idx < DHD_MAX_IFS; idx++) {
5288 if (list_head[idx]) {
5291 temp = list_head[idx];
5293 temp = PKTNEXT(osh, temp);
5297 dhd_os_sdunlock(bus->dhd);
5298 dhd_rx_frame(bus->dhd, idx, list_head[idx], cnt, 0);
5299 dhd_os_sdlock(bus->dhd);
5303 bus->rxglomframes++;
5304 bus->rxglompkts += num;
5310 /* Return TRUE if there may be more frames to read */
5312 dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished)
5314 osl_t *osh = bus->dhd->osh;
5315 bcmsdh_info_t *sdh = bus->sdh;
5317 uint16 len, check; /* Extracted hardware header fields */
5318 uint8 chan, seq, doff; /* Extracted software header fields */
5319 uint8 fcbits; /* Extracted fcbits from software header */
5322 void *pkt; /* Packet for event or data frames */
5323 uint16 pad; /* Number of pad bytes to read */
5324 uint16 rdlen; /* Total number of bytes to read */
5325 uint8 rxseq; /* Next sequence number to expect */
5326 uint rxleft = 0; /* Remaining number of frames allowed */
5327 int sdret; /* Return code from bcmsdh calls */
5328 uint8 txmax; /* Maximum tx sequence offered */
5329 bool len_consistent; /* Result of comparing readahead len and len from hw-hdr */
5332 uint rxcount = 0; /* Total frames read */
5333 uchar reorder_info_buf[WLHOST_REORDERDATA_TOTLEN];
5334 uint reorder_info_len;
5337 #if defined(DHD_DEBUG) || defined(SDTEST)
5338 bool sdtest = FALSE; /* To limit message spew from test mode */
5341 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5343 bus->readframes = TRUE;
5345 if (!KSO_ENAB(bus)) {
5346 DHD_ERROR(("%s: KSO off\n", __FUNCTION__));
5347 bus->readframes = FALSE;
5354 /* Allow pktgen to override maxframes */
5355 if (bus->pktgen_count && (bus->pktgen_mode == DHD_PKTGEN_RECV)) {
5356 maxframes = bus->pktgen_count;
5361 /* Not finished unless we encounter no more frames indication */
5365 for (rxseq = bus->rx_seq, rxleft = maxframes;
5366 !bus->rxskip && rxleft && bus->dhd->busstate != DHD_BUS_DOWN;
5367 rxseq++, rxleft--) {
5370 /* tx more to improve rx performance */
5371 if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL)) {
5372 dhdsdio_sendpendctl(bus);
5373 } else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate &&
5374 pktq_mlen(&bus->txq, ~bus->flowcontrol) && DATAOK(bus)) {
5375 dhdsdio_sendfromq(bus, dhd_txbound);
5377 #endif /* DHDTHREAD */
5379 /* Handle glomming separately */
5380 if (bus->glom || bus->glomd) {
5382 DHD_GLOM(("%s: calling rxglom: glomd %p, glom %p\n",
5383 __FUNCTION__, bus->glomd, bus->glom));
5384 cnt = dhdsdio_rxglom(bus, rxseq);
5385 DHD_GLOM(("%s: rxglom returned %d\n", __FUNCTION__, cnt));
5387 rxleft = (rxleft > cnt) ? (rxleft - cnt) : 1;
5391 /* Try doing single read if we can */
5392 if (dhd_readahead && bus->nextlen) {
5393 uint16 nextlen = bus->nextlen;
5396 if (bus->bus == SPI_BUS) {
5397 rdlen = len = nextlen;
5400 rdlen = len = nextlen << 4;
5402 /* Pad read to blocksize for efficiency */
5403 if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
5404 pad = bus->blocksize - (rdlen % bus->blocksize);
5405 if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
5406 ((rdlen + pad + firstread) < MAX_RX_DATASZ))
5408 } else if (rdlen % DHD_SDALIGN) {
5409 rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
5413 /* We use bus->rxctl buffer in WinXP for initial control pkt receives.
5414 * Later we use buffer-poll for data as well as control packets.
5415 * This is required because dhd receives full frame in gSPI unlike SDIO.
5416 * After the frame is received we have to distinguish whether it is data
5417 * or non-data frame.
5419 /* Allocate a packet buffer */
5420 dhd_os_sdlock_rxq(bus->dhd);
5421 if (!(pkt = PKTGET(osh, rdlen + DHD_SDALIGN, FALSE))) {
5422 if (bus->bus == SPI_BUS) {
5423 bus->usebufpool = FALSE;
5424 bus->rxctl = bus->rxbuf;
5426 bus->rxctl += firstread;
5427 if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN)))
5428 bus->rxctl += (DHD_SDALIGN - pad);
5429 bus->rxctl -= firstread;
5431 ASSERT(bus->rxctl >= bus->rxbuf);
5433 /* Read the entire frame */
5434 sdret = dhd_bcmsdh_recv_buf(bus,
5435 bcmsdh_cur_sbwad(sdh),
5437 F2SYNC, rxbuf, rdlen,
5440 ASSERT(sdret != BCME_PENDING);
5443 /* Control frame failures need retransmission */
5445 DHD_ERROR(("%s: read %d control bytes failed: %d\n",
5446 __FUNCTION__, rdlen, sdret));
5447 /* dhd.rx_ctlerrs is higher level */
5449 dhd_os_sdunlock_rxq(bus->dhd);
5450 dhdsdio_rxfail(bus, TRUE,
5451 (bus->bus == SPI_BUS) ? FALSE : TRUE);
5455 /* Give up on data, request rtx of events */
5456 DHD_ERROR(("%s (nextlen): PKTGET failed: len %d rdlen %d "
5457 "expected rxseq %d\n",
5458 __FUNCTION__, len, rdlen, rxseq));
5459 /* Just go try again w/normal header read */
5460 dhd_os_sdunlock_rxq(bus->dhd);
5464 if (bus->bus == SPI_BUS)
5465 bus->usebufpool = TRUE;
5467 ASSERT(!PKTLINK(pkt));
5468 PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN);
5469 rxbuf = (uint8 *)PKTDATA(osh, pkt);
5470 /* Read the entire frame */
5471 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh),
5473 F2SYNC, rxbuf, rdlen,
5476 ASSERT(sdret != BCME_PENDING);
5479 DHD_ERROR(("%s (nextlen): read %d bytes failed: %d\n",
5480 __FUNCTION__, rdlen, sdret));
5481 PKTFREE(bus->dhd->osh, pkt, FALSE);
5482 bus->dhd->rx_errors++;
5483 dhd_os_sdunlock_rxq(bus->dhd);
5484 /* Force retry w/normal header read. Don't attempt NAK for
5487 dhdsdio_rxfail(bus, TRUE,
5488 (bus->bus == SPI_BUS) ? FALSE : TRUE);
5492 dhd_os_sdunlock_rxq(bus->dhd);
5494 /* Now check the header */
5495 bcopy(rxbuf, bus->rxhdr, SDPCM_HDRLEN_RX);
5497 /* Extract hardware header fields */
5498 len = ltoh16_ua(bus->rxhdr);
5499 check = ltoh16_ua(bus->rxhdr + sizeof(uint16));
5501 /* All zeros means readahead info was bad */
5503 DHD_INFO(("%s (nextlen): read zeros in HW header???\n",
5505 dhd_os_sdlock_rxq(bus->dhd);
5507 dhd_os_sdunlock_rxq(bus->dhd);
5508 GSPI_PR55150_BAILOUT;
5512 /* Validate check bytes */
5513 if ((uint16)~(len^check)) {
5514 DHD_ERROR(("%s (nextlen): HW hdr error: nextlen/len/check"
5515 " 0x%04x/0x%04x/0x%04x\n", __FUNCTION__, nextlen,
5517 dhd_os_sdlock_rxq(bus->dhd);
5519 dhd_os_sdunlock_rxq(bus->dhd);
5521 dhdsdio_rxfail(bus, FALSE, FALSE);
5522 GSPI_PR55150_BAILOUT;
5526 /* Validate frame length */
5527 if (len < SDPCM_HDRLEN_RX) {
5528 DHD_ERROR(("%s (nextlen): HW hdr length invalid: %d\n",
5529 __FUNCTION__, len));
5530 dhd_os_sdlock_rxq(bus->dhd);
5532 dhd_os_sdunlock_rxq(bus->dhd);
5533 GSPI_PR55150_BAILOUT;
5537 /* Check for consistency with readahead info */
5538 len_consistent = (nextlen != (ROUNDUP(len, 16) >> 4));
5539 if (len_consistent) {
5540 /* Mismatch, force retry w/normal header (may be >4K) */
5541 DHD_ERROR(("%s (nextlen): mismatch, nextlen %d len %d rnd %d; "
5542 "expected rxseq %d\n",
5543 __FUNCTION__, nextlen, len, ROUNDUP(len, 16), rxseq));
5544 dhd_os_sdlock_rxq(bus->dhd);
5546 dhd_os_sdunlock_rxq(bus->dhd);
5547 dhdsdio_rxfail(bus, TRUE, (bus->bus == SPI_BUS) ? FALSE : TRUE);
5548 GSPI_PR55150_BAILOUT;
5553 /* Extract software header fields */
5554 chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5555 seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5556 doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5557 txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5560 bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
5561 if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
5562 DHD_INFO(("%s (nextlen): got frame w/nextlen too large"
5563 " (%d), seq %d\n", __FUNCTION__, bus->nextlen,
5568 bus->dhd->rx_readahead_cnt ++;
5569 /* Handle Flow Control */
5570 fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5573 if (~bus->flowcontrol & fcbits) {
5577 if (bus->flowcontrol & ~fcbits) {
5584 bus->flowcontrol = fcbits;
5587 /* Check and update sequence number */
5589 DHD_INFO(("%s (nextlen): rx_seq %d, expected %d\n",
5590 __FUNCTION__, seq, rxseq));
5595 /* Check window for sanity */
5596 if ((uint8)(txmax - bus->tx_seq) > 0x40) {
5597 DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
5598 __FUNCTION__, txmax, bus->tx_seq));
5599 txmax = bus->tx_max;
5601 bus->tx_max = txmax;
5604 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
5605 prhex("Rx Data", rxbuf, len);
5606 } else if (DHD_HDRS_ON()) {
5607 prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN_RX);
5611 if (chan == SDPCM_CONTROL_CHANNEL) {
5612 if (bus->bus == SPI_BUS) {
5613 dhdsdio_read_control(bus, rxbuf, len, doff);
5614 if (bus->usebufpool) {
5615 dhd_os_sdlock_rxq(bus->dhd);
5616 PKTFREE(bus->dhd->osh, pkt, FALSE);
5617 dhd_os_sdunlock_rxq(bus->dhd);
5621 DHD_ERROR(("%s (nextlen): readahead on control"
5622 " packet %d?\n", __FUNCTION__, seq));
5623 /* Force retry w/normal header read */
5625 dhdsdio_rxfail(bus, FALSE, TRUE);
5626 dhd_os_sdlock_rxq(bus->dhd);
5628 dhd_os_sdunlock_rxq(bus->dhd);
5633 if ((bus->bus == SPI_BUS) && !bus->usebufpool) {
5634 DHD_ERROR(("Received %d bytes on %d channel. Running out of "
5635 "rx pktbuf's or not yet malloced.\n", len, chan));
5639 /* Validate data offset */
5640 if ((doff < SDPCM_HDRLEN_RX) || (doff > len)) {
5641 DHD_ERROR(("%s (nextlen): bad data offset %d: HW len %d min %d\n",
5642 __FUNCTION__, doff, len, SDPCM_HDRLEN_RX));
5643 dhd_os_sdlock_rxq(bus->dhd);
5645 dhd_os_sdunlock_rxq(bus->dhd);
5647 dhdsdio_rxfail(bus, FALSE, FALSE);
5651 /* All done with this one -- now deliver the packet */
5654 /* gSPI frames should not be handled in fractions */
5655 if (bus->bus == SPI_BUS) {
5659 /* Read frame header (hardware and software) */
5660 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
5661 bus->rxhdr, firstread, NULL, NULL, NULL);
5663 ASSERT(sdret != BCME_PENDING);
5666 DHD_ERROR(("%s: RXHEADER FAILED: %d\n", __FUNCTION__, sdret));
5668 dhdsdio_rxfail(bus, TRUE, TRUE);
5673 if (DHD_BYTES_ON() || DHD_HDRS_ON()) {
5674 prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN_RX);
5678 /* Extract hardware header fields */
5679 len = ltoh16_ua(bus->rxhdr);
5680 check = ltoh16_ua(bus->rxhdr + sizeof(uint16));
5682 /* All zeros means no more frames */
5688 /* Validate check bytes */
5689 if ((uint16)~(len^check)) {
5690 DHD_ERROR(("%s: HW hdr error: len/check 0x%04x/0x%04x\n",
5691 __FUNCTION__, len, check));
5693 dhdsdio_rxfail(bus, FALSE, FALSE);
5697 /* Validate frame length */
5698 if (len < SDPCM_HDRLEN_RX) {
5699 DHD_ERROR(("%s: HW hdr length invalid: %d\n", __FUNCTION__, len));
5703 /* Extract software header fields */
5704 chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5705 seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5706 doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5707 txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5709 /* Validate data offset */
5710 if ((doff < SDPCM_HDRLEN_RX) || (doff > len)) {
5711 DHD_ERROR(("%s: Bad data offset %d: HW len %d, min %d seq %d\n",
5712 __FUNCTION__, doff, len, SDPCM_HDRLEN_RX, seq));
5715 dhdsdio_rxfail(bus, FALSE, FALSE);
5719 /* Save the readahead length if there is one */
5720 bus->nextlen = bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
5721 if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
5722 DHD_INFO(("%s (nextlen): got frame w/nextlen too large (%d), seq %d\n",
5723 __FUNCTION__, bus->nextlen, seq));
5727 /* Handle Flow Control */
5728 fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5731 if (~bus->flowcontrol & fcbits) {
5735 if (bus->flowcontrol & ~fcbits) {
5742 bus->flowcontrol = fcbits;
5745 /* Check and update sequence number */
5747 DHD_INFO(("%s: rx_seq %d, expected %d\n", __FUNCTION__, seq, rxseq));
5752 /* Check window for sanity */
5753 if ((uint8)(txmax - bus->tx_seq) > 0x40) {
5754 DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
5755 __FUNCTION__, txmax, bus->tx_seq));
5756 txmax = bus->tx_max;
5758 bus->tx_max = txmax;
5760 /* Call a separate function for control frames */
5761 if (chan == SDPCM_CONTROL_CHANNEL) {
5762 dhdsdio_read_control(bus, bus->rxhdr, len, doff);
5766 ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL) ||
5767 (chan == SDPCM_TEST_CHANNEL) || (chan == SDPCM_GLOM_CHANNEL));
5769 /* Length to read */
5770 rdlen = (len > firstread) ? (len - firstread) : 0;
5772 /* May pad read to blocksize for efficiency */
5773 if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
5774 pad = bus->blocksize - (rdlen % bus->blocksize);
5775 if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
5776 ((rdlen + pad + firstread) < MAX_RX_DATASZ))
5778 } else if (rdlen % DHD_SDALIGN) {
5779 rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
5782 /* Satisfy length-alignment requirements */
5783 if (forcealign && (rdlen & (ALIGNMENT - 1)))
5784 rdlen = ROUNDUP(rdlen, ALIGNMENT);
5786 if ((rdlen + firstread) > MAX_RX_DATASZ) {
5787 /* Too long -- skip this frame */
5788 DHD_ERROR(("%s: too long: len %d rdlen %d\n", __FUNCTION__, len, rdlen));
5789 bus->dhd->rx_errors++; bus->rx_toolong++;
5790 dhdsdio_rxfail(bus, FALSE, FALSE);
5794 dhd_os_sdlock_rxq(bus->dhd);
5795 if (!(pkt = PKTGET(osh, (rdlen + firstread + DHD_SDALIGN), FALSE))) {
5796 /* Give up on data, request rtx of events */
5797 DHD_ERROR(("%s: PKTGET failed: rdlen %d chan %d\n",
5798 __FUNCTION__, rdlen, chan));
5799 bus->dhd->rx_dropped++;
5800 dhd_os_sdunlock_rxq(bus->dhd);
5801 dhdsdio_rxfail(bus, FALSE, RETRYCHAN(chan));
5804 dhd_os_sdunlock_rxq(bus->dhd);
5806 ASSERT(!PKTLINK(pkt));
5808 /* Leave room for what we already read, and align remainder */
5809 ASSERT(firstread < (PKTLEN(osh, pkt)));
5810 PKTPULL(osh, pkt, firstread);
5811 PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN);
5813 /* Read the remaining frame data */
5814 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
5815 ((uint8 *)PKTDATA(osh, pkt)), rdlen, pkt, NULL, NULL);
5817 ASSERT(sdret != BCME_PENDING);
5820 DHD_ERROR(("%s: read %d %s bytes failed: %d\n", __FUNCTION__, rdlen,
5821 ((chan == SDPCM_EVENT_CHANNEL) ? "event" :
5822 ((chan == SDPCM_DATA_CHANNEL) ? "data" : "test")), sdret));
5823 dhd_os_sdlock_rxq(bus->dhd);
5824 PKTFREE(bus->dhd->osh, pkt, FALSE);
5825 dhd_os_sdunlock_rxq(bus->dhd);
5826 bus->dhd->rx_errors++;
5827 dhdsdio_rxfail(bus, TRUE, RETRYCHAN(chan));
5831 /* Copy the already-read portion */
5832 PKTPUSH(osh, pkt, firstread);
5833 bcopy(bus->rxhdr, PKTDATA(osh, pkt), firstread);
5836 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
5837 prhex("Rx Data", PKTDATA(osh, pkt), len);
5842 /* Save superframe descriptor and allocate packet frame */
5843 if (chan == SDPCM_GLOM_CHANNEL) {
5844 if (SDPCM_GLOMDESC(&bus->rxhdr[SDPCM_FRAMETAG_LEN])) {
5845 DHD_GLOM(("%s: got glom descriptor, %d bytes:\n",
5846 __FUNCTION__, len));
5848 if (DHD_GLOM_ON()) {
5849 prhex("Glom Data", PKTDATA(osh, pkt), len);
5852 PKTSETLEN(osh, pkt, len);
5853 ASSERT(doff == SDPCM_HDRLEN_RX);
5854 PKTPULL(osh, pkt, SDPCM_HDRLEN_RX);
5857 DHD_ERROR(("%s: glom superframe w/o descriptor!\n", __FUNCTION__));
5858 dhdsdio_rxfail(bus, FALSE, FALSE);
5863 /* Fill in packet len and prio, deliver upward */
5864 PKTSETLEN(osh, pkt, len);
5865 PKTPULL(osh, pkt, doff);
5868 /* Test channel packets are processed separately */
5869 if (chan == SDPCM_TEST_CHANNEL) {
5870 dhdsdio_testrcv(bus, pkt, seq);
5875 if (PKTLEN(osh, pkt) == 0) {
5876 dhd_os_sdlock_rxq(bus->dhd);
5877 PKTFREE(bus->dhd->osh, pkt, FALSE);
5878 dhd_os_sdunlock_rxq(bus->dhd);
5880 } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pkt, reorder_info_buf,
5881 &reorder_info_len) != 0) {
5882 DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__));
5883 dhd_os_sdlock_rxq(bus->dhd);
5884 PKTFREE(bus->dhd->osh, pkt, FALSE);
5885 dhd_os_sdunlock_rxq(bus->dhd);
5886 bus->dhd->rx_errors++;
5889 if (reorder_info_len) {
5890 /* Reordering info from the firmware */
5891 dhd_process_pkt_reorder_info(bus->dhd, reorder_info_buf, reorder_info_len,
5899 /* Unlock during rx call */
5900 dhd_os_sdunlock(bus->dhd);
5901 dhd_rx_frame(bus->dhd, ifidx, pkt, pkt_count, chan);
5902 dhd_os_sdlock(bus->dhd);
5904 rxcount = maxframes - rxleft;
5906 /* Message if we hit the limit */
5907 if (!rxleft && !sdtest)
5908 DHD_DATA(("%s: hit rx limit of %d frames\n", __FUNCTION__, maxframes));
5910 #endif /* DHD_DEBUG */
5911 DHD_DATA(("%s: processed %d frames\n", __FUNCTION__, rxcount));
5912 /* Back off rxseq if awaiting rtx, update rx_seq */
5915 bus->rx_seq = rxseq;
5917 if (bus->reqbussleep)
5919 dhdsdio_bussleep(bus, TRUE);
5920 bus->reqbussleep = FALSE;
5922 bus->readframes = FALSE;
5928 dhdsdio_hostmail(dhd_bus_t *bus)
5930 sdpcmd_regs_t *regs = bus->regs;
5931 uint32 intstatus = 0;
5936 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5938 /* Read mailbox data and ack that we did so */
5939 R_SDREG(hmb_data, ®s->tohostmailboxdata, retries);
5940 if (retries <= retry_limit)
5941 W_SDREG(SMB_INT_ACK, ®s->tosbmailbox, retries);
5942 bus->f1regdata += 2;
5944 /* Dongle recomposed rx frames, accept them again */
5945 if (hmb_data & HMB_DATA_NAKHANDLED) {
5946 DHD_INFO(("Dongle reports NAK handled, expect rtx of %d\n", bus->rx_seq));
5948 DHD_ERROR(("%s: unexpected NAKHANDLED!\n", __FUNCTION__));
5950 bus->rxskip = FALSE;
5951 intstatus |= FRAME_AVAIL_MASK(bus);
5955 * DEVREADY does not occur with gSPI.
5957 if (hmb_data & (HMB_DATA_DEVREADY | HMB_DATA_FWREADY)) {
5958 bus->sdpcm_ver = (hmb_data & HMB_DATA_VERSION_MASK) >> HMB_DATA_VERSION_SHIFT;
5959 if (bus->sdpcm_ver != SDPCM_PROT_VERSION)
5960 DHD_ERROR(("Version mismatch, dongle reports %d, expecting %d\n",
5961 bus->sdpcm_ver, SDPCM_PROT_VERSION));
5963 DHD_INFO(("Dongle ready, protocol version %d\n", bus->sdpcm_ver));
5964 /* make sure for the SDIO_DEVICE_RXDATAINT_MODE_1 corecontrol is proper */
5965 if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev >= 4) &&
5966 (bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_1)) {
5969 val = R_REG(bus->dhd->osh, &bus->regs->corecontrol);
5970 val &= ~CC_XMTDATAAVAIL_MODE;
5971 val |= CC_XMTDATAAVAIL_CTRL;
5972 W_REG(bus->dhd->osh, &bus->regs->corecontrol, val);
5974 val = R_REG(bus->dhd->osh, &bus->regs->corecontrol);
5978 /* Retrieve console state address now that firmware should have updated it */
5980 sdpcm_shared_t shared;
5981 if (dhdsdio_readshared(bus, &shared) == 0)
5982 bus->console_addr = shared.console_addr;
5984 #endif /* DHD_DEBUG */
5988 * Flow Control has been moved into the RX headers and this out of band
5989 * method isn't used any more. Leave this here for possibly remaining backward
5990 * compatible with older dongles
5992 if (hmb_data & HMB_DATA_FC) {
5993 fcbits = (hmb_data & HMB_DATA_FCDATA_MASK) >> HMB_DATA_FCDATA_SHIFT;
5995 if (fcbits & ~bus->flowcontrol)
5997 if (bus->flowcontrol & ~fcbits)
6001 bus->flowcontrol = fcbits;
6005 /* At least print a message if FW halted */
6006 if (hmb_data & HMB_DATA_FWHALT) {
6007 DHD_ERROR(("INTERNAL ERROR: FIRMWARE HALTED : set BUS DOWN\n"));
6008 dhdsdio_checkdied(bus, NULL, 0);
6009 bus->dhd->busstate = DHD_BUS_DOWN;
6011 #endif /* DHD_DEBUG */
6013 /* Shouldn't be any others */
6014 if (hmb_data & ~(HMB_DATA_DEVREADY |
6016 HMB_DATA_NAKHANDLED |
6019 HMB_DATA_FCDATA_MASK |
6020 HMB_DATA_VERSION_MASK)) {
6021 DHD_ERROR(("Unknown mailbox data content: 0x%02x\n", hmb_data));
6028 dhdsdio_dpc(dhd_bus_t *bus)
6030 bcmsdh_info_t *sdh = bus->sdh;
6031 sdpcmd_regs_t *regs = bus->regs;
6032 uint32 intstatus, newstatus = 0;
6034 uint rxlimit = dhd_rxbound; /* Rx frames to read before resched */
6035 uint txlimit = dhd_txbound; /* Tx frames to send before resched */
6036 uint framecnt = 0; /* Temporary counter of tx/rx frames */
6037 bool rxdone = TRUE; /* Flag for no more read data */
6038 bool resched = FALSE; /* Flag indicating resched wanted */
6039 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
6041 dhd_os_sdlock(bus->dhd);
6043 if (bus->dhd->busstate == DHD_BUS_DOWN) {
6044 DHD_ERROR(("%s: Bus down, ret\n", __FUNCTION__));
6046 dhd_os_sdunlock(bus->dhd);
6051 /* Start with leftover status bits */
6052 intstatus = bus->intstatus;
6054 if (!SLPAUTO_ENAB(bus) && !KSO_ENAB(bus)) {
6055 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
6059 /* If waiting for HTAVAIL, check status */
6060 if (!SLPAUTO_ENAB(bus) && (bus->clkstate == CLK_PENDING)) {
6062 uint8 clkctl, devctl = 0;
6065 /* Check for inconsistent device control */
6066 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
6068 DHD_ERROR(("%s: error reading DEVCTL: %d\n", __FUNCTION__, err));
6069 bus->dhd->busstate = DHD_BUS_DOWN;
6071 ASSERT(devctl & SBSDIO_DEVCTL_CA_INT_ONLY);
6073 #endif /* DHD_DEBUG */
6075 /* Read CSR, if clock on switch to AVAIL, else ignore */
6076 clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
6078 DHD_ERROR(("%s: error reading CSR: %d\n", __FUNCTION__, err));
6079 bus->dhd->busstate = DHD_BUS_DOWN;
6082 DHD_INFO(("DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n", devctl, clkctl));
6084 if (SBSDIO_HTAV(clkctl)) {
6085 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
6087 DHD_ERROR(("%s: error reading DEVCTL: %d\n",
6088 __FUNCTION__, err));
6089 bus->dhd->busstate = DHD_BUS_DOWN;
6091 devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
6092 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
6094 DHD_ERROR(("%s: error writing DEVCTL: %d\n",
6095 __FUNCTION__, err));
6096 bus->dhd->busstate = DHD_BUS_DOWN;
6098 bus->clkstate = CLK_AVAIL;
6106 /* Make sure backplane clock is on */
6107 dhdsdio_clkctl(bus, CLK_AVAIL, TRUE);
6108 if (bus->clkstate != CLK_AVAIL)
6111 /* Pending interrupt indicates new device status */
6114 R_SDREG(newstatus, ®s->intstatus, retries);
6116 if (bcmsdh_regfail(bus->sdh))
6118 newstatus &= bus->hostintmask;
6119 bus->fcstate = !!(newstatus & I_HMB_FC_STATE);
6122 if ((bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_0) &&
6123 (newstatus == I_XMTDATA_AVAIL)) {
6126 W_SDREG(newstatus, ®s->intstatus, retries);
6130 /* Merge new bits with previous */
6131 intstatus |= newstatus;
6134 /* Handle flow-control change: read new state in case our ack
6135 * crossed another change interrupt. If change still set, assume
6136 * FC ON for safety, let next loop through do the debounce.
6138 if (intstatus & I_HMB_FC_CHANGE) {
6139 intstatus &= ~I_HMB_FC_CHANGE;
6140 W_SDREG(I_HMB_FC_CHANGE, ®s->intstatus, retries);
6141 R_SDREG(newstatus, ®s->intstatus, retries);
6142 bus->f1regdata += 2;
6143 bus->fcstate = !!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE));
6144 intstatus |= (newstatus & bus->hostintmask);
6147 /* Just being here means nothing more to do for chipactive */
6148 if (intstatus & I_CHIPACTIVE) {
6149 /* ASSERT(bus->clkstate == CLK_AVAIL); */
6150 intstatus &= ~I_CHIPACTIVE;
6153 /* Handle host mailbox indication */
6154 if (intstatus & I_HMB_HOST_INT) {
6155 intstatus &= ~I_HMB_HOST_INT;
6156 intstatus |= dhdsdio_hostmail(bus);
6159 /* Generally don't ask for these, can get CRC errors... */
6160 if (intstatus & I_WR_OOSYNC) {
6161 DHD_ERROR(("Dongle reports WR_OOSYNC\n"));
6162 intstatus &= ~I_WR_OOSYNC;
6165 if (intstatus & I_RD_OOSYNC) {
6166 DHD_ERROR(("Dongle reports RD_OOSYNC\n"));
6167 intstatus &= ~I_RD_OOSYNC;
6170 if (intstatus & I_SBINT) {
6171 DHD_ERROR(("Dongle reports SBINT\n"));
6172 intstatus &= ~I_SBINT;
6175 /* Would be active due to wake-wlan in gSPI */
6176 if (intstatus & I_CHIPACTIVE) {
6177 DHD_INFO(("Dongle reports CHIPACTIVE\n"));
6178 intstatus &= ~I_CHIPACTIVE;
6181 /* Ignore frame indications if rxskip is set */
6183 intstatus &= ~FRAME_AVAIL_MASK(bus);
6186 /* On frame indication, read available frames */
6187 if (PKT_AVAILABLE(bus, intstatus)) {
6188 framecnt = dhdsdio_readframes(bus, rxlimit, &rxdone);
6189 if (rxdone || bus->rxskip)
6190 intstatus &= ~FRAME_AVAIL_MASK(bus);
6191 rxlimit -= MIN(framecnt, rxlimit);
6194 /* Keep still-pending events for next scheduling */
6195 bus->intstatus = intstatus;
6198 /* Re-enable interrupts to detect new device events (mailbox, rx frame)
6199 * or clock availability. (Allows tx loop to check ipend if desired.)
6200 * (Unless register access seems hosed, as we may not be able to ACK...)
6202 if (bus->intr && bus->intdis && !bcmsdh_regfail(sdh)) {
6203 DHD_INTR(("%s: enable SDIO interrupts, rxdone %d framecnt %d\n",
6204 __FUNCTION__, rxdone, framecnt));
6205 bus->intdis = FALSE;
6206 #if defined(OOB_INTR_ONLY)
6207 bcmsdh_oob_intr_set(1);
6208 #endif /* defined(OOB_INTR_ONLY) */
6209 bcmsdh_intr_enable(sdh);
6212 #if defined(OOB_INTR_ONLY) && !defined(HW_OOB)
6213 /* In case of SW-OOB(using edge trigger),
6214 * Check interrupt status in the dongle again after enable irq on the host.
6215 * and rechedule dpc if interrupt is pended in the dongle.
6216 * There is a chance to miss OOB interrupt while irq is disabled on the host.
6217 * No need to do this with HW-OOB(level trigger)
6219 R_SDREG(newstatus, ®s->intstatus, retries);
6220 if (bcmsdh_regfail(bus->sdh))
6222 if (newstatus & bus->hostintmask) {
6226 #endif /* defined(OOB_INTR_ONLY) && !defined(HW_OOB) */
6228 #ifdef PROP_TXSTATUS
6229 dhd_wlfc_trigger_pktcommit(bus->dhd);
6232 if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL))
6233 dhdsdio_sendpendctl(bus);
6235 /* Send queued frames (limit 1 if rx may still be pending) */
6236 else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate &&
6237 pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit && DATAOK(bus)) {
6238 framecnt = rxdone ? txlimit : MIN(txlimit, dhd_txminmax);
6239 framecnt = dhdsdio_sendfromq(bus, framecnt);
6240 txlimit -= framecnt;
6242 /* Resched the DPC if ctrl cmd is pending on bus credit */
6243 if (bus->ctrl_frame_stat)
6246 /* Resched if events or tx frames are pending, else await next interrupt */
6247 /* On failed register access, all bets are off: no resched or interrupts */
6248 if ((bus->dhd->busstate == DHD_BUS_DOWN) || bcmsdh_regfail(sdh)) {
6249 if ((bus->sih && bus->sih->buscorerev >= 12) && !(dhdsdio_sleepcsr_get(bus) &
6250 SBSDIO_FUNC1_SLEEPCSR_KSO_MASK)) {
6251 /* Bus failed because of KSO */
6252 DHD_ERROR(("%s: Bus failed due to KSO\n", __FUNCTION__));
6255 DHD_ERROR(("%s: failed backplane access over SDIO, halting operation\n",
6257 bus->dhd->busstate = DHD_BUS_DOWN;
6260 } else if (bus->clkstate == CLK_PENDING) {
6261 /* Awaiting I_CHIPACTIVE; don't resched */
6262 } else if (bus->intstatus || bus->ipend ||
6263 (!bus->fcstate && pktq_mlen(&bus->txq, ~bus->flowcontrol) && DATAOK(bus)) ||
6264 PKT_AVAILABLE(bus, bus->intstatus)) { /* Read multiple frames */
6268 bus->dpc_sched = resched;
6270 /* If we're done for now, turn off clock request. */
6271 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && (bus->clkstate != CLK_PENDING)) {
6272 bus->activity = FALSE;
6273 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
6278 if (!resched && dhd_dpcpoll) {
6279 if (dhdsdio_readframes(bus, dhd_rxbound, &rxdone) != 0) {
6284 dhd_os_sdunlock(bus->dhd);
6289 dhd_bus_dpc(struct dhd_bus *bus)
6293 /* Call the DPC directly. */
6294 DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__));
6295 resched = dhdsdio_dpc(bus);
6301 dhdsdio_isr(void *arg)
6303 dhd_bus_t *bus = (dhd_bus_t*)arg;
6306 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
6309 DHD_ERROR(("%s : bus is null pointer , exit \n", __FUNCTION__));
6314 if (bus->dhd->busstate == DHD_BUS_DOWN) {
6315 DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__));
6319 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
6321 /* Count the interrupt call */
6325 /* Shouldn't get this interrupt if we're sleeping? */
6326 if (!SLPAUTO_ENAB(bus)) {
6327 if (bus->sleeping) {
6328 DHD_ERROR(("INTERRUPT WHILE SLEEPING??\n"));
6330 } else if (!KSO_ENAB(bus)) {
6331 DHD_ERROR(("ISR in devsleep 1\n"));
6335 /* Disable additional interrupts (is this needed now)? */
6337 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
6339 DHD_ERROR(("dhdsdio_isr() w/o interrupt configured!\n"));
6342 bcmsdh_intr_disable(sdh);
6345 #if defined(SDIO_ISR_THREAD)
6346 DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__));
6347 DHD_OS_WAKE_LOCK(bus->dhd);
6349 DHD_OS_WAKE_UNLOCK(bus->dhd);
6352 bus->dpc_sched = TRUE;
6353 dhd_sched_dpc(bus->dhd);
6361 dhdsdio_pktgen_init(dhd_bus_t *bus)
6363 /* Default to specified length, or full range */
6364 if (dhd_pktgen_len) {
6365 bus->pktgen_maxlen = MIN(dhd_pktgen_len, MAX_PKTGEN_LEN);
6366 bus->pktgen_minlen = bus->pktgen_maxlen;
6368 bus->pktgen_maxlen = MAX_PKTGEN_LEN;
6369 bus->pktgen_minlen = 0;
6371 bus->pktgen_len = (uint16)bus->pktgen_minlen;
6373 /* Default to per-watchdog burst with 10s print time */
6374 bus->pktgen_freq = 1;
6375 bus->pktgen_print = dhd_watchdog_ms ? (10000 / dhd_watchdog_ms) : 0;
6376 bus->pktgen_count = (dhd_pktgen * dhd_watchdog_ms + 999) / 1000;
6378 /* Default to echo mode */
6379 bus->pktgen_mode = DHD_PKTGEN_ECHO;
6380 bus->pktgen_stop = 1;
6384 dhdsdio_pktgen(dhd_bus_t *bus)
6390 osl_t *osh = bus->dhd->osh;
6396 /* Display current count if appropriate */
6397 if (bus->pktgen_print && (++bus->pktgen_ptick >= bus->pktgen_print)) {
6398 bus->pktgen_ptick = 0;
6399 printf("%s: send attempts %d, rcvd %d, errors %d\n",
6400 __FUNCTION__, bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail);
6402 /* Print throughput stats only for constant length packet runs */
6403 if (bus->pktgen_minlen == bus->pktgen_maxlen) {
6404 time_lapse = jiffies - bus->pktgen_prev_time;
6405 bus->pktgen_prev_time = jiffies;
6406 sent_pkts = bus->pktgen_sent - bus->pktgen_prev_sent;
6407 bus->pktgen_prev_sent = bus->pktgen_sent;
6408 rcvd_pkts = bus->pktgen_rcvd - bus->pktgen_prev_rcvd;
6409 bus->pktgen_prev_rcvd = bus->pktgen_rcvd;
6411 printf("%s: Tx Throughput %d kbps, Rx Throughput %d kbps\n",
6413 (sent_pkts * bus->pktgen_len / jiffies_to_msecs(time_lapse)) * 8,
6414 (rcvd_pkts * bus->pktgen_len / jiffies_to_msecs(time_lapse)) * 8);
6418 /* For recv mode, just make sure dongle has started sending */
6419 if (bus->pktgen_mode == DHD_PKTGEN_RECV) {
6420 if (bus->pktgen_rcv_state == PKTGEN_RCV_IDLE) {
6421 bus->pktgen_rcv_state = PKTGEN_RCV_ONGOING;
6422 dhdsdio_sdtest_set(bus, bus->pktgen_total);
6427 /* Otherwise, generate or request the specified number of packets */
6428 for (pktcount = 0; pktcount < bus->pktgen_count; pktcount++) {
6429 /* Stop if total has been reached */
6430 if (bus->pktgen_total && (bus->pktgen_sent >= bus->pktgen_total)) {
6431 bus->pktgen_count = 0;
6435 /* Allocate an appropriate-sized packet */
6436 if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) {
6437 len = SDPCM_TEST_PKT_CNT_FLD_LEN;
6439 len = bus->pktgen_len;
6441 if (!(pkt = PKTGET(osh, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN),
6443 DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__));
6446 PKTALIGN(osh, pkt, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN), DHD_SDALIGN);
6447 data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
6449 /* Write test header cmd and extra based on mode */
6450 switch (bus->pktgen_mode) {
6451 case DHD_PKTGEN_ECHO:
6452 *data++ = SDPCM_TEST_ECHOREQ;
6453 *data++ = (uint8)bus->pktgen_sent;
6456 case DHD_PKTGEN_SEND:
6457 *data++ = SDPCM_TEST_DISCARD;
6458 *data++ = (uint8)bus->pktgen_sent;
6461 case DHD_PKTGEN_RXBURST:
6462 *data++ = SDPCM_TEST_BURST;
6463 *data++ = (uint8)bus->pktgen_count; /* Just for backward compatability */
6467 DHD_ERROR(("Unrecognized pktgen mode %d\n", bus->pktgen_mode));
6468 PKTFREE(osh, pkt, TRUE);
6469 bus->pktgen_count = 0;
6473 /* Write test header length field */
6474 *data++ = (bus->pktgen_len >> 0);
6475 *data++ = (bus->pktgen_len >> 8);
6477 /* Write frame count in a 4 byte field adjucent to SDPCM test header for
6480 if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) {
6481 *data++ = (uint8)(bus->pktgen_count >> 0);
6482 *data++ = (uint8)(bus->pktgen_count >> 8);
6483 *data++ = (uint8)(bus->pktgen_count >> 16);
6484 *data++ = (uint8)(bus->pktgen_count >> 24);
6487 /* Then fill in the remainder -- N/A for burst */
6488 for (fillbyte = 0; fillbyte < len; fillbyte++)
6489 *data++ = SDPCM_TEST_FILL(fillbyte, (uint8)bus->pktgen_sent);
6493 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
6494 data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
6495 prhex("dhdsdio_pktgen: Tx Data", data, PKTLEN(osh, pkt) - SDPCM_HDRLEN);
6500 if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE, FALSE)) {
6502 if (bus->pktgen_stop && bus->pktgen_stop == bus->pktgen_fail)
6503 bus->pktgen_count = 0;
6507 /* Bump length if not fixed, wrap at max */
6508 if (++bus->pktgen_len > bus->pktgen_maxlen)
6509 bus->pktgen_len = (uint16)bus->pktgen_minlen;
6511 /* Special case for burst mode: just send one request! */
6512 if (bus->pktgen_mode == DHD_PKTGEN_RXBURST)
6518 dhdsdio_sdtest_set(dhd_bus_t *bus, uint count)
6522 osl_t *osh = bus->dhd->osh;
6524 /* Allocate the packet */
6525 if (!(pkt = PKTGET(osh, SDPCM_HDRLEN + SDPCM_TEST_HDRLEN +
6526 SDPCM_TEST_PKT_CNT_FLD_LEN + DHD_SDALIGN, TRUE))) {
6527 DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__));
6530 PKTALIGN(osh, pkt, (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN +
6531 SDPCM_TEST_PKT_CNT_FLD_LEN), DHD_SDALIGN);
6532 data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
6534 /* Fill in the test header */
6535 *data++ = SDPCM_TEST_SEND;
6536 *data++ = (count > 0)?TRUE:FALSE;
6537 *data++ = (bus->pktgen_maxlen >> 0);
6538 *data++ = (bus->pktgen_maxlen >> 8);
6539 *data++ = (uint8)(count >> 0);
6540 *data++ = (uint8)(count >> 8);
6541 *data++ = (uint8)(count >> 16);
6542 *data++ = (uint8)(count >> 24);
6545 if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE, FALSE))
6551 dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq)
6553 osl_t *osh = bus->dhd->osh;
6562 /* Check for min length */
6563 if ((pktlen = PKTLEN(osh, pkt)) < SDPCM_TEST_HDRLEN) {
6564 DHD_ERROR(("dhdsdio_restrcv: toss runt frame, pktlen %d\n", pktlen));
6565 PKTFREE(osh, pkt, FALSE);
6569 /* Extract header fields */
6570 data = PKTDATA(osh, pkt);
6573 len = *data++; len += *data++ << 8;
6574 DHD_TRACE(("%s:cmd:%d, xtra:%d,len:%d\n", __FUNCTION__, cmd, extra, len));
6575 /* Check length for relevant commands */
6576 if (cmd == SDPCM_TEST_DISCARD || cmd == SDPCM_TEST_ECHOREQ || cmd == SDPCM_TEST_ECHORSP) {
6577 if (pktlen != len + SDPCM_TEST_HDRLEN) {
6578 DHD_ERROR(("dhdsdio_testrcv: frame length mismatch, pktlen %d seq %d"
6579 " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len));
6580 PKTFREE(osh, pkt, FALSE);
6585 /* Process as per command */
6587 case SDPCM_TEST_ECHOREQ:
6588 /* Rx->Tx turnaround ok (even on NDIS w/current implementation) */
6589 *(uint8 *)(PKTDATA(osh, pkt)) = SDPCM_TEST_ECHORSP;
6590 if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE, FALSE) == 0) {
6594 PKTFREE(osh, pkt, FALSE);
6599 case SDPCM_TEST_ECHORSP:
6600 if (bus->ext_loop) {
6601 PKTFREE(osh, pkt, FALSE);
6606 for (offset = 0; offset < len; offset++, data++) {
6607 if (*data != SDPCM_TEST_FILL(offset, extra)) {
6608 DHD_ERROR(("dhdsdio_testrcv: echo data mismatch: "
6609 "offset %d (len %d) expect 0x%02x rcvd 0x%02x\n",
6610 offset, len, SDPCM_TEST_FILL(offset, extra), *data));
6614 PKTFREE(osh, pkt, FALSE);
6618 case SDPCM_TEST_DISCARD:
6622 uint8 testval = extra;
6623 for (i = 0; i < len; i++) {
6624 if (*prn != testval) {
6625 DHD_ERROR(("DIErr@Pkt#:%d,Ix:%d, expected:0x%x, got:0x%x\n",
6626 i, bus->pktgen_rcvd_rcvsession, testval, *prn));
6631 PKTFREE(osh, pkt, FALSE);
6635 case SDPCM_TEST_BURST:
6636 case SDPCM_TEST_SEND:
6638 DHD_INFO(("dhdsdio_testrcv: unsupported or unknown command, pktlen %d seq %d"
6639 " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len));
6640 PKTFREE(osh, pkt, FALSE);
6644 /* For recv mode, stop at limit (and tell dongle to stop sending) */
6645 if (bus->pktgen_mode == DHD_PKTGEN_RECV) {
6646 if (bus->pktgen_rcv_state != PKTGEN_RCV_IDLE) {
6647 bus->pktgen_rcvd_rcvsession++;
6649 if (bus->pktgen_total &&
6650 (bus->pktgen_rcvd_rcvsession >= bus->pktgen_total)) {
6651 bus->pktgen_count = 0;
6652 DHD_ERROR(("Pktgen:rcv test complete!\n"));
6653 bus->pktgen_rcv_state = PKTGEN_RCV_IDLE;
6654 dhdsdio_sdtest_set(bus, FALSE);
6655 bus->pktgen_rcvd_rcvsession = 0;
6663 dhd_disable_intr(dhd_pub_t *dhdp)
6667 bcmsdh_intr_disable(bus->sdh);
6671 dhd_bus_watchdog(dhd_pub_t *dhdp)
6675 DHD_TIMER(("%s: Enter\n", __FUNCTION__));
6679 if (bus->dhd->dongle_reset)
6682 /* Ignore the timer if simulating bus down */
6683 if (!SLPAUTO_ENAB(bus) && bus->sleeping)
6686 if (dhdp->busstate == DHD_BUS_DOWN)
6689 /* Poll period: check device if appropriate. */
6690 if (!SLPAUTO_ENAB(bus) && (bus->poll && (++bus->polltick >= bus->pollrate))) {
6691 uint32 intstatus = 0;
6693 /* Reset poll tick */
6696 /* Check device if no interrupts */
6697 if (!bus->intr || (bus->intrcount == bus->lastintrs)) {
6699 if (!bus->dpc_sched) {
6701 devpend = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0,
6702 SDIOD_CCCR_INTPEND, NULL);
6703 intstatus = devpend & (INTR_STATUS_FUNC1 | INTR_STATUS_FUNC2);
6706 /* If there is something, make like the ISR and schedule the DPC */
6711 bcmsdh_intr_disable(bus->sdh);
6713 bus->dpc_sched = TRUE;
6714 dhd_sched_dpc(bus->dhd);
6719 /* Update interrupt tracking */
6720 bus->lastintrs = bus->intrcount;
6724 /* Poll for console output periodically */
6725 if (dhdp->busstate == DHD_BUS_DATA && dhd_console_ms != 0) {
6726 bus->console.count += dhd_watchdog_ms;
6727 if (bus->console.count >= dhd_console_ms) {
6728 bus->console.count -= dhd_console_ms;
6729 /* Make sure backplane clock is on */
6730 if (SLPAUTO_ENAB(bus))
6731 dhdsdio_bussleep(bus, FALSE);
6733 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
6734 if (dhdsdio_readconsole(bus) < 0)
6735 dhd_console_ms = 0; /* On error, stop trying */
6738 #endif /* DHD_DEBUG */
6741 /* Generate packets if configured */
6742 if (bus->pktgen_count && (++bus->pktgen_tick >= bus->pktgen_freq)) {
6743 /* Make sure backplane clock is on */
6744 if (SLPAUTO_ENAB(bus))
6745 dhdsdio_bussleep(bus, FALSE);
6747 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
6748 bus->pktgen_tick = 0;
6749 dhdsdio_pktgen(bus);
6753 /* On idle timeout clear activity flag and/or turn off clock */
6754 #ifdef DHD_USE_IDLECOUNT
6756 bus->activity = FALSE;
6760 if ((bus->idletime > 0) && (bus->idlecount >= bus->idletime)) {
6761 DHD_TIMER(("%s: DHD Idle state!!\n", __FUNCTION__));
6762 if (SLPAUTO_ENAB(bus)) {
6763 if (dhdsdio_bussleep(bus, TRUE) != BCME_BUSY)
6764 dhd_os_wd_timer(bus->dhd, 0);
6766 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
6772 if ((bus->idletime > 0) && (bus->clkstate == CLK_AVAIL)) {
6773 if (++bus->idlecount >= bus->idletime) {
6775 if (bus->activity) {
6776 bus->activity = FALSE;
6777 if (SLPAUTO_ENAB(bus)) {
6778 if (!bus->readframes)
6779 dhdsdio_bussleep(bus, TRUE);
6781 bus->reqbussleep = TRUE;
6784 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
6788 #endif /* DHD_USE_IDLECOUNT */
6795 dhd_bus_console_in(dhd_pub_t *dhdp, uchar *msg, uint msglen)
6797 dhd_bus_t *bus = dhdp->bus;
6802 /* Address could be zero if CONSOLE := 0 in dongle Makefile */
6803 if (bus->console_addr == 0)
6804 return BCME_UNSUPPORTED;
6806 /* Exclusive bus access */
6807 dhd_os_sdlock(bus->dhd);
6809 /* Don't allow input if dongle is in reset */
6810 if (bus->dhd->dongle_reset) {
6811 dhd_os_sdunlock(bus->dhd);
6812 return BCME_NOTREADY;
6815 /* Request clock to allow SDIO accesses */
6817 /* No pend allowed since txpkt is called later, ht clk has to be on */
6818 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
6820 /* Zero cbuf_index */
6821 addr = bus->console_addr + OFFSETOF(hndrte_cons_t, cbuf_idx);
6823 if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0)
6826 /* Write message into cbuf */
6827 addr = bus->console_addr + OFFSETOF(hndrte_cons_t, cbuf);
6828 if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)msg, msglen)) < 0)
6831 /* Write length into vcons_in */
6832 addr = bus->console_addr + OFFSETOF(hndrte_cons_t, vcons_in);
6833 val = htol32(msglen);
6834 if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0)
6837 /* Bump dongle by sending an empty packet on the event channel.
6838 * sdpcm_sendup (RX) checks for virtual console input.
6840 if ((pkt = PKTGET(bus->dhd->osh, 4 + SDPCM_RESERVE, TRUE)) != NULL)
6841 dhdsdio_txpkt(bus, pkt, SDPCM_EVENT_CHANNEL, TRUE, FALSE);
6844 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
6845 bus->activity = FALSE;
6846 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
6849 dhd_os_sdunlock(bus->dhd);
6853 #endif /* DHD_DEBUG */
6857 dhd_dump_cis(uint fn, uint8 *cis)
6859 uint byte, tag, tdata;
6860 DHD_INFO(("Function %d CIS:\n", fn));
6862 for (tdata = byte = 0; byte < SBSDIO_CIS_SIZE_LIMIT; byte++) {
6863 if ((byte % 16) == 0)
6865 DHD_INFO(("%02x ", cis[byte]));
6866 if ((byte % 16) == 15)
6874 else if ((byte + 1) < SBSDIO_CIS_SIZE_LIMIT)
6875 tdata = cis[byte + 1] + 1;
6880 if ((byte % 16) != 15)
6883 #endif /* DHD_DEBUG */
6886 dhdsdio_chipmatch(uint16 chipid)
6888 if (chipid == BCM4325_CHIP_ID)
6890 if (chipid == BCM4329_CHIP_ID)
6892 if (chipid == BCM4315_CHIP_ID)
6894 if (chipid == BCM4319_CHIP_ID)
6896 if (chipid == BCM4336_CHIP_ID)
6898 if (chipid == BCM4330_CHIP_ID)
6900 if (chipid == BCM43237_CHIP_ID)
6902 if (chipid == BCM43362_CHIP_ID)
6904 if (chipid == BCM4314_CHIP_ID)
6906 if (chipid == BCM43242_CHIP_ID)
6908 if (chipid == BCM43340_CHIP_ID)
6910 if (chipid == BCM43341_CHIP_ID)
6912 if (chipid == BCM43143_CHIP_ID)
6914 if (chipid == BCM43342_CHIP_ID)
6916 if (chipid == BCM4334_CHIP_ID)
6918 if (chipid == BCM43239_CHIP_ID)
6920 if (chipid == BCM4324_CHIP_ID)
6922 if (chipid == BCM4335_CHIP_ID)
6924 if (chipid == BCM4339_CHIP_ID)
6926 if (chipid == BCM4350_CHIP_ID)
6932 dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot,
6933 uint16 func, uint bustype, void *regsva, osl_t * osh, void *sdh, void *dev)
6937 #ifdef GET_CUSTOM_MAC_ENABLE
6938 struct ether_addr ea_addr;
6939 #endif /* GET_CUSTOM_MAC_ENABLE */
6942 /* Init global variables at run-time, not as part of the declaration.
6943 * This is required to support init/de-init of the driver. Initialization
6944 * of globals as part of the declaration results in non-deterministic
6945 * behavior since the value of the globals may be different on the
6946 * first time that the driver is initialized vs subsequent initializations.
6948 dhd_txbound = DHD_TXBOUND;
6949 dhd_rxbound = DHD_RXBOUND;
6950 dhd_alignctl = TRUE;
6952 dhd_readahead = TRUE;
6955 dhd_dongle_ramsize = 0;
6956 dhd_txminmax = DHD_TXMINMAX;
6960 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
6961 DHD_INFO(("%s: venid 0x%04x devid 0x%04x\n", __FUNCTION__, venid, devid));
6963 /* We make assumptions about address window mappings */
6964 ASSERT((uintptr)regsva == SI_ENUM_BASE);
6966 /* BCMSDH passes venid and devid based on CIS parsing -- but low-power start
6967 * means early parse could fail, so here we should get either an ID
6968 * we recognize OR (-1) indicating we must request power first.
6970 /* Check the Vendor ID */
6973 case VENDOR_BROADCOM:
6976 DHD_ERROR(("%s: unknown vendor: 0x%04x\n",
6977 __FUNCTION__, venid));
6981 /* Check the Device ID and make sure it's one that we support */
6983 case BCM4325_D11DUAL_ID: /* 4325 802.11a/g id */
6984 case BCM4325_D11G_ID: /* 4325 802.11g 2.4Ghz band id */
6985 case BCM4325_D11A_ID: /* 4325 802.11a 5Ghz band id */
6986 DHD_INFO(("%s: found 4325 Dongle\n", __FUNCTION__));
6988 case BCM4329_D11N_ID: /* 4329 802.11n dualband device */
6989 case BCM4329_D11N2G_ID: /* 4329 802.11n 2.4G device */
6990 case BCM4329_D11N5G_ID: /* 4329 802.11n 5G device */
6992 DHD_INFO(("%s: found 4329 Dongle\n", __FUNCTION__));
6994 case BCM4315_D11DUAL_ID: /* 4315 802.11a/g id */
6995 case BCM4315_D11G_ID: /* 4315 802.11g id */
6996 case BCM4315_D11A_ID: /* 4315 802.11a id */
6997 DHD_INFO(("%s: found 4315 Dongle\n", __FUNCTION__));
6999 case BCM4319_D11N_ID: /* 4319 802.11n id */
7000 case BCM4319_D11N2G_ID: /* 4319 802.11n2g id */
7001 case BCM4319_D11N5G_ID: /* 4319 802.11n5g id */
7002 DHD_INFO(("%s: found 4319 Dongle\n", __FUNCTION__));
7005 DHD_INFO(("%s: allow device id 0, will check chip internals\n",
7010 DHD_ERROR(("%s: skipping 0x%04x/0x%04x, not a dongle\n",
7011 __FUNCTION__, venid, devid));
7016 /* Ask the OS interface part for an OSL handle */
7017 if (!(osh = dhd_osl_attach(sdh, DHD_BUS))) {
7018 DHD_ERROR(("%s: osl_attach failed!\n", __FUNCTION__));
7023 /* Allocate private bus interface state */
7024 if (!(bus = MALLOC(osh, sizeof(dhd_bus_t)))) {
7025 DHD_ERROR(("%s: MALLOC of dhd_bus_t failed\n", __FUNCTION__));
7028 bzero(bus, sizeof(dhd_bus_t));
7030 bus->cl_devid = (uint16)devid;
7032 bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1;
7033 bus->usebufpool = FALSE; /* Use bufpool if allocated, else use locally malloced rxbuf */
7035 /* attach the common module */
7036 dhd_common_init(osh);
7038 /* attempt to attach to the dongle */
7039 if (!(dhdsdio_probe_attach(bus, osh, sdh, regsva, devid))) {
7040 DHD_ERROR(("%s: dhdsdio_probe_attach failed\n", __FUNCTION__));
7044 /* Attach to the dhd/OS/network interface */
7045 if (!(bus->dhd = dhd_attach(osh, bus, SDPCM_RESERVE, dev))) {
7046 DHD_ERROR(("%s: dhd_attach failed\n", __FUNCTION__));
7050 /* Allocate buffers */
7051 if (!(dhdsdio_probe_malloc(bus, osh, sdh))) {
7052 DHD_ERROR(("%s: dhdsdio_probe_malloc failed\n", __FUNCTION__));
7056 if (!(dhdsdio_probe_init(bus, osh, sdh))) {
7057 DHD_ERROR(("%s: dhdsdio_probe_init failed\n", __FUNCTION__));
7062 /* Register interrupt callback, but mask it (not operational yet). */
7063 DHD_INTR(("%s: disable SDIO interrupts (not interested yet)\n", __FUNCTION__));
7064 bcmsdh_intr_disable(sdh);
7065 if ((ret = bcmsdh_intr_reg(sdh, dhdsdio_isr, bus)) != 0) {
7066 DHD_ERROR(("%s: FAILED: bcmsdh_intr_reg returned %d\n",
7067 __FUNCTION__, ret));
7070 DHD_INTR(("%s: registered SDIO interrupt function ok\n", __FUNCTION__));
7072 DHD_INFO(("%s: SDIO interrupt function is NOT registered due to polling mode\n",
7076 DHD_INFO(("%s: completed!!\n", __FUNCTION__));
7078 #ifdef GET_CUSTOM_MAC_ENABLE
7079 /* Read MAC address from external customer place */
7080 memset(&ea_addr, 0, sizeof(ea_addr));
7081 ret = dhd_custom_get_mac_address(ea_addr.octet);
7083 memcpy(bus->dhd->mac.octet, (void *)&ea_addr, ETHER_ADDR_LEN);
7085 #endif /* GET_CUSTOM_MAC_ENABLE */
7087 /* if firmware path present try to download and bring up bus */
7088 bus->dhd->hang_report = TRUE;
7089 if (dhd_download_fw_on_driverload) {
7090 if ((ret = dhd_bus_start(bus->dhd)) != 0) {
7091 DHD_ERROR(("%s: dhd_bus_start failed\n", __FUNCTION__));
7095 /* Ok, have the per-port tell the stack we're open for business */
7096 if (dhd_net_attach(bus->dhd, 0) != 0) {
7097 DHD_ERROR(("%s: Net attach failed!!\n", __FUNCTION__));
7106 dhdsdio_release(bus, osh);
7114 dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva,
7120 bus->alp_only = TRUE;
7123 /* Return the window to backplane enumeration space for core access */
7124 if (dhdsdio_set_siaddr_window(bus, SI_ENUM_BASE)) {
7125 DHD_ERROR(("%s: FAILED to return to SI_ENUM_BASE\n", __FUNCTION__));
7129 /* Force PLL off until si_attach() programs PLL control regs */
7133 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, DHD_INIT_CLKCTL1, &err);
7135 clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
7137 if (err || ((clkctl & ~SBSDIO_AVBITS) != DHD_INIT_CLKCTL1)) {
7138 DHD_ERROR(("dhdsdio_probe: ChipClkCSR access: err %d wrote 0x%02x read 0x%02x\n",
7139 err, DHD_INIT_CLKCTL1, clkctl));
7144 if (DHD_INFO_ON()) {
7146 uint8 *cis[SDIOD_MAX_IOFUNCS];
7149 numfn = bcmsdh_query_iofnum(sdh);
7150 ASSERT(numfn <= SDIOD_MAX_IOFUNCS);
7152 /* Make sure ALP is available before trying to read CIS */
7153 SPINWAIT(((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
7154 SBSDIO_FUNC1_CHIPCLKCSR, NULL)),
7155 !SBSDIO_ALPAV(clkctl)), PMU_MAX_TRANSITION_DLY);
7157 /* Now request ALP be put on the bus */
7158 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
7159 DHD_INIT_CLKCTL2, &err);
7162 for (fn = 0; fn <= numfn; fn++) {
7163 if (!(cis[fn] = MALLOC(osh, SBSDIO_CIS_SIZE_LIMIT))) {
7164 DHD_INFO(("dhdsdio_probe: fn %d cis malloc failed\n", fn));
7167 bzero(cis[fn], SBSDIO_CIS_SIZE_LIMIT);
7169 if ((err = bcmsdh_cis_read(sdh, fn, cis[fn], SBSDIO_CIS_SIZE_LIMIT))) {
7170 DHD_INFO(("dhdsdio_probe: fn %d cis read err %d\n", fn, err));
7171 MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT);
7174 dhd_dump_cis(fn, cis[fn]);
7179 MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT);
7183 DHD_ERROR(("dhdsdio_probe: failure reading or parsing CIS\n"));
7187 #endif /* DHD_DEBUG */
7189 /* si_attach() will provide an SI handle and scan the backplane */
7190 if (!(bus->sih = si_attach((uint)devid, osh, regsva, DHD_BUS, sdh,
7191 &bus->vars, &bus->varsz))) {
7192 DHD_ERROR(("%s: si_attach failed!\n", __FUNCTION__));
7198 DHD_ERROR(("F1 signature OK, socitype:0x%x chip:0x%4x rev:0x%x pkg:0x%x\n",
7199 bus->sih->socitype, bus->sih->chip, bus->sih->chiprev,
7200 bus->sih->chippkg));
7201 #endif /* DHD_DEBUG */
7204 bcmsdh_chipinfo(sdh, bus->sih->chip, bus->sih->chiprev);
7206 if (!dhdsdio_chipmatch((uint16)bus->sih->chip)) {
7207 DHD_ERROR(("%s: unsupported chip: 0x%04x\n",
7208 __FUNCTION__, bus->sih->chip));
7212 if (bus->sih->buscorerev >= 12)
7213 dhdsdio_clk_kso_init(bus);
7217 if (CST4330_CHIPMODE_SDIOD(bus->sih->chipst)) {
7220 si_sdiod_drive_strength_init(bus->sih, osh, dhd_sdiod_drive_strength);
7223 /* Get info on the ARM and SOCRAM cores... */
7224 if (!DHD_NOPMU(bus)) {
7225 if ((si_setcore(bus->sih, ARM7S_CORE_ID, 0)) ||
7226 (si_setcore(bus->sih, ARMCM3_CORE_ID, 0)) ||
7227 (si_setcore(bus->sih, ARMCR4_CORE_ID, 0))) {
7228 bus->armrev = si_corerev(bus->sih);
7230 DHD_ERROR(("%s: failed to find ARM core!\n", __FUNCTION__));
7234 if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
7235 if (!(bus->orig_ramsize = si_socram_size(bus->sih))) {
7236 DHD_ERROR(("%s: failed to find SOCRAM memory!\n", __FUNCTION__));
7240 /* cr4 has a different way to find the RAM size from TCM's */
7241 if (!(bus->orig_ramsize = si_tcm_size(bus->sih))) {
7242 DHD_ERROR(("%s: failed to find CR4-TCM memory!\n", __FUNCTION__));
7245 /* also populate base address */
7246 switch ((uint16)bus->sih->chip) {
7247 case BCM4335_CHIP_ID:
7248 case BCM4339_CHIP_ID:
7249 bus->dongle_ram_base = CR4_4335_RAM_BASE;
7251 case BCM4350_CHIP_ID:
7252 bus->dongle_ram_base = CR4_4350_RAM_BASE;
7254 case BCM4360_CHIP_ID:
7255 bus->dongle_ram_base = CR4_4360_RAM_BASE;
7258 bus->dongle_ram_base = 0;
7259 DHD_ERROR(("%s: WARNING: Using default ram base at 0x%x\n",
7260 __FUNCTION__, bus->dongle_ram_base));
7263 bus->ramsize = bus->orig_ramsize;
7264 if (dhd_dongle_ramsize)
7265 dhd_dongle_setramsize(bus, dhd_dongle_ramsize);
7267 DHD_ERROR(("DHD: dongle ram size is set to %d(orig %d) at 0x%x\n",
7268 bus->ramsize, bus->orig_ramsize, bus->dongle_ram_base));
7270 bus->srmemsize = si_socram_srmem_size(bus->sih);
7273 /* ...but normally deal with the SDPCMDEV core */
7274 if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0)) &&
7275 !(bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0))) {
7276 DHD_ERROR(("%s: failed to find SDIODEV core!\n", __FUNCTION__));
7279 bus->sdpcmrev = si_corerev(bus->sih);
7281 /* Set core control so an SDIO reset does a backplane reset */
7282 OR_REG(osh, &bus->regs->corecontrol, CC_BPRESEN);
7283 bus->rxint_mode = SDIO_DEVICE_HMB_RXINT;
7285 if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev >= 4) &&
7286 (bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_1))
7290 val = R_REG(osh, &bus->regs->corecontrol);
7291 val &= ~CC_XMTDATAAVAIL_MODE;
7292 val |= CC_XMTDATAAVAIL_CTRL;
7293 W_REG(osh, &bus->regs->corecontrol, val);
7297 pktq_init(&bus->txq, (PRIOMASK + 1), QLEN);
7299 /* Locate an appropriately-aligned portion of hdrbuf */
7300 bus->rxhdr = (uint8 *)ROUNDUP((uintptr)&bus->hdrbuf[0], DHD_SDALIGN);
7302 /* Set the poll and/or interrupt flags */
7303 bus->intr = (bool)dhd_intr;
7304 if ((bus->poll = (bool)dhd_poll))
7307 #ifdef BCMSDIOH_TXGLOM
7308 /* Setting default Glom mode */
7309 bus->glom_mode = bcmsdh_set_mode(bus->sdh, SDPCM_DEFGLOM_MODE);
7310 /* Setting default Glom size */
7311 bus->glomsize = SDPCM_DEFGLOM_SIZE;
7317 if (bus->sih != NULL) {
7318 si_detach(bus->sih);
7325 dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh)
7327 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7329 if (bus->dhd->maxctl) {
7330 bus->rxblen = ROUNDUP((bus->dhd->maxctl + SDPCM_HDRLEN), ALIGNMENT) + DHD_SDALIGN;
7331 if (!(bus->rxbuf = DHD_OS_PREALLOC(osh, DHD_PREALLOC_RXBUF, bus->rxblen))) {
7332 DHD_ERROR(("%s: MALLOC of %d-byte rxbuf failed\n",
7333 __FUNCTION__, bus->rxblen));
7337 /* Allocate buffer to receive glomed packet */
7338 if (!(bus->databuf = DHD_OS_PREALLOC(osh, DHD_PREALLOC_DATABUF, MAX_DATA_BUF))) {
7339 DHD_ERROR(("%s: MALLOC of %d-byte databuf failed\n",
7340 __FUNCTION__, MAX_DATA_BUF));
7341 /* release rxbuf which was already located as above */
7343 DHD_OS_PREFREE(osh, bus->rxbuf, bus->rxblen);
7347 /* Align the buffer */
7348 if ((uintptr)bus->databuf % DHD_SDALIGN)
7349 bus->dataptr = bus->databuf + (DHD_SDALIGN - ((uintptr)bus->databuf % DHD_SDALIGN));
7351 bus->dataptr = bus->databuf;
7360 dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh)
7364 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7367 dhdsdio_pktgen_init(bus);
7370 /* Disable F2 to clear any intermediate frame state on the dongle */
7371 bcmsdh_cfg_write(sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL);
7373 bus->dhd->busstate = DHD_BUS_DOWN;
7374 bus->sleeping = FALSE;
7375 bus->rxflow = FALSE;
7376 bus->prev_rxlim_hit = 0;
7378 /* Done with backplane-dependent accesses, can drop clock... */
7379 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
7381 /* ...and initialize clock/power states */
7382 bus->clkstate = CLK_SDONLY;
7383 bus->idletime = (int32)dhd_idletime;
7384 bus->idleclock = DHD_IDLE_ACTIVE;
7386 /* Query the SD clock speed */
7387 if (bcmsdh_iovar_op(sdh, "sd_divisor", NULL, 0,
7388 &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) {
7389 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_divisor"));
7390 bus->sd_divisor = -1;
7392 DHD_INFO(("%s: Initial value for %s is %d\n",
7393 __FUNCTION__, "sd_divisor", bus->sd_divisor));
7396 /* Query the SD bus mode */
7397 if (bcmsdh_iovar_op(sdh, "sd_mode", NULL, 0,
7398 &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) {
7399 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_mode"));
7402 DHD_INFO(("%s: Initial value for %s is %d\n",
7403 __FUNCTION__, "sd_mode", bus->sd_mode));
7406 /* Query the F2 block size, set roundup accordingly */
7408 if (bcmsdh_iovar_op(sdh, "sd_blocksize", &fnum, sizeof(int32),
7409 &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) {
7411 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize"));
7413 DHD_INFO(("%s: Initial value for %s is %d\n",
7414 __FUNCTION__, "sd_blocksize", bus->blocksize));
7416 if ((bus->sih->chip == BCM4335_CHIP_ID) ||
7417 (bus->sih->chip == BCM4339_CHIP_ID))
7418 dhd_overflow_war(bus);
7420 bus->roundup = MIN(max_roundup, bus->blocksize);
7422 /* Query if bus module supports packet chaining, default to use if supported */
7423 if (bcmsdh_iovar_op(sdh, "sd_rxchain", NULL, 0,
7424 &bus->sd_rxchain, sizeof(int32), FALSE) != BCME_OK) {
7425 bus->sd_rxchain = FALSE;
7427 DHD_INFO(("%s: bus module (through bcmsdh API) %s chaining\n",
7428 __FUNCTION__, (bus->sd_rxchain ? "supports" : "does not support")));
7430 bus->use_rxchain = (bool)bus->sd_rxchain;
7436 dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh,
7437 char *pfw_path, char *pnv_path)
7440 bus->fw_path = pfw_path;
7441 bus->nv_path = pnv_path;
7443 ret = dhdsdio_download_firmware(bus, osh, bus->sdh);
7450 dhdsdio_download_firmware(struct dhd_bus *bus, osl_t *osh, void *sdh)
7454 DHD_OS_WAKE_LOCK(bus->dhd);
7456 /* Download the firmware */
7457 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
7459 ret = _dhdsdio_download_firmware(bus) == 0;
7461 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
7463 DHD_OS_WAKE_UNLOCK(bus->dhd);
7467 /* Detach and free everything */
7469 dhdsdio_release(dhd_bus_t *bus, osl_t *osh)
7471 bool dongle_isolation = FALSE;
7472 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7478 dongle_isolation = bus->dhd->dongle_isolation;
7479 dhd_detach(bus->dhd);
7482 /* De-register interrupt handler */
7483 bcmsdh_intr_disable(bus->sdh);
7484 bcmsdh_intr_dereg(bus->sdh);
7487 dhdsdio_release_dongle(bus, osh, dongle_isolation, TRUE);
7492 dhdsdio_release_malloc(bus, osh);
7495 if (bus->console.buf != NULL)
7496 MFREE(osh, bus->console.buf, bus->console.bufsize);
7499 MFREE(osh, bus, sizeof(dhd_bus_t));
7503 dhd_osl_detach(osh);
7505 DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
7509 dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh)
7511 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7513 if (bus->dhd && bus->dhd->dongle_reset)
7517 #ifndef CONFIG_DHD_USE_STATIC_BUF
7518 MFREE(osh, bus->rxbuf, bus->rxblen);
7520 bus->rxctl = bus->rxbuf = NULL;
7525 #ifndef CONFIG_DHD_USE_STATIC_BUF
7526 MFREE(osh, bus->databuf, MAX_DATA_BUF);
7528 bus->databuf = NULL;
7531 if (bus->vars && bus->varsz) {
7532 MFREE(osh, bus->vars, bus->varsz);
7540 dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation, bool reset_flag)
7542 DHD_TRACE(("%s: Enter bus->dhd %p bus->dhd->dongle_reset %d \n", __FUNCTION__,
7543 bus->dhd, bus->dhd->dongle_reset));
7545 if ((bus->dhd && bus->dhd->dongle_reset) && reset_flag)
7549 #if !defined(BCMLXSDMMC)
7551 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
7553 if (KSO_ENAB(bus) && (dongle_isolation == FALSE))
7554 si_watchdog(bus->sih, 4);
7555 #endif /* !defined(BCMLXSDMMC) */
7557 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
7559 si_detach(bus->sih);
7561 if (bus->vars && bus->varsz)
7562 MFREE(osh, bus->vars, bus->varsz);
7566 DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
7570 dhdsdio_disconnect(void *ptr)
7572 dhd_bus_t *bus = (dhd_bus_t *)ptr;
7574 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7580 dhdsdio_release(bus, bus->dhd->osh);
7585 DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
7589 /* Register/Unregister functions are called by the main DHD entry
7590 * point (e.g. module insertion) to link with the bus driver, in
7591 * order to look for or await the device.
7594 static bcmsdh_driver_t dhd_sdio = {
7600 dhd_bus_register(void)
7602 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7604 return bcmsdh_register(&dhd_sdio);
7608 dhd_bus_unregister(void)
7610 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7612 bcmsdh_unregister();
7615 #if defined(BCMLXSDMMC)
7616 /* Register a dummy SDIO client driver in order to be notified of new SDIO device */
7617 int dhd_bus_reg_sdio_notify(void* semaphore)
7619 return bcmsdh_reg_sdio_notify(semaphore);
7622 void dhd_bus_unreg_sdio_notify(void)
7624 bcmsdh_unreg_sdio_notify();
7626 #endif /* defined(BCMLXSDMMC) */
7628 #ifdef BCMEMBEDIMAGE
7630 dhdsdio_download_code_array(struct dhd_bus *bus)
7634 unsigned char *ularray = NULL;
7636 DHD_INFO(("%s: download embedded firmware...\n", __FUNCTION__));
7638 /* Download image */
7639 while ((offset + MEMBLOCK) < sizeof(dlarray)) {
7641 if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
7642 /* if address is 0, store the reset instruction to be written in 0 */
7645 bus->resetinstr = *(((uint32*)dlarray));
7646 /* Add start of RAM address to the address given by user */
7647 offset += bus->dongle_ram_base;
7651 bcmerror = dhdsdio_membytes(bus, TRUE, offset,
7652 (uint8 *) (dlarray + offset), MEMBLOCK);
7654 DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
7655 __FUNCTION__, bcmerror, MEMBLOCK, offset));
7662 if (offset < sizeof(dlarray)) {
7663 bcmerror = dhdsdio_membytes(bus, TRUE, offset,
7664 (uint8 *) (dlarray + offset), sizeof(dlarray) - offset);
7666 DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
7667 __FUNCTION__, bcmerror, sizeof(dlarray) - offset, offset));
7673 /* Upload and compare the downloaded code */
7675 ularray = MALLOC(bus->dhd->osh, bus->ramsize);
7676 /* Upload image to verify downloaded contents. */
7678 memset(ularray, 0xaa, bus->ramsize);
7679 while ((offset + MEMBLOCK) < sizeof(dlarray)) {
7680 bcmerror = dhdsdio_membytes(bus, FALSE, offset, ularray + offset, MEMBLOCK);
7682 DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n",
7683 __FUNCTION__, bcmerror, MEMBLOCK, offset));
7690 if (offset < sizeof(dlarray)) {
7691 bcmerror = dhdsdio_membytes(bus, FALSE, offset,
7692 ularray + offset, sizeof(dlarray) - offset);
7694 DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n",
7695 __FUNCTION__, bcmerror, sizeof(dlarray) - offset, offset));
7700 if (memcmp(dlarray, ularray, sizeof(dlarray))) {
7701 DHD_ERROR(("%s: Downloaded image is corrupted (%s, %s, %s).\n",
7702 __FUNCTION__, dlimagename, dlimagever, dlimagedate));
7705 DHD_ERROR(("%s: Download, Upload and compare succeeded (%s, %s, %s).\n",
7706 __FUNCTION__, dlimagename, dlimagever, dlimagedate));
7709 #endif /* DHD_DEBUG */
7713 MFREE(bus->dhd->osh, ularray, bus->ramsize);
7716 #endif /* BCMEMBEDIMAGE */
7719 dhdsdio_download_code_file(struct dhd_bus *bus, char *pfw_path)
7725 uint8 *memblock = NULL, *memptr;
7727 DHD_INFO(("%s: download firmware %s\n", __FUNCTION__, pfw_path));
7729 image = dhd_os_open_image(pfw_path);
7733 memptr = memblock = MALLOC(bus->dhd->osh, MEMBLOCK + DHD_SDALIGN);
7734 if (memblock == NULL) {
7735 DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, MEMBLOCK));
7738 if ((uint32)(uintptr)memblock % DHD_SDALIGN)
7739 memptr += (DHD_SDALIGN - ((uint32)(uintptr)memblock % DHD_SDALIGN));
7741 /* Download image */
7742 while ((len = dhd_os_get_image_block((char*)memptr, MEMBLOCK, image))) {
7744 DHD_ERROR(("%s: dhd_os_get_image_block failed (%d)\n", __FUNCTION__, len));
7745 bcmerror = BCME_ERROR;
7749 if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
7750 /* if address is 0, store the reset instruction to be written in 0 */
7753 bus->resetinstr = *(((uint32*)memptr));
7754 /* Add start of RAM address to the address given by user */
7755 offset += bus->dongle_ram_base;
7759 bcmerror = dhdsdio_membytes(bus, TRUE, offset, memptr, len);
7761 DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
7762 __FUNCTION__, bcmerror, MEMBLOCK, offset));
7771 MFREE(bus->dhd->osh, memblock, MEMBLOCK + DHD_SDALIGN);
7774 dhd_os_close_image(image);
7780 EXAMPLE: nvram_array
7783 Use carriage return at the end of each assignment, and an empty string with
7784 carriage return at the end of array.
7787 unsigned char nvram_array[] = {"name1=value1\n", "name2=value2\n", "\n"};
7788 Hex values start with 0x, and mac addr format: xx:xx:xx:xx:xx:xx.
7790 Search "EXAMPLE: nvram_array" to see how the array is activated.
7794 dhd_bus_set_nvram_params(struct dhd_bus * bus, const char *nvram_params)
7796 bus->nvram_params = nvram_params;
7800 dhdsdio_download_nvram(struct dhd_bus *bus)
7804 void * image = NULL;
7805 char * memblock = NULL;
7808 bool nvram_file_exists;
7810 pnv_path = bus->nv_path;
7812 nvram_file_exists = ((pnv_path != NULL) && (pnv_path[0] != '\0'));
7813 if (!nvram_file_exists && (bus->nvram_params == NULL))
7816 if (nvram_file_exists) {
7817 image = dhd_os_open_image(pnv_path);
7822 memblock = MALLOC(bus->dhd->osh, MAX_NVRAMBUF_SIZE);
7823 if (memblock == NULL) {
7824 DHD_ERROR(("%s: Failed to allocate memory %d bytes\n",
7825 __FUNCTION__, MAX_NVRAMBUF_SIZE));
7829 /* Download variables */
7830 if (nvram_file_exists) {
7831 len = dhd_os_get_image_block(memblock, MAX_NVRAMBUF_SIZE, image);
7834 len = strlen(bus->nvram_params);
7835 ASSERT(len <= MAX_NVRAMBUF_SIZE);
7836 memcpy(memblock, bus->nvram_params, len);
7838 if (len > 0 && len < MAX_NVRAMBUF_SIZE) {
7839 bufp = (char *)memblock;
7841 len = process_nvram_vars(bufp, len);
7843 len += 4 - (len % 4);
7848 bcmerror = dhdsdio_downloadvars(bus, memblock, len + 1);
7850 DHD_ERROR(("%s: error downloading vars: %d\n",
7851 __FUNCTION__, bcmerror));
7855 DHD_ERROR(("%s: error reading nvram file: %d\n",
7856 __FUNCTION__, len));
7857 bcmerror = BCME_SDIO_ERROR;
7862 MFREE(bus->dhd->osh, memblock, MAX_NVRAMBUF_SIZE);
7865 dhd_os_close_image(image);
7870 #ifdef NV_BCM943341_WBFGN_MULTI_MODULE_SUPPORT
7872 BCM943341_INVALID = 0,
7879 dhdsdio_read_boardrev_cis(struct dhd_bus *bus)
7883 uint8 *cis_fn0 = NULL;
7884 uint16 boardrev = 0;
7888 osh = bus->dhd->osh;
7891 DHD_TRACE(("%s: Enter\n", __func__));
7893 cis_fn0 = MALLOC(osh, SBSDIO_CIS_SIZE_LIMIT);
7895 DHD_ERROR(("%s: cis_fn0 alloc failed\n", __func__));
7899 bzero(cis_fn0, SBSDIO_CIS_SIZE_LIMIT);
7901 err = bcmsdh_cis_read(sdh, 0, cis_fn0, SBSDIO_CIS_SIZE_LIMIT);
7904 DHD_ERROR(("%s: : cis_fn0 read failed, err: %d\n", __func__,
7910 while (idx < SBSDIO_CIS_SIZE_LIMIT) {
7911 uint8 tuple = cis_fn0[idx++];
7913 /* read tuple type */
7917 } else if (tuple == 0xff) {
7919 DHD_INFO(("CISTPL_END\n"));
7922 int offset = cis_fn0[idx++];
7923 uint8 type = cis_fn0[idx];
7925 if (tuple == 0x80) {
7926 /* Vendor Unique Tuple */
7929 DHD_INFO(("sromrev: 0x%02x\n",
7931 } else if (type == 0x02) {
7933 boardrev = *((uint16 *)&cis_fn0[idx+1]);
7934 DHD_INFO(("boardrev: 0x%04x\n",
7936 } else if (type == 0x1b) {
7938 DHD_INFO(("boardtype: 0x%04x\n",
7939 *((uint16 *)&cis_fn0[idx+1])));
7940 } else if (type == 0x19) {
7942 DHD_INFO(("mac address\n"));
7944 DHD_INFO(("Unk Unique Tuple:0x%02x\n",
7956 MFREE(osh, cis_fn0, SBSDIO_CIS_SIZE_LIMIT);
7962 dhdsdio_boardrev_bcm943341wbfgn(struct dhd_bus *bus)
7966 DHD_TRACE(("%s: Enter\n", __func__));
7968 switch (dhd_bus_chiprev_id(bus->dhd)) {
7969 case 0x0: /* a0/a1 */
7970 if (dhdsdio_read_boardrev_cis(bus) == 0x1303) {
7971 DHD_ERROR(("%s: BCM943341_WBFGN_3\n", __func__));
7972 boardrev = BCM943341_WBFGN_3;
7974 DHD_ERROR(("%s: BCM943341_WBFGN_2\n", __func__));
7975 boardrev = BCM943341_WBFGN_2;
7979 DHD_ERROR(("%s: BCM943341_WBFGN_4\n", __func__));
7980 boardrev = BCM943341_WBFGN_4;
7983 DHD_ERROR(("%s: Unknown board\n", __func__));
7984 boardrev = BCM943341_INVALID;
7990 #endif /* NV_BCM943341_WBFGN_MULTI_MODULE_SUPPORT */
7993 _dhdsdio_download_firmware(struct dhd_bus *bus)
7998 bool embed = FALSE; /* download embedded firmware */
7999 bool dlok = FALSE; /* download firmware succeeded */
8001 /* Out immediately if no image to download */
8002 if ((bus->fw_path == NULL) || (bus->fw_path[0] == '\0')) {
8003 #ifdef BCMEMBEDIMAGE
8010 #ifdef NV_BCM943341_WBFGN_MULTI_MODULE_SUPPORT
8011 if (dhd_bus_chip_id(bus->dhd) == BCM43341_CHIP_ID) {
8012 int boardrev = dhdsdio_boardrev_bcm943341wbfgn(bus);
8013 char *ptr = strstr(bus->nv_path, "nvram");
8014 DHD_ERROR(("nvram path: %s\n", ptr));
8017 case BCM943341_WBFGN_2:
8018 strcpy(ptr, "nvram.txt");
8020 case BCM943341_WBFGN_3:
8021 strcpy(ptr, "nvram_43341_rev3.txt");
8023 case BCM943341_WBFGN_4:
8024 strcpy(ptr, "nvram_43341_rev4.txt");
8027 DHD_ERROR(("%s:Unknown bcm943341_wbfgn board\n",
8032 DHD_ERROR(("%s: Invalid nv_path for bcm943341\n",
8037 if (strstr(bus->fw_path, "fw_bcmdhd_apsta")) { /* HOTSPOT mode */
8038 char *ptr_fw = strstr(bus->fw_path, "fw_bcmdhd_apsta");
8039 if (boardrev == BCM943341_WBFGN_2
8040 || boardrev == BCM943341_WBFGN_3) {
8041 strcpy(ptr_fw, "fw_bcmdhd_apsta_a0.bin");
8043 } else if (strstr(bus->fw_path, "fw_bcmdhd")) { /* STATION mode */
8044 char *ptr_fw = strstr(bus->fw_path, "fw_bcmdhd");
8045 if (boardrev == BCM943341_WBFGN_2
8046 || boardrev == BCM943341_WBFGN_3) {
8047 strcpy(ptr_fw, "fw_bcmdhd_a0.bin");
8050 DHD_ERROR(("%s: Invalid fw_path for bcm943341: %s\n",
8051 __func__, bus->fw_path));
8055 DHD_ERROR(("%s: Modified nv_path for bcm943341_wbfgn_x: %s\n",
8056 __func__, bus->nv_path));
8057 DHD_ERROR(("%s: Modified fw_path for bcm943341_wbfgn_x: %s\n",
8058 __func__, bus->fw_path));
8060 #endif /* NV_BCM943341_WBFGN_MULTI_MODULE_SUPPORT */
8062 /* Keep arm in reset */
8063 if (dhdsdio_download_state(bus, TRUE)) {
8064 DHD_ERROR(("%s: error placing ARM core in reset\n", __FUNCTION__));
8068 /* External image takes precedence if specified */
8069 if ((bus->fw_path != NULL) && (bus->fw_path[0] != '\0')) {
8070 if (dhdsdio_download_code_file(bus, bus->fw_path)) {
8071 DHD_ERROR(("%s: dongle image file download failed\n", __FUNCTION__));
8072 #ifdef BCMEMBEDIMAGE
8084 #ifdef BCMEMBEDIMAGE
8086 if (dhdsdio_download_code_array(bus)) {
8087 DHD_ERROR(("%s: dongle image array download failed\n", __FUNCTION__));
8095 BCM_REFERENCE(embed);
8098 DHD_ERROR(("%s: dongle image download failed\n", __FUNCTION__));
8102 /* EXAMPLE: nvram_array */
8103 /* If a valid nvram_arry is specified as above, it can be passed down to dongle */
8104 /* dhd_bus_set_nvram_params(bus, (char *)&nvram_array); */
8106 /* External nvram takes precedence if specified */
8107 if (dhdsdio_download_nvram(bus)) {
8108 DHD_ERROR(("%s: dongle nvram file download failed\n", __FUNCTION__));
8112 /* Take arm out of reset */
8113 if (dhdsdio_download_state(bus, FALSE)) {
8114 DHD_ERROR(("%s: error getting out of ARM core reset\n", __FUNCTION__));
8125 dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes,
8126 void *pkt, bcmsdh_cmplt_fn_t complete, void *handle)
8130 if (!KSO_ENAB(bus)) {
8131 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
8132 return BCME_NODEVICE;
8135 status = bcmsdh_recv_buf(bus->sdh, addr, fn, flags, buf, nbytes, pkt, complete, handle);
8141 dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes,
8142 void *pkt, bcmsdh_cmplt_fn_t complete, void *handle)
8144 if (!KSO_ENAB(bus)) {
8145 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
8146 return BCME_NODEVICE;
8149 return (bcmsdh_send_buf(bus->sdh, addr, fn, flags, buf, nbytes, pkt, complete, handle));
8152 #ifdef BCMSDIOH_TXGLOM
8154 dhd_bcmsdh_glom_post(dhd_bus_t *bus, uint8 *frame, void *pkt, uint len)
8156 bcmsdh_glom_post(bus->sdh, frame, pkt, len);
8160 dhd_bcmsdh_glom_clear(dhd_bus_t *bus)
8162 bcmsdh_glom_clear(bus->sdh);
8167 dhd_bus_chip(struct dhd_bus *bus)
8169 ASSERT(bus->sih != NULL);
8170 return bus->sih->chip;
8174 dhd_bus_pub(struct dhd_bus *bus)
8180 dhd_bus_txq(struct dhd_bus *bus)
8186 dhd_bus_hdrlen(struct dhd_bus *bus)
8188 return SDPCM_HDRLEN;
8192 dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag)
8200 if (!bus->dhd->dongle_reset) {
8201 dhd_os_sdlock(dhdp);
8202 dhd_os_wd_timer(dhdp, 0);
8203 #if !defined(IGNORE_ETH0_DOWN)
8204 /* Force flow control as protection when stop come before ifconfig_down */
8205 dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON);
8206 #endif /* !defined(IGNORE_ETH0_DOWN) */
8207 /* Expect app to have torn down any connection before calling */
8208 /* Stop the bus, disable F2 */
8209 dhd_bus_stop(bus, FALSE);
8211 #if defined(OOB_INTR_ONLY)
8212 /* Clean up any pending IRQ */
8213 bcmsdh_set_irq(FALSE);
8216 /* Clean tx/rx buffer pointers, detach from the dongle */
8217 dhdsdio_release_dongle(bus, bus->dhd->osh, TRUE, TRUE);
8219 bus->dhd->dongle_reset = TRUE;
8220 bus->dhd->up = FALSE;
8221 #ifdef BCMSDIOH_TXGLOM
8222 dhd_txglom_enable(dhdp, FALSE);
8224 dhd_os_sdunlock(dhdp);
8226 DHD_TRACE(("%s: WLAN OFF DONE\n", __FUNCTION__));
8227 /* App can now remove power from device */
8229 bcmerror = BCME_SDIO_ERROR;
8231 /* App must have restored power to device before calling */
8233 DHD_TRACE(("\n\n%s: == WLAN ON ==\n", __FUNCTION__));
8235 if (bus->dhd->dongle_reset) {
8238 dhd_os_sdlock(dhdp);
8239 #endif /* DHDTHREAD */
8240 /* Reset SD client */
8241 bcmsdh_reset(bus->sdh);
8243 /* Attempt to re-attach & download */
8244 if (dhdsdio_probe_attach(bus, bus->dhd->osh, bus->sdh,
8245 (uint32 *)SI_ENUM_BASE,
8247 /* Attempt to download binary to the dongle */
8248 if (dhdsdio_probe_init(bus, bus->dhd->osh, bus->sdh) &&
8249 dhdsdio_download_firmware(bus, bus->dhd->osh, bus->sdh)) {
8251 /* Re-init bus, enable F2 transfer */
8252 bcmerror = dhd_bus_init((dhd_pub_t *) bus->dhd, FALSE);
8253 if (bcmerror == BCME_OK) {
8254 #if defined(OOB_INTR_ONLY)
8255 /* make sure oob intr get registered */
8256 if (!bcmsdh_is_oob_intr_registered()) {
8257 sdioh_start(NULL, 1);
8258 bcmsdh_register_oob_intr(dhdp);
8262 bcmsdh_set_irq(TRUE);
8263 dhd_enable_oob_intr(bus, TRUE);
8266 bus->dhd->dongle_reset = FALSE;
8267 bus->dhd->up = TRUE;
8269 #if !defined(IGNORE_ETH0_DOWN)
8270 /* Restore flow control */
8271 dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF);
8273 dhd_os_wd_timer(dhdp, dhd_watchdog_ms);
8275 DHD_TRACE(("%s: WLAN ON DONE\n", __FUNCTION__));
8277 dhd_bus_stop(bus, FALSE);
8278 dhdsdio_release_dongle(bus, bus->dhd->osh,
8282 bcmerror = BCME_SDIO_ERROR;
8284 bcmerror = BCME_SDIO_ERROR;
8287 dhd_os_sdunlock(dhdp);
8288 #endif /* DHDTHREAD */
8290 bcmerror = BCME_SDIO_ERROR;
8291 DHD_INFO(("%s called when dongle is not in reset\n",
8293 DHD_INFO(("Will call dhd_bus_start instead\n"));
8294 sdioh_start(NULL, 1);
8295 if ((bcmerror = dhd_bus_start(dhdp)) != 0)
8296 DHD_ERROR(("%s: dhd_bus_start fail with %d\n",
8297 __FUNCTION__, bcmerror));
8303 /* Get Chip ID version */
8304 uint dhd_bus_chip_id(dhd_pub_t *dhdp)
8306 dhd_bus_t *bus = dhdp->bus;
8308 return bus->sih->chip;
8311 /* Get Chip Rev ID version */
8312 uint dhd_bus_chiprev_id(dhd_pub_t *dhdp)
8314 dhd_bus_t *bus = dhdp->bus;
8316 return bus->sih->chiprev;
8319 /* Get Chip Pkg ID version */
8320 uint dhd_bus_chippkg_id(dhd_pub_t *dhdp)
8322 dhd_bus_t *bus = dhdp->bus;
8324 return bus->sih->chippkg;
8327 dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint size)
8332 return dhdsdio_membytes(bus, set, address, data, size);
8336 dhd_enableOOB(dhd_pub_t *dhd, bool sleep)
8338 dhd_bus_t *bus = dhd->bus;
8339 sdpcmd_regs_t *regs = bus->regs;
8343 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
8344 /* Tell device to start using OOB wakeup */
8345 W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries);
8346 if (retries > retry_limit) {
8347 DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
8350 /* Turn off our contribution to the HT clock request */
8351 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
8353 /* Make sure the controller has the bus up */
8354 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
8356 /* Send misc interrupt to indicate OOB not needed */
8357 W_SDREG(0, ®s->tosbmailboxdata, retries);
8358 if (retries <= retry_limit)
8359 W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries);
8361 if (retries > retry_limit)
8362 DHD_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n"));
8364 /* Make sure we have SD bus access */
8365 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
8371 dhd_bus_pktq_flush(dhd_pub_t *dhdp)
8373 dhd_bus_t *bus = dhdp->bus;
8374 /* Clear the data packet queues */
8375 pktq_flush(dhdp->osh, &bus->txq, TRUE, NULL, 0);
8379 dhd_sr_config(dhd_pub_t *dhd, bool on)
8381 dhd_bus_t *bus = dhd->bus;
8386 return dhdsdio_clk_devsleep_iovar(bus, on);
8390 dhd_get_chipid(dhd_pub_t *dhd)
8392 dhd_bus_t *bus = dhd->bus;
8394 if (bus && bus->sih)
8395 return (uint16)bus->sih->chip;