2 * DHD Bus Module for SDIO
4 * $Copyright Open Broadcom Corporation$
6 * $Id: dhd_sdio.c 506046 2014-10-02 12:40:12Z $
14 #include BCMEMBEDIMAGE
15 #endif /* BCMEMBEDIMAGE */
19 #include <bcmendian.h>
26 #if defined(DHD_DEBUG)
27 #include <hnd_armtrap.h>
29 #endif /* defined(DHD_DEBUG) */
35 #include <sbsdpcmdev.h>
39 #include <proto/ethernet.h>
40 #include <proto/802.1d.h>
41 #include <proto/802.11.h>
43 #include <dngl_stats.h>
46 #include <dhd_proto.h>
50 #include <dhd_config.h>
55 #ifdef DHDTCPACK_SUPPRESS
57 #endif /* DHDTCPACK_SUPPRESS */
59 bool dhd_mp_halting(dhd_pub_t *dhdp);
60 extern void bcmsdh_waitfor_iodrain(void *sdh);
61 extern void bcmsdh_reject_ioreqs(void *sdh, bool reject);
62 extern bool bcmsdh_fatal_error(void *sdh);
64 #ifndef DHDSDIO_MEM_DUMP_FNAME
65 #define DHDSDIO_MEM_DUMP_FNAME "mem_dump"
68 #define QLEN (1024) /* bulk rx and tx queue lengths */
69 #define FCHI (QLEN - 10)
70 #define FCLOW (FCHI / 2)
73 #define TXRETRIES 2 /* # of retries for tx frames */
74 #define READ_FRM_CNT_RETRIES 3
76 #define DHD_RXBOUND 50 /* Default for max rx frames in one scheduling */
80 #define DHD_TXBOUND 20 /* Default for max tx frames in one scheduling */
83 #define DHD_TXMINMAX 1 /* Max tx frames if rx still pending */
85 #define MEMBLOCK 2048 /* Block size used for downloading of dongle image */
86 #define MAX_NVRAMBUF_SIZE 4096 /* max nvram buf size */
87 #define MAX_DATA_BUF (64 * 1024) /* Must be large enough to hold biggest possible glom */
90 #define DHD_FIRSTREAD 32
92 #if !ISPOWEROF2(DHD_FIRSTREAD)
93 #error DHD_FIRSTREAD is not a power of 2!
96 /* Total length of frame header for dongle protocol */
97 #define SDPCM_HDRLEN (SDPCM_FRAMETAG_LEN + SDPCM_SWHEADER_LEN)
98 #define SDPCM_HDRLEN_TXGLOM (SDPCM_HDRLEN + SDPCM_HWEXT_LEN)
99 #define MAX_TX_PKTCHAIN_CNT SDPCM_MAXGLOM_SIZE
102 #define SDPCM_RESERVE (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN)
104 #define SDPCM_RESERVE (SDPCM_HDRLEN + DHD_SDALIGN)
107 /* Space for header read, limit for data packets */
109 #define MAX_HDR_READ 32
111 #if !ISPOWEROF2(MAX_HDR_READ)
112 #error MAX_HDR_READ is not a power of 2!
115 #define MAX_RX_DATASZ 2048
117 /* Maximum milliseconds to wait for F2 to come up */
118 #define DHD_WAIT_F2RDY 3000
120 /* Bump up limit on waiting for HT to account for first startup;
121 * if the image is doing a CRC calculation before programming the PMU
122 * for HT availability, it could take a couple hundred ms more, so
123 * max out at a 1 second (1000000us).
125 #if (PMU_MAX_TRANSITION_DLY <= 1000000)
126 #undef PMU_MAX_TRANSITION_DLY
127 #define PMU_MAX_TRANSITION_DLY 1000000
130 /* hooks for limiting threshold custom tx num in rx processing */
131 #define DEFAULT_TXINRX_THRES 0
132 #ifndef CUSTOM_TXINRX_THRES
133 #define CUSTOM_TXINRX_THRES DEFAULT_TXINRX_THRES
136 /* Value for ChipClockCSR during initial setup */
137 #define DHD_INIT_CLKCTL1 (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ)
138 #define DHD_INIT_CLKCTL2 (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP)
140 /* Flags for SDH calls */
141 #define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED)
143 /* Packet free applicable unconditionally for sdio and sdspi. Conditional if
144 * bufpool was present for gspi bus.
146 #define PKTFREE2() if ((bus->bus != SPI_BUS) || bus->usebufpool) \
147 PKTFREE(bus->dhd->osh, pkt, FALSE);
148 DHD_SPINWAIT_SLEEP_INIT(sdioh_spinwait_sleep);
150 #if defined(MULTIPLE_SUPPLICANT)
151 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
152 DEFINE_MUTEX(_dhd_sdio_mutex_lock_);
153 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
157 /* Device console log buffer state */
158 #define CONSOLE_LINE_MAX 192
159 #define CONSOLE_BUFFER_MAX 2024
160 typedef struct dhd_console {
161 uint count; /* Poll interval msec counter */
162 uint log_addr; /* Log struct address (fixed) */
163 hnd_log_t log; /* Log struct (host copy) */
164 uint bufsize; /* Size of log buffer */
165 uint8 *buf; /* Log buffer (host copy) */
166 uint last; /* Last buffer read index */
168 #endif /* DHD_DEBUG */
170 #define REMAP_ENAB(bus) ((bus)->remap)
171 #define REMAP_ISADDR(bus, a) (((a) >= ((bus)->orig_ramsize)) && ((a) < ((bus)->ramsize)))
172 #define KSO_ENAB(bus) ((bus)->kso)
173 #define SR_ENAB(bus) ((bus)->_srenab)
174 #define SLPAUTO_ENAB(bus) ((SR_ENAB(bus)) && ((bus)->_slpauto))
175 #define MIN_RSRC_ADDR (SI_ENUM_BASE + 0x618)
176 #define MIN_RSRC_SR 0x3
177 #define CORE_CAPEXT_ADDR (SI_ENUM_BASE + 0x64c)
178 #define CORE_CAPEXT_SR_SUPPORTED_MASK (1 << 1)
179 #define RCTL_MACPHY_DISABLE_MASK (1 << 26)
180 #define RCTL_LOGIC_DISABLE_MASK (1 << 27)
182 #define OOB_WAKEUP_ENAB(bus) ((bus)->_oobwakeup)
183 #define GPIO_DEV_SRSTATE 16 /* Host gpio17 mapped to device gpio0 SR state */
184 #define GPIO_DEV_SRSTATE_TIMEOUT 320000 /* 320ms */
185 #define GPIO_DEV_WAKEUP 17 /* Host gpio17 mapped to device gpio1 wakeup */
186 #define CC_CHIPCTRL2_GPIO1_WAKEUP (1 << 0)
187 #define CC_CHIPCTRL3_SR_ENG_ENABLE (1 << 2)
188 #define OVERFLOW_BLKSZ512_WM 96
189 #define OVERFLOW_BLKSZ512_MES 80
191 #define CC_PMUCC3 (0x3)
192 /* Private data for SDIO bus interaction */
193 typedef struct dhd_bus {
196 bcmsdh_info_t *sdh; /* Handle for BCMSDH calls */
197 si_t *sih; /* Handle for SI calls */
198 char *vars; /* Variables (from CIS and/or other) */
199 uint varsz; /* Size of variables buffer */
200 uint32 sbaddr; /* Current SB window pointer (-1, invalid) */
202 sdpcmd_regs_t *regs; /* Registers for SDIO core */
203 uint sdpcmrev; /* SDIO core revision */
204 uint armrev; /* CPU core revision */
205 uint ramrev; /* SOCRAM core revision */
206 uint32 ramsize; /* Size of RAM in SOCRAM (bytes) */
207 uint32 orig_ramsize; /* Size of RAM in SOCRAM (bytes) */
208 uint32 srmemsize; /* Size of SRMEM */
210 uint32 bus; /* gSPI or SDIO bus */
211 uint32 bus_num; /* bus number */
212 uint32 slot_num; /* slot ID */
213 uint32 hostintmask; /* Copy of Host Interrupt Mask */
214 uint32 intstatus; /* Intstatus bits (events) pending */
215 bool dpc_sched; /* Indicates DPC schedule (intrpt rcvd) */
216 bool fcstate; /* State of dongle flow-control */
218 uint16 cl_devid; /* cached devid for dhdsdio_probe_attach() */
219 char *fw_path; /* module_param: path to firmware image */
220 char *nv_path; /* module_param: path to nvram vars file */
221 const char *nvram_params; /* user specified nvram params. */
223 uint blocksize; /* Block size of SDIO transfers */
224 uint roundup; /* Max roundup limit */
226 struct pktq txq; /* Queue length used for flow-control */
227 uint8 flowcontrol; /* per prio flow control bitmask */
228 uint8 tx_seq; /* Transmit sequence number (next) */
229 uint8 tx_max; /* Maximum transmit sequence allowed */
231 uint8 hdrbuf[MAX_HDR_READ + DHD_SDALIGN];
232 uint8 *rxhdr; /* Header of current rx frame (in hdrbuf) */
233 uint16 nextlen; /* Next Read Len from last header */
234 uint8 rx_seq; /* Receive sequence number (expected) */
235 bool rxskip; /* Skip receive (awaiting NAK ACK) */
237 void *glomd; /* Packet containing glomming descriptor */
238 void *glom; /* Packet chain for glommed superframe */
239 uint glomerr; /* Glom packet read errors */
241 uint8 *rxbuf; /* Buffer for receiving control packets */
242 uint rxblen; /* Allocated length of rxbuf */
243 uint8 *rxctl; /* Aligned pointer into rxbuf */
244 uint8 *databuf; /* Buffer for receiving big glom packet */
245 uint8 *dataptr; /* Aligned pointer into databuf */
246 uint rxlen; /* Length of valid data in buffer */
248 uint8 sdpcm_ver; /* Bus protocol reported by dongle */
250 bool intr; /* Use interrupts */
251 bool poll; /* Use polling */
252 bool ipend; /* Device interrupt is pending */
253 bool intdis; /* Interrupts disabled by isr */
254 uint intrcount; /* Count of device interrupt callbacks */
255 uint lastintrs; /* Count as of last watchdog timer */
256 uint spurious; /* Count of spurious interrupts */
257 uint pollrate; /* Ticks between device polls */
258 uint polltick; /* Tick counter */
259 uint pollcnt; /* Count of active polls */
262 dhd_console_t console; /* Console output polling support */
263 uint console_addr; /* Console address from shared struct */
264 #endif /* DHD_DEBUG */
266 uint regfails; /* Count of R_REG/W_REG failures */
268 uint clkstate; /* State of sd and backplane clock(s) */
269 bool activity; /* Activity flag for clock down */
270 int32 idletime; /* Control for activity timeout */
271 int32 idlecount; /* Activity timeout counter */
272 int32 idleclock; /* How to set bus driver when idle */
273 int32 sd_divisor; /* Speed control to bus driver */
274 int32 sd_mode; /* Mode control to bus driver */
275 int32 sd_rxchain; /* If bcmsdh api accepts PKT chains */
276 bool use_rxchain; /* If dhd should use PKT chains */
277 bool sleeping; /* Is SDIO bus sleeping? */
278 wait_queue_head_t bus_sleep;
279 uint rxflow_mode; /* Rx flow control mode */
280 bool rxflow; /* Is rx flow control on */
281 uint prev_rxlim_hit; /* Is prev rx limit exceeded (per dpc schedule) */
282 bool alp_only; /* Don't use HT clock (ALP only) */
283 /* Field to decide if rx of control frames happen in rxbuf or lb-pool */
285 int32 txinrx_thres; /* num of in-queued pkts */
286 int32 dotxinrx; /* tx first in dhdsdio_readframes */
288 /* external loopback */
292 /* pktgen configuration */
293 uint pktgen_freq; /* Ticks between bursts */
294 uint pktgen_count; /* Packets to send each burst */
295 uint pktgen_print; /* Bursts between count displays */
296 uint pktgen_total; /* Stop after this many */
297 uint pktgen_minlen; /* Minimum packet data len */
298 uint pktgen_maxlen; /* Maximum packet data len */
299 uint pktgen_mode; /* Configured mode: tx, rx, or echo */
300 uint pktgen_stop; /* Number of tx failures causing stop */
302 /* active pktgen fields */
303 uint pktgen_tick; /* Tick counter for bursts */
304 uint pktgen_ptick; /* Burst counter for printing */
305 uint pktgen_sent; /* Number of test packets generated */
306 uint pktgen_rcvd; /* Number of test packets received */
307 uint pktgen_prev_time; /* Time at which previous stats where printed */
308 uint pktgen_prev_sent; /* Number of test packets generated when
309 * previous stats were printed
311 uint pktgen_prev_rcvd; /* Number of test packets received when
312 * previous stats were printed
314 uint pktgen_fail; /* Number of failed send attempts */
315 uint16 pktgen_len; /* Length of next packet to send */
316 #define PKTGEN_RCV_IDLE (0)
317 #define PKTGEN_RCV_ONGOING (1)
318 uint16 pktgen_rcv_state; /* receive state */
319 uint pktgen_rcvd_rcvsession; /* test pkts rcvd per rcv session. */
322 /* Some additional counters */
323 uint tx_sderrs; /* Count of tx attempts with sd errors */
324 uint fcqueued; /* Tx packets that got queued */
325 uint rxrtx; /* Count of rtx requests (NAK to dongle) */
326 uint rx_toolong; /* Receive frames too long to receive */
327 uint rxc_errors; /* SDIO errors when reading control frames */
328 uint rx_hdrfail; /* SDIO errors on header reads */
329 uint rx_badhdr; /* Bad received headers (roosync?) */
330 uint rx_badseq; /* Mismatched rx sequence number */
331 uint fc_rcvd; /* Number of flow-control events received */
332 uint fc_xoff; /* Number which turned on flow-control */
333 uint fc_xon; /* Number which turned off flow-control */
334 uint rxglomfail; /* Failed deglom attempts */
335 uint rxglomframes; /* Number of glom frames (superframes) */
336 uint rxglompkts; /* Number of packets from glom frames */
337 uint f2rxhdrs; /* Number of header reads */
338 uint f2rxdata; /* Number of frame data reads */
339 uint f2txdata; /* Number of f2 frame writes */
340 uint f1regdata; /* Number of f1 register accesses */
341 #ifdef DHDENABLE_TAILPAD
342 uint tx_tailpad_chain; /* Number of tail padding by chaining pad_pkt */
343 uint tx_tailpad_pktget; /* Number of tail padding by new PKTGET */
344 #endif /* DHDENABLE_TAILPAD */
345 uint8 *ctrl_frame_buf;
346 uint32 ctrl_frame_len;
347 bool ctrl_frame_stat;
348 uint32 rxint_mode; /* rx interrupt mode */
349 bool remap; /* Contiguous 1MB RAM: 512K socram + 512K devram
350 * Available with socram rev 16
351 * Remap region not DMA-able
360 uint32 dongle_ram_base;
362 void *glom_pkt_arr[SDPCM_MAXGLOM_SIZE]; /* Array of pkts for glomming */
363 uint32 txglom_cnt; /* Number of pkts in the glom array */
364 uint32 txglom_total_len; /* Total length of pkts in glom array */
365 bool txglom_enable; /* Flag to indicate whether tx glom is enabled/disabled */
366 uint32 txglomsize; /* Glom size limitation */
367 #ifdef DHDENABLE_TAILPAD
369 #endif /* DHDENABLE_TAILPAD */
370 uint txglomframes; /* Number of tx glom frames (superframes) */
371 uint txglompkts; /* Number of packets from tx glom frames */
377 #define CLK_PENDING 2 /* Not used yet */
380 #define DHD_NOPMU(dhd) (FALSE)
383 static int qcount[NUMPRIO];
384 static int tx_packets[NUMPRIO];
385 #endif /* DHD_DEBUG */
387 /* Deferred transmit */
388 const uint dhd_deferred_tx = 1;
390 extern uint dhd_watchdog_ms;
392 extern void dhd_os_wd_timer(void *bus, uint wdtick);
397 uint dhd_txminmax = DHD_TXMINMAX;
399 /* override the RAM size if possible */
400 #define DONGLE_MIN_RAMSIZE (128 *1024)
401 int dhd_dongle_ramsize;
403 uint dhd_doflow = TRUE;
404 uint dhd_dpcpoll = FALSE;
406 module_param(dhd_doflow, uint, 0644);
407 module_param(dhd_dpcpoll, uint, 0644);
409 static bool dhd_alignctl;
413 static bool retrydata;
414 #define RETRYCHAN(chan) (((chan) == SDPCM_EVENT_CHANNEL) || retrydata)
416 static uint watermark = 8;
417 static uint mesbusyctrl = 0;
418 static const uint firstread = DHD_FIRSTREAD;
420 /* Retry count for register access failures */
421 static const uint retry_limit = 2;
423 /* Force even SD lengths (some host controllers mess up on odd bytes) */
424 static bool forcealign;
428 #if defined(OOB_INTR_ONLY) && defined(HW_OOB)
429 extern void bcmsdh_enable_hw_oob_intr(void *sdh, bool enable);
432 #if defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD)
433 #error OOB_INTR_ONLY is NOT working with SDIO_ISR_THREAD
434 #endif /* defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD) */
435 #define PKTALIGN(osh, p, len, align) \
438 datalign = (uintptr)PKTDATA((osh), (p)); \
439 datalign = ROUNDUP(datalign, (align)) - datalign; \
440 ASSERT(datalign < (align)); \
441 ASSERT(PKTLEN((osh), (p)) >= ((len) + datalign)); \
443 PKTPULL((osh), (p), (uint)datalign); \
444 PKTSETLEN((osh), (p), (len)); \
447 /* Limit on rounding up frames */
448 static const uint max_roundup = 512;
450 /* Try doing readahead */
451 static bool dhd_readahead;
453 /* To check if there's window offered */
454 #define DATAOK(bus) \
455 (((uint8)(bus->tx_max - bus->tx_seq) > 1) && \
456 (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0))
458 /* To check if there's window offered for ctrl frame */
459 #define TXCTLOK(bus) \
460 (((uint8)(bus->tx_max - bus->tx_seq) != 0) && \
461 (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0))
463 /* Number of pkts available in dongle for data RX */
464 #define DATABUFCNT(bus) \
465 ((uint8)(bus->tx_max - bus->tx_seq) - 1)
467 /* Macros to get register read/write status */
468 /* NOTE: these assume a local dhdsdio_bus_t *bus! */
469 #define R_SDREG(regvar, regaddr, retryvar) \
473 regvar = R_REG(bus->dhd->osh, regaddr); \
474 } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \
476 bus->regfails += (retryvar-1); \
477 if (retryvar > retry_limit) { \
478 DHD_ERROR(("%s: FAILED" #regvar "READ, LINE %d\n", \
479 __FUNCTION__, __LINE__)); \
485 #define W_SDREG(regval, regaddr, retryvar) \
489 W_REG(bus->dhd->osh, regaddr, regval); \
490 } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \
492 bus->regfails += (retryvar-1); \
493 if (retryvar > retry_limit) \
494 DHD_ERROR(("%s: FAILED REGISTER WRITE, LINE %d\n", \
495 __FUNCTION__, __LINE__)); \
499 #define BUS_WAKE(bus) \
501 bus->idlecount = 0; \
502 if ((bus)->sleeping) \
503 dhdsdio_bussleep((bus), FALSE); \
507 * pktavail interrupts from dongle to host can be managed in 3 different ways
508 * whenever there is a packet available in dongle to transmit to host.
510 * Mode 0: Dongle writes the software host mailbox and host is interrupted.
511 * Mode 1: (sdiod core rev >= 4)
512 * Device sets a new bit in the intstatus whenever there is a packet
513 * available in fifo. Host can't clear this specific status bit until all the
514 * packets are read from the FIFO. No need to ack dongle intstatus.
515 * Mode 2: (sdiod core rev >= 4)
516 * Device sets a bit in the intstatus, and host acks this by writing
517 * one to this bit. Dongle won't generate anymore packet interrupts
518 * until host reads all the packets from the dongle and reads a zero to
519 * figure that there are no more packets. No need to disable host ints.
520 * Need to ack the intstatus.
523 #define SDIO_DEVICE_HMB_RXINT 0 /* default old way */
524 #define SDIO_DEVICE_RXDATAINT_MODE_0 1 /* from sdiod rev 4 */
525 #define SDIO_DEVICE_RXDATAINT_MODE_1 2 /* from sdiod rev 4 */
528 #define FRAME_AVAIL_MASK(bus) \
529 ((bus->rxint_mode == SDIO_DEVICE_HMB_RXINT) ? I_HMB_FRAME_IND : I_XMTDATA_AVAIL)
531 #define DHD_BUS SDIO_BUS
533 #define PKT_AVAILABLE(bus, intstatus) ((intstatus) & (FRAME_AVAIL_MASK(bus)))
535 #define HOSTINTMASK (I_HMB_SW_MASK | I_CHIPACTIVE)
537 #define GSPI_PR55150_BAILOUT
540 static void dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq);
541 static void dhdsdio_sdtest_set(dhd_bus_t *bus, uint count);
545 static int dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size);
546 static int dhd_serialconsole(dhd_bus_t *bus, bool get, bool enable, int *bcmerror);
547 #endif /* DHD_DEBUG */
549 static int dhdsdio_devcap_set(dhd_bus_t *bus, uint8 cap);
550 static int dhdsdio_download_state(dhd_bus_t *bus, bool enter);
552 static void dhdsdio_release(dhd_bus_t *bus, osl_t *osh);
553 static void dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh);
554 static void dhdsdio_disconnect(void *ptr);
555 static bool dhdsdio_chipmatch(uint16 chipid);
556 static bool dhdsdio_probe_attach(dhd_bus_t *bus, osl_t *osh, void *sdh,
557 void * regsva, uint16 devid);
558 static bool dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh);
559 static bool dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh);
560 static void dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation,
563 static void dhd_dongle_setramsize(struct dhd_bus *bus, int mem_size);
564 static int dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags,
565 uint8 *buf, uint nbytes,
566 void *pkt, bcmsdh_cmplt_fn_t complete, void *handle);
567 static int dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags,
568 uint8 *buf, uint nbytes,
569 void *pkt, bcmsdh_cmplt_fn_t complete, void *handle, int max_retry);
570 static int dhdsdio_txpkt(dhd_bus_t *bus, uint chan, void** pkts, int num_pkt, bool free_pkt);
571 static int dhdsdio_txpkt_preprocess(dhd_bus_t *bus, void *pkt, int chan, int txseq,
572 int prev_chain_total_len, bool last_chained_pkt,
573 int *pad_pkt_len, void **new_pkt);
574 static int dhdsdio_txpkt_postprocess(dhd_bus_t *bus, void *pkt);
576 static int dhdsdio_download_firmware(dhd_bus_t *bus, osl_t *osh, void *sdh);
577 static int _dhdsdio_download_firmware(dhd_bus_t *bus);
579 static int dhdsdio_download_code_file(dhd_bus_t *bus, char *image_path);
580 static int dhdsdio_download_nvram(dhd_bus_t *bus);
582 static int dhdsdio_download_code_array(dhd_bus_t *bus);
584 static int dhdsdio_bussleep(dhd_bus_t *bus, bool sleep);
585 static int dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok);
586 static uint8 dhdsdio_sleepcsr_get(dhd_bus_t *bus);
590 extern uint32 dhd_get_htsf(void *dhd, int ifidx);
591 #endif /* WLMEDIA_HTSF */
594 dhdsdio_tune_fifoparam(struct dhd_bus *bus)
597 uint8 devctl, wm, mes;
599 if (bus->sih->buscorerev >= 15) {
600 /* See .ppt in PR for these recommended values */
601 if (bus->blocksize == 512) {
602 wm = OVERFLOW_BLKSZ512_WM;
603 mes = OVERFLOW_BLKSZ512_MES;
605 mes = bus->blocksize/4;
606 wm = bus->blocksize/4;
612 DHD_INFO(("skip fifotune: SdioRev(%d) is lower than minimal requested ver\n",
613 bus->sih->buscorerev));
617 /* Update watermark */
619 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, wm, &err);
621 devctl = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
622 devctl |= SBSDIO_DEVCTL_F2WM_ENAB;
623 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);
632 DHD_INFO(("Apply overflow WAR: 0x%02x 0x%02x 0x%02x\n",
633 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err),
634 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, &err),
635 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL, &err)));
639 dhd_dongle_setramsize(struct dhd_bus *bus, int mem_size)
641 int32 min_size = DONGLE_MIN_RAMSIZE;
642 /* Restrict the ramsize to user specified limit */
643 DHD_ERROR(("user: Restrict the dongle ram size to %d, min accepted %d\n",
644 dhd_dongle_ramsize, min_size));
645 if ((dhd_dongle_ramsize > min_size) &&
646 (dhd_dongle_ramsize < (int32)bus->orig_ramsize))
647 bus->ramsize = dhd_dongle_ramsize;
651 dhdsdio_set_siaddr_window(dhd_bus_t *bus, uint32 address)
654 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW,
655 (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err);
657 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID,
658 (address >> 16) & SBSDIO_SBADDRMID_MASK, &err);
660 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH,
661 (address >> 24) & SBSDIO_SBADDRHIGH_MASK, &err);
668 dhdsdio_oobwakeup_init(dhd_bus_t *bus)
670 uint32 val, addr, data;
672 bcmsdh_gpioouten(bus->sdh, GPIO_DEV_WAKEUP);
674 addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr);
675 data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data);
677 /* Set device for gpio1 wakeup */
678 bcmsdh_reg_write(bus->sdh, addr, 4, 2);
679 val = bcmsdh_reg_read(bus->sdh, data, 4);
680 val |= CC_CHIPCTRL2_GPIO1_WAKEUP;
681 bcmsdh_reg_write(bus->sdh, data, 4, val);
683 bus->_oobwakeup = TRUE;
687 #endif /* USE_OOB_GPIO1 */
690 * Query if FW is in SR mode
693 dhdsdio_sr_cap(dhd_bus_t *bus)
696 uint32 core_capext, addr, data;
698 if (bus->sih->chip == BCM43430_CHIP_ID) {
699 /* check if fw initialized sr engine */
700 addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, sr_control1);
701 if (bcmsdh_reg_read(bus->sdh, addr, 4) != 0)
706 if (bus->sih->chip == BCM4324_CHIP_ID) {
707 addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr);
708 data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data);
709 bcmsdh_reg_write(bus->sdh, addr, 4, 3);
710 core_capext = bcmsdh_reg_read(bus->sdh, data, 4);
711 } else if ((bus->sih->chip == BCM4330_CHIP_ID) ||
712 (bus->sih->chip == BCM43362_CHIP_ID)) {
714 } else if ((bus->sih->chip == BCM4335_CHIP_ID) ||
715 (bus->sih->chip == BCM4339_CHIP_ID) ||
716 (bus->sih->chip == BCM43349_CHIP_ID) ||
717 (bus->sih->chip == BCM4345_CHIP_ID) ||
718 (bus->sih->chip == BCM4354_CHIP_ID) ||
719 (bus->sih->chip == BCM4356_CHIP_ID) ||
720 (bus->sih->chip == BCM4358_CHIP_ID) ||
721 (bus->sih->chip == BCM4371_CHIP_ID) ||
722 (BCM4349_CHIP(bus->sih->chip)) ||
723 (bus->sih->chip == BCM4350_CHIP_ID)) {
726 core_capext = bcmsdh_reg_read(bus->sdh, CORE_CAPEXT_ADDR, 4);
727 core_capext = (core_capext & CORE_CAPEXT_SR_SUPPORTED_MASK);
732 if (bus->sih->chip == BCM4324_CHIP_ID) {
733 /* FIX: Should change to query SR control register instead */
735 } else if ((bus->sih->chip == BCM4335_CHIP_ID) ||
736 (bus->sih->chip == BCM4339_CHIP_ID) ||
737 (bus->sih->chip == BCM43349_CHIP_ID) ||
738 (bus->sih->chip == BCM4345_CHIP_ID) ||
739 (bus->sih->chip == BCM4354_CHIP_ID) ||
740 (bus->sih->chip == BCM4356_CHIP_ID) ||
741 (bus->sih->chip == BCM4358_CHIP_ID) ||
742 (bus->sih->chip == BCM4371_CHIP_ID) ||
743 (bus->sih->chip == BCM4350_CHIP_ID)) {
745 addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr);
746 data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data);
747 bcmsdh_reg_write(bus->sdh, addr, 4, CC_PMUCC3);
748 enabval = bcmsdh_reg_read(bus->sdh, data, 4);
750 if ((bus->sih->chip == BCM4350_CHIP_ID) ||
751 (bus->sih->chip == BCM4345_CHIP_ID) ||
752 (bus->sih->chip == BCM4354_CHIP_ID) ||
753 (bus->sih->chip == BCM4356_CHIP_ID) ||
754 (bus->sih->chip == BCM4358_CHIP_ID) ||
755 (bus->sih->chip == BCM4371_CHIP_ID))
756 enabval &= CC_CHIPCTRL3_SR_ENG_ENABLE;
761 data = bcmsdh_reg_read(bus->sdh,
762 SI_ENUM_BASE + OFFSETOF(chipcregs_t, retention_ctl), 4);
763 if ((data & (RCTL_MACPHY_DISABLE_MASK | RCTL_LOGIC_DISABLE_MASK)) == 0)
771 dhdsdio_srwar_init(dhd_bus_t *bus)
773 #if !defined(NDISVER) || (NDISVER < 0x0630)
774 bcmsdh_gpio_init(bus->sdh);
775 #endif /* !defined(NDISVER) || (NDISVER < 0x0630) */
778 dhdsdio_oobwakeup_init(bus);
786 dhdsdio_sr_init(dhd_bus_t *bus)
791 if ((bus->sih->chip == BCM4334_CHIP_ID) && (bus->sih->chiprev == 2))
792 dhdsdio_srwar_init(bus);
794 val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, NULL);
795 val |= 1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT;
796 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL,
797 1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT, &err);
798 val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, NULL);
801 /* Add CMD14 Support */
802 dhdsdio_devcap_set(bus,
803 (SDIOD_CCCR_BRCM_CARDCAP_CMD14_SUPPORT | SDIOD_CCCR_BRCM_CARDCAP_CMD14_EXT));
804 #endif /* USE_CMD14 */
806 dhdsdio_devcap_set(bus, SDIOD_CCCR_BRCM_CARDCAP_CMD_NODEC);
808 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1,
809 SBSDIO_FUNC1_CHIPCLKCSR, SBSDIO_FORCE_HT, &err);
811 bus->_slpauto = dhd_slpauto ? TRUE : FALSE;
819 * FIX: Be sure KSO bit is enabled
820 * Currently, it's defaulting to 0 which should be 1.
823 dhdsdio_clk_kso_init(dhd_bus_t *bus)
832 * Enable KeepSdioOn (KSO) bit for normal operation
833 * Default is 0 (4334A0) so set it. Fixed in B0.
835 val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, NULL);
836 if (!(val & SBSDIO_FUNC1_SLEEPCSR_KSO_MASK)) {
837 val |= (SBSDIO_FUNC1_SLEEPCSR_KSO_EN << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT);
838 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, val, &err);
840 DHD_ERROR(("%s: SBSDIO_FUNC1_SLEEPCSR err: 0x%x\n", __FUNCTION__, err));
847 #define KSO_WAIT_US 50
848 #define KSO_WAIT_MS 1
849 #define KSO_SLEEP_RETRY_COUNT 20
850 #define ERROR_BCME_NODEVICE_MAX 1
852 #define MAX_KSO_ATTEMPTS (PMU_MAX_TRANSITION_DLY/KSO_WAIT_US)
854 dhdsdio_clk_kso_enab(dhd_bus_t *bus, bool on)
856 uint8 wr_val = 0, rd_val, cmp_val, bmask;
860 if (!bus->dhd->conf->kso_enable)
863 KSO_DBG(("%s> op:%s\n", __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR")));
865 wr_val |= (on << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT);
867 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, wr_val, &err);
870 cmp_val = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK | SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK;
875 /* Put device to sleep, turn off KSO */
877 bmask = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK;
881 rd_val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, &err);
882 if (((rd_val & bmask) == cmp_val) && !err)
885 KSO_DBG(("%s> KSO wr/rd retry:%d, ERR:%x \n", __FUNCTION__, try_cnt, err));
887 if (((try_cnt + 1) % KSO_SLEEP_RETRY_COUNT) == 0) {
888 OSL_SLEEP(KSO_WAIT_MS);
890 OSL_DELAY(KSO_WAIT_US);
892 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, wr_val, &err);
893 } while (try_cnt++ < MAX_KSO_ATTEMPTS);
897 KSO_DBG(("%s> op:%s, try_cnt:%d, rd_val:%x, ERR:%x \n",
898 __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"), try_cnt, rd_val, err));
900 if (try_cnt > MAX_KSO_ATTEMPTS) {
901 DHD_ERROR(("%s> op:%s, ERROR: try_cnt:%d, rd_val:%x, ERR:%x \n",
902 __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"), try_cnt, rd_val, err));
908 dhdsdio_clk_kso_iovar(dhd_bus_t *bus, bool on)
915 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
917 DHD_ERROR(("%s: KSO disable clk: 0x%x\n", __FUNCTION__,
918 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
919 SBSDIO_FUNC1_CHIPCLKCSR, &err)));
920 dhdsdio_clk_kso_enab(bus, FALSE);
922 DHD_ERROR(("%s: KSO enable\n", __FUNCTION__));
924 /* Make sure we have SD bus access */
925 if (bus->clkstate == CLK_NONE) {
926 DHD_ERROR(("%s: Request SD clk\n", __FUNCTION__));
927 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
930 dhdsdio_clk_kso_enab(bus, TRUE);
932 DHD_ERROR(("%s: sleepcsr: 0x%x\n", __FUNCTION__,
933 dhdsdio_sleepcsr_get(bus)));
943 dhdsdio_sleepcsr_get(dhd_bus_t *bus)
948 val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, &err);
950 DHD_TRACE(("Failed to read SLEEPCSR: %d\n", err));
956 dhdsdio_devcap_get(dhd_bus_t *bus)
958 return bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_BRCM_CARDCAP, NULL);
962 dhdsdio_devcap_set(dhd_bus_t *bus, uint8 cap)
966 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_BRCM_CARDCAP, cap, &err);
968 DHD_ERROR(("%s: devcap set err: 0x%x\n", __FUNCTION__, err));
974 dhdsdio_clk_devsleep_iovar(dhd_bus_t *bus, bool on)
983 /* Be sure we request clk before going to sleep
984 * so we can wake-up with clk request already set
985 * else device can go back to sleep immediately
987 if (!SLPAUTO_ENAB(bus))
988 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
990 val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
991 if ((val & SBSDIO_CSR_MASK) == 0) {
992 DHD_ERROR(("%s: No clock before enter sleep:0x%x\n",
995 /* Reset clock request */
996 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
997 SBSDIO_ALP_AVAIL_REQ, &err);
998 DHD_ERROR(("%s: clock before sleep:0x%x\n", __FUNCTION__,
999 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
1000 SBSDIO_FUNC1_CHIPCLKCSR, &err)));
1004 DHD_TRACE(("%s: clk before sleep: 0x%x\n", __FUNCTION__,
1005 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
1006 SBSDIO_FUNC1_CHIPCLKCSR, &err)));
1008 err = bcmsdh_sleep(bus->sdh, TRUE);
1010 err = dhdsdio_clk_kso_enab(bus, FALSE);
1011 if (OOB_WAKEUP_ENAB(bus))
1013 #if !defined(NDISVER) || (NDISVER < 0x0630)
1014 err = bcmsdh_gpioout(bus->sdh, GPIO_DEV_WAKEUP, FALSE); /* GPIO_1 is off */
1015 #endif /* !defined(NDISVER) || (NDISVER < 0x0630) */
1017 #endif /* USE_CMD14 */
1020 /* Make sure we have SD bus access */
1021 if (bus->clkstate == CLK_NONE) {
1022 DHD_TRACE(("%s: Request SD clk\n", __FUNCTION__));
1023 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
1025 #if !defined(NDISVER) || (NDISVER < 0x0630)
1027 if ((bus->sih->chip == BCM4334_CHIP_ID) && (bus->sih->chiprev == 2)) {
1028 SPINWAIT_SLEEP(sdioh_spinwait_sleep,
1029 (bcmsdh_gpioin(bus->sdh, GPIO_DEV_SRSTATE) != TRUE),
1030 GPIO_DEV_SRSTATE_TIMEOUT);
1032 if (bcmsdh_gpioin(bus->sdh, GPIO_DEV_SRSTATE) == FALSE) {
1033 DHD_ERROR(("ERROR: GPIO_DEV_SRSTATE still low!\n"));
1038 err = bcmsdh_sleep(bus->sdh, FALSE);
1039 if (SLPAUTO_ENAB(bus) && (err != 0)) {
1041 DHD_TRACE(("%s: Resync device sleep\n", __FUNCTION__));
1043 /* Toggle sleep to resync with host and device */
1044 err = bcmsdh_sleep(bus->sdh, TRUE);
1046 err = bcmsdh_sleep(bus->sdh, FALSE);
1050 DHD_ERROR(("%s: CMD14 exit failed again!\n", __FUNCTION__));
1052 /* Toggle sleep to resync with host and device */
1053 err = bcmsdh_sleep(bus->sdh, TRUE);
1055 err = bcmsdh_sleep(bus->sdh, FALSE);
1057 DHD_ERROR(("%s: CMD14 exit failed twice!\n", __FUNCTION__));
1058 DHD_ERROR(("%s: FATAL: Device non-response!\n",
1065 if (OOB_WAKEUP_ENAB(bus))
1067 #if !defined(NDISVER) || (NDISVER < 0x0630)
1068 err = bcmsdh_gpioout(bus->sdh, GPIO_DEV_WAKEUP, TRUE); /* GPIO_1 is on */
1069 #endif /* !defined(NDISVER) || (NDISVER < 0x0630) */
1072 err = dhdsdio_clk_kso_enab(bus, TRUE);
1075 } while ((err != 0) && (++retry < 3));
1078 DHD_ERROR(("ERROR: kso set failed retry: %d\n", retry));
1079 err = 0; /* continue anyway */
1081 #endif /* !USE_CMD14 */
1086 /* Wait for device ready during transition to wake-up */
1087 SPINWAIT_SLEEP(sdioh_spinwait_sleep,
1088 (((csr = dhdsdio_sleepcsr_get(bus)) &
1089 SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK) !=
1090 (SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK)), (20000));
1092 DHD_TRACE(("%s: ExitSleep sleepcsr: 0x%x\n", __FUNCTION__, csr));
1094 if (!(csr & SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK)) {
1095 DHD_ERROR(("%s:ERROR: ExitSleep device NOT Ready! 0x%x\n",
1096 __FUNCTION__, csr));
1097 err = BCME_NODEVICE;
1100 SPINWAIT_SLEEP(sdioh_spinwait_sleep,
1101 (((csr = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
1102 SBSDIO_FUNC1_CHIPCLKCSR, &err)) & SBSDIO_HT_AVAIL) !=
1103 (SBSDIO_HT_AVAIL)), (10000));
1105 DHD_TRACE(("%s: SBSDIO_FUNC1_CHIPCLKCSR : 0x%x\n", __FUNCTION__, csr));
1106 if (!err && ((csr & SBSDIO_HT_AVAIL) != SBSDIO_HT_AVAIL)) {
1107 DHD_ERROR(("%s:ERROR: device NOT Ready! 0x%x\n",
1108 __FUNCTION__, csr));
1109 err = BCME_NODEVICE;
1114 /* Update if successful */
1116 bus->kso = on ? FALSE : TRUE;
1118 DHD_ERROR(("%s: Sleep request failed: kso:%d on:%d err:%d\n",
1119 __FUNCTION__, bus->kso, on, err));
1120 if (!on && retry > 2)
1127 /* Turn backplane clock on or off */
1129 dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok)
1131 #define HT_AVAIL_ERROR_MAX 10
1132 static int ht_avail_error = 0;
1134 uint8 clkctl, clkreq, devctl;
1137 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1146 if (SLPAUTO_ENAB(bus)) {
1147 bus->clkstate = (on ? CLK_AVAIL : CLK_SDONLY);
1152 /* Request HT Avail */
1153 clkreq = bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ;
1157 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
1160 if (ht_avail_error < HT_AVAIL_ERROR_MAX) {
1161 DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err));
1164 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
1165 else if (ht_avail_error == HT_AVAIL_ERROR_MAX) {
1166 dhd_os_send_hang_message(bus->dhd);
1168 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) */
1175 /* Check current status */
1176 clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
1178 DHD_ERROR(("%s: HT Avail read error: %d\n", __FUNCTION__, err));
1182 #if !defined(OOB_INTR_ONLY)
1183 /* Go to pending and await interrupt if appropriate */
1184 if (!SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) {
1185 /* Allow only clock-available interrupt */
1186 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
1188 DHD_ERROR(("%s: Devctl access error setting CA: %d\n",
1189 __FUNCTION__, err));
1193 devctl |= SBSDIO_DEVCTL_CA_INT_ONLY;
1194 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
1195 DHD_INFO(("CLKCTL: set PENDING\n"));
1196 bus->clkstate = CLK_PENDING;
1199 #endif /* !defined (OOB_INTR_ONLY) */
1201 if (bus->clkstate == CLK_PENDING) {
1202 /* Cancel CA-only interrupt filter */
1203 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
1204 devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
1205 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
1209 /* Otherwise, wait here (polling) for HT Avail */
1210 if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
1211 SPINWAIT_SLEEP(sdioh_spinwait_sleep,
1212 ((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
1213 SBSDIO_FUNC1_CHIPCLKCSR, &err)),
1214 !SBSDIO_CLKAV(clkctl, bus->alp_only)), PMU_MAX_TRANSITION_DLY);
1217 DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err));
1220 if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
1221 DHD_ERROR(("%s: HT Avail timeout (%d): clkctl 0x%02x\n",
1222 __FUNCTION__, PMU_MAX_TRANSITION_DLY, clkctl));
1226 /* Mark clock available */
1227 bus->clkstate = CLK_AVAIL;
1228 DHD_INFO(("CLKCTL: turned ON\n"));
1230 #if defined(DHD_DEBUG)
1231 if (bus->alp_only == TRUE) {
1232 #if !defined(BCMLXSDMMC)
1233 if (!SBSDIO_ALPONLY(clkctl)) {
1234 DHD_ERROR(("%s: HT Clock, when ALP Only\n", __FUNCTION__));
1236 #endif /* !defined(BCMLXSDMMC) */
1238 if (SBSDIO_ALPONLY(clkctl)) {
1239 DHD_ERROR(("%s: HT Clock should be on.\n", __FUNCTION__));
1242 #endif /* defined (DHD_DEBUG) */
1244 bus->activity = TRUE;
1245 #ifdef DHD_USE_IDLECOUNT
1247 #endif /* DHD_USE_IDLECOUNT */
1251 if (bus->clkstate == CLK_PENDING) {
1252 /* Cancel CA-only interrupt filter */
1253 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
1254 devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
1255 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
1258 bus->clkstate = CLK_SDONLY;
1259 if (!SR_ENAB(bus)) {
1260 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
1261 DHD_INFO(("CLKCTL: turned OFF\n"));
1263 DHD_ERROR(("%s: Failed access turning clock off: %d\n",
1264 __FUNCTION__, err));
1272 /* Change idle/active SD state */
1274 dhdsdio_sdclk(dhd_bus_t *bus, bool on)
1279 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1282 if (bus->idleclock == DHD_IDLE_STOP) {
1283 /* Turn on clock and restore mode */
1285 err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0,
1286 &iovalue, sizeof(iovalue), TRUE);
1288 DHD_ERROR(("%s: error enabling sd_clock: %d\n",
1289 __FUNCTION__, err));
1293 iovalue = bus->sd_mode;
1294 err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
1295 &iovalue, sizeof(iovalue), TRUE);
1297 DHD_ERROR(("%s: error changing sd_mode: %d\n",
1298 __FUNCTION__, err));
1301 } else if (bus->idleclock != DHD_IDLE_ACTIVE) {
1302 /* Restore clock speed */
1303 iovalue = bus->sd_divisor;
1304 err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
1305 &iovalue, sizeof(iovalue), TRUE);
1307 DHD_ERROR(("%s: error restoring sd_divisor: %d\n",
1308 __FUNCTION__, err));
1312 bus->clkstate = CLK_SDONLY;
1314 /* Stop or slow the SD clock itself */
1315 if ((bus->sd_divisor == -1) || (bus->sd_mode == -1)) {
1316 DHD_TRACE(("%s: can't idle clock, divisor %d mode %d\n",
1317 __FUNCTION__, bus->sd_divisor, bus->sd_mode));
1320 if (bus->idleclock == DHD_IDLE_STOP) {
1322 /* Change to SD1 mode and turn off clock */
1324 err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
1325 &iovalue, sizeof(iovalue), TRUE);
1327 DHD_ERROR(("%s: error changing sd_clock: %d\n",
1328 __FUNCTION__, err));
1334 err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0,
1335 &iovalue, sizeof(iovalue), TRUE);
1337 DHD_ERROR(("%s: error disabling sd_clock: %d\n",
1338 __FUNCTION__, err));
1341 } else if (bus->idleclock != DHD_IDLE_ACTIVE) {
1342 /* Set divisor to idle value */
1343 iovalue = bus->idleclock;
1344 err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
1345 &iovalue, sizeof(iovalue), TRUE);
1347 DHD_ERROR(("%s: error changing sd_divisor: %d\n",
1348 __FUNCTION__, err));
1352 bus->clkstate = CLK_NONE;
1358 /* Transition SD and backplane clock readiness */
1360 dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok)
1364 uint oldstate = bus->clkstate;
1365 #endif /* DHD_DEBUG */
1367 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1369 /* Early exit if we're already there */
1370 if (bus->clkstate == target) {
1371 if (target == CLK_AVAIL) {
1372 dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
1373 bus->activity = TRUE;
1374 #ifdef DHD_USE_IDLECOUNT
1376 #endif /* DHD_USE_IDLECOUNT */
1383 /* Make sure SD clock is available */
1384 if (bus->clkstate == CLK_NONE)
1385 dhdsdio_sdclk(bus, TRUE);
1386 /* Now request HT Avail on the backplane */
1387 ret = dhdsdio_htclk(bus, TRUE, pendok);
1388 if (ret == BCME_OK) {
1389 dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
1390 bus->activity = TRUE;
1391 #ifdef DHD_USE_IDLECOUNT
1393 #endif /* DHD_USE_IDLECOUNT */
1398 /* Remove HT request, or bring up SD clock */
1399 if (bus->clkstate == CLK_NONE)
1400 ret = dhdsdio_sdclk(bus, TRUE);
1401 else if (bus->clkstate == CLK_AVAIL)
1402 ret = dhdsdio_htclk(bus, FALSE, FALSE);
1404 DHD_ERROR(("dhdsdio_clkctl: request for %d -> %d\n",
1405 bus->clkstate, target));
1406 if (ret == BCME_OK) {
1407 dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
1412 /* Make sure to remove HT request */
1413 if (bus->clkstate == CLK_AVAIL)
1414 ret = dhdsdio_htclk(bus, FALSE, FALSE);
1415 /* Now remove the SD clock */
1416 ret = dhdsdio_sdclk(bus, FALSE);
1418 if (dhd_console_ms == 0)
1419 #endif /* DHD_DEBUG */
1421 dhd_os_wd_timer(bus->dhd, 0);
1425 DHD_INFO(("dhdsdio_clkctl: %d -> %d\n", oldstate, bus->clkstate));
1426 #endif /* DHD_DEBUG */
1432 dhdsdio_bussleep(dhd_bus_t *bus, bool sleep)
1435 bcmsdh_info_t *sdh = bus->sdh;
1436 sdpcmd_regs_t *regs = bus->regs;
1439 DHD_INFO(("dhdsdio_bussleep: request %s (currently %s)\n",
1440 (sleep ? "SLEEP" : "WAKE"),
1441 (bus->sleeping ? "SLEEP" : "WAKE")));
1443 if (bus->dhd->hang_was_sent)
1446 /* Done if we're already in the requested state */
1447 if (sleep == bus->sleeping)
1450 /* Going to sleep: set the alarm and turn off the lights... */
1452 /* Don't sleep if something is pending */
1453 if (bus->dpc_sched || bus->rxskip || pktq_len(&bus->txq))
1457 if (!SLPAUTO_ENAB(bus)) {
1458 /* Disable SDIO interrupts (no longer interested) */
1459 bcmsdh_intr_disable(bus->sdh);
1461 /* Make sure the controller has the bus up */
1462 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
1464 /* Tell device to start using OOB wakeup */
1465 W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries);
1466 if (retries > retry_limit)
1467 DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
1469 /* Turn off our contribution to the HT clock request */
1470 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
1472 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
1473 SBSDIO_FORCE_HW_CLKREQ_OFF, NULL);
1475 /* Isolate the bus */
1476 if (bus->sih->chip != BCM4329_CHIP_ID &&
1477 bus->sih->chip != BCM4319_CHIP_ID) {
1478 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL,
1479 SBSDIO_DEVCTL_PADS_ISO, NULL);
1482 /* Leave interrupts enabled since device can exit sleep and
1485 err = dhdsdio_clk_devsleep_iovar(bus, TRUE /* sleep */);
1489 bus->sleeping = TRUE;
1490 wake_up(&bus->bus_sleep);
1492 /* Waking up: bus power up is ok, set local state */
1494 if (!SLPAUTO_ENAB(bus)) {
1495 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0, &err);
1497 /* Force pad isolation off if possible (in case power never toggled) */
1498 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, 0, NULL);
1501 /* Make sure the controller has the bus up */
1502 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
1504 /* Send misc interrupt to indicate OOB not needed */
1505 W_SDREG(0, ®s->tosbmailboxdata, retries);
1506 if (retries <= retry_limit)
1507 W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries);
1509 if (retries > retry_limit)
1510 DHD_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n"));
1512 /* Make sure we have SD bus access */
1513 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
1515 /* Enable interrupts again */
1516 if (bus->intr && (bus->dhd->busstate == DHD_BUS_DATA)) {
1517 bus->intdis = FALSE;
1518 bcmsdh_intr_enable(bus->sdh);
1521 err = dhdsdio_clk_devsleep_iovar(bus, FALSE /* wake */);
1526 bus->sleeping = FALSE;
1534 #if defined(OOB_INTR_ONLY)
1536 dhd_enable_oob_intr(struct dhd_bus *bus, bool enable)
1539 bcmsdh_enable_hw_oob_intr(bus->sdh, enable);
1541 sdpcmd_regs_t *regs = bus->regs;
1544 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
1545 if (enable == TRUE) {
1547 /* Tell device to start using OOB wakeup */
1548 W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries);
1549 if (retries > retry_limit)
1550 DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
1553 /* Send misc interrupt to indicate OOB not needed */
1554 W_SDREG(0, ®s->tosbmailboxdata, retries);
1555 if (retries <= retry_limit)
1556 W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries);
1559 /* Turn off our contribution to the HT clock request */
1560 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
1561 #endif /* !defined(HW_OOB) */
1566 dhd_bus_txdata(struct dhd_bus *bus, void *pkt)
1568 int ret = BCME_ERROR;
1572 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1574 osh = bus->dhd->osh;
1575 datalen = PKTLEN(osh, pkt);
1578 /* Push the test header if doing loopback */
1579 if (bus->ext_loop) {
1581 PKTPUSH(osh, pkt, SDPCM_TEST_HDRLEN);
1582 data = PKTDATA(osh, pkt);
1583 *data++ = SDPCM_TEST_ECHOREQ;
1584 *data++ = (uint8)bus->loopid++;
1585 *data++ = (datalen >> 0);
1586 *data++ = (datalen >> 8);
1587 datalen += SDPCM_TEST_HDRLEN;
1590 BCM_REFERENCE(datalen);
1593 prec = PRIO2PREC((PKTPRIO(pkt) & PRIOMASK));
1595 /* Check for existing queue, current flow-control, pending event, or pending clock */
1596 if (dhd_deferred_tx || bus->fcstate || pktq_len(&bus->txq) || bus->dpc_sched ||
1597 (!DATAOK(bus)) || (bus->flowcontrol & NBITVAL(prec)) ||
1598 (bus->clkstate != CLK_AVAIL)) {
1602 DHD_TRACE(("%s: deferring pktq len %d\n", __FUNCTION__, pktq_len(&bus->txq)));
1605 /* Priority based enq */
1606 dhd_os_sdlock_txq(bus->dhd);
1607 deq_ret = dhd_prec_enq(bus->dhd, &bus->txq, pkt, prec);
1608 dhd_os_sdunlock_txq(bus->dhd);
1611 #ifdef PROP_TXSTATUS
1612 if (DHD_PKTTAG_WLFCPKT(PKTTAG(pkt)) == 0)
1613 #endif /* PROP_TXSTATUS */
1615 #ifdef DHDTCPACK_SUPPRESS
1616 if (dhd_tcpack_check_xmit(bus->dhd, pkt) == BCME_ERROR) {
1617 DHD_ERROR(("%s %d: tcpack_suppress ERROR!!! Stop using\n",
1618 __FUNCTION__, __LINE__));
1619 dhd_tcpack_suppress_set(bus->dhd, TCPACK_SUP_OFF);
1621 #endif /* DHDTCPACK_SUPPRESS */
1622 dhd_txcomplete(bus->dhd, pkt, FALSE);
1623 PKTFREE(osh, pkt, TRUE);
1625 ret = BCME_NORESOURCE;
1629 dhd_os_sdlock_txq(bus->dhd);
1630 pkq_len = pktq_len(&bus->txq);
1631 dhd_os_sdunlock_txq(bus->dhd);
1632 if (pkq_len >= FCHI) {
1633 bool wlfc_enabled = FALSE;
1634 #ifdef PROP_TXSTATUS
1635 wlfc_enabled = (dhd_wlfc_flowcontrol(bus->dhd, ON, FALSE) !=
1638 if (!wlfc_enabled && dhd_doflow) {
1639 dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON);
1644 dhd_os_sdlock_txq(bus->dhd);
1645 if (pktq_plen(&bus->txq, prec) > qcount[prec])
1646 qcount[prec] = pktq_plen(&bus->txq, prec);
1647 dhd_os_sdunlock_txq(bus->dhd);
1650 /* Schedule DPC if needed to send queued packet(s) */
1651 if (dhd_deferred_tx && !bus->dpc_sched) {
1652 bus->dpc_sched = TRUE;
1653 dhd_sched_dpc(bus->dhd);
1656 int chan = SDPCM_DATA_CHANNEL;
1659 chan = (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL);
1661 /* Lock: we're about to use shared data/code (and SDIO) */
1662 dhd_os_sdlock(bus->dhd);
1664 /* Otherwise, send it now */
1666 /* Make sure back plane ht clk is on, no pending allowed */
1667 dhdsdio_clkctl(bus, CLK_AVAIL, TRUE);
1669 ret = dhdsdio_txpkt(bus, chan, &pkt, 1, TRUE);
1672 bus->dhd->tx_errors++;
1674 bus->dhd->dstats.tx_bytes += datalen;
1676 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
1677 bus->activity = FALSE;
1678 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
1681 dhd_os_sdunlock(bus->dhd);
1687 /* align packet data pointer and packet length to n-byte boundary, process packet headers,
1688 * a new packet may be allocated if there is not enough head and/or tail from for padding.
1689 * the caller is responsible for updating the glom size in the head packet (when glom is
1692 * pad_pkt_len: returns the length of extra padding needed from the padding packet, this parameter
1693 * is taken in tx glom mode only
1695 * new_pkt: out, pointer of the new packet allocated due to insufficient head room for alignment
1696 * padding, NULL if not needed, the caller is responsible for freeing the new packet
1698 * return: positive value - length of the packet, including head and tail padding
1699 * negative value - errors
1701 static int dhdsdio_txpkt_preprocess(dhd_bus_t *bus, void *pkt, int chan, int txseq,
1702 int prev_chain_total_len, bool last_chained_pkt,
1703 int *pad_pkt_len, void **new_pkt)
1710 int tail_padding = 0;
1712 uint32 swhdr_offset;
1713 bool alloc_new_pkt = FALSE;
1714 uint8 sdpcm_hdrlen = bus->txglom_enable ? SDPCM_HDRLEN_TXGLOM : SDPCM_HDRLEN;
1717 osh = bus->dhd->osh;
1719 #ifdef DHDTCPACK_SUPPRESS
1720 if (dhd_tcpack_check_xmit(bus->dhd, pkt) == BCME_ERROR) {
1721 DHD_ERROR(("%s %d: tcpack_suppress ERROR!!! Stop using it\n",
1722 __FUNCTION__, __LINE__));
1723 dhd_tcpack_suppress_set(bus->dhd, TCPACK_SUP_OFF);
1725 #endif /* DHDTCPACK_SUPPRESS */
1727 /* Add space for the SDPCM hardware/software headers */
1728 PKTPUSH(osh, pkt, sdpcm_hdrlen);
1729 ASSERT(ISALIGNED((uintptr)PKTDATA(osh, pkt), 2));
1731 frame = (uint8*)PKTDATA(osh, pkt);
1732 pkt_len = (uint16)PKTLEN(osh, pkt);
1735 frame = (uint8*)PKTDATA(osh, pkt);
1736 if (PKTLEN(osh, pkt) >= 100) {
1737 htsf_ts = (htsfts_t*) (frame + HTSF_HOSTOFFSET + 12);
1738 if (htsf_ts->magic == HTSFMAGIC) {
1739 htsf_ts->c20 = get_cycles();
1740 htsf_ts->t20 = dhd_get_htsf(bus->dhd->info, 0);
1743 #endif /* WLMEDIA_HTSF */
1745 if (PKTPRIO(pkt) < ARRAYSIZE(tx_packets))
1746 tx_packets[PKTPRIO(pkt)]++;
1747 #endif /* DHD_DEBUG */
1749 /* align the data pointer, allocate a new packet if there is not enough space (new
1750 * packet data pointer will be aligned thus no padding will be needed)
1752 head_padding = (ulong)frame % DHD_SDALIGN;
1753 if (PKTHEADROOM(osh, pkt) < head_padding) {
1755 alloc_new_pkt = TRUE;
1757 uint cur_chain_total_len;
1758 int chain_tail_padding = 0;
1760 /* All packets need to be aligned by DHD_SDALIGN */
1761 modulo = (pkt_len + head_padding) % DHD_SDALIGN;
1762 tail_padding = modulo > 0 ? (DHD_SDALIGN - modulo) : 0;
1764 /* Total pkt chain length needs to be aligned by block size,
1765 * unless it is a single pkt chain with total length less than one block size,
1766 * which we prefer sending by byte mode.
1768 * Do the chain alignment here if
1769 * 1. This is the last pkt of the chain of multiple pkts or a single pkt.
1770 * 2-1. This chain is of multiple pkts, or
1771 * 2-2. This is a single pkt whose size is longer than one block size.
1773 cur_chain_total_len = prev_chain_total_len +
1774 (head_padding + pkt_len + tail_padding);
1775 if (last_chained_pkt && bus->blocksize != 0 &&
1776 (cur_chain_total_len > (int)bus->blocksize || prev_chain_total_len > 0)) {
1777 modulo = cur_chain_total_len % bus->blocksize;
1778 chain_tail_padding = modulo > 0 ? (bus->blocksize - modulo) : 0;
1781 #ifdef DHDENABLE_TAILPAD
1782 if (PKTTAILROOM(osh, pkt) < tail_padding) {
1783 /* We don't have tail room to align by DHD_SDALIGN */
1784 alloc_new_pkt = TRUE;
1785 bus->tx_tailpad_pktget++;
1786 } else if (PKTTAILROOM(osh, pkt) < tail_padding + chain_tail_padding) {
1787 /* We have tail room for tail_padding of this pkt itself, but not for
1788 * total pkt chain alignment by block size.
1789 * Use the padding packet to avoid memory copy if applicable,
1790 * otherwise, just allocate a new pkt.
1793 *pad_pkt_len = chain_tail_padding;
1794 bus->tx_tailpad_chain++;
1796 alloc_new_pkt = TRUE;
1797 bus->tx_tailpad_pktget++;
1800 /* This last pkt's tailroom is sufficient to hold both tail_padding
1801 * of the pkt itself and chain_tail_padding of total pkt chain
1803 #endif /* DHDENABLE_TAILPAD */
1804 tail_padding += chain_tail_padding;
1807 DHD_INFO(("%s sdhdr len + orig_pkt_len %d h_pad %d t_pad %d pad_pkt_len %d\n",
1808 __FUNCTION__, pkt_len, head_padding, tail_padding, *pad_pkt_len));
1810 if (alloc_new_pkt) {
1815 ASSERT(*pad_pkt_len == 0);
1817 DHD_INFO(("%s allocating new packet for padding\n", __FUNCTION__));
1819 /* head pointer is aligned now, no padding needed */
1822 /* update the tail padding as it depends on the head padding, since a new packet is
1823 * allocated, the head padding is non longer needed and packet length is chagned
1826 cur_total_len = prev_chain_total_len + pkt_len;
1827 if (last_chained_pkt && bus->blocksize != 0 &&
1828 (cur_total_len > (int)bus->blocksize || prev_chain_total_len > 0)) {
1829 modulo = cur_total_len % bus->blocksize;
1830 tail_padding = modulo > 0 ? (bus->blocksize - modulo) : 0;
1833 modulo = pkt_len % DHD_SDALIGN;
1834 tail_padding = modulo > 0 ? (DHD_SDALIGN - modulo) : 0;
1837 newpkt_size = PKTLEN(osh, pkt) + bus->blocksize + DHD_SDALIGN;
1838 bus->dhd->tx_realloc++;
1839 tmp_pkt = PKTGET(osh, newpkt_size, TRUE);
1840 if (tmp_pkt == NULL) {
1841 DHD_ERROR(("failed to alloc new %d byte packet\n", newpkt_size));
1844 PKTALIGN(osh, tmp_pkt, PKTLEN(osh, pkt), DHD_SDALIGN);
1845 bcopy(PKTDATA(osh, pkt), PKTDATA(osh, tmp_pkt), PKTLEN(osh, pkt));
1851 PKTPUSH(osh, pkt, head_padding);
1853 frame = (uint8*)PKTDATA(osh, pkt);
1854 bzero(frame, head_padding + sdpcm_hdrlen);
1855 pkt_len = (uint16)PKTLEN(osh, pkt);
1857 /* the header has the followming format
1858 * 4-byte HW frame tag: length, ~length (for glom this is the total length)
1860 * 8-byte HW extesion flags (glom mode only) as the following:
1861 * 2-byte packet length, excluding HW tag and padding
1862 * 2-byte frame channel and frame flags (e.g. next frame following)
1863 * 2-byte header length
1864 * 2-byte tail padding size
1866 * 8-byte SW frame tags as the following
1867 * 4-byte flags: host tx seq, channel, data offset
1871 swhdr_offset = SDPCM_FRAMETAG_LEN;
1873 /* hardware frame tag:
1875 * in tx-glom mode, dongle only checks the hardware frame tag in the first
1876 * packet and sees it as the total lenght of the glom (including tail padding),
1877 * for each packet in the glom, the packet length needs to be updated, (see
1880 * in non tx-glom mode, PKTLEN still need to include tail padding as to be
1881 * referred to in sdioh_request_buffer(). The tail length will be excluded in
1882 * dhdsdio_txpkt_postprocess().
1884 *(uint16*)frame = (uint16)htol16(pkt_len);
1885 *(((uint16*)frame) + 1) = (uint16)htol16(~pkt_len);
1886 pkt_len += tail_padding;
1888 /* hardware extesion flags */
1889 if (bus->txglom_enable) {
1893 swhdr_offset += SDPCM_HWEXT_LEN;
1894 hwheader1 = (pkt_len - SDPCM_FRAMETAG_LEN - tail_padding) |
1895 (last_chained_pkt << 24);
1896 hwheader2 = (tail_padding) << 16;
1897 htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN);
1898 htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4);
1900 PKTSETLEN((osh), (pkt), (pkt_len));
1902 /* software frame tags */
1903 swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK)
1904 | (txseq % SDPCM_SEQUENCE_WRAP) |
1905 (((head_padding + sdpcm_hdrlen) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
1906 htol32_ua_store(swheader, frame + swhdr_offset);
1907 htol32_ua_store(0, frame + swhdr_offset + sizeof(swheader));
1912 static int dhdsdio_txpkt_postprocess(dhd_bus_t *bus, void *pkt)
1918 int swhdr_offset = SDPCM_FRAMETAG_LEN + (bus->txglom_enable ? SDPCM_HWEXT_LEN : 0);
1921 osh = bus->dhd->osh;
1923 /* restore pkt buffer pointer, but keeps the header pushed by dhd_prot_hdrpush */
1924 frame = (uint8*)PKTDATA(osh, pkt);
1926 DHD_INFO(("%s PKTLEN before postprocess %d",
1927 __FUNCTION__, PKTLEN(osh, pkt)));
1929 /* PKTLEN still includes tail_padding, so exclude it.
1930 * We shall have head_padding + original pkt_len for PKTLEN afterwards.
1932 if (bus->txglom_enable) {
1933 /* txglom pkts have tail_padding length in HW ext header */
1934 tail_padding = ltoh32_ua(frame + SDPCM_FRAMETAG_LEN + 4) >> 16;
1935 PKTSETLEN(osh, pkt, PKTLEN(osh, pkt) - tail_padding);
1936 DHD_INFO((" txglom pkt: tail_padding %d PKTLEN %d\n",
1937 tail_padding, PKTLEN(osh, pkt)));
1939 /* non-txglom pkts have head_padding + original pkt length in HW frame tag.
1940 * We cannot refer to this field for txglom pkts as the first pkt of the chain will
1941 * have the field for the total length of the chain.
1943 PKTSETLEN(osh, pkt, *(uint16*)frame);
1944 DHD_INFO((" non-txglom pkt: HW frame tag len %d after PKTLEN %d\n",
1945 *(uint16*)frame, PKTLEN(osh, pkt)));
1948 data_offset = ltoh32_ua(frame + swhdr_offset);
1949 data_offset = (data_offset & SDPCM_DOFFSET_MASK) >> SDPCM_DOFFSET_SHIFT;
1950 /* Get rid of sdpcm header + head_padding */
1951 PKTPULL(osh, pkt, data_offset);
1953 DHD_INFO(("%s data_offset %d, PKTLEN %d\n",
1954 __FUNCTION__, data_offset, PKTLEN(osh, pkt)));
1959 static int dhdsdio_txpkt(dhd_bus_t *bus, uint chan, void** pkts, int num_pkt, bool free_pkt)
1968 void *head_pkt = NULL;
1969 void *prev_pkt = NULL;
1970 int pad_pkt_len = 0;
1971 int new_pkt_num = 0;
1972 void *new_pkts[MAX_TX_PKTCHAIN_CNT];
1973 bool wlfc_enabled = FALSE;
1975 if (bus->dhd->dongle_reset)
1976 return BCME_NOTREADY;
1979 osh = bus->dhd->osh;
1980 /* init new_pkts[0] to make some compiler happy, not necessary as we check new_pkt_num */
1983 for (i = 0; i < num_pkt; i++) {
1986 void *new_pkt = NULL;
1990 last_pkt = (i == num_pkt - 1);
1991 pkt_len = dhdsdio_txpkt_preprocess(bus, pkt, chan, bus->tx_seq + i,
1992 total_len, last_pkt, &pad_pkt_len, &new_pkt);
1997 new_pkts[new_pkt_num++] = new_pkt;
1999 total_len += pkt_len;
2001 PKTSETNEXT(osh, pkt, NULL);
2002 /* insert the packet into the list */
2003 head_pkt ? PKTSETNEXT(osh, prev_pkt, pkt) : (head_pkt = pkt);
2008 /* Update the HW frame tag (total length) in the first pkt of the glom */
2009 if (bus->txglom_enable) {
2012 total_len += pad_pkt_len;
2013 frame = (uint8*)PKTDATA(osh, head_pkt);
2014 *(uint16*)frame = (uint16)htol16(total_len);
2015 *(((uint16*)frame) + 1) = (uint16)htol16(~total_len);
2019 #ifdef DHDENABLE_TAILPAD
2020 /* if a padding packet if needed, insert it to the end of the link list */
2022 PKTSETLEN(osh, bus->pad_pkt, pad_pkt_len);
2023 PKTSETNEXT(osh, pkt, bus->pad_pkt);
2025 #endif /* DHDENABLE_TAILPAD */
2027 /* dhd_bcmsdh_send_buf ignores the buffer pointer if he packet
2028 * parameter is not NULL, for non packet chian we pass NULL pkt pointer
2029 * so it will take the aligned length and buffer pointer.
2031 pkt_chain = PKTNEXT(osh, head_pkt) ? head_pkt : NULL;
2032 ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
2033 PKTDATA(osh, head_pkt), total_len, pkt_chain, NULL, NULL, TXRETRIES);
2035 bus->tx_seq = (bus->tx_seq + num_pkt) % SDPCM_SEQUENCE_WRAP;
2037 /* if a padding packet was needed, remove it from the link list as it not a data pkt */
2038 if (pad_pkt_len && pkt)
2039 PKTSETNEXT(osh, pkt, NULL);
2044 void *pkt_next = PKTNEXT(osh, pkt);
2045 PKTSETNEXT(osh, pkt, NULL);
2046 dhdsdio_txpkt_postprocess(bus, pkt);
2050 /* new packets might be allocated due to insufficient room for padding, but we
2051 * still have to indicate the original packets to upper layer
2053 for (i = 0; i < num_pkt; i++) {
2055 wlfc_enabled = FALSE;
2056 #ifdef PROP_TXSTATUS
2057 if (DHD_PKTTAG_WLFCPKT(PKTTAG(pkt))) {
2058 wlfc_enabled = (dhd_wlfc_txcomplete(bus->dhd, pkt, ret == 0) !=
2061 #endif /* PROP_TXSTATUS */
2062 if (!wlfc_enabled) {
2063 PKTSETNEXT(osh, pkt, NULL);
2064 dhd_txcomplete(bus->dhd, pkt, ret != 0);
2066 PKTFREE(osh, pkt, TRUE);
2070 for (i = 0; i < new_pkt_num; i++)
2071 PKTFREE(osh, new_pkts[i], TRUE);
2077 dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes)
2081 uint16 txpktqlen = 0;
2082 uint32 intstatus = 0;
2086 dhd_pub_t *dhd = bus->dhd;
2087 sdpcmd_regs_t *regs = bus->regs;
2089 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2091 if (!KSO_ENAB(bus)) {
2092 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
2093 return BCME_NODEVICE;
2097 tx_prec_map = ~bus->flowcontrol;
2098 for (cnt = 0; (cnt < maxframes) && DATAOK(bus);) {
2101 void *pkts[MAX_TX_PKTCHAIN_CNT];
2104 dhd_os_sdlock_txq(bus->dhd);
2105 if (bus->txglom_enable) {
2106 num_pkt = MIN((uint32)DATABUFCNT(bus), (uint32)bus->txglomsize);
2107 num_pkt = MIN(num_pkt, ARRAYSIZE(pkts));
2109 num_pkt = MIN(num_pkt, pktq_mlen(&bus->txq, tx_prec_map));
2110 for (i = 0; i < num_pkt; i++) {
2111 pkts[i] = pktq_mdeq(&bus->txq, ~bus->flowcontrol, &prec_out);
2113 DHD_ERROR(("%s: pktq_mlen non-zero when no pkt\n",
2119 datalen += PKTLEN(osh, pkts[i]);
2121 dhd_os_sdunlock_txq(bus->dhd);
2125 if (dhdsdio_txpkt(bus, SDPCM_DATA_CHANNEL, pkts, i, TRUE) != BCME_OK)
2128 dhd->dstats.tx_bytes += datalen;
2129 bus->txglomframes++;
2130 bus->txglompkts += num_pkt;
2134 /* In poll mode, need to check for other events */
2135 if (!bus->intr && cnt)
2137 /* Check device status, signal pending interrupt */
2138 R_SDREG(intstatus, ®s->intstatus, retries);
2140 if (bcmsdh_regfail(bus->sdh))
2142 if (intstatus & bus->hostintmask)
2148 dhd_os_sdlock_txq(bus->dhd);
2149 txpktqlen = pktq_len(&bus->txq);
2150 dhd_os_sdunlock_txq(bus->dhd);
2152 /* Do flow-control if needed */
2153 if (dhd->up && (dhd->busstate == DHD_BUS_DATA) && (txpktqlen < FCLOW)) {
2154 bool wlfc_enabled = FALSE;
2155 #ifdef PROP_TXSTATUS
2156 wlfc_enabled = (dhd_wlfc_flowcontrol(dhd, OFF, TRUE) != WLFC_UNSUPPORTED);
2158 if (!wlfc_enabled && dhd_doflow && dhd->txoff) {
2159 dhd_txflowcontrol(dhd, ALL_INTERFACES, OFF);
2167 dhdsdio_sendpendctl(dhd_bus_t *bus)
2169 bcmsdh_info_t *sdh = bus->sdh;
2171 uint8* frame_seq = bus->ctrl_frame_buf + SDPCM_FRAMETAG_LEN;
2173 if (bus->txglom_enable)
2174 frame_seq += SDPCM_HWEXT_LEN;
2176 if (*frame_seq != bus->tx_seq) {
2177 DHD_INFO(("%s IOCTL frame seq lag detected!"
2178 " frm_seq:%d != bus->tx_seq:%d, corrected\n",
2179 __FUNCTION__, *frame_seq, bus->tx_seq));
2180 *frame_seq = bus->tx_seq;
2183 ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
2184 (uint8 *)bus->ctrl_frame_buf, (uint32)bus->ctrl_frame_len,
2185 NULL, NULL, NULL, 1);
2187 bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
2189 bus->ctrl_frame_stat = FALSE;
2190 dhd_wait_event_wakeup(bus->dhd);
2194 dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen)
2196 static int err_nodevice = 0;
2200 bcmsdh_info_t *sdh = bus->sdh;
2203 uint8 sdpcm_hdrlen = bus->txglom_enable ? SDPCM_HDRLEN_TXGLOM : SDPCM_HDRLEN;
2205 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2207 if (bus->dhd->dongle_reset)
2210 /* Back the pointer to make a room for bus header */
2211 frame = msg - sdpcm_hdrlen;
2212 len = (msglen += sdpcm_hdrlen);
2214 /* Add alignment padding (optional for ctl frames) */
2216 if ((doff = ((uintptr)frame % DHD_SDALIGN))) {
2220 bzero(frame, doff + sdpcm_hdrlen);
2222 ASSERT(doff < DHD_SDALIGN);
2224 doff += sdpcm_hdrlen;
2226 /* Round send length to next SDIO block */
2227 if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
2228 uint16 pad = bus->blocksize - (len % bus->blocksize);
2229 if ((pad <= bus->roundup) && (pad < bus->blocksize))
2231 } else if (len % DHD_SDALIGN) {
2232 len += DHD_SDALIGN - (len % DHD_SDALIGN);
2235 /* Satisfy length-alignment requirements */
2236 if (forcealign && (len & (ALIGNMENT - 1)))
2237 len = ROUNDUP(len, ALIGNMENT);
2239 ASSERT(ISALIGNED((uintptr)frame, 2));
2242 /* Need to lock here to protect txseq and SDIO tx calls */
2243 dhd_os_sdlock(bus->dhd);
2247 /* Make sure backplane clock is on */
2248 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
2250 /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
2251 *(uint16*)frame = htol16((uint16)msglen);
2252 *(((uint16*)frame) + 1) = htol16(~msglen);
2254 if (bus->txglom_enable) {
2255 uint32 hwheader1, hwheader2;
2256 /* Software tag: channel, sequence number, data offset */
2257 swheader = ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK)
2259 | ((doff << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
2260 htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN);
2261 htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN
2262 + SDPCM_HWEXT_LEN + sizeof(swheader));
2264 hwheader1 = (msglen - SDPCM_FRAMETAG_LEN) | (1 << 24);
2265 hwheader2 = (len - (msglen)) << 16;
2266 htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN);
2267 htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4);
2269 *(uint16*)frame = htol16(len);
2270 *(((uint16*)frame) + 1) = htol16(~(len));
2272 /* Software tag: channel, sequence number, data offset */
2273 swheader = ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK)
2274 | bus->tx_seq | ((doff << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
2275 htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN);
2276 htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
2278 if (!TXCTLOK(bus)) {
2279 DHD_INFO(("%s: No bus credit bus->tx_max %d, bus->tx_seq %d\n",
2280 __FUNCTION__, bus->tx_max, bus->tx_seq));
2281 bus->ctrl_frame_stat = TRUE;
2283 bus->ctrl_frame_buf = frame;
2284 bus->ctrl_frame_len = len;
2286 if (!bus->dpc_sched) {
2287 bus->dpc_sched = TRUE;
2288 dhd_sched_dpc(bus->dhd);
2290 if (bus->ctrl_frame_stat) {
2291 dhd_wait_for_event(bus->dhd, &bus->ctrl_frame_stat);
2294 if (bus->ctrl_frame_stat == FALSE) {
2295 DHD_INFO(("%s: ctrl_frame_stat == FALSE\n", __FUNCTION__));
2298 bus->dhd->txcnt_timeout++;
2299 if (!bus->dhd->hang_was_sent) {
2300 DHD_ERROR(("%s: ctrl_frame_stat == TRUE txcnt_timeout=%d\n",
2301 __FUNCTION__, bus->dhd->txcnt_timeout));
2304 bus->ctrl_frame_stat = FALSE;
2309 bus->dhd->txcnt_timeout = 0;
2310 bus->ctrl_frame_stat = TRUE;
2314 if (DHD_BYTES_ON() && DHD_CTL_ON()) {
2315 prhex("Tx Frame", frame, len);
2316 } else if (DHD_HDRS_ON()) {
2317 prhex("TxHdr", frame, MIN(len, 16));
2320 ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
2321 frame, len, NULL, NULL, NULL, TXRETRIES);
2323 bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
2325 bus->ctrl_frame_stat = FALSE;
2328 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
2329 bus->activity = FALSE;
2330 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
2333 dhd_os_sdunlock(bus->dhd);
2336 bus->dhd->tx_ctlerrs++;
2338 bus->dhd->tx_ctlpkts++;
2340 if (bus->dhd->txcnt_timeout >= MAX_CNTL_TX_TIMEOUT)
2343 if (ret == BCME_NODEVICE)
2348 return ret ? err_nodevice >= ERROR_BCME_NODEVICE_MAX ? -ETIMEDOUT : -EIO : 0;
2352 dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen)
2358 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2360 if (bus->dhd->dongle_reset)
2363 /* Wait until control frame is available */
2364 timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->rxlen, &pending);
2366 dhd_os_sdlock(bus->dhd);
2368 bcopy(bus->rxctl, msg, MIN(msglen, rxlen));
2370 dhd_os_sdunlock(bus->dhd);
2373 DHD_CTL(("%s: resumed on rxctl frame, got %d expected %d\n",
2374 __FUNCTION__, rxlen, msglen));
2375 } else if (timeleft == 0) {
2377 uint32 status, retry = 0;
2378 R_SDREG(status, &bus->regs->intstatus, retry);
2379 DHD_ERROR(("%s: resumed on timeout, INT status=0x%08X\n",
2380 __FUNCTION__, status));
2382 DHD_ERROR(("%s: resumed on timeout\n", __FUNCTION__));
2383 #endif /* DHD_DEBUG */
2385 dhd_os_sdlock(bus->dhd);
2386 dhdsdio_checkdied(bus, NULL, 0);
2387 dhd_os_sdunlock(bus->dhd);
2388 #endif /* DHD_DEBUG */
2389 } else if (pending == TRUE) {
2390 /* signal pending */
2391 DHD_ERROR(("%s: signal pending\n", __FUNCTION__));
2395 DHD_CTL(("%s: resumed for unknown reason?\n", __FUNCTION__));
2397 dhd_os_sdlock(bus->dhd);
2398 dhdsdio_checkdied(bus, NULL, 0);
2399 dhd_os_sdunlock(bus->dhd);
2400 #endif /* DHD_DEBUG */
2402 if (timeleft == 0) {
2404 bus->dhd->rxcnt_timeout++;
2405 DHD_ERROR(("%s: rxcnt_timeout=%d, rxlen=%d\n", __FUNCTION__,
2406 bus->dhd->rxcnt_timeout, rxlen));
2409 bus->dhd->rxcnt_timeout = 0;
2412 bus->dhd->rx_ctlpkts++;
2414 bus->dhd->rx_ctlerrs++;
2416 if (bus->dhd->rxcnt_timeout >= MAX_CNTL_RX_TIMEOUT)
2419 if (bus->dhd->dongle_trap_occured)
2422 return rxlen ? (int)rxlen : -EIO;
2438 #endif /* DHD_DEBUG */
2439 IOV_SET_DOWNLOAD_STATE,
2449 #if defined(USE_SDIOFIFO_IOVAR)
2452 #endif /* USE_SDIOFIFO_IOVAR */
2465 IOV_DONGLEISOLATION,
2479 const bcm_iovar_t dhdsdio_iovars[] = {
2480 {"intr", IOV_INTR, 0, IOVT_BOOL, 0 },
2481 {"sleep", IOV_SLEEP, 0, IOVT_BOOL, 0 },
2482 {"pollrate", IOV_POLLRATE, 0, IOVT_UINT32, 0 },
2483 {"idletime", IOV_IDLETIME, 0, IOVT_INT32, 0 },
2484 {"idleclock", IOV_IDLECLOCK, 0, IOVT_INT32, 0 },
2485 {"sd1idle", IOV_SD1IDLE, 0, IOVT_BOOL, 0 },
2486 {"membytes", IOV_MEMBYTES, 0, IOVT_BUFFER, 2 * sizeof(int) },
2487 {"ramsize", IOV_RAMSIZE, 0, IOVT_UINT32, 0 },
2488 {"ramstart", IOV_RAMSTART, 0, IOVT_UINT32, 0 },
2489 {"dwnldstate", IOV_SET_DOWNLOAD_STATE, 0, IOVT_BOOL, 0 },
2490 {"socram_state", IOV_SOCRAM_STATE, 0, IOVT_BOOL, 0 },
2491 {"vars", IOV_VARS, 0, IOVT_BUFFER, 0 },
2492 {"sdiod_drive", IOV_SDIOD_DRIVE, 0, IOVT_UINT32, 0 },
2493 {"readahead", IOV_READAHEAD, 0, IOVT_BOOL, 0 },
2494 {"sdrxchain", IOV_SDRXCHAIN, 0, IOVT_BOOL, 0 },
2495 {"alignctl", IOV_ALIGNCTL, 0, IOVT_BOOL, 0 },
2496 {"sdalign", IOV_SDALIGN, 0, IOVT_BOOL, 0 },
2497 {"devreset", IOV_DEVRESET, 0, IOVT_BOOL, 0 },
2499 {"sdreg", IOV_SDREG, 0, IOVT_BUFFER, sizeof(sdreg_t) },
2500 {"sbreg", IOV_SBREG, 0, IOVT_BUFFER, sizeof(sdreg_t) },
2501 {"sd_cis", IOV_SDCIS, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN },
2502 {"forcealign", IOV_FORCEEVEN, 0, IOVT_BOOL, 0 },
2503 {"txbound", IOV_TXBOUND, 0, IOVT_UINT32, 0 },
2504 {"rxbound", IOV_RXBOUND, 0, IOVT_UINT32, 0 },
2505 {"txminmax", IOV_TXMINMAX, 0, IOVT_UINT32, 0 },
2506 {"cpu", IOV_CPU, 0, IOVT_BOOL, 0 },
2508 {"checkdied", IOV_CHECKDIED, 0, IOVT_BUFFER, 0 },
2509 {"serial", IOV_SERIALCONS, 0, IOVT_UINT32, 0 },
2510 #endif /* DHD_DEBUG */
2511 #endif /* DHD_DEBUG */
2513 {"extloop", IOV_EXTLOOP, 0, IOVT_BOOL, 0 },
2514 {"pktgen", IOV_PKTGEN, 0, IOVT_BUFFER, sizeof(dhd_pktgen_t) },
2516 #if defined(USE_SDIOFIFO_IOVAR)
2517 {"watermark", IOV_WATERMARK, 0, IOVT_UINT32, 0 },
2518 {"mesbusyctrl", IOV_MESBUSYCTRL, 0, IOVT_UINT32, 0 },
2519 #endif /* USE_SDIOFIFO_IOVAR */
2520 {"devcap", IOV_DEVCAP, 0, IOVT_UINT32, 0 },
2521 {"dngl_isolation", IOV_DONGLEISOLATION, 0, IOVT_UINT32, 0 },
2522 {"kso", IOV_KSO, 0, IOVT_UINT32, 0 },
2523 {"devsleep", IOV_DEVSLEEP, 0, IOVT_UINT32, 0 },
2525 {"fwpath", IOV_FWPATH, 0, IOVT_BUFFER, 0 },
2527 {"txglomsize", IOV_TXGLOMSIZE, 0, IOVT_UINT32, 0 },
2528 {"fw_hang_report", IOV_HANGREPORT, 0, IOVT_BOOL, 0 },
2529 {"txinrx_thres", IOV_TXINRX_THRES, 0, IOVT_INT32, 0 },
2534 dhd_dump_pct(struct bcmstrbuf *strbuf, char *desc, uint num, uint div)
2539 bcm_bprintf(strbuf, "%s N/A", desc);
2542 q2 = (100 * (num - (q1 * div))) / div;
2543 bcm_bprintf(strbuf, "%s %d.%02d", desc, q1, q2);
2548 dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf)
2550 dhd_bus_t *bus = dhdp->bus;
2552 bcm_bprintf(strbuf, "Bus SDIO structure:\n");
2553 bcm_bprintf(strbuf, "hostintmask 0x%08x intstatus 0x%08x sdpcm_ver %d\n",
2554 bus->hostintmask, bus->intstatus, bus->sdpcm_ver);
2555 bcm_bprintf(strbuf, "fcstate %d qlen %u tx_seq %d, max %d, rxskip %d rxlen %u rx_seq %d\n",
2556 bus->fcstate, pktq_len(&bus->txq), bus->tx_seq, bus->tx_max, bus->rxskip,
2557 bus->rxlen, bus->rx_seq);
2558 bcm_bprintf(strbuf, "intr %d intrcount %u lastintrs %u spurious %u\n",
2559 bus->intr, bus->intrcount, bus->lastintrs, bus->spurious);
2560 bcm_bprintf(strbuf, "pollrate %u pollcnt %u regfails %u\n",
2561 bus->pollrate, bus->pollcnt, bus->regfails);
2563 bcm_bprintf(strbuf, "\nAdditional counters:\n");
2564 #ifdef DHDENABLE_TAILPAD
2565 bcm_bprintf(strbuf, "tx_tailpad_chain %u tx_tailpad_pktget %u\n",
2566 bus->tx_tailpad_chain, bus->tx_tailpad_pktget);
2567 #endif /* DHDENABLE_TAILPAD */
2568 bcm_bprintf(strbuf, "tx_sderrs %u fcqueued %u rxrtx %u rx_toolong %u rxc_errors %u\n",
2569 bus->tx_sderrs, bus->fcqueued, bus->rxrtx, bus->rx_toolong,
2571 bcm_bprintf(strbuf, "rx_hdrfail %u badhdr %u badseq %u\n",
2572 bus->rx_hdrfail, bus->rx_badhdr, bus->rx_badseq);
2573 bcm_bprintf(strbuf, "fc_rcvd %u, fc_xoff %u, fc_xon %u\n",
2574 bus->fc_rcvd, bus->fc_xoff, bus->fc_xon);
2575 bcm_bprintf(strbuf, "rxglomfail %u, rxglomframes %u, rxglompkts %u\n",
2576 bus->rxglomfail, bus->rxglomframes, bus->rxglompkts);
2577 bcm_bprintf(strbuf, "f2rx (hdrs/data) %u (%u/%u), f2tx %u f1regs %u\n",
2578 (bus->f2rxhdrs + bus->f2rxdata), bus->f2rxhdrs, bus->f2rxdata,
2579 bus->f2txdata, bus->f1regdata);
2581 dhd_dump_pct(strbuf, "\nRx: pkts/f2rd", bus->dhd->rx_packets,
2582 (bus->f2rxhdrs + bus->f2rxdata));
2583 dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->rx_packets, bus->f1regdata);
2584 dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->rx_packets,
2585 (bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata));
2586 dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->rx_packets, bus->intrcount);
2587 bcm_bprintf(strbuf, "\n");
2589 dhd_dump_pct(strbuf, "Rx: glom pct", (100 * bus->rxglompkts),
2590 bus->dhd->rx_packets);
2591 dhd_dump_pct(strbuf, ", pkts/glom", bus->rxglompkts, bus->rxglomframes);
2592 bcm_bprintf(strbuf, "\n");
2594 dhd_dump_pct(strbuf, "Tx: pkts/f2wr", bus->dhd->tx_packets, bus->f2txdata);
2595 dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->tx_packets, bus->f1regdata);
2596 dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->tx_packets,
2597 (bus->f2txdata + bus->f1regdata));
2598 dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->tx_packets, bus->intrcount);
2599 bcm_bprintf(strbuf, "\n");
2601 dhd_dump_pct(strbuf, "Total: pkts/f2rw",
2602 (bus->dhd->tx_packets + bus->dhd->rx_packets),
2603 (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata));
2604 dhd_dump_pct(strbuf, ", pkts/f1sd",
2605 (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->f1regdata);
2606 dhd_dump_pct(strbuf, ", pkts/sd",
2607 (bus->dhd->tx_packets + bus->dhd->rx_packets),
2608 (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata));
2609 dhd_dump_pct(strbuf, ", pkts/int",
2610 (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->intrcount);
2611 bcm_bprintf(strbuf, "\n\n");
2615 if (bus->pktgen_count) {
2616 bcm_bprintf(strbuf, "pktgen config and count:\n");
2617 bcm_bprintf(strbuf, "freq %u count %u print %u total %u min %u len %u\n",
2618 bus->pktgen_freq, bus->pktgen_count, bus->pktgen_print,
2619 bus->pktgen_total, bus->pktgen_minlen, bus->pktgen_maxlen);
2620 bcm_bprintf(strbuf, "send attempts %u rcvd %u fail %u\n",
2621 bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail);
2625 bcm_bprintf(strbuf, "dpc_sched %d host interrupt%spending\n",
2626 bus->dpc_sched, (bcmsdh_intr_pending(bus->sdh) ? " " : " not "));
2627 bcm_bprintf(strbuf, "blocksize %u roundup %u\n", bus->blocksize, bus->roundup);
2628 #endif /* DHD_DEBUG */
2629 bcm_bprintf(strbuf, "clkstate %d activity %d idletime %d idlecount %d sleeping %d\n",
2630 bus->clkstate, bus->activity, bus->idletime, bus->idlecount, bus->sleeping);
2631 dhd_dump_pct(strbuf, "Tx: glom pct", (100 * bus->txglompkts), bus->dhd->tx_packets);
2632 dhd_dump_pct(strbuf, ", pkts/glom", bus->txglompkts, bus->txglomframes);
2633 bcm_bprintf(strbuf, "\n");
2634 bcm_bprintf(strbuf, "txglomframes %u, txglompkts %u\n", bus->txglomframes, bus->txglompkts);
2635 bcm_bprintf(strbuf, "\n");
2639 dhd_bus_clearcounts(dhd_pub_t *dhdp)
2641 dhd_bus_t *bus = (dhd_bus_t *)dhdp->bus;
2643 bus->intrcount = bus->lastintrs = bus->spurious = bus->regfails = 0;
2644 bus->rxrtx = bus->rx_toolong = bus->rxc_errors = 0;
2645 bus->rx_hdrfail = bus->rx_badhdr = bus->rx_badseq = 0;
2646 #ifdef DHDENABLE_TAILPAD
2647 bus->tx_tailpad_chain = bus->tx_tailpad_pktget = 0;
2648 #endif /* DHDENABLE_TAILPAD */
2649 bus->tx_sderrs = bus->fc_rcvd = bus->fc_xoff = bus->fc_xon = 0;
2650 bus->rxglomfail = bus->rxglomframes = bus->rxglompkts = 0;
2651 bus->f2rxhdrs = bus->f2rxdata = bus->f2txdata = bus->f1regdata = 0;
2652 bus->txglomframes = bus->txglompkts = 0;
2657 dhdsdio_pktgen_get(dhd_bus_t *bus, uint8 *arg)
2659 dhd_pktgen_t pktgen;
2661 pktgen.version = DHD_PKTGEN_VERSION;
2662 pktgen.freq = bus->pktgen_freq;
2663 pktgen.count = bus->pktgen_count;
2664 pktgen.print = bus->pktgen_print;
2665 pktgen.total = bus->pktgen_total;
2666 pktgen.minlen = bus->pktgen_minlen;
2667 pktgen.maxlen = bus->pktgen_maxlen;
2668 pktgen.numsent = bus->pktgen_sent;
2669 pktgen.numrcvd = bus->pktgen_rcvd;
2670 pktgen.numfail = bus->pktgen_fail;
2671 pktgen.mode = bus->pktgen_mode;
2672 pktgen.stop = bus->pktgen_stop;
2674 bcopy(&pktgen, arg, sizeof(pktgen));
2680 dhdsdio_pktgen_set(dhd_bus_t *bus, uint8 *arg)
2682 dhd_pktgen_t pktgen;
2683 uint oldcnt, oldmode;
2685 bcopy(arg, &pktgen, sizeof(pktgen));
2686 if (pktgen.version != DHD_PKTGEN_VERSION)
2689 oldcnt = bus->pktgen_count;
2690 oldmode = bus->pktgen_mode;
2692 bus->pktgen_freq = pktgen.freq;
2693 bus->pktgen_count = pktgen.count;
2694 bus->pktgen_print = pktgen.print;
2695 bus->pktgen_total = pktgen.total;
2696 bus->pktgen_minlen = pktgen.minlen;
2697 bus->pktgen_maxlen = pktgen.maxlen;
2698 bus->pktgen_mode = pktgen.mode;
2699 bus->pktgen_stop = pktgen.stop;
2701 bus->pktgen_tick = bus->pktgen_ptick = 0;
2702 bus->pktgen_prev_time = jiffies;
2703 bus->pktgen_len = MAX(bus->pktgen_len, bus->pktgen_minlen);
2704 bus->pktgen_len = MIN(bus->pktgen_len, bus->pktgen_maxlen);
2706 /* Clear counts for a new pktgen (mode change, or was stopped) */
2707 if (bus->pktgen_count && (!oldcnt || oldmode != bus->pktgen_mode)) {
2708 bus->pktgen_sent = bus->pktgen_prev_sent = bus->pktgen_rcvd = 0;
2709 bus->pktgen_prev_rcvd = bus->pktgen_fail = 0;
2717 dhdsdio_devram_remap(dhd_bus_t *bus, bool val)
2719 uint8 enable, protect, remap;
2721 si_socdevram(bus->sih, FALSE, &enable, &protect, &remap);
2722 remap = val ? TRUE : FALSE;
2723 si_socdevram(bus->sih, TRUE, &enable, &protect, &remap);
2727 dhdsdio_membytes(dhd_bus_t *bus, bool write, uint32 address, uint8 *data, uint size)
2733 /* In remap mode, adjust address beyond socram and redirect
2734 * to devram at SOCDEVRAM_BP_ADDR since remap address > orig_ramsize
2735 * is not backplane accessible
2737 if (REMAP_ENAB(bus) && REMAP_ISADDR(bus, address)) {
2738 address -= bus->orig_ramsize;
2739 address += SOCDEVRAM_BP_ADDR;
2742 /* Determine initial transfer parameters */
2743 sdaddr = address & SBSDIO_SB_OFT_ADDR_MASK;
2744 if ((sdaddr + size) & SBSDIO_SBWINDOW_MASK)
2745 dsize = (SBSDIO_SB_OFT_ADDR_LIMIT - sdaddr);
2749 /* Set the backplane window to include the start address */
2750 if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) {
2751 DHD_ERROR(("%s: window change failed\n", __FUNCTION__));
2755 /* Do the transfer(s) */
2757 DHD_INFO(("%s: %s %d bytes at offset 0x%08x in window 0x%08x\n",
2758 __FUNCTION__, (write ? "write" : "read"), dsize, sdaddr,
2759 (address & SBSDIO_SBWINDOW_MASK)));
2760 if ((bcmerror = bcmsdh_rwdata(bus->sdh, write, sdaddr, data, dsize))) {
2761 DHD_ERROR(("%s: membytes transfer failed\n", __FUNCTION__));
2765 /* Adjust for next transfer (if any) */
2766 if ((size -= dsize)) {
2769 if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) {
2770 DHD_ERROR(("%s: window change failed\n", __FUNCTION__));
2774 dsize = MIN(SBSDIO_SB_OFT_ADDR_LIMIT, size);
2780 /* Return the window to backplane enumeration space for core access */
2781 if (dhdsdio_set_siaddr_window(bus, bcmsdh_cur_sbwad(bus->sdh))) {
2782 DHD_ERROR(("%s: FAILED to set window back to 0x%x\n", __FUNCTION__,
2783 bcmsdh_cur_sbwad(bus->sdh)));
2791 dhdsdio_readshared(dhd_bus_t *bus, sdpcm_shared_t *sh)
2797 if (CHIPID(bus->sih->chip) == BCM43430_CHIP_ID && !dhdsdio_sr_cap(bus))
2800 shaddr = bus->dongle_ram_base + bus->ramsize - 4;
2803 /* Read last word in memory to determine address of sdpcm_shared structure */
2804 if ((rv = dhdsdio_membytes(bus, FALSE, shaddr, (uint8 *)&addr, 4)) < 0)
2807 addr = ltoh32(addr);
2809 DHD_INFO(("sdpcm_shared address 0x%08X\n", addr));
2812 * Check if addr is valid.
2813 * NVRAM length at the end of memory should have been overwritten.
2815 if (addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff)) {
2816 if ((bus->srmemsize > 0) && (i++ == 0)) {
2817 shaddr -= bus->srmemsize;
2819 DHD_ERROR(("%s: address (0x%08x) of sdpcm_shared invalid\n",
2820 __FUNCTION__, addr));
2827 /* Read hndrte_shared structure */
2828 if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)sh, sizeof(sdpcm_shared_t))) < 0)
2832 sh->flags = ltoh32(sh->flags);
2833 sh->trap_addr = ltoh32(sh->trap_addr);
2834 sh->assert_exp_addr = ltoh32(sh->assert_exp_addr);
2835 sh->assert_file_addr = ltoh32(sh->assert_file_addr);
2836 sh->assert_line = ltoh32(sh->assert_line);
2837 sh->console_addr = ltoh32(sh->console_addr);
2838 sh->msgtrace_addr = ltoh32(sh->msgtrace_addr);
2840 if ((sh->flags & SDPCM_SHARED_VERSION_MASK) == 3 && SDPCM_SHARED_VERSION == 1)
2843 if ((sh->flags & SDPCM_SHARED_VERSION_MASK) != SDPCM_SHARED_VERSION) {
2844 DHD_ERROR(("%s: sdpcm_shared version %d in dhd "
2845 "is different than sdpcm_shared version %d in dongle\n",
2846 __FUNCTION__, SDPCM_SHARED_VERSION,
2847 sh->flags & SDPCM_SHARED_VERSION_MASK));
2854 #define CONSOLE_LINE_MAX 192
2857 dhdsdio_readconsole(dhd_bus_t *bus)
2859 dhd_console_t *c = &bus->console;
2860 uint8 line[CONSOLE_LINE_MAX], ch;
2861 uint32 n, idx, addr;
2864 /* Don't do anything until FWREADY updates console address */
2865 if (bus->console_addr == 0)
2871 /* Read console log struct */
2872 addr = bus->console_addr + OFFSETOF(hnd_cons_t, log);
2873 if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)&c->log, sizeof(c->log))) < 0)
2876 /* Allocate console buffer (one time only) */
2877 if (c->buf == NULL) {
2878 c->bufsize = ltoh32(c->log.buf_size);
2879 if ((c->buf = MALLOC(bus->dhd->osh, c->bufsize)) == NULL)
2883 idx = ltoh32(c->log.idx);
2885 /* Protect against corrupt value */
2886 if (idx > c->bufsize)
2889 /* Skip reading the console buffer if the index pointer has not moved */
2893 /* Read the console buffer */
2894 addr = ltoh32(c->log.buf);
2895 if ((rv = dhdsdio_membytes(bus, FALSE, addr, c->buf, c->bufsize)) < 0)
2898 while (c->last != idx) {
2899 for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) {
2900 if (c->last == idx) {
2901 /* This would output a partial line. Instead, back up
2902 * the buffer pointer and output this line next time around.
2907 c->last = c->bufsize - n;
2910 ch = c->buf[c->last];
2911 c->last = (c->last + 1) % c->bufsize;
2918 if (line[n - 1] == '\r')
2921 printf("CONSOLE: %s\n", line);
2922 #ifdef LOG_INTO_TCPDUMP
2923 dhd_sendup_log(bus->dhd, line, n);
2924 #endif /* LOG_INTO_TCPDUMP */
2933 dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size)
2937 char *mbuffer = NULL;
2938 char *console_buffer = NULL;
2939 uint maxstrlen = 256;
2942 sdpcm_shared_t sdpcm_shared;
2943 struct bcmstrbuf strbuf;
2944 uint32 console_ptr, console_size, console_index;
2945 uint8 line[CONSOLE_LINE_MAX], ch;
2949 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2951 if (DHD_NOCHECKDIED_ON())
2956 * Called after a rx ctrl timeout. "data" is NULL.
2957 * allocate memory to trace the trap or assert.
2960 mbuffer = data = MALLOC(bus->dhd->osh, msize);
2961 if (mbuffer == NULL) {
2962 DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, msize));
2963 bcmerror = BCME_NOMEM;
2968 if ((str = MALLOC(bus->dhd->osh, maxstrlen)) == NULL) {
2969 DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, maxstrlen));
2970 bcmerror = BCME_NOMEM;
2974 if ((bcmerror = dhdsdio_readshared(bus, &sdpcm_shared)) < 0)
2977 bcm_binit(&strbuf, data, size);
2979 bcm_bprintf(&strbuf, "msgtrace address : 0x%08X\nconsole address : 0x%08X\n",
2980 sdpcm_shared.msgtrace_addr, sdpcm_shared.console_addr);
2982 if ((sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT) == 0) {
2983 /* NOTE: Misspelled assert is intentional - DO NOT FIX.
2984 * (Avoids conflict with real asserts for programmatic parsing of output.)
2986 bcm_bprintf(&strbuf, "Assrt not built in dongle\n");
2989 if ((sdpcm_shared.flags & (SDPCM_SHARED_ASSERT|SDPCM_SHARED_TRAP)) == 0) {
2990 /* NOTE: Misspelled assert is intentional - DO NOT FIX.
2991 * (Avoids conflict with real asserts for programmatic parsing of output.)
2993 bcm_bprintf(&strbuf, "No trap%s in dongle",
2994 (sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT)
2997 if (sdpcm_shared.flags & SDPCM_SHARED_ASSERT) {
2998 /* Download assert */
2999 bcm_bprintf(&strbuf, "Dongle assert");
3000 if (sdpcm_shared.assert_exp_addr != 0) {
3002 if ((bcmerror = dhdsdio_membytes(bus, FALSE,
3003 sdpcm_shared.assert_exp_addr,
3004 (uint8 *)str, maxstrlen)) < 0)
3007 str[maxstrlen - 1] = '\0';
3008 bcm_bprintf(&strbuf, " expr \"%s\"", str);
3011 if (sdpcm_shared.assert_file_addr != 0) {
3013 if ((bcmerror = dhdsdio_membytes(bus, FALSE,
3014 sdpcm_shared.assert_file_addr,
3015 (uint8 *)str, maxstrlen)) < 0)
3018 str[maxstrlen - 1] = '\0';
3019 bcm_bprintf(&strbuf, " file \"%s\"", str);
3022 bcm_bprintf(&strbuf, " line %d ", sdpcm_shared.assert_line);
3025 if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) {
3026 bus->dhd->dongle_trap_occured = TRUE;
3027 if ((bcmerror = dhdsdio_membytes(bus, FALSE,
3028 sdpcm_shared.trap_addr,
3029 (uint8*)&tr, sizeof(trap_t))) < 0)
3032 bcm_bprintf(&strbuf,
3033 "Dongle trap type 0x%x @ epc 0x%x, cpsr 0x%x, spsr 0x%x, sp 0x%x,"
3034 "lp 0x%x, rpc 0x%x Trap offset 0x%x, "
3035 "r0 0x%x, r1 0x%x, r2 0x%x, r3 0x%x, "
3036 "r4 0x%x, r5 0x%x, r6 0x%x, r7 0x%x\n\n",
3037 ltoh32(tr.type), ltoh32(tr.epc), ltoh32(tr.cpsr), ltoh32(tr.spsr),
3038 ltoh32(tr.r13), ltoh32(tr.r14), ltoh32(tr.pc),
3039 ltoh32(sdpcm_shared.trap_addr),
3040 ltoh32(tr.r0), ltoh32(tr.r1), ltoh32(tr.r2), ltoh32(tr.r3),
3041 ltoh32(tr.r4), ltoh32(tr.r5), ltoh32(tr.r6), ltoh32(tr.r7));
3043 addr = sdpcm_shared.console_addr + OFFSETOF(hnd_cons_t, log);
3044 if ((rv = dhdsdio_membytes(bus, FALSE, addr,
3045 (uint8 *)&console_ptr, sizeof(console_ptr))) < 0)
3048 addr = sdpcm_shared.console_addr + OFFSETOF(hnd_cons_t, log.buf_size);
3049 if ((rv = dhdsdio_membytes(bus, FALSE, addr,
3050 (uint8 *)&console_size, sizeof(console_size))) < 0)
3053 addr = sdpcm_shared.console_addr + OFFSETOF(hnd_cons_t, log.idx);
3054 if ((rv = dhdsdio_membytes(bus, FALSE, addr,
3055 (uint8 *)&console_index, sizeof(console_index))) < 0)
3058 console_ptr = ltoh32(console_ptr);
3059 console_size = ltoh32(console_size);
3060 console_index = ltoh32(console_index);
3062 if (console_size > CONSOLE_BUFFER_MAX ||
3063 !(console_buffer = MALLOC(bus->dhd->osh, console_size)))
3066 if ((rv = dhdsdio_membytes(bus, FALSE, console_ptr,
3067 (uint8 *)console_buffer, console_size)) < 0)
3070 for (i = 0, n = 0; i < console_size; i += n + 1) {
3071 for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) {
3072 ch = console_buffer[(console_index + i + n) % console_size];
3080 if (line[n - 1] == '\r')
3083 /* Don't use DHD_ERROR macro since we print
3084 * a lot of information quickly. The macro
3085 * will truncate a lot of the printfs
3088 if (dhd_msg_level & DHD_ERROR_VAL)
3089 printf("CONSOLE: %s\n", line);
3096 if (sdpcm_shared.flags & (SDPCM_SHARED_ASSERT | SDPCM_SHARED_TRAP)) {
3097 DHD_ERROR(("%s: %s\n", __FUNCTION__, strbuf.origbuf));
3103 MFREE(bus->dhd->osh, mbuffer, msize);
3105 MFREE(bus->dhd->osh, str, maxstrlen);
3107 MFREE(bus->dhd->osh, console_buffer, console_size);
3111 #endif /* #ifdef DHD_DEBUG */
3115 dhdsdio_downloadvars(dhd_bus_t *bus, void *arg, int len)
3117 int bcmerror = BCME_OK;
3119 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3121 /* Basic sanity checks */
3123 bcmerror = BCME_NOTDOWN;
3127 bcmerror = BCME_BUFTOOSHORT;
3131 /* Free the old ones and replace with passed variables */
3133 MFREE(bus->dhd->osh, bus->vars, bus->varsz);
3135 bus->vars = MALLOC(bus->dhd->osh, len);
3136 bus->varsz = bus->vars ? len : 0;
3137 if (bus->vars == NULL) {
3138 bcmerror = BCME_NOMEM;
3142 /* Copy the passed variables, which should include the terminating double-null */
3143 bcopy(arg, bus->vars, bus->varsz);
3150 #define CC_PLL_CHIPCTRL_SERIAL_ENAB (1 << 24)
3151 #define CC_CHIPCTRL_JTAG_SEL (1 << 3)
3152 #define CC_CHIPCTRL_GPIO_SEL (0x3)
3153 #define CC_PLL_CHIPCTRL_SERIAL_ENAB_4334 (1 << 28)
3156 dhd_serialconsole(dhd_bus_t *bus, bool set, bool enable, int *bcmerror)
3159 uint32 addr, data, uart_enab = 0;
3160 uint32 jtag_sel = CC_CHIPCTRL_JTAG_SEL;
3161 uint32 gpio_sel = CC_CHIPCTRL_GPIO_SEL;
3163 addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr);
3164 data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data);
3167 bcmsdh_reg_write(bus->sdh, addr, 4, 1);
3168 if (bcmsdh_regfail(bus->sdh)) {
3169 *bcmerror = BCME_SDIO_ERROR;
3172 int_val = bcmsdh_reg_read(bus->sdh, data, 4);
3173 if (bcmsdh_regfail(bus->sdh)) {
3174 *bcmerror = BCME_SDIO_ERROR;
3177 if (bus->sih->chip == BCM4330_CHIP_ID) {
3178 uart_enab = CC_PLL_CHIPCTRL_SERIAL_ENAB;
3180 else if (bus->sih->chip == BCM4334_CHIP_ID ||
3181 bus->sih->chip == BCM43340_CHIP_ID ||
3182 bus->sih->chip == BCM43341_CHIP_ID ||
3183 bus->sih->chip == BCM43342_CHIP_ID ||
3186 /* Moved to PMU chipcontrol 1 from 4330 */
3187 int_val &= ~gpio_sel;
3188 int_val |= jtag_sel;
3190 int_val |= gpio_sel;
3191 int_val &= ~jtag_sel;
3193 uart_enab = CC_PLL_CHIPCTRL_SERIAL_ENAB_4334;
3197 return (int_val & uart_enab);
3199 int_val |= uart_enab;
3201 int_val &= ~uart_enab;
3202 bcmsdh_reg_write(bus->sdh, data, 4, int_val);
3203 if (bcmsdh_regfail(bus->sdh)) {
3204 *bcmerror = BCME_SDIO_ERROR;
3207 if (bus->sih->chip == BCM4330_CHIP_ID) {
3209 addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol);
3210 chipcontrol = bcmsdh_reg_read(bus->sdh, addr, 4);
3211 chipcontrol &= ~jtag_sel;
3213 chipcontrol |= jtag_sel;
3214 chipcontrol &= ~gpio_sel;
3216 bcmsdh_reg_write(bus->sdh, addr, 4, chipcontrol);
3219 return (int_val & uart_enab);
3224 dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const char *name,
3225 void *params, int plen, void *arg, int len, int val_size)
3231 DHD_TRACE(("%s: Enter, action %d name %s params %p plen %d arg %p len %d val_size %d\n",
3232 __FUNCTION__, actionid, name, params, plen, arg, len, val_size));
3234 if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0)
3237 if (plen >= (int)sizeof(int_val))
3238 bcopy(params, &int_val, sizeof(int_val));
3240 bool_val = (int_val != 0) ? TRUE : FALSE;
3243 /* Some ioctls use the bus */
3244 dhd_os_sdlock(bus->dhd);
3246 /* Check if dongle is in reset. If so, only allow DEVRESET iovars */
3247 if (bus->dhd->dongle_reset && !(actionid == IOV_SVAL(IOV_DEVRESET) ||
3248 actionid == IOV_GVAL(IOV_DEVRESET))) {
3249 bcmerror = BCME_NOTREADY;
3254 * Special handling for keepSdioOn: New SDIO Wake-up Mechanism
3256 if ((vi->varid == IOV_KSO) && (IOV_ISSET(actionid))) {
3257 dhdsdio_clk_kso_iovar(bus, bool_val);
3259 } else if ((vi->varid == IOV_DEVSLEEP) && (IOV_ISSET(actionid))) {
3261 dhdsdio_clk_devsleep_iovar(bus, bool_val);
3262 if (!SLPAUTO_ENAB(bus) && (bool_val == FALSE) && (bus->ipend)) {
3263 DHD_ERROR(("INT pending in devsleep 1, dpc_sched: %d\n",
3265 if (!bus->dpc_sched) {
3266 bus->dpc_sched = TRUE;
3267 dhd_sched_dpc(bus->dhd);
3274 /* Handle sleep stuff before any clock mucking */
3275 if (vi->varid == IOV_SLEEP) {
3276 if (IOV_ISSET(actionid)) {
3277 bcmerror = dhdsdio_bussleep(bus, bool_val);
3279 int_val = (int32)bus->sleeping;
3280 bcopy(&int_val, arg, val_size);
3285 /* Request clock to allow SDIO accesses */
3286 if (!bus->dhd->dongle_reset) {
3288 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
3292 case IOV_GVAL(IOV_INTR):
3293 int_val = (int32)bus->intr;
3294 bcopy(&int_val, arg, val_size);
3297 case IOV_SVAL(IOV_INTR):
3298 bus->intr = bool_val;
3299 bus->intdis = FALSE;
3302 DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__));
3303 // terence 20141207: enbale intdis
3305 bcmsdh_intr_enable(bus->sdh);
3307 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
3308 bcmsdh_intr_disable(bus->sdh);
3313 case IOV_GVAL(IOV_POLLRATE):
3314 int_val = (int32)bus->pollrate;
3315 bcopy(&int_val, arg, val_size);
3318 case IOV_SVAL(IOV_POLLRATE):
3319 bus->pollrate = (uint)int_val;
3320 bus->poll = (bus->pollrate != 0);
3323 case IOV_GVAL(IOV_IDLETIME):
3324 int_val = bus->idletime;
3325 bcopy(&int_val, arg, val_size);
3328 case IOV_SVAL(IOV_IDLETIME):
3329 if ((int_val < 0) && (int_val != DHD_IDLE_IMMEDIATE)) {
3330 bcmerror = BCME_BADARG;
3332 bus->idletime = int_val;
3336 case IOV_GVAL(IOV_IDLECLOCK):
3337 int_val = (int32)bus->idleclock;
3338 bcopy(&int_val, arg, val_size);
3341 case IOV_SVAL(IOV_IDLECLOCK):
3342 bus->idleclock = int_val;
3345 case IOV_GVAL(IOV_SD1IDLE):
3346 int_val = (int32)sd1idle;
3347 bcopy(&int_val, arg, val_size);
3350 case IOV_SVAL(IOV_SD1IDLE):
3355 case IOV_SVAL(IOV_MEMBYTES):
3356 case IOV_GVAL(IOV_MEMBYTES):
3362 bool set = (actionid == IOV_SVAL(IOV_MEMBYTES));
3364 ASSERT(plen >= 2*sizeof(int));
3366 address = (uint32)int_val;
3367 bcopy((char *)params + sizeof(int_val), &int_val, sizeof(int_val));
3368 size = (uint)int_val;
3370 /* Do some validation */
3371 dsize = set ? plen - (2 * sizeof(int)) : len;
3373 DHD_ERROR(("%s: error on %s membytes, addr 0x%08x size %d dsize %d\n",
3374 __FUNCTION__, (set ? "set" : "get"), address, size, dsize));
3375 bcmerror = BCME_BADARG;
3379 DHD_INFO(("%s: Request to %s %d bytes at address 0x%08x\n", __FUNCTION__,
3380 (set ? "write" : "read"), size, address));
3383 if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
3385 * If address is start of RAM (i.e. a downloaded image),
3386 * store the reset instruction to be written in 0
3388 if (set && address == bus->dongle_ram_base) {
3389 bus->resetinstr = *(((uint32*)params) + 2);
3392 /* If we know about SOCRAM, check for a fit */
3393 if ((bus->orig_ramsize) &&
3394 ((address > bus->orig_ramsize) || (address + size > bus->orig_ramsize)))
3396 uint8 enable, protect, remap;
3397 si_socdevram(bus->sih, FALSE, &enable, &protect, &remap);
3398 if (!enable || protect) {
3399 DHD_ERROR(("%s: ramsize 0x%08x doesn't have %d bytes at 0x%08x\n",
3400 __FUNCTION__, bus->orig_ramsize, size, address));
3401 DHD_ERROR(("%s: socram enable %d, protect %d\n",
3402 __FUNCTION__, enable, protect));
3403 bcmerror = BCME_BADARG;
3407 if (!REMAP_ENAB(bus) && (address >= SOCDEVRAM_ARM_ADDR)) {
3408 uint32 devramsize = si_socdevram_size(bus->sih);
3409 if ((address < SOCDEVRAM_ARM_ADDR) ||
3410 (address + size > (SOCDEVRAM_ARM_ADDR + devramsize))) {
3411 DHD_ERROR(("%s: bad address 0x%08x, size 0x%08x\n",
3412 __FUNCTION__, address, size));
3413 DHD_ERROR(("%s: socram range 0x%08x,size 0x%08x\n",
3414 __FUNCTION__, SOCDEVRAM_ARM_ADDR, devramsize));
3415 bcmerror = BCME_BADARG;
3418 /* move it such that address is real now */
3419 address -= SOCDEVRAM_ARM_ADDR;
3420 address += SOCDEVRAM_BP_ADDR;
3421 DHD_INFO(("%s: Request to %s %d bytes @ Mapped address 0x%08x\n",
3422 __FUNCTION__, (set ? "write" : "read"), size, address));
3423 } else if (REMAP_ENAB(bus) && REMAP_ISADDR(bus, address) && remap) {
3424 /* Can not access remap region while devram remap bit is set
3425 * ROM content would be returned in this case
3427 DHD_ERROR(("%s: Need to disable remap for address 0x%08x\n",
3428 __FUNCTION__, address));
3429 bcmerror = BCME_ERROR;
3435 /* Generate the actual data pointer */
3436 data = set ? (uint8*)params + 2 * sizeof(int): (uint8*)arg;
3438 /* Call to do the transfer */
3439 bcmerror = dhdsdio_membytes(bus, set, address, data, size);
3444 case IOV_GVAL(IOV_RAMSIZE):
3445 int_val = (int32)bus->ramsize;
3446 bcopy(&int_val, arg, val_size);
3449 case IOV_GVAL(IOV_RAMSTART):
3450 int_val = (int32)bus->dongle_ram_base;
3451 bcopy(&int_val, arg, val_size);
3454 case IOV_GVAL(IOV_SDIOD_DRIVE):
3455 int_val = (int32)dhd_sdiod_drive_strength;
3456 bcopy(&int_val, arg, val_size);
3459 case IOV_SVAL(IOV_SDIOD_DRIVE):
3460 dhd_sdiod_drive_strength = int_val;
3461 si_sdiod_drive_strength_init(bus->sih, bus->dhd->osh, dhd_sdiod_drive_strength);
3464 case IOV_SVAL(IOV_SET_DOWNLOAD_STATE):
3465 bcmerror = dhdsdio_download_state(bus, bool_val);
3468 case IOV_SVAL(IOV_SOCRAM_STATE):
3469 bcmerror = dhdsdio_download_state(bus, bool_val);
3472 case IOV_SVAL(IOV_VARS):
3473 bcmerror = dhdsdio_downloadvars(bus, arg, len);
3476 case IOV_GVAL(IOV_READAHEAD):
3477 int_val = (int32)dhd_readahead;
3478 bcopy(&int_val, arg, val_size);
3481 case IOV_SVAL(IOV_READAHEAD):
3482 if (bool_val && !dhd_readahead)
3484 dhd_readahead = bool_val;
3487 case IOV_GVAL(IOV_SDRXCHAIN):
3488 int_val = (int32)bus->use_rxchain;
3489 bcopy(&int_val, arg, val_size);
3492 case IOV_SVAL(IOV_SDRXCHAIN):
3493 if (bool_val && !bus->sd_rxchain)
3494 bcmerror = BCME_UNSUPPORTED;
3496 bus->use_rxchain = bool_val;
3498 case IOV_GVAL(IOV_ALIGNCTL):
3499 int_val = (int32)dhd_alignctl;
3500 bcopy(&int_val, arg, val_size);
3503 case IOV_SVAL(IOV_ALIGNCTL):
3504 dhd_alignctl = bool_val;
3507 case IOV_GVAL(IOV_SDALIGN):
3508 int_val = DHD_SDALIGN;
3509 bcopy(&int_val, arg, val_size);
3513 case IOV_GVAL(IOV_VARS):
3514 if (bus->varsz < (uint)len)
3515 bcopy(bus->vars, arg, bus->varsz);
3517 bcmerror = BCME_BUFTOOSHORT;
3519 #endif /* DHD_DEBUG */
3522 case IOV_GVAL(IOV_SDREG):
3527 sd_ptr = (sdreg_t *)params;
3529 addr = (uint32)((ulong)bus->regs + sd_ptr->offset);
3530 size = sd_ptr->func;
3531 int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size);
3532 if (bcmsdh_regfail(bus->sdh))
3533 bcmerror = BCME_SDIO_ERROR;
3534 bcopy(&int_val, arg, sizeof(int32));
3538 case IOV_SVAL(IOV_SDREG):
3543 sd_ptr = (sdreg_t *)params;
3545 addr = (uint32)((ulong)bus->regs + sd_ptr->offset);
3546 size = sd_ptr->func;
3547 bcmsdh_reg_write(bus->sdh, addr, size, sd_ptr->value);
3548 if (bcmsdh_regfail(bus->sdh))
3549 bcmerror = BCME_SDIO_ERROR;
3553 /* Same as above, but offset is not backplane (not SDIO core) */
3554 case IOV_GVAL(IOV_SBREG):
3559 bcopy(params, &sdreg, sizeof(sdreg));
3561 addr = SI_ENUM_BASE + sdreg.offset;
3563 int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size);
3564 if (bcmsdh_regfail(bus->sdh))
3565 bcmerror = BCME_SDIO_ERROR;
3566 bcopy(&int_val, arg, sizeof(int32));
3570 case IOV_SVAL(IOV_SBREG):
3575 bcopy(params, &sdreg, sizeof(sdreg));
3577 addr = SI_ENUM_BASE + sdreg.offset;
3579 bcmsdh_reg_write(bus->sdh, addr, size, sdreg.value);
3580 if (bcmsdh_regfail(bus->sdh))
3581 bcmerror = BCME_SDIO_ERROR;
3585 case IOV_GVAL(IOV_SDCIS):
3589 bcmstrcat(arg, "\nFunc 0\n");
3590 bcmsdh_cis_read(bus->sdh, 0x10, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
3591 bcmstrcat(arg, "\nFunc 1\n");
3592 bcmsdh_cis_read(bus->sdh, 0x11, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
3593 bcmstrcat(arg, "\nFunc 2\n");
3594 bcmsdh_cis_read(bus->sdh, 0x12, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
3598 case IOV_GVAL(IOV_FORCEEVEN):
3599 int_val = (int32)forcealign;
3600 bcopy(&int_val, arg, val_size);
3603 case IOV_SVAL(IOV_FORCEEVEN):
3604 forcealign = bool_val;
3607 case IOV_GVAL(IOV_TXBOUND):
3608 int_val = (int32)dhd_txbound;
3609 bcopy(&int_val, arg, val_size);
3612 case IOV_SVAL(IOV_TXBOUND):
3613 dhd_txbound = (uint)int_val;
3616 case IOV_GVAL(IOV_RXBOUND):
3617 int_val = (int32)dhd_rxbound;
3618 bcopy(&int_val, arg, val_size);
3621 case IOV_SVAL(IOV_RXBOUND):
3622 dhd_rxbound = (uint)int_val;
3625 case IOV_GVAL(IOV_TXMINMAX):
3626 int_val = (int32)dhd_txminmax;
3627 bcopy(&int_val, arg, val_size);
3630 case IOV_SVAL(IOV_TXMINMAX):
3631 dhd_txminmax = (uint)int_val;
3634 case IOV_GVAL(IOV_SERIALCONS):
3635 int_val = dhd_serialconsole(bus, FALSE, 0, &bcmerror);
3639 bcopy(&int_val, arg, val_size);
3642 case IOV_SVAL(IOV_SERIALCONS):
3643 dhd_serialconsole(bus, TRUE, bool_val, &bcmerror);
3647 #endif /* DHD_DEBUG */
3651 case IOV_GVAL(IOV_EXTLOOP):
3652 int_val = (int32)bus->ext_loop;
3653 bcopy(&int_val, arg, val_size);
3656 case IOV_SVAL(IOV_EXTLOOP):
3657 bus->ext_loop = bool_val;
3660 case IOV_GVAL(IOV_PKTGEN):
3661 bcmerror = dhdsdio_pktgen_get(bus, arg);
3664 case IOV_SVAL(IOV_PKTGEN):
3665 bcmerror = dhdsdio_pktgen_set(bus, arg);
3669 #if defined(USE_SDIOFIFO_IOVAR)
3670 case IOV_GVAL(IOV_WATERMARK):
3671 int_val = (int32)watermark;
3672 bcopy(&int_val, arg, val_size);
3675 case IOV_SVAL(IOV_WATERMARK):
3676 watermark = (uint)int_val;
3677 watermark = (watermark > SBSDIO_WATERMARK_MASK) ? SBSDIO_WATERMARK_MASK : watermark;
3678 DHD_ERROR(("Setting watermark as 0x%x.\n", watermark));
3679 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, (uint8)watermark, NULL);
3682 case IOV_GVAL(IOV_MESBUSYCTRL):
3683 int_val = (int32)mesbusyctrl;
3684 bcopy(&int_val, arg, val_size);
3687 case IOV_SVAL(IOV_MESBUSYCTRL):
3688 mesbusyctrl = (uint)int_val;
3689 mesbusyctrl = (mesbusyctrl > SBSDIO_MESBUSYCTRL_MASK)
3690 ? SBSDIO_MESBUSYCTRL_MASK : mesbusyctrl;
3691 DHD_ERROR(("Setting mesbusyctrl as 0x%x.\n", mesbusyctrl));
3692 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL,
3693 ((uint8)mesbusyctrl | 0x80), NULL);
3698 case IOV_GVAL(IOV_DONGLEISOLATION):
3699 int_val = bus->dhd->dongle_isolation;
3700 bcopy(&int_val, arg, val_size);
3703 case IOV_SVAL(IOV_DONGLEISOLATION):
3704 bus->dhd->dongle_isolation = bool_val;
3707 case IOV_SVAL(IOV_DEVRESET):
3708 DHD_TRACE(("%s: Called set IOV_DEVRESET=%d dongle_reset=%d busstate=%d\n",
3709 __FUNCTION__, bool_val, bus->dhd->dongle_reset,
3710 bus->dhd->busstate));
3712 ASSERT(bus->dhd->osh);
3713 /* ASSERT(bus->cl_devid); */
3715 dhd_bus_devreset(bus->dhd, (uint8)bool_val);
3719 * softap firmware is updated through module parameter or android private command
3722 case IOV_GVAL(IOV_DEVRESET):
3723 DHD_TRACE(("%s: Called get IOV_DEVRESET\n", __FUNCTION__));
3725 /* Get its status */
3726 int_val = (bool) bus->dhd->dongle_reset;
3727 bcopy(&int_val, arg, val_size);
3731 case IOV_GVAL(IOV_KSO):
3732 int_val = dhdsdio_sleepcsr_get(bus);
3733 bcopy(&int_val, arg, val_size);
3736 case IOV_GVAL(IOV_DEVCAP):
3737 int_val = dhdsdio_devcap_get(bus);
3738 bcopy(&int_val, arg, val_size);
3741 case IOV_SVAL(IOV_DEVCAP):
3742 dhdsdio_devcap_set(bus, (uint8) int_val);
3744 case IOV_GVAL(IOV_TXGLOMSIZE):
3745 int_val = (int32)bus->txglomsize;
3746 bcopy(&int_val, arg, val_size);
3749 case IOV_SVAL(IOV_TXGLOMSIZE):
3750 if (int_val > SDPCM_MAXGLOM_SIZE) {
3751 bcmerror = BCME_ERROR;
3753 bus->txglomsize = (uint)int_val;
3756 case IOV_SVAL(IOV_HANGREPORT):
3757 bus->dhd->hang_report = bool_val;
3758 DHD_ERROR(("%s: Set hang_report as %d\n", __FUNCTION__, bus->dhd->hang_report));
3761 case IOV_GVAL(IOV_HANGREPORT):
3762 int_val = (int32)bus->dhd->hang_report;
3763 bcopy(&int_val, arg, val_size);
3766 case IOV_GVAL(IOV_TXINRX_THRES):
3767 int_val = bus->txinrx_thres;
3768 bcopy(&int_val, arg, val_size);
3770 case IOV_SVAL(IOV_TXINRX_THRES):
3772 bcmerror = BCME_BADARG;
3774 bus->txinrx_thres = int_val;
3779 bcmerror = BCME_UNSUPPORTED;
3784 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
3785 bus->activity = FALSE;
3786 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
3789 dhd_os_sdunlock(bus->dhd);
3795 dhdsdio_write_vars(dhd_bus_t *bus)
3798 uint32 varsize, phys_size;
3803 uint8 *nvram_ularray;
3804 #endif /* DHD_DEBUG */
3806 /* Even if there are no vars are to be written, we still need to set the ramsize. */
3807 varsize = bus->varsz ? ROUNDUP(bus->varsz, 4) : 0;
3808 varaddr = (bus->ramsize - 4) - varsize;
3810 // terence 20150412: fix for nvram failed to download
3811 if (bus->dhd->conf->chip == BCM43340_CHIP_ID ||
3812 bus->dhd->conf->chip == BCM43341_CHIP_ID) {
3813 varsize = varsize ? ROUNDUP(varsize, 64) : 0;
3814 varaddr = (bus->ramsize - 64) - varsize;
3817 varaddr += bus->dongle_ram_base;
3820 if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 7)) {
3821 if (((varaddr & 0x3C) == 0x3C) && (varsize > 4)) {
3822 DHD_ERROR(("PR85623WAR in place\n"));
3828 vbuffer = (uint8 *)MALLOC(bus->dhd->osh, varsize);
3832 bzero(vbuffer, varsize);
3833 bcopy(bus->vars, vbuffer, bus->varsz);
3835 /* Write the vars list */
3836 bcmerror = dhdsdio_membytes(bus, TRUE, varaddr, vbuffer, varsize);
3838 /* Verify NVRAM bytes */
3839 DHD_INFO(("Compare NVRAM dl & ul; varsize=%d\n", varsize));
3840 nvram_ularray = (uint8*)MALLOC(bus->dhd->osh, varsize);
3844 /* Upload image to verify downloaded contents. */
3845 memset(nvram_ularray, 0xaa, varsize);
3847 /* Read the vars list to temp buffer for comparison */
3848 bcmerror = dhdsdio_membytes(bus, FALSE, varaddr, nvram_ularray, varsize);
3850 DHD_ERROR(("%s: error %d on reading %d nvram bytes at 0x%08x\n",
3851 __FUNCTION__, bcmerror, varsize, varaddr));
3853 /* Compare the org NVRAM with the one read from RAM */
3854 if (memcmp(vbuffer, nvram_ularray, varsize)) {
3855 DHD_ERROR(("%s: Downloaded NVRAM image is corrupted.\n", __FUNCTION__));
3857 DHD_ERROR(("%s: Download, Upload and compare of NVRAM succeeded.\n",
3860 MFREE(bus->dhd->osh, nvram_ularray, varsize);
3861 #endif /* DHD_DEBUG */
3863 MFREE(bus->dhd->osh, vbuffer, varsize);
3866 phys_size = REMAP_ENAB(bus) ? bus->ramsize : bus->orig_ramsize;
3868 phys_size += bus->dongle_ram_base;
3870 /* adjust to the user specified RAM */
3871 DHD_INFO(("Physical memory size: %d, usable memory size: %d\n",
3872 phys_size, bus->ramsize));
3873 DHD_INFO(("Vars are at %d, orig varsize is %d\n",
3875 varsize = ((phys_size - 4) - varaddr);
3878 * Determine the length token:
3879 * Varsize, converted to words, in lower 16-bits, checksum in upper 16-bits.
3884 varsizew = varsize / 4;
3885 varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF);
3886 varsizew = htol32(varsizew);
3889 DHD_INFO(("New varsize is %d, length token=0x%08x\n", varsize, varsizew));
3891 /* Write the length token to the last word */
3892 bcmerror = dhdsdio_membytes(bus, TRUE, (phys_size - 4),
3893 (uint8*)&varsizew, 4);
3899 dhdsdio_download_state(dhd_bus_t *bus, bool enter)
3907 /* To enter download state, disable ARM and reset SOCRAM.
3908 * To exit download state, simply reset ARM (default is RAM boot).
3911 bus->alp_only = TRUE;
3913 if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) &&
3914 !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) {
3915 if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
3918 DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__));
3919 bcmerror = BCME_ERROR;
3925 si_core_disable(bus->sih, 0);
3926 if (bcmsdh_regfail(bus->sdh)) {
3927 bcmerror = BCME_SDIO_ERROR;
3931 if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) {
3932 DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__));
3933 bcmerror = BCME_ERROR;
3937 si_core_reset(bus->sih, 0, 0);
3938 if (bcmsdh_regfail(bus->sdh)) {
3939 DHD_ERROR(("%s: Failure trying reset SOCRAM core?\n",
3941 bcmerror = BCME_SDIO_ERROR;
3945 /* Disable remap for download */
3946 if (REMAP_ENAB(bus) && si_socdevram_remap_isenb(bus->sih))
3947 dhdsdio_devram_remap(bus, FALSE);
3949 if (CHIPID(bus->sih->chip) == BCM43430_CHIP_ID) {
3950 /* Disabling Remap for SRAM_3 */
3951 si_socram_set_bankpda(bus->sih, 0x3, 0x0);
3954 /* Clear the top bit of memory */
3957 if (dhdsdio_membytes(bus, TRUE, bus->ramsize - 4,
3958 (uint8*)&zeros, 4) < 0) {
3959 bcmerror = BCME_SDIO_ERROR;
3967 * Read RAM base address [0x18_0000]
3968 * [next] Download firmware
3969 * [done at else] Populate the reset vector
3970 * [done at else] Remove ARM halt
3972 /* Halt ARM & remove reset */
3973 si_core_reset(bus->sih, SICF_CPUHALT, SICF_CPUHALT);
3976 if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
3977 if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) {
3978 DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__));
3979 bcmerror = BCME_ERROR;
3983 if (!si_iscoreup(bus->sih)) {
3984 DHD_ERROR(("%s: SOCRAM core is down after reset?\n", __FUNCTION__));
3985 bcmerror = BCME_ERROR;
3989 if ((bcmerror = dhdsdio_write_vars(bus))) {
3990 DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__));
3994 /* Enable remap before ARM reset but after vars.
3995 * No backplane access in remap mode
3997 if (REMAP_ENAB(bus) && !si_socdevram_remap_isenb(bus->sih))
3998 dhdsdio_devram_remap(bus, TRUE);
4000 if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) &&
4001 !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) {
4002 DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__));
4003 bcmerror = BCME_ERROR;
4006 W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries);
4009 if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) &&
4010 !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) {
4011 DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__));
4012 bcmerror = BCME_ERROR;
4016 /* cr4 has no socram, but tcm's */
4018 if ((bcmerror = dhdsdio_write_vars(bus))) {
4019 DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__));
4023 if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) &&
4024 !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) {
4025 DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__));
4026 bcmerror = BCME_ERROR;
4029 W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries);
4031 /* switch back to arm core again */
4032 if (!(si_setcore(bus->sih, ARMCR4_CORE_ID, 0))) {
4033 DHD_ERROR(("%s: Failed to find ARM CR4 core!\n", __FUNCTION__));
4034 bcmerror = BCME_ERROR;
4037 /* write address 0 with reset instruction */
4038 bcmerror = dhdsdio_membytes(bus, TRUE, 0,
4039 (uint8 *)&bus->resetinstr, sizeof(bus->resetinstr));
4041 /* now remove reset and halt and continue to run CR4 */
4044 si_core_reset(bus->sih, 0, 0);
4045 if (bcmsdh_regfail(bus->sdh)) {
4046 DHD_ERROR(("%s: Failure trying to reset ARM core?\n", __FUNCTION__));
4047 bcmerror = BCME_SDIO_ERROR;
4051 /* Allow HT Clock now that the ARM is running. */
4052 bus->alp_only = FALSE;
4054 bus->dhd->busstate = DHD_BUS_LOAD;
4058 /* Always return to SDIOD core */
4059 if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0))
4060 si_setcore(bus->sih, SDIOD_CORE_ID, 0);
4066 dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name,
4067 void *params, int plen, void *arg, int len, bool set)
4069 dhd_bus_t *bus = dhdp->bus;
4070 const bcm_iovar_t *vi = NULL;
4075 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4080 /* Get MUST have return space */
4081 ASSERT(set || (arg && len));
4083 /* Set does NOT take qualifiers */
4084 ASSERT(!set || (!params && !plen));
4086 /* Look up var locally; if not found pass to host driver */
4087 if ((vi = bcm_iovar_lookup(dhdsdio_iovars, name)) == NULL) {
4088 dhd_os_sdlock(bus->dhd);
4092 /* Turn on clock in case SD command needs backplane */
4093 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
4095 bcmerror = bcmsdh_iovar_op(bus->sdh, name, params, plen, arg, len, set);
4097 /* Check for bus configuration changes of interest */
4099 /* If it was divisor change, read the new one */
4100 if (set && strcmp(name, "sd_divisor") == 0) {
4101 if (bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
4102 &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) {
4103 bus->sd_divisor = -1;
4104 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, name));
4106 DHD_INFO(("%s: noted %s update, value now %d\n",
4107 __FUNCTION__, name, bus->sd_divisor));
4110 /* If it was a mode change, read the new one */
4111 if (set && strcmp(name, "sd_mode") == 0) {
4112 if (bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
4113 &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) {
4115 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, name));
4117 DHD_INFO(("%s: noted %s update, value now %d\n",
4118 __FUNCTION__, name, bus->sd_mode));
4121 /* Similar check for blocksize change */
4122 if (set && strcmp(name, "sd_blocksize") == 0) {
4124 if (bcmsdh_iovar_op(bus->sdh, "sd_blocksize", &fnum, sizeof(int32),
4125 &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) {
4127 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize"));
4129 DHD_INFO(("%s: noted %s update, value now %d\n",
4130 __FUNCTION__, "sd_blocksize", bus->blocksize));
4132 dhdsdio_tune_fifoparam(bus);
4135 bus->roundup = MIN(max_roundup, bus->blocksize);
4137 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
4138 bus->activity = FALSE;
4139 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
4142 dhd_os_sdunlock(bus->dhd);
4146 DHD_CTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__,
4147 name, (set ? "set" : "get"), len, plen));
4149 /* set up 'params' pointer in case this is a set command so that
4150 * the convenience int and bool code can be common to set and get
4152 if (params == NULL) {
4157 if (vi->type == IOVT_VOID)
4159 else if (vi->type == IOVT_BUFFER)
4162 /* all other types are integer sized */
4163 val_size = sizeof(int);
4165 actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
4166 bcmerror = dhdsdio_doiovar(bus, vi, actionid, name, params, plen, arg, len, val_size);
4173 dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex)
4176 uint32 local_hostintmask;
4180 bool wlfc_enabled = FALSE;
4185 osh = bus->dhd->osh;
4186 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4188 bcmsdh_waitlockfree(bus->sdh);
4191 dhd_os_sdlock(bus->dhd);
4193 if ((bus->dhd->busstate == DHD_BUS_DOWN) || bus->dhd->hang_was_sent) {
4194 /* if Firmware already hangs disbale any interrupt */
4195 bus->dhd->busstate = DHD_BUS_DOWN;
4196 bus->hostintmask = 0;
4197 bcmsdh_intr_disable(bus->sdh);
4202 /* Change our idea of bus state */
4203 bus->dhd->busstate = DHD_BUS_DOWN;
4205 if (KSO_ENAB(bus)) {
4207 /* Enable clock for device interrupts */
4208 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
4210 /* Disable and clear interrupts at the chip level also */
4211 W_SDREG(0, &bus->regs->hostintmask, retries);
4212 local_hostintmask = bus->hostintmask;
4213 bus->hostintmask = 0;
4215 /* Force clocks on backplane to be sure F2 interrupt propagates */
4216 saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
4218 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
4219 (saveclk | SBSDIO_FORCE_HT), &err);
4222 DHD_ERROR(("%s: Failed to force clock for F2: err %d\n",
4223 __FUNCTION__, err));
4226 /* Turn off the bus (F2), free any pending packets */
4227 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
4228 #if !defined(NDISVER) || (NDISVER < 0x0630)
4229 bcmsdh_intr_disable(bus->sdh);
4230 #endif /* !defined(NDISVER) || (NDISVER < 0x0630) */
4231 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL);
4233 /* Clear any pending interrupts now that F2 is disabled */
4234 W_SDREG(local_hostintmask, &bus->regs->intstatus, retries);
4237 /* Turn off the backplane clock (only) */
4238 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
4241 #ifdef PROP_TXSTATUS
4242 wlfc_enabled = (dhd_wlfc_cleanup_txq(bus->dhd, NULL, 0) != WLFC_UNSUPPORTED);
4244 if (!wlfc_enabled) {
4245 #ifdef DHDTCPACK_SUPPRESS
4246 /* Clean tcp_ack_info_tbl in order to prevent access to flushed pkt,
4247 * when there is a newly coming packet from network stack.
4249 dhd_tcpack_info_tbl_clean(bus->dhd);
4250 #endif /* DHDTCPACK_SUPPRESS */
4251 /* Clear the data packet queues */
4252 pktq_flush(osh, &bus->txq, TRUE, NULL, 0);
4255 /* Clear any held glomming stuff */
4257 PKTFREE(osh, bus->glomd, FALSE);
4260 PKTFREE(osh, bus->glom, FALSE);
4262 bus->glom = bus->glomd = NULL;
4264 /* Clear rx control and wake any waiters */
4266 dhd_os_ioctl_resp_wake(bus->dhd);
4268 /* Reset some F2 state stuff */
4269 bus->rxskip = FALSE;
4270 bus->tx_seq = bus->rx_seq = 0;
4275 dhd_os_sdunlock(bus->dhd);
4278 #if defined(BCMSDIOH_TXGLOM) && defined(BCMSDIOH_STD)
4279 extern uint sd_txglom;
4282 dhd_txglom_enable(dhd_pub_t *dhdp, bool enable)
4284 /* can't enable host txglom by default, some platforms have no
4285 * (or crappy) ADMA support and txglom will cause kernel assertions (e.g.
4288 dhd_bus_t *bus = dhdp->bus;
4289 #ifdef BCMSDIOH_TXGLOM
4294 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4299 #endif /* BCMSDIOH_STD */
4303 memset(buf, 0, sizeof(buf));
4304 bcm_mkiovar("bus:rxglom", (void *)&rxglom, 4, buf, sizeof(buf));
4305 ret = dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0);
4307 bus->txglom_enable = TRUE;
4311 #endif /* BCMSDIOH_STD */
4312 bus->txglom_enable = FALSE;
4315 #endif /* BCMSDIOH_TXGLOM */
4316 bus->txglom_enable = FALSE;
4317 printf("%s: enable %d\n", __FUNCTION__, bus->txglom_enable);
4321 dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex)
4323 dhd_bus_t *bus = dhdp->bus;
4326 uint8 ready, enable;
4330 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4337 dhd_os_sdlock(bus->dhd);
4339 if (bus->sih->chip == BCM43362_CHIP_ID) {
4340 printf("%s: delay 100ms for BCM43362\n", __FUNCTION__);
4341 OSL_DELAY(100000); // terence 20131209: delay for 43362
4344 /* Make sure backplane clock is on, needed to generate F2 interrupt */
4345 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
4346 if (bus->clkstate != CLK_AVAIL) {
4347 DHD_ERROR(("%s: clock state is wrong. state = %d\n", __FUNCTION__, bus->clkstate));
4353 /* Force clocks on backplane to be sure F2 interrupt propagates */
4354 saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
4356 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
4357 (saveclk | SBSDIO_FORCE_HT), &err);
4360 DHD_ERROR(("%s: Failed to force clock for F2: err %d\n", __FUNCTION__, err));
4365 /* Enable function 2 (frame transfers) */
4366 W_SDREG((SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT),
4367 &bus->regs->tosbmailboxdata, retries);
4368 enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2);
4370 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL);
4372 /* Give the dongle some time to do its thing and set IOR2 */
4373 dhd_timeout_start(&tmo, DHD_WAIT_F2RDY * 1000);
4376 while (ready != enable && !dhd_timeout_expired(&tmo))
4377 ready = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IORDY, NULL);
4379 DHD_ERROR(("%s: enable 0x%02x, ready 0x%02x (waited %uus)\n",
4380 __FUNCTION__, enable, ready, tmo.elapsed));
4383 /* If F2 successfully enabled, set core and enable interrupts */
4384 if (ready == enable) {
4385 /* Make sure we're talking to the core. */
4386 if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0)))
4387 bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0);
4388 ASSERT(bus->regs != NULL);
4390 /* Set up the interrupt mask and enable interrupts */
4391 bus->hostintmask = HOSTINTMASK;
4392 /* corerev 4 could use the newer interrupt logic to detect the frames */
4393 if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 4) &&
4394 (bus->rxint_mode != SDIO_DEVICE_HMB_RXINT)) {
4395 bus->hostintmask &= ~I_HMB_FRAME_IND;
4396 bus->hostintmask |= I_XMTDATA_AVAIL;
4398 W_SDREG(bus->hostintmask, &bus->regs->hostintmask, retries);
4400 if (bus->sih->buscorerev < 15) {
4401 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK,
4402 (uint8)watermark, &err);
4405 /* Set bus state according to enable result */
4406 dhdp->busstate = DHD_BUS_DATA;
4408 /* bcmsdh_intr_unmask(bus->sdh); */
4410 bus->intdis = FALSE;
4412 DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__));
4413 bcmsdh_intr_enable(bus->sdh);
4415 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
4416 bcmsdh_intr_disable(bus->sdh);
4423 /* Disable F2 again */
4424 enable = SDIO_FUNC_ENABLE_1;
4425 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL);
4428 if (dhdsdio_sr_cap(bus)) {
4429 dhdsdio_sr_init(bus);
4430 /* Masking the chip active interrupt permanantly */
4431 bus->hostintmask &= ~I_CHIPACTIVE;
4432 W_SDREG(bus->hostintmask, &bus->regs->hostintmask, retries);
4433 DHD_INFO(("%s: disable I_CHIPACTIVE in hostintmask[0x%08x]\n",
4434 __FUNCTION__, bus->hostintmask));
4437 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1,
4438 SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err);
4440 /* If we didn't come up, turn off backplane clock */
4441 if (dhdp->busstate != DHD_BUS_DATA)
4442 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
4446 dhd_os_sdunlock(bus->dhd);
4452 dhdsdio_rxfail(dhd_bus_t *bus, bool abort, bool rtx)
4454 bcmsdh_info_t *sdh = bus->sdh;
4455 sdpcmd_regs_t *regs = bus->regs;
4461 DHD_ERROR(("%s: %sterminate frame%s\n", __FUNCTION__,
4462 (abort ? "abort command, " : ""), (rtx ? ", send NAK" : "")));
4464 if (!KSO_ENAB(bus)) {
4465 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
4470 bcmsdh_abort(sdh, SDIO_FUNC_2);
4473 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, SFC_RF_TERM, &err);
4475 DHD_ERROR(("%s: SBSDIO_FUNC1_FRAMECTRL cmd err\n", __FUNCTION__));
4480 /* Wait until the packet has been flushed (device/FIFO stable) */
4481 for (lastrbc = retries = 0xffff; retries > 0; retries--) {
4482 hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCHI, NULL);
4483 lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCLO, &err);
4485 DHD_ERROR(("%s: SBSDIO_FUNC1_RFAMEBCLO cmd err\n", __FUNCTION__));
4489 bus->f1regdata += 2;
4491 if ((hi == 0) && (lo == 0))
4494 if ((hi > (lastrbc >> 8)) && (lo > (lastrbc & 0x00ff))) {
4495 DHD_ERROR(("%s: count growing: last 0x%04x now 0x%04x\n",
4496 __FUNCTION__, lastrbc, ((hi << 8) + lo)));
4498 lastrbc = (hi << 8) + lo;
4502 DHD_ERROR(("%s: count never zeroed: last 0x%04x\n", __FUNCTION__, lastrbc));
4504 DHD_INFO(("%s: flush took %d iterations\n", __FUNCTION__, (0xffff - retries)));
4509 W_SDREG(SMB_NAK, ®s->tosbmailbox, retries);
4511 if (retries <= retry_limit) {
4516 /* Clear partial in any case */
4520 /* If we can't reach the device, signal failure */
4521 if (err || bcmsdh_regfail(sdh))
4522 bus->dhd->busstate = DHD_BUS_DOWN;
4526 dhdsdio_read_control(dhd_bus_t *bus, uint8 *hdr, uint len, uint doff)
4528 bcmsdh_info_t *sdh = bus->sdh;
4533 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4535 /* Control data already received in aligned rxctl */
4536 if ((bus->bus == SPI_BUS) && (!bus->usebufpool))
4540 /* Set rxctl for frame (w/optional alignment) */
4541 bus->rxctl = bus->rxbuf;
4543 bus->rxctl += firstread;
4544 if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN)))
4545 bus->rxctl += (DHD_SDALIGN - pad);
4546 bus->rxctl -= firstread;
4548 ASSERT(bus->rxctl >= bus->rxbuf);
4550 /* Copy the already-read portion over */
4551 bcopy(hdr, bus->rxctl, firstread);
4552 if (len <= firstread)
4555 /* Copy the full data pkt in gSPI case and process ioctl. */
4556 if (bus->bus == SPI_BUS) {
4557 bcopy(hdr, bus->rxctl, len);
4561 /* Raise rdlen to next SDIO block to avoid tail command */
4562 rdlen = len - firstread;
4563 if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
4564 pad = bus->blocksize - (rdlen % bus->blocksize);
4565 if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
4566 ((len + pad) < bus->dhd->maxctl))
4568 } else if (rdlen % DHD_SDALIGN) {
4569 rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
4572 /* Satisfy length-alignment requirements */
4573 if (forcealign && (rdlen & (ALIGNMENT - 1)))
4574 rdlen = ROUNDUP(rdlen, ALIGNMENT);
4576 /* Drop if the read is too big or it exceeds our maximum */
4577 if ((rdlen + firstread) > bus->dhd->maxctl) {
4578 DHD_ERROR(("%s: %d-byte control read exceeds %d-byte buffer\n",
4579 __FUNCTION__, rdlen, bus->dhd->maxctl));
4580 bus->dhd->rx_errors++;
4581 dhdsdio_rxfail(bus, FALSE, FALSE);
4585 if ((len - doff) > bus->dhd->maxctl) {
4586 DHD_ERROR(("%s: %d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n",
4587 __FUNCTION__, len, (len - doff), bus->dhd->maxctl));
4588 bus->dhd->rx_errors++; bus->rx_toolong++;
4589 dhdsdio_rxfail(bus, FALSE, FALSE);
4594 /* Read remainder of frame body into the rxctl buffer */
4595 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
4596 (bus->rxctl + firstread), rdlen, NULL, NULL, NULL);
4598 ASSERT(sdret != BCME_PENDING);
4600 /* Control frame failures need retransmission */
4602 DHD_ERROR(("%s: read %d control bytes failed: %d\n", __FUNCTION__, rdlen, sdret));
4603 bus->rxc_errors++; /* dhd.rx_ctlerrs is higher level */
4604 dhdsdio_rxfail(bus, TRUE, TRUE);
4611 if (DHD_BYTES_ON() && DHD_CTL_ON()) {
4612 prhex("RxCtrl", bus->rxctl, len);
4616 /* Point to valid data and indicate its length */
4618 bus->rxlen = len - doff;
4621 /* Awake any waiters */
4622 dhd_os_ioctl_resp_wake(bus->dhd);
4625 dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf, uint reorder_info_len,
4626 void **pkt, uint32 *pkt_count);
4629 dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq)
4631 uint16 dlen, totlen;
4632 uint8 *dptr, num = 0;
4634 uint16 sublen, check;
4635 void *pfirst, *plast, *pnext;
4636 void * list_tail[DHD_MAX_IFS] = { NULL };
4637 void * list_head[DHD_MAX_IFS] = { NULL };
4639 osl_t *osh = bus->dhd->osh;
4642 uint8 chan, seq, doff, sfdoff;
4644 uchar reorder_info_buf[WLHOST_REORDERDATA_TOTLEN];
4645 uint reorder_info_len;
4648 bool usechain = bus->use_rxchain;
4650 /* If packets, issue read(s) and send up packet chain */
4651 /* Return sequence numbers consumed? */
4653 DHD_TRACE(("dhdsdio_rxglom: start: glomd %p glom %p\n", bus->glomd, bus->glom));
4655 /* If there's a descriptor, generate the packet chain */
4657 dhd_os_sdlock_rxq(bus->dhd);
4659 pfirst = plast = pnext = NULL;
4660 dlen = (uint16)PKTLEN(osh, bus->glomd);
4661 dptr = PKTDATA(osh, bus->glomd);
4662 if (!dlen || (dlen & 1)) {
4663 DHD_ERROR(("%s: bad glomd len (%d), ignore descriptor\n",
4664 __FUNCTION__, dlen));
4668 for (totlen = num = 0; dlen; num++) {
4669 /* Get (and move past) next length */
4670 sublen = ltoh16_ua(dptr);
4671 dlen -= sizeof(uint16);
4672 dptr += sizeof(uint16);
4673 if ((sublen < SDPCM_HDRLEN) ||
4674 ((num == 0) && (sublen < (2 * SDPCM_HDRLEN)))) {
4675 DHD_ERROR(("%s: descriptor len %d bad: %d\n",
4676 __FUNCTION__, num, sublen));
4680 if (sublen % DHD_SDALIGN) {
4681 DHD_ERROR(("%s: sublen %d not a multiple of %d\n",
4682 __FUNCTION__, sublen, DHD_SDALIGN));
4687 /* For last frame, adjust read len so total is a block multiple */
4689 sublen += (ROUNDUP(totlen, bus->blocksize) - totlen);
4690 totlen = ROUNDUP(totlen, bus->blocksize);
4693 /* Allocate/chain packet for next subframe */
4694 if ((pnext = PKTGET(osh, sublen + DHD_SDALIGN, FALSE)) == NULL) {
4695 DHD_ERROR(("%s: PKTGET failed, num %d len %d\n",
4696 __FUNCTION__, num, sublen));
4699 ASSERT(!PKTLINK(pnext));
4702 pfirst = plast = pnext;
4705 PKTSETNEXT(osh, plast, pnext);
4709 /* Adhere to start alignment requirements */
4710 PKTALIGN(osh, pnext, sublen, DHD_SDALIGN);
4713 /* If all allocations succeeded, save packet chain in bus structure */
4715 DHD_GLOM(("%s: allocated %d-byte packet chain for %d subframes\n",
4716 __FUNCTION__, totlen, num));
4717 if (DHD_GLOM_ON() && bus->nextlen) {
4718 if (totlen != bus->nextlen) {
4719 DHD_GLOM(("%s: glomdesc mismatch: nextlen %d glomdesc %d "
4720 "rxseq %d\n", __FUNCTION__, bus->nextlen,
4725 pfirst = pnext = NULL;
4728 PKTFREE(osh, pfirst, FALSE);
4733 /* Done with descriptor packet */
4734 PKTFREE(osh, bus->glomd, FALSE);
4738 dhd_os_sdunlock_rxq(bus->dhd);
4741 /* Ok -- either we just generated a packet chain, or had one from before */
4743 if (DHD_GLOM_ON()) {
4744 DHD_GLOM(("%s: attempt superframe read, packet chain:\n", __FUNCTION__));
4745 for (pnext = bus->glom; pnext; pnext = PKTNEXT(osh, pnext)) {
4746 DHD_GLOM((" %p: %p len 0x%04x (%d)\n",
4747 pnext, (uint8*)PKTDATA(osh, pnext),
4748 PKTLEN(osh, pnext), PKTLEN(osh, pnext)));
4753 dlen = (uint16)pkttotlen(osh, pfirst);
4755 /* Do an SDIO read for the superframe. Configurable iovar to
4756 * read directly into the chained packet, or allocate a large
4757 * packet and and copy into the chain.
4760 errcode = dhd_bcmsdh_recv_buf(bus,
4761 bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2,
4762 F2SYNC, (uint8*)PKTDATA(osh, pfirst),
4763 dlen, pfirst, NULL, NULL);
4764 } else if (bus->dataptr) {
4765 errcode = dhd_bcmsdh_recv_buf(bus,
4766 bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2,
4767 F2SYNC, bus->dataptr,
4768 dlen, NULL, NULL, NULL);
4769 sublen = (uint16)pktfrombuf(osh, pfirst, 0, dlen, bus->dataptr);
4770 if (sublen != dlen) {
4771 DHD_ERROR(("%s: FAILED TO COPY, dlen %d sublen %d\n",
4772 __FUNCTION__, dlen, sublen));
4777 DHD_ERROR(("COULDN'T ALLOC %d-BYTE GLOM, FORCE FAILURE\n", dlen));
4781 ASSERT(errcode != BCME_PENDING);
4783 /* On failure, kill the superframe, allow a couple retries */
4785 DHD_ERROR(("%s: glom read of %d bytes failed: %d\n",
4786 __FUNCTION__, dlen, errcode));
4787 bus->dhd->rx_errors++;
4789 if (bus->glomerr++ < 3) {
4790 dhdsdio_rxfail(bus, TRUE, TRUE);
4793 dhdsdio_rxfail(bus, TRUE, FALSE);
4794 dhd_os_sdlock_rxq(bus->dhd);
4795 PKTFREE(osh, bus->glom, FALSE);
4796 dhd_os_sdunlock_rxq(bus->dhd);
4804 if (DHD_GLOM_ON()) {
4805 prhex("SUPERFRAME", PKTDATA(osh, pfirst),
4806 MIN(PKTLEN(osh, pfirst), 48));
4811 /* Validate the superframe header */
4812 dptr = (uint8 *)PKTDATA(osh, pfirst);
4813 sublen = ltoh16_ua(dptr);
4814 check = ltoh16_ua(dptr + sizeof(uint16));
4816 chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
4817 seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
4818 bus->nextlen = dptr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
4819 if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
4820 DHD_INFO(("%s: got frame w/nextlen too large (%d) seq %d\n",
4821 __FUNCTION__, bus->nextlen, seq));
4824 doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
4825 txmax = SDPCM_WINDOW_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
4828 if ((uint16)~(sublen^check)) {
4829 DHD_ERROR(("%s (superframe): HW hdr error: len/check 0x%04x/0x%04x\n",
4830 __FUNCTION__, sublen, check));
4832 } else if (ROUNDUP(sublen, bus->blocksize) != dlen) {
4833 DHD_ERROR(("%s (superframe): len 0x%04x, rounded 0x%04x, expect 0x%04x\n",
4834 __FUNCTION__, sublen, ROUNDUP(sublen, bus->blocksize), dlen));
4836 } else if (SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]) != SDPCM_GLOM_CHANNEL) {
4837 DHD_ERROR(("%s (superframe): bad channel %d\n", __FUNCTION__,
4838 SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN])));
4840 } else if (SDPCM_GLOMDESC(&dptr[SDPCM_FRAMETAG_LEN])) {
4841 DHD_ERROR(("%s (superframe): got second descriptor?\n", __FUNCTION__));
4843 } else if ((doff < SDPCM_HDRLEN) ||
4844 (doff > (PKTLEN(osh, pfirst) - SDPCM_HDRLEN))) {
4845 DHD_ERROR(("%s (superframe): Bad data offset %d: HW %d pkt %d min %d\n",
4846 __FUNCTION__, doff, sublen, PKTLEN(osh, pfirst),
4851 /* Check sequence number of superframe SW header */
4853 DHD_INFO(("%s: (superframe) rx_seq %d, expected %d\n",
4854 __FUNCTION__, seq, rxseq));
4859 /* Check window for sanity */
4860 if ((uint8)(txmax - bus->tx_seq) > 0x70) {
4861 DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
4862 __FUNCTION__, txmax, bus->tx_seq));
4863 txmax = bus->tx_max;
4865 bus->tx_max = txmax;
4867 /* Remove superframe header, remember offset */
4868 PKTPULL(osh, pfirst, doff);
4871 /* Validate all the subframe headers */
4872 for (num = 0, pnext = pfirst; pnext && !errcode;
4873 num++, pnext = PKTNEXT(osh, pnext)) {
4874 dptr = (uint8 *)PKTDATA(osh, pnext);
4875 dlen = (uint16)PKTLEN(osh, pnext);
4876 sublen = ltoh16_ua(dptr);
4877 check = ltoh16_ua(dptr + sizeof(uint16));
4878 chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
4879 doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
4881 if (DHD_GLOM_ON()) {
4882 prhex("subframe", dptr, 32);
4886 if ((uint16)~(sublen^check)) {
4887 DHD_ERROR(("%s (subframe %d): HW hdr error: "
4888 "len/check 0x%04x/0x%04x\n",
4889 __FUNCTION__, num, sublen, check));
4891 } else if ((sublen > dlen) || (sublen < SDPCM_HDRLEN)) {
4892 DHD_ERROR(("%s (subframe %d): length mismatch: "
4893 "len 0x%04x, expect 0x%04x\n",
4894 __FUNCTION__, num, sublen, dlen));
4896 } else if ((chan != SDPCM_DATA_CHANNEL) &&
4897 (chan != SDPCM_EVENT_CHANNEL)) {
4898 DHD_ERROR(("%s (subframe %d): bad channel %d\n",
4899 __FUNCTION__, num, chan));
4901 } else if ((doff < SDPCM_HDRLEN) || (doff > sublen)) {
4902 DHD_ERROR(("%s (subframe %d): Bad data offset %d: HW %d min %d\n",
4903 __FUNCTION__, num, doff, sublen, SDPCM_HDRLEN));
4909 /* Terminate frame on error, request a couple retries */
4910 if (bus->glomerr++ < 3) {
4911 /* Restore superframe header space */
4912 PKTPUSH(osh, pfirst, sfdoff);
4913 dhdsdio_rxfail(bus, TRUE, TRUE);
4916 dhdsdio_rxfail(bus, TRUE, FALSE);
4917 dhd_os_sdlock_rxq(bus->dhd);
4918 PKTFREE(osh, bus->glom, FALSE);
4919 dhd_os_sdunlock_rxq(bus->dhd);
4927 /* Basic SD framing looks ok - process each packet (header) */
4931 dhd_os_sdlock_rxq(bus->dhd);
4932 for (num = 0; pfirst; rxseq++, pfirst = pnext) {
4933 pnext = PKTNEXT(osh, pfirst);
4934 PKTSETNEXT(osh, pfirst, NULL);
4936 dptr = (uint8 *)PKTDATA(osh, pfirst);
4937 sublen = ltoh16_ua(dptr);
4938 chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
4939 seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
4940 doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
4942 DHD_GLOM(("%s: Get subframe %d, %p(%p/%d), sublen %d chan %d seq %d\n",
4943 __FUNCTION__, num, pfirst, PKTDATA(osh, pfirst),
4944 PKTLEN(osh, pfirst), sublen, chan, seq));
4946 ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL));
4949 DHD_GLOM(("%s: rx_seq %d, expected %d\n",
4950 __FUNCTION__, seq, rxseq));
4956 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
4957 prhex("Rx Subframe Data", dptr, dlen);
4961 PKTSETLEN(osh, pfirst, sublen);
4962 PKTPULL(osh, pfirst, doff);
4964 reorder_info_len = sizeof(reorder_info_buf);
4966 if (PKTLEN(osh, pfirst) == 0) {
4967 PKTFREE(bus->dhd->osh, pfirst, FALSE);
4969 } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pfirst, reorder_info_buf,
4970 &reorder_info_len) != 0) {
4971 DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__));
4972 bus->dhd->rx_errors++;
4973 PKTFREE(osh, pfirst, FALSE);
4976 if (reorder_info_len) {
4977 uint32 free_buf_count;
4981 /* Reordering info from the firmware */
4982 dhd_process_pkt_reorder_info(bus->dhd, reorder_info_buf,
4983 reorder_info_len, &ppfirst, &free_buf_count);
4985 if (free_buf_count == 0) {
4991 /* go to the end of the chain and attach the pnext there */
4993 while (PKTNEXT(osh, temp) != NULL) {
4994 temp = PKTNEXT(osh, temp);
4997 if (list_tail[ifidx] == NULL)
4998 list_head[ifidx] = ppfirst;
5000 PKTSETNEXT(osh, list_tail[ifidx], ppfirst);
5001 list_tail[ifidx] = pfirst;
5004 num += (uint8)free_buf_count;
5007 /* this packet will go up, link back into chain and count it */
5009 if (list_tail[ifidx] == NULL) {
5010 list_head[ifidx] = list_tail[ifidx] = pfirst;
5013 PKTSETNEXT(osh, list_tail[ifidx], pfirst);
5014 list_tail[ifidx] = pfirst;
5019 if (DHD_GLOM_ON()) {
5020 DHD_GLOM(("%s subframe %d to stack, %p(%p/%d) nxt/lnk %p/%p\n",
5021 __FUNCTION__, num, pfirst,
5022 PKTDATA(osh, pfirst), PKTLEN(osh, pfirst),
5023 PKTNEXT(osh, pfirst), PKTLINK(pfirst)));
5024 prhex("", (uint8 *)PKTDATA(osh, pfirst),
5025 MIN(PKTLEN(osh, pfirst), 32));
5027 #endif /* DHD_DEBUG */
5029 dhd_os_sdunlock_rxq(bus->dhd);
5031 for (idx = 0; idx < DHD_MAX_IFS; idx++) {
5032 if (list_head[idx]) {
5035 temp = list_head[idx];
5037 temp = PKTNEXT(osh, temp);
5041 dhd_os_sdunlock(bus->dhd);
5042 dhd_rx_frame(bus->dhd, idx, list_head[idx], cnt, 0);
5043 dhd_os_sdlock(bus->dhd);
5047 bus->rxglomframes++;
5048 bus->rxglompkts += num;
5054 /* Return TRUE if there may be more frames to read */
5056 dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished)
5058 osl_t *osh = bus->dhd->osh;
5059 bcmsdh_info_t *sdh = bus->sdh;
5061 uint16 len, check; /* Extracted hardware header fields */
5062 uint8 chan, seq, doff; /* Extracted software header fields */
5063 uint8 fcbits; /* Extracted fcbits from software header */
5066 void *pkt; /* Packet for event or data frames */
5067 uint16 pad; /* Number of pad bytes to read */
5068 uint16 rdlen; /* Total number of bytes to read */
5069 uint8 rxseq; /* Next sequence number to expect */
5070 uint rxleft = 0; /* Remaining number of frames allowed */
5071 int sdret; /* Return code from bcmsdh calls */
5072 uint8 txmax; /* Maximum tx sequence offered */
5073 bool len_consistent; /* Result of comparing readahead len and len from hw-hdr */
5076 uint rxcount = 0; /* Total frames read */
5077 uchar reorder_info_buf[WLHOST_REORDERDATA_TOTLEN];
5078 uint reorder_info_len;
5081 #if defined(DHD_DEBUG) || defined(SDTEST)
5082 bool sdtest = FALSE; /* To limit message spew from test mode */
5085 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5087 bus->readframes = TRUE;
5089 if (!KSO_ENAB(bus)) {
5090 DHD_ERROR(("%s: KSO off\n", __FUNCTION__));
5091 bus->readframes = FALSE;
5098 /* Allow pktgen to override maxframes */
5099 if (bus->pktgen_count && (bus->pktgen_mode == DHD_PKTGEN_RECV)) {
5100 maxframes = bus->pktgen_count;
5105 /* Not finished unless we encounter no more frames indication */
5109 for (rxseq = bus->rx_seq, rxleft = maxframes;
5110 !bus->rxskip && rxleft && bus->dhd->busstate != DHD_BUS_DOWN;
5111 rxseq++, rxleft--) {
5112 #ifdef DHDTCPACK_SUP_DBG
5113 if (bus->dhd->tcpack_sup_mode != TCPACK_SUP_DELAYTX) {
5114 if (bus->dotxinrx == FALSE)
5115 DHD_ERROR(("%s %d: dotxinrx FALSE with tcpack_sub_mode %d\n",
5116 __FUNCTION__, __LINE__, bus->dhd->tcpack_sup_mode));
5118 #ifdef DEBUG_COUNTER
5119 else if (pktq_mlen(&bus->txq, ~bus->flowcontrol) > 0) {
5120 tack_tbl.cnt[bus->dotxinrx ? 6 : 7]++;
5122 #endif /* DEBUG_COUNTER */
5123 #endif /* DHDTCPACK_SUP_DBG */
5124 /* tx more to improve rx performance */
5125 if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL)) {
5126 dhdsdio_sendpendctl(bus);
5127 } else if (bus->dotxinrx && (bus->clkstate == CLK_AVAIL) &&
5128 !bus->fcstate && DATAOK(bus) &&
5129 (pktq_mlen(&bus->txq, ~bus->flowcontrol) > bus->txinrx_thres)) {
5130 dhdsdio_sendfromq(bus, dhd_txbound);
5131 #ifdef DHDTCPACK_SUPPRESS
5132 /* In TCPACK_SUP_DELAYTX mode, do txinrx only if
5133 * 1. Any DATA packet to TX
5134 * 2. TCPACK to TCPDATA PSH packets.
5137 bus->dotxinrx = (bus->dhd->tcpack_sup_mode == TCPACK_SUP_DELAYTX) ?
5142 /* Handle glomming separately */
5143 if (bus->glom || bus->glomd) {
5145 DHD_GLOM(("%s: calling rxglom: glomd %p, glom %p\n",
5146 __FUNCTION__, bus->glomd, bus->glom));
5147 cnt = dhdsdio_rxglom(bus, rxseq);
5148 DHD_GLOM(("%s: rxglom returned %d\n", __FUNCTION__, cnt));
5150 rxleft = (rxleft > cnt) ? (rxleft - cnt) : 1;
5154 /* Try doing single read if we can */
5155 if (dhd_readahead && bus->nextlen) {
5156 uint16 nextlen = bus->nextlen;
5159 if (bus->bus == SPI_BUS) {
5160 rdlen = len = nextlen;
5163 rdlen = len = nextlen << 4;
5165 /* Pad read to blocksize for efficiency */
5166 if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
5167 pad = bus->blocksize - (rdlen % bus->blocksize);
5168 if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
5169 ((rdlen + pad + firstread) < MAX_RX_DATASZ))
5171 } else if (rdlen % DHD_SDALIGN) {
5172 rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
5176 /* We use bus->rxctl buffer in WinXP for initial control pkt receives.
5177 * Later we use buffer-poll for data as well as control packets.
5178 * This is required because dhd receives full frame in gSPI unlike SDIO.
5179 * After the frame is received we have to distinguish whether it is data
5180 * or non-data frame.
5182 /* Allocate a packet buffer */
5183 dhd_os_sdlock_rxq(bus->dhd);
5184 if (!(pkt = PKTGET(osh, rdlen + DHD_SDALIGN, FALSE))) {
5185 if (bus->bus == SPI_BUS) {
5186 bus->usebufpool = FALSE;
5187 bus->rxctl = bus->rxbuf;
5189 bus->rxctl += firstread;
5190 if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN)))
5191 bus->rxctl += (DHD_SDALIGN - pad);
5192 bus->rxctl -= firstread;
5194 ASSERT(bus->rxctl >= bus->rxbuf);
5196 /* Read the entire frame */
5197 sdret = dhd_bcmsdh_recv_buf(bus,
5198 bcmsdh_cur_sbwad(sdh),
5200 F2SYNC, rxbuf, rdlen,
5203 ASSERT(sdret != BCME_PENDING);
5206 /* Control frame failures need retransmission */
5208 DHD_ERROR(("%s: read %d control bytes failed: %d\n",
5209 __FUNCTION__, rdlen, sdret));
5210 /* dhd.rx_ctlerrs is higher level */
5212 dhd_os_sdunlock_rxq(bus->dhd);
5213 dhdsdio_rxfail(bus, TRUE,
5214 (bus->bus == SPI_BUS) ? FALSE : TRUE);
5218 /* Give up on data, request rtx of events */
5219 DHD_ERROR(("%s (nextlen): PKTGET failed: len %d rdlen %d "
5220 "expected rxseq %d\n",
5221 __FUNCTION__, len, rdlen, rxseq));
5222 /* Just go try again w/normal header read */
5223 dhd_os_sdunlock_rxq(bus->dhd);
5227 if (bus->bus == SPI_BUS)
5228 bus->usebufpool = TRUE;
5230 ASSERT(!PKTLINK(pkt));
5231 PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN);
5232 rxbuf = (uint8 *)PKTDATA(osh, pkt);
5233 /* Read the entire frame */
5234 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh),
5236 F2SYNC, rxbuf, rdlen,
5239 ASSERT(sdret != BCME_PENDING);
5242 DHD_ERROR(("%s (nextlen): read %d bytes failed: %d\n",
5243 __FUNCTION__, rdlen, sdret));
5244 PKTFREE(bus->dhd->osh, pkt, FALSE);
5245 bus->dhd->rx_errors++;
5246 dhd_os_sdunlock_rxq(bus->dhd);
5247 /* Force retry w/normal header read. Don't attempt NAK for
5250 dhdsdio_rxfail(bus, TRUE,
5251 (bus->bus == SPI_BUS) ? FALSE : TRUE);
5255 dhd_os_sdunlock_rxq(bus->dhd);
5257 /* Now check the header */
5258 bcopy(rxbuf, bus->rxhdr, SDPCM_HDRLEN);
5260 /* Extract hardware header fields */
5261 len = ltoh16_ua(bus->rxhdr);
5262 check = ltoh16_ua(bus->rxhdr + sizeof(uint16));
5264 /* All zeros means readahead info was bad */
5266 DHD_INFO(("%s (nextlen): read zeros in HW header???\n",
5268 dhd_os_sdlock_rxq(bus->dhd);
5270 dhd_os_sdunlock_rxq(bus->dhd);
5271 GSPI_PR55150_BAILOUT;
5275 /* Validate check bytes */
5276 if ((uint16)~(len^check)) {
5277 DHD_ERROR(("%s (nextlen): HW hdr error: nextlen/len/check"
5278 " 0x%04x/0x%04x/0x%04x\n", __FUNCTION__, nextlen,
5280 dhd_os_sdlock_rxq(bus->dhd);
5282 dhd_os_sdunlock_rxq(bus->dhd);
5284 dhdsdio_rxfail(bus, FALSE, FALSE);
5285 GSPI_PR55150_BAILOUT;
5289 /* Validate frame length */
5290 if (len < SDPCM_HDRLEN) {
5291 DHD_ERROR(("%s (nextlen): HW hdr length invalid: %d\n",
5292 __FUNCTION__, len));
5293 dhd_os_sdlock_rxq(bus->dhd);
5295 dhd_os_sdunlock_rxq(bus->dhd);
5296 GSPI_PR55150_BAILOUT;
5300 /* Check for consistency with readahead info */
5301 len_consistent = (nextlen != (ROUNDUP(len, 16) >> 4));
5302 if (len_consistent) {
5303 /* Mismatch, force retry w/normal header (may be >4K) */
5304 DHD_ERROR(("%s (nextlen): mismatch, nextlen %d len %d rnd %d; "
5305 "expected rxseq %d\n",
5306 __FUNCTION__, nextlen, len, ROUNDUP(len, 16), rxseq));
5307 dhd_os_sdlock_rxq(bus->dhd);
5309 dhd_os_sdunlock_rxq(bus->dhd);
5310 dhdsdio_rxfail(bus, TRUE, (bus->bus == SPI_BUS) ? FALSE : TRUE);
5311 GSPI_PR55150_BAILOUT;
5316 /* Extract software header fields */
5317 chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5318 seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5319 doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5320 txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5323 bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
5324 if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
5325 DHD_INFO(("%s (nextlen): got frame w/nextlen too large"
5326 " (%d), seq %d\n", __FUNCTION__, bus->nextlen,
5331 bus->dhd->rx_readahead_cnt ++;
5332 /* Handle Flow Control */
5333 fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5336 if (~bus->flowcontrol & fcbits) {
5340 if (bus->flowcontrol & ~fcbits) {
5347 bus->flowcontrol = fcbits;
5350 /* Check and update sequence number */
5352 DHD_INFO(("%s (nextlen): rx_seq %d, expected %d\n",
5353 __FUNCTION__, seq, rxseq));
5358 /* Check window for sanity */
5359 if ((uint8)(txmax - bus->tx_seq) > 0x70) {
5360 DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
5361 __FUNCTION__, txmax, bus->tx_seq));
5362 txmax = bus->tx_max;
5364 bus->tx_max = txmax;
5367 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
5368 prhex("Rx Data", rxbuf, len);
5369 } else if (DHD_HDRS_ON()) {
5370 prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN);
5374 if (chan == SDPCM_CONTROL_CHANNEL) {
5375 if (bus->bus == SPI_BUS) {
5376 dhdsdio_read_control(bus, rxbuf, len, doff);
5377 if (bus->usebufpool) {
5378 dhd_os_sdlock_rxq(bus->dhd);
5379 PKTFREE(bus->dhd->osh, pkt, FALSE);
5380 dhd_os_sdunlock_rxq(bus->dhd);
5384 DHD_ERROR(("%s (nextlen): readahead on control"
5385 " packet %d?\n", __FUNCTION__, seq));
5386 /* Force retry w/normal header read */
5388 dhdsdio_rxfail(bus, FALSE, TRUE);
5389 dhd_os_sdlock_rxq(bus->dhd);
5391 dhd_os_sdunlock_rxq(bus->dhd);
5396 if ((bus->bus == SPI_BUS) && !bus->usebufpool) {
5397 DHD_ERROR(("Received %d bytes on %d channel. Running out of "
5398 "rx pktbuf's or not yet malloced.\n", len, chan));
5402 /* Validate data offset */
5403 if ((doff < SDPCM_HDRLEN) || (doff > len)) {
5404 DHD_ERROR(("%s (nextlen): bad data offset %d: HW len %d min %d\n",
5405 __FUNCTION__, doff, len, SDPCM_HDRLEN));
5406 dhd_os_sdlock_rxq(bus->dhd);
5408 dhd_os_sdunlock_rxq(bus->dhd);
5410 dhdsdio_rxfail(bus, FALSE, FALSE);
5414 /* All done with this one -- now deliver the packet */
5417 /* gSPI frames should not be handled in fractions */
5418 if (bus->bus == SPI_BUS) {
5422 /* Read frame header (hardware and software) */
5423 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
5424 bus->rxhdr, firstread, NULL, NULL, NULL);
5426 ASSERT(sdret != BCME_PENDING);
5429 DHD_ERROR(("%s: RXHEADER FAILED: %d\n", __FUNCTION__, sdret));
5431 dhdsdio_rxfail(bus, TRUE, TRUE);
5436 if (DHD_BYTES_ON() || DHD_HDRS_ON()) {
5437 prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN);
5441 /* Extract hardware header fields */
5442 len = ltoh16_ua(bus->rxhdr);
5443 check = ltoh16_ua(bus->rxhdr + sizeof(uint16));
5445 /* All zeros means no more frames */
5451 /* Validate check bytes */
5452 if ((uint16)~(len^check)) {
5453 DHD_ERROR(("%s: HW hdr error: len/check 0x%04x/0x%04x\n",
5454 __FUNCTION__, len, check));
5456 dhdsdio_rxfail(bus, FALSE, FALSE);
5460 /* Validate frame length */
5461 if (len < SDPCM_HDRLEN) {
5462 DHD_ERROR(("%s: HW hdr length invalid: %d\n", __FUNCTION__, len));
5466 /* Extract software header fields */
5467 chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5468 seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5469 doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5470 txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5472 /* Validate data offset */
5473 if ((doff < SDPCM_HDRLEN) || (doff > len)) {
5474 DHD_ERROR(("%s: Bad data offset %d: HW len %d, min %d seq %d\n",
5475 __FUNCTION__, doff, len, SDPCM_HDRLEN, seq));
5478 dhdsdio_rxfail(bus, FALSE, FALSE);
5482 /* Save the readahead length if there is one */
5483 bus->nextlen = bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
5484 if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
5485 DHD_INFO(("%s (nextlen): got frame w/nextlen too large (%d), seq %d\n",
5486 __FUNCTION__, bus->nextlen, seq));
5490 /* Handle Flow Control */
5491 fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5494 if (~bus->flowcontrol & fcbits) {
5498 if (bus->flowcontrol & ~fcbits) {
5505 bus->flowcontrol = fcbits;
5508 /* Check and update sequence number */
5510 DHD_INFO(("%s: rx_seq %d, expected %d\n", __FUNCTION__, seq, rxseq));
5515 /* Check window for sanity */
5516 if ((uint8)(txmax - bus->tx_seq) > 0x70) {
5517 DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
5518 __FUNCTION__, txmax, bus->tx_seq));
5519 txmax = bus->tx_max;
5521 bus->tx_max = txmax;
5523 /* Call a separate function for control frames */
5524 if (chan == SDPCM_CONTROL_CHANNEL) {
5525 dhdsdio_read_control(bus, bus->rxhdr, len, doff);
5529 ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL) ||
5530 (chan == SDPCM_TEST_CHANNEL) || (chan == SDPCM_GLOM_CHANNEL));
5532 /* Length to read */
5533 rdlen = (len > firstread) ? (len - firstread) : 0;
5535 /* May pad read to blocksize for efficiency */
5536 if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
5537 pad = bus->blocksize - (rdlen % bus->blocksize);
5538 if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
5539 ((rdlen + pad + firstread) < MAX_RX_DATASZ))
5541 } else if (rdlen % DHD_SDALIGN) {
5542 rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
5545 /* Satisfy length-alignment requirements */
5546 if (forcealign && (rdlen & (ALIGNMENT - 1)))
5547 rdlen = ROUNDUP(rdlen, ALIGNMENT);
5549 if ((rdlen + firstread) > MAX_RX_DATASZ) {
5550 /* Too long -- skip this frame */
5551 DHD_ERROR(("%s: too long: len %d rdlen %d\n", __FUNCTION__, len, rdlen));
5552 bus->dhd->rx_errors++; bus->rx_toolong++;
5553 dhdsdio_rxfail(bus, FALSE, FALSE);
5557 dhd_os_sdlock_rxq(bus->dhd);
5558 if (!(pkt = PKTGET(osh, (rdlen + firstread + DHD_SDALIGN), FALSE))) {
5559 /* Give up on data, request rtx of events */
5560 DHD_ERROR(("%s: PKTGET failed: rdlen %d chan %d\n",
5561 __FUNCTION__, rdlen, chan));
5562 bus->dhd->rx_dropped++;
5563 dhd_os_sdunlock_rxq(bus->dhd);
5564 dhdsdio_rxfail(bus, FALSE, RETRYCHAN(chan));
5567 dhd_os_sdunlock_rxq(bus->dhd);
5569 ASSERT(!PKTLINK(pkt));
5571 /* Leave room for what we already read, and align remainder */
5572 ASSERT(firstread < (PKTLEN(osh, pkt)));
5573 PKTPULL(osh, pkt, firstread);
5574 PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN);
5576 /* Read the remaining frame data */
5577 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
5578 ((uint8 *)PKTDATA(osh, pkt)), rdlen, pkt, NULL, NULL);
5580 ASSERT(sdret != BCME_PENDING);
5583 DHD_ERROR(("%s: read %d %s bytes failed: %d\n", __FUNCTION__, rdlen,
5584 ((chan == SDPCM_EVENT_CHANNEL) ? "event" :
5585 ((chan == SDPCM_DATA_CHANNEL) ? "data" : "test")), sdret));
5586 dhd_os_sdlock_rxq(bus->dhd);
5587 PKTFREE(bus->dhd->osh, pkt, FALSE);
5588 dhd_os_sdunlock_rxq(bus->dhd);
5589 bus->dhd->rx_errors++;
5590 dhdsdio_rxfail(bus, TRUE, RETRYCHAN(chan));
5594 /* Copy the already-read portion */
5595 PKTPUSH(osh, pkt, firstread);
5596 bcopy(bus->rxhdr, PKTDATA(osh, pkt), firstread);
5599 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
5600 prhex("Rx Data", PKTDATA(osh, pkt), len);
5605 /* Save superframe descriptor and allocate packet frame */
5606 if (chan == SDPCM_GLOM_CHANNEL) {
5607 if (SDPCM_GLOMDESC(&bus->rxhdr[SDPCM_FRAMETAG_LEN])) {
5608 DHD_GLOM(("%s: got glom descriptor, %d bytes:\n",
5609 __FUNCTION__, len));
5611 if (DHD_GLOM_ON()) {
5612 prhex("Glom Data", PKTDATA(osh, pkt), len);
5615 PKTSETLEN(osh, pkt, len);
5616 ASSERT(doff == SDPCM_HDRLEN);
5617 PKTPULL(osh, pkt, SDPCM_HDRLEN);
5620 DHD_ERROR(("%s: glom superframe w/o descriptor!\n", __FUNCTION__));
5621 dhdsdio_rxfail(bus, FALSE, FALSE);
5626 /* Fill in packet len and prio, deliver upward */
5627 PKTSETLEN(osh, pkt, len);
5628 PKTPULL(osh, pkt, doff);
5631 /* Test channel packets are processed separately */
5632 if (chan == SDPCM_TEST_CHANNEL) {
5633 dhdsdio_testrcv(bus, pkt, seq);
5638 if (PKTLEN(osh, pkt) == 0) {
5639 dhd_os_sdlock_rxq(bus->dhd);
5640 PKTFREE(bus->dhd->osh, pkt, FALSE);
5641 dhd_os_sdunlock_rxq(bus->dhd);
5643 } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pkt, reorder_info_buf,
5644 &reorder_info_len) != 0) {
5645 DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__));
5646 dhd_os_sdlock_rxq(bus->dhd);
5647 PKTFREE(bus->dhd->osh, pkt, FALSE);
5648 dhd_os_sdunlock_rxq(bus->dhd);
5649 bus->dhd->rx_errors++;
5652 if (reorder_info_len) {
5653 /* Reordering info from the firmware */
5654 dhd_process_pkt_reorder_info(bus->dhd, reorder_info_buf, reorder_info_len,
5662 /* Unlock during rx call */
5663 dhd_os_sdunlock(bus->dhd);
5664 dhd_rx_frame(bus->dhd, ifidx, pkt, pkt_count, chan);
5665 dhd_os_sdlock(bus->dhd);
5666 #if defined(SDIO_ISR_THREAD)
5667 /* terence 20150615: fix for below error due to bussleep in watchdog after dhd_os_sdunlock here,
5668 * so call BUS_WAKE to wake up bus again
5669 * dhd_bcmsdh_recv_buf: Device asleep
5670 * dhdsdio_readframes: RXHEADER FAILED: -40
5671 * dhdsdio_rxfail: abort command, terminate frame, send NAK
5676 rxcount = maxframes - rxleft;
5678 /* Message if we hit the limit */
5679 if (!rxleft && !sdtest)
5680 DHD_DATA(("%s: hit rx limit of %d frames\n", __FUNCTION__, maxframes));
5682 #endif /* DHD_DEBUG */
5683 DHD_DATA(("%s: processed %d frames\n", __FUNCTION__, rxcount));
5684 /* Back off rxseq if awaiting rtx, update rx_seq */
5687 bus->rx_seq = rxseq;
5689 if (bus->reqbussleep)
5691 dhdsdio_bussleep(bus, TRUE);
5692 bus->reqbussleep = FALSE;
5694 bus->readframes = FALSE;
5700 dhdsdio_hostmail(dhd_bus_t *bus)
5702 sdpcmd_regs_t *regs = bus->regs;
5703 uint32 intstatus = 0;
5708 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5710 /* Read mailbox data and ack that we did so */
5711 R_SDREG(hmb_data, ®s->tohostmailboxdata, retries);
5712 if (retries <= retry_limit)
5713 W_SDREG(SMB_INT_ACK, ®s->tosbmailbox, retries);
5714 bus->f1regdata += 2;
5716 /* Dongle recomposed rx frames, accept them again */
5717 if (hmb_data & HMB_DATA_NAKHANDLED) {
5718 DHD_INFO(("Dongle reports NAK handled, expect rtx of %d\n", bus->rx_seq));
5720 DHD_ERROR(("%s: unexpected NAKHANDLED!\n", __FUNCTION__));
5722 bus->rxskip = FALSE;
5723 intstatus |= FRAME_AVAIL_MASK(bus);
5727 * DEVREADY does not occur with gSPI.
5729 if (hmb_data & (HMB_DATA_DEVREADY | HMB_DATA_FWREADY)) {
5730 bus->sdpcm_ver = (hmb_data & HMB_DATA_VERSION_MASK) >> HMB_DATA_VERSION_SHIFT;
5731 if (bus->sdpcm_ver != SDPCM_PROT_VERSION)
5732 DHD_ERROR(("Version mismatch, dongle reports %d, expecting %d\n",
5733 bus->sdpcm_ver, SDPCM_PROT_VERSION));
5735 DHD_INFO(("Dongle ready, protocol version %d\n", bus->sdpcm_ver));
5736 /* make sure for the SDIO_DEVICE_RXDATAINT_MODE_1 corecontrol is proper */
5737 if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev >= 4) &&
5738 (bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_1)) {
5741 val = R_REG(bus->dhd->osh, &bus->regs->corecontrol);
5742 val &= ~CC_XMTDATAAVAIL_MODE;
5743 val |= CC_XMTDATAAVAIL_CTRL;
5744 W_REG(bus->dhd->osh, &bus->regs->corecontrol, val);
5746 val = R_REG(bus->dhd->osh, &bus->regs->corecontrol);
5750 /* Retrieve console state address now that firmware should have updated it */
5752 sdpcm_shared_t shared;
5753 if (dhdsdio_readshared(bus, &shared) == 0)
5754 bus->console_addr = shared.console_addr;
5756 #endif /* DHD_DEBUG */
5760 * Flow Control has been moved into the RX headers and this out of band
5761 * method isn't used any more. Leave this here for possibly remaining backward
5762 * compatible with older dongles
5764 if (hmb_data & HMB_DATA_FC) {
5765 fcbits = (hmb_data & HMB_DATA_FCDATA_MASK) >> HMB_DATA_FCDATA_SHIFT;
5767 if (fcbits & ~bus->flowcontrol)
5769 if (bus->flowcontrol & ~fcbits)
5773 bus->flowcontrol = fcbits;
5777 /* At least print a message if FW halted */
5778 if (hmb_data & HMB_DATA_FWHALT) {
5779 DHD_ERROR(("INTERNAL ERROR: FIRMWARE HALTED : set BUS DOWN\n"));
5780 dhdsdio_checkdied(bus, NULL, 0);
5781 bus->dhd->busstate = DHD_BUS_DOWN;
5783 #endif /* DHD_DEBUG */
5785 /* Shouldn't be any others */
5786 if (hmb_data & ~(HMB_DATA_DEVREADY |
5788 HMB_DATA_NAKHANDLED |
5791 HMB_DATA_FCDATA_MASK |
5792 HMB_DATA_VERSION_MASK)) {
5793 DHD_ERROR(("Unknown mailbox data content: 0x%02x\n", hmb_data));
5800 dhdsdio_dpc(dhd_bus_t *bus)
5802 bcmsdh_info_t *sdh = bus->sdh;
5803 sdpcmd_regs_t *regs = bus->regs;
5804 uint32 intstatus, newstatus = 0;
5806 uint rxlimit = dhd_rxbound; /* Rx frames to read before resched */
5807 uint txlimit = dhd_txbound; /* Tx frames to send before resched */
5808 uint framecnt = 0; /* Temporary counter of tx/rx frames */
5809 bool rxdone = TRUE; /* Flag for no more read data */
5810 bool resched = FALSE; /* Flag indicating resched wanted */
5811 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5813 dhd_os_sdlock(bus->dhd);
5815 if (bus->dhd->busstate == DHD_BUS_DOWN) {
5816 DHD_ERROR(("%s: Bus down, ret\n", __FUNCTION__));
5818 dhd_os_sdunlock(bus->dhd);
5822 /* Start with leftover status bits */
5823 intstatus = bus->intstatus;
5825 if (!SLPAUTO_ENAB(bus) && !KSO_ENAB(bus)) {
5826 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
5830 /* If waiting for HTAVAIL, check status */
5831 if (!SLPAUTO_ENAB(bus) && (bus->clkstate == CLK_PENDING)) {
5833 uint8 clkctl, devctl = 0;
5836 /* Check for inconsistent device control */
5837 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
5839 DHD_ERROR(("%s: error reading DEVCTL: %d\n", __FUNCTION__, err));
5840 bus->dhd->busstate = DHD_BUS_DOWN;
5842 ASSERT(devctl & SBSDIO_DEVCTL_CA_INT_ONLY);
5844 #endif /* DHD_DEBUG */
5846 /* Read CSR, if clock on switch to AVAIL, else ignore */
5847 clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
5849 DHD_ERROR(("%s: error reading CSR: %d\n", __FUNCTION__, err));
5850 bus->dhd->busstate = DHD_BUS_DOWN;
5853 DHD_INFO(("DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n", devctl, clkctl));
5855 if (SBSDIO_HTAV(clkctl)) {
5856 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
5858 DHD_ERROR(("%s: error reading DEVCTL: %d\n",
5859 __FUNCTION__, err));
5860 bus->dhd->busstate = DHD_BUS_DOWN;
5862 devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
5863 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
5865 DHD_ERROR(("%s: error writing DEVCTL: %d\n",
5866 __FUNCTION__, err));
5867 bus->dhd->busstate = DHD_BUS_DOWN;
5869 bus->clkstate = CLK_AVAIL;
5877 /* Make sure backplane clock is on */
5878 dhdsdio_clkctl(bus, CLK_AVAIL, TRUE);
5879 if (bus->clkstate != CLK_AVAIL)
5882 /* Pending interrupt indicates new device status */
5885 R_SDREG(newstatus, ®s->intstatus, retries);
5887 if (bcmsdh_regfail(bus->sdh))
5889 newstatus &= bus->hostintmask;
5890 bus->fcstate = !!(newstatus & I_HMB_FC_STATE);
5893 if ((bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_0) &&
5894 (newstatus == I_XMTDATA_AVAIL)) {
5897 W_SDREG(newstatus, ®s->intstatus, retries);
5901 /* Merge new bits with previous */
5902 intstatus |= newstatus;
5905 /* Handle flow-control change: read new state in case our ack
5906 * crossed another change interrupt. If change still set, assume
5907 * FC ON for safety, let next loop through do the debounce.
5909 if (intstatus & I_HMB_FC_CHANGE) {
5910 intstatus &= ~I_HMB_FC_CHANGE;
5911 W_SDREG(I_HMB_FC_CHANGE, ®s->intstatus, retries);
5912 R_SDREG(newstatus, ®s->intstatus, retries);
5913 bus->f1regdata += 2;
5914 bus->fcstate = !!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE));
5915 intstatus |= (newstatus & bus->hostintmask);
5918 /* Just being here means nothing more to do for chipactive */
5919 if (intstatus & I_CHIPACTIVE) {
5920 /* ASSERT(bus->clkstate == CLK_AVAIL); */
5921 intstatus &= ~I_CHIPACTIVE;
5924 /* Handle host mailbox indication */
5925 if (intstatus & I_HMB_HOST_INT) {
5926 intstatus &= ~I_HMB_HOST_INT;
5927 intstatus |= dhdsdio_hostmail(bus);
5930 /* Generally don't ask for these, can get CRC errors... */
5931 if (intstatus & I_WR_OOSYNC) {
5932 DHD_ERROR(("Dongle reports WR_OOSYNC\n"));
5933 intstatus &= ~I_WR_OOSYNC;
5936 if (intstatus & I_RD_OOSYNC) {
5937 DHD_ERROR(("Dongle reports RD_OOSYNC\n"));
5938 intstatus &= ~I_RD_OOSYNC;
5941 if (intstatus & I_SBINT) {
5942 DHD_ERROR(("Dongle reports SBINT\n"));
5943 intstatus &= ~I_SBINT;
5946 /* Would be active due to wake-wlan in gSPI */
5947 if (intstatus & I_CHIPACTIVE) {
5948 DHD_INFO(("Dongle reports CHIPACTIVE\n"));
5949 intstatus &= ~I_CHIPACTIVE;
5952 if (intstatus & I_HMB_FC_STATE) {
5953 DHD_INFO(("Dongle reports HMB_FC_STATE\n"));
5954 intstatus &= ~I_HMB_FC_STATE;
5957 /* Ignore frame indications if rxskip is set */
5959 intstatus &= ~FRAME_AVAIL_MASK(bus);
5962 /* On frame indication, read available frames */
5963 if (PKT_AVAILABLE(bus, intstatus)) {
5964 framecnt = dhdsdio_readframes(bus, rxlimit, &rxdone);
5965 if (rxdone || bus->rxskip)
5966 intstatus &= ~FRAME_AVAIL_MASK(bus);
5967 rxlimit -= MIN(framecnt, rxlimit);
5970 /* Keep still-pending events for next scheduling */
5971 bus->intstatus = intstatus;
5974 /* Re-enable interrupts to detect new device events (mailbox, rx frame)
5975 * or clock availability. (Allows tx loop to check ipend if desired.)
5976 * (Unless register access seems hosed, as we may not be able to ACK...)
5978 if (bus->intr && bus->intdis && !bcmsdh_regfail(sdh)) {
5979 DHD_INTR(("%s: enable SDIO interrupts, rxdone %d framecnt %d\n",
5980 __FUNCTION__, rxdone, framecnt));
5981 bus->intdis = FALSE;
5982 #if defined(OOB_INTR_ONLY)
5983 bcmsdh_oob_intr_set(bus->sdh, TRUE);
5984 #endif /* defined(OOB_INTR_ONLY) */
5985 #if !defined(NDISVER) || (NDISVER < 0x0630)
5986 bcmsdh_intr_enable(sdh);
5987 #endif /* !defined(NDISVER) || (NDISVER < 0x0630) */
5990 #if defined(OOB_INTR_ONLY) && !defined(HW_OOB)
5991 /* In case of SW-OOB(using edge trigger),
5992 * Check interrupt status in the dongle again after enable irq on the host.
5993 * and rechedule dpc if interrupt is pended in the dongle.
5994 * There is a chance to miss OOB interrupt while irq is disabled on the host.
5995 * No need to do this with HW-OOB(level trigger)
5997 R_SDREG(newstatus, ®s->intstatus, retries);
5998 if (bcmsdh_regfail(bus->sdh))
6000 if (newstatus & bus->hostintmask) {
6004 #endif /* defined(OOB_INTR_ONLY) && !defined(HW_OOB) */
6006 #ifdef PROP_TXSTATUS
6007 dhd_wlfc_commit_packets(bus->dhd, (f_commitpkt_t)dhd_bus_txdata, (void *)bus, NULL, FALSE);
6010 if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL))
6011 dhdsdio_sendpendctl(bus);
6013 /* Send queued frames (limit 1 if rx may still be pending) */
6014 else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate &&
6015 pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit && DATAOK(bus)) {
6016 framecnt = rxdone ? txlimit : MIN(txlimit, dhd_txminmax);
6017 framecnt = dhdsdio_sendfromq(bus, framecnt);
6018 txlimit -= framecnt;
6020 /* Resched the DPC if ctrl cmd is pending on bus credit */
6021 if (bus->ctrl_frame_stat)
6024 /* Resched if events or tx frames are pending, else await next interrupt */
6025 /* On failed register access, all bets are off: no resched or interrupts */
6026 if ((bus->dhd->busstate == DHD_BUS_DOWN) || bcmsdh_regfail(sdh)) {
6027 if ((bus->sih && bus->sih->buscorerev >= 12) && !(dhdsdio_sleepcsr_get(bus) &
6028 SBSDIO_FUNC1_SLEEPCSR_KSO_MASK)) {
6029 /* Bus failed because of KSO */
6030 DHD_ERROR(("%s: Bus failed due to KSO\n", __FUNCTION__));
6033 DHD_ERROR(("%s: failed backplane access over SDIO, halting operation\n",
6035 bus->dhd->busstate = DHD_BUS_DOWN;
6038 } else if (bus->clkstate == CLK_PENDING) {
6039 /* Awaiting I_CHIPACTIVE; don't resched */
6040 } else if (bus->intstatus || bus->ipend ||
6041 (!bus->fcstate && pktq_mlen(&bus->txq, ~bus->flowcontrol) && DATAOK(bus)) ||
6042 PKT_AVAILABLE(bus, bus->intstatus)) { /* Read multiple frames */
6046 bus->dpc_sched = resched;
6048 /* If we're done for now, turn off clock request. */
6049 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && (bus->clkstate != CLK_PENDING)) {
6050 bus->activity = FALSE;
6051 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
6056 if (!resched && dhd_dpcpoll) {
6057 if (dhdsdio_readframes(bus, dhd_rxbound, &rxdone) != 0)
6061 dhd_os_sdunlock(bus->dhd);
6066 dhd_bus_dpc(struct dhd_bus *bus)
6070 /* Call the DPC directly. */
6071 DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__));
6072 resched = dhdsdio_dpc(bus);
6078 dhdsdio_isr(void *arg)
6080 dhd_bus_t *bus = (dhd_bus_t*)arg;
6083 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
6086 DHD_ERROR(("%s : bus is null pointer , exit \n", __FUNCTION__));
6091 if (bus->dhd->busstate == DHD_BUS_DOWN) {
6092 DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__));
6096 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
6098 /* Count the interrupt call */
6102 /* Shouldn't get this interrupt if we're sleeping? */
6103 if (!SLPAUTO_ENAB(bus)) {
6104 if (bus->sleeping) {
6105 DHD_ERROR(("INTERRUPT WHILE SLEEPING??\n"));
6107 } else if (!KSO_ENAB(bus)) {
6108 DHD_ERROR(("ISR in devsleep 1\n"));
6112 /* Disable additional interrupts (is this needed now)? */
6114 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
6116 DHD_ERROR(("dhdsdio_isr() w/o interrupt configured!\n"));
6119 #if !defined(NDISVER) || (NDISVER < 0x0630)
6120 bcmsdh_intr_disable(sdh);
6121 #endif /* !defined(NDISVER) || (NDISVER < 0x0630) */
6124 #if defined(SDIO_ISR_THREAD)
6125 DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__));
6126 DHD_OS_WAKE_LOCK(bus->dhd);
6127 /* terence 20150209: dpc should be scheded again if dpc_sched is TRUE or dhd_bus_txdata can
6128 not schedule anymore because dpc_sched is TRUE now.
6130 if (dhdsdio_dpc(bus)) {
6131 bus->dpc_sched = TRUE;
6132 dhd_sched_dpc(bus->dhd);
6134 DHD_OS_WAKE_UNLOCK(bus->dhd);
6137 #if !defined(NDISVER) || (NDISVER < 0x0630)
6138 bus->dpc_sched = TRUE;
6139 dhd_sched_dpc(bus->dhd);
6140 #endif /* !defined(NDISVER) || (NDISVER < 0x0630) */
6142 #endif /* defined(SDIO_ISR_THREAD) */
6148 dhdsdio_pktgen_init(dhd_bus_t *bus)
6150 /* Default to specified length, or full range */
6151 if (dhd_pktgen_len) {
6152 bus->pktgen_maxlen = MIN(dhd_pktgen_len, MAX_PKTGEN_LEN);
6153 bus->pktgen_minlen = bus->pktgen_maxlen;
6155 bus->pktgen_maxlen = MAX_PKTGEN_LEN;
6156 bus->pktgen_minlen = 0;
6158 bus->pktgen_len = (uint16)bus->pktgen_minlen;
6160 /* Default to per-watchdog burst with 10s print time */
6161 bus->pktgen_freq = 1;
6162 bus->pktgen_print = dhd_watchdog_ms ? (10000 / dhd_watchdog_ms) : 0;
6163 bus->pktgen_count = (dhd_pktgen * dhd_watchdog_ms + 999) / 1000;
6165 /* Default to echo mode */
6166 bus->pktgen_mode = DHD_PKTGEN_ECHO;
6167 bus->pktgen_stop = 1;
6171 dhdsdio_pktgen(dhd_bus_t *bus)
6177 osl_t *osh = bus->dhd->osh;
6183 /* Display current count if appropriate */
6184 if (bus->pktgen_print && (++bus->pktgen_ptick >= bus->pktgen_print)) {
6185 bus->pktgen_ptick = 0;
6186 printf("%s: send attempts %d, rcvd %d, errors %d\n",
6187 __FUNCTION__, bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail);
6189 /* Print throughput stats only for constant length packet runs */
6190 if (bus->pktgen_minlen == bus->pktgen_maxlen) {
6191 time_lapse = jiffies - bus->pktgen_prev_time;
6192 bus->pktgen_prev_time = jiffies;
6193 sent_pkts = bus->pktgen_sent - bus->pktgen_prev_sent;
6194 bus->pktgen_prev_sent = bus->pktgen_sent;
6195 rcvd_pkts = bus->pktgen_rcvd - bus->pktgen_prev_rcvd;
6196 bus->pktgen_prev_rcvd = bus->pktgen_rcvd;
6198 printf("%s: Tx Throughput %d kbps, Rx Throughput %d kbps\n",
6200 (sent_pkts * bus->pktgen_len / jiffies_to_msecs(time_lapse)) * 8,
6201 (rcvd_pkts * bus->pktgen_len / jiffies_to_msecs(time_lapse)) * 8);
6205 /* For recv mode, just make sure dongle has started sending */
6206 if (bus->pktgen_mode == DHD_PKTGEN_RECV) {
6207 if (bus->pktgen_rcv_state == PKTGEN_RCV_IDLE) {
6208 bus->pktgen_rcv_state = PKTGEN_RCV_ONGOING;
6209 dhdsdio_sdtest_set(bus, bus->pktgen_total);
6214 /* Otherwise, generate or request the specified number of packets */
6215 for (pktcount = 0; pktcount < bus->pktgen_count; pktcount++) {
6216 /* Stop if total has been reached */
6217 if (bus->pktgen_total && (bus->pktgen_sent >= bus->pktgen_total)) {
6218 bus->pktgen_count = 0;
6222 /* Allocate an appropriate-sized packet */
6223 if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) {
6224 len = SDPCM_TEST_PKT_CNT_FLD_LEN;
6226 len = bus->pktgen_len;
6228 if (!(pkt = PKTGET(osh, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN),
6230 DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__));
6233 PKTALIGN(osh, pkt, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN), DHD_SDALIGN);
6234 data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
6236 /* Write test header cmd and extra based on mode */
6237 switch (bus->pktgen_mode) {
6238 case DHD_PKTGEN_ECHO:
6239 *data++ = SDPCM_TEST_ECHOREQ;
6240 *data++ = (uint8)bus->pktgen_sent;
6243 case DHD_PKTGEN_SEND:
6244 *data++ = SDPCM_TEST_DISCARD;
6245 *data++ = (uint8)bus->pktgen_sent;
6248 case DHD_PKTGEN_RXBURST:
6249 *data++ = SDPCM_TEST_BURST;
6250 *data++ = (uint8)bus->pktgen_count; /* Just for backward compatability */
6254 DHD_ERROR(("Unrecognized pktgen mode %d\n", bus->pktgen_mode));
6255 PKTFREE(osh, pkt, TRUE);
6256 bus->pktgen_count = 0;
6260 /* Write test header length field */
6261 *data++ = (bus->pktgen_len >> 0);
6262 *data++ = (bus->pktgen_len >> 8);
6264 /* Write frame count in a 4 byte field adjucent to SDPCM test header for
6267 if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) {
6268 *data++ = (uint8)(bus->pktgen_count >> 0);
6269 *data++ = (uint8)(bus->pktgen_count >> 8);
6270 *data++ = (uint8)(bus->pktgen_count >> 16);
6271 *data++ = (uint8)(bus->pktgen_count >> 24);
6274 /* Then fill in the remainder -- N/A for burst */
6275 for (fillbyte = 0; fillbyte < len; fillbyte++)
6276 *data++ = SDPCM_TEST_FILL(fillbyte, (uint8)bus->pktgen_sent);
6280 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
6281 data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
6282 prhex("dhdsdio_pktgen: Tx Data", data, PKTLEN(osh, pkt) - SDPCM_HDRLEN);
6287 if (dhdsdio_txpkt(bus, SDPCM_TEST_CHANNEL, &pkt, 1, TRUE) != BCME_OK) {
6289 if (bus->pktgen_stop && bus->pktgen_stop == bus->pktgen_fail)
6290 bus->pktgen_count = 0;
6294 /* Bump length if not fixed, wrap at max */
6295 if (++bus->pktgen_len > bus->pktgen_maxlen)
6296 bus->pktgen_len = (uint16)bus->pktgen_minlen;
6298 /* Special case for burst mode: just send one request! */
6299 if (bus->pktgen_mode == DHD_PKTGEN_RXBURST)
6305 dhdsdio_sdtest_set(dhd_bus_t *bus, uint count)
6309 osl_t *osh = bus->dhd->osh;
6311 /* Allocate the packet */
6312 if (!(pkt = PKTGET(osh, SDPCM_HDRLEN + SDPCM_TEST_HDRLEN +
6313 SDPCM_TEST_PKT_CNT_FLD_LEN + DHD_SDALIGN, TRUE))) {
6314 DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__));
6317 PKTALIGN(osh, pkt, (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN +
6318 SDPCM_TEST_PKT_CNT_FLD_LEN), DHD_SDALIGN);
6319 data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
6321 /* Fill in the test header */
6322 *data++ = SDPCM_TEST_SEND;
6323 *data++ = (count > 0)?TRUE:FALSE;
6324 *data++ = (bus->pktgen_maxlen >> 0);
6325 *data++ = (bus->pktgen_maxlen >> 8);
6326 *data++ = (uint8)(count >> 0);
6327 *data++ = (uint8)(count >> 8);
6328 *data++ = (uint8)(count >> 16);
6329 *data++ = (uint8)(count >> 24);
6332 if (dhdsdio_txpkt(bus, SDPCM_TEST_CHANNEL, &pkt, 1, TRUE) != BCME_OK)
6338 dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq)
6340 osl_t *osh = bus->dhd->osh;
6349 /* Check for min length */
6350 if ((pktlen = PKTLEN(osh, pkt)) < SDPCM_TEST_HDRLEN) {
6351 DHD_ERROR(("dhdsdio_restrcv: toss runt frame, pktlen %d\n", pktlen));
6352 PKTFREE(osh, pkt, FALSE);
6356 /* Extract header fields */
6357 data = PKTDATA(osh, pkt);
6360 len = *data++; len += *data++ << 8;
6361 DHD_TRACE(("%s:cmd:%d, xtra:%d,len:%d\n", __FUNCTION__, cmd, extra, len));
6362 /* Check length for relevant commands */
6363 if (cmd == SDPCM_TEST_DISCARD || cmd == SDPCM_TEST_ECHOREQ || cmd == SDPCM_TEST_ECHORSP) {
6364 if (pktlen != len + SDPCM_TEST_HDRLEN) {
6365 DHD_ERROR(("dhdsdio_testrcv: frame length mismatch, pktlen %d seq %d"
6366 " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len));
6367 PKTFREE(osh, pkt, FALSE);
6372 /* Process as per command */
6374 case SDPCM_TEST_ECHOREQ:
6375 /* Rx->Tx turnaround ok (even on NDIS w/current implementation) */
6376 *(uint8 *)(PKTDATA(osh, pkt)) = SDPCM_TEST_ECHORSP;
6377 if (dhdsdio_txpkt(bus, SDPCM_TEST_CHANNEL, &pkt, 1, TRUE) == BCME_OK) {
6381 PKTFREE(osh, pkt, FALSE);
6386 case SDPCM_TEST_ECHORSP:
6387 if (bus->ext_loop) {
6388 PKTFREE(osh, pkt, FALSE);
6393 for (offset = 0; offset < len; offset++, data++) {
6394 if (*data != SDPCM_TEST_FILL(offset, extra)) {
6395 DHD_ERROR(("dhdsdio_testrcv: echo data mismatch: "
6396 "offset %d (len %d) expect 0x%02x rcvd 0x%02x\n",
6397 offset, len, SDPCM_TEST_FILL(offset, extra), *data));
6401 PKTFREE(osh, pkt, FALSE);
6405 case SDPCM_TEST_DISCARD:
6409 uint8 testval = extra;
6410 for (i = 0; i < len; i++) {
6411 if (*prn != testval) {
6412 DHD_ERROR(("DIErr@Pkt#:%d,Ix:%d, expected:0x%x, got:0x%x\n",
6413 i, bus->pktgen_rcvd_rcvsession, testval, *prn));
6418 PKTFREE(osh, pkt, FALSE);
6422 case SDPCM_TEST_BURST:
6423 case SDPCM_TEST_SEND:
6425 DHD_INFO(("dhdsdio_testrcv: unsupported or unknown command, pktlen %d seq %d"
6426 " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len));
6427 PKTFREE(osh, pkt, FALSE);
6431 /* For recv mode, stop at limit (and tell dongle to stop sending) */
6432 if (bus->pktgen_mode == DHD_PKTGEN_RECV) {
6433 if (bus->pktgen_rcv_state != PKTGEN_RCV_IDLE) {
6434 bus->pktgen_rcvd_rcvsession++;
6436 if (bus->pktgen_total &&
6437 (bus->pktgen_rcvd_rcvsession >= bus->pktgen_total)) {
6438 bus->pktgen_count = 0;
6439 DHD_ERROR(("Pktgen:rcv test complete!\n"));
6440 bus->pktgen_rcv_state = PKTGEN_RCV_IDLE;
6441 dhdsdio_sdtest_set(bus, FALSE);
6442 bus->pktgen_rcvd_rcvsession = 0;
6449 int dhd_bus_oob_intr_register(dhd_pub_t *dhdp)
6453 #if defined(OOB_INTR_ONLY)
6454 err = bcmsdh_oob_intr_register(dhdp->bus->sdh, dhdsdio_isr, dhdp->bus);
6459 void dhd_bus_oob_intr_unregister(dhd_pub_t *dhdp)
6461 #if defined(OOB_INTR_ONLY)
6462 bcmsdh_oob_intr_unregister(dhdp->bus->sdh);
6466 void dhd_bus_oob_intr_set(dhd_pub_t *dhdp, bool enable)
6468 #if defined(OOB_INTR_ONLY)
6469 bcmsdh_oob_intr_set(dhdp->bus->sdh, enable);
6473 void dhd_bus_dev_pm_stay_awake(dhd_pub_t *dhdpub)
6475 bcmsdh_dev_pm_stay_awake(dhdpub->bus->sdh);
6478 void dhd_bus_dev_pm_relax(dhd_pub_t *dhdpub)
6480 bcmsdh_dev_relax(dhdpub->bus->sdh);
6483 bool dhd_bus_dev_pm_enabled(dhd_pub_t *dhdpub)
6485 bool enabled = FALSE;
6487 enabled = bcmsdh_dev_pm_enabled(dhdpub->bus->sdh);
6492 dhd_bus_watchdog(dhd_pub_t *dhdp)
6496 DHD_TIMER(("%s: Enter\n", __FUNCTION__));
6500 if (bus->dhd->dongle_reset)
6503 if (bus->dhd->hang_was_sent) {
6504 dhd_os_wd_timer(bus->dhd, 0);
6508 /* Ignore the timer if simulating bus down */
6509 if (!SLPAUTO_ENAB(bus) && bus->sleeping)
6512 if (dhdp->busstate == DHD_BUS_DOWN)
6515 dhd_os_sdlock(bus->dhd);
6517 /* Poll period: check device if appropriate. */
6518 if (!SLPAUTO_ENAB(bus) && (bus->poll && (++bus->polltick >= bus->pollrate))) {
6519 uint32 intstatus = 0;
6521 /* Reset poll tick */
6524 /* Check device if no interrupts */
6525 if (!bus->intr || (bus->intrcount == bus->lastintrs)) {
6527 if (!bus->dpc_sched) {
6529 devpend = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0,
6530 SDIOD_CCCR_INTPEND, NULL);
6531 intstatus = devpend & (INTR_STATUS_FUNC1 | INTR_STATUS_FUNC2);
6534 /* If there is something, make like the ISR and schedule the DPC */
6539 bcmsdh_intr_disable(bus->sdh);
6541 bus->dpc_sched = TRUE;
6542 dhd_sched_dpc(bus->dhd);
6546 /* Update interrupt tracking */
6547 bus->lastintrs = bus->intrcount;
6551 /* Poll for console output periodically */
6552 if (dhdp->busstate == DHD_BUS_DATA && dhd_console_ms != 0) {
6553 bus->console.count += dhd_watchdog_ms;
6554 if (bus->console.count >= dhd_console_ms) {
6555 bus->console.count -= dhd_console_ms;
6556 /* Make sure backplane clock is on */
6557 if (SLPAUTO_ENAB(bus))
6558 dhdsdio_bussleep(bus, FALSE);
6560 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
6561 if (dhdsdio_readconsole(bus) < 0)
6562 dhd_console_ms = 0; /* On error, stop trying */
6565 #endif /* DHD_DEBUG */
6568 /* Generate packets if configured */
6569 if (bus->pktgen_count && (++bus->pktgen_tick >= bus->pktgen_freq)) {
6570 /* Make sure backplane clock is on */
6571 if (SLPAUTO_ENAB(bus))
6572 dhdsdio_bussleep(bus, FALSE);
6574 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
6575 bus->pktgen_tick = 0;
6576 dhdsdio_pktgen(bus);
6580 /* On idle timeout clear activity flag and/or turn off clock */
6581 #ifdef DHD_USE_IDLECOUNT
6583 bus->activity = FALSE;
6587 if ((bus->idletime > 0) && (bus->idlecount >= bus->idletime)) {
6588 DHD_TIMER(("%s: DHD Idle state!!\n", __FUNCTION__));
6589 if (SLPAUTO_ENAB(bus)) {
6590 if (dhdsdio_bussleep(bus, TRUE) != BCME_BUSY)
6591 dhd_os_wd_timer(bus->dhd, 0);
6593 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
6599 if ((bus->idletime > 0) && (bus->clkstate == CLK_AVAIL)) {
6600 if (++bus->idlecount >= bus->idletime) {
6602 if (bus->activity) {
6603 bus->activity = FALSE;
6604 if (SLPAUTO_ENAB(bus)) {
6605 if (!bus->readframes)
6606 dhdsdio_bussleep(bus, TRUE);
6608 bus->reqbussleep = TRUE;
6611 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
6615 #endif /* DHD_USE_IDLECOUNT */
6617 dhd_os_sdunlock(bus->dhd);
6624 dhd_bus_console_in(dhd_pub_t *dhdp, uchar *msg, uint msglen)
6626 dhd_bus_t *bus = dhdp->bus;
6631 /* Address could be zero if CONSOLE := 0 in dongle Makefile */
6632 if (bus->console_addr == 0)
6633 return BCME_UNSUPPORTED;
6635 /* Exclusive bus access */
6636 dhd_os_sdlock(bus->dhd);
6638 /* Don't allow input if dongle is in reset */
6639 if (bus->dhd->dongle_reset) {
6640 dhd_os_sdunlock(bus->dhd);
6641 return BCME_NOTREADY;
6644 /* Request clock to allow SDIO accesses */
6646 /* No pend allowed since txpkt is called later, ht clk has to be on */
6647 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
6649 /* Zero cbuf_index */
6650 addr = bus->console_addr + OFFSETOF(hnd_cons_t, cbuf_idx);
6652 if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0)
6655 /* Write message into cbuf */
6656 addr = bus->console_addr + OFFSETOF(hnd_cons_t, cbuf);
6657 if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)msg, msglen)) < 0)
6660 /* Write length into vcons_in */
6661 addr = bus->console_addr + OFFSETOF(hnd_cons_t, vcons_in);
6662 val = htol32(msglen);
6663 if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0)
6666 /* Bump dongle by sending an empty packet on the event channel.
6667 * sdpcm_sendup (RX) checks for virtual console input.
6669 if ((pkt = PKTGET(bus->dhd->osh, 4 + SDPCM_RESERVE, TRUE)) != NULL)
6670 rv = dhdsdio_txpkt(bus, SDPCM_EVENT_CHANNEL, &pkt, 1, TRUE);
6673 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
6674 bus->activity = FALSE;
6675 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
6678 dhd_os_sdunlock(bus->dhd);
6682 #endif /* DHD_DEBUG */
6686 dhd_dump_cis(uint fn, uint8 *cis)
6688 uint byte, tag, tdata;
6689 DHD_INFO(("Function %d CIS:\n", fn));
6691 for (tdata = byte = 0; byte < SBSDIO_CIS_SIZE_LIMIT; byte++) {
6692 if ((byte % 16) == 0)
6694 DHD_INFO(("%02x ", cis[byte]));
6695 if ((byte % 16) == 15)
6703 else if ((byte + 1) < SBSDIO_CIS_SIZE_LIMIT)
6704 tdata = cis[byte + 1] + 1;
6709 if ((byte % 16) != 15)
6712 #endif /* DHD_DEBUG */
6715 dhdsdio_chipmatch(uint16 chipid)
6717 if (chipid == BCM4325_CHIP_ID)
6719 if (chipid == BCM4329_CHIP_ID)
6721 if (chipid == BCM4315_CHIP_ID)
6723 if (chipid == BCM4319_CHIP_ID)
6725 if (chipid == BCM4336_CHIP_ID)
6727 if (chipid == BCM4330_CHIP_ID)
6729 if (chipid == BCM43237_CHIP_ID)
6731 if (chipid == BCM43362_CHIP_ID)
6733 if (chipid == BCM4314_CHIP_ID)
6735 if (chipid == BCM43242_CHIP_ID)
6737 if (chipid == BCM43340_CHIP_ID)
6739 if (chipid == BCM43341_CHIP_ID)
6741 if (chipid == BCM43143_CHIP_ID)
6743 if (chipid == BCM43342_CHIP_ID)
6745 if (chipid == BCM4334_CHIP_ID)
6747 if (chipid == BCM43239_CHIP_ID)
6749 if (chipid == BCM4324_CHIP_ID)
6751 if (chipid == BCM4335_CHIP_ID)
6753 if (chipid == BCM4339_CHIP_ID)
6755 if (chipid == BCM43349_CHIP_ID)
6757 if (chipid == BCM4345_CHIP_ID)
6759 if (chipid == BCM4350_CHIP_ID)
6761 if (chipid == BCM4354_CHIP_ID)
6763 if (chipid == BCM4356_CHIP_ID)
6765 if (chipid == BCM4358_CHIP_ID)
6767 if (chipid == BCM4371_CHIP_ID)
6769 if (chipid == BCM43430_CHIP_ID)
6771 if (BCM4349_CHIP(chipid))
6776 #if defined(MULTIPLE_SUPPLICANT)
6777 extern void wl_android_post_init(void); // terence 20120530: fix critical section in dhd_open and dhdsdio_probe
6781 dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot,
6782 uint16 func, uint bustype, void *regsva, osl_t * osh, void *sdh)
6786 struct ether_addr ea_addr;
6788 #if defined(MULTIPLE_SUPPLICANT)
6789 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
6790 if (mutex_is_locked(&_dhd_sdio_mutex_lock_) == 0) {
6791 DHD_ERROR(("%s : no mutex held. set lock\n", __FUNCTION__));
6794 DHD_ERROR(("%s : mutex is locked!. wait for unlocking\n", __FUNCTION__));
6796 mutex_lock(&_dhd_sdio_mutex_lock_);
6797 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
6800 /* Init global variables at run-time, not as part of the declaration.
6801 * This is required to support init/de-init of the driver. Initialization
6802 * of globals as part of the declaration results in non-deterministic
6803 * behavior since the value of the globals may be different on the
6804 * first time that the driver is initialized vs subsequent initializations.
6806 dhd_txbound = DHD_TXBOUND;
6807 dhd_rxbound = DHD_RXBOUND;
6808 dhd_alignctl = TRUE;
6810 dhd_readahead = TRUE;
6812 #if !defined(PLATFORM_MPS)
6816 #endif /* OEM_ANDROID */
6817 dhd_dongle_ramsize = 0;
6818 dhd_txminmax = DHD_TXMINMAX;
6822 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
6823 DHD_INFO(("%s: venid 0x%04x devid 0x%04x\n", __FUNCTION__, venid, devid));
6825 /* We make assumptions about address window mappings */
6826 ASSERT((uintptr)regsva == SI_ENUM_BASE);
6828 /* BCMSDH passes venid and devid based on CIS parsing -- but low-power start
6829 * means early parse could fail, so here we should get either an ID
6830 * we recognize OR (-1) indicating we must request power first.
6832 /* Check the Vendor ID */
6835 case VENDOR_BROADCOM:
6838 DHD_ERROR(("%s: unknown vendor: 0x%04x\n",
6839 __FUNCTION__, venid));
6843 /* Check the Device ID and make sure it's one that we support */
6845 case BCM4325_D11DUAL_ID: /* 4325 802.11a/g id */
6846 case BCM4325_D11G_ID: /* 4325 802.11g 2.4Ghz band id */
6847 case BCM4325_D11A_ID: /* 4325 802.11a 5Ghz band id */
6848 DHD_INFO(("%s: found 4325 Dongle\n", __FUNCTION__));
6850 case BCM4329_D11N_ID: /* 4329 802.11n dualband device */
6851 case BCM4329_D11N2G_ID: /* 4329 802.11n 2.4G device */
6852 case BCM4329_D11N5G_ID: /* 4329 802.11n 5G device */
6854 DHD_INFO(("%s: found 4329 Dongle\n", __FUNCTION__));
6856 case BCM4315_D11DUAL_ID: /* 4315 802.11a/g id */
6857 case BCM4315_D11G_ID: /* 4315 802.11g id */
6858 case BCM4315_D11A_ID: /* 4315 802.11a id */
6859 DHD_INFO(("%s: found 4315 Dongle\n", __FUNCTION__));
6861 case BCM4319_D11N_ID: /* 4319 802.11n id */
6862 case BCM4319_D11N2G_ID: /* 4319 802.11n2g id */
6863 case BCM4319_D11N5G_ID: /* 4319 802.11n5g id */
6864 DHD_INFO(("%s: found 4319 Dongle\n", __FUNCTION__));
6867 DHD_INFO(("%s: allow device id 0, will check chip internals\n",
6872 DHD_ERROR(("%s: skipping 0x%04x/0x%04x, not a dongle\n",
6873 __FUNCTION__, venid, devid));
6878 DHD_ERROR(("%s: osh is NULL!\n", __FUNCTION__));
6882 /* Allocate private bus interface state */
6883 if (!(bus = MALLOC(osh, sizeof(dhd_bus_t)))) {
6884 DHD_ERROR(("%s: MALLOC of dhd_bus_t failed\n", __FUNCTION__));
6887 bzero(bus, sizeof(dhd_bus_t));
6889 bus->cl_devid = (uint16)devid;
6891 bus->bus_num = bus_no;
6892 bus->slot_num = slot;
6893 bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1;
6894 bus->usebufpool = FALSE; /* Use bufpool if allocated, else use locally malloced rxbuf */
6896 /* attempt to attach to the dongle */
6897 if (!(dhdsdio_probe_attach(bus, osh, sdh, regsva, devid))) {
6898 DHD_ERROR(("%s: dhdsdio_probe_attach failed\n", __FUNCTION__));
6902 /* Attach to the dhd/OS/network interface */
6903 if (!(bus->dhd = dhd_attach(osh, bus, SDPCM_RESERVE))) {
6904 DHD_ERROR(("%s: dhd_attach failed\n", __FUNCTION__));
6908 /* Allocate buffers */
6909 if (!(dhdsdio_probe_malloc(bus, osh, sdh))) {
6910 DHD_ERROR(("%s: dhdsdio_probe_malloc failed\n", __FUNCTION__));
6914 if (!(dhdsdio_probe_init(bus, osh, sdh))) {
6915 DHD_ERROR(("%s: dhdsdio_probe_init failed\n", __FUNCTION__));
6920 /* Register interrupt callback, but mask it (not operational yet). */
6921 DHD_INTR(("%s: disable SDIO interrupts (not interested yet)\n", __FUNCTION__));
6922 bcmsdh_intr_disable(sdh);
6923 if ((ret = bcmsdh_intr_reg(sdh, dhdsdio_isr, bus)) != 0) {
6924 DHD_ERROR(("%s: FAILED: bcmsdh_intr_reg returned %d\n",
6925 __FUNCTION__, ret));
6928 DHD_INTR(("%s: registered SDIO interrupt function ok\n", __FUNCTION__));
6930 DHD_INFO(("%s: SDIO interrupt function is NOT registered due to polling mode\n",
6934 DHD_INFO(("%s: completed!!\n", __FUNCTION__));
6936 /* if firmware path present try to download and bring up bus */
6937 bus->dhd->hang_report = TRUE;
6938 #if 0 // terence 20150325: fix for WPA/WPA2 4-way handshake fail in hostapd
6939 if (dhd_download_fw_on_driverload) {
6940 if ((ret = dhd_bus_start(bus->dhd)) != 0) {
6941 DHD_ERROR(("%s: dhd_bus_start failed\n", __FUNCTION__));
6947 #ifdef GET_OTP_MAC_ENABLE
6948 if (dhd_conf_get_mac(bus->dhd, sdh, ea_addr.octet)) {
6949 DHD_TRACE(("%s: Can not read MAC address\n", __FUNCTION__));
6951 memcpy(bus->dhd->mac.octet, (void *)&ea_addr, ETHER_ADDR_LEN);
6952 #endif /* GET_CUSTOM_MAC_ENABLE */
6954 /* Ok, have the per-port tell the stack we're open for business */
6955 if (dhd_register_if(bus->dhd, 0, TRUE) != 0) {
6956 DHD_ERROR(("%s: Net attach failed!!\n", __FUNCTION__));
6961 #if defined(MULTIPLE_SUPPLICANT)
6962 wl_android_post_init(); // terence 20120530: fix critical section in dhd_open and dhdsdio_probe
6963 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
6964 mutex_unlock(&_dhd_sdio_mutex_lock_);
6965 DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__));
6966 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
6969 init_waitqueue_head(&bus->bus_sleep);
6974 dhdsdio_release(bus, osh);
6977 #if defined(MULTIPLE_SUPPLICANT)
6978 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
6979 mutex_unlock(&_dhd_sdio_mutex_lock_);
6980 DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__));
6981 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
6987 #ifdef REGON_BP_HANG_FIX
6988 static int dhd_sdio_backplane_reset(struct dhd_bus *bus)
6991 DHD_ERROR(("Resetting the backplane to avoid failure in firmware download..\n"));
6993 temp = bcmsdh_reg_read(bus->sdh, 0x180021e0, 4);
6994 DHD_INFO(("SDIO Clk Control Reg = %x\n", temp));
6996 /* Force HT req from PMU */
6997 bcmsdh_reg_write(bus->sdh, 0x18000644, 4, 0x6000005);
6999 /* Increase the clock stretch duration. */
7000 bcmsdh_reg_write(bus->sdh, 0x18000630, 4, 0xC8FFC8);
7002 /* Setting ALP clock request in SDIOD clock control status register */
7003 bcmsdh_reg_write(bus->sdh, 0x180021e0, 4, 0x41);
7005 /* Allowing clock from SR engine to SR memory */
7006 bcmsdh_reg_write(bus->sdh, 0x18004400, 4, 0xf92f1);
7007 /* Disabling SR Engine before SR binary download. */
7008 bcmsdh_reg_write(bus->sdh, 0x18000650, 4, 0x3);
7009 bcmsdh_reg_write(bus->sdh, 0x18000654, 4, 0x0);
7011 /* Enabling clock from backplane to SR memory */
7012 bcmsdh_reg_write(bus->sdh, 0x18004400, 4, 0xf9af1);
7014 /* Initializing SR memory address register in SOCRAM */
7015 bcmsdh_reg_write(bus->sdh, 0x18004408, 4, 0x0);
7017 /* Downloading the SR binary */
7018 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7019 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7020 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7021 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7022 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7023 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7024 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7025 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0xc0002000);
7026 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7027 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7028 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7029 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7030 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7031 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7032 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7033 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7034 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7035 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7036 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7037 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7038 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7039 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7040 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7041 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7042 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7043 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7044 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7045 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7046 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7047 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7048 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7049 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7050 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x80008000);
7051 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x1051f080);
7052 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x80008000);
7053 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x1050f080);
7054 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x80008000);
7055 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x1050f080);
7056 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x80008000);
7057 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x1050f080);
7058 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000004);
7059 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
7060 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000604);
7061 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
7062 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00001604);
7063 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
7064 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00001404);
7065 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a08c80);
7066 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010001);
7067 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x14a00000);
7068 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00011404);
7069 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
7070 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00002000);
7071 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x04a00000);
7072 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00002000);
7073 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0xf8000000);
7074 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00002000);
7075 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x04a00000);
7076 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00002000);
7077 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0xf8000000);
7078 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00011604);
7079 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
7080 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010604);
7081 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
7082 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010004);
7083 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
7084 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010000);
7085 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x14a00000);
7086 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000004);
7087 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
7088 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010001);
7089 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x14a00000);
7090 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010004);
7091 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
7092 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010000);
7093 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
7094 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010000);
7095 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x14a00000);
7096 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7097 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
7098 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000008);
7099 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x04a00000);
7100 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000008);
7101 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0xfc000000);
7102 /* SR Binary Download complete */
7104 /* Allowing clock from SR engine to SR memory */
7105 bcmsdh_reg_write(bus->sdh, 0x18004400, 4, 0xf92f1);
7107 /* Turning ON SR Engine to initiate backplane reset Repeated ?? Maharana */
7108 bcmsdh_reg_write(bus->sdh, 0x18000650, 4, 0x3);
7109 bcmsdh_reg_write(bus->sdh, 0x18000654, 4, 0x0);
7110 bcmsdh_reg_write(bus->sdh, 0x18000650, 4, 0x3);
7111 bcmsdh_reg_write(bus->sdh, 0x18000654, 4, 0x2);
7112 bcmsdh_reg_write(bus->sdh, 0x18000650, 4, 0x3);
7113 bcmsdh_reg_write(bus->sdh, 0x18000654, 4, 0x3);
7114 bcmsdh_reg_write(bus->sdh, 0x18000650, 4, 0x3);
7115 bcmsdh_reg_write(bus->sdh, 0x18000654, 4, 0x37);
7116 bcmsdh_reg_write(bus->sdh, 0x18000650, 4, 0x3);
7117 temp = bcmsdh_reg_read(bus->sdh, 0x18000654, 4);
7118 DHD_INFO(("0x18000654 = %x\n", temp));
7119 bcmsdh_reg_write(bus->sdh, 0x18000654, 4, 0x800037);
7121 /* Rolling back the original values for clock stretch and PMU timers */
7122 bcmsdh_reg_write(bus->sdh, 0x18000644, 4, 0x0);
7123 bcmsdh_reg_write(bus->sdh, 0x18000630, 4, 0xC800C8);
7124 /* Removing ALP clock request in SDIOD clock control status register */
7125 bcmsdh_reg_write(bus->sdh, 0x180021e0, 4, 0x40);
7130 static int dhdsdio_sdio_hang_war(struct dhd_bus *bus)
7132 uint32 temp = 0, temp2 = 0, counter = 0, BT_pwr_up = 0, BT_ready = 0;
7133 /* Removing reset of D11 Core */
7134 bcmsdh_reg_write(bus->sdh, 0x18101408, 4, 0x3);
7135 bcmsdh_reg_write(bus->sdh, 0x18101800, 4, 0x0);
7136 bcmsdh_reg_write(bus->sdh, 0x18101408, 4, 0x1);
7137 /* Reading CLB XTAL BT cntrl register */
7138 bcmsdh_reg_write(bus->sdh, 0x180013D8, 2, 0xD1);
7139 bcmsdh_reg_write(bus->sdh, 0x180013DA, 2, 0x12);
7140 bcmsdh_reg_write(bus->sdh, 0x180013D8, 2, 0x2D0);
7141 /* Read if BT is powered up */
7142 temp = bcmsdh_reg_read(bus->sdh, 0x180013DA, 2);
7143 /* Read BT_ready from WLAN wireless register */
7144 temp2 = bcmsdh_reg_read(bus->sdh, 0x1800002C, 4);
7146 Check if the BT is powered up and ready. The duration between BT being powered up
7147 and BT becoming ready is the problematic window for WLAN. If we move ahead at this
7148 time then we may encounter a corrupted backplane later. So we wait for BT to be ready
7149 and then proceed after checking the health of the backplane. If the backplane shows
7150 indications of failure then we have to do a full reset of the backplane using SR engine
7153 (temp & 0xF0) ? (BT_pwr_up = 1):(BT_pwr_up = 0);
7154 (temp2 & (1<<17)) ? (BT_ready = 1):(BT_ready = 0);
7155 DHD_ERROR(("WARNING: Checking if BT is ready BT_pwr_up = %x"
7156 "BT_ready = %x \n", BT_pwr_up, BT_ready));
7157 while (BT_pwr_up && !BT_ready)
7160 bcmsdh_reg_write(bus->sdh, 0x180013D8, 2, 0x2D0);
7161 temp = bcmsdh_reg_read(bus->sdh, 0x180013DA, 2);
7162 temp2 = bcmsdh_reg_read(bus->sdh, 0x1800002C, 4);
7163 (temp & 0xF0) ? (BT_pwr_up = 1):(BT_pwr_up = 0);
7164 (temp2 & (1<<17)) ? (BT_ready = 1):(BT_ready = 0);
7166 if (counter == 5000)
7168 DHD_ERROR(("WARNING: Going ahead after 5 secs with"
7169 "risk of failure because BT ready is not yet set\n"));
7173 DHD_ERROR(("\nWARNING: WL Proceeding BT_pwr_up = %x BT_ready = %x"
7174 "\n", BT_pwr_up, BT_ready));
7178 Get the information of who accessed the crucial backplane entities
7179 by reading read and write access registers
7181 DHD_TRACE(("%d: Read Value @ 0x18104808 = %x."
7182 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18104808, 4)));
7183 DHD_TRACE(("%d: Read Value @ 0x1810480C = %x."
7184 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810480C, 4)));
7185 DHD_TRACE(("%d: Read Value @ 0x18106808 = %x."
7186 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18106808, 4)));
7187 DHD_TRACE(("%d: Read Value @ 0x1810680C = %x."
7188 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810680C, 4)));
7189 DHD_TRACE(("%d: Read Value @ 0x18107808 = %x."
7190 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18107808, 4)));
7191 DHD_TRACE(("%d: Read Value @ 0x1810780C = %x."
7192 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810780C, 4)));
7193 DHD_TRACE(("%d: Read Value @ 0x18108808 = %x."
7194 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18108808, 4)));
7195 DHD_TRACE(("%d: Read Value @ 0x1810880C = %x."
7196 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810880C, 4)));
7197 DHD_TRACE(("%d: Read Value @ 0x18109808 = %x."
7198 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18109808, 4)));
7199 DHD_TRACE(("%d: Read Value @ 0x1810980C = %x."
7200 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810980C, 4)));
7201 DHD_TRACE(("%d: Read Value @ 0x1810C808 = %x."
7202 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810c808, 4)));
7203 DHD_TRACE(("%d: Read Value @ 0x1810C80C = %x."
7204 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810c80C, 4)));
7206 while ((bcmsdh_reg_read(bus->sdh, 0x18104808, 4) == 5) ||
7207 (bcmsdh_reg_read(bus->sdh, 0x1810480C, 4) == 5) ||
7208 (bcmsdh_reg_read(bus->sdh, 0x18106808, 4) == 5) ||
7209 (bcmsdh_reg_read(bus->sdh, 0x1810680C, 4) == 5) ||
7210 (bcmsdh_reg_read(bus->sdh, 0x1810780C, 4) == 5) ||
7211 (bcmsdh_reg_read(bus->sdh, 0x1810780C, 4) == 5) ||
7212 (bcmsdh_reg_read(bus->sdh, 0x1810880C, 4) == 5) ||
7213 (bcmsdh_reg_read(bus->sdh, 0x1810880C, 4) == 5) ||
7214 (bcmsdh_reg_read(bus->sdh, 0x1810980C, 4) == 5) ||
7215 (bcmsdh_reg_read(bus->sdh, 0x1810980C, 4) == 5) ||
7216 (bcmsdh_reg_read(bus->sdh, 0x1810C80C, 4) == 5) ||
7217 (bcmsdh_reg_read(bus->sdh, 0x1810C80C, 4) == 5))
7221 DHD_ERROR(("Unable to recover the backkplane corruption"
7222 "..Tried %d times.. Exiting\n", counter));
7226 dhd_sdio_backplane_reset(bus);
7228 Get the information of who accessed the crucial backplane
7229 entities by reading read and write access registers
7231 DHD_ERROR(("%d: Read Value @ 0x18104808 = %x."
7232 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18104808, 4)));
7233 DHD_ERROR(("%d: Read Value @ 0x1810480C = %x."
7234 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810480C, 4)));
7235 DHD_ERROR(("%d: Read Value @ 0x18106808 = %x."
7236 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18106808, 4)));
7237 DHD_ERROR(("%d: Read Value @ 0x1810680C = %x."
7238 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810680C, 4)));
7239 DHD_ERROR(("%d: Read Value @ 0x18107808 = %x."
7240 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18107808, 4)));
7241 DHD_ERROR(("%d: Read Value @ 0x1810780C = %x."
7242 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810780C, 4)));
7243 DHD_ERROR(("%d: Read Value @ 0x18108808 = %x."
7244 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18108808, 4)));
7245 DHD_ERROR(("%d: Read Value @ 0x1810880C = %x."
7246 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810880C, 4)));
7247 DHD_ERROR(("%d: Read Value @ 0x18109808 = %x."
7248 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18109808, 4)));
7249 DHD_ERROR(("%d: Read Value @ 0x1810980C = %x."
7250 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810980C, 4)));
7251 DHD_ERROR(("%d: Read Value @ 0x1810C808 = %x."
7252 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810c808, 4)));
7253 DHD_ERROR(("%d: Read Value @ 0x1810C80C = %x."
7254 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810c80C, 4)));
7256 /* Set the WL ready to indicate BT that we are done with backplane reset */
7257 DHD_ERROR(("Setting up AXI_OK\n"));
7258 bcmsdh_reg_write(bus->sdh, 0x18000658, 4, 0x3);
7259 temp = bcmsdh_reg_read(bus->sdh, 0x1800065c, 4);
7261 bcmsdh_reg_write(bus->sdh, 0x1800065c, 4, temp);
7264 #endif /* REGON_BP_HANG_FIX */
7266 dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva,
7272 bus->alp_only = TRUE;
7275 /* Return the window to backplane enumeration space for core access */
7276 if (dhdsdio_set_siaddr_window(bus, SI_ENUM_BASE)) {
7277 DHD_ERROR(("%s: FAILED to return to SI_ENUM_BASE\n", __FUNCTION__));
7280 #if defined(DHD_DEBUG)
7281 DHD_ERROR(("F1 signature read @0x18000000=0x%4x\n",
7282 bcmsdh_reg_read(bus->sdh, SI_ENUM_BASE, 4)));
7286 /* Force PLL off until si_attach() programs PLL control regs */
7290 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, DHD_INIT_CLKCTL1, &err);
7292 clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
7294 if (err || ((clkctl & ~SBSDIO_AVBITS) != DHD_INIT_CLKCTL1)) {
7295 DHD_ERROR(("dhdsdio_probe: ChipClkCSR access: err %d wrote 0x%02x read 0x%02x\n",
7296 err, DHD_INIT_CLKCTL1, clkctl));
7301 if (DHD_INFO_ON()) {
7303 uint8 *cis[SDIOD_MAX_IOFUNCS];
7306 numfn = bcmsdh_query_iofnum(sdh);
7307 ASSERT(numfn <= SDIOD_MAX_IOFUNCS);
7309 /* Make sure ALP is available before trying to read CIS */
7310 SPINWAIT(((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
7311 SBSDIO_FUNC1_CHIPCLKCSR, NULL)),
7312 !SBSDIO_ALPAV(clkctl)), PMU_MAX_TRANSITION_DLY);
7314 /* Now request ALP be put on the bus */
7315 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
7316 DHD_INIT_CLKCTL2, &err);
7319 for (fn = 0; fn <= numfn; fn++) {
7320 if (!(cis[fn] = MALLOC(osh, SBSDIO_CIS_SIZE_LIMIT))) {
7321 DHD_INFO(("dhdsdio_probe: fn %d cis malloc failed\n", fn));
7324 bzero(cis[fn], SBSDIO_CIS_SIZE_LIMIT);
7326 if ((err = bcmsdh_cis_read(sdh, fn, cis[fn], SBSDIO_CIS_SIZE_LIMIT))) {
7327 DHD_INFO(("dhdsdio_probe: fn %d cis read err %d\n", fn, err));
7328 MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT);
7331 dhd_dump_cis(fn, cis[fn]);
7336 MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT);
7340 DHD_ERROR(("dhdsdio_probe: failure reading or parsing CIS\n"));
7344 #endif /* DHD_DEBUG */
7346 /* si_attach() will provide an SI handle and scan the backplane */
7347 if (!(bus->sih = si_attach((uint)devid, osh, regsva, DHD_BUS, sdh,
7348 &bus->vars, &bus->varsz))) {
7349 DHD_ERROR(("%s: si_attach failed!\n", __FUNCTION__));
7354 DHD_ERROR(("F1 signature OK, socitype:0x%x chip:0x%4x rev:0x%x pkg:0x%x\n",
7355 bus->sih->socitype, bus->sih->chip, bus->sih->chiprev, bus->sih->chippkg));
7356 #endif /* DHD_DEBUG */
7358 #ifdef REGON_BP_HANG_FIX
7359 /* WAR - for 43241 B0-B1-B2. B3 onwards do not need this */
7360 if (((uint16)bus->sih->chip == BCM4324_CHIP_ID) && (bus->sih->chiprev < 3))
7361 dhdsdio_sdio_hang_war(bus);
7362 #endif /* REGON_BP_HANG_FIX */
7364 bcmsdh_chipinfo(sdh, bus->sih->chip, bus->sih->chiprev);
7366 if (!dhdsdio_chipmatch((uint16)bus->sih->chip)) {
7367 DHD_ERROR(("%s: unsupported chip: 0x%04x\n",
7368 __FUNCTION__, bus->sih->chip));
7372 if (bus->sih->buscorerev >= 12)
7373 dhdsdio_clk_kso_init(bus);
7377 if (CST4330_CHIPMODE_SDIOD(bus->sih->chipst)) {
7380 si_sdiod_drive_strength_init(bus->sih, osh, dhd_sdiod_drive_strength);
7383 /* Get info on the ARM and SOCRAM cores... */
7384 if (!DHD_NOPMU(bus)) {
7385 if ((si_setcore(bus->sih, ARM7S_CORE_ID, 0)) ||
7386 (si_setcore(bus->sih, ARMCM3_CORE_ID, 0)) ||
7387 (si_setcore(bus->sih, ARMCR4_CORE_ID, 0))) {
7388 bus->armrev = si_corerev(bus->sih);
7390 DHD_ERROR(("%s: failed to find ARM core!\n", __FUNCTION__));
7394 if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
7395 if (!(bus->orig_ramsize = si_socram_size(bus->sih))) {
7396 DHD_ERROR(("%s: failed to find SOCRAM memory!\n", __FUNCTION__));
7400 /* cr4 has a different way to find the RAM size from TCM's */
7401 if (!(bus->orig_ramsize = si_tcm_size(bus->sih))) {
7402 DHD_ERROR(("%s: failed to find CR4-TCM memory!\n", __FUNCTION__));
7405 /* also populate base address */
7406 switch ((uint16)bus->sih->chip) {
7407 case BCM4335_CHIP_ID:
7408 case BCM4339_CHIP_ID:
7409 case BCM43349_CHIP_ID:
7410 bus->dongle_ram_base = CR4_4335_RAM_BASE;
7412 case BCM4350_CHIP_ID:
7413 case BCM4354_CHIP_ID:
7414 case BCM4356_CHIP_ID:
7415 case BCM4358_CHIP_ID:
7416 case BCM4371_CHIP_ID:
7417 bus->dongle_ram_base = CR4_4350_RAM_BASE;
7419 case BCM4360_CHIP_ID:
7420 bus->dongle_ram_base = CR4_4360_RAM_BASE;
7422 case BCM4345_CHIP_ID:
7423 bus->dongle_ram_base = (bus->sih->chiprev < 6) /* from 4345C0 */
7424 ? CR4_4345_LT_C0_RAM_BASE : CR4_4345_GE_C0_RAM_BASE;
7426 case BCM4349_CHIP_GRPID:
7427 bus->dongle_ram_base = CR4_4349_RAM_BASE;
7430 bus->dongle_ram_base = 0;
7431 DHD_ERROR(("%s: WARNING: Using default ram base at 0x%x\n",
7432 __FUNCTION__, bus->dongle_ram_base));
7435 bus->ramsize = bus->orig_ramsize;
7436 if (dhd_dongle_ramsize)
7437 dhd_dongle_setramsize(bus, dhd_dongle_ramsize);
7439 DHD_ERROR(("DHD: dongle ram size is set to %d(orig %d) at 0x%x\n",
7440 bus->ramsize, bus->orig_ramsize, bus->dongle_ram_base));
7442 bus->srmemsize = si_socram_srmem_size(bus->sih);
7445 /* ...but normally deal with the SDPCMDEV core */
7446 if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0)) &&
7447 !(bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0))) {
7448 DHD_ERROR(("%s: failed to find SDIODEV core!\n", __FUNCTION__));
7451 bus->sdpcmrev = si_corerev(bus->sih);
7453 /* Set core control so an SDIO reset does a backplane reset */
7454 OR_REG(osh, &bus->regs->corecontrol, CC_BPRESEN);
7455 bus->rxint_mode = SDIO_DEVICE_HMB_RXINT;
7457 if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev >= 4) &&
7458 (bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_1))
7462 val = R_REG(osh, &bus->regs->corecontrol);
7463 val &= ~CC_XMTDATAAVAIL_MODE;
7464 val |= CC_XMTDATAAVAIL_CTRL;
7465 W_REG(osh, &bus->regs->corecontrol, val);
7469 pktq_init(&bus->txq, (PRIOMASK + 1), QLEN);
7471 /* Locate an appropriately-aligned portion of hdrbuf */
7472 bus->rxhdr = (uint8 *)ROUNDUP((uintptr)&bus->hdrbuf[0], DHD_SDALIGN);
7474 /* Set the poll and/or interrupt flags */
7475 bus->intr = (bool)dhd_intr;
7476 if ((bus->poll = (bool)dhd_poll))
7479 /* Setting default Glom size */
7480 bus->txglomsize = SDPCM_DEFGLOM_SIZE;
7485 if (bus->sih != NULL) {
7486 si_detach(bus->sih);
7493 dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh)
7495 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7497 if (bus->dhd->maxctl) {
7498 bus->rxblen = ROUNDUP((bus->dhd->maxctl+SDPCM_HDRLEN), ALIGNMENT) + DHD_SDALIGN;
7499 if (!(bus->rxbuf = DHD_OS_PREALLOC(bus->dhd, DHD_PREALLOC_RXBUF, bus->rxblen))) {
7500 DHD_ERROR(("%s: MALLOC of %d-byte rxbuf failed\n",
7501 __FUNCTION__, bus->rxblen));
7505 /* Allocate buffer to receive glomed packet */
7506 if (!(bus->databuf = DHD_OS_PREALLOC(bus->dhd, DHD_PREALLOC_DATABUF, MAX_DATA_BUF))) {
7507 DHD_ERROR(("%s: MALLOC of %d-byte databuf failed\n",
7508 __FUNCTION__, MAX_DATA_BUF));
7509 /* release rxbuf which was already located as above */
7511 DHD_OS_PREFREE(bus->dhd, bus->rxbuf, bus->rxblen);
7515 /* Align the buffer */
7516 if ((uintptr)bus->databuf % DHD_SDALIGN)
7517 bus->dataptr = bus->databuf + (DHD_SDALIGN - ((uintptr)bus->databuf % DHD_SDALIGN));
7519 bus->dataptr = bus->databuf;
7528 dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh)
7532 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7534 bus->_srenab = FALSE;
7537 dhdsdio_pktgen_init(bus);
7540 /* Disable F2 to clear any intermediate frame state on the dongle */
7541 bcmsdh_cfg_write(sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL);
7543 bus->dhd->busstate = DHD_BUS_DOWN;
7544 bus->sleeping = FALSE;
7545 bus->rxflow = FALSE;
7546 bus->prev_rxlim_hit = 0;
7548 /* Done with backplane-dependent accesses, can drop clock... */
7549 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
7551 /* ...and initialize clock/power states */
7552 bus->clkstate = CLK_SDONLY;
7553 bus->idletime = (int32)dhd_idletime;
7554 bus->idleclock = DHD_IDLE_ACTIVE;
7556 /* Query the SD clock speed */
7557 if (bcmsdh_iovar_op(sdh, "sd_divisor", NULL, 0,
7558 &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) {
7559 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_divisor"));
7560 bus->sd_divisor = -1;
7562 DHD_INFO(("%s: Initial value for %s is %d\n",
7563 __FUNCTION__, "sd_divisor", bus->sd_divisor));
7566 /* Query the SD bus mode */
7567 if (bcmsdh_iovar_op(sdh, "sd_mode", NULL, 0,
7568 &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) {
7569 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_mode"));
7572 DHD_INFO(("%s: Initial value for %s is %d\n",
7573 __FUNCTION__, "sd_mode", bus->sd_mode));
7576 /* Query the F2 block size, set roundup accordingly */
7578 if (bcmsdh_iovar_op(sdh, "sd_blocksize", &fnum, sizeof(int32),
7579 &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) {
7581 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize"));
7583 DHD_INFO(("%s: Initial value for %s is %d\n",
7584 __FUNCTION__, "sd_blocksize", bus->blocksize));
7586 dhdsdio_tune_fifoparam(bus);
7588 bus->roundup = MIN(max_roundup, bus->blocksize);
7590 #ifdef DHDENABLE_TAILPAD
7592 PKTFREE(osh, bus->pad_pkt, FALSE);
7593 bus->pad_pkt = PKTGET(osh, SDIO_MAX_BLOCK_SIZE, FALSE);
7594 if (bus->pad_pkt == NULL)
7595 DHD_ERROR(("failed to allocate padding packet\n"));
7597 int alignment_offset = 0;
7598 uintptr pktprt = (uintptr)PKTDATA(osh, bus->pad_pkt);
7599 if (!(pktprt&1) && (pktprt = (pktprt % DHD_SDALIGN)))
7600 PKTPUSH(osh, bus->pad_pkt, alignment_offset);
7601 PKTSETNEXT(osh, bus->pad_pkt, NULL);
7603 #endif /* DHDENABLE_TAILPAD */
7605 /* Query if bus module supports packet chaining, default to use if supported */
7606 if (bcmsdh_iovar_op(sdh, "sd_rxchain", NULL, 0,
7607 &bus->sd_rxchain, sizeof(int32), FALSE) != BCME_OK) {
7608 bus->sd_rxchain = FALSE;
7610 DHD_INFO(("%s: bus module (through bcmsdh API) %s chaining\n",
7611 __FUNCTION__, (bus->sd_rxchain ? "supports" : "does not support")));
7613 bus->use_rxchain = (bool)bus->sd_rxchain;
7614 if (bus->dhd->conf->use_rxchain >= 0) {
7615 printf("%s: set use_rxchain %d from config.txt\n", __FUNCTION__, bus->dhd->conf->use_rxchain);
7616 bus->use_rxchain = (bool)bus->dhd->conf->use_rxchain;
7618 /* Setting default Glom size */
7619 if (bus->dhd->conf->txglomsize >= 0) {
7620 printf("%s: set txglomsize %d from config.txt\n", __FUNCTION__, bus->dhd->conf->txglomsize);
7621 bus->txglomsize = bus->dhd->conf->txglomsize;
7623 bus->txinrx_thres = CUSTOM_TXINRX_THRES;
7624 /* TX first in dhdsdio_readframes() */
7625 bus->dotxinrx = TRUE;
7631 dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh,
7632 char *pfw_path, char *pnv_path, char *pconf_path)
7636 bus->fw_path = pfw_path;
7637 bus->nv_path = pnv_path;
7638 bus->dhd->conf_path = pconf_path;
7640 ret = dhdsdio_download_firmware(bus, osh, bus->sdh);
7647 dhdsdio_download_firmware(struct dhd_bus *bus, osl_t *osh, void *sdh)
7651 DHD_TRACE_HW4(("%s: firmware path=%s, nvram path=%s\n",
7652 __FUNCTION__, bus->fw_path, bus->nv_path));
7653 DHD_OS_WAKE_LOCK(bus->dhd);
7655 /* Download the firmware */
7656 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
7658 /* External conf takes precedence if specified */
7659 dhd_conf_preinit(bus->dhd);
7660 dhd_conf_read_config(bus->dhd, bus->dhd->conf_path);
7661 dhd_conf_set_fw_name_by_chip(bus->dhd, bus->fw_path, bus->nv_path);
7662 dhd_conf_set_nv_name_by_chip(bus->dhd, bus->nv_path);
7663 dhd_conf_set_fw_name_by_mac(bus->dhd, bus->sdh, bus->fw_path);
7664 dhd_conf_set_nv_name_by_mac(bus->dhd, bus->sdh, bus->nv_path);
7666 printf("Final fw_path=%s\n", bus->fw_path);
7667 printf("Final nv_path=%s\n", bus->nv_path);
7668 printf("Final conf_path=%s\n", bus->dhd->conf_path);
7670 ret = _dhdsdio_download_firmware(bus);
7672 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
7674 DHD_OS_WAKE_UNLOCK(bus->dhd);
7678 /* Detach and free everything */
7680 dhdsdio_release(dhd_bus_t *bus, osl_t *osh)
7682 bool dongle_isolation = FALSE;
7683 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7689 dongle_isolation = bus->dhd->dongle_isolation;
7690 dhd_detach(bus->dhd);
7693 /* De-register interrupt handler */
7694 bcmsdh_intr_disable(bus->sdh);
7695 bcmsdh_intr_dereg(bus->sdh);
7698 dhdsdio_release_dongle(bus, osh, dongle_isolation, TRUE);
7703 dhdsdio_release_malloc(bus, osh);
7706 if (bus->console.buf != NULL)
7707 MFREE(osh, bus->console.buf, bus->console.bufsize);
7710 #ifdef DHDENABLE_TAILPAD
7712 PKTFREE(osh, bus->pad_pkt, FALSE);
7713 #endif /* DHDENABLE_TAILPAD */
7715 MFREE(osh, bus, sizeof(dhd_bus_t));
7718 DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
7722 dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh)
7724 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7726 if (bus->dhd && bus->dhd->dongle_reset)
7730 #ifndef CONFIG_DHD_USE_STATIC_BUF
7731 MFREE(osh, bus->rxbuf, bus->rxblen);
7733 bus->rxctl = bus->rxbuf = NULL;
7738 #ifndef CONFIG_DHD_USE_STATIC_BUF
7739 MFREE(osh, bus->databuf, MAX_DATA_BUF);
7741 bus->databuf = NULL;
7744 if (bus->vars && bus->varsz) {
7745 MFREE(osh, bus->vars, bus->varsz);
7753 dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation, bool reset_flag)
7755 DHD_TRACE(("%s: Enter bus->dhd %p bus->dhd->dongle_reset %d \n", __FUNCTION__,
7756 bus->dhd, bus->dhd->dongle_reset));
7758 if ((bus->dhd && bus->dhd->dongle_reset) && reset_flag)
7762 #if !defined(BCMLXSDMMC)
7764 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
7766 if (KSO_ENAB(bus) && (dongle_isolation == FALSE))
7767 si_watchdog(bus->sih, 4);
7768 #endif /* !defined(BCMLXSDMMC) */
7770 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
7772 si_detach(bus->sih);
7774 if (bus->vars && bus->varsz)
7775 MFREE(osh, bus->vars, bus->varsz);
7779 DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
7783 dhdsdio_disconnect(void *ptr)
7785 dhd_bus_t *bus = (dhd_bus_t *)ptr;
7787 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7789 #if defined(MULTIPLE_SUPPLICANT)
7790 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
7791 if (mutex_is_locked(&_dhd_sdio_mutex_lock_) == 0) {
7792 DHD_ERROR(("%s : no mutex held. set lock\n", __FUNCTION__));
7795 DHD_ERROR(("%s : mutex is locked!. wait for unlocking\n", __FUNCTION__));
7797 mutex_lock(&_dhd_sdio_mutex_lock_);
7798 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
7804 dhdsdio_release(bus, bus->dhd->osh);
7807 #if defined(MULTIPLE_SUPPLICANT)
7808 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
7809 mutex_unlock(&_dhd_sdio_mutex_lock_);
7810 DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__));
7811 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
7815 DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
7819 dhdsdio_suspend(void *context)
7823 dhd_bus_t *bus = (dhd_bus_t*)context;
7825 if (bus->idletime > 0) {
7826 wait_time = msecs_to_jiffies(bus->idletime * dhd_watchdog_ms);
7829 ret = dhd_os_check_wakelock(bus->dhd);
7830 // terence 20141124: fix for suspend issue
7831 if (SLPAUTO_ENAB(bus) && (!ret) && (bus->dhd->up)) {
7832 if (wait_event_timeout(bus->bus_sleep, bus->sleeping, wait_time) == 0) {
7833 if (!bus->sleeping) {
7842 dhdsdio_resume(void *context)
7844 #if defined(OOB_INTR_ONLY)
7845 dhd_bus_t *bus = (dhd_bus_t*)context;
7847 if (dhd_os_check_if_up(bus->dhd))
7848 bcmsdh_oob_intr_set(bus->sdh, TRUE);
7854 /* Register/Unregister functions are called by the main DHD entry
7855 * point (e.g. module insertion) to link with the bus driver, in
7856 * order to look for or await the device.
7859 static bcmsdh_driver_t dhd_sdio = {
7867 dhd_bus_register(void)
7869 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7871 return bcmsdh_register(&dhd_sdio);
7875 dhd_bus_unregister(void)
7877 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7879 bcmsdh_unregister();
7882 #if defined(BCMLXSDMMC)
7883 /* Register a dummy SDIO client driver in order to be notified of new SDIO device */
7884 int dhd_bus_reg_sdio_notify(void* semaphore)
7886 return bcmsdh_reg_sdio_notify(semaphore);
7889 void dhd_bus_unreg_sdio_notify(void)
7891 bcmsdh_unreg_sdio_notify();
7893 #endif /* defined(BCMLXSDMMC) */
7895 #ifdef BCMEMBEDIMAGE
7897 dhdsdio_download_code_array(struct dhd_bus *bus)
7901 unsigned char *ularray = NULL;
7903 DHD_INFO(("%s: download embedded firmware...\n", __FUNCTION__));
7905 /* Download image */
7906 while ((offset + MEMBLOCK) < sizeof(dlarray)) {
7908 if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
7909 /* if address is 0, store the reset instruction to be written in 0 */
7912 bus->resetinstr = *(((uint32*)dlarray));
7913 /* Add start of RAM address to the address given by user */
7914 offset += bus->dongle_ram_base;
7918 bcmerror = dhdsdio_membytes(bus, TRUE, offset,
7919 (uint8 *) (dlarray + offset), MEMBLOCK);
7921 DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
7922 __FUNCTION__, bcmerror, MEMBLOCK, offset));
7929 if (offset < sizeof(dlarray)) {
7930 bcmerror = dhdsdio_membytes(bus, TRUE, offset,
7931 (uint8 *) (dlarray + offset), sizeof(dlarray) - offset);
7933 DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
7934 __FUNCTION__, bcmerror, sizeof(dlarray) - offset, offset));
7940 /* Upload and compare the downloaded code */
7942 ularray = MALLOC(bus->dhd->osh, bus->ramsize);
7943 /* Upload image to verify downloaded contents. */
7945 memset(ularray, 0xaa, bus->ramsize);
7946 while ((offset + MEMBLOCK) < sizeof(dlarray)) {
7947 bcmerror = dhdsdio_membytes(bus, FALSE, offset, ularray + offset, MEMBLOCK);
7949 DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n",
7950 __FUNCTION__, bcmerror, MEMBLOCK, offset));
7957 if (offset < sizeof(dlarray)) {
7958 bcmerror = dhdsdio_membytes(bus, FALSE, offset,
7959 ularray + offset, sizeof(dlarray) - offset);
7961 DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n",
7962 __FUNCTION__, bcmerror, sizeof(dlarray) - offset, offset));
7967 if (memcmp(dlarray, ularray, sizeof(dlarray))) {
7968 DHD_ERROR(("%s: Downloaded image is corrupted (%s, %s, %s).\n",
7969 __FUNCTION__, dlimagename, dlimagever, dlimagedate));
7972 DHD_ERROR(("%s: Download, Upload and compare succeeded (%s, %s, %s).\n",
7973 __FUNCTION__, dlimagename, dlimagever, dlimagedate));
7976 #endif /* DHD_DEBUG */
7980 MFREE(bus->dhd->osh, ularray, bus->ramsize);
7983 #endif /* BCMEMBEDIMAGE */
7986 dhdsdio_download_code_file(struct dhd_bus *bus, char *pfw_path)
7992 uint8 *memblock = NULL, *memptr;
7993 uint8 *memptr_tmp = NULL; // terence: check downloaded firmware is correct
7995 DHD_INFO(("%s: download firmware %s\n", __FUNCTION__, pfw_path));
7997 image = dhd_os_open_image(pfw_path);
7998 if (image == NULL) {
7999 printf("%s: Open firmware file failed %s\n", __FUNCTION__, pfw_path);
8003 memptr = memblock = MALLOC(bus->dhd->osh, MEMBLOCK + DHD_SDALIGN);
8004 if (memblock == NULL) {
8005 DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, MEMBLOCK));
8008 if (dhd_msg_level & DHD_TRACE_VAL) {
8009 memptr_tmp = MALLOC(bus->dhd->osh, MEMBLOCK + DHD_SDALIGN);
8010 if (memptr_tmp == NULL) {
8011 DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, MEMBLOCK));
8015 if ((uint32)(uintptr)memblock % DHD_SDALIGN)
8016 memptr += (DHD_SDALIGN - ((uint32)(uintptr)memblock % DHD_SDALIGN));
8018 /* Download image */
8019 while ((len = dhd_os_get_image_block((char*)memptr, MEMBLOCK, image))) {
8020 // terence 20150412: fix for firmware failed to download
8021 if (bus->dhd->conf->chip == BCM43340_CHIP_ID ||
8022 bus->dhd->conf->chip == BCM43341_CHIP_ID) {
8024 memset(memptr+len, 0, len%64);
8025 len += (64 - len%64);
8029 DHD_ERROR(("%s: dhd_os_get_image_block failed (%d)\n", __FUNCTION__, len));
8030 bcmerror = BCME_ERROR;
8034 if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
8035 /* if address is 0, store the reset instruction to be written in 0 */
8038 bus->resetinstr = *(((uint32*)memptr));
8039 /* Add start of RAM address to the address given by user */
8040 offset += bus->dongle_ram_base;
8044 bcmerror = dhdsdio_membytes(bus, TRUE, offset, memptr, len);
8046 DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
8047 __FUNCTION__, bcmerror, MEMBLOCK, offset));
8051 if (dhd_msg_level & DHD_TRACE_VAL) {
8052 bcmerror = dhdsdio_membytes(bus, FALSE, offset, memptr_tmp, len);
8054 DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n",
8055 __FUNCTION__, bcmerror, MEMBLOCK, offset));
8058 if (memcmp(memptr_tmp, memptr, len)) {
8059 DHD_ERROR(("%s: Downloaded image is corrupted.\n", __FUNCTION__));
8062 DHD_INFO(("%s: Download, Upload and compare succeeded.\n", __FUNCTION__));
8069 MFREE(bus->dhd->osh, memblock, MEMBLOCK + DHD_SDALIGN);
8070 if (dhd_msg_level & DHD_TRACE_VAL) {
8072 MFREE(bus->dhd->osh, memptr_tmp, MEMBLOCK + DHD_SDALIGN);
8076 dhd_os_close_image(image);
8082 EXAMPLE: nvram_array
8085 Use carriage return at the end of each assignment, and an empty string with
8086 carriage return at the end of array.
8089 unsigned char nvram_array[] = {"name1=value1\n", "name2=value2\n", "\n"};
8090 Hex values start with 0x, and mac addr format: xx:xx:xx:xx:xx:xx.
8092 Search "EXAMPLE: nvram_array" to see how the array is activated.
8096 dhd_bus_set_nvram_params(struct dhd_bus * bus, const char *nvram_params)
8098 bus->nvram_params = nvram_params;
8102 dhdsdio_download_nvram(struct dhd_bus *bus)
8106 void * image = NULL;
8107 char * memblock = NULL;
8110 bool nvram_file_exists;
8112 pnv_path = bus->nv_path;
8114 nvram_file_exists = ((pnv_path != NULL) && (pnv_path[0] != '\0'));
8115 if (!nvram_file_exists && (bus->nvram_params == NULL))
8118 if (nvram_file_exists) {
8119 image = dhd_os_open_image(pnv_path);
8120 if (image == NULL) {
8121 printf("%s: Open nvram file failed %s\n", __FUNCTION__, pnv_path);
8126 memblock = MALLOC(bus->dhd->osh, MAX_NVRAMBUF_SIZE);
8127 if (memblock == NULL) {
8128 DHD_ERROR(("%s: Failed to allocate memory %d bytes\n",
8129 __FUNCTION__, MAX_NVRAMBUF_SIZE));
8133 /* Download variables */
8134 if (nvram_file_exists) {
8135 len = dhd_os_get_image_block(memblock, MAX_NVRAMBUF_SIZE, image);
8138 len = strlen(bus->nvram_params);
8139 ASSERT(len <= MAX_NVRAMBUF_SIZE);
8140 memcpy(memblock, bus->nvram_params, len);
8142 if (len > 0 && len < MAX_NVRAMBUF_SIZE) {
8143 bufp = (char *)memblock;
8145 len = process_nvram_vars(bufp, len);
8147 len += 4 - (len % 4);
8152 bcmerror = dhdsdio_downloadvars(bus, memblock, len + 1);
8154 DHD_ERROR(("%s: error downloading vars: %d\n",
8155 __FUNCTION__, bcmerror));
8159 DHD_ERROR(("%s: error reading nvram file: %d\n",
8160 __FUNCTION__, len));
8161 bcmerror = BCME_SDIO_ERROR;
8166 MFREE(bus->dhd->osh, memblock, MAX_NVRAMBUF_SIZE);
8169 dhd_os_close_image(image);
8175 _dhdsdio_download_firmware(struct dhd_bus *bus)
8179 bool embed = FALSE; /* download embedded firmware */
8180 bool dlok = FALSE; /* download firmware succeeded */
8182 /* Out immediately if no image to download */
8183 if ((bus->fw_path == NULL) || (bus->fw_path[0] == '\0')) {
8184 #ifdef BCMEMBEDIMAGE
8191 /* Keep arm in reset */
8192 if (dhdsdio_download_state(bus, TRUE)) {
8193 DHD_ERROR(("%s: error placing ARM core in reset\n", __FUNCTION__));
8197 /* External image takes precedence if specified */
8198 if ((bus->fw_path != NULL) && (bus->fw_path[0] != '\0')) {
8199 if (dhdsdio_download_code_file(bus, bus->fw_path)) {
8200 DHD_ERROR(("%s: dongle image file download failed\n", __FUNCTION__));
8201 #ifdef BCMEMBEDIMAGE
8213 #ifdef BCMEMBEDIMAGE
8215 if (dhdsdio_download_code_array(bus)) {
8216 DHD_ERROR(("%s: dongle image array download failed\n", __FUNCTION__));
8224 BCM_REFERENCE(embed);
8227 DHD_ERROR(("%s: dongle image download failed\n", __FUNCTION__));
8231 /* EXAMPLE: nvram_array */
8232 /* If a valid nvram_arry is specified as above, it can be passed down to dongle */
8233 /* dhd_bus_set_nvram_params(bus, (char *)&nvram_array); */
8235 /* External nvram takes precedence if specified */
8236 if (dhdsdio_download_nvram(bus)) {
8237 DHD_ERROR(("%s: dongle nvram file download failed\n", __FUNCTION__));
8241 /* Take arm out of reset */
8242 if (dhdsdio_download_state(bus, FALSE)) {
8243 DHD_ERROR(("%s: error getting out of ARM core reset\n", __FUNCTION__));
8254 dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes,
8255 void *pkt, bcmsdh_cmplt_fn_t complete, void *handle)
8259 if (!KSO_ENAB(bus)) {
8260 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
8261 return BCME_NODEVICE;
8264 status = bcmsdh_recv_buf(bus->sdh, addr, fn, flags, buf, nbytes, pkt, complete, handle);
8270 dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes,
8271 void *pkt, bcmsdh_cmplt_fn_t complete, void *handle, int max_retry)
8278 if (!KSO_ENAB(bus)) {
8279 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
8280 return BCME_NODEVICE;
8285 ret = bcmsdh_send_buf(bus->sdh, addr, fn, flags, buf, nbytes,
8286 pkt, complete, handle);
8289 ASSERT(ret != BCME_PENDING);
8291 if (ret == BCME_NODEVICE) {
8292 DHD_ERROR(("%s: Device asleep already\n", __FUNCTION__));
8293 } else if (ret < 0) {
8294 /* On failure, abort the command and terminate the frame */
8295 DHD_ERROR(("%s: sdio error %d, abort command and terminate frame.\n",
8296 __FUNCTION__, ret));
8299 bus->dhd->tx_errors++;
8300 bcmsdh_abort(sdh, SDIO_FUNC_2);
8301 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
8303 for (i = 0; i < READ_FRM_CNT_RETRIES; i++) {
8305 hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WFRAMEBCHI,
8307 lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WFRAMEBCLO,
8309 bus->f1regdata += 2;
8310 if ((hi == 0) && (lo == 0))
8314 } while ((ret < 0) && retrydata && ++retries < max_retry);
8320 dhd_bus_chip(struct dhd_bus *bus)
8322 ASSERT(bus->sih != NULL);
8323 return bus->sih->chip;
8327 dhd_bus_chiprev(struct dhd_bus *bus)
8330 ASSERT(bus->sih != NULL);
8331 return bus->sih->chiprev;
8335 dhd_bus_pub(struct dhd_bus *bus)
8341 dhd_bus_sih(struct dhd_bus *bus)
8343 return (void *)bus->sih;
8347 dhd_bus_txq(struct dhd_bus *bus)
8353 dhd_bus_hdrlen(struct dhd_bus *bus)
8355 return (bus->txglom_enable) ? SDPCM_HDRLEN_TXGLOM : SDPCM_HDRLEN;
8359 dhd_bus_set_dotxinrx(struct dhd_bus *bus, bool val)
8361 bus->dotxinrx = val;
8365 dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag)
8373 if (!bus->dhd->dongle_reset) {
8374 dhd_os_sdlock(dhdp);
8375 dhd_os_wd_timer(dhdp, 0);
8376 #if !defined(IGNORE_ETH0_DOWN)
8377 /* Force flow control as protection when stop come before ifconfig_down */
8378 dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON);
8379 #endif /* !defined(IGNORE_ETH0_DOWN) */
8380 /* Expect app to have torn down any connection before calling */
8381 /* Stop the bus, disable F2 */
8382 dhd_bus_stop(bus, FALSE);
8384 #if defined(OOB_INTR_ONLY)
8385 /* Clean up any pending IRQ */
8386 dhd_enable_oob_intr(bus, FALSE);
8387 bcmsdh_oob_intr_set(bus->sdh, FALSE);
8388 bcmsdh_oob_intr_unregister(bus->sdh);
8391 /* Clean tx/rx buffer pointers, detach from the dongle */
8392 dhdsdio_release_dongle(bus, bus->dhd->osh, TRUE, TRUE);
8394 bus->dhd->dongle_reset = TRUE;
8395 bus->dhd->up = FALSE;
8396 dhd_txglom_enable(dhdp, FALSE);
8397 dhd_os_sdunlock(dhdp);
8399 printf("%s: WLAN OFF DONE\n", __FUNCTION__);
8400 /* App can now remove power from device */
8402 bcmerror = BCME_SDIO_ERROR;
8404 /* App must have restored power to device before calling */
8406 printf("\n\n%s: == WLAN ON ==\n", __FUNCTION__);
8408 if (bus->dhd->dongle_reset) {
8410 dhd_os_sdlock(dhdp);
8411 /* Reset SD client */
8412 bcmsdh_reset(bus->sdh);
8414 /* Attempt to re-attach & download */
8415 if (dhdsdio_probe_attach(bus, bus->dhd->osh, bus->sdh,
8416 (uint32 *)SI_ENUM_BASE,
8418 /* Attempt to download binary to the dongle */
8419 if (dhdsdio_probe_init(bus, bus->dhd->osh, bus->sdh) &&
8420 dhdsdio_download_firmware(bus, bus->dhd->osh, bus->sdh) >= 0) {
8422 /* Re-init bus, enable F2 transfer */
8423 bcmerror = dhd_bus_init((dhd_pub_t *) bus->dhd, FALSE);
8424 if (bcmerror == BCME_OK) {
8425 #if defined(OOB_INTR_ONLY)
8426 dhd_enable_oob_intr(bus, TRUE);
8427 bcmsdh_oob_intr_register(bus->sdh,
8429 bcmsdh_oob_intr_set(bus->sdh, TRUE);
8432 bus->dhd->dongle_reset = FALSE;
8433 bus->dhd->up = TRUE;
8435 #if !defined(IGNORE_ETH0_DOWN)
8436 /* Restore flow control */
8437 dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF);
8439 dhd_os_wd_timer(dhdp, dhd_watchdog_ms);
8441 DHD_TRACE(("%s: WLAN ON DONE\n", __FUNCTION__));
8443 dhd_bus_stop(bus, FALSE);
8444 dhdsdio_release_dongle(bus, bus->dhd->osh,
8448 bcmerror = BCME_SDIO_ERROR;
8450 bcmerror = BCME_SDIO_ERROR;
8452 dhd_os_sdunlock(dhdp);
8454 bcmerror = BCME_SDIO_ERROR;
8455 printf("%s called when dongle is not in reset\n",
8457 printf("Will call dhd_bus_start instead\n");
8458 dhd_bus_resume(dhdp, 1);
8460 dhd_conf_set_hw_oob_intr(bus->sdh, bus->sih->chip); // terence 20120615: fix for OOB initial issue
8462 if ((bcmerror = dhd_bus_start(dhdp)) != 0)
8463 DHD_ERROR(("%s: dhd_bus_start fail with %d\n",
8464 __FUNCTION__, bcmerror));
8470 int dhd_bus_suspend(dhd_pub_t *dhdpub)
8472 return bcmsdh_stop(dhdpub->bus->sdh);
8475 int dhd_bus_resume(dhd_pub_t *dhdpub, int stage)
8477 return bcmsdh_start(dhdpub->bus->sdh, stage);
8480 /* Get Chip ID version */
8481 uint dhd_bus_chip_id(dhd_pub_t *dhdp)
8483 dhd_bus_t *bus = dhdp->bus;
8485 if (bus && bus->sih)
8486 return bus->sih->chip;
8491 /* Get Chip Rev ID version */
8492 uint dhd_bus_chiprev_id(dhd_pub_t *dhdp)
8494 dhd_bus_t *bus = dhdp->bus;
8496 if (bus && bus->sih)
8497 return bus->sih->chiprev;
8502 /* Get Chip Pkg ID version */
8503 uint dhd_bus_chippkg_id(dhd_pub_t *dhdp)
8505 dhd_bus_t *bus = dhdp->bus;
8507 return bus->sih->chippkg;
8510 int dhd_bus_get_ids(struct dhd_bus *bus, uint32 *bus_type, uint32 *bus_num, uint32 *slot_num)
8512 *bus_type = bus->bus;
8513 *bus_num = bus->bus_num;
8514 *slot_num = bus->slot_num;
8519 dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint size)
8524 return dhdsdio_membytes(bus, set, address, data, size);
8527 #if defined(NDISVER) && (NDISVER >= 0x0630)
8529 dhd_bus_reject_ioreqs(dhd_pub_t *dhdp, bool reject)
8532 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
8534 bcmsdh_reject_ioreqs(dhdp->bus->sdh, reject);
8538 dhd_bus_waitfor_iodrain(dhd_pub_t *dhdp)
8541 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
8543 bcmsdh_waitfor_iodrain(dhdp->bus->sdh);
8545 #endif /* (NDISVER) && (NDISVER >= 0x0630) */
8548 dhd_bus_update_fw_nv_path(struct dhd_bus *bus, char *pfw_path, char *pnv_path, char *pconf_path)
8550 bus->fw_path = pfw_path;
8551 bus->nv_path = pnv_path;
8552 bus->dhd->conf_path = pconf_path;
8556 dhd_enableOOB(dhd_pub_t *dhd, bool sleep)
8558 dhd_bus_t *bus = dhd->bus;
8559 sdpcmd_regs_t *regs = bus->regs;
8563 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
8564 /* Tell device to start using OOB wakeup */
8565 W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries);
8566 if (retries > retry_limit) {
8567 DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
8570 /* Turn off our contribution to the HT clock request */
8571 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
8573 /* Make sure the controller has the bus up */
8574 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
8576 /* Send misc interrupt to indicate OOB not needed */
8577 W_SDREG(0, ®s->tosbmailboxdata, retries);
8578 if (retries <= retry_limit)
8579 W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries);
8581 if (retries > retry_limit)
8582 DHD_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n"));
8584 /* Make sure we have SD bus access */
8585 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
8591 dhd_bus_pktq_flush(dhd_pub_t *dhdp)
8593 dhd_bus_t *bus = dhdp->bus;
8594 bool wlfc_enabled = FALSE;
8596 #ifdef PROP_TXSTATUS
8597 wlfc_enabled = (dhd_wlfc_cleanup_txq(dhdp, NULL, 0) != WLFC_UNSUPPORTED);
8599 if (!wlfc_enabled) {
8600 #ifdef DHDTCPACK_SUPPRESS
8601 /* Clean tcp_ack_info_tbl in order to prevent access to flushed pkt,
8602 * when there is a newly coming packet from network stack.
8604 dhd_tcpack_info_tbl_clean(bus->dhd);
8605 #endif /* DHDTCPACK_SUPPRESS */
8606 /* Clear the data packet queues */
8607 pktq_flush(dhdp->osh, &bus->txq, TRUE, NULL, 0);
8613 dhd_sr_config(dhd_pub_t *dhd, bool on)
8615 dhd_bus_t *bus = dhd->bus;
8620 return dhdsdio_clk_devsleep_iovar(bus, on);
8624 dhd_get_chipid(dhd_pub_t *dhd)
8626 dhd_bus_t *bus = dhd->bus;
8628 if (bus && bus->sih)
8629 return (uint16)bus->sih->chip;
8633 #endif /* BCMSDIO */
8636 uint32 dhd_sdio_reg_read(void *h, uint32 addr)
8639 struct dhd_bus *bus = (struct dhd_bus *) h;
8641 dhd_os_sdlock(bus->dhd);
8645 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
8647 rval = bcmsdh_reg_read(bus->sdh, addr, 4);
8649 dhd_os_sdunlock(bus->dhd);
8654 void dhd_sdio_reg_write(void *h, uint32 addr, uint32 val)
8656 struct dhd_bus *bus = (struct dhd_bus *) h;
8658 dhd_os_sdlock(bus->dhd);
8662 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
8664 bcmsdh_reg_write(bus->sdh, addr, 4, val);
8666 dhd_os_sdunlock(bus->dhd);
8668 #endif /* DEBUGGER */
8670 #if defined(SOFTAP_TPUT_ENHANCE)
8671 void dhd_bus_setidletime(dhd_pub_t *dhdp, int idle_time)
8673 if (!dhdp || !dhdp->bus) {
8674 DHD_ERROR(("%s:Bus is Invalid\n", __FUNCTION__));
8677 dhdp->bus->idletime = idle_time;
8680 void dhd_bus_getidletime(dhd_pub_t *dhdp, int* idle_time)
8682 if (!dhdp || !dhdp->bus) {
8683 DHD_ERROR(("%s:Bus is Invalid\n", __FUNCTION__));
8688 DHD_ERROR(("%s:Arg idle_time is NULL\n", __FUNCTION__));
8691 *idle_time = dhdp->bus->idletime;
8693 #endif /* SOFTAP_TPUT_ENHANCE */