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 */
375 #define CLK_PENDING 2 /* Not used yet */
378 #define DHD_NOPMU(dhd) (FALSE)
381 static int qcount[NUMPRIO];
382 static int tx_packets[NUMPRIO];
383 #endif /* DHD_DEBUG */
385 /* Deferred transmit */
386 const uint dhd_deferred_tx = 1;
388 extern uint dhd_watchdog_ms;
390 extern void dhd_os_wd_timer(void *bus, uint wdtick);
395 uint dhd_txminmax = DHD_TXMINMAX;
397 /* override the RAM size if possible */
398 #define DONGLE_MIN_RAMSIZE (128 *1024)
399 int dhd_dongle_ramsize;
401 uint dhd_doflow = TRUE;
402 uint dhd_dpcpoll = FALSE;
404 module_param(dhd_doflow, uint, 0644);
405 module_param(dhd_dpcpoll, uint, 0644);
407 static bool dhd_alignctl;
411 static bool retrydata;
412 #define RETRYCHAN(chan) (((chan) == SDPCM_EVENT_CHANNEL) || retrydata)
414 static uint watermark = 8;
415 static uint mesbusyctrl = 0;
416 static const uint firstread = DHD_FIRSTREAD;
418 /* Retry count for register access failures */
419 static const uint retry_limit = 2;
421 /* Force even SD lengths (some host controllers mess up on odd bytes) */
422 static bool forcealign;
426 #if defined(OOB_INTR_ONLY) && defined(HW_OOB)
427 extern void bcmsdh_enable_hw_oob_intr(void *sdh, bool enable);
430 #if defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD)
431 #error OOB_INTR_ONLY is NOT working with SDIO_ISR_THREAD
432 #endif /* defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD) */
433 #define PKTALIGN(osh, p, len, align) \
436 datalign = (uintptr)PKTDATA((osh), (p)); \
437 datalign = ROUNDUP(datalign, (align)) - datalign; \
438 ASSERT(datalign < (align)); \
439 ASSERT(PKTLEN((osh), (p)) >= ((len) + datalign)); \
441 PKTPULL((osh), (p), (uint)datalign); \
442 PKTSETLEN((osh), (p), (len)); \
445 /* Limit on rounding up frames */
446 static const uint max_roundup = 512;
448 /* Try doing readahead */
449 static bool dhd_readahead;
451 /* To check if there's window offered */
452 #define DATAOK(bus) \
453 (((uint8)(bus->tx_max - bus->tx_seq) > 1) && \
454 (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0))
456 /* To check if there's window offered for ctrl frame */
457 #define TXCTLOK(bus) \
458 (((uint8)(bus->tx_max - bus->tx_seq) != 0) && \
459 (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0))
461 /* Number of pkts available in dongle for data RX */
462 #define DATABUFCNT(bus) \
463 ((uint8)(bus->tx_max - bus->tx_seq) - 1)
465 /* Macros to get register read/write status */
466 /* NOTE: these assume a local dhdsdio_bus_t *bus! */
467 #define R_SDREG(regvar, regaddr, retryvar) \
471 regvar = R_REG(bus->dhd->osh, regaddr); \
472 } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \
474 bus->regfails += (retryvar-1); \
475 if (retryvar > retry_limit) { \
476 DHD_ERROR(("%s: FAILED" #regvar "READ, LINE %d\n", \
477 __FUNCTION__, __LINE__)); \
483 #define W_SDREG(regval, regaddr, retryvar) \
487 W_REG(bus->dhd->osh, regaddr, regval); \
488 } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \
490 bus->regfails += (retryvar-1); \
491 if (retryvar > retry_limit) \
492 DHD_ERROR(("%s: FAILED REGISTER WRITE, LINE %d\n", \
493 __FUNCTION__, __LINE__)); \
497 #define BUS_WAKE(bus) \
499 bus->idlecount = 0; \
500 if ((bus)->sleeping) \
501 dhdsdio_bussleep((bus), FALSE); \
505 * pktavail interrupts from dongle to host can be managed in 3 different ways
506 * whenever there is a packet available in dongle to transmit to host.
508 * Mode 0: Dongle writes the software host mailbox and host is interrupted.
509 * Mode 1: (sdiod core rev >= 4)
510 * Device sets a new bit in the intstatus whenever there is a packet
511 * available in fifo. Host can't clear this specific status bit until all the
512 * packets are read from the FIFO. No need to ack dongle intstatus.
513 * Mode 2: (sdiod core rev >= 4)
514 * Device sets a bit in the intstatus, and host acks this by writing
515 * one to this bit. Dongle won't generate anymore packet interrupts
516 * until host reads all the packets from the dongle and reads a zero to
517 * figure that there are no more packets. No need to disable host ints.
518 * Need to ack the intstatus.
521 #define SDIO_DEVICE_HMB_RXINT 0 /* default old way */
522 #define SDIO_DEVICE_RXDATAINT_MODE_0 1 /* from sdiod rev 4 */
523 #define SDIO_DEVICE_RXDATAINT_MODE_1 2 /* from sdiod rev 4 */
526 #define FRAME_AVAIL_MASK(bus) \
527 ((bus->rxint_mode == SDIO_DEVICE_HMB_RXINT) ? I_HMB_FRAME_IND : I_XMTDATA_AVAIL)
529 #define DHD_BUS SDIO_BUS
531 #define PKT_AVAILABLE(bus, intstatus) ((intstatus) & (FRAME_AVAIL_MASK(bus)))
533 #define HOSTINTMASK (I_HMB_SW_MASK | I_CHIPACTIVE)
535 #define GSPI_PR55150_BAILOUT
538 static void dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq);
539 static void dhdsdio_sdtest_set(dhd_bus_t *bus, uint count);
543 static int dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size);
544 static int dhd_serialconsole(dhd_bus_t *bus, bool get, bool enable, int *bcmerror);
545 #endif /* DHD_DEBUG */
547 static int dhdsdio_devcap_set(dhd_bus_t *bus, uint8 cap);
548 static int dhdsdio_download_state(dhd_bus_t *bus, bool enter);
550 static void dhdsdio_release(dhd_bus_t *bus, osl_t *osh);
551 static void dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh);
552 static void dhdsdio_disconnect(void *ptr);
553 static bool dhdsdio_chipmatch(uint16 chipid);
554 static bool dhdsdio_probe_attach(dhd_bus_t *bus, osl_t *osh, void *sdh,
555 void * regsva, uint16 devid);
556 static bool dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh);
557 static bool dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh);
558 static void dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation,
561 static void dhd_dongle_setramsize(struct dhd_bus *bus, int mem_size);
562 static int dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags,
563 uint8 *buf, uint nbytes,
564 void *pkt, bcmsdh_cmplt_fn_t complete, void *handle);
565 static int dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags,
566 uint8 *buf, uint nbytes,
567 void *pkt, bcmsdh_cmplt_fn_t complete, void *handle, int max_retry);
568 static int dhdsdio_txpkt(dhd_bus_t *bus, uint chan, void** pkts, int num_pkt, bool free_pkt);
569 static int dhdsdio_txpkt_preprocess(dhd_bus_t *bus, void *pkt, int chan, int txseq,
570 int prev_chain_total_len, bool last_chained_pkt,
571 int *pad_pkt_len, void **new_pkt);
572 static int dhdsdio_txpkt_postprocess(dhd_bus_t *bus, void *pkt);
574 static int dhdsdio_download_firmware(dhd_bus_t *bus, osl_t *osh, void *sdh);
575 static int _dhdsdio_download_firmware(dhd_bus_t *bus);
577 static int dhdsdio_download_code_file(dhd_bus_t *bus, char *image_path);
578 static int dhdsdio_download_nvram(dhd_bus_t *bus);
580 static int dhdsdio_download_code_array(dhd_bus_t *bus);
582 static int dhdsdio_bussleep(dhd_bus_t *bus, bool sleep);
583 static int dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok);
584 static uint8 dhdsdio_sleepcsr_get(dhd_bus_t *bus);
588 extern uint32 dhd_get_htsf(void *dhd, int ifidx);
589 #endif /* WLMEDIA_HTSF */
592 dhdsdio_tune_fifoparam(struct dhd_bus *bus)
595 uint8 devctl, wm, mes;
597 if (bus->sih->buscorerev >= 15) {
598 /* See .ppt in PR for these recommended values */
599 if (bus->blocksize == 512) {
600 wm = OVERFLOW_BLKSZ512_WM;
601 mes = OVERFLOW_BLKSZ512_MES;
603 mes = bus->blocksize/4;
604 wm = bus->blocksize/4;
610 DHD_INFO(("skip fifotune: SdioRev(%d) is lower than minimal requested ver\n",
611 bus->sih->buscorerev));
615 /* Update watermark */
617 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, wm, &err);
619 devctl = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
620 devctl |= SBSDIO_DEVCTL_F2WM_ENAB;
621 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
626 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL,
627 (mes | SBSDIO_MESBUSYCTRL_ENAB), &err);
630 DHD_INFO(("Apply overflow WAR: 0x%02x 0x%02x 0x%02x\n",
631 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err),
632 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, &err),
633 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL, &err)));
637 dhd_dongle_setramsize(struct dhd_bus *bus, int mem_size)
639 int32 min_size = DONGLE_MIN_RAMSIZE;
640 /* Restrict the ramsize to user specified limit */
641 DHD_ERROR(("user: Restrict the dongle ram size to %d, min accepted %d\n",
642 dhd_dongle_ramsize, min_size));
643 if ((dhd_dongle_ramsize > min_size) &&
644 (dhd_dongle_ramsize < (int32)bus->orig_ramsize))
645 bus->ramsize = dhd_dongle_ramsize;
649 dhdsdio_set_siaddr_window(dhd_bus_t *bus, uint32 address)
652 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW,
653 (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err);
655 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID,
656 (address >> 16) & SBSDIO_SBADDRMID_MASK, &err);
658 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH,
659 (address >> 24) & SBSDIO_SBADDRHIGH_MASK, &err);
666 dhdsdio_oobwakeup_init(dhd_bus_t *bus)
668 uint32 val, addr, data;
670 bcmsdh_gpioouten(bus->sdh, GPIO_DEV_WAKEUP);
672 addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr);
673 data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data);
675 /* Set device for gpio1 wakeup */
676 bcmsdh_reg_write(bus->sdh, addr, 4, 2);
677 val = bcmsdh_reg_read(bus->sdh, data, 4);
678 val |= CC_CHIPCTRL2_GPIO1_WAKEUP;
679 bcmsdh_reg_write(bus->sdh, data, 4, val);
681 bus->_oobwakeup = TRUE;
685 #endif /* USE_OOB_GPIO1 */
688 * Query if FW is in SR mode
691 dhdsdio_sr_cap(dhd_bus_t *bus)
694 uint32 core_capext, addr, data;
696 if (bus->sih->chip == BCM43430_CHIP_ID) {
697 /* check if fw initialized sr engine */
698 addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, sr_control1);
699 if (bcmsdh_reg_read(bus->sdh, addr, 4) != 0)
704 if (bus->sih->chip == BCM4324_CHIP_ID) {
705 addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr);
706 data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data);
707 bcmsdh_reg_write(bus->sdh, addr, 4, 3);
708 core_capext = bcmsdh_reg_read(bus->sdh, data, 4);
709 } else if ((bus->sih->chip == BCM4330_CHIP_ID) ||
710 (bus->sih->chip == BCM43362_CHIP_ID)) {
712 } else if ((bus->sih->chip == BCM4335_CHIP_ID) ||
713 (bus->sih->chip == BCM4339_CHIP_ID) ||
714 (bus->sih->chip == BCM43349_CHIP_ID) ||
715 (bus->sih->chip == BCM4345_CHIP_ID) ||
716 (bus->sih->chip == BCM4354_CHIP_ID) ||
717 (bus->sih->chip == BCM4356_CHIP_ID) ||
718 (bus->sih->chip == BCM4358_CHIP_ID) ||
719 (BCM4349_CHIP(bus->sih->chip)) ||
720 (bus->sih->chip == BCM4350_CHIP_ID)) {
723 core_capext = bcmsdh_reg_read(bus->sdh, CORE_CAPEXT_ADDR, 4);
724 core_capext = (core_capext & CORE_CAPEXT_SR_SUPPORTED_MASK);
729 if (bus->sih->chip == BCM4324_CHIP_ID) {
730 /* FIX: Should change to query SR control register instead */
732 } else if ((bus->sih->chip == BCM4335_CHIP_ID) ||
733 (bus->sih->chip == BCM4339_CHIP_ID) ||
734 (bus->sih->chip == BCM43349_CHIP_ID) ||
735 (bus->sih->chip == BCM4345_CHIP_ID) ||
736 (bus->sih->chip == BCM4354_CHIP_ID) ||
737 (bus->sih->chip == BCM4356_CHIP_ID) ||
738 (bus->sih->chip == BCM4358_CHIP_ID) ||
739 (bus->sih->chip == BCM4350_CHIP_ID)) {
741 addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr);
742 data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data);
743 bcmsdh_reg_write(bus->sdh, addr, 4, CC_PMUCC3);
744 enabval = bcmsdh_reg_read(bus->sdh, data, 4);
746 if ((bus->sih->chip == BCM4350_CHIP_ID) ||
747 (bus->sih->chip == BCM4345_CHIP_ID) ||
748 (bus->sih->chip == BCM4354_CHIP_ID) ||
749 (bus->sih->chip == BCM4356_CHIP_ID) ||
750 (bus->sih->chip == BCM4358_CHIP_ID))
751 enabval &= CC_CHIPCTRL3_SR_ENG_ENABLE;
756 data = bcmsdh_reg_read(bus->sdh,
757 SI_ENUM_BASE + OFFSETOF(chipcregs_t, retention_ctl), 4);
758 if ((data & (RCTL_MACPHY_DISABLE_MASK | RCTL_LOGIC_DISABLE_MASK)) == 0)
766 dhdsdio_srwar_init(dhd_bus_t *bus)
768 #if !defined(NDISVER) || (NDISVER < 0x0630)
769 bcmsdh_gpio_init(bus->sdh);
770 #endif /* !defined(NDISVER) || (NDISVER < 0x0630) */
773 dhdsdio_oobwakeup_init(bus);
781 dhdsdio_sr_init(dhd_bus_t *bus)
786 if ((bus->sih->chip == BCM4334_CHIP_ID) && (bus->sih->chiprev == 2))
787 dhdsdio_srwar_init(bus);
789 val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, NULL);
790 val |= 1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT;
791 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL,
792 1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT, &err);
793 val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, NULL);
796 /* Add CMD14 Support */
797 dhdsdio_devcap_set(bus,
798 (SDIOD_CCCR_BRCM_CARDCAP_CMD14_SUPPORT | SDIOD_CCCR_BRCM_CARDCAP_CMD14_EXT));
799 #endif /* USE_CMD14 */
801 dhdsdio_devcap_set(bus, SDIOD_CCCR_BRCM_CARDCAP_CMD_NODEC);
803 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1,
804 SBSDIO_FUNC1_CHIPCLKCSR, SBSDIO_FORCE_HT, &err);
806 bus->_slpauto = dhd_slpauto ? TRUE : FALSE;
814 * FIX: Be sure KSO bit is enabled
815 * Currently, it's defaulting to 0 which should be 1.
818 dhdsdio_clk_kso_init(dhd_bus_t *bus)
827 * Enable KeepSdioOn (KSO) bit for normal operation
828 * Default is 0 (4334A0) so set it. Fixed in B0.
830 val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, NULL);
831 if (!(val & SBSDIO_FUNC1_SLEEPCSR_KSO_MASK)) {
832 val |= (SBSDIO_FUNC1_SLEEPCSR_KSO_EN << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT);
833 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, val, &err);
835 DHD_ERROR(("%s: SBSDIO_FUNC1_SLEEPCSR err: 0x%x\n", __FUNCTION__, err));
842 #define KSO_WAIT_US 50
843 #define KSO_WAIT_MS 1
844 #define KSO_SLEEP_RETRY_COUNT 20
845 #define ERROR_BCME_NODEVICE_MAX 1
847 #define MAX_KSO_ATTEMPTS (PMU_MAX_TRANSITION_DLY/KSO_WAIT_US)
849 dhdsdio_clk_kso_enab(dhd_bus_t *bus, bool on)
851 uint8 wr_val = 0, rd_val, cmp_val, bmask;
855 if (!bus->dhd->conf->kso_enable)
858 KSO_DBG(("%s> op:%s\n", __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR")));
860 wr_val |= (on << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT);
862 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, wr_val, &err);
865 cmp_val = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK | SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK;
870 /* Put device to sleep, turn off KSO */
872 bmask = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK;
876 rd_val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, &err);
877 if (((rd_val & bmask) == cmp_val) && !err)
880 KSO_DBG(("%s> KSO wr/rd retry:%d, ERR:%x \n", __FUNCTION__, try_cnt, err));
882 if (((try_cnt + 1) % KSO_SLEEP_RETRY_COUNT) == 0) {
883 OSL_SLEEP(KSO_WAIT_MS);
885 OSL_DELAY(KSO_WAIT_US);
887 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, wr_val, &err);
888 } while (try_cnt++ < MAX_KSO_ATTEMPTS);
892 KSO_DBG(("%s> op:%s, try_cnt:%d, rd_val:%x, ERR:%x \n",
893 __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"), try_cnt, rd_val, err));
895 if (try_cnt > MAX_KSO_ATTEMPTS) {
896 DHD_ERROR(("%s> op:%s, ERROR: try_cnt:%d, rd_val:%x, ERR:%x \n",
897 __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"), try_cnt, rd_val, err));
903 dhdsdio_clk_kso_iovar(dhd_bus_t *bus, bool on)
910 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
912 DHD_ERROR(("%s: KSO disable clk: 0x%x\n", __FUNCTION__,
913 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
914 SBSDIO_FUNC1_CHIPCLKCSR, &err)));
915 dhdsdio_clk_kso_enab(bus, FALSE);
917 DHD_ERROR(("%s: KSO enable\n", __FUNCTION__));
919 /* Make sure we have SD bus access */
920 if (bus->clkstate == CLK_NONE) {
921 DHD_ERROR(("%s: Request SD clk\n", __FUNCTION__));
922 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
925 dhdsdio_clk_kso_enab(bus, TRUE);
927 DHD_ERROR(("%s: sleepcsr: 0x%x\n", __FUNCTION__,
928 dhdsdio_sleepcsr_get(bus)));
938 dhdsdio_sleepcsr_get(dhd_bus_t *bus)
943 val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, &err);
945 DHD_TRACE(("Failed to read SLEEPCSR: %d\n", err));
951 dhdsdio_devcap_get(dhd_bus_t *bus)
953 return bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_BRCM_CARDCAP, NULL);
957 dhdsdio_devcap_set(dhd_bus_t *bus, uint8 cap)
961 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_BRCM_CARDCAP, cap, &err);
963 DHD_ERROR(("%s: devcap set err: 0x%x\n", __FUNCTION__, err));
969 dhdsdio_clk_devsleep_iovar(dhd_bus_t *bus, bool on)
978 /* Be sure we request clk before going to sleep
979 * so we can wake-up with clk request already set
980 * else device can go back to sleep immediately
982 if (!SLPAUTO_ENAB(bus))
983 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
985 val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
986 if ((val & SBSDIO_CSR_MASK) == 0) {
987 DHD_ERROR(("%s: No clock before enter sleep:0x%x\n",
990 /* Reset clock request */
991 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
992 SBSDIO_ALP_AVAIL_REQ, &err);
993 DHD_ERROR(("%s: clock before sleep:0x%x\n", __FUNCTION__,
994 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
995 SBSDIO_FUNC1_CHIPCLKCSR, &err)));
999 DHD_TRACE(("%s: clk before sleep: 0x%x\n", __FUNCTION__,
1000 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
1001 SBSDIO_FUNC1_CHIPCLKCSR, &err)));
1003 err = bcmsdh_sleep(bus->sdh, TRUE);
1005 err = dhdsdio_clk_kso_enab(bus, FALSE);
1006 if (OOB_WAKEUP_ENAB(bus))
1008 #if !defined(NDISVER) || (NDISVER < 0x0630)
1009 err = bcmsdh_gpioout(bus->sdh, GPIO_DEV_WAKEUP, FALSE); /* GPIO_1 is off */
1010 #endif /* !defined(NDISVER) || (NDISVER < 0x0630) */
1012 #endif /* USE_CMD14 */
1015 /* Make sure we have SD bus access */
1016 if (bus->clkstate == CLK_NONE) {
1017 DHD_TRACE(("%s: Request SD clk\n", __FUNCTION__));
1018 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
1020 #if !defined(NDISVER) || (NDISVER < 0x0630)
1022 if ((bus->sih->chip == BCM4334_CHIP_ID) && (bus->sih->chiprev == 2)) {
1023 SPINWAIT_SLEEP(sdioh_spinwait_sleep,
1024 (bcmsdh_gpioin(bus->sdh, GPIO_DEV_SRSTATE) != TRUE),
1025 GPIO_DEV_SRSTATE_TIMEOUT);
1027 if (bcmsdh_gpioin(bus->sdh, GPIO_DEV_SRSTATE) == FALSE) {
1028 DHD_ERROR(("ERROR: GPIO_DEV_SRSTATE still low!\n"));
1033 err = bcmsdh_sleep(bus->sdh, FALSE);
1034 if (SLPAUTO_ENAB(bus) && (err != 0)) {
1036 DHD_TRACE(("%s: Resync device sleep\n", __FUNCTION__));
1038 /* Toggle sleep to resync with host and device */
1039 err = bcmsdh_sleep(bus->sdh, TRUE);
1041 err = bcmsdh_sleep(bus->sdh, FALSE);
1045 DHD_ERROR(("%s: CMD14 exit failed again!\n", __FUNCTION__));
1047 /* Toggle sleep to resync with host and device */
1048 err = bcmsdh_sleep(bus->sdh, TRUE);
1050 err = bcmsdh_sleep(bus->sdh, FALSE);
1052 DHD_ERROR(("%s: CMD14 exit failed twice!\n", __FUNCTION__));
1053 DHD_ERROR(("%s: FATAL: Device non-response!\n",
1060 if (OOB_WAKEUP_ENAB(bus))
1062 #if !defined(NDISVER) || (NDISVER < 0x0630)
1063 err = bcmsdh_gpioout(bus->sdh, GPIO_DEV_WAKEUP, TRUE); /* GPIO_1 is on */
1064 #endif /* !defined(NDISVER) || (NDISVER < 0x0630) */
1067 err = dhdsdio_clk_kso_enab(bus, TRUE);
1070 } while ((err != 0) && (++retry < 3));
1073 DHD_ERROR(("ERROR: kso set failed retry: %d\n", retry));
1074 err = 0; /* continue anyway */
1076 #endif /* !USE_CMD14 */
1081 /* Wait for device ready during transition to wake-up */
1082 SPINWAIT_SLEEP(sdioh_spinwait_sleep,
1083 (((csr = dhdsdio_sleepcsr_get(bus)) &
1084 SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK) !=
1085 (SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK)), (20000));
1087 DHD_TRACE(("%s: ExitSleep sleepcsr: 0x%x\n", __FUNCTION__, csr));
1089 if (!(csr & SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK)) {
1090 DHD_ERROR(("%s:ERROR: ExitSleep device NOT Ready! 0x%x\n",
1091 __FUNCTION__, csr));
1092 err = BCME_NODEVICE;
1095 SPINWAIT_SLEEP(sdioh_spinwait_sleep,
1096 (((csr = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
1097 SBSDIO_FUNC1_CHIPCLKCSR, &err)) & SBSDIO_HT_AVAIL) !=
1098 (SBSDIO_HT_AVAIL)), (10000));
1100 DHD_TRACE(("%s: SBSDIO_FUNC1_CHIPCLKCSR : 0x%x\n", __FUNCTION__, csr));
1101 if (!err && ((csr & SBSDIO_HT_AVAIL) != SBSDIO_HT_AVAIL)) {
1102 DHD_ERROR(("%s:ERROR: device NOT Ready! 0x%x\n",
1103 __FUNCTION__, csr));
1104 err = BCME_NODEVICE;
1109 /* Update if successful */
1111 bus->kso = on ? FALSE : TRUE;
1113 DHD_ERROR(("%s: Sleep request failed: kso:%d on:%d err:%d\n",
1114 __FUNCTION__, bus->kso, on, err));
1115 if (!on && retry > 2)
1122 /* Turn backplane clock on or off */
1124 dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok)
1126 #define HT_AVAIL_ERROR_MAX 10
1127 static int ht_avail_error = 0;
1129 uint8 clkctl, clkreq, devctl;
1132 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1141 if (SLPAUTO_ENAB(bus)) {
1142 bus->clkstate = (on ? CLK_AVAIL : CLK_SDONLY);
1147 /* Request HT Avail */
1148 clkreq = bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ;
1152 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
1155 if (ht_avail_error < HT_AVAIL_ERROR_MAX) {
1156 DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err));
1159 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
1160 else if (ht_avail_error == HT_AVAIL_ERROR_MAX) {
1161 dhd_os_send_hang_message(bus->dhd);
1163 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) */
1170 /* Check current status */
1171 clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
1173 DHD_ERROR(("%s: HT Avail read error: %d\n", __FUNCTION__, err));
1177 #if !defined(OOB_INTR_ONLY)
1178 /* Go to pending and await interrupt if appropriate */
1179 if (!SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) {
1180 /* Allow only clock-available interrupt */
1181 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
1183 DHD_ERROR(("%s: Devctl access error setting CA: %d\n",
1184 __FUNCTION__, err));
1188 devctl |= SBSDIO_DEVCTL_CA_INT_ONLY;
1189 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
1190 DHD_INFO(("CLKCTL: set PENDING\n"));
1191 bus->clkstate = CLK_PENDING;
1194 #endif /* !defined (OOB_INTR_ONLY) */
1196 if (bus->clkstate == CLK_PENDING) {
1197 /* Cancel CA-only interrupt filter */
1198 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
1199 devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
1200 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
1204 /* Otherwise, wait here (polling) for HT Avail */
1205 if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
1206 SPINWAIT_SLEEP(sdioh_spinwait_sleep,
1207 ((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
1208 SBSDIO_FUNC1_CHIPCLKCSR, &err)),
1209 !SBSDIO_CLKAV(clkctl, bus->alp_only)), PMU_MAX_TRANSITION_DLY);
1212 DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err));
1215 if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
1216 DHD_ERROR(("%s: HT Avail timeout (%d): clkctl 0x%02x\n",
1217 __FUNCTION__, PMU_MAX_TRANSITION_DLY, clkctl));
1221 /* Mark clock available */
1222 bus->clkstate = CLK_AVAIL;
1223 DHD_INFO(("CLKCTL: turned ON\n"));
1225 #if defined(DHD_DEBUG)
1226 if (bus->alp_only == TRUE) {
1227 #if !defined(BCMLXSDMMC)
1228 if (!SBSDIO_ALPONLY(clkctl)) {
1229 DHD_ERROR(("%s: HT Clock, when ALP Only\n", __FUNCTION__));
1231 #endif /* !defined(BCMLXSDMMC) */
1233 if (SBSDIO_ALPONLY(clkctl)) {
1234 DHD_ERROR(("%s: HT Clock should be on.\n", __FUNCTION__));
1237 #endif /* defined (DHD_DEBUG) */
1239 bus->activity = TRUE;
1240 #ifdef DHD_USE_IDLECOUNT
1242 #endif /* DHD_USE_IDLECOUNT */
1246 if (bus->clkstate == CLK_PENDING) {
1247 /* Cancel CA-only interrupt filter */
1248 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
1249 devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
1250 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
1253 bus->clkstate = CLK_SDONLY;
1254 if (!SR_ENAB(bus)) {
1255 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
1256 DHD_INFO(("CLKCTL: turned OFF\n"));
1258 DHD_ERROR(("%s: Failed access turning clock off: %d\n",
1259 __FUNCTION__, err));
1267 /* Change idle/active SD state */
1269 dhdsdio_sdclk(dhd_bus_t *bus, bool on)
1274 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1277 if (bus->idleclock == DHD_IDLE_STOP) {
1278 /* Turn on clock and restore mode */
1280 err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0,
1281 &iovalue, sizeof(iovalue), TRUE);
1283 DHD_ERROR(("%s: error enabling sd_clock: %d\n",
1284 __FUNCTION__, err));
1288 iovalue = bus->sd_mode;
1289 err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
1290 &iovalue, sizeof(iovalue), TRUE);
1292 DHD_ERROR(("%s: error changing sd_mode: %d\n",
1293 __FUNCTION__, err));
1296 } else if (bus->idleclock != DHD_IDLE_ACTIVE) {
1297 /* Restore clock speed */
1298 iovalue = bus->sd_divisor;
1299 err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
1300 &iovalue, sizeof(iovalue), TRUE);
1302 DHD_ERROR(("%s: error restoring sd_divisor: %d\n",
1303 __FUNCTION__, err));
1307 bus->clkstate = CLK_SDONLY;
1309 /* Stop or slow the SD clock itself */
1310 if ((bus->sd_divisor == -1) || (bus->sd_mode == -1)) {
1311 DHD_TRACE(("%s: can't idle clock, divisor %d mode %d\n",
1312 __FUNCTION__, bus->sd_divisor, bus->sd_mode));
1315 if (bus->idleclock == DHD_IDLE_STOP) {
1317 /* Change to SD1 mode and turn off clock */
1319 err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
1320 &iovalue, sizeof(iovalue), TRUE);
1322 DHD_ERROR(("%s: error changing sd_clock: %d\n",
1323 __FUNCTION__, err));
1329 err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0,
1330 &iovalue, sizeof(iovalue), TRUE);
1332 DHD_ERROR(("%s: error disabling sd_clock: %d\n",
1333 __FUNCTION__, err));
1336 } else if (bus->idleclock != DHD_IDLE_ACTIVE) {
1337 /* Set divisor to idle value */
1338 iovalue = bus->idleclock;
1339 err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
1340 &iovalue, sizeof(iovalue), TRUE);
1342 DHD_ERROR(("%s: error changing sd_divisor: %d\n",
1343 __FUNCTION__, err));
1347 bus->clkstate = CLK_NONE;
1353 /* Transition SD and backplane clock readiness */
1355 dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok)
1359 uint oldstate = bus->clkstate;
1360 #endif /* DHD_DEBUG */
1362 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1364 /* Early exit if we're already there */
1365 if (bus->clkstate == target) {
1366 if (target == CLK_AVAIL) {
1367 dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
1368 bus->activity = TRUE;
1369 #ifdef DHD_USE_IDLECOUNT
1371 #endif /* DHD_USE_IDLECOUNT */
1378 /* Make sure SD clock is available */
1379 if (bus->clkstate == CLK_NONE)
1380 dhdsdio_sdclk(bus, TRUE);
1381 /* Now request HT Avail on the backplane */
1382 ret = dhdsdio_htclk(bus, TRUE, pendok);
1383 if (ret == BCME_OK) {
1384 dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
1385 bus->activity = TRUE;
1386 #ifdef DHD_USE_IDLECOUNT
1388 #endif /* DHD_USE_IDLECOUNT */
1393 /* Remove HT request, or bring up SD clock */
1394 if (bus->clkstate == CLK_NONE)
1395 ret = dhdsdio_sdclk(bus, TRUE);
1396 else if (bus->clkstate == CLK_AVAIL)
1397 ret = dhdsdio_htclk(bus, FALSE, FALSE);
1399 DHD_ERROR(("dhdsdio_clkctl: request for %d -> %d\n",
1400 bus->clkstate, target));
1401 if (ret == BCME_OK) {
1402 dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
1407 /* Make sure to remove HT request */
1408 if (bus->clkstate == CLK_AVAIL)
1409 ret = dhdsdio_htclk(bus, FALSE, FALSE);
1410 /* Now remove the SD clock */
1411 ret = dhdsdio_sdclk(bus, FALSE);
1413 if (dhd_console_ms == 0)
1414 #endif /* DHD_DEBUG */
1416 dhd_os_wd_timer(bus->dhd, 0);
1420 DHD_INFO(("dhdsdio_clkctl: %d -> %d\n", oldstate, bus->clkstate));
1421 #endif /* DHD_DEBUG */
1427 dhdsdio_bussleep(dhd_bus_t *bus, bool sleep)
1430 bcmsdh_info_t *sdh = bus->sdh;
1431 sdpcmd_regs_t *regs = bus->regs;
1434 DHD_INFO(("dhdsdio_bussleep: request %s (currently %s)\n",
1435 (sleep ? "SLEEP" : "WAKE"),
1436 (bus->sleeping ? "SLEEP" : "WAKE")));
1438 if (bus->dhd->hang_was_sent)
1441 /* Done if we're already in the requested state */
1442 if (sleep == bus->sleeping)
1445 /* Going to sleep: set the alarm and turn off the lights... */
1447 /* Don't sleep if something is pending */
1448 if (bus->dpc_sched || bus->rxskip || pktq_len(&bus->txq))
1452 if (!SLPAUTO_ENAB(bus)) {
1453 /* Disable SDIO interrupts (no longer interested) */
1454 bcmsdh_intr_disable(bus->sdh);
1456 /* Make sure the controller has the bus up */
1457 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
1459 /* Tell device to start using OOB wakeup */
1460 W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries);
1461 if (retries > retry_limit)
1462 DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
1464 /* Turn off our contribution to the HT clock request */
1465 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
1467 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
1468 SBSDIO_FORCE_HW_CLKREQ_OFF, NULL);
1470 /* Isolate the bus */
1471 if (bus->sih->chip != BCM4329_CHIP_ID &&
1472 bus->sih->chip != BCM4319_CHIP_ID) {
1473 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL,
1474 SBSDIO_DEVCTL_PADS_ISO, NULL);
1477 /* Leave interrupts enabled since device can exit sleep and
1480 err = dhdsdio_clk_devsleep_iovar(bus, TRUE /* sleep */);
1484 bus->sleeping = TRUE;
1485 wake_up(&bus->bus_sleep);
1487 /* Waking up: bus power up is ok, set local state */
1489 if (!SLPAUTO_ENAB(bus)) {
1490 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0, &err);
1492 /* Force pad isolation off if possible (in case power never toggled) */
1493 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, 0, NULL);
1496 /* Make sure the controller has the bus up */
1497 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
1499 /* Send misc interrupt to indicate OOB not needed */
1500 W_SDREG(0, ®s->tosbmailboxdata, retries);
1501 if (retries <= retry_limit)
1502 W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries);
1504 if (retries > retry_limit)
1505 DHD_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n"));
1507 /* Make sure we have SD bus access */
1508 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
1510 /* Enable interrupts again */
1511 if (bus->intr && (bus->dhd->busstate == DHD_BUS_DATA)) {
1512 bus->intdis = FALSE;
1513 bcmsdh_intr_enable(bus->sdh);
1516 err = dhdsdio_clk_devsleep_iovar(bus, FALSE /* wake */);
1521 bus->sleeping = FALSE;
1529 #if defined(OOB_INTR_ONLY)
1531 dhd_enable_oob_intr(struct dhd_bus *bus, bool enable)
1534 bcmsdh_enable_hw_oob_intr(bus->sdh, enable);
1536 sdpcmd_regs_t *regs = bus->regs;
1539 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
1540 if (enable == TRUE) {
1542 /* Tell device to start using OOB wakeup */
1543 W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries);
1544 if (retries > retry_limit)
1545 DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
1548 /* Send misc interrupt to indicate OOB not needed */
1549 W_SDREG(0, ®s->tosbmailboxdata, retries);
1550 if (retries <= retry_limit)
1551 W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries);
1554 /* Turn off our contribution to the HT clock request */
1555 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
1556 #endif /* !defined(HW_OOB) */
1561 dhd_bus_txdata(struct dhd_bus *bus, void *pkt)
1563 int ret = BCME_ERROR;
1566 #if defined(DHD_TX_DUMP)
1569 #endif /* DHD_TX_DUMP */
1571 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1573 osh = bus->dhd->osh;
1574 datalen = PKTLEN(osh, pkt);
1577 /* Push the test header if doing loopback */
1578 if (bus->ext_loop) {
1580 PKTPUSH(osh, pkt, SDPCM_TEST_HDRLEN);
1581 data = PKTDATA(osh, pkt);
1582 *data++ = SDPCM_TEST_ECHOREQ;
1583 *data++ = (uint8)bus->loopid++;
1584 *data++ = (datalen >> 0);
1585 *data++ = (datalen >> 8);
1586 datalen += SDPCM_TEST_HDRLEN;
1589 BCM_REFERENCE(datalen);
1592 #if defined(DHD_TX_DUMP)
1593 dump_data = PKTDATA(osh, pkt);
1594 dump_data += 4; /* skip 4 bytes header */
1595 protocol = (dump_data[12] << 8) | dump_data[13];
1597 if (protocol == ETHER_TYPE_802_1X) {
1598 DHD_ERROR(("ETHER_TYPE_802_1X [TX]: ver %d, type %d, replay %d\n",
1599 dump_data[14], dump_data[15], dump_data[30]));
1601 #endif /* DHD_TX_DUMP */
1603 #if defined(DHD_TX_DUMP) && defined(DHD_TX_FULL_DUMP)
1606 DHD_ERROR(("TX DUMP\n"));
1608 for (i = 0; i < (datalen - 4); i++) {
1609 DHD_ERROR(("%02X ", dump_data[i]));
1615 #endif /* DHD_TX_DUMP && DHD_TX_FULL_DUMP */
1617 prec = PRIO2PREC((PKTPRIO(pkt) & PRIOMASK));
1619 /* Check for existing queue, current flow-control, pending event, or pending clock */
1620 if (dhd_deferred_tx || bus->fcstate || pktq_len(&bus->txq) || bus->dpc_sched ||
1621 (!DATAOK(bus)) || (bus->flowcontrol & NBITVAL(prec)) ||
1622 (bus->clkstate != CLK_AVAIL)) {
1626 DHD_TRACE(("%s: deferring pktq len %d\n", __FUNCTION__, pktq_len(&bus->txq)));
1629 /* Priority based enq */
1630 dhd_os_sdlock_txq(bus->dhd);
1631 deq_ret = dhd_prec_enq(bus->dhd, &bus->txq, pkt, prec);
1632 dhd_os_sdunlock_txq(bus->dhd);
1635 #ifdef PROP_TXSTATUS
1636 if (DHD_PKTTAG_WLFCPKT(PKTTAG(pkt)) == 0)
1637 #endif /* PROP_TXSTATUS */
1639 #ifdef DHDTCPACK_SUPPRESS
1640 if (dhd_tcpack_check_xmit(bus->dhd, pkt) == BCME_ERROR) {
1641 DHD_ERROR(("%s %d: tcpack_suppress ERROR!!! Stop using\n",
1642 __FUNCTION__, __LINE__));
1643 dhd_tcpack_suppress_set(bus->dhd, TCPACK_SUP_OFF);
1645 #endif /* DHDTCPACK_SUPPRESS */
1646 dhd_txcomplete(bus->dhd, pkt, FALSE);
1647 PKTFREE(osh, pkt, TRUE);
1649 ret = BCME_NORESOURCE;
1653 dhd_os_sdlock_txq(bus->dhd);
1654 pkq_len = pktq_len(&bus->txq);
1655 dhd_os_sdunlock_txq(bus->dhd);
1656 if (pkq_len >= FCHI) {
1657 bool wlfc_enabled = FALSE;
1658 #ifdef PROP_TXSTATUS
1659 wlfc_enabled = (dhd_wlfc_flowcontrol(bus->dhd, ON, FALSE) !=
1662 if (!wlfc_enabled && dhd_doflow) {
1663 dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON);
1668 dhd_os_sdlock_txq(bus->dhd);
1669 if (pktq_plen(&bus->txq, prec) > qcount[prec])
1670 qcount[prec] = pktq_plen(&bus->txq, prec);
1671 dhd_os_sdunlock_txq(bus->dhd);
1674 /* Schedule DPC if needed to send queued packet(s) */
1675 if (dhd_deferred_tx && !bus->dpc_sched) {
1676 bus->dpc_sched = TRUE;
1677 dhd_sched_dpc(bus->dhd);
1680 int chan = SDPCM_DATA_CHANNEL;
1683 chan = (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL);
1685 /* Lock: we're about to use shared data/code (and SDIO) */
1686 dhd_os_sdlock(bus->dhd);
1688 /* Otherwise, send it now */
1690 /* Make sure back plane ht clk is on, no pending allowed */
1691 dhdsdio_clkctl(bus, CLK_AVAIL, TRUE);
1693 ret = dhdsdio_txpkt(bus, chan, &pkt, 1, TRUE);
1696 bus->dhd->tx_errors++;
1698 bus->dhd->dstats.tx_bytes += datalen;
1700 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
1701 bus->activity = FALSE;
1702 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
1705 dhd_os_sdunlock(bus->dhd);
1711 /* align packet data pointer and packet length to n-byte boundary, process packet headers,
1712 * a new packet may be allocated if there is not enough head and/or tail from for padding.
1713 * the caller is responsible for updating the glom size in the head packet (when glom is
1716 * pad_pkt_len: returns the length of extra padding needed from the padding packet, this parameter
1717 * is taken in tx glom mode only
1719 * new_pkt: out, pointer of the new packet allocated due to insufficient head room for alignment
1720 * padding, NULL if not needed, the caller is responsible for freeing the new packet
1722 * return: positive value - length of the packet, including head and tail padding
1723 * negative value - errors
1725 static int dhdsdio_txpkt_preprocess(dhd_bus_t *bus, void *pkt, int chan, int txseq,
1726 int prev_chain_total_len, bool last_chained_pkt,
1727 int *pad_pkt_len, void **new_pkt)
1734 int tail_padding = 0;
1736 uint32 swhdr_offset;
1737 bool alloc_new_pkt = FALSE;
1738 uint8 sdpcm_hdrlen = bus->txglom_enable ? SDPCM_HDRLEN_TXGLOM : SDPCM_HDRLEN;
1741 osh = bus->dhd->osh;
1743 #ifdef DHDTCPACK_SUPPRESS
1744 if (dhd_tcpack_check_xmit(bus->dhd, pkt) == BCME_ERROR) {
1745 DHD_ERROR(("%s %d: tcpack_suppress ERROR!!! Stop using it\n",
1746 __FUNCTION__, __LINE__));
1747 dhd_tcpack_suppress_set(bus->dhd, TCPACK_SUP_OFF);
1749 #endif /* DHDTCPACK_SUPPRESS */
1751 /* Add space for the SDPCM hardware/software headers */
1752 PKTPUSH(osh, pkt, sdpcm_hdrlen);
1753 ASSERT(ISALIGNED((uintptr)PKTDATA(osh, pkt), 2));
1755 frame = (uint8*)PKTDATA(osh, pkt);
1756 pkt_len = (uint16)PKTLEN(osh, pkt);
1759 frame = (uint8*)PKTDATA(osh, pkt);
1760 if (PKTLEN(osh, pkt) >= 100) {
1761 htsf_ts = (htsfts_t*) (frame + HTSF_HOSTOFFSET + 12);
1762 if (htsf_ts->magic == HTSFMAGIC) {
1763 htsf_ts->c20 = get_cycles();
1764 htsf_ts->t20 = dhd_get_htsf(bus->dhd->info, 0);
1767 #endif /* WLMEDIA_HTSF */
1769 if (PKTPRIO(pkt) < ARRAYSIZE(tx_packets))
1770 tx_packets[PKTPRIO(pkt)]++;
1771 #endif /* DHD_DEBUG */
1773 /* align the data pointer, allocate a new packet if there is not enough space (new
1774 * packet data pointer will be aligned thus no padding will be needed)
1776 head_padding = (ulong)frame % DHD_SDALIGN;
1777 if (PKTHEADROOM(osh, pkt) < head_padding) {
1779 alloc_new_pkt = TRUE;
1781 uint cur_chain_total_len;
1782 int chain_tail_padding = 0;
1784 /* All packets need to be aligned by DHD_SDALIGN */
1785 modulo = (pkt_len + head_padding) % DHD_SDALIGN;
1786 tail_padding = modulo > 0 ? (DHD_SDALIGN - modulo) : 0;
1788 /* Total pkt chain length needs to be aligned by block size,
1789 * unless it is a single pkt chain with total length less than one block size,
1790 * which we prefer sending by byte mode.
1792 * Do the chain alignment here if
1793 * 1. This is the last pkt of the chain of multiple pkts or a single pkt.
1794 * 2-1. This chain is of multiple pkts, or
1795 * 2-2. This is a single pkt whose size is longer than one block size.
1797 cur_chain_total_len = prev_chain_total_len +
1798 (head_padding + pkt_len + tail_padding);
1799 if (last_chained_pkt && bus->blocksize != 0 &&
1800 (cur_chain_total_len > (int)bus->blocksize || prev_chain_total_len > 0)) {
1801 modulo = cur_chain_total_len % bus->blocksize;
1802 chain_tail_padding = modulo > 0 ? (bus->blocksize - modulo) : 0;
1805 #ifdef DHDENABLE_TAILPAD
1806 if (PKTTAILROOM(osh, pkt) < tail_padding) {
1807 /* We don't have tail room to align by DHD_SDALIGN */
1808 alloc_new_pkt = TRUE;
1809 bus->tx_tailpad_pktget++;
1810 } else if (PKTTAILROOM(osh, pkt) < tail_padding + chain_tail_padding) {
1811 /* We have tail room for tail_padding of this pkt itself, but not for
1812 * total pkt chain alignment by block size.
1813 * Use the padding packet to avoid memory copy if applicable,
1814 * otherwise, just allocate a new pkt.
1817 *pad_pkt_len = chain_tail_padding;
1818 bus->tx_tailpad_chain++;
1820 alloc_new_pkt = TRUE;
1821 bus->tx_tailpad_pktget++;
1824 /* This last pkt's tailroom is sufficient to hold both tail_padding
1825 * of the pkt itself and chain_tail_padding of total pkt chain
1827 #endif /* DHDENABLE_TAILPAD */
1828 tail_padding += chain_tail_padding;
1831 DHD_INFO(("%s sdhdr len + orig_pkt_len %d h_pad %d t_pad %d pad_pkt_len %d\n",
1832 __FUNCTION__, pkt_len, head_padding, tail_padding, *pad_pkt_len));
1834 if (alloc_new_pkt) {
1839 ASSERT(*pad_pkt_len == 0);
1841 DHD_INFO(("%s allocating new packet for padding\n", __FUNCTION__));
1843 /* head pointer is aligned now, no padding needed */
1846 /* update the tail padding as it depends on the head padding, since a new packet is
1847 * allocated, the head padding is non longer needed and packet length is chagned
1850 cur_total_len = prev_chain_total_len + pkt_len;
1851 if (last_chained_pkt && bus->blocksize != 0 &&
1852 (cur_total_len > (int)bus->blocksize || prev_chain_total_len > 0)) {
1853 modulo = cur_total_len % bus->blocksize;
1854 tail_padding = modulo > 0 ? (bus->blocksize - modulo) : 0;
1857 modulo = pkt_len % DHD_SDALIGN;
1858 tail_padding = modulo > 0 ? (DHD_SDALIGN - modulo) : 0;
1861 newpkt_size = PKTLEN(osh, pkt) + bus->blocksize + DHD_SDALIGN;
1862 bus->dhd->tx_realloc++;
1863 tmp_pkt = PKTGET(osh, newpkt_size, TRUE);
1864 if (tmp_pkt == NULL) {
1865 DHD_ERROR(("failed to alloc new %d byte packet\n", newpkt_size));
1868 PKTALIGN(osh, tmp_pkt, PKTLEN(osh, pkt), DHD_SDALIGN);
1869 bcopy(PKTDATA(osh, pkt), PKTDATA(osh, tmp_pkt), PKTLEN(osh, pkt));
1875 PKTPUSH(osh, pkt, head_padding);
1877 frame = (uint8*)PKTDATA(osh, pkt);
1878 bzero(frame, head_padding + sdpcm_hdrlen);
1879 pkt_len = (uint16)PKTLEN(osh, pkt);
1881 /* the header has the followming format
1882 * 4-byte HW frame tag: length, ~length (for glom this is the total length)
1884 * 8-byte HW extesion flags (glom mode only) as the following:
1885 * 2-byte packet length, excluding HW tag and padding
1886 * 2-byte frame channel and frame flags (e.g. next frame following)
1887 * 2-byte header length
1888 * 2-byte tail padding size
1890 * 8-byte SW frame tags as the following
1891 * 4-byte flags: host tx seq, channel, data offset
1895 swhdr_offset = SDPCM_FRAMETAG_LEN;
1897 /* hardware frame tag:
1899 * in tx-glom mode, dongle only checks the hardware frame tag in the first
1900 * packet and sees it as the total lenght of the glom (including tail padding),
1901 * for each packet in the glom, the packet length needs to be updated, (see
1904 * in non tx-glom mode, PKTLEN still need to include tail padding as to be
1905 * referred to in sdioh_request_buffer(). The tail length will be excluded in
1906 * dhdsdio_txpkt_postprocess().
1908 *(uint16*)frame = (uint16)htol16(pkt_len);
1909 *(((uint16*)frame) + 1) = (uint16)htol16(~pkt_len);
1910 pkt_len += tail_padding;
1912 /* hardware extesion flags */
1913 if (bus->txglom_enable) {
1917 swhdr_offset += SDPCM_HWEXT_LEN;
1918 hwheader1 = (pkt_len - SDPCM_FRAMETAG_LEN - tail_padding) |
1919 (last_chained_pkt << 24);
1920 hwheader2 = (tail_padding) << 16;
1921 htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN);
1922 htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4);
1924 PKTSETLEN((osh), (pkt), (pkt_len));
1926 /* software frame tags */
1927 swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK)
1928 | (txseq % SDPCM_SEQUENCE_WRAP) |
1929 (((head_padding + sdpcm_hdrlen) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
1930 htol32_ua_store(swheader, frame + swhdr_offset);
1931 htol32_ua_store(0, frame + swhdr_offset + sizeof(swheader));
1936 static int dhdsdio_txpkt_postprocess(dhd_bus_t *bus, void *pkt)
1942 int swhdr_offset = SDPCM_FRAMETAG_LEN + (bus->txglom_enable ? SDPCM_HWEXT_LEN : 0);
1945 osh = bus->dhd->osh;
1947 /* restore pkt buffer pointer, but keeps the header pushed by dhd_prot_hdrpush */
1948 frame = (uint8*)PKTDATA(osh, pkt);
1950 DHD_INFO(("%s PKTLEN before postprocess %d",
1951 __FUNCTION__, PKTLEN(osh, pkt)));
1953 /* PKTLEN still includes tail_padding, so exclude it.
1954 * We shall have head_padding + original pkt_len for PKTLEN afterwards.
1956 if (bus->txglom_enable) {
1957 /* txglom pkts have tail_padding length in HW ext header */
1958 tail_padding = ltoh32_ua(frame + SDPCM_FRAMETAG_LEN + 4) >> 16;
1959 PKTSETLEN(osh, pkt, PKTLEN(osh, pkt) - tail_padding);
1960 DHD_INFO((" txglom pkt: tail_padding %d PKTLEN %d\n",
1961 tail_padding, PKTLEN(osh, pkt)));
1963 /* non-txglom pkts have head_padding + original pkt length in HW frame tag.
1964 * We cannot refer to this field for txglom pkts as the first pkt of the chain will
1965 * have the field for the total length of the chain.
1967 PKTSETLEN(osh, pkt, *(uint16*)frame);
1968 DHD_INFO((" non-txglom pkt: HW frame tag len %d after PKTLEN %d\n",
1969 *(uint16*)frame, PKTLEN(osh, pkt)));
1972 data_offset = ltoh32_ua(frame + swhdr_offset);
1973 data_offset = (data_offset & SDPCM_DOFFSET_MASK) >> SDPCM_DOFFSET_SHIFT;
1974 /* Get rid of sdpcm header + head_padding */
1975 PKTPULL(osh, pkt, data_offset);
1977 DHD_INFO(("%s data_offset %d, PKTLEN %d\n",
1978 __FUNCTION__, data_offset, PKTLEN(osh, pkt)));
1983 static int dhdsdio_txpkt(dhd_bus_t *bus, uint chan, void** pkts, int num_pkt, bool free_pkt)
1992 void *head_pkt = NULL;
1993 void *prev_pkt = NULL;
1994 int pad_pkt_len = 0;
1995 int new_pkt_num = 0;
1996 void *new_pkts[MAX_TX_PKTCHAIN_CNT];
1997 bool wlfc_enabled = FALSE;
1999 if (bus->dhd->dongle_reset)
2000 return BCME_NOTREADY;
2003 osh = bus->dhd->osh;
2004 /* init new_pkts[0] to make some compiler happy, not necessary as we check new_pkt_num */
2007 for (i = 0; i < num_pkt; i++) {
2010 void *new_pkt = NULL;
2014 last_pkt = (i == num_pkt - 1);
2015 pkt_len = dhdsdio_txpkt_preprocess(bus, pkt, chan, bus->tx_seq + i,
2016 total_len, last_pkt, &pad_pkt_len, &new_pkt);
2021 new_pkts[new_pkt_num++] = new_pkt;
2023 total_len += pkt_len;
2025 PKTSETNEXT(osh, pkt, NULL);
2026 /* insert the packet into the list */
2027 head_pkt ? PKTSETNEXT(osh, prev_pkt, pkt) : (head_pkt = pkt);
2032 /* Update the HW frame tag (total length) in the first pkt of the glom */
2033 if (bus->txglom_enable) {
2036 total_len += pad_pkt_len;
2037 frame = (uint8*)PKTDATA(osh, head_pkt);
2038 *(uint16*)frame = (uint16)htol16(total_len);
2039 *(((uint16*)frame) + 1) = (uint16)htol16(~total_len);
2043 #ifdef DHDENABLE_TAILPAD
2044 /* if a padding packet if needed, insert it to the end of the link list */
2046 PKTSETLEN(osh, bus->pad_pkt, pad_pkt_len);
2047 PKTSETNEXT(osh, pkt, bus->pad_pkt);
2049 #endif /* DHDENABLE_TAILPAD */
2051 /* dhd_bcmsdh_send_buf ignores the buffer pointer if he packet
2052 * parameter is not NULL, for non packet chian we pass NULL pkt pointer
2053 * so it will take the aligned length and buffer pointer.
2055 pkt_chain = PKTNEXT(osh, head_pkt) ? head_pkt : NULL;
2056 ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
2057 PKTDATA(osh, head_pkt), total_len, pkt_chain, NULL, NULL, TXRETRIES);
2059 bus->tx_seq = (bus->tx_seq + num_pkt) % SDPCM_SEQUENCE_WRAP;
2061 /* if a padding packet was needed, remove it from the link list as it not a data pkt */
2062 if (pad_pkt_len && pkt)
2063 PKTSETNEXT(osh, pkt, NULL);
2068 void *pkt_next = PKTNEXT(osh, pkt);
2069 PKTSETNEXT(osh, pkt, NULL);
2070 dhdsdio_txpkt_postprocess(bus, pkt);
2074 /* new packets might be allocated due to insufficient room for padding, but we
2075 * still have to indicate the original packets to upper layer
2077 for (i = 0; i < num_pkt; i++) {
2079 wlfc_enabled = FALSE;
2080 #ifdef PROP_TXSTATUS
2081 if (DHD_PKTTAG_WLFCPKT(PKTTAG(pkt))) {
2082 wlfc_enabled = (dhd_wlfc_txcomplete(bus->dhd, pkt, ret == 0) !=
2085 #endif /* PROP_TXSTATUS */
2086 if (!wlfc_enabled) {
2087 PKTSETNEXT(osh, pkt, NULL);
2088 dhd_txcomplete(bus->dhd, pkt, ret != 0);
2090 PKTFREE(osh, pkt, TRUE);
2094 for (i = 0; i < new_pkt_num; i++)
2095 PKTFREE(osh, new_pkts[i], TRUE);
2101 dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes)
2105 uint16 txpktqlen = 0;
2106 uint32 intstatus = 0;
2110 dhd_pub_t *dhd = bus->dhd;
2111 sdpcmd_regs_t *regs = bus->regs;
2113 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2115 if (!KSO_ENAB(bus)) {
2116 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
2117 return BCME_NODEVICE;
2121 tx_prec_map = ~bus->flowcontrol;
2122 for (cnt = 0; (cnt < maxframes) && DATAOK(bus);) {
2125 void *pkts[MAX_TX_PKTCHAIN_CNT];
2128 dhd_os_sdlock_txq(bus->dhd);
2129 if (bus->txglom_enable) {
2130 num_pkt = MIN((uint32)DATABUFCNT(bus), (uint32)bus->txglomsize);
2131 num_pkt = MIN(num_pkt, ARRAYSIZE(pkts));
2133 num_pkt = MIN(num_pkt, pktq_mlen(&bus->txq, tx_prec_map));
2134 for (i = 0; i < num_pkt; i++) {
2135 pkts[i] = pktq_mdeq(&bus->txq, ~bus->flowcontrol, &prec_out);
2137 DHD_ERROR(("%s: pktq_mlen non-zero when no pkt\n",
2143 datalen += PKTLEN(osh, pkts[i]);
2145 dhd_os_sdunlock_txq(bus->dhd);
2149 if (dhdsdio_txpkt(bus, SDPCM_DATA_CHANNEL, pkts, i, TRUE) != BCME_OK)
2152 dhd->dstats.tx_bytes += datalen;
2155 /* In poll mode, need to check for other events */
2156 if (!bus->intr && cnt)
2158 /* Check device status, signal pending interrupt */
2159 R_SDREG(intstatus, ®s->intstatus, retries);
2161 if (bcmsdh_regfail(bus->sdh))
2163 if (intstatus & bus->hostintmask)
2169 dhd_os_sdlock_txq(bus->dhd);
2170 txpktqlen = pktq_len(&bus->txq);
2171 dhd_os_sdunlock_txq(bus->dhd);
2173 /* Do flow-control if needed */
2174 if (dhd->up && (dhd->busstate == DHD_BUS_DATA) && (txpktqlen < FCLOW)) {
2175 bool wlfc_enabled = FALSE;
2176 #ifdef PROP_TXSTATUS
2177 wlfc_enabled = (dhd_wlfc_flowcontrol(dhd, OFF, TRUE) != WLFC_UNSUPPORTED);
2179 if (!wlfc_enabled && dhd_doflow && dhd->txoff) {
2180 dhd_txflowcontrol(dhd, ALL_INTERFACES, OFF);
2188 dhdsdio_sendpendctl(dhd_bus_t *bus)
2190 bcmsdh_info_t *sdh = bus->sdh;
2192 uint8* frame_seq = bus->ctrl_frame_buf + SDPCM_FRAMETAG_LEN;
2194 if (bus->txglom_enable)
2195 frame_seq += SDPCM_HWEXT_LEN;
2197 if (*frame_seq != bus->tx_seq) {
2198 DHD_INFO(("%s IOCTL frame seq lag detected!"
2199 " frm_seq:%d != bus->tx_seq:%d, corrected\n",
2200 __FUNCTION__, *frame_seq, bus->tx_seq));
2201 *frame_seq = bus->tx_seq;
2204 ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
2205 (uint8 *)bus->ctrl_frame_buf, (uint32)bus->ctrl_frame_len,
2206 NULL, NULL, NULL, 1);
2208 bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
2210 bus->ctrl_frame_stat = FALSE;
2211 dhd_wait_event_wakeup(bus->dhd);
2215 dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen)
2217 static int err_nodevice = 0;
2221 bcmsdh_info_t *sdh = bus->sdh;
2224 uint8 sdpcm_hdrlen = bus->txglom_enable ? SDPCM_HDRLEN_TXGLOM : SDPCM_HDRLEN;
2226 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2228 if (bus->dhd->dongle_reset)
2231 /* Back the pointer to make a room for bus header */
2232 frame = msg - sdpcm_hdrlen;
2233 len = (msglen += sdpcm_hdrlen);
2235 /* Add alignment padding (optional for ctl frames) */
2237 if ((doff = ((uintptr)frame % DHD_SDALIGN))) {
2241 bzero(frame, doff + sdpcm_hdrlen);
2243 ASSERT(doff < DHD_SDALIGN);
2245 doff += sdpcm_hdrlen;
2247 /* Round send length to next SDIO block */
2248 if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
2249 uint16 pad = bus->blocksize - (len % bus->blocksize);
2250 if ((pad <= bus->roundup) && (pad < bus->blocksize))
2252 } else if (len % DHD_SDALIGN) {
2253 len += DHD_SDALIGN - (len % DHD_SDALIGN);
2256 /* Satisfy length-alignment requirements */
2257 if (forcealign && (len & (ALIGNMENT - 1)))
2258 len = ROUNDUP(len, ALIGNMENT);
2260 ASSERT(ISALIGNED((uintptr)frame, 2));
2263 /* Need to lock here to protect txseq and SDIO tx calls */
2264 dhd_os_sdlock(bus->dhd);
2268 /* Make sure backplane clock is on */
2269 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
2271 /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
2272 *(uint16*)frame = htol16((uint16)msglen);
2273 *(((uint16*)frame) + 1) = htol16(~msglen);
2275 if (bus->txglom_enable) {
2276 uint32 hwheader1, hwheader2;
2277 /* Software tag: channel, sequence number, data offset */
2278 swheader = ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK)
2280 | ((doff << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
2281 htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN);
2282 htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN
2283 + SDPCM_HWEXT_LEN + sizeof(swheader));
2285 hwheader1 = (msglen - SDPCM_FRAMETAG_LEN) | (1 << 24);
2286 hwheader2 = (len - (msglen)) << 16;
2287 htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN);
2288 htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4);
2290 *(uint16*)frame = htol16(len);
2291 *(((uint16*)frame) + 1) = htol16(~(len));
2293 /* Software tag: channel, sequence number, data offset */
2294 swheader = ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK)
2295 | bus->tx_seq | ((doff << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
2296 htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN);
2297 htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
2299 if (!TXCTLOK(bus)) {
2300 DHD_INFO(("%s: No bus credit bus->tx_max %d, bus->tx_seq %d\n",
2301 __FUNCTION__, bus->tx_max, bus->tx_seq));
2302 bus->ctrl_frame_stat = TRUE;
2304 bus->ctrl_frame_buf = frame;
2305 bus->ctrl_frame_len = len;
2307 if (!bus->dpc_sched) {
2308 bus->dpc_sched = TRUE;
2309 dhd_sched_dpc(bus->dhd);
2311 if (bus->ctrl_frame_stat) {
2312 dhd_wait_for_event(bus->dhd, &bus->ctrl_frame_stat);
2315 if (bus->ctrl_frame_stat == FALSE) {
2316 DHD_INFO(("%s: ctrl_frame_stat == FALSE\n", __FUNCTION__));
2319 bus->dhd->txcnt_timeout++;
2320 if (!bus->dhd->hang_was_sent) {
2321 DHD_ERROR(("%s: ctrl_frame_stat == TRUE txcnt_timeout=%d\n",
2322 __FUNCTION__, bus->dhd->txcnt_timeout));
2325 bus->ctrl_frame_stat = FALSE;
2330 bus->dhd->txcnt_timeout = 0;
2331 bus->ctrl_frame_stat = TRUE;
2335 if (DHD_BYTES_ON() && DHD_CTL_ON()) {
2336 prhex("Tx Frame", frame, len);
2337 } else if (DHD_HDRS_ON()) {
2338 prhex("TxHdr", frame, MIN(len, 16));
2341 ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
2342 frame, len, NULL, NULL, NULL, TXRETRIES);
2344 bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
2346 bus->ctrl_frame_stat = FALSE;
2349 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
2350 bus->activity = FALSE;
2351 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
2354 dhd_os_sdunlock(bus->dhd);
2357 bus->dhd->tx_ctlerrs++;
2359 bus->dhd->tx_ctlpkts++;
2361 if (bus->dhd->txcnt_timeout >= MAX_CNTL_TX_TIMEOUT)
2364 if (ret == BCME_NODEVICE)
2369 return ret ? err_nodevice >= ERROR_BCME_NODEVICE_MAX ? -ETIMEDOUT : -EIO : 0;
2373 dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen)
2379 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2381 if (bus->dhd->dongle_reset)
2384 /* Wait until control frame is available */
2385 timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->rxlen, &pending);
2387 dhd_os_sdlock(bus->dhd);
2389 bcopy(bus->rxctl, msg, MIN(msglen, rxlen));
2391 dhd_os_sdunlock(bus->dhd);
2394 DHD_CTL(("%s: resumed on rxctl frame, got %d expected %d\n",
2395 __FUNCTION__, rxlen, msglen));
2396 } else if (timeleft == 0) {
2398 uint32 status, retry = 0;
2399 R_SDREG(status, &bus->regs->intstatus, retry);
2400 DHD_ERROR(("%s: resumed on timeout, INT status=0x%08X\n",
2401 __FUNCTION__, status));
2403 DHD_ERROR(("%s: resumed on timeout\n", __FUNCTION__));
2404 #endif /* DHD_DEBUG */
2406 dhd_os_sdlock(bus->dhd);
2407 dhdsdio_checkdied(bus, NULL, 0);
2408 dhd_os_sdunlock(bus->dhd);
2409 #endif /* DHD_DEBUG */
2410 } else if (pending == TRUE) {
2411 /* signal pending */
2412 DHD_ERROR(("%s: signal pending\n", __FUNCTION__));
2416 DHD_CTL(("%s: resumed for unknown reason?\n", __FUNCTION__));
2418 dhd_os_sdlock(bus->dhd);
2419 dhdsdio_checkdied(bus, NULL, 0);
2420 dhd_os_sdunlock(bus->dhd);
2421 #endif /* DHD_DEBUG */
2423 if (timeleft == 0) {
2425 bus->dhd->rxcnt_timeout++;
2426 DHD_ERROR(("%s: rxcnt_timeout=%d, rxlen=%d\n", __FUNCTION__,
2427 bus->dhd->rxcnt_timeout, rxlen));
2430 bus->dhd->rxcnt_timeout = 0;
2433 bus->dhd->rx_ctlpkts++;
2435 bus->dhd->rx_ctlerrs++;
2437 if (bus->dhd->rxcnt_timeout >= MAX_CNTL_RX_TIMEOUT)
2440 if (bus->dhd->dongle_trap_occured)
2443 return rxlen ? (int)rxlen : -EIO;
2459 #endif /* DHD_DEBUG */
2460 IOV_SET_DOWNLOAD_STATE,
2470 #if defined(USE_SDIOFIFO_IOVAR)
2473 #endif /* USE_SDIOFIFO_IOVAR */
2486 IOV_DONGLEISOLATION,
2500 const bcm_iovar_t dhdsdio_iovars[] = {
2501 {"intr", IOV_INTR, 0, IOVT_BOOL, 0 },
2502 {"sleep", IOV_SLEEP, 0, IOVT_BOOL, 0 },
2503 {"pollrate", IOV_POLLRATE, 0, IOVT_UINT32, 0 },
2504 {"idletime", IOV_IDLETIME, 0, IOVT_INT32, 0 },
2505 {"idleclock", IOV_IDLECLOCK, 0, IOVT_INT32, 0 },
2506 {"sd1idle", IOV_SD1IDLE, 0, IOVT_BOOL, 0 },
2507 {"membytes", IOV_MEMBYTES, 0, IOVT_BUFFER, 2 * sizeof(int) },
2508 {"ramsize", IOV_RAMSIZE, 0, IOVT_UINT32, 0 },
2509 {"ramstart", IOV_RAMSTART, 0, IOVT_UINT32, 0 },
2510 {"dwnldstate", IOV_SET_DOWNLOAD_STATE, 0, IOVT_BOOL, 0 },
2511 {"socram_state", IOV_SOCRAM_STATE, 0, IOVT_BOOL, 0 },
2512 {"vars", IOV_VARS, 0, IOVT_BUFFER, 0 },
2513 {"sdiod_drive", IOV_SDIOD_DRIVE, 0, IOVT_UINT32, 0 },
2514 {"readahead", IOV_READAHEAD, 0, IOVT_BOOL, 0 },
2515 {"sdrxchain", IOV_SDRXCHAIN, 0, IOVT_BOOL, 0 },
2516 {"alignctl", IOV_ALIGNCTL, 0, IOVT_BOOL, 0 },
2517 {"sdalign", IOV_SDALIGN, 0, IOVT_BOOL, 0 },
2518 {"devreset", IOV_DEVRESET, 0, IOVT_BOOL, 0 },
2520 {"sdreg", IOV_SDREG, 0, IOVT_BUFFER, sizeof(sdreg_t) },
2521 {"sbreg", IOV_SBREG, 0, IOVT_BUFFER, sizeof(sdreg_t) },
2522 {"sd_cis", IOV_SDCIS, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN },
2523 {"forcealign", IOV_FORCEEVEN, 0, IOVT_BOOL, 0 },
2524 {"txbound", IOV_TXBOUND, 0, IOVT_UINT32, 0 },
2525 {"rxbound", IOV_RXBOUND, 0, IOVT_UINT32, 0 },
2526 {"txminmax", IOV_TXMINMAX, 0, IOVT_UINT32, 0 },
2527 {"cpu", IOV_CPU, 0, IOVT_BOOL, 0 },
2529 {"checkdied", IOV_CHECKDIED, 0, IOVT_BUFFER, 0 },
2530 {"serial", IOV_SERIALCONS, 0, IOVT_UINT32, 0 },
2531 #endif /* DHD_DEBUG */
2532 #endif /* DHD_DEBUG */
2534 {"extloop", IOV_EXTLOOP, 0, IOVT_BOOL, 0 },
2535 {"pktgen", IOV_PKTGEN, 0, IOVT_BUFFER, sizeof(dhd_pktgen_t) },
2537 #if defined(USE_SDIOFIFO_IOVAR)
2538 {"watermark", IOV_WATERMARK, 0, IOVT_UINT32, 0 },
2539 {"mesbusyctrl", IOV_MESBUSYCTRL, 0, IOVT_UINT32, 0 },
2540 #endif /* USE_SDIOFIFO_IOVAR */
2541 {"devcap", IOV_DEVCAP, 0, IOVT_UINT32, 0 },
2542 {"dngl_isolation", IOV_DONGLEISOLATION, 0, IOVT_UINT32, 0 },
2543 {"kso", IOV_KSO, 0, IOVT_UINT32, 0 },
2544 {"devsleep", IOV_DEVSLEEP, 0, IOVT_UINT32, 0 },
2546 {"fwpath", IOV_FWPATH, 0, IOVT_BUFFER, 0 },
2548 {"txglomsize", IOV_TXGLOMSIZE, 0, IOVT_UINT32, 0 },
2549 {"fw_hang_report", IOV_HANGREPORT, 0, IOVT_BOOL, 0 },
2550 {"txinrx_thres", IOV_TXINRX_THRES, 0, IOVT_INT32, 0 },
2555 dhd_dump_pct(struct bcmstrbuf *strbuf, char *desc, uint num, uint div)
2560 bcm_bprintf(strbuf, "%s N/A", desc);
2563 q2 = (100 * (num - (q1 * div))) / div;
2564 bcm_bprintf(strbuf, "%s %d.%02d", desc, q1, q2);
2569 dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf)
2571 dhd_bus_t *bus = dhdp->bus;
2573 bcm_bprintf(strbuf, "Bus SDIO structure:\n");
2574 bcm_bprintf(strbuf, "hostintmask 0x%08x intstatus 0x%08x sdpcm_ver %d\n",
2575 bus->hostintmask, bus->intstatus, bus->sdpcm_ver);
2576 bcm_bprintf(strbuf, "fcstate %d qlen %u tx_seq %d, max %d, rxskip %d rxlen %u rx_seq %d\n",
2577 bus->fcstate, pktq_len(&bus->txq), bus->tx_seq, bus->tx_max, bus->rxskip,
2578 bus->rxlen, bus->rx_seq);
2579 bcm_bprintf(strbuf, "intr %d intrcount %u lastintrs %u spurious %u\n",
2580 bus->intr, bus->intrcount, bus->lastintrs, bus->spurious);
2581 bcm_bprintf(strbuf, "pollrate %u pollcnt %u regfails %u\n",
2582 bus->pollrate, bus->pollcnt, bus->regfails);
2584 bcm_bprintf(strbuf, "\nAdditional counters:\n");
2585 #ifdef DHDENABLE_TAILPAD
2586 bcm_bprintf(strbuf, "tx_tailpad_chain %u tx_tailpad_pktget %u\n",
2587 bus->tx_tailpad_chain, bus->tx_tailpad_pktget);
2588 #endif /* DHDENABLE_TAILPAD */
2589 bcm_bprintf(strbuf, "tx_sderrs %u fcqueued %u rxrtx %u rx_toolong %u rxc_errors %u\n",
2590 bus->tx_sderrs, bus->fcqueued, bus->rxrtx, bus->rx_toolong,
2592 bcm_bprintf(strbuf, "rx_hdrfail %u badhdr %u badseq %u\n",
2593 bus->rx_hdrfail, bus->rx_badhdr, bus->rx_badseq);
2594 bcm_bprintf(strbuf, "fc_rcvd %u, fc_xoff %u, fc_xon %u\n",
2595 bus->fc_rcvd, bus->fc_xoff, bus->fc_xon);
2596 bcm_bprintf(strbuf, "rxglomfail %u, rxglomframes %u, rxglompkts %u\n",
2597 bus->rxglomfail, bus->rxglomframes, bus->rxglompkts);
2598 bcm_bprintf(strbuf, "f2rx (hdrs/data) %u (%u/%u), f2tx %u f1regs %u\n",
2599 (bus->f2rxhdrs + bus->f2rxdata), bus->f2rxhdrs, bus->f2rxdata,
2600 bus->f2txdata, bus->f1regdata);
2602 dhd_dump_pct(strbuf, "\nRx: pkts/f2rd", bus->dhd->rx_packets,
2603 (bus->f2rxhdrs + bus->f2rxdata));
2604 dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->rx_packets, bus->f1regdata);
2605 dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->rx_packets,
2606 (bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata));
2607 dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->rx_packets, bus->intrcount);
2608 bcm_bprintf(strbuf, "\n");
2610 dhd_dump_pct(strbuf, "Rx: glom pct", (100 * bus->rxglompkts),
2611 bus->dhd->rx_packets);
2612 dhd_dump_pct(strbuf, ", pkts/glom", bus->rxglompkts, bus->rxglomframes);
2613 bcm_bprintf(strbuf, "\n");
2615 dhd_dump_pct(strbuf, "Tx: pkts/f2wr", bus->dhd->tx_packets, bus->f2txdata);
2616 dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->tx_packets, bus->f1regdata);
2617 dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->tx_packets,
2618 (bus->f2txdata + bus->f1regdata));
2619 dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->tx_packets, bus->intrcount);
2620 bcm_bprintf(strbuf, "\n");
2622 dhd_dump_pct(strbuf, "Total: pkts/f2rw",
2623 (bus->dhd->tx_packets + bus->dhd->rx_packets),
2624 (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata));
2625 dhd_dump_pct(strbuf, ", pkts/f1sd",
2626 (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->f1regdata);
2627 dhd_dump_pct(strbuf, ", pkts/sd",
2628 (bus->dhd->tx_packets + bus->dhd->rx_packets),
2629 (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata));
2630 dhd_dump_pct(strbuf, ", pkts/int",
2631 (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->intrcount);
2632 bcm_bprintf(strbuf, "\n\n");
2636 if (bus->pktgen_count) {
2637 bcm_bprintf(strbuf, "pktgen config and count:\n");
2638 bcm_bprintf(strbuf, "freq %u count %u print %u total %u min %u len %u\n",
2639 bus->pktgen_freq, bus->pktgen_count, bus->pktgen_print,
2640 bus->pktgen_total, bus->pktgen_minlen, bus->pktgen_maxlen);
2641 bcm_bprintf(strbuf, "send attempts %u rcvd %u fail %u\n",
2642 bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail);
2646 bcm_bprintf(strbuf, "dpc_sched %d host interrupt%spending\n",
2647 bus->dpc_sched, (bcmsdh_intr_pending(bus->sdh) ? " " : " not "));
2648 bcm_bprintf(strbuf, "blocksize %u roundup %u\n", bus->blocksize, bus->roundup);
2649 #endif /* DHD_DEBUG */
2650 bcm_bprintf(strbuf, "clkstate %d activity %d idletime %d idlecount %d sleeping %d\n",
2651 bus->clkstate, bus->activity, bus->idletime, bus->idlecount, bus->sleeping);
2655 dhd_bus_clearcounts(dhd_pub_t *dhdp)
2657 dhd_bus_t *bus = (dhd_bus_t *)dhdp->bus;
2659 bus->intrcount = bus->lastintrs = bus->spurious = bus->regfails = 0;
2660 bus->rxrtx = bus->rx_toolong = bus->rxc_errors = 0;
2661 bus->rx_hdrfail = bus->rx_badhdr = bus->rx_badseq = 0;
2662 #ifdef DHDENABLE_TAILPAD
2663 bus->tx_tailpad_chain = bus->tx_tailpad_pktget = 0;
2664 #endif /* DHDENABLE_TAILPAD */
2665 bus->tx_sderrs = bus->fc_rcvd = bus->fc_xoff = bus->fc_xon = 0;
2666 bus->rxglomfail = bus->rxglomframes = bus->rxglompkts = 0;
2667 bus->f2rxhdrs = bus->f2rxdata = bus->f2txdata = bus->f1regdata = 0;
2672 dhdsdio_pktgen_get(dhd_bus_t *bus, uint8 *arg)
2674 dhd_pktgen_t pktgen;
2676 pktgen.version = DHD_PKTGEN_VERSION;
2677 pktgen.freq = bus->pktgen_freq;
2678 pktgen.count = bus->pktgen_count;
2679 pktgen.print = bus->pktgen_print;
2680 pktgen.total = bus->pktgen_total;
2681 pktgen.minlen = bus->pktgen_minlen;
2682 pktgen.maxlen = bus->pktgen_maxlen;
2683 pktgen.numsent = bus->pktgen_sent;
2684 pktgen.numrcvd = bus->pktgen_rcvd;
2685 pktgen.numfail = bus->pktgen_fail;
2686 pktgen.mode = bus->pktgen_mode;
2687 pktgen.stop = bus->pktgen_stop;
2689 bcopy(&pktgen, arg, sizeof(pktgen));
2695 dhdsdio_pktgen_set(dhd_bus_t *bus, uint8 *arg)
2697 dhd_pktgen_t pktgen;
2698 uint oldcnt, oldmode;
2700 bcopy(arg, &pktgen, sizeof(pktgen));
2701 if (pktgen.version != DHD_PKTGEN_VERSION)
2704 oldcnt = bus->pktgen_count;
2705 oldmode = bus->pktgen_mode;
2707 bus->pktgen_freq = pktgen.freq;
2708 bus->pktgen_count = pktgen.count;
2709 bus->pktgen_print = pktgen.print;
2710 bus->pktgen_total = pktgen.total;
2711 bus->pktgen_minlen = pktgen.minlen;
2712 bus->pktgen_maxlen = pktgen.maxlen;
2713 bus->pktgen_mode = pktgen.mode;
2714 bus->pktgen_stop = pktgen.stop;
2716 bus->pktgen_tick = bus->pktgen_ptick = 0;
2717 bus->pktgen_prev_time = jiffies;
2718 bus->pktgen_len = MAX(bus->pktgen_len, bus->pktgen_minlen);
2719 bus->pktgen_len = MIN(bus->pktgen_len, bus->pktgen_maxlen);
2721 /* Clear counts for a new pktgen (mode change, or was stopped) */
2722 if (bus->pktgen_count && (!oldcnt || oldmode != bus->pktgen_mode)) {
2723 bus->pktgen_sent = bus->pktgen_prev_sent = bus->pktgen_rcvd = 0;
2724 bus->pktgen_prev_rcvd = bus->pktgen_fail = 0;
2732 dhdsdio_devram_remap(dhd_bus_t *bus, bool val)
2734 uint8 enable, protect, remap;
2736 si_socdevram(bus->sih, FALSE, &enable, &protect, &remap);
2737 remap = val ? TRUE : FALSE;
2738 si_socdevram(bus->sih, TRUE, &enable, &protect, &remap);
2742 dhdsdio_membytes(dhd_bus_t *bus, bool write, uint32 address, uint8 *data, uint size)
2748 /* In remap mode, adjust address beyond socram and redirect
2749 * to devram at SOCDEVRAM_BP_ADDR since remap address > orig_ramsize
2750 * is not backplane accessible
2752 if (REMAP_ENAB(bus) && REMAP_ISADDR(bus, address)) {
2753 address -= bus->orig_ramsize;
2754 address += SOCDEVRAM_BP_ADDR;
2757 /* Determine initial transfer parameters */
2758 sdaddr = address & SBSDIO_SB_OFT_ADDR_MASK;
2759 if ((sdaddr + size) & SBSDIO_SBWINDOW_MASK)
2760 dsize = (SBSDIO_SB_OFT_ADDR_LIMIT - sdaddr);
2764 /* Set the backplane window to include the start address */
2765 if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) {
2766 DHD_ERROR(("%s: window change failed\n", __FUNCTION__));
2770 /* Do the transfer(s) */
2772 DHD_INFO(("%s: %s %d bytes at offset 0x%08x in window 0x%08x\n",
2773 __FUNCTION__, (write ? "write" : "read"), dsize, sdaddr,
2774 (address & SBSDIO_SBWINDOW_MASK)));
2775 if ((bcmerror = bcmsdh_rwdata(bus->sdh, write, sdaddr, data, dsize))) {
2776 DHD_ERROR(("%s: membytes transfer failed\n", __FUNCTION__));
2780 /* Adjust for next transfer (if any) */
2781 if ((size -= dsize)) {
2784 if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) {
2785 DHD_ERROR(("%s: window change failed\n", __FUNCTION__));
2789 dsize = MIN(SBSDIO_SB_OFT_ADDR_LIMIT, size);
2795 /* Return the window to backplane enumeration space for core access */
2796 if (dhdsdio_set_siaddr_window(bus, bcmsdh_cur_sbwad(bus->sdh))) {
2797 DHD_ERROR(("%s: FAILED to set window back to 0x%x\n", __FUNCTION__,
2798 bcmsdh_cur_sbwad(bus->sdh)));
2806 dhdsdio_readshared(dhd_bus_t *bus, sdpcm_shared_t *sh)
2812 if (CHIPID(bus->sih->chip) == BCM43430_CHIP_ID && !dhdsdio_sr_cap(bus))
2815 shaddr = bus->dongle_ram_base + bus->ramsize - 4;
2818 /* Read last word in memory to determine address of sdpcm_shared structure */
2819 if ((rv = dhdsdio_membytes(bus, FALSE, shaddr, (uint8 *)&addr, 4)) < 0)
2822 addr = ltoh32(addr);
2824 DHD_INFO(("sdpcm_shared address 0x%08X\n", addr));
2827 * Check if addr is valid.
2828 * NVRAM length at the end of memory should have been overwritten.
2830 if (addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff)) {
2831 if ((bus->srmemsize > 0) && (i++ == 0)) {
2832 shaddr -= bus->srmemsize;
2834 DHD_ERROR(("%s: address (0x%08x) of sdpcm_shared invalid\n",
2835 __FUNCTION__, addr));
2842 /* Read hndrte_shared structure */
2843 if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)sh, sizeof(sdpcm_shared_t))) < 0)
2847 sh->flags = ltoh32(sh->flags);
2848 sh->trap_addr = ltoh32(sh->trap_addr);
2849 sh->assert_exp_addr = ltoh32(sh->assert_exp_addr);
2850 sh->assert_file_addr = ltoh32(sh->assert_file_addr);
2851 sh->assert_line = ltoh32(sh->assert_line);
2852 sh->console_addr = ltoh32(sh->console_addr);
2853 sh->msgtrace_addr = ltoh32(sh->msgtrace_addr);
2855 if ((sh->flags & SDPCM_SHARED_VERSION_MASK) == 3 && SDPCM_SHARED_VERSION == 1)
2858 if ((sh->flags & SDPCM_SHARED_VERSION_MASK) != SDPCM_SHARED_VERSION) {
2859 DHD_ERROR(("%s: sdpcm_shared version %d in dhd "
2860 "is different than sdpcm_shared version %d in dongle\n",
2861 __FUNCTION__, SDPCM_SHARED_VERSION,
2862 sh->flags & SDPCM_SHARED_VERSION_MASK));
2869 #define CONSOLE_LINE_MAX 192
2872 dhdsdio_readconsole(dhd_bus_t *bus)
2874 dhd_console_t *c = &bus->console;
2875 uint8 line[CONSOLE_LINE_MAX], ch;
2876 uint32 n, idx, addr;
2879 /* Don't do anything until FWREADY updates console address */
2880 if (bus->console_addr == 0)
2886 /* Read console log struct */
2887 addr = bus->console_addr + OFFSETOF(hnd_cons_t, log);
2888 if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)&c->log, sizeof(c->log))) < 0)
2891 /* Allocate console buffer (one time only) */
2892 if (c->buf == NULL) {
2893 c->bufsize = ltoh32(c->log.buf_size);
2894 if ((c->buf = MALLOC(bus->dhd->osh, c->bufsize)) == NULL)
2898 idx = ltoh32(c->log.idx);
2900 /* Protect against corrupt value */
2901 if (idx > c->bufsize)
2904 /* Skip reading the console buffer if the index pointer has not moved */
2908 /* Read the console buffer */
2909 addr = ltoh32(c->log.buf);
2910 if ((rv = dhdsdio_membytes(bus, FALSE, addr, c->buf, c->bufsize)) < 0)
2913 while (c->last != idx) {
2914 for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) {
2915 if (c->last == idx) {
2916 /* This would output a partial line. Instead, back up
2917 * the buffer pointer and output this line next time around.
2922 c->last = c->bufsize - n;
2925 ch = c->buf[c->last];
2926 c->last = (c->last + 1) % c->bufsize;
2933 if (line[n - 1] == '\r')
2936 printf("CONSOLE: %s\n", line);
2937 #ifdef LOG_INTO_TCPDUMP
2938 dhd_sendup_log(bus->dhd, line, n);
2939 #endif /* LOG_INTO_TCPDUMP */
2948 dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size)
2952 char *mbuffer = NULL;
2953 char *console_buffer = NULL;
2954 uint maxstrlen = 256;
2957 sdpcm_shared_t sdpcm_shared;
2958 struct bcmstrbuf strbuf;
2959 uint32 console_ptr, console_size, console_index;
2960 uint8 line[CONSOLE_LINE_MAX], ch;
2964 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2966 if (DHD_NOCHECKDIED_ON())
2971 * Called after a rx ctrl timeout. "data" is NULL.
2972 * allocate memory to trace the trap or assert.
2975 mbuffer = data = MALLOC(bus->dhd->osh, msize);
2976 if (mbuffer == NULL) {
2977 DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, msize));
2978 bcmerror = BCME_NOMEM;
2983 if ((str = MALLOC(bus->dhd->osh, maxstrlen)) == NULL) {
2984 DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, maxstrlen));
2985 bcmerror = BCME_NOMEM;
2989 if ((bcmerror = dhdsdio_readshared(bus, &sdpcm_shared)) < 0)
2992 bcm_binit(&strbuf, data, size);
2994 bcm_bprintf(&strbuf, "msgtrace address : 0x%08X\nconsole address : 0x%08X\n",
2995 sdpcm_shared.msgtrace_addr, sdpcm_shared.console_addr);
2997 if ((sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT) == 0) {
2998 /* NOTE: Misspelled assert is intentional - DO NOT FIX.
2999 * (Avoids conflict with real asserts for programmatic parsing of output.)
3001 bcm_bprintf(&strbuf, "Assrt not built in dongle\n");
3004 if ((sdpcm_shared.flags & (SDPCM_SHARED_ASSERT|SDPCM_SHARED_TRAP)) == 0) {
3005 /* NOTE: Misspelled assert is intentional - DO NOT FIX.
3006 * (Avoids conflict with real asserts for programmatic parsing of output.)
3008 bcm_bprintf(&strbuf, "No trap%s in dongle",
3009 (sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT)
3012 if (sdpcm_shared.flags & SDPCM_SHARED_ASSERT) {
3013 /* Download assert */
3014 bcm_bprintf(&strbuf, "Dongle assert");
3015 if (sdpcm_shared.assert_exp_addr != 0) {
3017 if ((bcmerror = dhdsdio_membytes(bus, FALSE,
3018 sdpcm_shared.assert_exp_addr,
3019 (uint8 *)str, maxstrlen)) < 0)
3022 str[maxstrlen - 1] = '\0';
3023 bcm_bprintf(&strbuf, " expr \"%s\"", str);
3026 if (sdpcm_shared.assert_file_addr != 0) {
3028 if ((bcmerror = dhdsdio_membytes(bus, FALSE,
3029 sdpcm_shared.assert_file_addr,
3030 (uint8 *)str, maxstrlen)) < 0)
3033 str[maxstrlen - 1] = '\0';
3034 bcm_bprintf(&strbuf, " file \"%s\"", str);
3037 bcm_bprintf(&strbuf, " line %d ", sdpcm_shared.assert_line);
3040 if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) {
3041 bus->dhd->dongle_trap_occured = TRUE;
3042 if ((bcmerror = dhdsdio_membytes(bus, FALSE,
3043 sdpcm_shared.trap_addr,
3044 (uint8*)&tr, sizeof(trap_t))) < 0)
3047 bcm_bprintf(&strbuf,
3048 "Dongle trap type 0x%x @ epc 0x%x, cpsr 0x%x, spsr 0x%x, sp 0x%x,"
3049 "lp 0x%x, rpc 0x%x Trap offset 0x%x, "
3050 "r0 0x%x, r1 0x%x, r2 0x%x, r3 0x%x, "
3051 "r4 0x%x, r5 0x%x, r6 0x%x, r7 0x%x\n\n",
3052 ltoh32(tr.type), ltoh32(tr.epc), ltoh32(tr.cpsr), ltoh32(tr.spsr),
3053 ltoh32(tr.r13), ltoh32(tr.r14), ltoh32(tr.pc),
3054 ltoh32(sdpcm_shared.trap_addr),
3055 ltoh32(tr.r0), ltoh32(tr.r1), ltoh32(tr.r2), ltoh32(tr.r3),
3056 ltoh32(tr.r4), ltoh32(tr.r5), ltoh32(tr.r6), ltoh32(tr.r7));
3058 addr = sdpcm_shared.console_addr + OFFSETOF(hnd_cons_t, log);
3059 if ((rv = dhdsdio_membytes(bus, FALSE, addr,
3060 (uint8 *)&console_ptr, sizeof(console_ptr))) < 0)
3063 addr = sdpcm_shared.console_addr + OFFSETOF(hnd_cons_t, log.buf_size);
3064 if ((rv = dhdsdio_membytes(bus, FALSE, addr,
3065 (uint8 *)&console_size, sizeof(console_size))) < 0)
3068 addr = sdpcm_shared.console_addr + OFFSETOF(hnd_cons_t, log.idx);
3069 if ((rv = dhdsdio_membytes(bus, FALSE, addr,
3070 (uint8 *)&console_index, sizeof(console_index))) < 0)
3073 console_ptr = ltoh32(console_ptr);
3074 console_size = ltoh32(console_size);
3075 console_index = ltoh32(console_index);
3077 if (console_size > CONSOLE_BUFFER_MAX ||
3078 !(console_buffer = MALLOC(bus->dhd->osh, console_size)))
3081 if ((rv = dhdsdio_membytes(bus, FALSE, console_ptr,
3082 (uint8 *)console_buffer, console_size)) < 0)
3085 for (i = 0, n = 0; i < console_size; i += n + 1) {
3086 for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) {
3087 ch = console_buffer[(console_index + i + n) % console_size];
3095 if (line[n - 1] == '\r')
3098 /* Don't use DHD_ERROR macro since we print
3099 * a lot of information quickly. The macro
3100 * will truncate a lot of the printfs
3103 if (dhd_msg_level & DHD_ERROR_VAL)
3104 printf("CONSOLE: %s\n", line);
3111 if (sdpcm_shared.flags & (SDPCM_SHARED_ASSERT | SDPCM_SHARED_TRAP)) {
3112 DHD_ERROR(("%s: %s\n", __FUNCTION__, strbuf.origbuf));
3118 MFREE(bus->dhd->osh, mbuffer, msize);
3120 MFREE(bus->dhd->osh, str, maxstrlen);
3122 MFREE(bus->dhd->osh, console_buffer, console_size);
3126 #endif /* #ifdef DHD_DEBUG */
3130 dhdsdio_downloadvars(dhd_bus_t *bus, void *arg, int len)
3132 int bcmerror = BCME_OK;
3134 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3136 /* Basic sanity checks */
3138 bcmerror = BCME_NOTDOWN;
3142 bcmerror = BCME_BUFTOOSHORT;
3146 /* Free the old ones and replace with passed variables */
3148 MFREE(bus->dhd->osh, bus->vars, bus->varsz);
3150 bus->vars = MALLOC(bus->dhd->osh, len);
3151 bus->varsz = bus->vars ? len : 0;
3152 if (bus->vars == NULL) {
3153 bcmerror = BCME_NOMEM;
3157 /* Copy the passed variables, which should include the terminating double-null */
3158 bcopy(arg, bus->vars, bus->varsz);
3165 #define CC_PLL_CHIPCTRL_SERIAL_ENAB (1 << 24)
3166 #define CC_CHIPCTRL_JTAG_SEL (1 << 3)
3167 #define CC_CHIPCTRL_GPIO_SEL (0x3)
3168 #define CC_PLL_CHIPCTRL_SERIAL_ENAB_4334 (1 << 28)
3171 dhd_serialconsole(dhd_bus_t *bus, bool set, bool enable, int *bcmerror)
3174 uint32 addr, data, uart_enab = 0;
3175 uint32 jtag_sel = CC_CHIPCTRL_JTAG_SEL;
3176 uint32 gpio_sel = CC_CHIPCTRL_GPIO_SEL;
3178 addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr);
3179 data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data);
3182 bcmsdh_reg_write(bus->sdh, addr, 4, 1);
3183 if (bcmsdh_regfail(bus->sdh)) {
3184 *bcmerror = BCME_SDIO_ERROR;
3187 int_val = bcmsdh_reg_read(bus->sdh, data, 4);
3188 if (bcmsdh_regfail(bus->sdh)) {
3189 *bcmerror = BCME_SDIO_ERROR;
3192 if (bus->sih->chip == BCM4330_CHIP_ID) {
3193 uart_enab = CC_PLL_CHIPCTRL_SERIAL_ENAB;
3195 else if (bus->sih->chip == BCM4334_CHIP_ID ||
3196 bus->sih->chip == BCM43340_CHIP_ID ||
3197 bus->sih->chip == BCM43341_CHIP_ID ||
3198 bus->sih->chip == BCM43342_CHIP_ID ||
3201 /* Moved to PMU chipcontrol 1 from 4330 */
3202 int_val &= ~gpio_sel;
3203 int_val |= jtag_sel;
3205 int_val |= gpio_sel;
3206 int_val &= ~jtag_sel;
3208 uart_enab = CC_PLL_CHIPCTRL_SERIAL_ENAB_4334;
3212 return (int_val & uart_enab);
3214 int_val |= uart_enab;
3216 int_val &= ~uart_enab;
3217 bcmsdh_reg_write(bus->sdh, data, 4, int_val);
3218 if (bcmsdh_regfail(bus->sdh)) {
3219 *bcmerror = BCME_SDIO_ERROR;
3222 if (bus->sih->chip == BCM4330_CHIP_ID) {
3224 addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol);
3225 chipcontrol = bcmsdh_reg_read(bus->sdh, addr, 4);
3226 chipcontrol &= ~jtag_sel;
3228 chipcontrol |= jtag_sel;
3229 chipcontrol &= ~gpio_sel;
3231 bcmsdh_reg_write(bus->sdh, addr, 4, chipcontrol);
3234 return (int_val & uart_enab);
3239 dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const char *name,
3240 void *params, int plen, void *arg, int len, int val_size)
3246 DHD_TRACE(("%s: Enter, action %d name %s params %p plen %d arg %p len %d val_size %d\n",
3247 __FUNCTION__, actionid, name, params, plen, arg, len, val_size));
3249 if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0)
3252 if (plen >= (int)sizeof(int_val))
3253 bcopy(params, &int_val, sizeof(int_val));
3255 bool_val = (int_val != 0) ? TRUE : FALSE;
3258 /* Some ioctls use the bus */
3259 dhd_os_sdlock(bus->dhd);
3261 /* Check if dongle is in reset. If so, only allow DEVRESET iovars */
3262 if (bus->dhd->dongle_reset && !(actionid == IOV_SVAL(IOV_DEVRESET) ||
3263 actionid == IOV_GVAL(IOV_DEVRESET))) {
3264 bcmerror = BCME_NOTREADY;
3269 * Special handling for keepSdioOn: New SDIO Wake-up Mechanism
3271 if ((vi->varid == IOV_KSO) && (IOV_ISSET(actionid))) {
3272 dhdsdio_clk_kso_iovar(bus, bool_val);
3274 } else if ((vi->varid == IOV_DEVSLEEP) && (IOV_ISSET(actionid))) {
3276 dhdsdio_clk_devsleep_iovar(bus, bool_val);
3277 if (!SLPAUTO_ENAB(bus) && (bool_val == FALSE) && (bus->ipend)) {
3278 DHD_ERROR(("INT pending in devsleep 1, dpc_sched: %d\n",
3280 if (!bus->dpc_sched) {
3281 bus->dpc_sched = TRUE;
3282 dhd_sched_dpc(bus->dhd);
3289 /* Handle sleep stuff before any clock mucking */
3290 if (vi->varid == IOV_SLEEP) {
3291 if (IOV_ISSET(actionid)) {
3292 bcmerror = dhdsdio_bussleep(bus, bool_val);
3294 int_val = (int32)bus->sleeping;
3295 bcopy(&int_val, arg, val_size);
3300 /* Request clock to allow SDIO accesses */
3301 if (!bus->dhd->dongle_reset) {
3303 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
3307 case IOV_GVAL(IOV_INTR):
3308 int_val = (int32)bus->intr;
3309 bcopy(&int_val, arg, val_size);
3312 case IOV_SVAL(IOV_INTR):
3313 bus->intr = bool_val;
3314 bus->intdis = FALSE;
3317 DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__));
3318 // terence 20141207: enbale intdis
3320 bcmsdh_intr_enable(bus->sdh);
3322 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
3323 bcmsdh_intr_disable(bus->sdh);
3328 case IOV_GVAL(IOV_POLLRATE):
3329 int_val = (int32)bus->pollrate;
3330 bcopy(&int_val, arg, val_size);
3333 case IOV_SVAL(IOV_POLLRATE):
3334 bus->pollrate = (uint)int_val;
3335 bus->poll = (bus->pollrate != 0);
3338 case IOV_GVAL(IOV_IDLETIME):
3339 int_val = bus->idletime;
3340 bcopy(&int_val, arg, val_size);
3343 case IOV_SVAL(IOV_IDLETIME):
3344 if ((int_val < 0) && (int_val != DHD_IDLE_IMMEDIATE)) {
3345 bcmerror = BCME_BADARG;
3347 bus->idletime = int_val;
3351 case IOV_GVAL(IOV_IDLECLOCK):
3352 int_val = (int32)bus->idleclock;
3353 bcopy(&int_val, arg, val_size);
3356 case IOV_SVAL(IOV_IDLECLOCK):
3357 bus->idleclock = int_val;
3360 case IOV_GVAL(IOV_SD1IDLE):
3361 int_val = (int32)sd1idle;
3362 bcopy(&int_val, arg, val_size);
3365 case IOV_SVAL(IOV_SD1IDLE):
3370 case IOV_SVAL(IOV_MEMBYTES):
3371 case IOV_GVAL(IOV_MEMBYTES):
3377 bool set = (actionid == IOV_SVAL(IOV_MEMBYTES));
3379 ASSERT(plen >= 2*sizeof(int));
3381 address = (uint32)int_val;
3382 bcopy((char *)params + sizeof(int_val), &int_val, sizeof(int_val));
3383 size = (uint)int_val;
3385 /* Do some validation */
3386 dsize = set ? plen - (2 * sizeof(int)) : len;
3388 DHD_ERROR(("%s: error on %s membytes, addr 0x%08x size %d dsize %d\n",
3389 __FUNCTION__, (set ? "set" : "get"), address, size, dsize));
3390 bcmerror = BCME_BADARG;
3394 DHD_INFO(("%s: Request to %s %d bytes at address 0x%08x\n", __FUNCTION__,
3395 (set ? "write" : "read"), size, address));
3398 if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
3400 * If address is start of RAM (i.e. a downloaded image),
3401 * store the reset instruction to be written in 0
3403 if (set && address == bus->dongle_ram_base) {
3404 bus->resetinstr = *(((uint32*)params) + 2);
3407 /* If we know about SOCRAM, check for a fit */
3408 if ((bus->orig_ramsize) &&
3409 ((address > bus->orig_ramsize) || (address + size > bus->orig_ramsize)))
3411 uint8 enable, protect, remap;
3412 si_socdevram(bus->sih, FALSE, &enable, &protect, &remap);
3413 if (!enable || protect) {
3414 DHD_ERROR(("%s: ramsize 0x%08x doesn't have %d bytes at 0x%08x\n",
3415 __FUNCTION__, bus->orig_ramsize, size, address));
3416 DHD_ERROR(("%s: socram enable %d, protect %d\n",
3417 __FUNCTION__, enable, protect));
3418 bcmerror = BCME_BADARG;
3422 if (!REMAP_ENAB(bus) && (address >= SOCDEVRAM_ARM_ADDR)) {
3423 uint32 devramsize = si_socdevram_size(bus->sih);
3424 if ((address < SOCDEVRAM_ARM_ADDR) ||
3425 (address + size > (SOCDEVRAM_ARM_ADDR + devramsize))) {
3426 DHD_ERROR(("%s: bad address 0x%08x, size 0x%08x\n",
3427 __FUNCTION__, address, size));
3428 DHD_ERROR(("%s: socram range 0x%08x,size 0x%08x\n",
3429 __FUNCTION__, SOCDEVRAM_ARM_ADDR, devramsize));
3430 bcmerror = BCME_BADARG;
3433 /* move it such that address is real now */
3434 address -= SOCDEVRAM_ARM_ADDR;
3435 address += SOCDEVRAM_BP_ADDR;
3436 DHD_INFO(("%s: Request to %s %d bytes @ Mapped address 0x%08x\n",
3437 __FUNCTION__, (set ? "write" : "read"), size, address));
3438 } else if (REMAP_ENAB(bus) && REMAP_ISADDR(bus, address) && remap) {
3439 /* Can not access remap region while devram remap bit is set
3440 * ROM content would be returned in this case
3442 DHD_ERROR(("%s: Need to disable remap for address 0x%08x\n",
3443 __FUNCTION__, address));
3444 bcmerror = BCME_ERROR;
3450 /* Generate the actual data pointer */
3451 data = set ? (uint8*)params + 2 * sizeof(int): (uint8*)arg;
3453 /* Call to do the transfer */
3454 bcmerror = dhdsdio_membytes(bus, set, address, data, size);
3459 case IOV_GVAL(IOV_RAMSIZE):
3460 int_val = (int32)bus->ramsize;
3461 bcopy(&int_val, arg, val_size);
3464 case IOV_GVAL(IOV_RAMSTART):
3465 int_val = (int32)bus->dongle_ram_base;
3466 bcopy(&int_val, arg, val_size);
3469 case IOV_GVAL(IOV_SDIOD_DRIVE):
3470 int_val = (int32)dhd_sdiod_drive_strength;
3471 bcopy(&int_val, arg, val_size);
3474 case IOV_SVAL(IOV_SDIOD_DRIVE):
3475 dhd_sdiod_drive_strength = int_val;
3476 si_sdiod_drive_strength_init(bus->sih, bus->dhd->osh, dhd_sdiod_drive_strength);
3479 case IOV_SVAL(IOV_SET_DOWNLOAD_STATE):
3480 bcmerror = dhdsdio_download_state(bus, bool_val);
3483 case IOV_SVAL(IOV_SOCRAM_STATE):
3484 bcmerror = dhdsdio_download_state(bus, bool_val);
3487 case IOV_SVAL(IOV_VARS):
3488 bcmerror = dhdsdio_downloadvars(bus, arg, len);
3491 case IOV_GVAL(IOV_READAHEAD):
3492 int_val = (int32)dhd_readahead;
3493 bcopy(&int_val, arg, val_size);
3496 case IOV_SVAL(IOV_READAHEAD):
3497 if (bool_val && !dhd_readahead)
3499 dhd_readahead = bool_val;
3502 case IOV_GVAL(IOV_SDRXCHAIN):
3503 int_val = (int32)bus->use_rxchain;
3504 bcopy(&int_val, arg, val_size);
3507 case IOV_SVAL(IOV_SDRXCHAIN):
3508 if (bool_val && !bus->sd_rxchain)
3509 bcmerror = BCME_UNSUPPORTED;
3511 bus->use_rxchain = bool_val;
3513 case IOV_GVAL(IOV_ALIGNCTL):
3514 int_val = (int32)dhd_alignctl;
3515 bcopy(&int_val, arg, val_size);
3518 case IOV_SVAL(IOV_ALIGNCTL):
3519 dhd_alignctl = bool_val;
3522 case IOV_GVAL(IOV_SDALIGN):
3523 int_val = DHD_SDALIGN;
3524 bcopy(&int_val, arg, val_size);
3528 case IOV_GVAL(IOV_VARS):
3529 if (bus->varsz < (uint)len)
3530 bcopy(bus->vars, arg, bus->varsz);
3532 bcmerror = BCME_BUFTOOSHORT;
3534 #endif /* DHD_DEBUG */
3537 case IOV_GVAL(IOV_SDREG):
3542 sd_ptr = (sdreg_t *)params;
3544 addr = (uint32)((ulong)bus->regs + sd_ptr->offset);
3545 size = sd_ptr->func;
3546 int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size);
3547 if (bcmsdh_regfail(bus->sdh))
3548 bcmerror = BCME_SDIO_ERROR;
3549 bcopy(&int_val, arg, sizeof(int32));
3553 case IOV_SVAL(IOV_SDREG):
3558 sd_ptr = (sdreg_t *)params;
3560 addr = (uint32)((ulong)bus->regs + sd_ptr->offset);
3561 size = sd_ptr->func;
3562 bcmsdh_reg_write(bus->sdh, addr, size, sd_ptr->value);
3563 if (bcmsdh_regfail(bus->sdh))
3564 bcmerror = BCME_SDIO_ERROR;
3568 /* Same as above, but offset is not backplane (not SDIO core) */
3569 case IOV_GVAL(IOV_SBREG):
3574 bcopy(params, &sdreg, sizeof(sdreg));
3576 addr = SI_ENUM_BASE + sdreg.offset;
3578 int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size);
3579 if (bcmsdh_regfail(bus->sdh))
3580 bcmerror = BCME_SDIO_ERROR;
3581 bcopy(&int_val, arg, sizeof(int32));
3585 case IOV_SVAL(IOV_SBREG):
3590 bcopy(params, &sdreg, sizeof(sdreg));
3592 addr = SI_ENUM_BASE + sdreg.offset;
3594 bcmsdh_reg_write(bus->sdh, addr, size, sdreg.value);
3595 if (bcmsdh_regfail(bus->sdh))
3596 bcmerror = BCME_SDIO_ERROR;
3600 case IOV_GVAL(IOV_SDCIS):
3604 bcmstrcat(arg, "\nFunc 0\n");
3605 bcmsdh_cis_read(bus->sdh, 0x10, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
3606 bcmstrcat(arg, "\nFunc 1\n");
3607 bcmsdh_cis_read(bus->sdh, 0x11, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
3608 bcmstrcat(arg, "\nFunc 2\n");
3609 bcmsdh_cis_read(bus->sdh, 0x12, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
3613 case IOV_GVAL(IOV_FORCEEVEN):
3614 int_val = (int32)forcealign;
3615 bcopy(&int_val, arg, val_size);
3618 case IOV_SVAL(IOV_FORCEEVEN):
3619 forcealign = bool_val;
3622 case IOV_GVAL(IOV_TXBOUND):
3623 int_val = (int32)dhd_txbound;
3624 bcopy(&int_val, arg, val_size);
3627 case IOV_SVAL(IOV_TXBOUND):
3628 dhd_txbound = (uint)int_val;
3631 case IOV_GVAL(IOV_RXBOUND):
3632 int_val = (int32)dhd_rxbound;
3633 bcopy(&int_val, arg, val_size);
3636 case IOV_SVAL(IOV_RXBOUND):
3637 dhd_rxbound = (uint)int_val;
3640 case IOV_GVAL(IOV_TXMINMAX):
3641 int_val = (int32)dhd_txminmax;
3642 bcopy(&int_val, arg, val_size);
3645 case IOV_SVAL(IOV_TXMINMAX):
3646 dhd_txminmax = (uint)int_val;
3649 case IOV_GVAL(IOV_SERIALCONS):
3650 int_val = dhd_serialconsole(bus, FALSE, 0, &bcmerror);
3654 bcopy(&int_val, arg, val_size);
3657 case IOV_SVAL(IOV_SERIALCONS):
3658 dhd_serialconsole(bus, TRUE, bool_val, &bcmerror);
3662 #endif /* DHD_DEBUG */
3666 case IOV_GVAL(IOV_EXTLOOP):
3667 int_val = (int32)bus->ext_loop;
3668 bcopy(&int_val, arg, val_size);
3671 case IOV_SVAL(IOV_EXTLOOP):
3672 bus->ext_loop = bool_val;
3675 case IOV_GVAL(IOV_PKTGEN):
3676 bcmerror = dhdsdio_pktgen_get(bus, arg);
3679 case IOV_SVAL(IOV_PKTGEN):
3680 bcmerror = dhdsdio_pktgen_set(bus, arg);
3684 #if defined(USE_SDIOFIFO_IOVAR)
3685 case IOV_GVAL(IOV_WATERMARK):
3686 int_val = (int32)watermark;
3687 bcopy(&int_val, arg, val_size);
3690 case IOV_SVAL(IOV_WATERMARK):
3691 watermark = (uint)int_val;
3692 watermark = (watermark > SBSDIO_WATERMARK_MASK) ? SBSDIO_WATERMARK_MASK : watermark;
3693 DHD_ERROR(("Setting watermark as 0x%x.\n", watermark));
3694 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, (uint8)watermark, NULL);
3697 case IOV_GVAL(IOV_MESBUSYCTRL):
3698 int_val = (int32)mesbusyctrl;
3699 bcopy(&int_val, arg, val_size);
3702 case IOV_SVAL(IOV_MESBUSYCTRL):
3703 mesbusyctrl = (uint)int_val;
3704 mesbusyctrl = (mesbusyctrl > SBSDIO_MESBUSYCTRL_MASK)
3705 ? SBSDIO_MESBUSYCTRL_MASK : mesbusyctrl;
3706 DHD_ERROR(("Setting mesbusyctrl as 0x%x.\n", mesbusyctrl));
3707 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL,
3708 ((uint8)mesbusyctrl | 0x80), NULL);
3713 case IOV_GVAL(IOV_DONGLEISOLATION):
3714 int_val = bus->dhd->dongle_isolation;
3715 bcopy(&int_val, arg, val_size);
3718 case IOV_SVAL(IOV_DONGLEISOLATION):
3719 bus->dhd->dongle_isolation = bool_val;
3722 case IOV_SVAL(IOV_DEVRESET):
3723 DHD_TRACE(("%s: Called set IOV_DEVRESET=%d dongle_reset=%d busstate=%d\n",
3724 __FUNCTION__, bool_val, bus->dhd->dongle_reset,
3725 bus->dhd->busstate));
3727 ASSERT(bus->dhd->osh);
3728 /* ASSERT(bus->cl_devid); */
3730 dhd_bus_devreset(bus->dhd, (uint8)bool_val);
3734 * softap firmware is updated through module parameter or android private command
3737 case IOV_GVAL(IOV_DEVRESET):
3738 DHD_TRACE(("%s: Called get IOV_DEVRESET\n", __FUNCTION__));
3740 /* Get its status */
3741 int_val = (bool) bus->dhd->dongle_reset;
3742 bcopy(&int_val, arg, val_size);
3746 case IOV_GVAL(IOV_KSO):
3747 int_val = dhdsdio_sleepcsr_get(bus);
3748 bcopy(&int_val, arg, val_size);
3751 case IOV_GVAL(IOV_DEVCAP):
3752 int_val = dhdsdio_devcap_get(bus);
3753 bcopy(&int_val, arg, val_size);
3756 case IOV_SVAL(IOV_DEVCAP):
3757 dhdsdio_devcap_set(bus, (uint8) int_val);
3759 case IOV_GVAL(IOV_TXGLOMSIZE):
3760 int_val = (int32)bus->txglomsize;
3761 bcopy(&int_val, arg, val_size);
3764 case IOV_SVAL(IOV_TXGLOMSIZE):
3765 if (int_val > SDPCM_MAXGLOM_SIZE) {
3766 bcmerror = BCME_ERROR;
3768 bus->txglomsize = (uint)int_val;
3771 case IOV_SVAL(IOV_HANGREPORT):
3772 bus->dhd->hang_report = bool_val;
3773 DHD_ERROR(("%s: Set hang_report as %d\n", __FUNCTION__, bus->dhd->hang_report));
3776 case IOV_GVAL(IOV_HANGREPORT):
3777 int_val = (int32)bus->dhd->hang_report;
3778 bcopy(&int_val, arg, val_size);
3781 case IOV_GVAL(IOV_TXINRX_THRES):
3782 int_val = bus->txinrx_thres;
3783 bcopy(&int_val, arg, val_size);
3785 case IOV_SVAL(IOV_TXINRX_THRES):
3787 bcmerror = BCME_BADARG;
3789 bus->txinrx_thres = int_val;
3794 bcmerror = BCME_UNSUPPORTED;
3799 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
3800 bus->activity = FALSE;
3801 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
3804 dhd_os_sdunlock(bus->dhd);
3810 dhdsdio_write_vars(dhd_bus_t *bus)
3813 uint32 varsize, phys_size;
3818 uint8 *nvram_ularray;
3819 #endif /* DHD_DEBUG */
3821 /* Even if there are no vars are to be written, we still need to set the ramsize. */
3822 varsize = bus->varsz ? ROUNDUP(bus->varsz, 4) : 0;
3823 varaddr = (bus->ramsize - 4) - varsize;
3825 // terence 20150412: fix for nvram failed to download
3826 if (bus->dhd->conf->chip == BCM43340_CHIP_ID ||
3827 bus->dhd->conf->chip == BCM43341_CHIP_ID) {
3828 varsize = varsize ? ROUNDUP(varsize, 64) : 0;
3829 varaddr = (bus->ramsize - 64) - varsize;
3832 varaddr += bus->dongle_ram_base;
3835 if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 7)) {
3836 if (((varaddr & 0x3C) == 0x3C) && (varsize > 4)) {
3837 DHD_ERROR(("PR85623WAR in place\n"));
3843 vbuffer = (uint8 *)MALLOC(bus->dhd->osh, varsize);
3847 bzero(vbuffer, varsize);
3848 bcopy(bus->vars, vbuffer, bus->varsz);
3850 /* Write the vars list */
3851 bcmerror = dhdsdio_membytes(bus, TRUE, varaddr, vbuffer, varsize);
3853 /* Verify NVRAM bytes */
3854 DHD_INFO(("Compare NVRAM dl & ul; varsize=%d\n", varsize));
3855 nvram_ularray = (uint8*)MALLOC(bus->dhd->osh, varsize);
3859 /* Upload image to verify downloaded contents. */
3860 memset(nvram_ularray, 0xaa, varsize);
3862 /* Read the vars list to temp buffer for comparison */
3863 bcmerror = dhdsdio_membytes(bus, FALSE, varaddr, nvram_ularray, varsize);
3865 DHD_ERROR(("%s: error %d on reading %d nvram bytes at 0x%08x\n",
3866 __FUNCTION__, bcmerror, varsize, varaddr));
3868 /* Compare the org NVRAM with the one read from RAM */
3869 if (memcmp(vbuffer, nvram_ularray, varsize)) {
3870 DHD_ERROR(("%s: Downloaded NVRAM image is corrupted.\n", __FUNCTION__));
3872 DHD_ERROR(("%s: Download, Upload and compare of NVRAM succeeded.\n",
3875 MFREE(bus->dhd->osh, nvram_ularray, varsize);
3876 #endif /* DHD_DEBUG */
3878 MFREE(bus->dhd->osh, vbuffer, varsize);
3881 phys_size = REMAP_ENAB(bus) ? bus->ramsize : bus->orig_ramsize;
3883 phys_size += bus->dongle_ram_base;
3885 /* adjust to the user specified RAM */
3886 DHD_INFO(("Physical memory size: %d, usable memory size: %d\n",
3887 phys_size, bus->ramsize));
3888 DHD_INFO(("Vars are at %d, orig varsize is %d\n",
3890 varsize = ((phys_size - 4) - varaddr);
3893 * Determine the length token:
3894 * Varsize, converted to words, in lower 16-bits, checksum in upper 16-bits.
3899 varsizew = varsize / 4;
3900 varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF);
3901 varsizew = htol32(varsizew);
3904 DHD_INFO(("New varsize is %d, length token=0x%08x\n", varsize, varsizew));
3906 /* Write the length token to the last word */
3907 bcmerror = dhdsdio_membytes(bus, TRUE, (phys_size - 4),
3908 (uint8*)&varsizew, 4);
3914 dhdsdio_download_state(dhd_bus_t *bus, bool enter)
3922 /* To enter download state, disable ARM and reset SOCRAM.
3923 * To exit download state, simply reset ARM (default is RAM boot).
3926 bus->alp_only = TRUE;
3928 if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) &&
3929 !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) {
3930 if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
3933 DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__));
3934 bcmerror = BCME_ERROR;
3940 si_core_disable(bus->sih, 0);
3941 if (bcmsdh_regfail(bus->sdh)) {
3942 bcmerror = BCME_SDIO_ERROR;
3946 if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) {
3947 DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__));
3948 bcmerror = BCME_ERROR;
3952 si_core_reset(bus->sih, 0, 0);
3953 if (bcmsdh_regfail(bus->sdh)) {
3954 DHD_ERROR(("%s: Failure trying reset SOCRAM core?\n",
3956 bcmerror = BCME_SDIO_ERROR;
3960 /* Disable remap for download */
3961 if (REMAP_ENAB(bus) && si_socdevram_remap_isenb(bus->sih))
3962 dhdsdio_devram_remap(bus, FALSE);
3964 if (CHIPID(bus->sih->chip) == BCM43430_CHIP_ID) {
3965 /* Disabling Remap for SRAM_3 */
3966 si_socram_set_bankpda(bus->sih, 0x3, 0x0);
3969 /* Clear the top bit of memory */
3972 if (dhdsdio_membytes(bus, TRUE, bus->ramsize - 4,
3973 (uint8*)&zeros, 4) < 0) {
3974 bcmerror = BCME_SDIO_ERROR;
3982 * Read RAM base address [0x18_0000]
3983 * [next] Download firmware
3984 * [done at else] Populate the reset vector
3985 * [done at else] Remove ARM halt
3987 /* Halt ARM & remove reset */
3988 si_core_reset(bus->sih, SICF_CPUHALT, SICF_CPUHALT);
3991 if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
3992 if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) {
3993 DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__));
3994 bcmerror = BCME_ERROR;
3998 if (!si_iscoreup(bus->sih)) {
3999 DHD_ERROR(("%s: SOCRAM core is down after reset?\n", __FUNCTION__));
4000 bcmerror = BCME_ERROR;
4004 if ((bcmerror = dhdsdio_write_vars(bus))) {
4005 DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__));
4009 /* Enable remap before ARM reset but after vars.
4010 * No backplane access in remap mode
4012 if (REMAP_ENAB(bus) && !si_socdevram_remap_isenb(bus->sih))
4013 dhdsdio_devram_remap(bus, TRUE);
4015 if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) &&
4016 !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) {
4017 DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__));
4018 bcmerror = BCME_ERROR;
4021 W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries);
4024 if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) &&
4025 !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) {
4026 DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__));
4027 bcmerror = BCME_ERROR;
4031 /* cr4 has no socram, but tcm's */
4033 if ((bcmerror = dhdsdio_write_vars(bus))) {
4034 DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__));
4038 if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) &&
4039 !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) {
4040 DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__));
4041 bcmerror = BCME_ERROR;
4044 W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries);
4046 /* switch back to arm core again */
4047 if (!(si_setcore(bus->sih, ARMCR4_CORE_ID, 0))) {
4048 DHD_ERROR(("%s: Failed to find ARM CR4 core!\n", __FUNCTION__));
4049 bcmerror = BCME_ERROR;
4052 /* write address 0 with reset instruction */
4053 bcmerror = dhdsdio_membytes(bus, TRUE, 0,
4054 (uint8 *)&bus->resetinstr, sizeof(bus->resetinstr));
4056 /* now remove reset and halt and continue to run CR4 */
4059 si_core_reset(bus->sih, 0, 0);
4060 if (bcmsdh_regfail(bus->sdh)) {
4061 DHD_ERROR(("%s: Failure trying to reset ARM core?\n", __FUNCTION__));
4062 bcmerror = BCME_SDIO_ERROR;
4066 /* Allow HT Clock now that the ARM is running. */
4067 bus->alp_only = FALSE;
4069 bus->dhd->busstate = DHD_BUS_LOAD;
4073 /* Always return to SDIOD core */
4074 if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0))
4075 si_setcore(bus->sih, SDIOD_CORE_ID, 0);
4081 dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name,
4082 void *params, int plen, void *arg, int len, bool set)
4084 dhd_bus_t *bus = dhdp->bus;
4085 const bcm_iovar_t *vi = NULL;
4090 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4095 /* Get MUST have return space */
4096 ASSERT(set || (arg && len));
4098 /* Set does NOT take qualifiers */
4099 ASSERT(!set || (!params && !plen));
4101 /* Look up var locally; if not found pass to host driver */
4102 if ((vi = bcm_iovar_lookup(dhdsdio_iovars, name)) == NULL) {
4103 dhd_os_sdlock(bus->dhd);
4107 /* Turn on clock in case SD command needs backplane */
4108 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
4110 bcmerror = bcmsdh_iovar_op(bus->sdh, name, params, plen, arg, len, set);
4112 /* Check for bus configuration changes of interest */
4114 /* If it was divisor change, read the new one */
4115 if (set && strcmp(name, "sd_divisor") == 0) {
4116 if (bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
4117 &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) {
4118 bus->sd_divisor = -1;
4119 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, name));
4121 DHD_INFO(("%s: noted %s update, value now %d\n",
4122 __FUNCTION__, name, bus->sd_divisor));
4125 /* If it was a mode change, read the new one */
4126 if (set && strcmp(name, "sd_mode") == 0) {
4127 if (bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
4128 &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) {
4130 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, name));
4132 DHD_INFO(("%s: noted %s update, value now %d\n",
4133 __FUNCTION__, name, bus->sd_mode));
4136 /* Similar check for blocksize change */
4137 if (set && strcmp(name, "sd_blocksize") == 0) {
4139 if (bcmsdh_iovar_op(bus->sdh, "sd_blocksize", &fnum, sizeof(int32),
4140 &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) {
4142 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize"));
4144 DHD_INFO(("%s: noted %s update, value now %d\n",
4145 __FUNCTION__, "sd_blocksize", bus->blocksize));
4147 dhdsdio_tune_fifoparam(bus);
4150 bus->roundup = MIN(max_roundup, bus->blocksize);
4152 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
4153 bus->activity = FALSE;
4154 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
4157 dhd_os_sdunlock(bus->dhd);
4161 DHD_CTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__,
4162 name, (set ? "set" : "get"), len, plen));
4164 /* set up 'params' pointer in case this is a set command so that
4165 * the convenience int and bool code can be common to set and get
4167 if (params == NULL) {
4172 if (vi->type == IOVT_VOID)
4174 else if (vi->type == IOVT_BUFFER)
4177 /* all other types are integer sized */
4178 val_size = sizeof(int);
4180 actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
4181 bcmerror = dhdsdio_doiovar(bus, vi, actionid, name, params, plen, arg, len, val_size);
4188 dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex)
4191 uint32 local_hostintmask;
4195 bool wlfc_enabled = FALSE;
4200 osh = bus->dhd->osh;
4201 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4203 bcmsdh_waitlockfree(bus->sdh);
4206 dhd_os_sdlock(bus->dhd);
4208 if ((bus->dhd->busstate == DHD_BUS_DOWN) || bus->dhd->hang_was_sent) {
4209 /* if Firmware already hangs disbale any interrupt */
4210 bus->dhd->busstate = DHD_BUS_DOWN;
4211 bus->hostintmask = 0;
4212 bcmsdh_intr_disable(bus->sdh);
4217 /* Change our idea of bus state */
4218 bus->dhd->busstate = DHD_BUS_DOWN;
4220 if (KSO_ENAB(bus)) {
4222 /* Enable clock for device interrupts */
4223 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
4225 /* Disable and clear interrupts at the chip level also */
4226 W_SDREG(0, &bus->regs->hostintmask, retries);
4227 local_hostintmask = bus->hostintmask;
4228 bus->hostintmask = 0;
4230 /* Force clocks on backplane to be sure F2 interrupt propagates */
4231 saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
4233 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
4234 (saveclk | SBSDIO_FORCE_HT), &err);
4237 DHD_ERROR(("%s: Failed to force clock for F2: err %d\n",
4238 __FUNCTION__, err));
4241 /* Turn off the bus (F2), free any pending packets */
4242 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
4243 #if !defined(NDISVER) || (NDISVER < 0x0630)
4244 bcmsdh_intr_disable(bus->sdh);
4245 #endif /* !defined(NDISVER) || (NDISVER < 0x0630) */
4246 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL);
4248 /* Clear any pending interrupts now that F2 is disabled */
4249 W_SDREG(local_hostintmask, &bus->regs->intstatus, retries);
4252 /* Turn off the backplane clock (only) */
4253 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
4256 #ifdef PROP_TXSTATUS
4257 wlfc_enabled = (dhd_wlfc_cleanup_txq(bus->dhd, NULL, 0) != WLFC_UNSUPPORTED);
4259 if (!wlfc_enabled) {
4260 #ifdef DHDTCPACK_SUPPRESS
4261 /* Clean tcp_ack_info_tbl in order to prevent access to flushed pkt,
4262 * when there is a newly coming packet from network stack.
4264 dhd_tcpack_info_tbl_clean(bus->dhd);
4265 #endif /* DHDTCPACK_SUPPRESS */
4266 /* Clear the data packet queues */
4267 pktq_flush(osh, &bus->txq, TRUE, NULL, 0);
4270 /* Clear any held glomming stuff */
4272 PKTFREE(osh, bus->glomd, FALSE);
4275 PKTFREE(osh, bus->glom, FALSE);
4277 bus->glom = bus->glomd = NULL;
4279 /* Clear rx control and wake any waiters */
4281 dhd_os_ioctl_resp_wake(bus->dhd);
4283 /* Reset some F2 state stuff */
4284 bus->rxskip = FALSE;
4285 bus->tx_seq = bus->rx_seq = 0;
4290 dhd_os_sdunlock(bus->dhd);
4293 #if defined(BCMSDIOH_TXGLOM) && defined(BCMSDIOH_STD)
4294 extern uint sd_txglom;
4297 dhd_txglom_enable(dhd_pub_t *dhdp, bool enable)
4299 /* can't enable host txglom by default, some platforms have no
4300 * (or crappy) ADMA support and txglom will cause kernel assertions (e.g.
4303 dhd_bus_t *bus = dhdp->bus;
4304 #ifdef BCMSDIOH_TXGLOM
4309 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4314 #endif /* BCMSDIOH_STD */
4318 memset(buf, 0, sizeof(buf));
4319 bcm_mkiovar("bus:rxglom", (void *)&rxglom, 4, buf, sizeof(buf));
4320 ret = dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0);
4322 bus->txglom_enable = TRUE;
4326 #endif /* BCMSDIOH_STD */
4327 bus->txglom_enable = FALSE;
4330 #endif /* BCMSDIOH_TXGLOM */
4331 bus->txglom_enable = FALSE;
4332 printk("%s: enable %d\n", __FUNCTION__, bus->txglom_enable);
4336 dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex)
4338 dhd_bus_t *bus = dhdp->bus;
4341 uint8 ready, enable;
4345 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4352 dhd_os_sdlock(bus->dhd);
4354 if (bus->sih->chip == BCM43362_CHIP_ID) {
4355 printf("%s: delay 100ms for BCM43362\n", __FUNCTION__);
4356 OSL_DELAY(100000); // terence 20131209: delay for 43362
4359 /* Make sure backplane clock is on, needed to generate F2 interrupt */
4360 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
4361 if (bus->clkstate != CLK_AVAIL) {
4362 DHD_ERROR(("%s: clock state is wrong. state = %d\n", __FUNCTION__, bus->clkstate));
4368 /* Force clocks on backplane to be sure F2 interrupt propagates */
4369 saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
4371 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
4372 (saveclk | SBSDIO_FORCE_HT), &err);
4375 DHD_ERROR(("%s: Failed to force clock for F2: err %d\n", __FUNCTION__, err));
4380 /* Enable function 2 (frame transfers) */
4381 W_SDREG((SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT),
4382 &bus->regs->tosbmailboxdata, retries);
4383 enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2);
4385 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL);
4387 /* Give the dongle some time to do its thing and set IOR2 */
4388 dhd_timeout_start(&tmo, DHD_WAIT_F2RDY * 1000);
4391 while (ready != enable && !dhd_timeout_expired(&tmo))
4392 ready = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IORDY, NULL);
4394 DHD_ERROR(("%s: enable 0x%02x, ready 0x%02x (waited %uus)\n",
4395 __FUNCTION__, enable, ready, tmo.elapsed));
4398 /* If F2 successfully enabled, set core and enable interrupts */
4399 if (ready == enable) {
4400 /* Make sure we're talking to the core. */
4401 if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0)))
4402 bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0);
4403 ASSERT(bus->regs != NULL);
4405 /* Set up the interrupt mask and enable interrupts */
4406 bus->hostintmask = HOSTINTMASK;
4407 /* corerev 4 could use the newer interrupt logic to detect the frames */
4408 if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 4) &&
4409 (bus->rxint_mode != SDIO_DEVICE_HMB_RXINT)) {
4410 bus->hostintmask &= ~I_HMB_FRAME_IND;
4411 bus->hostintmask |= I_XMTDATA_AVAIL;
4413 W_SDREG(bus->hostintmask, &bus->regs->hostintmask, retries);
4415 if (bus->sih->buscorerev < 15) {
4416 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK,
4417 (uint8)watermark, &err);
4420 /* Set bus state according to enable result */
4421 dhdp->busstate = DHD_BUS_DATA;
4423 /* bcmsdh_intr_unmask(bus->sdh); */
4425 bus->intdis = FALSE;
4427 DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__));
4428 bcmsdh_intr_enable(bus->sdh);
4430 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
4431 bcmsdh_intr_disable(bus->sdh);
4438 /* Disable F2 again */
4439 enable = SDIO_FUNC_ENABLE_1;
4440 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL);
4443 if (dhdsdio_sr_cap(bus)) {
4444 dhdsdio_sr_init(bus);
4445 /* Masking the chip active interrupt permanantly */
4446 bus->hostintmask &= ~I_CHIPACTIVE;
4447 W_SDREG(bus->hostintmask, &bus->regs->hostintmask, retries);
4448 DHD_INFO(("%s: disable I_CHIPACTIVE in hostintmask[0x%08x]\n",
4449 __FUNCTION__, bus->hostintmask));
4452 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1,
4453 SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err);
4455 /* If we didn't come up, turn off backplane clock */
4456 if (dhdp->busstate != DHD_BUS_DATA)
4457 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
4461 dhd_os_sdunlock(bus->dhd);
4467 dhdsdio_rxfail(dhd_bus_t *bus, bool abort, bool rtx)
4469 bcmsdh_info_t *sdh = bus->sdh;
4470 sdpcmd_regs_t *regs = bus->regs;
4476 DHD_ERROR(("%s: %sterminate frame%s\n", __FUNCTION__,
4477 (abort ? "abort command, " : ""), (rtx ? ", send NAK" : "")));
4479 if (!KSO_ENAB(bus)) {
4480 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
4485 bcmsdh_abort(sdh, SDIO_FUNC_2);
4488 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, SFC_RF_TERM, &err);
4490 DHD_ERROR(("%s: SBSDIO_FUNC1_FRAMECTRL cmd err\n", __FUNCTION__));
4495 /* Wait until the packet has been flushed (device/FIFO stable) */
4496 for (lastrbc = retries = 0xffff; retries > 0; retries--) {
4497 hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCHI, NULL);
4498 lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCLO, &err);
4500 DHD_ERROR(("%s: SBSDIO_FUNC1_RFAMEBCLO cmd err\n", __FUNCTION__));
4504 bus->f1regdata += 2;
4506 if ((hi == 0) && (lo == 0))
4509 if ((hi > (lastrbc >> 8)) && (lo > (lastrbc & 0x00ff))) {
4510 DHD_ERROR(("%s: count growing: last 0x%04x now 0x%04x\n",
4511 __FUNCTION__, lastrbc, ((hi << 8) + lo)));
4513 lastrbc = (hi << 8) + lo;
4517 DHD_ERROR(("%s: count never zeroed: last 0x%04x\n", __FUNCTION__, lastrbc));
4519 DHD_INFO(("%s: flush took %d iterations\n", __FUNCTION__, (0xffff - retries)));
4524 W_SDREG(SMB_NAK, ®s->tosbmailbox, retries);
4526 if (retries <= retry_limit) {
4531 /* Clear partial in any case */
4535 /* If we can't reach the device, signal failure */
4536 if (err || bcmsdh_regfail(sdh))
4537 bus->dhd->busstate = DHD_BUS_DOWN;
4541 dhdsdio_read_control(dhd_bus_t *bus, uint8 *hdr, uint len, uint doff)
4543 bcmsdh_info_t *sdh = bus->sdh;
4548 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4550 /* Control data already received in aligned rxctl */
4551 if ((bus->bus == SPI_BUS) && (!bus->usebufpool))
4555 /* Set rxctl for frame (w/optional alignment) */
4556 bus->rxctl = bus->rxbuf;
4558 bus->rxctl += firstread;
4559 if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN)))
4560 bus->rxctl += (DHD_SDALIGN - pad);
4561 bus->rxctl -= firstread;
4563 ASSERT(bus->rxctl >= bus->rxbuf);
4565 /* Copy the already-read portion over */
4566 bcopy(hdr, bus->rxctl, firstread);
4567 if (len <= firstread)
4570 /* Copy the full data pkt in gSPI case and process ioctl. */
4571 if (bus->bus == SPI_BUS) {
4572 bcopy(hdr, bus->rxctl, len);
4576 /* Raise rdlen to next SDIO block to avoid tail command */
4577 rdlen = len - firstread;
4578 if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
4579 pad = bus->blocksize - (rdlen % bus->blocksize);
4580 if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
4581 ((len + pad) < bus->dhd->maxctl))
4583 } else if (rdlen % DHD_SDALIGN) {
4584 rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
4587 /* Satisfy length-alignment requirements */
4588 if (forcealign && (rdlen & (ALIGNMENT - 1)))
4589 rdlen = ROUNDUP(rdlen, ALIGNMENT);
4591 /* Drop if the read is too big or it exceeds our maximum */
4592 if ((rdlen + firstread) > bus->dhd->maxctl) {
4593 DHD_ERROR(("%s: %d-byte control read exceeds %d-byte buffer\n",
4594 __FUNCTION__, rdlen, bus->dhd->maxctl));
4595 bus->dhd->rx_errors++;
4596 dhdsdio_rxfail(bus, FALSE, FALSE);
4600 if ((len - doff) > bus->dhd->maxctl) {
4601 DHD_ERROR(("%s: %d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n",
4602 __FUNCTION__, len, (len - doff), bus->dhd->maxctl));
4603 bus->dhd->rx_errors++; bus->rx_toolong++;
4604 dhdsdio_rxfail(bus, FALSE, FALSE);
4609 /* Read remainder of frame body into the rxctl buffer */
4610 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
4611 (bus->rxctl + firstread), rdlen, NULL, NULL, NULL);
4613 ASSERT(sdret != BCME_PENDING);
4615 /* Control frame failures need retransmission */
4617 DHD_ERROR(("%s: read %d control bytes failed: %d\n", __FUNCTION__, rdlen, sdret));
4618 bus->rxc_errors++; /* dhd.rx_ctlerrs is higher level */
4619 dhdsdio_rxfail(bus, TRUE, TRUE);
4626 if (DHD_BYTES_ON() && DHD_CTL_ON()) {
4627 prhex("RxCtrl", bus->rxctl, len);
4631 /* Point to valid data and indicate its length */
4633 bus->rxlen = len - doff;
4636 /* Awake any waiters */
4637 dhd_os_ioctl_resp_wake(bus->dhd);
4640 dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf, uint reorder_info_len,
4641 void **pkt, uint32 *pkt_count);
4644 dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq)
4646 uint16 dlen, totlen;
4647 uint8 *dptr, num = 0;
4649 uint16 sublen, check;
4650 void *pfirst, *plast, *pnext;
4651 void * list_tail[DHD_MAX_IFS] = { NULL };
4652 void * list_head[DHD_MAX_IFS] = { NULL };
4654 osl_t *osh = bus->dhd->osh;
4657 uint8 chan, seq, doff, sfdoff;
4659 uchar reorder_info_buf[WLHOST_REORDERDATA_TOTLEN];
4660 uint reorder_info_len;
4663 bool usechain = bus->use_rxchain;
4665 /* If packets, issue read(s) and send up packet chain */
4666 /* Return sequence numbers consumed? */
4668 DHD_TRACE(("dhdsdio_rxglom: start: glomd %p glom %p\n", bus->glomd, bus->glom));
4670 /* If there's a descriptor, generate the packet chain */
4672 dhd_os_sdlock_rxq(bus->dhd);
4674 pfirst = plast = pnext = NULL;
4675 dlen = (uint16)PKTLEN(osh, bus->glomd);
4676 dptr = PKTDATA(osh, bus->glomd);
4677 if (!dlen || (dlen & 1)) {
4678 DHD_ERROR(("%s: bad glomd len (%d), ignore descriptor\n",
4679 __FUNCTION__, dlen));
4683 for (totlen = num = 0; dlen; num++) {
4684 /* Get (and move past) next length */
4685 sublen = ltoh16_ua(dptr);
4686 dlen -= sizeof(uint16);
4687 dptr += sizeof(uint16);
4688 if ((sublen < SDPCM_HDRLEN) ||
4689 ((num == 0) && (sublen < (2 * SDPCM_HDRLEN)))) {
4690 DHD_ERROR(("%s: descriptor len %d bad: %d\n",
4691 __FUNCTION__, num, sublen));
4695 if (sublen % DHD_SDALIGN) {
4696 DHD_ERROR(("%s: sublen %d not a multiple of %d\n",
4697 __FUNCTION__, sublen, DHD_SDALIGN));
4702 /* For last frame, adjust read len so total is a block multiple */
4704 sublen += (ROUNDUP(totlen, bus->blocksize) - totlen);
4705 totlen = ROUNDUP(totlen, bus->blocksize);
4708 /* Allocate/chain packet for next subframe */
4709 if ((pnext = PKTGET(osh, sublen + DHD_SDALIGN, FALSE)) == NULL) {
4710 DHD_ERROR(("%s: PKTGET failed, num %d len %d\n",
4711 __FUNCTION__, num, sublen));
4714 ASSERT(!PKTLINK(pnext));
4717 pfirst = plast = pnext;
4720 PKTSETNEXT(osh, plast, pnext);
4724 /* Adhere to start alignment requirements */
4725 PKTALIGN(osh, pnext, sublen, DHD_SDALIGN);
4728 /* If all allocations succeeded, save packet chain in bus structure */
4730 DHD_GLOM(("%s: allocated %d-byte packet chain for %d subframes\n",
4731 __FUNCTION__, totlen, num));
4732 if (DHD_GLOM_ON() && bus->nextlen) {
4733 if (totlen != bus->nextlen) {
4734 DHD_GLOM(("%s: glomdesc mismatch: nextlen %d glomdesc %d "
4735 "rxseq %d\n", __FUNCTION__, bus->nextlen,
4740 pfirst = pnext = NULL;
4743 PKTFREE(osh, pfirst, FALSE);
4748 /* Done with descriptor packet */
4749 PKTFREE(osh, bus->glomd, FALSE);
4753 dhd_os_sdunlock_rxq(bus->dhd);
4756 /* Ok -- either we just generated a packet chain, or had one from before */
4758 if (DHD_GLOM_ON()) {
4759 DHD_GLOM(("%s: attempt superframe read, packet chain:\n", __FUNCTION__));
4760 for (pnext = bus->glom; pnext; pnext = PKTNEXT(osh, pnext)) {
4761 DHD_GLOM((" %p: %p len 0x%04x (%d)\n",
4762 pnext, (uint8*)PKTDATA(osh, pnext),
4763 PKTLEN(osh, pnext), PKTLEN(osh, pnext)));
4768 dlen = (uint16)pkttotlen(osh, pfirst);
4770 /* Do an SDIO read for the superframe. Configurable iovar to
4771 * read directly into the chained packet, or allocate a large
4772 * packet and and copy into the chain.
4775 errcode = dhd_bcmsdh_recv_buf(bus,
4776 bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2,
4777 F2SYNC, (uint8*)PKTDATA(osh, pfirst),
4778 dlen, pfirst, NULL, NULL);
4779 } else if (bus->dataptr) {
4780 errcode = dhd_bcmsdh_recv_buf(bus,
4781 bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2,
4782 F2SYNC, bus->dataptr,
4783 dlen, NULL, NULL, NULL);
4784 sublen = (uint16)pktfrombuf(osh, pfirst, 0, dlen, bus->dataptr);
4785 if (sublen != dlen) {
4786 DHD_ERROR(("%s: FAILED TO COPY, dlen %d sublen %d\n",
4787 __FUNCTION__, dlen, sublen));
4792 DHD_ERROR(("COULDN'T ALLOC %d-BYTE GLOM, FORCE FAILURE\n", dlen));
4796 ASSERT(errcode != BCME_PENDING);
4798 /* On failure, kill the superframe, allow a couple retries */
4800 DHD_ERROR(("%s: glom read of %d bytes failed: %d\n",
4801 __FUNCTION__, dlen, errcode));
4802 bus->dhd->rx_errors++;
4804 if (bus->glomerr++ < 3) {
4805 dhdsdio_rxfail(bus, TRUE, TRUE);
4808 dhdsdio_rxfail(bus, TRUE, FALSE);
4809 dhd_os_sdlock_rxq(bus->dhd);
4810 PKTFREE(osh, bus->glom, FALSE);
4811 dhd_os_sdunlock_rxq(bus->dhd);
4819 if (DHD_GLOM_ON()) {
4820 prhex("SUPERFRAME", PKTDATA(osh, pfirst),
4821 MIN(PKTLEN(osh, pfirst), 48));
4826 /* Validate the superframe header */
4827 dptr = (uint8 *)PKTDATA(osh, pfirst);
4828 sublen = ltoh16_ua(dptr);
4829 check = ltoh16_ua(dptr + sizeof(uint16));
4831 chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
4832 seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
4833 bus->nextlen = dptr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
4834 if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
4835 DHD_INFO(("%s: got frame w/nextlen too large (%d) seq %d\n",
4836 __FUNCTION__, bus->nextlen, seq));
4839 doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
4840 txmax = SDPCM_WINDOW_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
4843 if ((uint16)~(sublen^check)) {
4844 DHD_ERROR(("%s (superframe): HW hdr error: len/check 0x%04x/0x%04x\n",
4845 __FUNCTION__, sublen, check));
4847 } else if (ROUNDUP(sublen, bus->blocksize) != dlen) {
4848 DHD_ERROR(("%s (superframe): len 0x%04x, rounded 0x%04x, expect 0x%04x\n",
4849 __FUNCTION__, sublen, ROUNDUP(sublen, bus->blocksize), dlen));
4851 } else if (SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]) != SDPCM_GLOM_CHANNEL) {
4852 DHD_ERROR(("%s (superframe): bad channel %d\n", __FUNCTION__,
4853 SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN])));
4855 } else if (SDPCM_GLOMDESC(&dptr[SDPCM_FRAMETAG_LEN])) {
4856 DHD_ERROR(("%s (superframe): got second descriptor?\n", __FUNCTION__));
4858 } else if ((doff < SDPCM_HDRLEN) ||
4859 (doff > (PKTLEN(osh, pfirst) - SDPCM_HDRLEN))) {
4860 DHD_ERROR(("%s (superframe): Bad data offset %d: HW %d pkt %d min %d\n",
4861 __FUNCTION__, doff, sublen, PKTLEN(osh, pfirst),
4866 /* Check sequence number of superframe SW header */
4868 DHD_INFO(("%s: (superframe) rx_seq %d, expected %d\n",
4869 __FUNCTION__, seq, rxseq));
4874 /* Check window for sanity */
4875 if ((uint8)(txmax - bus->tx_seq) > 0x70) {
4876 DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
4877 __FUNCTION__, txmax, bus->tx_seq));
4878 txmax = bus->tx_max;
4880 bus->tx_max = txmax;
4882 /* Remove superframe header, remember offset */
4883 PKTPULL(osh, pfirst, doff);
4886 /* Validate all the subframe headers */
4887 for (num = 0, pnext = pfirst; pnext && !errcode;
4888 num++, pnext = PKTNEXT(osh, pnext)) {
4889 dptr = (uint8 *)PKTDATA(osh, pnext);
4890 dlen = (uint16)PKTLEN(osh, pnext);
4891 sublen = ltoh16_ua(dptr);
4892 check = ltoh16_ua(dptr + sizeof(uint16));
4893 chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
4894 doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
4896 if (DHD_GLOM_ON()) {
4897 prhex("subframe", dptr, 32);
4901 if ((uint16)~(sublen^check)) {
4902 DHD_ERROR(("%s (subframe %d): HW hdr error: "
4903 "len/check 0x%04x/0x%04x\n",
4904 __FUNCTION__, num, sublen, check));
4906 } else if ((sublen > dlen) || (sublen < SDPCM_HDRLEN)) {
4907 DHD_ERROR(("%s (subframe %d): length mismatch: "
4908 "len 0x%04x, expect 0x%04x\n",
4909 __FUNCTION__, num, sublen, dlen));
4911 } else if ((chan != SDPCM_DATA_CHANNEL) &&
4912 (chan != SDPCM_EVENT_CHANNEL)) {
4913 DHD_ERROR(("%s (subframe %d): bad channel %d\n",
4914 __FUNCTION__, num, chan));
4916 } else if ((doff < SDPCM_HDRLEN) || (doff > sublen)) {
4917 DHD_ERROR(("%s (subframe %d): Bad data offset %d: HW %d min %d\n",
4918 __FUNCTION__, num, doff, sublen, SDPCM_HDRLEN));
4924 /* Terminate frame on error, request a couple retries */
4925 if (bus->glomerr++ < 3) {
4926 /* Restore superframe header space */
4927 PKTPUSH(osh, pfirst, sfdoff);
4928 dhdsdio_rxfail(bus, TRUE, TRUE);
4931 dhdsdio_rxfail(bus, TRUE, FALSE);
4932 dhd_os_sdlock_rxq(bus->dhd);
4933 PKTFREE(osh, bus->glom, FALSE);
4934 dhd_os_sdunlock_rxq(bus->dhd);
4942 /* Basic SD framing looks ok - process each packet (header) */
4946 dhd_os_sdlock_rxq(bus->dhd);
4947 for (num = 0; pfirst; rxseq++, pfirst = pnext) {
4948 pnext = PKTNEXT(osh, pfirst);
4949 PKTSETNEXT(osh, pfirst, NULL);
4951 dptr = (uint8 *)PKTDATA(osh, pfirst);
4952 sublen = ltoh16_ua(dptr);
4953 chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
4954 seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
4955 doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
4957 DHD_GLOM(("%s: Get subframe %d, %p(%p/%d), sublen %d chan %d seq %d\n",
4958 __FUNCTION__, num, pfirst, PKTDATA(osh, pfirst),
4959 PKTLEN(osh, pfirst), sublen, chan, seq));
4961 ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL));
4964 DHD_GLOM(("%s: rx_seq %d, expected %d\n",
4965 __FUNCTION__, seq, rxseq));
4971 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
4972 prhex("Rx Subframe Data", dptr, dlen);
4976 PKTSETLEN(osh, pfirst, sublen);
4977 PKTPULL(osh, pfirst, doff);
4979 reorder_info_len = sizeof(reorder_info_buf);
4981 if (PKTLEN(osh, pfirst) == 0) {
4982 PKTFREE(bus->dhd->osh, pfirst, FALSE);
4984 } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pfirst, reorder_info_buf,
4985 &reorder_info_len) != 0) {
4986 DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__));
4987 bus->dhd->rx_errors++;
4988 PKTFREE(osh, pfirst, FALSE);
4991 if (reorder_info_len) {
4992 uint32 free_buf_count;
4996 /* Reordering info from the firmware */
4997 dhd_process_pkt_reorder_info(bus->dhd, reorder_info_buf,
4998 reorder_info_len, &ppfirst, &free_buf_count);
5000 if (free_buf_count == 0) {
5006 /* go to the end of the chain and attach the pnext there */
5008 while (PKTNEXT(osh, temp) != NULL) {
5009 temp = PKTNEXT(osh, temp);
5012 if (list_tail[ifidx] == NULL)
5013 list_head[ifidx] = ppfirst;
5015 PKTSETNEXT(osh, list_tail[ifidx], ppfirst);
5016 list_tail[ifidx] = pfirst;
5019 num += (uint8)free_buf_count;
5022 /* this packet will go up, link back into chain and count it */
5024 if (list_tail[ifidx] == NULL) {
5025 list_head[ifidx] = list_tail[ifidx] = pfirst;
5028 PKTSETNEXT(osh, list_tail[ifidx], pfirst);
5029 list_tail[ifidx] = pfirst;
5034 if (DHD_GLOM_ON()) {
5035 DHD_GLOM(("%s subframe %d to stack, %p(%p/%d) nxt/lnk %p/%p\n",
5036 __FUNCTION__, num, pfirst,
5037 PKTDATA(osh, pfirst), PKTLEN(osh, pfirst),
5038 PKTNEXT(osh, pfirst), PKTLINK(pfirst)));
5039 prhex("", (uint8 *)PKTDATA(osh, pfirst),
5040 MIN(PKTLEN(osh, pfirst), 32));
5042 #endif /* DHD_DEBUG */
5044 dhd_os_sdunlock_rxq(bus->dhd);
5046 for (idx = 0; idx < DHD_MAX_IFS; idx++) {
5047 if (list_head[idx]) {
5050 temp = list_head[idx];
5052 temp = PKTNEXT(osh, temp);
5056 dhd_os_sdunlock(bus->dhd);
5057 dhd_rx_frame(bus->dhd, idx, list_head[idx], cnt, 0);
5058 dhd_os_sdlock(bus->dhd);
5062 bus->rxglomframes++;
5063 bus->rxglompkts += num;
5069 /* Return TRUE if there may be more frames to read */
5071 dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished)
5073 osl_t *osh = bus->dhd->osh;
5074 bcmsdh_info_t *sdh = bus->sdh;
5076 uint16 len, check; /* Extracted hardware header fields */
5077 uint8 chan, seq, doff; /* Extracted software header fields */
5078 uint8 fcbits; /* Extracted fcbits from software header */
5081 void *pkt; /* Packet for event or data frames */
5082 uint16 pad; /* Number of pad bytes to read */
5083 uint16 rdlen; /* Total number of bytes to read */
5084 uint8 rxseq; /* Next sequence number to expect */
5085 uint rxleft = 0; /* Remaining number of frames allowed */
5086 int sdret; /* Return code from bcmsdh calls */
5087 uint8 txmax; /* Maximum tx sequence offered */
5088 bool len_consistent; /* Result of comparing readahead len and len from hw-hdr */
5091 uint rxcount = 0; /* Total frames read */
5092 uchar reorder_info_buf[WLHOST_REORDERDATA_TOTLEN];
5093 uint reorder_info_len;
5096 #if defined(DHD_DEBUG) || defined(SDTEST)
5097 bool sdtest = FALSE; /* To limit message spew from test mode */
5100 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5102 bus->readframes = TRUE;
5104 if (!KSO_ENAB(bus)) {
5105 DHD_ERROR(("%s: KSO off\n", __FUNCTION__));
5106 bus->readframes = FALSE;
5113 /* Allow pktgen to override maxframes */
5114 if (bus->pktgen_count && (bus->pktgen_mode == DHD_PKTGEN_RECV)) {
5115 maxframes = bus->pktgen_count;
5120 /* Not finished unless we encounter no more frames indication */
5124 for (rxseq = bus->rx_seq, rxleft = maxframes;
5125 !bus->rxskip && rxleft && bus->dhd->busstate != DHD_BUS_DOWN;
5126 rxseq++, rxleft--) {
5127 #ifdef DHDTCPACK_SUP_DBG
5128 if (bus->dhd->tcpack_sup_mode != TCPACK_SUP_DELAYTX) {
5129 if (bus->dotxinrx == FALSE)
5130 DHD_ERROR(("%s %d: dotxinrx FALSE with tcpack_sub_mode %d\n",
5131 __FUNCTION__, __LINE__, bus->dhd->tcpack_sup_mode));
5133 #ifdef DEBUG_COUNTER
5134 else if (pktq_mlen(&bus->txq, ~bus->flowcontrol) > 0) {
5135 tack_tbl.cnt[bus->dotxinrx ? 6 : 7]++;
5137 #endif /* DEBUG_COUNTER */
5138 #endif /* DHDTCPACK_SUP_DBG */
5139 /* tx more to improve rx performance */
5140 if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL)) {
5141 dhdsdio_sendpendctl(bus);
5142 } else if (bus->dotxinrx && (bus->clkstate == CLK_AVAIL) &&
5143 !bus->fcstate && DATAOK(bus) &&
5144 (pktq_mlen(&bus->txq, ~bus->flowcontrol) > bus->txinrx_thres)) {
5145 dhdsdio_sendfromq(bus, dhd_txbound);
5146 #ifdef DHDTCPACK_SUPPRESS
5147 /* In TCPACK_SUP_DELAYTX mode, do txinrx only if
5148 * 1. Any DATA packet to TX
5149 * 2. TCPACK to TCPDATA PSH packets.
5152 bus->dotxinrx = (bus->dhd->tcpack_sup_mode == TCPACK_SUP_DELAYTX) ?
5157 /* Handle glomming separately */
5158 if (bus->glom || bus->glomd) {
5160 DHD_GLOM(("%s: calling rxglom: glomd %p, glom %p\n",
5161 __FUNCTION__, bus->glomd, bus->glom));
5162 cnt = dhdsdio_rxglom(bus, rxseq);
5163 DHD_GLOM(("%s: rxglom returned %d\n", __FUNCTION__, cnt));
5165 rxleft = (rxleft > cnt) ? (rxleft - cnt) : 1;
5169 /* Try doing single read if we can */
5170 if (dhd_readahead && bus->nextlen) {
5171 uint16 nextlen = bus->nextlen;
5174 if (bus->bus == SPI_BUS) {
5175 rdlen = len = nextlen;
5178 rdlen = len = nextlen << 4;
5180 /* Pad read to blocksize for efficiency */
5181 if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
5182 pad = bus->blocksize - (rdlen % bus->blocksize);
5183 if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
5184 ((rdlen + pad + firstread) < MAX_RX_DATASZ))
5186 } else if (rdlen % DHD_SDALIGN) {
5187 rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
5191 /* We use bus->rxctl buffer in WinXP for initial control pkt receives.
5192 * Later we use buffer-poll for data as well as control packets.
5193 * This is required because dhd receives full frame in gSPI unlike SDIO.
5194 * After the frame is received we have to distinguish whether it is data
5195 * or non-data frame.
5197 /* Allocate a packet buffer */
5198 dhd_os_sdlock_rxq(bus->dhd);
5199 if (!(pkt = PKTGET(osh, rdlen + DHD_SDALIGN, FALSE))) {
5200 if (bus->bus == SPI_BUS) {
5201 bus->usebufpool = FALSE;
5202 bus->rxctl = bus->rxbuf;
5204 bus->rxctl += firstread;
5205 if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN)))
5206 bus->rxctl += (DHD_SDALIGN - pad);
5207 bus->rxctl -= firstread;
5209 ASSERT(bus->rxctl >= bus->rxbuf);
5211 /* Read the entire frame */
5212 sdret = dhd_bcmsdh_recv_buf(bus,
5213 bcmsdh_cur_sbwad(sdh),
5215 F2SYNC, rxbuf, rdlen,
5218 ASSERT(sdret != BCME_PENDING);
5221 /* Control frame failures need retransmission */
5223 DHD_ERROR(("%s: read %d control bytes failed: %d\n",
5224 __FUNCTION__, rdlen, sdret));
5225 /* dhd.rx_ctlerrs is higher level */
5227 dhd_os_sdunlock_rxq(bus->dhd);
5228 dhdsdio_rxfail(bus, TRUE,
5229 (bus->bus == SPI_BUS) ? FALSE : TRUE);
5233 /* Give up on data, request rtx of events */
5234 DHD_ERROR(("%s (nextlen): PKTGET failed: len %d rdlen %d "
5235 "expected rxseq %d\n",
5236 __FUNCTION__, len, rdlen, rxseq));
5237 /* Just go try again w/normal header read */
5238 dhd_os_sdunlock_rxq(bus->dhd);
5242 if (bus->bus == SPI_BUS)
5243 bus->usebufpool = TRUE;
5245 ASSERT(!PKTLINK(pkt));
5246 PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN);
5247 rxbuf = (uint8 *)PKTDATA(osh, pkt);
5248 /* Read the entire frame */
5249 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh),
5251 F2SYNC, rxbuf, rdlen,
5254 ASSERT(sdret != BCME_PENDING);
5257 DHD_ERROR(("%s (nextlen): read %d bytes failed: %d\n",
5258 __FUNCTION__, rdlen, sdret));
5259 PKTFREE(bus->dhd->osh, pkt, FALSE);
5260 bus->dhd->rx_errors++;
5261 dhd_os_sdunlock_rxq(bus->dhd);
5262 /* Force retry w/normal header read. Don't attempt NAK for
5265 dhdsdio_rxfail(bus, TRUE,
5266 (bus->bus == SPI_BUS) ? FALSE : TRUE);
5270 dhd_os_sdunlock_rxq(bus->dhd);
5272 /* Now check the header */
5273 bcopy(rxbuf, bus->rxhdr, SDPCM_HDRLEN);
5275 /* Extract hardware header fields */
5276 len = ltoh16_ua(bus->rxhdr);
5277 check = ltoh16_ua(bus->rxhdr + sizeof(uint16));
5279 /* All zeros means readahead info was bad */
5281 DHD_INFO(("%s (nextlen): read zeros in HW header???\n",
5283 dhd_os_sdlock_rxq(bus->dhd);
5285 dhd_os_sdunlock_rxq(bus->dhd);
5286 GSPI_PR55150_BAILOUT;
5290 /* Validate check bytes */
5291 if ((uint16)~(len^check)) {
5292 DHD_ERROR(("%s (nextlen): HW hdr error: nextlen/len/check"
5293 " 0x%04x/0x%04x/0x%04x\n", __FUNCTION__, nextlen,
5295 dhd_os_sdlock_rxq(bus->dhd);
5297 dhd_os_sdunlock_rxq(bus->dhd);
5299 dhdsdio_rxfail(bus, FALSE, FALSE);
5300 GSPI_PR55150_BAILOUT;
5304 /* Validate frame length */
5305 if (len < SDPCM_HDRLEN) {
5306 DHD_ERROR(("%s (nextlen): HW hdr length invalid: %d\n",
5307 __FUNCTION__, len));
5308 dhd_os_sdlock_rxq(bus->dhd);
5310 dhd_os_sdunlock_rxq(bus->dhd);
5311 GSPI_PR55150_BAILOUT;
5315 /* Check for consistency with readahead info */
5316 len_consistent = (nextlen != (ROUNDUP(len, 16) >> 4));
5317 if (len_consistent) {
5318 /* Mismatch, force retry w/normal header (may be >4K) */
5319 DHD_ERROR(("%s (nextlen): mismatch, nextlen %d len %d rnd %d; "
5320 "expected rxseq %d\n",
5321 __FUNCTION__, nextlen, len, ROUNDUP(len, 16), rxseq));
5322 dhd_os_sdlock_rxq(bus->dhd);
5324 dhd_os_sdunlock_rxq(bus->dhd);
5325 dhdsdio_rxfail(bus, TRUE, (bus->bus == SPI_BUS) ? FALSE : TRUE);
5326 GSPI_PR55150_BAILOUT;
5331 /* Extract software header fields */
5332 chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5333 seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5334 doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5335 txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5338 bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
5339 if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
5340 DHD_INFO(("%s (nextlen): got frame w/nextlen too large"
5341 " (%d), seq %d\n", __FUNCTION__, bus->nextlen,
5346 bus->dhd->rx_readahead_cnt ++;
5347 /* Handle Flow Control */
5348 fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5351 if (~bus->flowcontrol & fcbits) {
5355 if (bus->flowcontrol & ~fcbits) {
5362 bus->flowcontrol = fcbits;
5365 /* Check and update sequence number */
5367 DHD_INFO(("%s (nextlen): rx_seq %d, expected %d\n",
5368 __FUNCTION__, seq, rxseq));
5373 /* Check window for sanity */
5374 if ((uint8)(txmax - bus->tx_seq) > 0x70) {
5375 DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
5376 __FUNCTION__, txmax, bus->tx_seq));
5377 txmax = bus->tx_max;
5379 bus->tx_max = txmax;
5382 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
5383 prhex("Rx Data", rxbuf, len);
5384 } else if (DHD_HDRS_ON()) {
5385 prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN);
5389 if (chan == SDPCM_CONTROL_CHANNEL) {
5390 if (bus->bus == SPI_BUS) {
5391 dhdsdio_read_control(bus, rxbuf, len, doff);
5392 if (bus->usebufpool) {
5393 dhd_os_sdlock_rxq(bus->dhd);
5394 PKTFREE(bus->dhd->osh, pkt, FALSE);
5395 dhd_os_sdunlock_rxq(bus->dhd);
5399 DHD_ERROR(("%s (nextlen): readahead on control"
5400 " packet %d?\n", __FUNCTION__, seq));
5401 /* Force retry w/normal header read */
5403 dhdsdio_rxfail(bus, FALSE, TRUE);
5404 dhd_os_sdlock_rxq(bus->dhd);
5406 dhd_os_sdunlock_rxq(bus->dhd);
5411 if ((bus->bus == SPI_BUS) && !bus->usebufpool) {
5412 DHD_ERROR(("Received %d bytes on %d channel. Running out of "
5413 "rx pktbuf's or not yet malloced.\n", len, chan));
5417 /* Validate data offset */
5418 if ((doff < SDPCM_HDRLEN) || (doff > len)) {
5419 DHD_ERROR(("%s (nextlen): bad data offset %d: HW len %d min %d\n",
5420 __FUNCTION__, doff, len, SDPCM_HDRLEN));
5421 dhd_os_sdlock_rxq(bus->dhd);
5423 dhd_os_sdunlock_rxq(bus->dhd);
5425 dhdsdio_rxfail(bus, FALSE, FALSE);
5429 /* All done with this one -- now deliver the packet */
5432 /* gSPI frames should not be handled in fractions */
5433 if (bus->bus == SPI_BUS) {
5437 /* Read frame header (hardware and software) */
5438 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
5439 bus->rxhdr, firstread, NULL, NULL, NULL);
5441 ASSERT(sdret != BCME_PENDING);
5444 DHD_ERROR(("%s: RXHEADER FAILED: %d\n", __FUNCTION__, sdret));
5446 dhdsdio_rxfail(bus, TRUE, TRUE);
5451 if (DHD_BYTES_ON() || DHD_HDRS_ON()) {
5452 prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN);
5456 /* Extract hardware header fields */
5457 len = ltoh16_ua(bus->rxhdr);
5458 check = ltoh16_ua(bus->rxhdr + sizeof(uint16));
5460 /* All zeros means no more frames */
5466 /* Validate check bytes */
5467 if ((uint16)~(len^check)) {
5468 DHD_ERROR(("%s: HW hdr error: len/check 0x%04x/0x%04x\n",
5469 __FUNCTION__, len, check));
5471 dhdsdio_rxfail(bus, FALSE, FALSE);
5475 /* Validate frame length */
5476 if (len < SDPCM_HDRLEN) {
5477 DHD_ERROR(("%s: HW hdr length invalid: %d\n", __FUNCTION__, len));
5481 /* Extract software header fields */
5482 chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5483 seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5484 doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5485 txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5487 /* Validate data offset */
5488 if ((doff < SDPCM_HDRLEN) || (doff > len)) {
5489 DHD_ERROR(("%s: Bad data offset %d: HW len %d, min %d seq %d\n",
5490 __FUNCTION__, doff, len, SDPCM_HDRLEN, seq));
5493 dhdsdio_rxfail(bus, FALSE, FALSE);
5497 /* Save the readahead length if there is one */
5498 bus->nextlen = bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
5499 if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
5500 DHD_INFO(("%s (nextlen): got frame w/nextlen too large (%d), seq %d\n",
5501 __FUNCTION__, bus->nextlen, seq));
5505 /* Handle Flow Control */
5506 fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5509 if (~bus->flowcontrol & fcbits) {
5513 if (bus->flowcontrol & ~fcbits) {
5520 bus->flowcontrol = fcbits;
5523 /* Check and update sequence number */
5525 DHD_INFO(("%s: rx_seq %d, expected %d\n", __FUNCTION__, seq, rxseq));
5530 /* Check window for sanity */
5531 if ((uint8)(txmax - bus->tx_seq) > 0x70) {
5532 DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
5533 __FUNCTION__, txmax, bus->tx_seq));
5534 txmax = bus->tx_max;
5536 bus->tx_max = txmax;
5538 /* Call a separate function for control frames */
5539 if (chan == SDPCM_CONTROL_CHANNEL) {
5540 dhdsdio_read_control(bus, bus->rxhdr, len, doff);
5544 ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL) ||
5545 (chan == SDPCM_TEST_CHANNEL) || (chan == SDPCM_GLOM_CHANNEL));
5547 /* Length to read */
5548 rdlen = (len > firstread) ? (len - firstread) : 0;
5550 /* May pad read to blocksize for efficiency */
5551 if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
5552 pad = bus->blocksize - (rdlen % bus->blocksize);
5553 if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
5554 ((rdlen + pad + firstread) < MAX_RX_DATASZ))
5556 } else if (rdlen % DHD_SDALIGN) {
5557 rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
5560 /* Satisfy length-alignment requirements */
5561 if (forcealign && (rdlen & (ALIGNMENT - 1)))
5562 rdlen = ROUNDUP(rdlen, ALIGNMENT);
5564 if ((rdlen + firstread) > MAX_RX_DATASZ) {
5565 /* Too long -- skip this frame */
5566 DHD_ERROR(("%s: too long: len %d rdlen %d\n", __FUNCTION__, len, rdlen));
5567 bus->dhd->rx_errors++; bus->rx_toolong++;
5568 dhdsdio_rxfail(bus, FALSE, FALSE);
5572 dhd_os_sdlock_rxq(bus->dhd);
5573 if (!(pkt = PKTGET(osh, (rdlen + firstread + DHD_SDALIGN), FALSE))) {
5574 /* Give up on data, request rtx of events */
5575 DHD_ERROR(("%s: PKTGET failed: rdlen %d chan %d\n",
5576 __FUNCTION__, rdlen, chan));
5577 bus->dhd->rx_dropped++;
5578 dhd_os_sdunlock_rxq(bus->dhd);
5579 dhdsdio_rxfail(bus, FALSE, RETRYCHAN(chan));
5582 dhd_os_sdunlock_rxq(bus->dhd);
5584 ASSERT(!PKTLINK(pkt));
5586 /* Leave room for what we already read, and align remainder */
5587 ASSERT(firstread < (PKTLEN(osh, pkt)));
5588 PKTPULL(osh, pkt, firstread);
5589 PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN);
5591 /* Read the remaining frame data */
5592 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
5593 ((uint8 *)PKTDATA(osh, pkt)), rdlen, pkt, NULL, NULL);
5595 ASSERT(sdret != BCME_PENDING);
5598 DHD_ERROR(("%s: read %d %s bytes failed: %d\n", __FUNCTION__, rdlen,
5599 ((chan == SDPCM_EVENT_CHANNEL) ? "event" :
5600 ((chan == SDPCM_DATA_CHANNEL) ? "data" : "test")), sdret));
5601 dhd_os_sdlock_rxq(bus->dhd);
5602 PKTFREE(bus->dhd->osh, pkt, FALSE);
5603 dhd_os_sdunlock_rxq(bus->dhd);
5604 bus->dhd->rx_errors++;
5605 dhdsdio_rxfail(bus, TRUE, RETRYCHAN(chan));
5609 /* Copy the already-read portion */
5610 PKTPUSH(osh, pkt, firstread);
5611 bcopy(bus->rxhdr, PKTDATA(osh, pkt), firstread);
5614 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
5615 prhex("Rx Data", PKTDATA(osh, pkt), len);
5620 /* Save superframe descriptor and allocate packet frame */
5621 if (chan == SDPCM_GLOM_CHANNEL) {
5622 if (SDPCM_GLOMDESC(&bus->rxhdr[SDPCM_FRAMETAG_LEN])) {
5623 DHD_GLOM(("%s: got glom descriptor, %d bytes:\n",
5624 __FUNCTION__, len));
5626 if (DHD_GLOM_ON()) {
5627 prhex("Glom Data", PKTDATA(osh, pkt), len);
5630 PKTSETLEN(osh, pkt, len);
5631 ASSERT(doff == SDPCM_HDRLEN);
5632 PKTPULL(osh, pkt, SDPCM_HDRLEN);
5635 DHD_ERROR(("%s: glom superframe w/o descriptor!\n", __FUNCTION__));
5636 dhdsdio_rxfail(bus, FALSE, FALSE);
5641 /* Fill in packet len and prio, deliver upward */
5642 PKTSETLEN(osh, pkt, len);
5643 PKTPULL(osh, pkt, doff);
5646 /* Test channel packets are processed separately */
5647 if (chan == SDPCM_TEST_CHANNEL) {
5648 dhdsdio_testrcv(bus, pkt, seq);
5653 if (PKTLEN(osh, pkt) == 0) {
5654 dhd_os_sdlock_rxq(bus->dhd);
5655 PKTFREE(bus->dhd->osh, pkt, FALSE);
5656 dhd_os_sdunlock_rxq(bus->dhd);
5658 } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pkt, reorder_info_buf,
5659 &reorder_info_len) != 0) {
5660 DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__));
5661 dhd_os_sdlock_rxq(bus->dhd);
5662 PKTFREE(bus->dhd->osh, pkt, FALSE);
5663 dhd_os_sdunlock_rxq(bus->dhd);
5664 bus->dhd->rx_errors++;
5667 if (reorder_info_len) {
5668 /* Reordering info from the firmware */
5669 dhd_process_pkt_reorder_info(bus->dhd, reorder_info_buf, reorder_info_len,
5677 /* Unlock during rx call */
5678 dhd_os_sdunlock(bus->dhd);
5679 dhd_rx_frame(bus->dhd, ifidx, pkt, pkt_count, chan);
5680 dhd_os_sdlock(bus->dhd);
5682 rxcount = maxframes - rxleft;
5684 /* Message if we hit the limit */
5685 if (!rxleft && !sdtest)
5686 DHD_DATA(("%s: hit rx limit of %d frames\n", __FUNCTION__, maxframes));
5688 #endif /* DHD_DEBUG */
5689 DHD_DATA(("%s: processed %d frames\n", __FUNCTION__, rxcount));
5690 /* Back off rxseq if awaiting rtx, update rx_seq */
5693 bus->rx_seq = rxseq;
5695 if (bus->reqbussleep)
5697 dhdsdio_bussleep(bus, TRUE);
5698 bus->reqbussleep = FALSE;
5700 bus->readframes = FALSE;
5706 dhdsdio_hostmail(dhd_bus_t *bus)
5708 sdpcmd_regs_t *regs = bus->regs;
5709 uint32 intstatus = 0;
5714 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5716 /* Read mailbox data and ack that we did so */
5717 R_SDREG(hmb_data, ®s->tohostmailboxdata, retries);
5718 if (retries <= retry_limit)
5719 W_SDREG(SMB_INT_ACK, ®s->tosbmailbox, retries);
5720 bus->f1regdata += 2;
5722 /* Dongle recomposed rx frames, accept them again */
5723 if (hmb_data & HMB_DATA_NAKHANDLED) {
5724 DHD_INFO(("Dongle reports NAK handled, expect rtx of %d\n", bus->rx_seq));
5726 DHD_ERROR(("%s: unexpected NAKHANDLED!\n", __FUNCTION__));
5728 bus->rxskip = FALSE;
5729 intstatus |= FRAME_AVAIL_MASK(bus);
5733 * DEVREADY does not occur with gSPI.
5735 if (hmb_data & (HMB_DATA_DEVREADY | HMB_DATA_FWREADY)) {
5736 bus->sdpcm_ver = (hmb_data & HMB_DATA_VERSION_MASK) >> HMB_DATA_VERSION_SHIFT;
5737 if (bus->sdpcm_ver != SDPCM_PROT_VERSION)
5738 DHD_ERROR(("Version mismatch, dongle reports %d, expecting %d\n",
5739 bus->sdpcm_ver, SDPCM_PROT_VERSION));
5741 DHD_INFO(("Dongle ready, protocol version %d\n", bus->sdpcm_ver));
5742 /* make sure for the SDIO_DEVICE_RXDATAINT_MODE_1 corecontrol is proper */
5743 if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev >= 4) &&
5744 (bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_1)) {
5747 val = R_REG(bus->dhd->osh, &bus->regs->corecontrol);
5748 val &= ~CC_XMTDATAAVAIL_MODE;
5749 val |= CC_XMTDATAAVAIL_CTRL;
5750 W_REG(bus->dhd->osh, &bus->regs->corecontrol, val);
5752 val = R_REG(bus->dhd->osh, &bus->regs->corecontrol);
5756 /* Retrieve console state address now that firmware should have updated it */
5758 sdpcm_shared_t shared;
5759 if (dhdsdio_readshared(bus, &shared) == 0)
5760 bus->console_addr = shared.console_addr;
5762 #endif /* DHD_DEBUG */
5766 * Flow Control has been moved into the RX headers and this out of band
5767 * method isn't used any more. Leave this here for possibly remaining backward
5768 * compatible with older dongles
5770 if (hmb_data & HMB_DATA_FC) {
5771 fcbits = (hmb_data & HMB_DATA_FCDATA_MASK) >> HMB_DATA_FCDATA_SHIFT;
5773 if (fcbits & ~bus->flowcontrol)
5775 if (bus->flowcontrol & ~fcbits)
5779 bus->flowcontrol = fcbits;
5783 /* At least print a message if FW halted */
5784 if (hmb_data & HMB_DATA_FWHALT) {
5785 DHD_ERROR(("INTERNAL ERROR: FIRMWARE HALTED : set BUS DOWN\n"));
5786 dhdsdio_checkdied(bus, NULL, 0);
5787 bus->dhd->busstate = DHD_BUS_DOWN;
5789 #endif /* DHD_DEBUG */
5791 /* Shouldn't be any others */
5792 if (hmb_data & ~(HMB_DATA_DEVREADY |
5794 HMB_DATA_NAKHANDLED |
5797 HMB_DATA_FCDATA_MASK |
5798 HMB_DATA_VERSION_MASK)) {
5799 DHD_ERROR(("Unknown mailbox data content: 0x%02x\n", hmb_data));
5806 dhdsdio_dpc(dhd_bus_t *bus)
5808 bcmsdh_info_t *sdh = bus->sdh;
5809 sdpcmd_regs_t *regs = bus->regs;
5810 uint32 intstatus, newstatus = 0;
5812 uint rxlimit = dhd_rxbound; /* Rx frames to read before resched */
5813 uint txlimit = dhd_txbound; /* Tx frames to send before resched */
5814 uint framecnt = 0; /* Temporary counter of tx/rx frames */
5815 bool rxdone = TRUE; /* Flag for no more read data */
5816 bool resched = FALSE; /* Flag indicating resched wanted */
5817 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5819 dhd_os_sdlock(bus->dhd);
5821 if (bus->dhd->busstate == DHD_BUS_DOWN) {
5822 DHD_ERROR(("%s: Bus down, ret\n", __FUNCTION__));
5824 dhd_os_sdunlock(bus->dhd);
5828 /* Start with leftover status bits */
5829 intstatus = bus->intstatus;
5831 if (!SLPAUTO_ENAB(bus) && !KSO_ENAB(bus)) {
5832 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
5836 /* If waiting for HTAVAIL, check status */
5837 if (!SLPAUTO_ENAB(bus) && (bus->clkstate == CLK_PENDING)) {
5839 uint8 clkctl, devctl = 0;
5842 /* Check for inconsistent device control */
5843 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
5845 DHD_ERROR(("%s: error reading DEVCTL: %d\n", __FUNCTION__, err));
5846 bus->dhd->busstate = DHD_BUS_DOWN;
5848 ASSERT(devctl & SBSDIO_DEVCTL_CA_INT_ONLY);
5850 #endif /* DHD_DEBUG */
5852 /* Read CSR, if clock on switch to AVAIL, else ignore */
5853 clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
5855 DHD_ERROR(("%s: error reading CSR: %d\n", __FUNCTION__, err));
5856 bus->dhd->busstate = DHD_BUS_DOWN;
5859 DHD_INFO(("DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n", devctl, clkctl));
5861 if (SBSDIO_HTAV(clkctl)) {
5862 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
5864 DHD_ERROR(("%s: error reading DEVCTL: %d\n",
5865 __FUNCTION__, err));
5866 bus->dhd->busstate = DHD_BUS_DOWN;
5868 devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
5869 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
5871 DHD_ERROR(("%s: error writing DEVCTL: %d\n",
5872 __FUNCTION__, err));
5873 bus->dhd->busstate = DHD_BUS_DOWN;
5875 bus->clkstate = CLK_AVAIL;
5883 /* Make sure backplane clock is on */
5884 dhdsdio_clkctl(bus, CLK_AVAIL, TRUE);
5885 if (bus->clkstate != CLK_AVAIL)
5888 /* Pending interrupt indicates new device status */
5891 R_SDREG(newstatus, ®s->intstatus, retries);
5893 if (bcmsdh_regfail(bus->sdh))
5895 newstatus &= bus->hostintmask;
5896 bus->fcstate = !!(newstatus & I_HMB_FC_STATE);
5899 if ((bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_0) &&
5900 (newstatus == I_XMTDATA_AVAIL)) {
5903 W_SDREG(newstatus, ®s->intstatus, retries);
5907 /* Merge new bits with previous */
5908 intstatus |= newstatus;
5911 /* Handle flow-control change: read new state in case our ack
5912 * crossed another change interrupt. If change still set, assume
5913 * FC ON for safety, let next loop through do the debounce.
5915 if (intstatus & I_HMB_FC_CHANGE) {
5916 intstatus &= ~I_HMB_FC_CHANGE;
5917 W_SDREG(I_HMB_FC_CHANGE, ®s->intstatus, retries);
5918 R_SDREG(newstatus, ®s->intstatus, retries);
5919 bus->f1regdata += 2;
5920 bus->fcstate = !!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE));
5921 intstatus |= (newstatus & bus->hostintmask);
5924 /* Just being here means nothing more to do for chipactive */
5925 if (intstatus & I_CHIPACTIVE) {
5926 /* ASSERT(bus->clkstate == CLK_AVAIL); */
5927 intstatus &= ~I_CHIPACTIVE;
5930 /* Handle host mailbox indication */
5931 if (intstatus & I_HMB_HOST_INT) {
5932 intstatus &= ~I_HMB_HOST_INT;
5933 intstatus |= dhdsdio_hostmail(bus);
5936 /* Generally don't ask for these, can get CRC errors... */
5937 if (intstatus & I_WR_OOSYNC) {
5938 DHD_ERROR(("Dongle reports WR_OOSYNC\n"));
5939 intstatus &= ~I_WR_OOSYNC;
5942 if (intstatus & I_RD_OOSYNC) {
5943 DHD_ERROR(("Dongle reports RD_OOSYNC\n"));
5944 intstatus &= ~I_RD_OOSYNC;
5947 if (intstatus & I_SBINT) {
5948 DHD_ERROR(("Dongle reports SBINT\n"));
5949 intstatus &= ~I_SBINT;
5952 /* Would be active due to wake-wlan in gSPI */
5953 if (intstatus & I_CHIPACTIVE) {
5954 DHD_INFO(("Dongle reports CHIPACTIVE\n"));
5955 intstatus &= ~I_CHIPACTIVE;
5958 if (intstatus & I_HMB_FC_STATE) {
5959 DHD_INFO(("Dongle reports HMB_FC_STATE\n"));
5960 intstatus &= ~I_HMB_FC_STATE;
5963 /* Ignore frame indications if rxskip is set */
5965 intstatus &= ~FRAME_AVAIL_MASK(bus);
5968 /* On frame indication, read available frames */
5969 if (PKT_AVAILABLE(bus, intstatus)) {
5970 framecnt = dhdsdio_readframes(bus, rxlimit, &rxdone);
5971 if (rxdone || bus->rxskip)
5972 intstatus &= ~FRAME_AVAIL_MASK(bus);
5973 rxlimit -= MIN(framecnt, rxlimit);
5976 /* Keep still-pending events for next scheduling */
5977 bus->intstatus = intstatus;
5980 /* Re-enable interrupts to detect new device events (mailbox, rx frame)
5981 * or clock availability. (Allows tx loop to check ipend if desired.)
5982 * (Unless register access seems hosed, as we may not be able to ACK...)
5984 if (bus->intr && bus->intdis && !bcmsdh_regfail(sdh)) {
5985 DHD_INTR(("%s: enable SDIO interrupts, rxdone %d framecnt %d\n",
5986 __FUNCTION__, rxdone, framecnt));
5987 bus->intdis = FALSE;
5988 #if defined(OOB_INTR_ONLY)
5989 bcmsdh_oob_intr_set(bus->sdh, TRUE);
5990 #endif /* defined(OOB_INTR_ONLY) */
5991 #if !defined(NDISVER) || (NDISVER < 0x0630)
5992 bcmsdh_intr_enable(sdh);
5993 #endif /* !defined(NDISVER) || (NDISVER < 0x0630) */
5996 #if defined(OOB_INTR_ONLY) && !defined(HW_OOB)
5997 /* In case of SW-OOB(using edge trigger),
5998 * Check interrupt status in the dongle again after enable irq on the host.
5999 * and rechedule dpc if interrupt is pended in the dongle.
6000 * There is a chance to miss OOB interrupt while irq is disabled on the host.
6001 * No need to do this with HW-OOB(level trigger)
6003 R_SDREG(newstatus, ®s->intstatus, retries);
6004 if (bcmsdh_regfail(bus->sdh))
6006 if (newstatus & bus->hostintmask) {
6010 #endif /* defined(OOB_INTR_ONLY) && !defined(HW_OOB) */
6012 #ifdef PROP_TXSTATUS
6013 dhd_wlfc_commit_packets(bus->dhd, (f_commitpkt_t)dhd_bus_txdata, (void *)bus, NULL, FALSE);
6016 if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL))
6017 dhdsdio_sendpendctl(bus);
6019 /* Send queued frames (limit 1 if rx may still be pending) */
6020 else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate &&
6021 pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit && DATAOK(bus)) {
6022 framecnt = rxdone ? txlimit : MIN(txlimit, dhd_txminmax);
6023 framecnt = dhdsdio_sendfromq(bus, framecnt);
6024 txlimit -= framecnt;
6026 /* Resched the DPC if ctrl cmd is pending on bus credit */
6027 if (bus->ctrl_frame_stat)
6030 /* Resched if events or tx frames are pending, else await next interrupt */
6031 /* On failed register access, all bets are off: no resched or interrupts */
6032 if ((bus->dhd->busstate == DHD_BUS_DOWN) || bcmsdh_regfail(sdh)) {
6033 if ((bus->sih && bus->sih->buscorerev >= 12) && !(dhdsdio_sleepcsr_get(bus) &
6034 SBSDIO_FUNC1_SLEEPCSR_KSO_MASK)) {
6035 /* Bus failed because of KSO */
6036 DHD_ERROR(("%s: Bus failed due to KSO\n", __FUNCTION__));
6039 DHD_ERROR(("%s: failed backplane access over SDIO, halting operation\n",
6041 bus->dhd->busstate = DHD_BUS_DOWN;
6044 } else if (bus->clkstate == CLK_PENDING) {
6045 /* Awaiting I_CHIPACTIVE; don't resched */
6046 } else if (bus->intstatus || bus->ipend ||
6047 (!bus->fcstate && pktq_mlen(&bus->txq, ~bus->flowcontrol) && DATAOK(bus)) ||
6048 PKT_AVAILABLE(bus, bus->intstatus)) { /* Read multiple frames */
6052 bus->dpc_sched = resched;
6054 /* If we're done for now, turn off clock request. */
6055 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && (bus->clkstate != CLK_PENDING)) {
6056 bus->activity = FALSE;
6057 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
6062 if (!resched && dhd_dpcpoll) {
6063 if (dhdsdio_readframes(bus, dhd_rxbound, &rxdone) != 0)
6067 dhd_os_sdunlock(bus->dhd);
6072 dhd_bus_dpc(struct dhd_bus *bus)
6076 /* Call the DPC directly. */
6077 DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__));
6078 resched = dhdsdio_dpc(bus);
6084 dhdsdio_isr(void *arg)
6086 dhd_bus_t *bus = (dhd_bus_t*)arg;
6089 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
6092 DHD_ERROR(("%s : bus is null pointer , exit \n", __FUNCTION__));
6097 if (bus->dhd->busstate == DHD_BUS_DOWN) {
6098 DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__));
6102 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
6104 /* Count the interrupt call */
6108 /* Shouldn't get this interrupt if we're sleeping? */
6109 if (!SLPAUTO_ENAB(bus)) {
6110 if (bus->sleeping) {
6111 DHD_ERROR(("INTERRUPT WHILE SLEEPING??\n"));
6113 } else if (!KSO_ENAB(bus)) {
6114 DHD_ERROR(("ISR in devsleep 1\n"));
6118 /* Disable additional interrupts (is this needed now)? */
6120 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
6122 DHD_ERROR(("dhdsdio_isr() w/o interrupt configured!\n"));
6125 #if !defined(NDISVER) || (NDISVER < 0x0630)
6126 bcmsdh_intr_disable(sdh);
6127 #endif /* !defined(NDISVER) || (NDISVER < 0x0630) */
6130 #if defined(SDIO_ISR_THREAD)
6131 DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__));
6132 DHD_OS_WAKE_LOCK(bus->dhd);
6133 /* terence 20150209: dpc should be scheded again if dpc_sched is TRUE or dhd_bus_txdata can
6134 not schedule anymore because dpc_sched is TRUE now.
6136 if (dhdsdio_dpc(bus)) {
6137 bus->dpc_sched = TRUE;
6138 dhd_sched_dpc(bus->dhd);
6140 DHD_OS_WAKE_UNLOCK(bus->dhd);
6143 #if !defined(NDISVER) || (NDISVER < 0x0630)
6144 bus->dpc_sched = TRUE;
6145 dhd_sched_dpc(bus->dhd);
6146 #endif /* !defined(NDISVER) || (NDISVER < 0x0630) */
6148 #endif /* defined(SDIO_ISR_THREAD) */
6154 dhdsdio_pktgen_init(dhd_bus_t *bus)
6156 /* Default to specified length, or full range */
6157 if (dhd_pktgen_len) {
6158 bus->pktgen_maxlen = MIN(dhd_pktgen_len, MAX_PKTGEN_LEN);
6159 bus->pktgen_minlen = bus->pktgen_maxlen;
6161 bus->pktgen_maxlen = MAX_PKTGEN_LEN;
6162 bus->pktgen_minlen = 0;
6164 bus->pktgen_len = (uint16)bus->pktgen_minlen;
6166 /* Default to per-watchdog burst with 10s print time */
6167 bus->pktgen_freq = 1;
6168 bus->pktgen_print = dhd_watchdog_ms ? (10000 / dhd_watchdog_ms) : 0;
6169 bus->pktgen_count = (dhd_pktgen * dhd_watchdog_ms + 999) / 1000;
6171 /* Default to echo mode */
6172 bus->pktgen_mode = DHD_PKTGEN_ECHO;
6173 bus->pktgen_stop = 1;
6177 dhdsdio_pktgen(dhd_bus_t *bus)
6183 osl_t *osh = bus->dhd->osh;
6189 /* Display current count if appropriate */
6190 if (bus->pktgen_print && (++bus->pktgen_ptick >= bus->pktgen_print)) {
6191 bus->pktgen_ptick = 0;
6192 printf("%s: send attempts %d, rcvd %d, errors %d\n",
6193 __FUNCTION__, bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail);
6195 /* Print throughput stats only for constant length packet runs */
6196 if (bus->pktgen_minlen == bus->pktgen_maxlen) {
6197 time_lapse = jiffies - bus->pktgen_prev_time;
6198 bus->pktgen_prev_time = jiffies;
6199 sent_pkts = bus->pktgen_sent - bus->pktgen_prev_sent;
6200 bus->pktgen_prev_sent = bus->pktgen_sent;
6201 rcvd_pkts = bus->pktgen_rcvd - bus->pktgen_prev_rcvd;
6202 bus->pktgen_prev_rcvd = bus->pktgen_rcvd;
6204 printf("%s: Tx Throughput %d kbps, Rx Throughput %d kbps\n",
6206 (sent_pkts * bus->pktgen_len / jiffies_to_msecs(time_lapse)) * 8,
6207 (rcvd_pkts * bus->pktgen_len / jiffies_to_msecs(time_lapse)) * 8);
6211 /* For recv mode, just make sure dongle has started sending */
6212 if (bus->pktgen_mode == DHD_PKTGEN_RECV) {
6213 if (bus->pktgen_rcv_state == PKTGEN_RCV_IDLE) {
6214 bus->pktgen_rcv_state = PKTGEN_RCV_ONGOING;
6215 dhdsdio_sdtest_set(bus, bus->pktgen_total);
6220 /* Otherwise, generate or request the specified number of packets */
6221 for (pktcount = 0; pktcount < bus->pktgen_count; pktcount++) {
6222 /* Stop if total has been reached */
6223 if (bus->pktgen_total && (bus->pktgen_sent >= bus->pktgen_total)) {
6224 bus->pktgen_count = 0;
6228 /* Allocate an appropriate-sized packet */
6229 if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) {
6230 len = SDPCM_TEST_PKT_CNT_FLD_LEN;
6232 len = bus->pktgen_len;
6234 if (!(pkt = PKTGET(osh, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN),
6236 DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__));
6239 PKTALIGN(osh, pkt, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN), DHD_SDALIGN);
6240 data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
6242 /* Write test header cmd and extra based on mode */
6243 switch (bus->pktgen_mode) {
6244 case DHD_PKTGEN_ECHO:
6245 *data++ = SDPCM_TEST_ECHOREQ;
6246 *data++ = (uint8)bus->pktgen_sent;
6249 case DHD_PKTGEN_SEND:
6250 *data++ = SDPCM_TEST_DISCARD;
6251 *data++ = (uint8)bus->pktgen_sent;
6254 case DHD_PKTGEN_RXBURST:
6255 *data++ = SDPCM_TEST_BURST;
6256 *data++ = (uint8)bus->pktgen_count; /* Just for backward compatability */
6260 DHD_ERROR(("Unrecognized pktgen mode %d\n", bus->pktgen_mode));
6261 PKTFREE(osh, pkt, TRUE);
6262 bus->pktgen_count = 0;
6266 /* Write test header length field */
6267 *data++ = (bus->pktgen_len >> 0);
6268 *data++ = (bus->pktgen_len >> 8);
6270 /* Write frame count in a 4 byte field adjucent to SDPCM test header for
6273 if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) {
6274 *data++ = (uint8)(bus->pktgen_count >> 0);
6275 *data++ = (uint8)(bus->pktgen_count >> 8);
6276 *data++ = (uint8)(bus->pktgen_count >> 16);
6277 *data++ = (uint8)(bus->pktgen_count >> 24);
6280 /* Then fill in the remainder -- N/A for burst */
6281 for (fillbyte = 0; fillbyte < len; fillbyte++)
6282 *data++ = SDPCM_TEST_FILL(fillbyte, (uint8)bus->pktgen_sent);
6286 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
6287 data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
6288 prhex("dhdsdio_pktgen: Tx Data", data, PKTLEN(osh, pkt) - SDPCM_HDRLEN);
6293 if (dhdsdio_txpkt(bus, SDPCM_TEST_CHANNEL, &pkt, 1, TRUE) != BCME_OK) {
6295 if (bus->pktgen_stop && bus->pktgen_stop == bus->pktgen_fail)
6296 bus->pktgen_count = 0;
6300 /* Bump length if not fixed, wrap at max */
6301 if (++bus->pktgen_len > bus->pktgen_maxlen)
6302 bus->pktgen_len = (uint16)bus->pktgen_minlen;
6304 /* Special case for burst mode: just send one request! */
6305 if (bus->pktgen_mode == DHD_PKTGEN_RXBURST)
6311 dhdsdio_sdtest_set(dhd_bus_t *bus, uint count)
6315 osl_t *osh = bus->dhd->osh;
6317 /* Allocate the packet */
6318 if (!(pkt = PKTGET(osh, SDPCM_HDRLEN + SDPCM_TEST_HDRLEN +
6319 SDPCM_TEST_PKT_CNT_FLD_LEN + DHD_SDALIGN, TRUE))) {
6320 DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__));
6323 PKTALIGN(osh, pkt, (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN +
6324 SDPCM_TEST_PKT_CNT_FLD_LEN), DHD_SDALIGN);
6325 data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
6327 /* Fill in the test header */
6328 *data++ = SDPCM_TEST_SEND;
6329 *data++ = (count > 0)?TRUE:FALSE;
6330 *data++ = (bus->pktgen_maxlen >> 0);
6331 *data++ = (bus->pktgen_maxlen >> 8);
6332 *data++ = (uint8)(count >> 0);
6333 *data++ = (uint8)(count >> 8);
6334 *data++ = (uint8)(count >> 16);
6335 *data++ = (uint8)(count >> 24);
6338 if (dhdsdio_txpkt(bus, SDPCM_TEST_CHANNEL, &pkt, 1, TRUE) != BCME_OK)
6344 dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq)
6346 osl_t *osh = bus->dhd->osh;
6355 /* Check for min length */
6356 if ((pktlen = PKTLEN(osh, pkt)) < SDPCM_TEST_HDRLEN) {
6357 DHD_ERROR(("dhdsdio_restrcv: toss runt frame, pktlen %d\n", pktlen));
6358 PKTFREE(osh, pkt, FALSE);
6362 /* Extract header fields */
6363 data = PKTDATA(osh, pkt);
6366 len = *data++; len += *data++ << 8;
6367 DHD_TRACE(("%s:cmd:%d, xtra:%d,len:%d\n", __FUNCTION__, cmd, extra, len));
6368 /* Check length for relevant commands */
6369 if (cmd == SDPCM_TEST_DISCARD || cmd == SDPCM_TEST_ECHOREQ || cmd == SDPCM_TEST_ECHORSP) {
6370 if (pktlen != len + SDPCM_TEST_HDRLEN) {
6371 DHD_ERROR(("dhdsdio_testrcv: frame length mismatch, pktlen %d seq %d"
6372 " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len));
6373 PKTFREE(osh, pkt, FALSE);
6378 /* Process as per command */
6380 case SDPCM_TEST_ECHOREQ:
6381 /* Rx->Tx turnaround ok (even on NDIS w/current implementation) */
6382 *(uint8 *)(PKTDATA(osh, pkt)) = SDPCM_TEST_ECHORSP;
6383 if (dhdsdio_txpkt(bus, SDPCM_TEST_CHANNEL, &pkt, 1, TRUE) == BCME_OK) {
6387 PKTFREE(osh, pkt, FALSE);
6392 case SDPCM_TEST_ECHORSP:
6393 if (bus->ext_loop) {
6394 PKTFREE(osh, pkt, FALSE);
6399 for (offset = 0; offset < len; offset++, data++) {
6400 if (*data != SDPCM_TEST_FILL(offset, extra)) {
6401 DHD_ERROR(("dhdsdio_testrcv: echo data mismatch: "
6402 "offset %d (len %d) expect 0x%02x rcvd 0x%02x\n",
6403 offset, len, SDPCM_TEST_FILL(offset, extra), *data));
6407 PKTFREE(osh, pkt, FALSE);
6411 case SDPCM_TEST_DISCARD:
6415 uint8 testval = extra;
6416 for (i = 0; i < len; i++) {
6417 if (*prn != testval) {
6418 DHD_ERROR(("DIErr@Pkt#:%d,Ix:%d, expected:0x%x, got:0x%x\n",
6419 i, bus->pktgen_rcvd_rcvsession, testval, *prn));
6424 PKTFREE(osh, pkt, FALSE);
6428 case SDPCM_TEST_BURST:
6429 case SDPCM_TEST_SEND:
6431 DHD_INFO(("dhdsdio_testrcv: unsupported or unknown command, pktlen %d seq %d"
6432 " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len));
6433 PKTFREE(osh, pkt, FALSE);
6437 /* For recv mode, stop at limit (and tell dongle to stop sending) */
6438 if (bus->pktgen_mode == DHD_PKTGEN_RECV) {
6439 if (bus->pktgen_rcv_state != PKTGEN_RCV_IDLE) {
6440 bus->pktgen_rcvd_rcvsession++;
6442 if (bus->pktgen_total &&
6443 (bus->pktgen_rcvd_rcvsession >= bus->pktgen_total)) {
6444 bus->pktgen_count = 0;
6445 DHD_ERROR(("Pktgen:rcv test complete!\n"));
6446 bus->pktgen_rcv_state = PKTGEN_RCV_IDLE;
6447 dhdsdio_sdtest_set(bus, FALSE);
6448 bus->pktgen_rcvd_rcvsession = 0;
6455 int dhd_bus_oob_intr_register(dhd_pub_t *dhdp)
6459 #if defined(OOB_INTR_ONLY)
6460 err = bcmsdh_oob_intr_register(dhdp->bus->sdh, dhdsdio_isr, dhdp->bus);
6465 void dhd_bus_oob_intr_unregister(dhd_pub_t *dhdp)
6467 #if defined(OOB_INTR_ONLY)
6468 bcmsdh_oob_intr_unregister(dhdp->bus->sdh);
6472 void dhd_bus_oob_intr_set(dhd_pub_t *dhdp, bool enable)
6474 #if defined(OOB_INTR_ONLY)
6475 bcmsdh_oob_intr_set(dhdp->bus->sdh, enable);
6479 void dhd_bus_dev_pm_stay_awake(dhd_pub_t *dhdpub)
6481 bcmsdh_dev_pm_stay_awake(dhdpub->bus->sdh);
6484 void dhd_bus_dev_pm_relax(dhd_pub_t *dhdpub)
6486 bcmsdh_dev_relax(dhdpub->bus->sdh);
6489 bool dhd_bus_dev_pm_enabled(dhd_pub_t *dhdpub)
6491 bool enabled = FALSE;
6493 enabled = bcmsdh_dev_pm_enabled(dhdpub->bus->sdh);
6498 dhd_bus_watchdog(dhd_pub_t *dhdp)
6502 DHD_TIMER(("%s: Enter\n", __FUNCTION__));
6506 if (bus->dhd->dongle_reset)
6509 if (bus->dhd->hang_was_sent) {
6510 dhd_os_wd_timer(bus->dhd, 0);
6514 /* Ignore the timer if simulating bus down */
6515 if (!SLPAUTO_ENAB(bus) && bus->sleeping)
6518 if (dhdp->busstate == DHD_BUS_DOWN)
6521 dhd_os_sdlock(bus->dhd);
6523 /* Poll period: check device if appropriate. */
6524 if (!SLPAUTO_ENAB(bus) && (bus->poll && (++bus->polltick >= bus->pollrate))) {
6525 uint32 intstatus = 0;
6527 /* Reset poll tick */
6530 /* Check device if no interrupts */
6531 if (!bus->intr || (bus->intrcount == bus->lastintrs)) {
6533 if (!bus->dpc_sched) {
6535 devpend = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0,
6536 SDIOD_CCCR_INTPEND, NULL);
6537 intstatus = devpend & (INTR_STATUS_FUNC1 | INTR_STATUS_FUNC2);
6540 /* If there is something, make like the ISR and schedule the DPC */
6545 bcmsdh_intr_disable(bus->sdh);
6547 bus->dpc_sched = TRUE;
6548 dhd_sched_dpc(bus->dhd);
6552 /* Update interrupt tracking */
6553 bus->lastintrs = bus->intrcount;
6557 /* Poll for console output periodically */
6558 if (dhdp->busstate == DHD_BUS_DATA && dhd_console_ms != 0) {
6559 bus->console.count += dhd_watchdog_ms;
6560 if (bus->console.count >= dhd_console_ms) {
6561 bus->console.count -= dhd_console_ms;
6562 /* Make sure backplane clock is on */
6563 if (SLPAUTO_ENAB(bus))
6564 dhdsdio_bussleep(bus, FALSE);
6566 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
6567 if (dhdsdio_readconsole(bus) < 0)
6568 dhd_console_ms = 0; /* On error, stop trying */
6571 #endif /* DHD_DEBUG */
6574 /* Generate packets if configured */
6575 if (bus->pktgen_count && (++bus->pktgen_tick >= bus->pktgen_freq)) {
6576 /* Make sure backplane clock is on */
6577 if (SLPAUTO_ENAB(bus))
6578 dhdsdio_bussleep(bus, FALSE);
6580 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
6581 bus->pktgen_tick = 0;
6582 dhdsdio_pktgen(bus);
6586 /* On idle timeout clear activity flag and/or turn off clock */
6587 #ifdef DHD_USE_IDLECOUNT
6589 bus->activity = FALSE;
6593 if ((bus->idletime > 0) && (bus->idlecount >= bus->idletime)) {
6594 DHD_TIMER(("%s: DHD Idle state!!\n", __FUNCTION__));
6595 if (SLPAUTO_ENAB(bus)) {
6596 if (dhdsdio_bussleep(bus, TRUE) != BCME_BUSY)
6597 dhd_os_wd_timer(bus->dhd, 0);
6599 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
6605 if ((bus->idletime > 0) && (bus->clkstate == CLK_AVAIL)) {
6606 if (++bus->idlecount >= bus->idletime) {
6608 if (bus->activity) {
6609 bus->activity = FALSE;
6610 if (SLPAUTO_ENAB(bus)) {
6611 if (!bus->readframes)
6612 dhdsdio_bussleep(bus, TRUE);
6614 bus->reqbussleep = TRUE;
6617 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
6621 #endif /* DHD_USE_IDLECOUNT */
6623 dhd_os_sdunlock(bus->dhd);
6630 dhd_bus_console_in(dhd_pub_t *dhdp, uchar *msg, uint msglen)
6632 dhd_bus_t *bus = dhdp->bus;
6637 /* Address could be zero if CONSOLE := 0 in dongle Makefile */
6638 if (bus->console_addr == 0)
6639 return BCME_UNSUPPORTED;
6641 /* Exclusive bus access */
6642 dhd_os_sdlock(bus->dhd);
6644 /* Don't allow input if dongle is in reset */
6645 if (bus->dhd->dongle_reset) {
6646 dhd_os_sdunlock(bus->dhd);
6647 return BCME_NOTREADY;
6650 /* Request clock to allow SDIO accesses */
6652 /* No pend allowed since txpkt is called later, ht clk has to be on */
6653 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
6655 /* Zero cbuf_index */
6656 addr = bus->console_addr + OFFSETOF(hnd_cons_t, cbuf_idx);
6658 if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0)
6661 /* Write message into cbuf */
6662 addr = bus->console_addr + OFFSETOF(hnd_cons_t, cbuf);
6663 if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)msg, msglen)) < 0)
6666 /* Write length into vcons_in */
6667 addr = bus->console_addr + OFFSETOF(hnd_cons_t, vcons_in);
6668 val = htol32(msglen);
6669 if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0)
6672 /* Bump dongle by sending an empty packet on the event channel.
6673 * sdpcm_sendup (RX) checks for virtual console input.
6675 if ((pkt = PKTGET(bus->dhd->osh, 4 + SDPCM_RESERVE, TRUE)) != NULL)
6676 rv = dhdsdio_txpkt(bus, SDPCM_EVENT_CHANNEL, &pkt, 1, TRUE);
6679 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
6680 bus->activity = FALSE;
6681 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
6684 dhd_os_sdunlock(bus->dhd);
6688 #endif /* DHD_DEBUG */
6692 dhd_dump_cis(uint fn, uint8 *cis)
6694 uint byte, tag, tdata;
6695 DHD_INFO(("Function %d CIS:\n", fn));
6697 for (tdata = byte = 0; byte < SBSDIO_CIS_SIZE_LIMIT; byte++) {
6698 if ((byte % 16) == 0)
6700 DHD_INFO(("%02x ", cis[byte]));
6701 if ((byte % 16) == 15)
6709 else if ((byte + 1) < SBSDIO_CIS_SIZE_LIMIT)
6710 tdata = cis[byte + 1] + 1;
6715 if ((byte % 16) != 15)
6718 #endif /* DHD_DEBUG */
6721 dhdsdio_chipmatch(uint16 chipid)
6723 if (chipid == BCM4325_CHIP_ID)
6725 if (chipid == BCM4329_CHIP_ID)
6727 if (chipid == BCM4315_CHIP_ID)
6729 if (chipid == BCM4319_CHIP_ID)
6731 if (chipid == BCM4336_CHIP_ID)
6733 if (chipid == BCM4330_CHIP_ID)
6735 if (chipid == BCM43237_CHIP_ID)
6737 if (chipid == BCM43362_CHIP_ID)
6739 if (chipid == BCM4314_CHIP_ID)
6741 if (chipid == BCM43242_CHIP_ID)
6743 if (chipid == BCM43340_CHIP_ID)
6745 if (chipid == BCM43341_CHIP_ID)
6747 if (chipid == BCM43143_CHIP_ID)
6749 if (chipid == BCM43342_CHIP_ID)
6751 if (chipid == BCM4334_CHIP_ID)
6753 if (chipid == BCM43239_CHIP_ID)
6755 if (chipid == BCM4324_CHIP_ID)
6757 if (chipid == BCM4335_CHIP_ID)
6759 if (chipid == BCM4339_CHIP_ID)
6761 if (chipid == BCM43349_CHIP_ID)
6763 if (chipid == BCM4345_CHIP_ID)
6765 if (chipid == BCM4350_CHIP_ID)
6767 if (chipid == BCM4354_CHIP_ID)
6769 if (chipid == BCM4356_CHIP_ID)
6771 if (chipid == BCM4358_CHIP_ID)
6773 if (chipid == BCM43430_CHIP_ID)
6775 if (BCM4349_CHIP(chipid))
6780 #if defined(MULTIPLE_SUPPLICANT)
6781 extern void wl_android_post_init(void); // terence 20120530: fix critical section in dhd_open and dhdsdio_probe
6785 dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot,
6786 uint16 func, uint bustype, void *regsva, osl_t * osh, void *sdh)
6790 struct ether_addr ea_addr;
6792 #if defined(MULTIPLE_SUPPLICANT)
6793 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
6794 if (mutex_is_locked(&_dhd_sdio_mutex_lock_) == 0) {
6795 DHD_ERROR(("%s : no mutex held. set lock\n", __FUNCTION__));
6798 DHD_ERROR(("%s : mutex is locked!. wait for unlocking\n", __FUNCTION__));
6800 mutex_lock(&_dhd_sdio_mutex_lock_);
6801 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
6804 /* Init global variables at run-time, not as part of the declaration.
6805 * This is required to support init/de-init of the driver. Initialization
6806 * of globals as part of the declaration results in non-deterministic
6807 * behavior since the value of the globals may be different on the
6808 * first time that the driver is initialized vs subsequent initializations.
6810 dhd_txbound = DHD_TXBOUND;
6811 dhd_rxbound = DHD_RXBOUND;
6812 dhd_alignctl = TRUE;
6814 dhd_readahead = TRUE;
6816 #if !defined(PLATFORM_MPS)
6820 #endif /* OEM_ANDROID */
6821 dhd_dongle_ramsize = 0;
6822 dhd_txminmax = DHD_TXMINMAX;
6826 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
6827 DHD_INFO(("%s: venid 0x%04x devid 0x%04x\n", __FUNCTION__, venid, devid));
6829 /* We make assumptions about address window mappings */
6830 ASSERT((uintptr)regsva == SI_ENUM_BASE);
6832 /* BCMSDH passes venid and devid based on CIS parsing -- but low-power start
6833 * means early parse could fail, so here we should get either an ID
6834 * we recognize OR (-1) indicating we must request power first.
6836 /* Check the Vendor ID */
6839 case VENDOR_BROADCOM:
6842 DHD_ERROR(("%s: unknown vendor: 0x%04x\n",
6843 __FUNCTION__, venid));
6847 /* Check the Device ID and make sure it's one that we support */
6849 case BCM4325_D11DUAL_ID: /* 4325 802.11a/g id */
6850 case BCM4325_D11G_ID: /* 4325 802.11g 2.4Ghz band id */
6851 case BCM4325_D11A_ID: /* 4325 802.11a 5Ghz band id */
6852 DHD_INFO(("%s: found 4325 Dongle\n", __FUNCTION__));
6854 case BCM4329_D11N_ID: /* 4329 802.11n dualband device */
6855 case BCM4329_D11N2G_ID: /* 4329 802.11n 2.4G device */
6856 case BCM4329_D11N5G_ID: /* 4329 802.11n 5G device */
6858 DHD_INFO(("%s: found 4329 Dongle\n", __FUNCTION__));
6860 case BCM4315_D11DUAL_ID: /* 4315 802.11a/g id */
6861 case BCM4315_D11G_ID: /* 4315 802.11g id */
6862 case BCM4315_D11A_ID: /* 4315 802.11a id */
6863 DHD_INFO(("%s: found 4315 Dongle\n", __FUNCTION__));
6865 case BCM4319_D11N_ID: /* 4319 802.11n id */
6866 case BCM4319_D11N2G_ID: /* 4319 802.11n2g id */
6867 case BCM4319_D11N5G_ID: /* 4319 802.11n5g id */
6868 DHD_INFO(("%s: found 4319 Dongle\n", __FUNCTION__));
6871 DHD_INFO(("%s: allow device id 0, will check chip internals\n",
6876 DHD_ERROR(("%s: skipping 0x%04x/0x%04x, not a dongle\n",
6877 __FUNCTION__, venid, devid));
6882 DHD_ERROR(("%s: osh is NULL!\n", __FUNCTION__));
6886 /* Allocate private bus interface state */
6887 if (!(bus = MALLOC(osh, sizeof(dhd_bus_t)))) {
6888 DHD_ERROR(("%s: MALLOC of dhd_bus_t failed\n", __FUNCTION__));
6891 bzero(bus, sizeof(dhd_bus_t));
6893 bus->cl_devid = (uint16)devid;
6895 bus->bus_num = bus_no;
6896 bus->slot_num = slot;
6897 bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1;
6898 bus->usebufpool = FALSE; /* Use bufpool if allocated, else use locally malloced rxbuf */
6900 /* attempt to attach to the dongle */
6901 if (!(dhdsdio_probe_attach(bus, osh, sdh, regsva, devid))) {
6902 DHD_ERROR(("%s: dhdsdio_probe_attach failed\n", __FUNCTION__));
6906 /* Attach to the dhd/OS/network interface */
6907 if (!(bus->dhd = dhd_attach(osh, bus, SDPCM_RESERVE))) {
6908 DHD_ERROR(("%s: dhd_attach failed\n", __FUNCTION__));
6912 /* Allocate buffers */
6913 if (!(dhdsdio_probe_malloc(bus, osh, sdh))) {
6914 DHD_ERROR(("%s: dhdsdio_probe_malloc failed\n", __FUNCTION__));
6918 if (!(dhdsdio_probe_init(bus, osh, sdh))) {
6919 DHD_ERROR(("%s: dhdsdio_probe_init failed\n", __FUNCTION__));
6924 /* Register interrupt callback, but mask it (not operational yet). */
6925 DHD_INTR(("%s: disable SDIO interrupts (not interested yet)\n", __FUNCTION__));
6926 bcmsdh_intr_disable(sdh);
6927 if ((ret = bcmsdh_intr_reg(sdh, dhdsdio_isr, bus)) != 0) {
6928 DHD_ERROR(("%s: FAILED: bcmsdh_intr_reg returned %d\n",
6929 __FUNCTION__, ret));
6932 DHD_INTR(("%s: registered SDIO interrupt function ok\n", __FUNCTION__));
6934 DHD_INFO(("%s: SDIO interrupt function is NOT registered due to polling mode\n",
6938 DHD_INFO(("%s: completed!!\n", __FUNCTION__));
6940 /* if firmware path present try to download and bring up bus */
6941 bus->dhd->hang_report = TRUE;
6942 #if 0 // terence 20150325: fix for WPA/WPA2 4-way handshake fail in hostapd
6943 if (dhd_download_fw_on_driverload) {
6944 if ((ret = dhd_bus_start(bus->dhd)) != 0) {
6945 DHD_ERROR(("%s: dhd_bus_start failed\n", __FUNCTION__));
6951 #ifdef GET_OTP_MAC_ENABLE
6952 if (dhd_conf_get_mac(bus->dhd, sdh, ea_addr.octet)) {
6953 DHD_TRACE(("%s: Can not read MAC address\n", __FUNCTION__));
6955 memcpy(bus->dhd->mac.octet, (void *)&ea_addr, ETHER_ADDR_LEN);
6956 #endif /* GET_CUSTOM_MAC_ENABLE */
6958 /* Ok, have the per-port tell the stack we're open for business */
6959 if (dhd_register_if(bus->dhd, 0, TRUE) != 0) {
6960 DHD_ERROR(("%s: Net attach failed!!\n", __FUNCTION__));
6965 #if defined(MULTIPLE_SUPPLICANT)
6966 wl_android_post_init(); // terence 20120530: fix critical section in dhd_open and dhdsdio_probe
6967 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
6968 mutex_unlock(&_dhd_sdio_mutex_lock_);
6969 DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__));
6970 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
6973 init_waitqueue_head(&bus->bus_sleep);
6978 dhdsdio_release(bus, osh);
6981 #if defined(MULTIPLE_SUPPLICANT)
6982 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
6983 mutex_unlock(&_dhd_sdio_mutex_lock_);
6984 DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__));
6985 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
6991 #ifdef REGON_BP_HANG_FIX
6992 static int dhd_sdio_backplane_reset(struct dhd_bus *bus)
6995 DHD_ERROR(("Resetting the backplane to avoid failure in firmware download..\n"));
6997 temp = bcmsdh_reg_read(bus->sdh, 0x180021e0, 4);
6998 DHD_INFO(("SDIO Clk Control Reg = %x\n", temp));
7000 /* Force HT req from PMU */
7001 bcmsdh_reg_write(bus->sdh, 0x18000644, 4, 0x6000005);
7003 /* Increase the clock stretch duration. */
7004 bcmsdh_reg_write(bus->sdh, 0x18000630, 4, 0xC8FFC8);
7006 /* Setting ALP clock request in SDIOD clock control status register */
7007 bcmsdh_reg_write(bus->sdh, 0x180021e0, 4, 0x41);
7009 /* Allowing clock from SR engine to SR memory */
7010 bcmsdh_reg_write(bus->sdh, 0x18004400, 4, 0xf92f1);
7011 /* Disabling SR Engine before SR binary download. */
7012 bcmsdh_reg_write(bus->sdh, 0x18000650, 4, 0x3);
7013 bcmsdh_reg_write(bus->sdh, 0x18000654, 4, 0x0);
7015 /* Enabling clock from backplane to SR memory */
7016 bcmsdh_reg_write(bus->sdh, 0x18004400, 4, 0xf9af1);
7018 /* Initializing SR memory address register in SOCRAM */
7019 bcmsdh_reg_write(bus->sdh, 0x18004408, 4, 0x0);
7021 /* Downloading the SR binary */
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, 0x00000000);
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, 0xc0002000);
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, 0x00000000);
7051 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7052 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7053 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7054 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x80008000);
7055 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x1051f080);
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, 0x80008000);
7059 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x1050f080);
7060 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x80008000);
7061 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x1050f080);
7062 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000004);
7063 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
7064 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000604);
7065 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
7066 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00001604);
7067 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
7068 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00001404);
7069 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a08c80);
7070 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010001);
7071 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x14a00000);
7072 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00011404);
7073 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
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, 0x00002000);
7079 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x04a00000);
7080 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00002000);
7081 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0xf8000000);
7082 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00011604);
7083 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
7084 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010604);
7085 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
7086 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010004);
7087 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
7088 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010000);
7089 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x14a00000);
7090 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000004);
7091 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
7092 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010001);
7093 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x14a00000);
7094 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010004);
7095 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
7096 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010000);
7097 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
7098 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010000);
7099 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x14a00000);
7100 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7101 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
7102 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000008);
7103 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x04a00000);
7104 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000008);
7105 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0xfc000000);
7106 /* SR Binary Download complete */
7108 /* Allowing clock from SR engine to SR memory */
7109 bcmsdh_reg_write(bus->sdh, 0x18004400, 4, 0xf92f1);
7111 /* Turning ON SR Engine to initiate backplane reset Repeated ?? Maharana */
7112 bcmsdh_reg_write(bus->sdh, 0x18000650, 4, 0x3);
7113 bcmsdh_reg_write(bus->sdh, 0x18000654, 4, 0x0);
7114 bcmsdh_reg_write(bus->sdh, 0x18000650, 4, 0x3);
7115 bcmsdh_reg_write(bus->sdh, 0x18000654, 4, 0x2);
7116 bcmsdh_reg_write(bus->sdh, 0x18000650, 4, 0x3);
7117 bcmsdh_reg_write(bus->sdh, 0x18000654, 4, 0x3);
7118 bcmsdh_reg_write(bus->sdh, 0x18000650, 4, 0x3);
7119 bcmsdh_reg_write(bus->sdh, 0x18000654, 4, 0x37);
7120 bcmsdh_reg_write(bus->sdh, 0x18000650, 4, 0x3);
7121 temp = bcmsdh_reg_read(bus->sdh, 0x18000654, 4);
7122 DHD_INFO(("0x18000654 = %x\n", temp));
7123 bcmsdh_reg_write(bus->sdh, 0x18000654, 4, 0x800037);
7125 /* Rolling back the original values for clock stretch and PMU timers */
7126 bcmsdh_reg_write(bus->sdh, 0x18000644, 4, 0x0);
7127 bcmsdh_reg_write(bus->sdh, 0x18000630, 4, 0xC800C8);
7128 /* Removing ALP clock request in SDIOD clock control status register */
7129 bcmsdh_reg_write(bus->sdh, 0x180021e0, 4, 0x40);
7134 static int dhdsdio_sdio_hang_war(struct dhd_bus *bus)
7136 uint32 temp = 0, temp2 = 0, counter = 0, BT_pwr_up = 0, BT_ready = 0;
7137 /* Removing reset of D11 Core */
7138 bcmsdh_reg_write(bus->sdh, 0x18101408, 4, 0x3);
7139 bcmsdh_reg_write(bus->sdh, 0x18101800, 4, 0x0);
7140 bcmsdh_reg_write(bus->sdh, 0x18101408, 4, 0x1);
7141 /* Reading CLB XTAL BT cntrl register */
7142 bcmsdh_reg_write(bus->sdh, 0x180013D8, 2, 0xD1);
7143 bcmsdh_reg_write(bus->sdh, 0x180013DA, 2, 0x12);
7144 bcmsdh_reg_write(bus->sdh, 0x180013D8, 2, 0x2D0);
7145 /* Read if BT is powered up */
7146 temp = bcmsdh_reg_read(bus->sdh, 0x180013DA, 2);
7147 /* Read BT_ready from WLAN wireless register */
7148 temp2 = bcmsdh_reg_read(bus->sdh, 0x1800002C, 4);
7150 Check if the BT is powered up and ready. The duration between BT being powered up
7151 and BT becoming ready is the problematic window for WLAN. If we move ahead at this
7152 time then we may encounter a corrupted backplane later. So we wait for BT to be ready
7153 and then proceed after checking the health of the backplane. If the backplane shows
7154 indications of failure then we have to do a full reset of the backplane using SR engine
7157 (temp & 0xF0) ? (BT_pwr_up = 1):(BT_pwr_up = 0);
7158 (temp2 & (1<<17)) ? (BT_ready = 1):(BT_ready = 0);
7159 DHD_ERROR(("WARNING: Checking if BT is ready BT_pwr_up = %x"
7160 "BT_ready = %x \n", BT_pwr_up, BT_ready));
7161 while (BT_pwr_up && !BT_ready)
7164 bcmsdh_reg_write(bus->sdh, 0x180013D8, 2, 0x2D0);
7165 temp = bcmsdh_reg_read(bus->sdh, 0x180013DA, 2);
7166 temp2 = bcmsdh_reg_read(bus->sdh, 0x1800002C, 4);
7167 (temp & 0xF0) ? (BT_pwr_up = 1):(BT_pwr_up = 0);
7168 (temp2 & (1<<17)) ? (BT_ready = 1):(BT_ready = 0);
7170 if (counter == 5000)
7172 DHD_ERROR(("WARNING: Going ahead after 5 secs with"
7173 "risk of failure because BT ready is not yet set\n"));
7177 DHD_ERROR(("\nWARNING: WL Proceeding BT_pwr_up = %x BT_ready = %x"
7178 "\n", BT_pwr_up, BT_ready));
7182 Get the information of who accessed the crucial backplane entities
7183 by reading read and write access registers
7185 DHD_TRACE(("%d: Read Value @ 0x18104808 = %x."
7186 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18104808, 4)));
7187 DHD_TRACE(("%d: Read Value @ 0x1810480C = %x."
7188 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810480C, 4)));
7189 DHD_TRACE(("%d: Read Value @ 0x18106808 = %x."
7190 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18106808, 4)));
7191 DHD_TRACE(("%d: Read Value @ 0x1810680C = %x."
7192 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810680C, 4)));
7193 DHD_TRACE(("%d: Read Value @ 0x18107808 = %x."
7194 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18107808, 4)));
7195 DHD_TRACE(("%d: Read Value @ 0x1810780C = %x."
7196 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810780C, 4)));
7197 DHD_TRACE(("%d: Read Value @ 0x18108808 = %x."
7198 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18108808, 4)));
7199 DHD_TRACE(("%d: Read Value @ 0x1810880C = %x."
7200 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810880C, 4)));
7201 DHD_TRACE(("%d: Read Value @ 0x18109808 = %x."
7202 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18109808, 4)));
7203 DHD_TRACE(("%d: Read Value @ 0x1810980C = %x."
7204 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810980C, 4)));
7205 DHD_TRACE(("%d: Read Value @ 0x1810C808 = %x."
7206 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810c808, 4)));
7207 DHD_TRACE(("%d: Read Value @ 0x1810C80C = %x."
7208 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810c80C, 4)));
7210 while ((bcmsdh_reg_read(bus->sdh, 0x18104808, 4) == 5) ||
7211 (bcmsdh_reg_read(bus->sdh, 0x1810480C, 4) == 5) ||
7212 (bcmsdh_reg_read(bus->sdh, 0x18106808, 4) == 5) ||
7213 (bcmsdh_reg_read(bus->sdh, 0x1810680C, 4) == 5) ||
7214 (bcmsdh_reg_read(bus->sdh, 0x1810780C, 4) == 5) ||
7215 (bcmsdh_reg_read(bus->sdh, 0x1810780C, 4) == 5) ||
7216 (bcmsdh_reg_read(bus->sdh, 0x1810880C, 4) == 5) ||
7217 (bcmsdh_reg_read(bus->sdh, 0x1810880C, 4) == 5) ||
7218 (bcmsdh_reg_read(bus->sdh, 0x1810980C, 4) == 5) ||
7219 (bcmsdh_reg_read(bus->sdh, 0x1810980C, 4) == 5) ||
7220 (bcmsdh_reg_read(bus->sdh, 0x1810C80C, 4) == 5) ||
7221 (bcmsdh_reg_read(bus->sdh, 0x1810C80C, 4) == 5))
7225 DHD_ERROR(("Unable to recover the backkplane corruption"
7226 "..Tried %d times.. Exiting\n", counter));
7230 dhd_sdio_backplane_reset(bus);
7232 Get the information of who accessed the crucial backplane
7233 entities by reading read and write access registers
7235 DHD_ERROR(("%d: Read Value @ 0x18104808 = %x."
7236 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18104808, 4)));
7237 DHD_ERROR(("%d: Read Value @ 0x1810480C = %x."
7238 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810480C, 4)));
7239 DHD_ERROR(("%d: Read Value @ 0x18106808 = %x."
7240 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18106808, 4)));
7241 DHD_ERROR(("%d: Read Value @ 0x1810680C = %x."
7242 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810680C, 4)));
7243 DHD_ERROR(("%d: Read Value @ 0x18107808 = %x."
7244 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18107808, 4)));
7245 DHD_ERROR(("%d: Read Value @ 0x1810780C = %x."
7246 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810780C, 4)));
7247 DHD_ERROR(("%d: Read Value @ 0x18108808 = %x."
7248 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18108808, 4)));
7249 DHD_ERROR(("%d: Read Value @ 0x1810880C = %x."
7250 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810880C, 4)));
7251 DHD_ERROR(("%d: Read Value @ 0x18109808 = %x."
7252 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18109808, 4)));
7253 DHD_ERROR(("%d: Read Value @ 0x1810980C = %x."
7254 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810980C, 4)));
7255 DHD_ERROR(("%d: Read Value @ 0x1810C808 = %x."
7256 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810c808, 4)));
7257 DHD_ERROR(("%d: Read Value @ 0x1810C80C = %x."
7258 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810c80C, 4)));
7260 /* Set the WL ready to indicate BT that we are done with backplane reset */
7261 DHD_ERROR(("Setting up AXI_OK\n"));
7262 bcmsdh_reg_write(bus->sdh, 0x18000658, 4, 0x3);
7263 temp = bcmsdh_reg_read(bus->sdh, 0x1800065c, 4);
7265 bcmsdh_reg_write(bus->sdh, 0x1800065c, 4, temp);
7268 #endif /* REGON_BP_HANG_FIX */
7270 dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva,
7276 bus->alp_only = TRUE;
7279 /* Return the window to backplane enumeration space for core access */
7280 if (dhdsdio_set_siaddr_window(bus, SI_ENUM_BASE)) {
7281 DHD_ERROR(("%s: FAILED to return to SI_ENUM_BASE\n", __FUNCTION__));
7284 #if defined(DHD_DEBUG)
7285 DHD_ERROR(("F1 signature read @0x18000000=0x%4x\n",
7286 bcmsdh_reg_read(bus->sdh, SI_ENUM_BASE, 4)));
7290 /* Force PLL off until si_attach() programs PLL control regs */
7294 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, DHD_INIT_CLKCTL1, &err);
7296 clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
7298 if (err || ((clkctl & ~SBSDIO_AVBITS) != DHD_INIT_CLKCTL1)) {
7299 DHD_ERROR(("dhdsdio_probe: ChipClkCSR access: err %d wrote 0x%02x read 0x%02x\n",
7300 err, DHD_INIT_CLKCTL1, clkctl));
7305 if (DHD_INFO_ON()) {
7307 uint8 *cis[SDIOD_MAX_IOFUNCS];
7310 numfn = bcmsdh_query_iofnum(sdh);
7311 ASSERT(numfn <= SDIOD_MAX_IOFUNCS);
7313 /* Make sure ALP is available before trying to read CIS */
7314 SPINWAIT(((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
7315 SBSDIO_FUNC1_CHIPCLKCSR, NULL)),
7316 !SBSDIO_ALPAV(clkctl)), PMU_MAX_TRANSITION_DLY);
7318 /* Now request ALP be put on the bus */
7319 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
7320 DHD_INIT_CLKCTL2, &err);
7323 for (fn = 0; fn <= numfn; fn++) {
7324 if (!(cis[fn] = MALLOC(osh, SBSDIO_CIS_SIZE_LIMIT))) {
7325 DHD_INFO(("dhdsdio_probe: fn %d cis malloc failed\n", fn));
7328 bzero(cis[fn], SBSDIO_CIS_SIZE_LIMIT);
7330 if ((err = bcmsdh_cis_read(sdh, fn, cis[fn], SBSDIO_CIS_SIZE_LIMIT))) {
7331 DHD_INFO(("dhdsdio_probe: fn %d cis read err %d\n", fn, err));
7332 MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT);
7335 dhd_dump_cis(fn, cis[fn]);
7340 MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT);
7344 DHD_ERROR(("dhdsdio_probe: failure reading or parsing CIS\n"));
7348 #endif /* DHD_DEBUG */
7350 /* si_attach() will provide an SI handle and scan the backplane */
7351 if (!(bus->sih = si_attach((uint)devid, osh, regsva, DHD_BUS, sdh,
7352 &bus->vars, &bus->varsz))) {
7353 DHD_ERROR(("%s: si_attach failed!\n", __FUNCTION__));
7358 DHD_ERROR(("F1 signature OK, socitype:0x%x chip:0x%4x rev:0x%x pkg:0x%x\n",
7359 bus->sih->socitype, bus->sih->chip, bus->sih->chiprev, bus->sih->chippkg));
7360 #endif /* DHD_DEBUG */
7362 #ifdef REGON_BP_HANG_FIX
7363 /* WAR - for 43241 B0-B1-B2. B3 onwards do not need this */
7364 if (((uint16)bus->sih->chip == BCM4324_CHIP_ID) && (bus->sih->chiprev < 3))
7365 dhdsdio_sdio_hang_war(bus);
7366 #endif /* REGON_BP_HANG_FIX */
7368 bcmsdh_chipinfo(sdh, bus->sih->chip, bus->sih->chiprev);
7370 if (!dhdsdio_chipmatch((uint16)bus->sih->chip)) {
7371 DHD_ERROR(("%s: unsupported chip: 0x%04x\n",
7372 __FUNCTION__, bus->sih->chip));
7376 if (bus->sih->buscorerev >= 12)
7377 dhdsdio_clk_kso_init(bus);
7381 if (CST4330_CHIPMODE_SDIOD(bus->sih->chipst)) {
7384 si_sdiod_drive_strength_init(bus->sih, osh, dhd_sdiod_drive_strength);
7387 /* Get info on the ARM and SOCRAM cores... */
7388 if (!DHD_NOPMU(bus)) {
7389 if ((si_setcore(bus->sih, ARM7S_CORE_ID, 0)) ||
7390 (si_setcore(bus->sih, ARMCM3_CORE_ID, 0)) ||
7391 (si_setcore(bus->sih, ARMCR4_CORE_ID, 0))) {
7392 bus->armrev = si_corerev(bus->sih);
7394 DHD_ERROR(("%s: failed to find ARM core!\n", __FUNCTION__));
7398 if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
7399 if (!(bus->orig_ramsize = si_socram_size(bus->sih))) {
7400 DHD_ERROR(("%s: failed to find SOCRAM memory!\n", __FUNCTION__));
7404 /* cr4 has a different way to find the RAM size from TCM's */
7405 if (!(bus->orig_ramsize = si_tcm_size(bus->sih))) {
7406 DHD_ERROR(("%s: failed to find CR4-TCM memory!\n", __FUNCTION__));
7409 /* also populate base address */
7410 switch ((uint16)bus->sih->chip) {
7411 case BCM4335_CHIP_ID:
7412 case BCM4339_CHIP_ID:
7413 case BCM43349_CHIP_ID:
7414 bus->dongle_ram_base = CR4_4335_RAM_BASE;
7416 case BCM4350_CHIP_ID:
7417 case BCM4354_CHIP_ID:
7418 case BCM4356_CHIP_ID:
7419 case BCM4358_CHIP_ID:
7420 bus->dongle_ram_base = CR4_4350_RAM_BASE;
7422 case BCM4360_CHIP_ID:
7423 bus->dongle_ram_base = CR4_4360_RAM_BASE;
7425 case BCM4345_CHIP_ID:
7426 bus->dongle_ram_base = CR4_4345_RAM_BASE;
7428 case BCM4349_CHIP_GRPID:
7429 bus->dongle_ram_base = CR4_4349_RAM_BASE;
7432 bus->dongle_ram_base = 0;
7433 DHD_ERROR(("%s: WARNING: Using default ram base at 0x%x\n",
7434 __FUNCTION__, bus->dongle_ram_base));
7437 bus->ramsize = bus->orig_ramsize;
7438 if (dhd_dongle_ramsize)
7439 dhd_dongle_setramsize(bus, dhd_dongle_ramsize);
7441 DHD_ERROR(("DHD: dongle ram size is set to %d(orig %d) at 0x%x\n",
7442 bus->ramsize, bus->orig_ramsize, bus->dongle_ram_base));
7444 bus->srmemsize = si_socram_srmem_size(bus->sih);
7447 /* ...but normally deal with the SDPCMDEV core */
7448 if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0)) &&
7449 !(bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0))) {
7450 DHD_ERROR(("%s: failed to find SDIODEV core!\n", __FUNCTION__));
7453 bus->sdpcmrev = si_corerev(bus->sih);
7455 /* Set core control so an SDIO reset does a backplane reset */
7456 OR_REG(osh, &bus->regs->corecontrol, CC_BPRESEN);
7457 bus->rxint_mode = SDIO_DEVICE_HMB_RXINT;
7459 if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev >= 4) &&
7460 (bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_1))
7464 val = R_REG(osh, &bus->regs->corecontrol);
7465 val &= ~CC_XMTDATAAVAIL_MODE;
7466 val |= CC_XMTDATAAVAIL_CTRL;
7467 W_REG(osh, &bus->regs->corecontrol, val);
7471 pktq_init(&bus->txq, (PRIOMASK + 1), QLEN);
7473 /* Locate an appropriately-aligned portion of hdrbuf */
7474 bus->rxhdr = (uint8 *)ROUNDUP((uintptr)&bus->hdrbuf[0], DHD_SDALIGN);
7476 /* Set the poll and/or interrupt flags */
7477 bus->intr = (bool)dhd_intr;
7478 if ((bus->poll = (bool)dhd_poll))
7481 /* Setting default Glom size */
7482 bus->txglomsize = SDPCM_DEFGLOM_SIZE;
7487 if (bus->sih != NULL) {
7488 si_detach(bus->sih);
7495 dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh)
7497 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7499 if (bus->dhd->maxctl) {
7500 bus->rxblen = ROUNDUP((bus->dhd->maxctl+SDPCM_HDRLEN), ALIGNMENT) + DHD_SDALIGN;
7501 if (!(bus->rxbuf = DHD_OS_PREALLOC(bus->dhd, DHD_PREALLOC_RXBUF, bus->rxblen))) {
7502 DHD_ERROR(("%s: MALLOC of %d-byte rxbuf failed\n",
7503 __FUNCTION__, bus->rxblen));
7507 /* Allocate buffer to receive glomed packet */
7508 if (!(bus->databuf = DHD_OS_PREALLOC(bus->dhd, DHD_PREALLOC_DATABUF, MAX_DATA_BUF))) {
7509 DHD_ERROR(("%s: MALLOC of %d-byte databuf failed\n",
7510 __FUNCTION__, MAX_DATA_BUF));
7511 /* release rxbuf which was already located as above */
7513 DHD_OS_PREFREE(bus->dhd, bus->rxbuf, bus->rxblen);
7517 /* Align the buffer */
7518 if ((uintptr)bus->databuf % DHD_SDALIGN)
7519 bus->dataptr = bus->databuf + (DHD_SDALIGN - ((uintptr)bus->databuf % DHD_SDALIGN));
7521 bus->dataptr = bus->databuf;
7530 dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh)
7534 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7536 bus->_srenab = FALSE;
7539 dhdsdio_pktgen_init(bus);
7542 /* Disable F2 to clear any intermediate frame state on the dongle */
7543 bcmsdh_cfg_write(sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL);
7545 bus->dhd->busstate = DHD_BUS_DOWN;
7546 bus->sleeping = FALSE;
7547 bus->rxflow = FALSE;
7548 bus->prev_rxlim_hit = 0;
7550 /* Done with backplane-dependent accesses, can drop clock... */
7551 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
7553 /* ...and initialize clock/power states */
7554 bus->clkstate = CLK_SDONLY;
7555 bus->idletime = (int32)dhd_idletime;
7556 bus->idleclock = DHD_IDLE_ACTIVE;
7558 /* Query the SD clock speed */
7559 if (bcmsdh_iovar_op(sdh, "sd_divisor", NULL, 0,
7560 &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) {
7561 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_divisor"));
7562 bus->sd_divisor = -1;
7564 DHD_INFO(("%s: Initial value for %s is %d\n",
7565 __FUNCTION__, "sd_divisor", bus->sd_divisor));
7568 /* Query the SD bus mode */
7569 if (bcmsdh_iovar_op(sdh, "sd_mode", NULL, 0,
7570 &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) {
7571 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_mode"));
7574 DHD_INFO(("%s: Initial value for %s is %d\n",
7575 __FUNCTION__, "sd_mode", bus->sd_mode));
7578 /* Query the F2 block size, set roundup accordingly */
7580 if (bcmsdh_iovar_op(sdh, "sd_blocksize", &fnum, sizeof(int32),
7581 &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) {
7583 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize"));
7585 DHD_INFO(("%s: Initial value for %s is %d\n",
7586 __FUNCTION__, "sd_blocksize", bus->blocksize));
7588 dhdsdio_tune_fifoparam(bus);
7590 bus->roundup = MIN(max_roundup, bus->blocksize);
7592 #ifdef DHDENABLE_TAILPAD
7594 PKTFREE(osh, bus->pad_pkt, FALSE);
7595 bus->pad_pkt = PKTGET(osh, SDIO_MAX_BLOCK_SIZE, FALSE);
7596 if (bus->pad_pkt == NULL)
7597 DHD_ERROR(("failed to allocate padding packet\n"));
7599 int alignment_offset = 0;
7600 uintptr pktprt = (uintptr)PKTDATA(osh, bus->pad_pkt);
7601 if (!(pktprt&1) && (pktprt = (pktprt % DHD_SDALIGN)))
7602 PKTPUSH(osh, bus->pad_pkt, alignment_offset);
7603 PKTSETNEXT(osh, bus->pad_pkt, NULL);
7605 #endif /* DHDENABLE_TAILPAD */
7607 /* Query if bus module supports packet chaining, default to use if supported */
7608 if (bcmsdh_iovar_op(sdh, "sd_rxchain", NULL, 0,
7609 &bus->sd_rxchain, sizeof(int32), FALSE) != BCME_OK) {
7610 bus->sd_rxchain = FALSE;
7612 DHD_INFO(("%s: bus module (through bcmsdh API) %s chaining\n",
7613 __FUNCTION__, (bus->sd_rxchain ? "supports" : "does not support")));
7615 bus->use_rxchain = (bool)bus->sd_rxchain;
7616 if (bus->dhd->conf->use_rxchain >= 0) {
7617 printf("%s: set use_rxchain %d from config.txt\n", __FUNCTION__, bus->dhd->conf->use_rxchain);
7618 bus->use_rxchain = (bool)bus->dhd->conf->use_rxchain;
7620 /* Setting default Glom size */
7621 if (bus->dhd->conf->txglomsize >= 0) {
7622 printf("%s: set txglomsize %d from config.txt\n", __FUNCTION__, bus->dhd->conf->txglomsize);
7623 bus->txglomsize = bus->dhd->conf->txglomsize;
7625 bus->txinrx_thres = CUSTOM_TXINRX_THRES;
7626 /* TX first in dhdsdio_readframes() */
7627 bus->dotxinrx = TRUE;
7633 dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh,
7634 char *pfw_path, char *pnv_path, char *pconf_path)
7638 bus->fw_path = pfw_path;
7639 bus->nv_path = pnv_path;
7640 bus->dhd->conf_path = pconf_path;
7642 ret = dhdsdio_download_firmware(bus, osh, bus->sdh);
7649 dhdsdio_download_firmware(struct dhd_bus *bus, osl_t *osh, void *sdh)
7653 DHD_TRACE_HW4(("%s: firmware path=%s, nvram path=%s\n",
7654 __FUNCTION__, bus->fw_path, bus->nv_path));
7655 DHD_OS_WAKE_LOCK(bus->dhd);
7657 /* Download the firmware */
7658 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
7660 /* External conf takes precedence if specified */
7661 dhd_conf_preinit(bus->dhd);
7662 dhd_conf_read_config(bus->dhd, bus->dhd->conf_path);
7663 dhd_conf_set_fw_name_by_chip(bus->dhd, bus->fw_path);
7664 dhd_conf_set_fw_name_by_mac(bus->dhd, bus->sdh, bus->fw_path);
7665 dhd_conf_set_nv_name_by_mac(bus->dhd, bus->sdh, bus->nv_path);
7667 printk("Final fw_path=%s\n", bus->fw_path);
7668 printk("Final nv_path=%s\n", bus->nv_path);
7669 printk("Final conf_path=%s\n", bus->dhd->conf_path);
7671 ret = _dhdsdio_download_firmware(bus);
7673 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
7675 DHD_OS_WAKE_UNLOCK(bus->dhd);
7679 /* Detach and free everything */
7681 dhdsdio_release(dhd_bus_t *bus, osl_t *osh)
7683 bool dongle_isolation = FALSE;
7684 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7690 dongle_isolation = bus->dhd->dongle_isolation;
7691 dhd_detach(bus->dhd);
7694 /* De-register interrupt handler */
7695 bcmsdh_intr_disable(bus->sdh);
7696 bcmsdh_intr_dereg(bus->sdh);
7699 dhdsdio_release_dongle(bus, osh, dongle_isolation, TRUE);
7704 dhdsdio_release_malloc(bus, osh);
7707 if (bus->console.buf != NULL)
7708 MFREE(osh, bus->console.buf, bus->console.bufsize);
7711 #ifdef DHDENABLE_TAILPAD
7713 PKTFREE(osh, bus->pad_pkt, FALSE);
7714 #endif /* DHDENABLE_TAILPAD */
7716 MFREE(osh, bus, sizeof(dhd_bus_t));
7719 DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
7723 dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh)
7725 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7727 if (bus->dhd && bus->dhd->dongle_reset)
7731 #ifndef CONFIG_DHD_USE_STATIC_BUF
7732 MFREE(osh, bus->rxbuf, bus->rxblen);
7734 bus->rxctl = bus->rxbuf = NULL;
7739 #ifndef CONFIG_DHD_USE_STATIC_BUF
7740 MFREE(osh, bus->databuf, MAX_DATA_BUF);
7742 bus->databuf = NULL;
7745 if (bus->vars && bus->varsz) {
7746 MFREE(osh, bus->vars, bus->varsz);
7754 dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation, bool reset_flag)
7756 DHD_TRACE(("%s: Enter bus->dhd %p bus->dhd->dongle_reset %d \n", __FUNCTION__,
7757 bus->dhd, bus->dhd->dongle_reset));
7759 if ((bus->dhd && bus->dhd->dongle_reset) && reset_flag)
7763 #if !defined(BCMLXSDMMC)
7765 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
7767 if (KSO_ENAB(bus) && (dongle_isolation == FALSE))
7768 si_watchdog(bus->sih, 4);
7769 #endif /* !defined(BCMLXSDMMC) */
7771 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
7773 si_detach(bus->sih);
7775 if (bus->vars && bus->varsz)
7776 MFREE(osh, bus->vars, bus->varsz);
7780 DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
7784 dhdsdio_disconnect(void *ptr)
7786 dhd_bus_t *bus = (dhd_bus_t *)ptr;
7788 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7790 #if defined(MULTIPLE_SUPPLICANT)
7791 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
7792 if (mutex_is_locked(&_dhd_sdio_mutex_lock_) == 0) {
7793 DHD_ERROR(("%s : no mutex held. set lock\n", __FUNCTION__));
7796 DHD_ERROR(("%s : mutex is locked!. wait for unlocking\n", __FUNCTION__));
7798 mutex_lock(&_dhd_sdio_mutex_lock_);
7799 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
7805 dhdsdio_release(bus, bus->dhd->osh);
7808 #if defined(MULTIPLE_SUPPLICANT)
7809 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
7810 mutex_unlock(&_dhd_sdio_mutex_lock_);
7811 DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__));
7812 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
7816 DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
7820 dhdsdio_suspend(void *context)
7824 dhd_bus_t *bus = (dhd_bus_t*)context;
7826 if (bus->idletime > 0) {
7827 wait_time = msecs_to_jiffies(bus->idletime * dhd_watchdog_ms);
7830 ret = dhd_os_check_wakelock(bus->dhd);
7831 // terence 20141124: fix for suspend issue
7832 if (SLPAUTO_ENAB(bus) && (!ret) && (bus->dhd->up)) {
7833 if (wait_event_timeout(bus->bus_sleep, bus->sleeping, wait_time) == 0) {
7834 if (!bus->sleeping) {
7843 dhdsdio_resume(void *context)
7845 #if defined(OOB_INTR_ONLY)
7846 dhd_bus_t *bus = (dhd_bus_t*)context;
7848 if (dhd_os_check_if_up(bus->dhd))
7849 bcmsdh_oob_intr_set(bus->sdh, TRUE);
7855 /* Register/Unregister functions are called by the main DHD entry
7856 * point (e.g. module insertion) to link with the bus driver, in
7857 * order to look for or await the device.
7860 static bcmsdh_driver_t dhd_sdio = {
7868 dhd_bus_register(void)
7870 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7872 return bcmsdh_register(&dhd_sdio);
7876 dhd_bus_unregister(void)
7878 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7880 bcmsdh_unregister();
7883 #if defined(BCMLXSDMMC)
7884 /* Register a dummy SDIO client driver in order to be notified of new SDIO device */
7885 int dhd_bus_reg_sdio_notify(void* semaphore)
7887 return bcmsdh_reg_sdio_notify(semaphore);
7890 void dhd_bus_unreg_sdio_notify(void)
7892 bcmsdh_unreg_sdio_notify();
7894 #endif /* defined(BCMLXSDMMC) */
7896 #ifdef BCMEMBEDIMAGE
7898 dhdsdio_download_code_array(struct dhd_bus *bus)
7902 unsigned char *ularray = NULL;
7904 DHD_INFO(("%s: download embedded firmware...\n", __FUNCTION__));
7906 /* Download image */
7907 while ((offset + MEMBLOCK) < sizeof(dlarray)) {
7909 if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
7910 /* if address is 0, store the reset instruction to be written in 0 */
7913 bus->resetinstr = *(((uint32*)dlarray));
7914 /* Add start of RAM address to the address given by user */
7915 offset += bus->dongle_ram_base;
7919 bcmerror = dhdsdio_membytes(bus, TRUE, offset,
7920 (uint8 *) (dlarray + offset), MEMBLOCK);
7922 DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
7923 __FUNCTION__, bcmerror, MEMBLOCK, offset));
7930 if (offset < sizeof(dlarray)) {
7931 bcmerror = dhdsdio_membytes(bus, TRUE, offset,
7932 (uint8 *) (dlarray + offset), sizeof(dlarray) - offset);
7934 DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
7935 __FUNCTION__, bcmerror, sizeof(dlarray) - offset, offset));
7941 /* Upload and compare the downloaded code */
7943 ularray = MALLOC(bus->dhd->osh, bus->ramsize);
7944 /* Upload image to verify downloaded contents. */
7946 memset(ularray, 0xaa, bus->ramsize);
7947 while ((offset + MEMBLOCK) < sizeof(dlarray)) {
7948 bcmerror = dhdsdio_membytes(bus, FALSE, offset, ularray + offset, MEMBLOCK);
7950 DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n",
7951 __FUNCTION__, bcmerror, MEMBLOCK, offset));
7958 if (offset < sizeof(dlarray)) {
7959 bcmerror = dhdsdio_membytes(bus, FALSE, offset,
7960 ularray + offset, sizeof(dlarray) - offset);
7962 DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n",
7963 __FUNCTION__, bcmerror, sizeof(dlarray) - offset, offset));
7968 if (memcmp(dlarray, ularray, sizeof(dlarray))) {
7969 DHD_ERROR(("%s: Downloaded image is corrupted (%s, %s, %s).\n",
7970 __FUNCTION__, dlimagename, dlimagever, dlimagedate));
7973 DHD_ERROR(("%s: Download, Upload and compare succeeded (%s, %s, %s).\n",
7974 __FUNCTION__, dlimagename, dlimagever, dlimagedate));
7977 #endif /* DHD_DEBUG */
7981 MFREE(bus->dhd->osh, ularray, bus->ramsize);
7984 #endif /* BCMEMBEDIMAGE */
7987 dhdsdio_download_code_file(struct dhd_bus *bus, char *pfw_path)
7993 uint8 *memblock = NULL, *memptr;
7994 uint8 *memptr_tmp = NULL; // terence: check downloaded firmware is correct
7996 DHD_INFO(("%s: download firmware %s\n", __FUNCTION__, pfw_path));
7998 image = dhd_os_open_image(pfw_path);
7999 if (image == NULL) {
8000 printk("%s: Open firmware file failed %s\n", __FUNCTION__, pfw_path);
8004 memptr = memblock = MALLOC(bus->dhd->osh, MEMBLOCK + DHD_SDALIGN);
8005 if (memblock == NULL) {
8006 DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, MEMBLOCK));
8009 if (dhd_msg_level & DHD_TRACE_VAL) {
8010 memptr_tmp = MALLOC(bus->dhd->osh, MEMBLOCK + DHD_SDALIGN);
8011 if (memptr_tmp == NULL) {
8012 DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, MEMBLOCK));
8016 if ((uint32)(uintptr)memblock % DHD_SDALIGN)
8017 memptr += (DHD_SDALIGN - ((uint32)(uintptr)memblock % DHD_SDALIGN));
8019 /* Download image */
8020 while ((len = dhd_os_get_image_block((char*)memptr, MEMBLOCK, image))) {
8021 // terence 20150412: fix for firmware failed to download
8022 if (bus->dhd->conf->chip == BCM43340_CHIP_ID ||
8023 bus->dhd->conf->chip == BCM43341_CHIP_ID) {
8025 memset(memptr+len, 0, len%64);
8026 len += (64 - len%64);
8030 DHD_ERROR(("%s: dhd_os_get_image_block failed (%d)\n", __FUNCTION__, len));
8031 bcmerror = BCME_ERROR;
8035 if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
8036 /* if address is 0, store the reset instruction to be written in 0 */
8039 bus->resetinstr = *(((uint32*)memptr));
8040 /* Add start of RAM address to the address given by user */
8041 offset += bus->dongle_ram_base;
8045 bcmerror = dhdsdio_membytes(bus, TRUE, offset, memptr, len);
8047 DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
8048 __FUNCTION__, bcmerror, MEMBLOCK, offset));
8052 if (dhd_msg_level & DHD_TRACE_VAL) {
8053 bcmerror = dhdsdio_membytes(bus, FALSE, offset, memptr_tmp, len);
8055 DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n",
8056 __FUNCTION__, bcmerror, MEMBLOCK, offset));
8059 if (memcmp(memptr_tmp, memptr, len)) {
8060 DHD_ERROR(("%s: Downloaded image is corrupted.\n", __FUNCTION__));
8063 DHD_INFO(("%s: Download, Upload and compare succeeded.\n", __FUNCTION__));
8070 MFREE(bus->dhd->osh, memblock, MEMBLOCK + DHD_SDALIGN);
8071 if (dhd_msg_level & DHD_TRACE_VAL) {
8073 MFREE(bus->dhd->osh, memptr_tmp, MEMBLOCK + DHD_SDALIGN);
8077 dhd_os_close_image(image);
8083 EXAMPLE: nvram_array
8086 Use carriage return at the end of each assignment, and an empty string with
8087 carriage return at the end of array.
8090 unsigned char nvram_array[] = {"name1=value1\n", "name2=value2\n", "\n"};
8091 Hex values start with 0x, and mac addr format: xx:xx:xx:xx:xx:xx.
8093 Search "EXAMPLE: nvram_array" to see how the array is activated.
8097 dhd_bus_set_nvram_params(struct dhd_bus * bus, const char *nvram_params)
8099 bus->nvram_params = nvram_params;
8103 dhdsdio_download_nvram(struct dhd_bus *bus)
8107 void * image = NULL;
8108 char * memblock = NULL;
8111 bool nvram_file_exists;
8113 pnv_path = bus->nv_path;
8115 nvram_file_exists = ((pnv_path != NULL) && (pnv_path[0] != '\0'));
8116 if (!nvram_file_exists && (bus->nvram_params == NULL))
8119 if (nvram_file_exists) {
8120 image = dhd_os_open_image(pnv_path);
8121 if (image == NULL) {
8122 printk("%s: Open nvram file failed %s\n", __FUNCTION__, pnv_path);
8127 memblock = MALLOC(bus->dhd->osh, MAX_NVRAMBUF_SIZE);
8128 if (memblock == NULL) {
8129 DHD_ERROR(("%s: Failed to allocate memory %d bytes\n",
8130 __FUNCTION__, MAX_NVRAMBUF_SIZE));
8134 /* Download variables */
8135 if (nvram_file_exists) {
8136 len = dhd_os_get_image_block(memblock, MAX_NVRAMBUF_SIZE, image);
8139 len = strlen(bus->nvram_params);
8140 ASSERT(len <= MAX_NVRAMBUF_SIZE);
8141 memcpy(memblock, bus->nvram_params, len);
8143 if (len > 0 && len < MAX_NVRAMBUF_SIZE) {
8144 bufp = (char *)memblock;
8146 len = process_nvram_vars(bufp, len);
8148 len += 4 - (len % 4);
8153 bcmerror = dhdsdio_downloadvars(bus, memblock, len + 1);
8155 DHD_ERROR(("%s: error downloading vars: %d\n",
8156 __FUNCTION__, bcmerror));
8160 DHD_ERROR(("%s: error reading nvram file: %d\n",
8161 __FUNCTION__, len));
8162 bcmerror = BCME_SDIO_ERROR;
8167 MFREE(bus->dhd->osh, memblock, MAX_NVRAMBUF_SIZE);
8170 dhd_os_close_image(image);
8176 _dhdsdio_download_firmware(struct dhd_bus *bus)
8180 bool embed = FALSE; /* download embedded firmware */
8181 bool dlok = FALSE; /* download firmware succeeded */
8183 /* Out immediately if no image to download */
8184 if ((bus->fw_path == NULL) || (bus->fw_path[0] == '\0')) {
8185 #ifdef BCMEMBEDIMAGE
8192 /* Keep arm in reset */
8193 if (dhdsdio_download_state(bus, TRUE)) {
8194 DHD_ERROR(("%s: error placing ARM core in reset\n", __FUNCTION__));
8198 /* External image takes precedence if specified */
8199 if ((bus->fw_path != NULL) && (bus->fw_path[0] != '\0')) {
8200 if (dhdsdio_download_code_file(bus, bus->fw_path)) {
8201 DHD_ERROR(("%s: dongle image file download failed\n", __FUNCTION__));
8202 #ifdef BCMEMBEDIMAGE
8214 #ifdef BCMEMBEDIMAGE
8216 if (dhdsdio_download_code_array(bus)) {
8217 DHD_ERROR(("%s: dongle image array download failed\n", __FUNCTION__));
8225 BCM_REFERENCE(embed);
8228 DHD_ERROR(("%s: dongle image download failed\n", __FUNCTION__));
8232 /* EXAMPLE: nvram_array */
8233 /* If a valid nvram_arry is specified as above, it can be passed down to dongle */
8234 /* dhd_bus_set_nvram_params(bus, (char *)&nvram_array); */
8236 /* External nvram takes precedence if specified */
8237 if (dhdsdio_download_nvram(bus)) {
8238 DHD_ERROR(("%s: dongle nvram file download failed\n", __FUNCTION__));
8242 /* Take arm out of reset */
8243 if (dhdsdio_download_state(bus, FALSE)) {
8244 DHD_ERROR(("%s: error getting out of ARM core reset\n", __FUNCTION__));
8255 dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes,
8256 void *pkt, bcmsdh_cmplt_fn_t complete, void *handle)
8260 if (!KSO_ENAB(bus)) {
8261 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
8262 return BCME_NODEVICE;
8265 status = bcmsdh_recv_buf(bus->sdh, addr, fn, flags, buf, nbytes, pkt, complete, handle);
8271 dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes,
8272 void *pkt, bcmsdh_cmplt_fn_t complete, void *handle, int max_retry)
8279 if (!KSO_ENAB(bus)) {
8280 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
8281 return BCME_NODEVICE;
8286 ret = bcmsdh_send_buf(bus->sdh, addr, fn, flags, buf, nbytes,
8287 pkt, complete, handle);
8290 ASSERT(ret != BCME_PENDING);
8292 if (ret == BCME_NODEVICE) {
8293 DHD_ERROR(("%s: Device asleep already\n", __FUNCTION__));
8294 } else if (ret < 0) {
8295 /* On failure, abort the command and terminate the frame */
8296 DHD_ERROR(("%s: sdio error %d, abort command and terminate frame.\n",
8297 __FUNCTION__, ret));
8300 bus->dhd->tx_errors++;
8301 bcmsdh_abort(sdh, SDIO_FUNC_2);
8302 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
8304 for (i = 0; i < READ_FRM_CNT_RETRIES; i++) {
8306 hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WFRAMEBCHI,
8308 lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WFRAMEBCLO,
8310 bus->f1regdata += 2;
8311 if ((hi == 0) && (lo == 0))
8315 } while ((ret < 0) && retrydata && ++retries < max_retry);
8321 dhd_bus_chip(struct dhd_bus *bus)
8323 ASSERT(bus->sih != NULL);
8324 return bus->sih->chip;
8328 dhd_bus_chiprev(struct dhd_bus *bus)
8331 ASSERT(bus->sih != NULL);
8332 return bus->sih->chiprev;
8336 dhd_bus_pub(struct dhd_bus *bus)
8342 dhd_bus_sih(struct dhd_bus *bus)
8344 return (void *)bus->sih;
8348 dhd_bus_txq(struct dhd_bus *bus)
8354 dhd_bus_hdrlen(struct dhd_bus *bus)
8356 return (bus->txglom_enable) ? SDPCM_HDRLEN_TXGLOM : SDPCM_HDRLEN;
8360 dhd_bus_set_dotxinrx(struct dhd_bus *bus, bool val)
8362 bus->dotxinrx = val;
8366 dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag)
8374 if (!bus->dhd->dongle_reset) {
8375 dhd_os_sdlock(dhdp);
8376 dhd_os_wd_timer(dhdp, 0);
8377 #if !defined(IGNORE_ETH0_DOWN)
8378 /* Force flow control as protection when stop come before ifconfig_down */
8379 dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON);
8380 #endif /* !defined(IGNORE_ETH0_DOWN) */
8381 /* Expect app to have torn down any connection before calling */
8382 /* Stop the bus, disable F2 */
8383 dhd_bus_stop(bus, FALSE);
8385 #if defined(OOB_INTR_ONLY)
8386 /* Clean up any pending IRQ */
8387 dhd_enable_oob_intr(bus, FALSE);
8388 bcmsdh_oob_intr_set(bus->sdh, FALSE);
8389 bcmsdh_oob_intr_unregister(bus->sdh);
8392 /* Clean tx/rx buffer pointers, detach from the dongle */
8393 dhdsdio_release_dongle(bus, bus->dhd->osh, TRUE, TRUE);
8395 bus->dhd->dongle_reset = TRUE;
8396 bus->dhd->up = FALSE;
8397 dhd_txglom_enable(dhdp, FALSE);
8398 dhd_os_sdunlock(dhdp);
8400 printk("%s: WLAN OFF DONE\n", __FUNCTION__);
8401 /* App can now remove power from device */
8403 bcmerror = BCME_SDIO_ERROR;
8405 /* App must have restored power to device before calling */
8407 printk("\n\n%s: == WLAN ON ==\n", __FUNCTION__);
8409 if (bus->dhd->dongle_reset) {
8411 dhd_os_sdlock(dhdp);
8412 /* Reset SD client */
8413 bcmsdh_reset(bus->sdh);
8415 /* Attempt to re-attach & download */
8416 if (dhdsdio_probe_attach(bus, bus->dhd->osh, bus->sdh,
8417 (uint32 *)SI_ENUM_BASE,
8419 /* Attempt to download binary to the dongle */
8420 if (dhdsdio_probe_init(bus, bus->dhd->osh, bus->sdh) &&
8421 dhdsdio_download_firmware(bus, bus->dhd->osh, bus->sdh) >= 0) {
8423 /* Re-init bus, enable F2 transfer */
8424 bcmerror = dhd_bus_init((dhd_pub_t *) bus->dhd, FALSE);
8425 if (bcmerror == BCME_OK) {
8426 #if defined(OOB_INTR_ONLY)
8427 dhd_enable_oob_intr(bus, TRUE);
8428 bcmsdh_oob_intr_register(bus->sdh,
8430 bcmsdh_oob_intr_set(bus->sdh, TRUE);
8433 bus->dhd->dongle_reset = FALSE;
8434 bus->dhd->up = TRUE;
8436 #if !defined(IGNORE_ETH0_DOWN)
8437 /* Restore flow control */
8438 dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF);
8440 dhd_os_wd_timer(dhdp, dhd_watchdog_ms);
8442 DHD_TRACE(("%s: WLAN ON DONE\n", __FUNCTION__));
8444 dhd_bus_stop(bus, FALSE);
8445 dhdsdio_release_dongle(bus, bus->dhd->osh,
8449 bcmerror = BCME_SDIO_ERROR;
8451 bcmerror = BCME_SDIO_ERROR;
8453 dhd_os_sdunlock(dhdp);
8455 bcmerror = BCME_SDIO_ERROR;
8456 printk("%s called when dongle is not in reset\n",
8458 printk("Will call dhd_bus_start instead\n");
8459 dhd_bus_resume(dhdp, 1);
8461 dhd_conf_set_hw_oob_intr(bus->sdh, bus->sih->chip); // terence 20120615: fix for OOB initial issue
8463 if ((bcmerror = dhd_bus_start(dhdp)) != 0)
8464 DHD_ERROR(("%s: dhd_bus_start fail with %d\n",
8465 __FUNCTION__, bcmerror));
8471 int dhd_bus_suspend(dhd_pub_t *dhdpub)
8473 return bcmsdh_stop(dhdpub->bus->sdh);
8476 int dhd_bus_resume(dhd_pub_t *dhdpub, int stage)
8478 return bcmsdh_start(dhdpub->bus->sdh, stage);
8481 /* Get Chip ID version */
8482 uint dhd_bus_chip_id(dhd_pub_t *dhdp)
8484 dhd_bus_t *bus = dhdp->bus;
8486 if (bus && bus->sih)
8487 return bus->sih->chip;
8492 /* Get Chip Rev ID version */
8493 uint dhd_bus_chiprev_id(dhd_pub_t *dhdp)
8495 dhd_bus_t *bus = dhdp->bus;
8497 if (bus && bus->sih)
8498 return bus->sih->chiprev;
8503 /* Get Chip Pkg ID version */
8504 uint dhd_bus_chippkg_id(dhd_pub_t *dhdp)
8506 dhd_bus_t *bus = dhdp->bus;
8508 return bus->sih->chippkg;
8511 int dhd_bus_get_ids(struct dhd_bus *bus, uint32 *bus_type, uint32 *bus_num, uint32 *slot_num)
8513 *bus_type = bus->bus;
8514 *bus_num = bus->bus_num;
8515 *slot_num = bus->slot_num;
8520 dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint size)
8525 return dhdsdio_membytes(bus, set, address, data, size);
8528 #if defined(NDISVER) && (NDISVER >= 0x0630)
8530 dhd_bus_reject_ioreqs(dhd_pub_t *dhdp, bool reject)
8533 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
8535 bcmsdh_reject_ioreqs(dhdp->bus->sdh, reject);
8539 dhd_bus_waitfor_iodrain(dhd_pub_t *dhdp)
8542 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
8544 bcmsdh_waitfor_iodrain(dhdp->bus->sdh);
8546 #endif /* (NDISVER) && (NDISVER >= 0x0630) */
8549 dhd_bus_update_fw_nv_path(struct dhd_bus *bus, char *pfw_path, char *pnv_path, char *pconf_path)
8551 bus->fw_path = pfw_path;
8552 bus->nv_path = pnv_path;
8553 bus->dhd->conf_path = pconf_path;
8557 dhd_enableOOB(dhd_pub_t *dhd, bool sleep)
8559 dhd_bus_t *bus = dhd->bus;
8560 sdpcmd_regs_t *regs = bus->regs;
8564 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
8565 /* Tell device to start using OOB wakeup */
8566 W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries);
8567 if (retries > retry_limit) {
8568 DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
8571 /* Turn off our contribution to the HT clock request */
8572 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
8574 /* Make sure the controller has the bus up */
8575 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
8577 /* Send misc interrupt to indicate OOB not needed */
8578 W_SDREG(0, ®s->tosbmailboxdata, retries);
8579 if (retries <= retry_limit)
8580 W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries);
8582 if (retries > retry_limit)
8583 DHD_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n"));
8585 /* Make sure we have SD bus access */
8586 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
8592 dhd_bus_pktq_flush(dhd_pub_t *dhdp)
8594 dhd_bus_t *bus = dhdp->bus;
8595 bool wlfc_enabled = FALSE;
8597 #ifdef PROP_TXSTATUS
8598 wlfc_enabled = (dhd_wlfc_cleanup_txq(dhdp, NULL, 0) != WLFC_UNSUPPORTED);
8600 if (!wlfc_enabled) {
8601 #ifdef DHDTCPACK_SUPPRESS
8602 /* Clean tcp_ack_info_tbl in order to prevent access to flushed pkt,
8603 * when there is a newly coming packet from network stack.
8605 dhd_tcpack_info_tbl_clean(bus->dhd);
8606 #endif /* DHDTCPACK_SUPPRESS */
8607 /* Clear the data packet queues */
8608 pktq_flush(dhdp->osh, &bus->txq, TRUE, NULL, 0);
8614 dhd_sr_config(dhd_pub_t *dhd, bool on)
8616 dhd_bus_t *bus = dhd->bus;
8621 return dhdsdio_clk_devsleep_iovar(bus, on);
8625 dhd_get_chipid(dhd_pub_t *dhd)
8627 dhd_bus_t *bus = dhd->bus;
8629 if (bus && bus->sih)
8630 return (uint16)bus->sih->chip;
8634 #endif /* BCMSDIO */
8637 uint32 dhd_sdio_reg_read(void *h, uint32 addr)
8640 struct dhd_bus *bus = (struct dhd_bus *) h;
8642 dhd_os_sdlock(bus->dhd);
8646 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
8648 rval = bcmsdh_reg_read(bus->sdh, addr, 4);
8650 dhd_os_sdunlock(bus->dhd);
8655 void dhd_sdio_reg_write(void *h, uint32 addr, uint32 val)
8657 struct dhd_bus *bus = (struct dhd_bus *) h;
8659 dhd_os_sdlock(bus->dhd);
8663 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
8665 bcmsdh_reg_write(bus->sdh, addr, 4, val);
8667 dhd_os_sdunlock(bus->dhd);
8669 #endif /* DEBUGGER */
8671 #if defined(SOFTAP_TPUT_ENHANCE)
8672 void dhd_bus_setidletime(dhd_pub_t *dhdp, int idle_time)
8674 if (!dhdp || !dhdp->bus) {
8675 DHD_ERROR(("%s:Bus is Invalid\n", __FUNCTION__));
8678 dhdp->bus->idletime = idle_time;
8681 void dhd_bus_getidletime(dhd_pub_t *dhdp, int* idle_time)
8683 if (!dhdp || !dhdp->bus) {
8684 DHD_ERROR(("%s:Bus is Invalid\n", __FUNCTION__));
8689 DHD_ERROR(("%s:Arg idle_time is NULL\n", __FUNCTION__));
8692 *idle_time = dhdp->bus->idletime;
8694 #endif /* SOFTAP_TPUT_ENHANCE */