2 * DHD Bus Module for SDIO
4 * $Copyright Open Broadcom Corporation$
6 * $Id: dhd_sdio.c 489913 2014-07-08 18:57:48Z $
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);
795 /* Add CMD14 Support */
796 dhdsdio_devcap_set(bus,
797 (SDIOD_CCCR_BRCM_CARDCAP_CMD14_SUPPORT | SDIOD_CCCR_BRCM_CARDCAP_CMD14_EXT));
799 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1,
800 SBSDIO_FUNC1_CHIPCLKCSR, SBSDIO_FORCE_HT, &err);
802 bus->_slpauto = dhd_slpauto ? TRUE : FALSE;
810 * FIX: Be sure KSO bit is enabled
811 * Currently, it's defaulting to 0 which should be 1.
814 dhdsdio_clk_kso_init(dhd_bus_t *bus)
823 * Enable KeepSdioOn (KSO) bit for normal operation
824 * Default is 0 (4334A0) so set it. Fixed in B0.
826 val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, NULL);
827 if (!(val & SBSDIO_FUNC1_SLEEPCSR_KSO_MASK)) {
828 val |= (SBSDIO_FUNC1_SLEEPCSR_KSO_EN << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT);
829 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, val, &err);
831 DHD_ERROR(("%s: SBSDIO_FUNC1_SLEEPCSR err: 0x%x\n", __FUNCTION__, err));
838 #define KSO_WAIT_US 50
839 #define KSO_WAIT_MS 1
840 #define KSO_SLEEP_RETRY_COUNT 20
841 #define ERROR_BCME_NODEVICE_MAX 1
843 #define MAX_KSO_ATTEMPTS (PMU_MAX_TRANSITION_DLY/KSO_WAIT_US)
845 dhdsdio_clk_kso_enab(dhd_bus_t *bus, bool on)
847 uint8 wr_val = 0, rd_val, cmp_val, bmask;
851 if (!bus->dhd->conf->kso_enable)
854 KSO_DBG(("%s> op:%s\n", __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR")));
856 wr_val |= (on << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT);
858 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, wr_val, &err);
861 cmp_val = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK | SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK;
866 /* Put device to sleep, turn off KSO */
868 bmask = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK;
872 rd_val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, &err);
873 if (((rd_val & bmask) == cmp_val) && !err)
876 KSO_DBG(("%s> KSO wr/rd retry:%d, ERR:%x \n", __FUNCTION__, try_cnt, err));
878 if (((try_cnt + 1) % KSO_SLEEP_RETRY_COUNT) == 0) {
879 OSL_SLEEP(KSO_WAIT_MS);
881 OSL_DELAY(KSO_WAIT_US);
883 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, wr_val, &err);
884 } while (try_cnt++ < MAX_KSO_ATTEMPTS);
888 KSO_DBG(("%s> op:%s, try_cnt:%d, rd_val:%x, ERR:%x \n",
889 __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"), try_cnt, rd_val, err));
891 if (try_cnt > MAX_KSO_ATTEMPTS) {
892 DHD_ERROR(("%s> op:%s, ERROR: try_cnt:%d, rd_val:%x, ERR:%x \n",
893 __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"), try_cnt, rd_val, err));
899 dhdsdio_clk_kso_iovar(dhd_bus_t *bus, bool on)
906 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
908 DHD_ERROR(("%s: KSO disable clk: 0x%x\n", __FUNCTION__,
909 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
910 SBSDIO_FUNC1_CHIPCLKCSR, &err)));
911 dhdsdio_clk_kso_enab(bus, FALSE);
913 DHD_ERROR(("%s: KSO enable\n", __FUNCTION__));
915 /* Make sure we have SD bus access */
916 if (bus->clkstate == CLK_NONE) {
917 DHD_ERROR(("%s: Request SD clk\n", __FUNCTION__));
918 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
921 dhdsdio_clk_kso_enab(bus, TRUE);
923 DHD_ERROR(("%s: sleepcsr: 0x%x\n", __FUNCTION__,
924 dhdsdio_sleepcsr_get(bus)));
934 dhdsdio_sleepcsr_get(dhd_bus_t *bus)
939 val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, &err);
941 DHD_TRACE(("Failed to read SLEEPCSR: %d\n", err));
947 dhdsdio_devcap_get(dhd_bus_t *bus)
949 return bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_BRCM_CARDCAP, NULL);
953 dhdsdio_devcap_set(dhd_bus_t *bus, uint8 cap)
957 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_BRCM_CARDCAP, cap, &err);
959 DHD_ERROR(("%s: devcap set err: 0x%x\n", __FUNCTION__, err));
965 dhdsdio_clk_devsleep_iovar(dhd_bus_t *bus, bool on)
974 /* Be sure we request clk before going to sleep
975 * so we can wake-up with clk request already set
976 * else device can go back to sleep immediately
978 if (!SLPAUTO_ENAB(bus))
979 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
981 val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
982 if ((val & SBSDIO_CSR_MASK) == 0) {
983 DHD_ERROR(("%s: No clock before enter sleep:0x%x\n",
986 /* Reset clock request */
987 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
988 SBSDIO_ALP_AVAIL_REQ, &err);
989 DHD_ERROR(("%s: clock before sleep:0x%x\n", __FUNCTION__,
990 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
991 SBSDIO_FUNC1_CHIPCLKCSR, &err)));
995 DHD_TRACE(("%s: clk before sleep: 0x%x\n", __FUNCTION__,
996 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
997 SBSDIO_FUNC1_CHIPCLKCSR, &err)));
999 err = bcmsdh_sleep(bus->sdh, TRUE);
1001 err = dhdsdio_clk_kso_enab(bus, FALSE);
1002 if (OOB_WAKEUP_ENAB(bus))
1004 #if !defined(NDISVER) || (NDISVER < 0x0630)
1005 err = bcmsdh_gpioout(bus->sdh, GPIO_DEV_WAKEUP, FALSE); /* GPIO_1 is off */
1006 #endif /* !defined(NDISVER) || (NDISVER < 0x0630) */
1008 #endif /* USE_CMD14 */
1011 /* Make sure we have SD bus access */
1012 if (bus->clkstate == CLK_NONE) {
1013 DHD_TRACE(("%s: Request SD clk\n", __FUNCTION__));
1014 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
1016 #if !defined(NDISVER) || (NDISVER < 0x0630)
1018 if ((bus->sih->chip == BCM4334_CHIP_ID) && (bus->sih->chiprev == 2)) {
1019 SPINWAIT_SLEEP(sdioh_spinwait_sleep,
1020 (bcmsdh_gpioin(bus->sdh, GPIO_DEV_SRSTATE) != TRUE),
1021 GPIO_DEV_SRSTATE_TIMEOUT);
1023 if (bcmsdh_gpioin(bus->sdh, GPIO_DEV_SRSTATE) == FALSE) {
1024 DHD_ERROR(("ERROR: GPIO_DEV_SRSTATE still low!\n"));
1029 err = bcmsdh_sleep(bus->sdh, FALSE);
1030 if (SLPAUTO_ENAB(bus) && (err != 0)) {
1032 DHD_TRACE(("%s: Resync device sleep\n", __FUNCTION__));
1034 /* Toggle sleep to resync with host and device */
1035 err = bcmsdh_sleep(bus->sdh, TRUE);
1037 err = bcmsdh_sleep(bus->sdh, FALSE);
1041 DHD_ERROR(("%s: CMD14 exit failed again!\n", __FUNCTION__));
1043 /* Toggle sleep to resync with host and device */
1044 err = bcmsdh_sleep(bus->sdh, TRUE);
1046 err = bcmsdh_sleep(bus->sdh, FALSE);
1048 DHD_ERROR(("%s: CMD14 exit failed twice!\n", __FUNCTION__));
1049 DHD_ERROR(("%s: FATAL: Device non-response!\n",
1056 if (OOB_WAKEUP_ENAB(bus))
1058 #if !defined(NDISVER) || (NDISVER < 0x0630)
1059 err = bcmsdh_gpioout(bus->sdh, GPIO_DEV_WAKEUP, TRUE); /* GPIO_1 is on */
1060 #endif /* !defined(NDISVER) || (NDISVER < 0x0630) */
1063 err = dhdsdio_clk_kso_enab(bus, TRUE);
1066 } while ((err != 0) && (++retry < 3));
1069 DHD_ERROR(("ERROR: kso set failed retry: %d\n", retry));
1070 err = 0; /* continue anyway */
1072 #endif /* !USE_CMD14 */
1077 /* Wait for device ready during transition to wake-up */
1078 SPINWAIT_SLEEP(sdioh_spinwait_sleep,
1079 (((csr = dhdsdio_sleepcsr_get(bus)) &
1080 SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK) !=
1081 (SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK)), (20000));
1083 DHD_TRACE(("%s: ExitSleep sleepcsr: 0x%x\n", __FUNCTION__, csr));
1085 if (!(csr & SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK)) {
1086 DHD_ERROR(("%s:ERROR: ExitSleep device NOT Ready! 0x%x\n",
1087 __FUNCTION__, csr));
1088 err = BCME_NODEVICE;
1091 SPINWAIT_SLEEP(sdioh_spinwait_sleep,
1092 (((csr = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
1093 SBSDIO_FUNC1_CHIPCLKCSR, &err)) & SBSDIO_HT_AVAIL) !=
1094 (SBSDIO_HT_AVAIL)), (10000));
1096 DHD_TRACE(("%s: SBSDIO_FUNC1_CHIPCLKCSR : 0x%x\n", __FUNCTION__, csr));
1097 if (!err && ((csr & SBSDIO_HT_AVAIL) != SBSDIO_HT_AVAIL)) {
1098 DHD_ERROR(("%s:ERROR: device NOT Ready! 0x%x\n",
1099 __FUNCTION__, csr));
1100 err = BCME_NODEVICE;
1105 /* Update if successful */
1107 bus->kso = on ? FALSE : TRUE;
1109 DHD_ERROR(("%s: Sleep request failed: kso:%d on:%d err:%d\n",
1110 __FUNCTION__, bus->kso, on, err));
1111 if (!on && retry > 2)
1118 /* Turn backplane clock on or off */
1120 dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok)
1122 #define HT_AVAIL_ERROR_MAX 10
1123 static int ht_avail_error = 0;
1125 uint8 clkctl, clkreq, devctl;
1128 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1137 if (SLPAUTO_ENAB(bus)) {
1138 bus->clkstate = (on ? CLK_AVAIL : CLK_SDONLY);
1143 /* Request HT Avail */
1144 clkreq = bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ;
1148 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
1151 if (ht_avail_error < HT_AVAIL_ERROR_MAX) {
1152 DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err));
1155 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
1156 else if (ht_avail_error == HT_AVAIL_ERROR_MAX) {
1157 dhd_os_send_hang_message(bus->dhd);
1159 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) */
1166 /* Check current status */
1167 clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
1169 DHD_ERROR(("%s: HT Avail read error: %d\n", __FUNCTION__, err));
1173 #if !defined(OOB_INTR_ONLY)
1174 /* Go to pending and await interrupt if appropriate */
1175 if (!SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) {
1176 /* Allow only clock-available interrupt */
1177 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
1179 DHD_ERROR(("%s: Devctl access error setting CA: %d\n",
1180 __FUNCTION__, err));
1184 devctl |= SBSDIO_DEVCTL_CA_INT_ONLY;
1185 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
1186 DHD_INFO(("CLKCTL: set PENDING\n"));
1187 bus->clkstate = CLK_PENDING;
1190 #endif /* !defined (OOB_INTR_ONLY) */
1192 if (bus->clkstate == CLK_PENDING) {
1193 /* Cancel CA-only interrupt filter */
1194 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
1195 devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
1196 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
1200 /* Otherwise, wait here (polling) for HT Avail */
1201 if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
1202 SPINWAIT_SLEEP(sdioh_spinwait_sleep,
1203 ((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
1204 SBSDIO_FUNC1_CHIPCLKCSR, &err)),
1205 !SBSDIO_CLKAV(clkctl, bus->alp_only)), PMU_MAX_TRANSITION_DLY);
1208 DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err));
1211 if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
1212 DHD_ERROR(("%s: HT Avail timeout (%d): clkctl 0x%02x\n",
1213 __FUNCTION__, PMU_MAX_TRANSITION_DLY, clkctl));
1217 /* Mark clock available */
1218 bus->clkstate = CLK_AVAIL;
1219 DHD_INFO(("CLKCTL: turned ON\n"));
1221 #if defined(DHD_DEBUG)
1222 if (bus->alp_only == TRUE) {
1223 #if !defined(BCMLXSDMMC)
1224 if (!SBSDIO_ALPONLY(clkctl)) {
1225 DHD_ERROR(("%s: HT Clock, when ALP Only\n", __FUNCTION__));
1227 #endif /* !defined(BCMLXSDMMC) */
1229 if (SBSDIO_ALPONLY(clkctl)) {
1230 DHD_ERROR(("%s: HT Clock should be on.\n", __FUNCTION__));
1233 #endif /* defined (DHD_DEBUG) */
1235 bus->activity = TRUE;
1236 #ifdef DHD_USE_IDLECOUNT
1238 #endif /* DHD_USE_IDLECOUNT */
1242 if (bus->clkstate == CLK_PENDING) {
1243 /* Cancel CA-only interrupt filter */
1244 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
1245 devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
1246 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
1249 bus->clkstate = CLK_SDONLY;
1250 if (!SR_ENAB(bus)) {
1251 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
1252 DHD_INFO(("CLKCTL: turned OFF\n"));
1254 DHD_ERROR(("%s: Failed access turning clock off: %d\n",
1255 __FUNCTION__, err));
1263 /* Change idle/active SD state */
1265 dhdsdio_sdclk(dhd_bus_t *bus, bool on)
1270 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1273 if (bus->idleclock == DHD_IDLE_STOP) {
1274 /* Turn on clock and restore mode */
1276 err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0,
1277 &iovalue, sizeof(iovalue), TRUE);
1279 DHD_ERROR(("%s: error enabling sd_clock: %d\n",
1280 __FUNCTION__, err));
1284 iovalue = bus->sd_mode;
1285 err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
1286 &iovalue, sizeof(iovalue), TRUE);
1288 DHD_ERROR(("%s: error changing sd_mode: %d\n",
1289 __FUNCTION__, err));
1292 } else if (bus->idleclock != DHD_IDLE_ACTIVE) {
1293 /* Restore clock speed */
1294 iovalue = bus->sd_divisor;
1295 err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
1296 &iovalue, sizeof(iovalue), TRUE);
1298 DHD_ERROR(("%s: error restoring sd_divisor: %d\n",
1299 __FUNCTION__, err));
1303 bus->clkstate = CLK_SDONLY;
1305 /* Stop or slow the SD clock itself */
1306 if ((bus->sd_divisor == -1) || (bus->sd_mode == -1)) {
1307 DHD_TRACE(("%s: can't idle clock, divisor %d mode %d\n",
1308 __FUNCTION__, bus->sd_divisor, bus->sd_mode));
1311 if (bus->idleclock == DHD_IDLE_STOP) {
1313 /* Change to SD1 mode and turn off clock */
1315 err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
1316 &iovalue, sizeof(iovalue), TRUE);
1318 DHD_ERROR(("%s: error changing sd_clock: %d\n",
1319 __FUNCTION__, err));
1325 err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0,
1326 &iovalue, sizeof(iovalue), TRUE);
1328 DHD_ERROR(("%s: error disabling sd_clock: %d\n",
1329 __FUNCTION__, err));
1332 } else if (bus->idleclock != DHD_IDLE_ACTIVE) {
1333 /* Set divisor to idle value */
1334 iovalue = bus->idleclock;
1335 err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
1336 &iovalue, sizeof(iovalue), TRUE);
1338 DHD_ERROR(("%s: error changing sd_divisor: %d\n",
1339 __FUNCTION__, err));
1343 bus->clkstate = CLK_NONE;
1349 /* Transition SD and backplane clock readiness */
1351 dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok)
1355 uint oldstate = bus->clkstate;
1356 #endif /* DHD_DEBUG */
1358 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1360 /* Early exit if we're already there */
1361 if (bus->clkstate == target) {
1362 if (target == CLK_AVAIL) {
1363 dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
1364 bus->activity = TRUE;
1365 #ifdef DHD_USE_IDLECOUNT
1367 #endif /* DHD_USE_IDLECOUNT */
1374 /* Make sure SD clock is available */
1375 if (bus->clkstate == CLK_NONE)
1376 dhdsdio_sdclk(bus, TRUE);
1377 /* Now request HT Avail on the backplane */
1378 ret = dhdsdio_htclk(bus, TRUE, pendok);
1379 if (ret == BCME_OK) {
1380 dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
1381 bus->activity = TRUE;
1382 #ifdef DHD_USE_IDLECOUNT
1384 #endif /* DHD_USE_IDLECOUNT */
1389 /* Remove HT request, or bring up SD clock */
1390 if (bus->clkstate == CLK_NONE)
1391 ret = dhdsdio_sdclk(bus, TRUE);
1392 else if (bus->clkstate == CLK_AVAIL)
1393 ret = dhdsdio_htclk(bus, FALSE, FALSE);
1395 DHD_ERROR(("dhdsdio_clkctl: request for %d -> %d\n",
1396 bus->clkstate, target));
1397 if (ret == BCME_OK) {
1398 dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
1403 /* Make sure to remove HT request */
1404 if (bus->clkstate == CLK_AVAIL)
1405 ret = dhdsdio_htclk(bus, FALSE, FALSE);
1406 /* Now remove the SD clock */
1407 ret = dhdsdio_sdclk(bus, FALSE);
1409 if (dhd_console_ms == 0)
1410 #endif /* DHD_DEBUG */
1412 dhd_os_wd_timer(bus->dhd, 0);
1416 DHD_INFO(("dhdsdio_clkctl: %d -> %d\n", oldstate, bus->clkstate));
1417 #endif /* DHD_DEBUG */
1423 dhdsdio_bussleep(dhd_bus_t *bus, bool sleep)
1426 bcmsdh_info_t *sdh = bus->sdh;
1427 sdpcmd_regs_t *regs = bus->regs;
1430 DHD_INFO(("dhdsdio_bussleep: request %s (currently %s)\n",
1431 (sleep ? "SLEEP" : "WAKE"),
1432 (bus->sleeping ? "SLEEP" : "WAKE")));
1434 if (bus->dhd->hang_was_sent)
1437 /* Done if we're already in the requested state */
1438 if (sleep == bus->sleeping)
1441 /* Going to sleep: set the alarm and turn off the lights... */
1443 /* Don't sleep if something is pending */
1444 if (bus->dpc_sched || bus->rxskip || pktq_len(&bus->txq))
1448 if (!SLPAUTO_ENAB(bus)) {
1449 /* Disable SDIO interrupts (no longer interested) */
1450 bcmsdh_intr_disable(bus->sdh);
1452 /* Make sure the controller has the bus up */
1453 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
1455 /* Tell device to start using OOB wakeup */
1456 W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries);
1457 if (retries > retry_limit)
1458 DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
1460 /* Turn off our contribution to the HT clock request */
1461 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
1463 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
1464 SBSDIO_FORCE_HW_CLKREQ_OFF, NULL);
1466 /* Isolate the bus */
1467 if (bus->sih->chip != BCM4329_CHIP_ID &&
1468 bus->sih->chip != BCM4319_CHIP_ID) {
1469 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL,
1470 SBSDIO_DEVCTL_PADS_ISO, NULL);
1473 /* Leave interrupts enabled since device can exit sleep and
1476 err = dhdsdio_clk_devsleep_iovar(bus, TRUE /* sleep */);
1480 bus->sleeping = TRUE;
1481 wake_up(&bus->bus_sleep);
1483 /* Waking up: bus power up is ok, set local state */
1485 if (!SLPAUTO_ENAB(bus)) {
1486 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0, &err);
1488 /* Force pad isolation off if possible (in case power never toggled) */
1489 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, 0, NULL);
1492 /* Make sure the controller has the bus up */
1493 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
1495 /* Send misc interrupt to indicate OOB not needed */
1496 W_SDREG(0, ®s->tosbmailboxdata, retries);
1497 if (retries <= retry_limit)
1498 W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries);
1500 if (retries > retry_limit)
1501 DHD_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n"));
1503 /* Make sure we have SD bus access */
1504 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
1506 /* Enable interrupts again */
1507 if (bus->intr && (bus->dhd->busstate == DHD_BUS_DATA)) {
1508 bus->intdis = FALSE;
1509 bcmsdh_intr_enable(bus->sdh);
1512 err = dhdsdio_clk_devsleep_iovar(bus, FALSE /* wake */);
1517 bus->sleeping = FALSE;
1525 #if defined(OOB_INTR_ONLY)
1527 dhd_enable_oob_intr(struct dhd_bus *bus, bool enable)
1530 bcmsdh_enable_hw_oob_intr(bus->sdh, enable);
1532 sdpcmd_regs_t *regs = bus->regs;
1535 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
1536 if (enable == TRUE) {
1538 /* Tell device to start using OOB wakeup */
1539 W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries);
1540 if (retries > retry_limit)
1541 DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
1544 /* Send misc interrupt to indicate OOB not needed */
1545 W_SDREG(0, ®s->tosbmailboxdata, retries);
1546 if (retries <= retry_limit)
1547 W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries);
1550 /* Turn off our contribution to the HT clock request */
1551 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
1552 #endif /* !defined(HW_OOB) */
1557 dhd_bus_txdata(struct dhd_bus *bus, void *pkt)
1559 int ret = BCME_ERROR;
1562 #if defined(DHD_TX_DUMP) || defined(DHD_8021X_DUMP)
1565 #endif /* DHD_TX_DUMP || DHD_8021X_DUMP */
1567 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1569 osh = bus->dhd->osh;
1570 datalen = PKTLEN(osh, pkt);
1573 /* Push the test header if doing loopback */
1574 if (bus->ext_loop) {
1576 PKTPUSH(osh, pkt, SDPCM_TEST_HDRLEN);
1577 data = PKTDATA(osh, pkt);
1578 *data++ = SDPCM_TEST_ECHOREQ;
1579 *data++ = (uint8)bus->loopid++;
1580 *data++ = (datalen >> 0);
1581 *data++ = (datalen >> 8);
1582 datalen += SDPCM_TEST_HDRLEN;
1585 BCM_REFERENCE(datalen);
1588 #if defined(DHD_TX_DUMP) || defined(DHD_8021X_DUMP)
1589 dump_data = PKTDATA(osh, pkt);
1590 dump_data += 4; /* skip 4 bytes header */
1591 protocol = (dump_data[12] << 8) | dump_data[13];
1593 if (protocol == ETHER_TYPE_802_1X) {
1594 DHD_ERROR(("ETHER_TYPE_802_1X [TX]: ver %d, type %d, replay %d\n",
1595 dump_data[14], dump_data[15], dump_data[30]));
1597 #endif /* DHD_TX_DUMP || DHD_8021X_DUMP */
1599 #if defined(DHD_TX_DUMP) && defined(DHD_TX_FULL_DUMP)
1602 DHD_ERROR(("TX DUMP\n"));
1604 for (i = 0; i < (datalen - 4); i++) {
1605 DHD_ERROR(("%02X ", dump_data[i]));
1611 #endif /* DHD_TX_DUMP && DHD_TX_FULL_DUMP */
1613 prec = PRIO2PREC((PKTPRIO(pkt) & PRIOMASK));
1615 /* Check for existing queue, current flow-control, pending event, or pending clock */
1616 if (dhd_deferred_tx || bus->fcstate || pktq_len(&bus->txq) || bus->dpc_sched ||
1617 (!DATAOK(bus)) || (bus->flowcontrol & NBITVAL(prec)) ||
1618 (bus->clkstate != CLK_AVAIL)) {
1622 DHD_TRACE(("%s: deferring pktq len %d\n", __FUNCTION__, pktq_len(&bus->txq)));
1625 /* Priority based enq */
1626 dhd_os_sdlock_txq(bus->dhd);
1627 deq_ret = dhd_prec_enq(bus->dhd, &bus->txq, pkt, prec);
1628 dhd_os_sdunlock_txq(bus->dhd);
1631 #ifdef PROP_TXSTATUS
1632 if (DHD_PKTTAG_WLFCPKT(PKTTAG(pkt)) == 0)
1633 #endif /* PROP_TXSTATUS */
1635 #ifdef DHDTCPACK_SUPPRESS
1636 if (dhd_tcpack_check_xmit(bus->dhd, pkt) == BCME_ERROR) {
1637 DHD_ERROR(("%s %d: tcpack_suppress ERROR!!! Stop using\n",
1638 __FUNCTION__, __LINE__));
1639 dhd_tcpack_suppress_set(bus->dhd, TCPACK_SUP_OFF);
1641 #endif /* DHDTCPACK_SUPPRESS */
1642 dhd_txcomplete(bus->dhd, pkt, FALSE);
1643 PKTFREE(osh, pkt, TRUE);
1645 ret = BCME_NORESOURCE;
1649 dhd_os_sdlock_txq(bus->dhd);
1650 pkq_len = pktq_len(&bus->txq);
1651 dhd_os_sdunlock_txq(bus->dhd);
1652 if (pkq_len >= FCHI) {
1653 bool wlfc_enabled = FALSE;
1654 #ifdef PROP_TXSTATUS
1655 wlfc_enabled = (dhd_wlfc_flowcontrol(bus->dhd, ON, FALSE) !=
1658 if (!wlfc_enabled && dhd_doflow) {
1659 dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON);
1664 dhd_os_sdlock_txq(bus->dhd);
1665 if (pktq_plen(&bus->txq, prec) > qcount[prec])
1666 qcount[prec] = pktq_plen(&bus->txq, prec);
1667 dhd_os_sdunlock_txq(bus->dhd);
1670 /* Schedule DPC if needed to send queued packet(s) */
1671 if (dhd_deferred_tx && !bus->dpc_sched) {
1672 bus->dpc_sched = TRUE;
1673 dhd_sched_dpc(bus->dhd);
1676 int chan = SDPCM_DATA_CHANNEL;
1679 chan = (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL);
1681 /* Lock: we're about to use shared data/code (and SDIO) */
1682 dhd_os_sdlock(bus->dhd);
1684 /* Otherwise, send it now */
1686 /* Make sure back plane ht clk is on, no pending allowed */
1687 dhdsdio_clkctl(bus, CLK_AVAIL, TRUE);
1689 ret = dhdsdio_txpkt(bus, chan, &pkt, 1, TRUE);
1692 bus->dhd->tx_errors++;
1694 bus->dhd->dstats.tx_bytes += datalen;
1696 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
1697 bus->activity = FALSE;
1698 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
1701 dhd_os_sdunlock(bus->dhd);
1707 /* align packet data pointer and packet length to n-byte boundary, process packet headers,
1708 * a new packet may be allocated if there is not enough head and/or tail from for padding.
1709 * the caller is responsible for updating the glom size in the head packet (when glom is
1712 * pad_pkt_len: returns the length of extra padding needed from the padding packet, this parameter
1713 * is taken in tx glom mode only
1715 * new_pkt: out, pointer of the new packet allocated due to insufficient head room for alignment
1716 * padding, NULL if not needed, the caller is responsible for freeing the new packet
1718 * return: positive value - length of the packet, including head and tail padding
1719 * negative value - errors
1721 static int dhdsdio_txpkt_preprocess(dhd_bus_t *bus, void *pkt, int chan, int txseq,
1722 int prev_chain_total_len, bool last_chained_pkt,
1723 int *pad_pkt_len, void **new_pkt)
1730 int tail_padding = 0;
1732 uint32 swhdr_offset;
1733 bool alloc_new_pkt = FALSE;
1734 uint8 sdpcm_hdrlen = bus->txglom_enable ? SDPCM_HDRLEN_TXGLOM : SDPCM_HDRLEN;
1737 osh = bus->dhd->osh;
1739 #ifdef DHDTCPACK_SUPPRESS
1740 if (dhd_tcpack_check_xmit(bus->dhd, pkt) == BCME_ERROR) {
1741 DHD_ERROR(("%s %d: tcpack_suppress ERROR!!! Stop using it\n",
1742 __FUNCTION__, __LINE__));
1743 dhd_tcpack_suppress_set(bus->dhd, TCPACK_SUP_OFF);
1745 #endif /* DHDTCPACK_SUPPRESS */
1747 /* Add space for the SDPCM hardware/software headers */
1748 PKTPUSH(osh, pkt, sdpcm_hdrlen);
1749 ASSERT(ISALIGNED((uintptr)PKTDATA(osh, pkt), 2));
1751 frame = (uint8*)PKTDATA(osh, pkt);
1752 pkt_len = (uint16)PKTLEN(osh, pkt);
1755 frame = (uint8*)PKTDATA(osh, pkt);
1756 if (PKTLEN(osh, pkt) >= 100) {
1757 htsf_ts = (htsfts_t*) (frame + HTSF_HOSTOFFSET + 12);
1758 if (htsf_ts->magic == HTSFMAGIC) {
1759 htsf_ts->c20 = get_cycles();
1760 htsf_ts->t20 = dhd_get_htsf(bus->dhd->info, 0);
1763 #endif /* WLMEDIA_HTSF */
1765 if (PKTPRIO(pkt) < ARRAYSIZE(tx_packets))
1766 tx_packets[PKTPRIO(pkt)]++;
1767 #endif /* DHD_DEBUG */
1769 /* align the data pointer, allocate a new packet if there is not enough space (new
1770 * packet data pointer will be aligned thus no padding will be needed)
1772 head_padding = (ulong)frame % DHD_SDALIGN;
1773 if (PKTHEADROOM(osh, pkt) < head_padding) {
1775 alloc_new_pkt = TRUE;
1777 uint cur_chain_total_len;
1778 int chain_tail_padding = 0;
1780 /* All packets need to be aligned by DHD_SDALIGN */
1781 modulo = (pkt_len + head_padding) % DHD_SDALIGN;
1782 tail_padding = modulo > 0 ? (DHD_SDALIGN - modulo) : 0;
1784 /* Total pkt chain length needs to be aligned by block size,
1785 * unless it is a single pkt chain with total length less than one block size,
1786 * which we prefer sending by byte mode.
1788 * Do the chain alignment here if
1789 * 1. This is the last pkt of the chain of multiple pkts or a single pkt.
1790 * 2-1. This chain is of multiple pkts, or
1791 * 2-2. This is a single pkt whose size is longer than one block size.
1793 cur_chain_total_len = prev_chain_total_len +
1794 (head_padding + pkt_len + tail_padding);
1795 if (last_chained_pkt && bus->blocksize != 0 &&
1796 (cur_chain_total_len > (int)bus->blocksize || prev_chain_total_len > 0)) {
1797 modulo = cur_chain_total_len % bus->blocksize;
1798 chain_tail_padding = modulo > 0 ? (bus->blocksize - modulo) : 0;
1801 #ifdef DHDENABLE_TAILPAD
1802 if (PKTTAILROOM(osh, pkt) < tail_padding) {
1803 /* We don't have tail room to align by DHD_SDALIGN */
1804 alloc_new_pkt = TRUE;
1805 bus->tx_tailpad_pktget++;
1806 } else if (PKTTAILROOM(osh, pkt) < tail_padding + chain_tail_padding) {
1807 /* We have tail room for tail_padding of this pkt itself, but not for
1808 * total pkt chain alignment by block size.
1809 * Use the padding packet to avoid memory copy if applicable,
1810 * otherwise, just allocate a new pkt.
1813 *pad_pkt_len = chain_tail_padding;
1814 bus->tx_tailpad_chain++;
1816 alloc_new_pkt = TRUE;
1817 bus->tx_tailpad_pktget++;
1820 /* This last pkt's tailroom is sufficient to hold both tail_padding
1821 * of the pkt itself and chain_tail_padding of total pkt chain
1823 #endif /* DHDENABLE_TAILPAD */
1824 tail_padding += chain_tail_padding;
1827 DHD_INFO(("%s sdhdr len + orig_pkt_len %d h_pad %d t_pad %d pad_pkt_len %d\n",
1828 __FUNCTION__, pkt_len, head_padding, tail_padding, *pad_pkt_len));
1830 if (alloc_new_pkt) {
1835 ASSERT(*pad_pkt_len == 0);
1837 DHD_INFO(("%s allocating new packet for padding\n", __FUNCTION__));
1839 /* head pointer is aligned now, no padding needed */
1842 /* update the tail padding as it depends on the head padding, since a new packet is
1843 * allocated, the head padding is non longer needed and packet length is chagned
1846 cur_total_len = prev_chain_total_len + pkt_len;
1847 if (last_chained_pkt && bus->blocksize != 0 &&
1848 (cur_total_len > (int)bus->blocksize || prev_chain_total_len > 0)) {
1849 modulo = cur_total_len % bus->blocksize;
1850 tail_padding = modulo > 0 ? (bus->blocksize - modulo) : 0;
1853 modulo = pkt_len % DHD_SDALIGN;
1854 tail_padding = modulo > 0 ? (DHD_SDALIGN - modulo) : 0;
1857 newpkt_size = PKTLEN(osh, pkt) + bus->blocksize + DHD_SDALIGN;
1858 bus->dhd->tx_realloc++;
1859 tmp_pkt = PKTGET(osh, newpkt_size, TRUE);
1860 if (tmp_pkt == NULL) {
1861 DHD_ERROR(("failed to alloc new %d byte packet\n", newpkt_size));
1864 PKTALIGN(osh, tmp_pkt, PKTLEN(osh, pkt), DHD_SDALIGN);
1865 bcopy(PKTDATA(osh, pkt), PKTDATA(osh, tmp_pkt), PKTLEN(osh, pkt));
1871 PKTPUSH(osh, pkt, head_padding);
1873 frame = (uint8*)PKTDATA(osh, pkt);
1874 bzero(frame, head_padding + sdpcm_hdrlen);
1875 pkt_len = (uint16)PKTLEN(osh, pkt);
1877 /* the header has the followming format
1878 * 4-byte HW frame tag: length, ~length (for glom this is the total length)
1880 * 8-byte HW extesion flags (glom mode only) as the following:
1881 * 2-byte packet length, excluding HW tag and padding
1882 * 2-byte frame channel and frame flags (e.g. next frame following)
1883 * 2-byte header length
1884 * 2-byte tail padding size
1886 * 8-byte SW frame tags as the following
1887 * 4-byte flags: host tx seq, channel, data offset
1891 swhdr_offset = SDPCM_FRAMETAG_LEN;
1893 /* hardware frame tag:
1895 * in tx-glom mode, dongle only checks the hardware frame tag in the first
1896 * packet and sees it as the total lenght of the glom (including tail padding),
1897 * for each packet in the glom, the packet length needs to be updated, (see
1900 * in non tx-glom mode, PKTLEN still need to include tail padding as to be
1901 * referred to in sdioh_request_buffer(). The tail length will be excluded in
1902 * dhdsdio_txpkt_postprocess().
1904 *(uint16*)frame = (uint16)htol16(pkt_len);
1905 *(((uint16*)frame) + 1) = (uint16)htol16(~pkt_len);
1906 pkt_len += tail_padding;
1908 /* hardware extesion flags */
1909 if (bus->txglom_enable) {
1913 swhdr_offset += SDPCM_HWEXT_LEN;
1914 hwheader1 = (pkt_len - SDPCM_FRAMETAG_LEN - tail_padding) |
1915 (last_chained_pkt << 24);
1916 hwheader2 = (tail_padding) << 16;
1917 htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN);
1918 htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4);
1920 PKTSETLEN((osh), (pkt), (pkt_len));
1922 /* software frame tags */
1923 swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK)
1924 | (txseq % SDPCM_SEQUENCE_WRAP) |
1925 (((head_padding + sdpcm_hdrlen) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
1926 htol32_ua_store(swheader, frame + swhdr_offset);
1927 htol32_ua_store(0, frame + swhdr_offset + sizeof(swheader));
1932 static int dhdsdio_txpkt_postprocess(dhd_bus_t *bus, void *pkt)
1938 int swhdr_offset = SDPCM_FRAMETAG_LEN + (bus->txglom_enable ? SDPCM_HWEXT_LEN : 0);
1941 osh = bus->dhd->osh;
1943 /* restore pkt buffer pointer, but keeps the header pushed by dhd_prot_hdrpush */
1944 frame = (uint8*)PKTDATA(osh, pkt);
1946 DHD_INFO(("%s PKTLEN before postprocess %d",
1947 __FUNCTION__, PKTLEN(osh, pkt)));
1949 /* PKTLEN still includes tail_padding, so exclude it.
1950 * We shall have head_padding + original pkt_len for PKTLEN afterwards.
1952 if (bus->txglom_enable) {
1953 /* txglom pkts have tail_padding length in HW ext header */
1954 tail_padding = ltoh32_ua(frame + SDPCM_FRAMETAG_LEN + 4) >> 16;
1955 PKTSETLEN(osh, pkt, PKTLEN(osh, pkt) - tail_padding);
1956 DHD_INFO((" txglom pkt: tail_padding %d PKTLEN %d\n",
1957 tail_padding, PKTLEN(osh, pkt)));
1959 /* non-txglom pkts have head_padding + original pkt length in HW frame tag.
1960 * We cannot refer to this field for txglom pkts as the first pkt of the chain will
1961 * have the field for the total length of the chain.
1963 PKTSETLEN(osh, pkt, *(uint16*)frame);
1964 DHD_INFO((" non-txglom pkt: HW frame tag len %d after PKTLEN %d\n",
1965 *(uint16*)frame, PKTLEN(osh, pkt)));
1968 data_offset = ltoh32_ua(frame + swhdr_offset);
1969 data_offset = (data_offset & SDPCM_DOFFSET_MASK) >> SDPCM_DOFFSET_SHIFT;
1970 /* Get rid of sdpcm header + head_padding */
1971 PKTPULL(osh, pkt, data_offset);
1973 DHD_INFO(("%s data_offset %d, PKTLEN %d\n",
1974 __FUNCTION__, data_offset, PKTLEN(osh, pkt)));
1979 static int dhdsdio_txpkt(dhd_bus_t *bus, uint chan, void** pkts, int num_pkt, bool free_pkt)
1988 void *head_pkt = NULL;
1989 void *prev_pkt = NULL;
1990 int pad_pkt_len = 0;
1991 int new_pkt_num = 0;
1992 void *new_pkts[MAX_TX_PKTCHAIN_CNT];
1993 bool wlfc_enabled = FALSE;
1995 if (bus->dhd->dongle_reset)
1996 return BCME_NOTREADY;
1999 osh = bus->dhd->osh;
2000 /* init new_pkts[0] to make some compiler happy, not necessary as we check new_pkt_num */
2003 for (i = 0; i < num_pkt; i++) {
2006 void *new_pkt = NULL;
2010 last_pkt = (i == num_pkt - 1);
2011 pkt_len = dhdsdio_txpkt_preprocess(bus, pkt, chan, bus->tx_seq + i,
2012 total_len, last_pkt, &pad_pkt_len, &new_pkt);
2017 new_pkts[new_pkt_num++] = new_pkt;
2019 total_len += pkt_len;
2021 PKTSETNEXT(osh, pkt, NULL);
2022 /* insert the packet into the list */
2023 head_pkt ? PKTSETNEXT(osh, prev_pkt, pkt) : (head_pkt = pkt);
2028 /* Update the HW frame tag (total length) in the first pkt of the glom */
2029 if (bus->txglom_enable) {
2032 total_len += pad_pkt_len;
2033 frame = (uint8*)PKTDATA(osh, head_pkt);
2034 *(uint16*)frame = (uint16)htol16(total_len);
2035 *(((uint16*)frame) + 1) = (uint16)htol16(~total_len);
2039 #ifdef DHDENABLE_TAILPAD
2040 /* if a padding packet if needed, insert it to the end of the link list */
2042 PKTSETLEN(osh, bus->pad_pkt, pad_pkt_len);
2043 PKTSETNEXT(osh, pkt, bus->pad_pkt);
2045 #endif /* DHDENABLE_TAILPAD */
2047 /* dhd_bcmsdh_send_buf ignores the buffer pointer if he packet
2048 * parameter is not NULL, for non packet chian we pass NULL pkt pointer
2049 * so it will take the aligned length and buffer pointer.
2051 pkt_chain = PKTNEXT(osh, head_pkt) ? head_pkt : NULL;
2052 ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
2053 PKTDATA(osh, head_pkt), total_len, pkt_chain, NULL, NULL, TXRETRIES);
2055 bus->tx_seq = (bus->tx_seq + num_pkt) % SDPCM_SEQUENCE_WRAP;
2057 /* if a padding packet was needed, remove it from the link list as it not a data pkt */
2058 if (pad_pkt_len && pkt)
2059 PKTSETNEXT(osh, pkt, NULL);
2064 void *pkt_next = PKTNEXT(osh, pkt);
2065 PKTSETNEXT(osh, pkt, NULL);
2066 dhdsdio_txpkt_postprocess(bus, pkt);
2070 /* new packets might be allocated due to insufficient room for padding, but we
2071 * still have to indicate the original packets to upper layer
2073 for (i = 0; i < num_pkt; i++) {
2075 wlfc_enabled = FALSE;
2076 #ifdef PROP_TXSTATUS
2077 if (DHD_PKTTAG_WLFCPKT(PKTTAG(pkt))) {
2078 wlfc_enabled = (dhd_wlfc_txcomplete(bus->dhd, pkt, ret == 0) !=
2081 #endif /* PROP_TXSTATUS */
2082 if (!wlfc_enabled) {
2083 PKTSETNEXT(osh, pkt, NULL);
2084 dhd_txcomplete(bus->dhd, pkt, ret != 0);
2086 PKTFREE(osh, pkt, TRUE);
2090 for (i = 0; i < new_pkt_num; i++)
2091 PKTFREE(osh, new_pkts[i], TRUE);
2097 dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes)
2101 uint16 txpktqlen = 0;
2102 uint32 intstatus = 0;
2106 dhd_pub_t *dhd = bus->dhd;
2107 sdpcmd_regs_t *regs = bus->regs;
2109 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2111 if (!KSO_ENAB(bus)) {
2112 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
2113 return BCME_NODEVICE;
2117 tx_prec_map = ~bus->flowcontrol;
2118 for (cnt = 0; (cnt < maxframes) && DATAOK(bus);) {
2121 void *pkts[MAX_TX_PKTCHAIN_CNT];
2124 dhd_os_sdlock_txq(bus->dhd);
2125 if (bus->txglom_enable) {
2126 num_pkt = MIN((uint32)DATABUFCNT(bus), (uint32)bus->txglomsize);
2127 num_pkt = MIN(num_pkt, ARRAYSIZE(pkts));
2129 num_pkt = MIN(num_pkt, pktq_mlen(&bus->txq, tx_prec_map));
2130 for (i = 0; i < num_pkt; i++) {
2131 pkts[i] = pktq_mdeq(&bus->txq, ~bus->flowcontrol, &prec_out);
2133 DHD_ERROR(("%s: pktq_mlen non-zero when no pkt\n",
2139 datalen += PKTLEN(osh, pkts[i]);
2141 dhd_os_sdunlock_txq(bus->dhd);
2145 if (dhdsdio_txpkt(bus, SDPCM_DATA_CHANNEL, pkts, i, TRUE) != BCME_OK)
2148 dhd->dstats.tx_bytes += datalen;
2151 /* In poll mode, need to check for other events */
2152 if (!bus->intr && cnt)
2154 /* Check device status, signal pending interrupt */
2155 R_SDREG(intstatus, ®s->intstatus, retries);
2157 if (bcmsdh_regfail(bus->sdh))
2159 if (intstatus & bus->hostintmask)
2165 dhd_os_sdlock_txq(bus->dhd);
2166 txpktqlen = pktq_len(&bus->txq);
2167 dhd_os_sdunlock_txq(bus->dhd);
2169 /* Do flow-control if needed */
2170 if (dhd->up && (dhd->busstate == DHD_BUS_DATA) && (txpktqlen < FCLOW)) {
2171 bool wlfc_enabled = FALSE;
2172 #ifdef PROP_TXSTATUS
2173 wlfc_enabled = (dhd_wlfc_flowcontrol(dhd, OFF, TRUE) != WLFC_UNSUPPORTED);
2175 if (!wlfc_enabled && dhd_doflow && dhd->txoff) {
2176 dhd_txflowcontrol(dhd, ALL_INTERFACES, OFF);
2184 dhdsdio_sendpendctl(dhd_bus_t *bus)
2186 bcmsdh_info_t *sdh = bus->sdh;
2188 uint8* frame_seq = bus->ctrl_frame_buf + SDPCM_FRAMETAG_LEN;
2190 if (bus->txglom_enable)
2191 frame_seq += SDPCM_HWEXT_LEN;
2193 if (*frame_seq != bus->tx_seq) {
2194 DHD_INFO(("%s IOCTL frame seq lag detected!"
2195 " frm_seq:%d != bus->tx_seq:%d, corrected\n",
2196 __FUNCTION__, *frame_seq, bus->tx_seq));
2197 *frame_seq = bus->tx_seq;
2200 ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
2201 (uint8 *)bus->ctrl_frame_buf, (uint32)bus->ctrl_frame_len,
2202 NULL, NULL, NULL, 1);
2204 bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
2206 bus->ctrl_frame_stat = FALSE;
2207 dhd_wait_event_wakeup(bus->dhd);
2211 dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen)
2213 static int err_nodevice = 0;
2217 bcmsdh_info_t *sdh = bus->sdh;
2220 uint8 sdpcm_hdrlen = bus->txglom_enable ? SDPCM_HDRLEN_TXGLOM : SDPCM_HDRLEN;
2222 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2224 if (bus->dhd->dongle_reset)
2227 /* Back the pointer to make a room for bus header */
2228 frame = msg - sdpcm_hdrlen;
2229 len = (msglen += sdpcm_hdrlen);
2231 /* Add alignment padding (optional for ctl frames) */
2233 if ((doff = ((uintptr)frame % DHD_SDALIGN))) {
2237 bzero(frame, doff + sdpcm_hdrlen);
2239 ASSERT(doff < DHD_SDALIGN);
2241 doff += sdpcm_hdrlen;
2243 /* Round send length to next SDIO block */
2244 if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
2245 uint16 pad = bus->blocksize - (len % bus->blocksize);
2246 if ((pad <= bus->roundup) && (pad < bus->blocksize))
2248 } else if (len % DHD_SDALIGN) {
2249 len += DHD_SDALIGN - (len % DHD_SDALIGN);
2252 /* Satisfy length-alignment requirements */
2253 if (forcealign && (len & (ALIGNMENT - 1)))
2254 len = ROUNDUP(len, ALIGNMENT);
2256 ASSERT(ISALIGNED((uintptr)frame, 2));
2259 /* Need to lock here to protect txseq and SDIO tx calls */
2260 dhd_os_sdlock(bus->dhd);
2264 /* Make sure backplane clock is on */
2265 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
2267 /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
2268 *(uint16*)frame = htol16((uint16)msglen);
2269 *(((uint16*)frame) + 1) = htol16(~msglen);
2271 if (bus->txglom_enable) {
2272 uint32 hwheader1, hwheader2;
2273 /* Software tag: channel, sequence number, data offset */
2274 swheader = ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK)
2276 | ((doff << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
2277 htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN);
2278 htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN
2279 + SDPCM_HWEXT_LEN + sizeof(swheader));
2281 hwheader1 = (msglen - SDPCM_FRAMETAG_LEN) | (1 << 24);
2282 hwheader2 = (len - (msglen)) << 16;
2283 htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN);
2284 htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4);
2286 *(uint16*)frame = htol16(len);
2287 *(((uint16*)frame) + 1) = htol16(~(len));
2289 /* Software tag: channel, sequence number, data offset */
2290 swheader = ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK)
2291 | bus->tx_seq | ((doff << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
2292 htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN);
2293 htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
2295 if (!TXCTLOK(bus)) {
2296 DHD_INFO(("%s: No bus credit bus->tx_max %d, bus->tx_seq %d\n",
2297 __FUNCTION__, bus->tx_max, bus->tx_seq));
2298 bus->ctrl_frame_stat = TRUE;
2300 bus->ctrl_frame_buf = frame;
2301 bus->ctrl_frame_len = len;
2303 if (!bus->dpc_sched) {
2304 bus->dpc_sched = TRUE;
2305 dhd_sched_dpc(bus->dhd);
2307 if (bus->ctrl_frame_stat) {
2308 dhd_wait_for_event(bus->dhd, &bus->ctrl_frame_stat);
2311 if (bus->ctrl_frame_stat == FALSE) {
2312 DHD_INFO(("%s: ctrl_frame_stat == FALSE\n", __FUNCTION__));
2315 bus->dhd->txcnt_timeout++;
2316 if (!bus->dhd->hang_was_sent) {
2317 DHD_ERROR(("%s: ctrl_frame_stat == TRUE txcnt_timeout=%d\n",
2318 __FUNCTION__, bus->dhd->txcnt_timeout));
2321 bus->ctrl_frame_stat = FALSE;
2326 bus->dhd->txcnt_timeout = 0;
2327 bus->ctrl_frame_stat = TRUE;
2331 if (DHD_BYTES_ON() && DHD_CTL_ON()) {
2332 prhex("Tx Frame", frame, len);
2333 } else if (DHD_HDRS_ON()) {
2334 prhex("TxHdr", frame, MIN(len, 16));
2337 ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
2338 frame, len, NULL, NULL, NULL, TXRETRIES);
2340 bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
2342 bus->ctrl_frame_stat = FALSE;
2345 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
2346 bus->activity = FALSE;
2347 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
2350 dhd_os_sdunlock(bus->dhd);
2353 bus->dhd->tx_ctlerrs++;
2355 bus->dhd->tx_ctlpkts++;
2357 if (bus->dhd->txcnt_timeout >= MAX_CNTL_TX_TIMEOUT)
2360 if (ret == BCME_NODEVICE)
2365 return ret ? err_nodevice >= ERROR_BCME_NODEVICE_MAX ? -ETIMEDOUT : -EIO : 0;
2369 dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen)
2375 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2377 if (bus->dhd->dongle_reset)
2380 /* Wait until control frame is available */
2381 timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->rxlen, &pending);
2383 dhd_os_sdlock(bus->dhd);
2385 bcopy(bus->rxctl, msg, MIN(msglen, rxlen));
2387 dhd_os_sdunlock(bus->dhd);
2390 DHD_CTL(("%s: resumed on rxctl frame, got %d expected %d\n",
2391 __FUNCTION__, rxlen, msglen));
2392 } else if (timeleft == 0) {
2394 uint32 status, retry = 0;
2395 R_SDREG(status, &bus->regs->intstatus, retry);
2396 DHD_ERROR(("%s: resumed on timeout, INT status=0x%08X\n",
2397 __FUNCTION__, status));
2399 DHD_ERROR(("%s: resumed on timeout\n", __FUNCTION__));
2400 #endif /* DHD_DEBUG */
2402 dhd_os_sdlock(bus->dhd);
2403 dhdsdio_checkdied(bus, NULL, 0);
2404 dhd_os_sdunlock(bus->dhd);
2405 #endif /* DHD_DEBUG */
2406 } else if (pending == TRUE) {
2407 /* signal pending */
2408 DHD_ERROR(("%s: signal pending\n", __FUNCTION__));
2412 DHD_CTL(("%s: resumed for unknown reason?\n", __FUNCTION__));
2414 dhd_os_sdlock(bus->dhd);
2415 dhdsdio_checkdied(bus, NULL, 0);
2416 dhd_os_sdunlock(bus->dhd);
2417 #endif /* DHD_DEBUG */
2419 if (timeleft == 0) {
2421 bus->dhd->rxcnt_timeout++;
2422 DHD_ERROR(("%s: rxcnt_timeout=%d, rxlen=%d\n", __FUNCTION__,
2423 bus->dhd->rxcnt_timeout, rxlen));
2426 bus->dhd->rxcnt_timeout = 0;
2429 bus->dhd->rx_ctlpkts++;
2431 bus->dhd->rx_ctlerrs++;
2433 if (bus->dhd->rxcnt_timeout >= MAX_CNTL_RX_TIMEOUT)
2436 if (bus->dhd->dongle_trap_occured)
2439 return rxlen ? (int)rxlen : -EIO;
2455 #endif /* DHD_DEBUG */
2456 IOV_SET_DOWNLOAD_STATE,
2466 #if defined(USE_SDIOFIFO_IOVAR)
2469 #endif /* USE_SDIOFIFO_IOVAR */
2482 IOV_DONGLEISOLATION,
2496 const bcm_iovar_t dhdsdio_iovars[] = {
2497 {"intr", IOV_INTR, 0, IOVT_BOOL, 0 },
2498 {"sleep", IOV_SLEEP, 0, IOVT_BOOL, 0 },
2499 {"pollrate", IOV_POLLRATE, 0, IOVT_UINT32, 0 },
2500 {"idletime", IOV_IDLETIME, 0, IOVT_INT32, 0 },
2501 {"idleclock", IOV_IDLECLOCK, 0, IOVT_INT32, 0 },
2502 {"sd1idle", IOV_SD1IDLE, 0, IOVT_BOOL, 0 },
2503 {"membytes", IOV_MEMBYTES, 0, IOVT_BUFFER, 2 * sizeof(int) },
2504 {"ramsize", IOV_RAMSIZE, 0, IOVT_UINT32, 0 },
2505 {"ramstart", IOV_RAMSTART, 0, IOVT_UINT32, 0 },
2506 {"dwnldstate", IOV_SET_DOWNLOAD_STATE, 0, IOVT_BOOL, 0 },
2507 {"socram_state", IOV_SOCRAM_STATE, 0, IOVT_BOOL, 0 },
2508 {"vars", IOV_VARS, 0, IOVT_BUFFER, 0 },
2509 {"sdiod_drive", IOV_SDIOD_DRIVE, 0, IOVT_UINT32, 0 },
2510 {"readahead", IOV_READAHEAD, 0, IOVT_BOOL, 0 },
2511 {"sdrxchain", IOV_SDRXCHAIN, 0, IOVT_BOOL, 0 },
2512 {"alignctl", IOV_ALIGNCTL, 0, IOVT_BOOL, 0 },
2513 {"sdalign", IOV_SDALIGN, 0, IOVT_BOOL, 0 },
2514 {"devreset", IOV_DEVRESET, 0, IOVT_BOOL, 0 },
2516 {"sdreg", IOV_SDREG, 0, IOVT_BUFFER, sizeof(sdreg_t) },
2517 {"sbreg", IOV_SBREG, 0, IOVT_BUFFER, sizeof(sdreg_t) },
2518 {"sd_cis", IOV_SDCIS, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN },
2519 {"forcealign", IOV_FORCEEVEN, 0, IOVT_BOOL, 0 },
2520 {"txbound", IOV_TXBOUND, 0, IOVT_UINT32, 0 },
2521 {"rxbound", IOV_RXBOUND, 0, IOVT_UINT32, 0 },
2522 {"txminmax", IOV_TXMINMAX, 0, IOVT_UINT32, 0 },
2523 {"cpu", IOV_CPU, 0, IOVT_BOOL, 0 },
2525 {"checkdied", IOV_CHECKDIED, 0, IOVT_BUFFER, 0 },
2526 {"serial", IOV_SERIALCONS, 0, IOVT_UINT32, 0 },
2527 #endif /* DHD_DEBUG */
2528 #endif /* DHD_DEBUG */
2530 {"extloop", IOV_EXTLOOP, 0, IOVT_BOOL, 0 },
2531 {"pktgen", IOV_PKTGEN, 0, IOVT_BUFFER, sizeof(dhd_pktgen_t) },
2533 #if defined(USE_SDIOFIFO_IOVAR)
2534 {"watermark", IOV_WATERMARK, 0, IOVT_UINT32, 0 },
2535 {"mesbusyctrl", IOV_MESBUSYCTRL, 0, IOVT_UINT32, 0 },
2536 #endif /* USE_SDIOFIFO_IOVAR */
2537 {"devcap", IOV_DEVCAP, 0, IOVT_UINT32, 0 },
2538 {"dngl_isolation", IOV_DONGLEISOLATION, 0, IOVT_UINT32, 0 },
2539 {"kso", IOV_KSO, 0, IOVT_UINT32, 0 },
2540 {"devsleep", IOV_DEVSLEEP, 0, IOVT_UINT32, 0 },
2542 {"fwpath", IOV_FWPATH, 0, IOVT_BUFFER, 0 },
2544 {"txglomsize", IOV_TXGLOMSIZE, 0, IOVT_UINT32, 0 },
2545 {"fw_hang_report", IOV_HANGREPORT, 0, IOVT_BOOL, 0 },
2546 {"txinrx_thres", IOV_TXINRX_THRES, 0, IOVT_INT32, 0 },
2551 dhd_dump_pct(struct bcmstrbuf *strbuf, char *desc, uint num, uint div)
2556 bcm_bprintf(strbuf, "%s N/A", desc);
2559 q2 = (100 * (num - (q1 * div))) / div;
2560 bcm_bprintf(strbuf, "%s %d.%02d", desc, q1, q2);
2565 dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf)
2567 dhd_bus_t *bus = dhdp->bus;
2569 bcm_bprintf(strbuf, "Bus SDIO structure:\n");
2570 bcm_bprintf(strbuf, "hostintmask 0x%08x intstatus 0x%08x sdpcm_ver %d\n",
2571 bus->hostintmask, bus->intstatus, bus->sdpcm_ver);
2572 bcm_bprintf(strbuf, "fcstate %d qlen %u tx_seq %d, max %d, rxskip %d rxlen %u rx_seq %d\n",
2573 bus->fcstate, pktq_len(&bus->txq), bus->tx_seq, bus->tx_max, bus->rxskip,
2574 bus->rxlen, bus->rx_seq);
2575 bcm_bprintf(strbuf, "intr %d intrcount %u lastintrs %u spurious %u\n",
2576 bus->intr, bus->intrcount, bus->lastintrs, bus->spurious);
2577 bcm_bprintf(strbuf, "pollrate %u pollcnt %u regfails %u\n",
2578 bus->pollrate, bus->pollcnt, bus->regfails);
2580 bcm_bprintf(strbuf, "\nAdditional counters:\n");
2581 #ifdef DHDENABLE_TAILPAD
2582 bcm_bprintf(strbuf, "tx_tailpad_chain %u tx_tailpad_pktget %u\n",
2583 bus->tx_tailpad_chain, bus->tx_tailpad_pktget);
2584 #endif /* DHDENABLE_TAILPAD */
2585 bcm_bprintf(strbuf, "tx_sderrs %u fcqueued %u rxrtx %u rx_toolong %u rxc_errors %u\n",
2586 bus->tx_sderrs, bus->fcqueued, bus->rxrtx, bus->rx_toolong,
2588 bcm_bprintf(strbuf, "rx_hdrfail %u badhdr %u badseq %u\n",
2589 bus->rx_hdrfail, bus->rx_badhdr, bus->rx_badseq);
2590 bcm_bprintf(strbuf, "fc_rcvd %u, fc_xoff %u, fc_xon %u\n",
2591 bus->fc_rcvd, bus->fc_xoff, bus->fc_xon);
2592 bcm_bprintf(strbuf, "rxglomfail %u, rxglomframes %u, rxglompkts %u\n",
2593 bus->rxglomfail, bus->rxglomframes, bus->rxglompkts);
2594 bcm_bprintf(strbuf, "f2rx (hdrs/data) %u (%u/%u), f2tx %u f1regs %u\n",
2595 (bus->f2rxhdrs + bus->f2rxdata), bus->f2rxhdrs, bus->f2rxdata,
2596 bus->f2txdata, bus->f1regdata);
2598 dhd_dump_pct(strbuf, "\nRx: pkts/f2rd", bus->dhd->rx_packets,
2599 (bus->f2rxhdrs + bus->f2rxdata));
2600 dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->rx_packets, bus->f1regdata);
2601 dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->rx_packets,
2602 (bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata));
2603 dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->rx_packets, bus->intrcount);
2604 bcm_bprintf(strbuf, "\n");
2606 dhd_dump_pct(strbuf, "Rx: glom pct", (100 * bus->rxglompkts),
2607 bus->dhd->rx_packets);
2608 dhd_dump_pct(strbuf, ", pkts/glom", bus->rxglompkts, bus->rxglomframes);
2609 bcm_bprintf(strbuf, "\n");
2611 dhd_dump_pct(strbuf, "Tx: pkts/f2wr", bus->dhd->tx_packets, bus->f2txdata);
2612 dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->tx_packets, bus->f1regdata);
2613 dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->tx_packets,
2614 (bus->f2txdata + bus->f1regdata));
2615 dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->tx_packets, bus->intrcount);
2616 bcm_bprintf(strbuf, "\n");
2618 dhd_dump_pct(strbuf, "Total: pkts/f2rw",
2619 (bus->dhd->tx_packets + bus->dhd->rx_packets),
2620 (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata));
2621 dhd_dump_pct(strbuf, ", pkts/f1sd",
2622 (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->f1regdata);
2623 dhd_dump_pct(strbuf, ", pkts/sd",
2624 (bus->dhd->tx_packets + bus->dhd->rx_packets),
2625 (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata));
2626 dhd_dump_pct(strbuf, ", pkts/int",
2627 (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->intrcount);
2628 bcm_bprintf(strbuf, "\n\n");
2632 if (bus->pktgen_count) {
2633 bcm_bprintf(strbuf, "pktgen config and count:\n");
2634 bcm_bprintf(strbuf, "freq %u count %u print %u total %u min %u len %u\n",
2635 bus->pktgen_freq, bus->pktgen_count, bus->pktgen_print,
2636 bus->pktgen_total, bus->pktgen_minlen, bus->pktgen_maxlen);
2637 bcm_bprintf(strbuf, "send attempts %u rcvd %u fail %u\n",
2638 bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail);
2642 bcm_bprintf(strbuf, "dpc_sched %d host interrupt%spending\n",
2643 bus->dpc_sched, (bcmsdh_intr_pending(bus->sdh) ? " " : " not "));
2644 bcm_bprintf(strbuf, "blocksize %u roundup %u\n", bus->blocksize, bus->roundup);
2645 #endif /* DHD_DEBUG */
2646 bcm_bprintf(strbuf, "clkstate %d activity %d idletime %d idlecount %d sleeping %d\n",
2647 bus->clkstate, bus->activity, bus->idletime, bus->idlecount, bus->sleeping);
2651 dhd_bus_clearcounts(dhd_pub_t *dhdp)
2653 dhd_bus_t *bus = (dhd_bus_t *)dhdp->bus;
2655 bus->intrcount = bus->lastintrs = bus->spurious = bus->regfails = 0;
2656 bus->rxrtx = bus->rx_toolong = bus->rxc_errors = 0;
2657 bus->rx_hdrfail = bus->rx_badhdr = bus->rx_badseq = 0;
2658 #ifdef DHDENABLE_TAILPAD
2659 bus->tx_tailpad_chain = bus->tx_tailpad_pktget = 0;
2660 #endif /* DHDENABLE_TAILPAD */
2661 bus->tx_sderrs = bus->fc_rcvd = bus->fc_xoff = bus->fc_xon = 0;
2662 bus->rxglomfail = bus->rxglomframes = bus->rxglompkts = 0;
2663 bus->f2rxhdrs = bus->f2rxdata = bus->f2txdata = bus->f1regdata = 0;
2668 dhdsdio_pktgen_get(dhd_bus_t *bus, uint8 *arg)
2670 dhd_pktgen_t pktgen;
2672 pktgen.version = DHD_PKTGEN_VERSION;
2673 pktgen.freq = bus->pktgen_freq;
2674 pktgen.count = bus->pktgen_count;
2675 pktgen.print = bus->pktgen_print;
2676 pktgen.total = bus->pktgen_total;
2677 pktgen.minlen = bus->pktgen_minlen;
2678 pktgen.maxlen = bus->pktgen_maxlen;
2679 pktgen.numsent = bus->pktgen_sent;
2680 pktgen.numrcvd = bus->pktgen_rcvd;
2681 pktgen.numfail = bus->pktgen_fail;
2682 pktgen.mode = bus->pktgen_mode;
2683 pktgen.stop = bus->pktgen_stop;
2685 bcopy(&pktgen, arg, sizeof(pktgen));
2691 dhdsdio_pktgen_set(dhd_bus_t *bus, uint8 *arg)
2693 dhd_pktgen_t pktgen;
2694 uint oldcnt, oldmode;
2696 bcopy(arg, &pktgen, sizeof(pktgen));
2697 if (pktgen.version != DHD_PKTGEN_VERSION)
2700 oldcnt = bus->pktgen_count;
2701 oldmode = bus->pktgen_mode;
2703 bus->pktgen_freq = pktgen.freq;
2704 bus->pktgen_count = pktgen.count;
2705 bus->pktgen_print = pktgen.print;
2706 bus->pktgen_total = pktgen.total;
2707 bus->pktgen_minlen = pktgen.minlen;
2708 bus->pktgen_maxlen = pktgen.maxlen;
2709 bus->pktgen_mode = pktgen.mode;
2710 bus->pktgen_stop = pktgen.stop;
2712 bus->pktgen_tick = bus->pktgen_ptick = 0;
2713 bus->pktgen_prev_time = jiffies;
2714 bus->pktgen_len = MAX(bus->pktgen_len, bus->pktgen_minlen);
2715 bus->pktgen_len = MIN(bus->pktgen_len, bus->pktgen_maxlen);
2717 /* Clear counts for a new pktgen (mode change, or was stopped) */
2718 if (bus->pktgen_count && (!oldcnt || oldmode != bus->pktgen_mode)) {
2719 bus->pktgen_sent = bus->pktgen_prev_sent = bus->pktgen_rcvd = 0;
2720 bus->pktgen_prev_rcvd = bus->pktgen_fail = 0;
2728 dhdsdio_devram_remap(dhd_bus_t *bus, bool val)
2730 uint8 enable, protect, remap;
2732 si_socdevram(bus->sih, FALSE, &enable, &protect, &remap);
2733 remap = val ? TRUE : FALSE;
2734 si_socdevram(bus->sih, TRUE, &enable, &protect, &remap);
2738 dhdsdio_membytes(dhd_bus_t *bus, bool write, uint32 address, uint8 *data, uint size)
2744 /* In remap mode, adjust address beyond socram and redirect
2745 * to devram at SOCDEVRAM_BP_ADDR since remap address > orig_ramsize
2746 * is not backplane accessible
2748 if (REMAP_ENAB(bus) && REMAP_ISADDR(bus, address)) {
2749 address -= bus->orig_ramsize;
2750 address += SOCDEVRAM_BP_ADDR;
2753 /* Determine initial transfer parameters */
2754 sdaddr = address & SBSDIO_SB_OFT_ADDR_MASK;
2755 if ((sdaddr + size) & SBSDIO_SBWINDOW_MASK)
2756 dsize = (SBSDIO_SB_OFT_ADDR_LIMIT - sdaddr);
2760 /* Set the backplane window to include the start address */
2761 if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) {
2762 DHD_ERROR(("%s: window change failed\n", __FUNCTION__));
2766 /* Do the transfer(s) */
2768 DHD_INFO(("%s: %s %d bytes at offset 0x%08x in window 0x%08x\n",
2769 __FUNCTION__, (write ? "write" : "read"), dsize, sdaddr,
2770 (address & SBSDIO_SBWINDOW_MASK)));
2771 if ((bcmerror = bcmsdh_rwdata(bus->sdh, write, sdaddr, data, dsize))) {
2772 DHD_ERROR(("%s: membytes transfer failed\n", __FUNCTION__));
2776 /* Adjust for next transfer (if any) */
2777 if ((size -= dsize)) {
2780 if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) {
2781 DHD_ERROR(("%s: window change failed\n", __FUNCTION__));
2785 dsize = MIN(SBSDIO_SB_OFT_ADDR_LIMIT, size);
2791 /* Return the window to backplane enumeration space for core access */
2792 if (dhdsdio_set_siaddr_window(bus, bcmsdh_cur_sbwad(bus->sdh))) {
2793 DHD_ERROR(("%s: FAILED to set window back to 0x%x\n", __FUNCTION__,
2794 bcmsdh_cur_sbwad(bus->sdh)));
2802 dhdsdio_readshared(dhd_bus_t *bus, sdpcm_shared_t *sh)
2808 if (CHIPID(bus->sih->chip) == BCM43430_CHIP_ID && !dhdsdio_sr_cap(bus))
2811 shaddr = bus->dongle_ram_base + bus->ramsize - 4;
2814 /* Read last word in memory to determine address of sdpcm_shared structure */
2815 if ((rv = dhdsdio_membytes(bus, FALSE, shaddr, (uint8 *)&addr, 4)) < 0)
2818 addr = ltoh32(addr);
2820 DHD_INFO(("sdpcm_shared address 0x%08X\n", addr));
2823 * Check if addr is valid.
2824 * NVRAM length at the end of memory should have been overwritten.
2826 if (addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff)) {
2827 if ((bus->srmemsize > 0) && (i++ == 0)) {
2828 shaddr -= bus->srmemsize;
2830 DHD_ERROR(("%s: address (0x%08x) of sdpcm_shared invalid\n",
2831 __FUNCTION__, addr));
2838 /* Read hndrte_shared structure */
2839 if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)sh, sizeof(sdpcm_shared_t))) < 0)
2843 sh->flags = ltoh32(sh->flags);
2844 sh->trap_addr = ltoh32(sh->trap_addr);
2845 sh->assert_exp_addr = ltoh32(sh->assert_exp_addr);
2846 sh->assert_file_addr = ltoh32(sh->assert_file_addr);
2847 sh->assert_line = ltoh32(sh->assert_line);
2848 sh->console_addr = ltoh32(sh->console_addr);
2849 sh->msgtrace_addr = ltoh32(sh->msgtrace_addr);
2851 if ((sh->flags & SDPCM_SHARED_VERSION_MASK) == 3 && SDPCM_SHARED_VERSION == 1)
2854 if ((sh->flags & SDPCM_SHARED_VERSION_MASK) != SDPCM_SHARED_VERSION) {
2855 DHD_ERROR(("%s: sdpcm_shared version %d in dhd "
2856 "is different than sdpcm_shared version %d in dongle\n",
2857 __FUNCTION__, SDPCM_SHARED_VERSION,
2858 sh->flags & SDPCM_SHARED_VERSION_MASK));
2865 #define CONSOLE_LINE_MAX 192
2868 dhdsdio_readconsole(dhd_bus_t *bus)
2870 dhd_console_t *c = &bus->console;
2871 uint8 line[CONSOLE_LINE_MAX], ch;
2872 uint32 n, idx, addr;
2875 /* Don't do anything until FWREADY updates console address */
2876 if (bus->console_addr == 0)
2882 /* Read console log struct */
2883 addr = bus->console_addr + OFFSETOF(hnd_cons_t, log);
2884 if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)&c->log, sizeof(c->log))) < 0)
2887 /* Allocate console buffer (one time only) */
2888 if (c->buf == NULL) {
2889 c->bufsize = ltoh32(c->log.buf_size);
2890 if ((c->buf = MALLOC(bus->dhd->osh, c->bufsize)) == NULL)
2894 idx = ltoh32(c->log.idx);
2896 /* Protect against corrupt value */
2897 if (idx > c->bufsize)
2900 /* Skip reading the console buffer if the index pointer has not moved */
2904 /* Read the console buffer */
2905 addr = ltoh32(c->log.buf);
2906 if ((rv = dhdsdio_membytes(bus, FALSE, addr, c->buf, c->bufsize)) < 0)
2909 while (c->last != idx) {
2910 for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) {
2911 if (c->last == idx) {
2912 /* This would output a partial line. Instead, back up
2913 * the buffer pointer and output this line next time around.
2918 c->last = c->bufsize - n;
2921 ch = c->buf[c->last];
2922 c->last = (c->last + 1) % c->bufsize;
2929 if (line[n - 1] == '\r')
2932 printf("CONSOLE: %s\n", line);
2933 #ifdef LOG_INTO_TCPDUMP
2934 dhd_sendup_log(bus->dhd, line, n);
2935 #endif /* LOG_INTO_TCPDUMP */
2944 dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size)
2948 char *mbuffer = NULL;
2949 char *console_buffer = NULL;
2950 uint maxstrlen = 256;
2953 sdpcm_shared_t sdpcm_shared;
2954 struct bcmstrbuf strbuf;
2955 uint32 console_ptr, console_size, console_index;
2956 uint8 line[CONSOLE_LINE_MAX], ch;
2960 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2962 if (DHD_NOCHECKDIED_ON())
2967 * Called after a rx ctrl timeout. "data" is NULL.
2968 * allocate memory to trace the trap or assert.
2971 mbuffer = data = MALLOC(bus->dhd->osh, msize);
2972 if (mbuffer == NULL) {
2973 DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, msize));
2974 bcmerror = BCME_NOMEM;
2979 if ((str = MALLOC(bus->dhd->osh, maxstrlen)) == NULL) {
2980 DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, maxstrlen));
2981 bcmerror = BCME_NOMEM;
2985 if ((bcmerror = dhdsdio_readshared(bus, &sdpcm_shared)) < 0)
2988 bcm_binit(&strbuf, data, size);
2990 bcm_bprintf(&strbuf, "msgtrace address : 0x%08X\nconsole address : 0x%08X\n",
2991 sdpcm_shared.msgtrace_addr, sdpcm_shared.console_addr);
2993 if ((sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT) == 0) {
2994 /* NOTE: Misspelled assert is intentional - DO NOT FIX.
2995 * (Avoids conflict with real asserts for programmatic parsing of output.)
2997 bcm_bprintf(&strbuf, "Assrt not built in dongle\n");
3000 if ((sdpcm_shared.flags & (SDPCM_SHARED_ASSERT|SDPCM_SHARED_TRAP)) == 0) {
3001 /* NOTE: Misspelled assert is intentional - DO NOT FIX.
3002 * (Avoids conflict with real asserts for programmatic parsing of output.)
3004 bcm_bprintf(&strbuf, "No trap%s in dongle",
3005 (sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT)
3008 if (sdpcm_shared.flags & SDPCM_SHARED_ASSERT) {
3009 /* Download assert */
3010 bcm_bprintf(&strbuf, "Dongle assert");
3011 if (sdpcm_shared.assert_exp_addr != 0) {
3013 if ((bcmerror = dhdsdio_membytes(bus, FALSE,
3014 sdpcm_shared.assert_exp_addr,
3015 (uint8 *)str, maxstrlen)) < 0)
3018 str[maxstrlen - 1] = '\0';
3019 bcm_bprintf(&strbuf, " expr \"%s\"", str);
3022 if (sdpcm_shared.assert_file_addr != 0) {
3024 if ((bcmerror = dhdsdio_membytes(bus, FALSE,
3025 sdpcm_shared.assert_file_addr,
3026 (uint8 *)str, maxstrlen)) < 0)
3029 str[maxstrlen - 1] = '\0';
3030 bcm_bprintf(&strbuf, " file \"%s\"", str);
3033 bcm_bprintf(&strbuf, " line %d ", sdpcm_shared.assert_line);
3036 if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) {
3037 bus->dhd->dongle_trap_occured = TRUE;
3038 if ((bcmerror = dhdsdio_membytes(bus, FALSE,
3039 sdpcm_shared.trap_addr,
3040 (uint8*)&tr, sizeof(trap_t))) < 0)
3043 bcm_bprintf(&strbuf,
3044 "Dongle trap type 0x%x @ epc 0x%x, cpsr 0x%x, spsr 0x%x, sp 0x%x,"
3045 "lp 0x%x, rpc 0x%x Trap offset 0x%x, "
3046 "r0 0x%x, r1 0x%x, r2 0x%x, r3 0x%x, "
3047 "r4 0x%x, r5 0x%x, r6 0x%x, r7 0x%x\n\n",
3048 ltoh32(tr.type), ltoh32(tr.epc), ltoh32(tr.cpsr), ltoh32(tr.spsr),
3049 ltoh32(tr.r13), ltoh32(tr.r14), ltoh32(tr.pc),
3050 ltoh32(sdpcm_shared.trap_addr),
3051 ltoh32(tr.r0), ltoh32(tr.r1), ltoh32(tr.r2), ltoh32(tr.r3),
3052 ltoh32(tr.r4), ltoh32(tr.r5), ltoh32(tr.r6), ltoh32(tr.r7));
3054 addr = sdpcm_shared.console_addr + OFFSETOF(hnd_cons_t, log);
3055 if ((rv = dhdsdio_membytes(bus, FALSE, addr,
3056 (uint8 *)&console_ptr, sizeof(console_ptr))) < 0)
3059 addr = sdpcm_shared.console_addr + OFFSETOF(hnd_cons_t, log.buf_size);
3060 if ((rv = dhdsdio_membytes(bus, FALSE, addr,
3061 (uint8 *)&console_size, sizeof(console_size))) < 0)
3064 addr = sdpcm_shared.console_addr + OFFSETOF(hnd_cons_t, log.idx);
3065 if ((rv = dhdsdio_membytes(bus, FALSE, addr,
3066 (uint8 *)&console_index, sizeof(console_index))) < 0)
3069 console_ptr = ltoh32(console_ptr);
3070 console_size = ltoh32(console_size);
3071 console_index = ltoh32(console_index);
3073 if (console_size > CONSOLE_BUFFER_MAX ||
3074 !(console_buffer = MALLOC(bus->dhd->osh, console_size)))
3077 if ((rv = dhdsdio_membytes(bus, FALSE, console_ptr,
3078 (uint8 *)console_buffer, console_size)) < 0)
3081 for (i = 0, n = 0; i < console_size; i += n + 1) {
3082 for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) {
3083 ch = console_buffer[(console_index + i + n) % console_size];
3091 if (line[n - 1] == '\r')
3094 /* Don't use DHD_ERROR macro since we print
3095 * a lot of information quickly. The macro
3096 * will truncate a lot of the printfs
3099 if (dhd_msg_level & DHD_ERROR_VAL)
3100 printf("CONSOLE: %s\n", line);
3107 if (sdpcm_shared.flags & (SDPCM_SHARED_ASSERT | SDPCM_SHARED_TRAP)) {
3108 DHD_ERROR(("%s: %s\n", __FUNCTION__, strbuf.origbuf));
3114 MFREE(bus->dhd->osh, mbuffer, msize);
3116 MFREE(bus->dhd->osh, str, maxstrlen);
3118 MFREE(bus->dhd->osh, console_buffer, console_size);
3122 #endif /* #ifdef DHD_DEBUG */
3126 dhdsdio_downloadvars(dhd_bus_t *bus, void *arg, int len)
3128 int bcmerror = BCME_OK;
3130 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3132 /* Basic sanity checks */
3134 bcmerror = BCME_NOTDOWN;
3138 bcmerror = BCME_BUFTOOSHORT;
3142 /* Free the old ones and replace with passed variables */
3144 MFREE(bus->dhd->osh, bus->vars, bus->varsz);
3146 bus->vars = MALLOC(bus->dhd->osh, len);
3147 bus->varsz = bus->vars ? len : 0;
3148 if (bus->vars == NULL) {
3149 bcmerror = BCME_NOMEM;
3153 /* Copy the passed variables, which should include the terminating double-null */
3154 bcopy(arg, bus->vars, bus->varsz);
3161 #define CC_PLL_CHIPCTRL_SERIAL_ENAB (1 << 24)
3162 #define CC_CHIPCTRL_JTAG_SEL (1 << 3)
3163 #define CC_CHIPCTRL_GPIO_SEL (0x3)
3164 #define CC_PLL_CHIPCTRL_SERIAL_ENAB_4334 (1 << 28)
3167 dhd_serialconsole(dhd_bus_t *bus, bool set, bool enable, int *bcmerror)
3170 uint32 addr, data, uart_enab = 0;
3171 uint32 jtag_sel = CC_CHIPCTRL_JTAG_SEL;
3172 uint32 gpio_sel = CC_CHIPCTRL_GPIO_SEL;
3174 addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr);
3175 data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data);
3178 bcmsdh_reg_write(bus->sdh, addr, 4, 1);
3179 if (bcmsdh_regfail(bus->sdh)) {
3180 *bcmerror = BCME_SDIO_ERROR;
3183 int_val = bcmsdh_reg_read(bus->sdh, data, 4);
3184 if (bcmsdh_regfail(bus->sdh)) {
3185 *bcmerror = BCME_SDIO_ERROR;
3188 if (bus->sih->chip == BCM4330_CHIP_ID) {
3189 uart_enab = CC_PLL_CHIPCTRL_SERIAL_ENAB;
3191 else if (bus->sih->chip == BCM4334_CHIP_ID ||
3192 bus->sih->chip == BCM43340_CHIP_ID ||
3193 bus->sih->chip == BCM43341_CHIP_ID ||
3194 bus->sih->chip == BCM43342_CHIP_ID ||
3197 /* Moved to PMU chipcontrol 1 from 4330 */
3198 int_val &= ~gpio_sel;
3199 int_val |= jtag_sel;
3201 int_val |= gpio_sel;
3202 int_val &= ~jtag_sel;
3204 uart_enab = CC_PLL_CHIPCTRL_SERIAL_ENAB_4334;
3208 return (int_val & uart_enab);
3210 int_val |= uart_enab;
3212 int_val &= ~uart_enab;
3213 bcmsdh_reg_write(bus->sdh, data, 4, int_val);
3214 if (bcmsdh_regfail(bus->sdh)) {
3215 *bcmerror = BCME_SDIO_ERROR;
3218 if (bus->sih->chip == BCM4330_CHIP_ID) {
3220 addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol);
3221 chipcontrol = bcmsdh_reg_read(bus->sdh, addr, 4);
3222 chipcontrol &= ~jtag_sel;
3224 chipcontrol |= jtag_sel;
3225 chipcontrol &= ~gpio_sel;
3227 bcmsdh_reg_write(bus->sdh, addr, 4, chipcontrol);
3230 return (int_val & uart_enab);
3235 dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const char *name,
3236 void *params, int plen, void *arg, int len, int val_size)
3242 DHD_TRACE(("%s: Enter, action %d name %s params %p plen %d arg %p len %d val_size %d\n",
3243 __FUNCTION__, actionid, name, params, plen, arg, len, val_size));
3245 if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0)
3248 if (plen >= (int)sizeof(int_val))
3249 bcopy(params, &int_val, sizeof(int_val));
3251 bool_val = (int_val != 0) ? TRUE : FALSE;
3254 /* Some ioctls use the bus */
3255 dhd_os_sdlock(bus->dhd);
3257 /* Check if dongle is in reset. If so, only allow DEVRESET iovars */
3258 if (bus->dhd->dongle_reset && !(actionid == IOV_SVAL(IOV_DEVRESET) ||
3259 actionid == IOV_GVAL(IOV_DEVRESET))) {
3260 bcmerror = BCME_NOTREADY;
3265 * Special handling for keepSdioOn: New SDIO Wake-up Mechanism
3267 if ((vi->varid == IOV_KSO) && (IOV_ISSET(actionid))) {
3268 dhdsdio_clk_kso_iovar(bus, bool_val);
3270 } else if ((vi->varid == IOV_DEVSLEEP) && (IOV_ISSET(actionid))) {
3272 dhdsdio_clk_devsleep_iovar(bus, bool_val);
3273 if (!SLPAUTO_ENAB(bus) && (bool_val == FALSE) && (bus->ipend)) {
3274 DHD_ERROR(("INT pending in devsleep 1, dpc_sched: %d\n",
3276 if (!bus->dpc_sched) {
3277 bus->dpc_sched = TRUE;
3278 dhd_sched_dpc(bus->dhd);
3285 /* Handle sleep stuff before any clock mucking */
3286 if (vi->varid == IOV_SLEEP) {
3287 if (IOV_ISSET(actionid)) {
3288 bcmerror = dhdsdio_bussleep(bus, bool_val);
3290 int_val = (int32)bus->sleeping;
3291 bcopy(&int_val, arg, val_size);
3296 /* Request clock to allow SDIO accesses */
3297 if (!bus->dhd->dongle_reset) {
3299 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
3303 case IOV_GVAL(IOV_INTR):
3304 int_val = (int32)bus->intr;
3305 bcopy(&int_val, arg, val_size);
3308 case IOV_SVAL(IOV_INTR):
3309 bus->intr = bool_val;
3310 bus->intdis = FALSE;
3313 DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__));
3314 // terence 20141207: enbale intdis
3316 bcmsdh_intr_enable(bus->sdh);
3318 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
3319 bcmsdh_intr_disable(bus->sdh);
3324 case IOV_GVAL(IOV_POLLRATE):
3325 int_val = (int32)bus->pollrate;
3326 bcopy(&int_val, arg, val_size);
3329 case IOV_SVAL(IOV_POLLRATE):
3330 bus->pollrate = (uint)int_val;
3331 bus->poll = (bus->pollrate != 0);
3334 case IOV_GVAL(IOV_IDLETIME):
3335 int_val = bus->idletime;
3336 bcopy(&int_val, arg, val_size);
3339 case IOV_SVAL(IOV_IDLETIME):
3340 if ((int_val < 0) && (int_val != DHD_IDLE_IMMEDIATE)) {
3341 bcmerror = BCME_BADARG;
3343 bus->idletime = int_val;
3347 case IOV_GVAL(IOV_IDLECLOCK):
3348 int_val = (int32)bus->idleclock;
3349 bcopy(&int_val, arg, val_size);
3352 case IOV_SVAL(IOV_IDLECLOCK):
3353 bus->idleclock = int_val;
3356 case IOV_GVAL(IOV_SD1IDLE):
3357 int_val = (int32)sd1idle;
3358 bcopy(&int_val, arg, val_size);
3361 case IOV_SVAL(IOV_SD1IDLE):
3366 case IOV_SVAL(IOV_MEMBYTES):
3367 case IOV_GVAL(IOV_MEMBYTES):
3373 bool set = (actionid == IOV_SVAL(IOV_MEMBYTES));
3375 ASSERT(plen >= 2*sizeof(int));
3377 address = (uint32)int_val;
3378 bcopy((char *)params + sizeof(int_val), &int_val, sizeof(int_val));
3379 size = (uint)int_val;
3381 /* Do some validation */
3382 dsize = set ? plen - (2 * sizeof(int)) : len;
3384 DHD_ERROR(("%s: error on %s membytes, addr 0x%08x size %d dsize %d\n",
3385 __FUNCTION__, (set ? "set" : "get"), address, size, dsize));
3386 bcmerror = BCME_BADARG;
3390 DHD_INFO(("%s: Request to %s %d bytes at address 0x%08x\n", __FUNCTION__,
3391 (set ? "write" : "read"), size, address));
3394 if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
3396 * If address is start of RAM (i.e. a downloaded image),
3397 * store the reset instruction to be written in 0
3399 if (set && address == bus->dongle_ram_base) {
3400 bus->resetinstr = *(((uint32*)params) + 2);
3403 /* If we know about SOCRAM, check for a fit */
3404 if ((bus->orig_ramsize) &&
3405 ((address > bus->orig_ramsize) || (address + size > bus->orig_ramsize)))
3407 uint8 enable, protect, remap;
3408 si_socdevram(bus->sih, FALSE, &enable, &protect, &remap);
3409 if (!enable || protect) {
3410 DHD_ERROR(("%s: ramsize 0x%08x doesn't have %d bytes at 0x%08x\n",
3411 __FUNCTION__, bus->orig_ramsize, size, address));
3412 DHD_ERROR(("%s: socram enable %d, protect %d\n",
3413 __FUNCTION__, enable, protect));
3414 bcmerror = BCME_BADARG;
3418 if (!REMAP_ENAB(bus) && (address >= SOCDEVRAM_ARM_ADDR)) {
3419 uint32 devramsize = si_socdevram_size(bus->sih);
3420 if ((address < SOCDEVRAM_ARM_ADDR) ||
3421 (address + size > (SOCDEVRAM_ARM_ADDR + devramsize))) {
3422 DHD_ERROR(("%s: bad address 0x%08x, size 0x%08x\n",
3423 __FUNCTION__, address, size));
3424 DHD_ERROR(("%s: socram range 0x%08x,size 0x%08x\n",
3425 __FUNCTION__, SOCDEVRAM_ARM_ADDR, devramsize));
3426 bcmerror = BCME_BADARG;
3429 /* move it such that address is real now */
3430 address -= SOCDEVRAM_ARM_ADDR;
3431 address += SOCDEVRAM_BP_ADDR;
3432 DHD_INFO(("%s: Request to %s %d bytes @ Mapped address 0x%08x\n",
3433 __FUNCTION__, (set ? "write" : "read"), size, address));
3434 } else if (REMAP_ENAB(bus) && REMAP_ISADDR(bus, address) && remap) {
3435 /* Can not access remap region while devram remap bit is set
3436 * ROM content would be returned in this case
3438 DHD_ERROR(("%s: Need to disable remap for address 0x%08x\n",
3439 __FUNCTION__, address));
3440 bcmerror = BCME_ERROR;
3446 /* Generate the actual data pointer */
3447 data = set ? (uint8*)params + 2 * sizeof(int): (uint8*)arg;
3449 /* Call to do the transfer */
3450 bcmerror = dhdsdio_membytes(bus, set, address, data, size);
3455 case IOV_GVAL(IOV_RAMSIZE):
3456 int_val = (int32)bus->ramsize;
3457 bcopy(&int_val, arg, val_size);
3460 case IOV_GVAL(IOV_RAMSTART):
3461 int_val = (int32)bus->dongle_ram_base;
3462 bcopy(&int_val, arg, val_size);
3465 case IOV_GVAL(IOV_SDIOD_DRIVE):
3466 int_val = (int32)dhd_sdiod_drive_strength;
3467 bcopy(&int_val, arg, val_size);
3470 case IOV_SVAL(IOV_SDIOD_DRIVE):
3471 dhd_sdiod_drive_strength = int_val;
3472 si_sdiod_drive_strength_init(bus->sih, bus->dhd->osh, dhd_sdiod_drive_strength);
3475 case IOV_SVAL(IOV_SET_DOWNLOAD_STATE):
3476 bcmerror = dhdsdio_download_state(bus, bool_val);
3479 case IOV_SVAL(IOV_SOCRAM_STATE):
3480 bcmerror = dhdsdio_download_state(bus, bool_val);
3483 case IOV_SVAL(IOV_VARS):
3484 bcmerror = dhdsdio_downloadvars(bus, arg, len);
3487 case IOV_GVAL(IOV_READAHEAD):
3488 int_val = (int32)dhd_readahead;
3489 bcopy(&int_val, arg, val_size);
3492 case IOV_SVAL(IOV_READAHEAD):
3493 if (bool_val && !dhd_readahead)
3495 dhd_readahead = bool_val;
3498 case IOV_GVAL(IOV_SDRXCHAIN):
3499 int_val = (int32)bus->use_rxchain;
3500 bcopy(&int_val, arg, val_size);
3503 case IOV_SVAL(IOV_SDRXCHAIN):
3504 if (bool_val && !bus->sd_rxchain)
3505 bcmerror = BCME_UNSUPPORTED;
3507 bus->use_rxchain = bool_val;
3509 case IOV_GVAL(IOV_ALIGNCTL):
3510 int_val = (int32)dhd_alignctl;
3511 bcopy(&int_val, arg, val_size);
3514 case IOV_SVAL(IOV_ALIGNCTL):
3515 dhd_alignctl = bool_val;
3518 case IOV_GVAL(IOV_SDALIGN):
3519 int_val = DHD_SDALIGN;
3520 bcopy(&int_val, arg, val_size);
3524 case IOV_GVAL(IOV_VARS):
3525 if (bus->varsz < (uint)len)
3526 bcopy(bus->vars, arg, bus->varsz);
3528 bcmerror = BCME_BUFTOOSHORT;
3530 #endif /* DHD_DEBUG */
3533 case IOV_GVAL(IOV_SDREG):
3538 sd_ptr = (sdreg_t *)params;
3540 addr = (uint32)((ulong)bus->regs + sd_ptr->offset);
3541 size = sd_ptr->func;
3542 int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size);
3543 if (bcmsdh_regfail(bus->sdh))
3544 bcmerror = BCME_SDIO_ERROR;
3545 bcopy(&int_val, arg, sizeof(int32));
3549 case IOV_SVAL(IOV_SDREG):
3554 sd_ptr = (sdreg_t *)params;
3556 addr = (uint32)((ulong)bus->regs + sd_ptr->offset);
3557 size = sd_ptr->func;
3558 bcmsdh_reg_write(bus->sdh, addr, size, sd_ptr->value);
3559 if (bcmsdh_regfail(bus->sdh))
3560 bcmerror = BCME_SDIO_ERROR;
3564 /* Same as above, but offset is not backplane (not SDIO core) */
3565 case IOV_GVAL(IOV_SBREG):
3570 bcopy(params, &sdreg, sizeof(sdreg));
3572 addr = SI_ENUM_BASE + sdreg.offset;
3574 int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size);
3575 if (bcmsdh_regfail(bus->sdh))
3576 bcmerror = BCME_SDIO_ERROR;
3577 bcopy(&int_val, arg, sizeof(int32));
3581 case IOV_SVAL(IOV_SBREG):
3586 bcopy(params, &sdreg, sizeof(sdreg));
3588 addr = SI_ENUM_BASE + sdreg.offset;
3590 bcmsdh_reg_write(bus->sdh, addr, size, sdreg.value);
3591 if (bcmsdh_regfail(bus->sdh))
3592 bcmerror = BCME_SDIO_ERROR;
3596 case IOV_GVAL(IOV_SDCIS):
3600 bcmstrcat(arg, "\nFunc 0\n");
3601 bcmsdh_cis_read(bus->sdh, 0x10, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
3602 bcmstrcat(arg, "\nFunc 1\n");
3603 bcmsdh_cis_read(bus->sdh, 0x11, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
3604 bcmstrcat(arg, "\nFunc 2\n");
3605 bcmsdh_cis_read(bus->sdh, 0x12, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
3609 case IOV_GVAL(IOV_FORCEEVEN):
3610 int_val = (int32)forcealign;
3611 bcopy(&int_val, arg, val_size);
3614 case IOV_SVAL(IOV_FORCEEVEN):
3615 forcealign = bool_val;
3618 case IOV_GVAL(IOV_TXBOUND):
3619 int_val = (int32)dhd_txbound;
3620 bcopy(&int_val, arg, val_size);
3623 case IOV_SVAL(IOV_TXBOUND):
3624 dhd_txbound = (uint)int_val;
3627 case IOV_GVAL(IOV_RXBOUND):
3628 int_val = (int32)dhd_rxbound;
3629 bcopy(&int_val, arg, val_size);
3632 case IOV_SVAL(IOV_RXBOUND):
3633 dhd_rxbound = (uint)int_val;
3636 case IOV_GVAL(IOV_TXMINMAX):
3637 int_val = (int32)dhd_txminmax;
3638 bcopy(&int_val, arg, val_size);
3641 case IOV_SVAL(IOV_TXMINMAX):
3642 dhd_txminmax = (uint)int_val;
3645 case IOV_GVAL(IOV_SERIALCONS):
3646 int_val = dhd_serialconsole(bus, FALSE, 0, &bcmerror);
3650 bcopy(&int_val, arg, val_size);
3653 case IOV_SVAL(IOV_SERIALCONS):
3654 dhd_serialconsole(bus, TRUE, bool_val, &bcmerror);
3658 #endif /* DHD_DEBUG */
3662 case IOV_GVAL(IOV_EXTLOOP):
3663 int_val = (int32)bus->ext_loop;
3664 bcopy(&int_val, arg, val_size);
3667 case IOV_SVAL(IOV_EXTLOOP):
3668 bus->ext_loop = bool_val;
3671 case IOV_GVAL(IOV_PKTGEN):
3672 bcmerror = dhdsdio_pktgen_get(bus, arg);
3675 case IOV_SVAL(IOV_PKTGEN):
3676 bcmerror = dhdsdio_pktgen_set(bus, arg);
3680 #if defined(USE_SDIOFIFO_IOVAR)
3681 case IOV_GVAL(IOV_WATERMARK):
3682 int_val = (int32)watermark;
3683 bcopy(&int_val, arg, val_size);
3686 case IOV_SVAL(IOV_WATERMARK):
3687 watermark = (uint)int_val;
3688 watermark = (watermark > SBSDIO_WATERMARK_MASK) ? SBSDIO_WATERMARK_MASK : watermark;
3689 DHD_ERROR(("Setting watermark as 0x%x.\n", watermark));
3690 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, (uint8)watermark, NULL);
3693 case IOV_GVAL(IOV_MESBUSYCTRL):
3694 int_val = (int32)mesbusyctrl;
3695 bcopy(&int_val, arg, val_size);
3698 case IOV_SVAL(IOV_MESBUSYCTRL):
3699 mesbusyctrl = (uint)int_val;
3700 mesbusyctrl = (mesbusyctrl > SBSDIO_MESBUSYCTRL_MASK)
3701 ? SBSDIO_MESBUSYCTRL_MASK : mesbusyctrl;
3702 DHD_ERROR(("Setting mesbusyctrl as 0x%x.\n", mesbusyctrl));
3703 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL,
3704 ((uint8)mesbusyctrl | 0x80), NULL);
3709 case IOV_GVAL(IOV_DONGLEISOLATION):
3710 int_val = bus->dhd->dongle_isolation;
3711 bcopy(&int_val, arg, val_size);
3714 case IOV_SVAL(IOV_DONGLEISOLATION):
3715 bus->dhd->dongle_isolation = bool_val;
3718 case IOV_SVAL(IOV_DEVRESET):
3719 DHD_TRACE(("%s: Called set IOV_DEVRESET=%d dongle_reset=%d busstate=%d\n",
3720 __FUNCTION__, bool_val, bus->dhd->dongle_reset,
3721 bus->dhd->busstate));
3723 ASSERT(bus->dhd->osh);
3724 /* ASSERT(bus->cl_devid); */
3726 dhd_bus_devreset(bus->dhd, (uint8)bool_val);
3730 * softap firmware is updated through module parameter or android private command
3733 case IOV_GVAL(IOV_DEVRESET):
3734 DHD_TRACE(("%s: Called get IOV_DEVRESET\n", __FUNCTION__));
3736 /* Get its status */
3737 int_val = (bool) bus->dhd->dongle_reset;
3738 bcopy(&int_val, arg, val_size);
3742 case IOV_GVAL(IOV_KSO):
3743 int_val = dhdsdio_sleepcsr_get(bus);
3744 bcopy(&int_val, arg, val_size);
3747 case IOV_GVAL(IOV_DEVCAP):
3748 int_val = dhdsdio_devcap_get(bus);
3749 bcopy(&int_val, arg, val_size);
3752 case IOV_SVAL(IOV_DEVCAP):
3753 dhdsdio_devcap_set(bus, (uint8) int_val);
3755 case IOV_GVAL(IOV_TXGLOMSIZE):
3756 int_val = (int32)bus->txglomsize;
3757 bcopy(&int_val, arg, val_size);
3760 case IOV_SVAL(IOV_TXGLOMSIZE):
3761 if (int_val > SDPCM_MAXGLOM_SIZE) {
3762 bcmerror = BCME_ERROR;
3764 bus->txglomsize = (uint)int_val;
3767 case IOV_SVAL(IOV_HANGREPORT):
3768 bus->dhd->hang_report = bool_val;
3769 DHD_ERROR(("%s: Set hang_report as %d\n", __FUNCTION__, bus->dhd->hang_report));
3772 case IOV_GVAL(IOV_HANGREPORT):
3773 int_val = (int32)bus->dhd->hang_report;
3774 bcopy(&int_val, arg, val_size);
3777 case IOV_GVAL(IOV_TXINRX_THRES):
3778 int_val = bus->txinrx_thres;
3779 bcopy(&int_val, arg, val_size);
3781 case IOV_SVAL(IOV_TXINRX_THRES):
3783 bcmerror = BCME_BADARG;
3785 bus->txinrx_thres = int_val;
3790 bcmerror = BCME_UNSUPPORTED;
3795 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
3796 bus->activity = FALSE;
3797 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
3800 dhd_os_sdunlock(bus->dhd);
3806 dhdsdio_write_vars(dhd_bus_t *bus)
3809 uint32 varsize, phys_size;
3814 uint8 *nvram_ularray;
3815 #endif /* DHD_DEBUG */
3817 /* Even if there are no vars are to be written, we still need to set the ramsize. */
3818 varsize = bus->varsz ? ROUNDUP(bus->varsz, 4) : 0;
3819 varaddr = (bus->ramsize - 4) - varsize;
3821 varaddr += bus->dongle_ram_base;
3824 if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 7)) {
3825 if (((varaddr & 0x3C) == 0x3C) && (varsize > 4)) {
3826 DHD_ERROR(("PR85623WAR in place\n"));
3832 vbuffer = (uint8 *)MALLOC(bus->dhd->osh, varsize);
3836 bzero(vbuffer, varsize);
3837 bcopy(bus->vars, vbuffer, bus->varsz);
3839 /* Write the vars list */
3840 bcmerror = dhdsdio_membytes(bus, TRUE, varaddr, vbuffer, varsize);
3842 /* Verify NVRAM bytes */
3843 DHD_INFO(("Compare NVRAM dl & ul; varsize=%d\n", varsize));
3844 nvram_ularray = (uint8*)MALLOC(bus->dhd->osh, varsize);
3848 /* Upload image to verify downloaded contents. */
3849 memset(nvram_ularray, 0xaa, varsize);
3851 /* Read the vars list to temp buffer for comparison */
3852 bcmerror = dhdsdio_membytes(bus, FALSE, varaddr, nvram_ularray, varsize);
3854 DHD_ERROR(("%s: error %d on reading %d nvram bytes at 0x%08x\n",
3855 __FUNCTION__, bcmerror, varsize, varaddr));
3857 /* Compare the org NVRAM with the one read from RAM */
3858 if (memcmp(vbuffer, nvram_ularray, varsize)) {
3859 DHD_ERROR(("%s: Downloaded NVRAM image is corrupted.\n", __FUNCTION__));
3861 DHD_ERROR(("%s: Download, Upload and compare of NVRAM succeeded.\n",
3864 MFREE(bus->dhd->osh, nvram_ularray, varsize);
3865 #endif /* DHD_DEBUG */
3867 MFREE(bus->dhd->osh, vbuffer, varsize);
3870 phys_size = REMAP_ENAB(bus) ? bus->ramsize : bus->orig_ramsize;
3872 phys_size += bus->dongle_ram_base;
3874 /* adjust to the user specified RAM */
3875 DHD_INFO(("Physical memory size: %d, usable memory size: %d\n",
3876 phys_size, bus->ramsize));
3877 DHD_INFO(("Vars are at %d, orig varsize is %d\n",
3879 varsize = ((phys_size - 4) - varaddr);
3882 * Determine the length token:
3883 * Varsize, converted to words, in lower 16-bits, checksum in upper 16-bits.
3888 varsizew = varsize / 4;
3889 varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF);
3890 varsizew = htol32(varsizew);
3893 DHD_INFO(("New varsize is %d, length token=0x%08x\n", varsize, varsizew));
3895 /* Write the length token to the last word */
3896 bcmerror = dhdsdio_membytes(bus, TRUE, (phys_size - 4),
3897 (uint8*)&varsizew, 4);
3903 dhdsdio_download_state(dhd_bus_t *bus, bool enter)
3911 /* To enter download state, disable ARM and reset SOCRAM.
3912 * To exit download state, simply reset ARM (default is RAM boot).
3915 bus->alp_only = TRUE;
3917 if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) &&
3918 !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) {
3919 if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
3922 DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__));
3923 bcmerror = BCME_ERROR;
3929 si_core_disable(bus->sih, 0);
3930 if (bcmsdh_regfail(bus->sdh)) {
3931 bcmerror = BCME_SDIO_ERROR;
3935 if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) {
3936 DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__));
3937 bcmerror = BCME_ERROR;
3941 si_core_reset(bus->sih, 0, 0);
3942 if (bcmsdh_regfail(bus->sdh)) {
3943 DHD_ERROR(("%s: Failure trying reset SOCRAM core?\n",
3945 bcmerror = BCME_SDIO_ERROR;
3949 /* Disable remap for download */
3950 if (REMAP_ENAB(bus) && si_socdevram_remap_isenb(bus->sih))
3951 dhdsdio_devram_remap(bus, FALSE);
3953 if (CHIPID(bus->sih->chip) == BCM43430_CHIP_ID) {
3954 /* Disabling Remap for SRAM_3 */
3955 si_socram_set_bankpda(bus->sih, 0x3, 0x0);
3958 /* Clear the top bit of memory */
3961 if (dhdsdio_membytes(bus, TRUE, bus->ramsize - 4,
3962 (uint8*)&zeros, 4) < 0) {
3963 bcmerror = BCME_SDIO_ERROR;
3971 * Read RAM base address [0x18_0000]
3972 * [next] Download firmware
3973 * [done at else] Populate the reset vector
3974 * [done at else] Remove ARM halt
3976 /* Halt ARM & remove reset */
3977 si_core_reset(bus->sih, SICF_CPUHALT, SICF_CPUHALT);
3980 if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
3981 if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) {
3982 DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__));
3983 bcmerror = BCME_ERROR;
3987 if (!si_iscoreup(bus->sih)) {
3988 DHD_ERROR(("%s: SOCRAM core is down after reset?\n", __FUNCTION__));
3989 bcmerror = BCME_ERROR;
3993 if ((bcmerror = dhdsdio_write_vars(bus))) {
3994 DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__));
3998 /* Enable remap before ARM reset but after vars.
3999 * No backplane access in remap mode
4001 if (REMAP_ENAB(bus) && !si_socdevram_remap_isenb(bus->sih))
4002 dhdsdio_devram_remap(bus, TRUE);
4004 if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) &&
4005 !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) {
4006 DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__));
4007 bcmerror = BCME_ERROR;
4010 W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries);
4013 if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) &&
4014 !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) {
4015 DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__));
4016 bcmerror = BCME_ERROR;
4020 /* cr4 has no socram, but tcm's */
4022 if ((bcmerror = dhdsdio_write_vars(bus))) {
4023 DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__));
4027 if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) &&
4028 !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) {
4029 DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__));
4030 bcmerror = BCME_ERROR;
4033 W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries);
4035 /* switch back to arm core again */
4036 if (!(si_setcore(bus->sih, ARMCR4_CORE_ID, 0))) {
4037 DHD_ERROR(("%s: Failed to find ARM CR4 core!\n", __FUNCTION__));
4038 bcmerror = BCME_ERROR;
4041 /* write address 0 with reset instruction */
4042 bcmerror = dhdsdio_membytes(bus, TRUE, 0,
4043 (uint8 *)&bus->resetinstr, sizeof(bus->resetinstr));
4045 /* now remove reset and halt and continue to run CR4 */
4048 si_core_reset(bus->sih, 0, 0);
4049 if (bcmsdh_regfail(bus->sdh)) {
4050 DHD_ERROR(("%s: Failure trying to reset ARM core?\n", __FUNCTION__));
4051 bcmerror = BCME_SDIO_ERROR;
4055 /* Allow HT Clock now that the ARM is running. */
4056 bus->alp_only = FALSE;
4058 bus->dhd->busstate = DHD_BUS_LOAD;
4062 /* Always return to SDIOD core */
4063 if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0))
4064 si_setcore(bus->sih, SDIOD_CORE_ID, 0);
4070 dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name,
4071 void *params, int plen, void *arg, int len, bool set)
4073 dhd_bus_t *bus = dhdp->bus;
4074 const bcm_iovar_t *vi = NULL;
4079 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4084 /* Get MUST have return space */
4085 ASSERT(set || (arg && len));
4087 /* Set does NOT take qualifiers */
4088 ASSERT(!set || (!params && !plen));
4090 /* Look up var locally; if not found pass to host driver */
4091 if ((vi = bcm_iovar_lookup(dhdsdio_iovars, name)) == NULL) {
4092 dhd_os_sdlock(bus->dhd);
4096 /* Turn on clock in case SD command needs backplane */
4097 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
4099 bcmerror = bcmsdh_iovar_op(bus->sdh, name, params, plen, arg, len, set);
4101 /* Check for bus configuration changes of interest */
4103 /* If it was divisor change, read the new one */
4104 if (set && strcmp(name, "sd_divisor") == 0) {
4105 if (bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
4106 &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) {
4107 bus->sd_divisor = -1;
4108 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, name));
4110 DHD_INFO(("%s: noted %s update, value now %d\n",
4111 __FUNCTION__, name, bus->sd_divisor));
4114 /* If it was a mode change, read the new one */
4115 if (set && strcmp(name, "sd_mode") == 0) {
4116 if (bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
4117 &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) {
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_mode));
4125 /* Similar check for blocksize change */
4126 if (set && strcmp(name, "sd_blocksize") == 0) {
4128 if (bcmsdh_iovar_op(bus->sdh, "sd_blocksize", &fnum, sizeof(int32),
4129 &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) {
4131 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize"));
4133 DHD_INFO(("%s: noted %s update, value now %d\n",
4134 __FUNCTION__, "sd_blocksize", bus->blocksize));
4136 dhdsdio_tune_fifoparam(bus);
4139 bus->roundup = MIN(max_roundup, bus->blocksize);
4141 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
4142 bus->activity = FALSE;
4143 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
4146 dhd_os_sdunlock(bus->dhd);
4150 DHD_CTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__,
4151 name, (set ? "set" : "get"), len, plen));
4153 /* set up 'params' pointer in case this is a set command so that
4154 * the convenience int and bool code can be common to set and get
4156 if (params == NULL) {
4161 if (vi->type == IOVT_VOID)
4163 else if (vi->type == IOVT_BUFFER)
4166 /* all other types are integer sized */
4167 val_size = sizeof(int);
4169 actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
4170 bcmerror = dhdsdio_doiovar(bus, vi, actionid, name, params, plen, arg, len, val_size);
4177 dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex)
4180 uint32 local_hostintmask;
4184 bool wlfc_enabled = FALSE;
4189 osh = bus->dhd->osh;
4190 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4192 bcmsdh_waitlockfree(bus->sdh);
4195 dhd_os_sdlock(bus->dhd);
4197 if ((bus->dhd->busstate == DHD_BUS_DOWN) || bus->dhd->hang_was_sent) {
4198 /* if Firmware already hangs disbale any interrupt */
4199 bus->dhd->busstate = DHD_BUS_DOWN;
4200 bus->hostintmask = 0;
4201 bcmsdh_intr_disable(bus->sdh);
4206 /* Change our idea of bus state */
4207 bus->dhd->busstate = DHD_BUS_DOWN;
4209 if (KSO_ENAB(bus)) {
4211 /* Enable clock for device interrupts */
4212 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
4214 /* Disable and clear interrupts at the chip level also */
4215 W_SDREG(0, &bus->regs->hostintmask, retries);
4216 local_hostintmask = bus->hostintmask;
4217 bus->hostintmask = 0;
4219 /* Force clocks on backplane to be sure F2 interrupt propagates */
4220 saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
4222 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
4223 (saveclk | SBSDIO_FORCE_HT), &err);
4226 DHD_ERROR(("%s: Failed to force clock for F2: err %d\n",
4227 __FUNCTION__, err));
4230 /* Turn off the bus (F2), free any pending packets */
4231 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
4232 #if !defined(NDISVER) || (NDISVER < 0x0630)
4233 bcmsdh_intr_disable(bus->sdh);
4234 #endif /* !defined(NDISVER) || (NDISVER < 0x0630) */
4235 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL);
4237 /* Clear any pending interrupts now that F2 is disabled */
4238 W_SDREG(local_hostintmask, &bus->regs->intstatus, retries);
4241 /* Turn off the backplane clock (only) */
4242 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
4245 #ifdef PROP_TXSTATUS
4246 wlfc_enabled = (dhd_wlfc_cleanup_txq(bus->dhd, NULL, 0) != WLFC_UNSUPPORTED);
4248 if (!wlfc_enabled) {
4249 #ifdef DHDTCPACK_SUPPRESS
4250 /* Clean tcp_ack_info_tbl in order to prevent access to flushed pkt,
4251 * when there is a newly coming packet from network stack.
4253 dhd_tcpack_info_tbl_clean(bus->dhd);
4254 #endif /* DHDTCPACK_SUPPRESS */
4255 /* Clear the data packet queues */
4256 pktq_flush(osh, &bus->txq, TRUE, NULL, 0);
4259 /* Clear any held glomming stuff */
4261 PKTFREE(osh, bus->glomd, FALSE);
4264 PKTFREE(osh, bus->glom, FALSE);
4266 bus->glom = bus->glomd = NULL;
4268 /* Clear rx control and wake any waiters */
4270 dhd_os_ioctl_resp_wake(bus->dhd);
4272 /* Reset some F2 state stuff */
4273 bus->rxskip = FALSE;
4274 bus->tx_seq = bus->rx_seq = 0;
4279 dhd_os_sdunlock(bus->dhd);
4282 #if defined(BCMSDIOH_TXGLOM) && defined(BCMSDIOH_STD)
4283 extern uint sd_txglom;
4286 dhd_txglom_enable(dhd_pub_t *dhdp, bool enable)
4288 /* can't enable host txglom by default, some platforms have no
4289 * (or crappy) ADMA support and txglom will cause kernel assertions (e.g.
4292 dhd_bus_t *bus = dhdp->bus;
4293 #ifdef BCMSDIOH_TXGLOM
4298 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4303 #endif /* BCMSDIOH_STD */
4307 memset(buf, 0, sizeof(buf));
4308 bcm_mkiovar("bus:rxglom", (void *)&rxglom, 4, buf, sizeof(buf));
4309 ret = dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0);
4311 bus->txglom_enable = TRUE;
4315 #endif /* BCMSDIOH_STD */
4316 bus->txglom_enable = FALSE;
4319 #endif /* BCMSDIOH_TXGLOM */
4320 bus->txglom_enable = FALSE;
4324 dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex)
4326 dhd_bus_t *bus = dhdp->bus;
4329 uint8 ready, enable;
4333 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4340 dhd_os_sdlock(bus->dhd);
4342 if (bus->sih->chip == BCM43362_CHIP_ID) {
4343 printf("%s: delay 100ms for BCM43362\n", __FUNCTION__);
4344 OSL_DELAY(100000); // terence 20131209: delay for 43362
4347 /* Make sure backplane clock is on, needed to generate F2 interrupt */
4348 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
4349 if (bus->clkstate != CLK_AVAIL) {
4350 DHD_ERROR(("%s: clock state is wrong. state = %d\n", __FUNCTION__, bus->clkstate));
4356 /* Force clocks on backplane to be sure F2 interrupt propagates */
4357 saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
4359 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
4360 (saveclk | SBSDIO_FORCE_HT), &err);
4363 DHD_ERROR(("%s: Failed to force clock for F2: err %d\n", __FUNCTION__, err));
4368 /* Enable function 2 (frame transfers) */
4369 W_SDREG((SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT),
4370 &bus->regs->tosbmailboxdata, retries);
4371 enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2);
4373 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL);
4375 /* Give the dongle some time to do its thing and set IOR2 */
4376 dhd_timeout_start(&tmo, DHD_WAIT_F2RDY * 1000);
4379 while (ready != enable && !dhd_timeout_expired(&tmo))
4380 ready = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IORDY, NULL);
4382 DHD_ERROR(("%s: enable 0x%02x, ready 0x%02x (waited %uus)\n",
4383 __FUNCTION__, enable, ready, tmo.elapsed));
4386 /* If F2 successfully enabled, set core and enable interrupts */
4387 if (ready == enable) {
4388 /* Make sure we're talking to the core. */
4389 if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0)))
4390 bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0);
4391 ASSERT(bus->regs != NULL);
4393 /* Set up the interrupt mask and enable interrupts */
4394 bus->hostintmask = HOSTINTMASK;
4395 /* corerev 4 could use the newer interrupt logic to detect the frames */
4396 if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 4) &&
4397 (bus->rxint_mode != SDIO_DEVICE_HMB_RXINT)) {
4398 bus->hostintmask &= ~I_HMB_FRAME_IND;
4399 bus->hostintmask |= I_XMTDATA_AVAIL;
4401 W_SDREG(bus->hostintmask, &bus->regs->hostintmask, retries);
4403 if (bus->sih->buscorerev < 15) {
4404 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK,
4405 (uint8)watermark, &err);
4408 /* Set bus state according to enable result */
4409 dhdp->busstate = DHD_BUS_DATA;
4411 /* bcmsdh_intr_unmask(bus->sdh); */
4413 bus->intdis = FALSE;
4415 DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__));
4416 bcmsdh_intr_enable(bus->sdh);
4418 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
4419 bcmsdh_intr_disable(bus->sdh);
4426 /* Disable F2 again */
4427 enable = SDIO_FUNC_ENABLE_1;
4428 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL);
4431 if (dhdsdio_sr_cap(bus)) {
4432 dhdsdio_sr_init(bus);
4433 /* Masking the chip active interrupt permanantly */
4434 bus->hostintmask &= ~I_CHIPACTIVE;
4435 W_SDREG(bus->hostintmask, &bus->regs->hostintmask, retries);
4436 DHD_INFO(("%s: disable I_CHIPACTIVE in hostintmask[0x%08x]\n",
4437 __FUNCTION__, bus->hostintmask));
4440 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1,
4441 SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err);
4443 /* If we didn't come up, turn off backplane clock */
4444 if (dhdp->busstate != DHD_BUS_DATA)
4445 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
4449 dhd_os_sdunlock(bus->dhd);
4455 dhdsdio_rxfail(dhd_bus_t *bus, bool abort, bool rtx)
4457 bcmsdh_info_t *sdh = bus->sdh;
4458 sdpcmd_regs_t *regs = bus->regs;
4464 DHD_ERROR(("%s: %sterminate frame%s\n", __FUNCTION__,
4465 (abort ? "abort command, " : ""), (rtx ? ", send NAK" : "")));
4467 if (!KSO_ENAB(bus)) {
4468 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
4473 bcmsdh_abort(sdh, SDIO_FUNC_2);
4476 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, SFC_RF_TERM, &err);
4478 DHD_ERROR(("%s: SBSDIO_FUNC1_FRAMECTRL cmd err\n", __FUNCTION__));
4483 /* Wait until the packet has been flushed (device/FIFO stable) */
4484 for (lastrbc = retries = 0xffff; retries > 0; retries--) {
4485 hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCHI, NULL);
4486 lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCLO, &err);
4488 DHD_ERROR(("%s: SBSDIO_FUNC1_RFAMEBCLO cmd err\n", __FUNCTION__));
4492 bus->f1regdata += 2;
4494 if ((hi == 0) && (lo == 0))
4497 if ((hi > (lastrbc >> 8)) && (lo > (lastrbc & 0x00ff))) {
4498 DHD_ERROR(("%s: count growing: last 0x%04x now 0x%04x\n",
4499 __FUNCTION__, lastrbc, ((hi << 8) + lo)));
4501 lastrbc = (hi << 8) + lo;
4505 DHD_ERROR(("%s: count never zeroed: last 0x%04x\n", __FUNCTION__, lastrbc));
4507 DHD_INFO(("%s: flush took %d iterations\n", __FUNCTION__, (0xffff - retries)));
4512 W_SDREG(SMB_NAK, ®s->tosbmailbox, retries);
4514 if (retries <= retry_limit) {
4519 /* Clear partial in any case */
4523 /* If we can't reach the device, signal failure */
4524 if (err || bcmsdh_regfail(sdh))
4525 bus->dhd->busstate = DHD_BUS_DOWN;
4529 dhdsdio_read_control(dhd_bus_t *bus, uint8 *hdr, uint len, uint doff)
4531 bcmsdh_info_t *sdh = bus->sdh;
4536 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4538 /* Control data already received in aligned rxctl */
4539 if ((bus->bus == SPI_BUS) && (!bus->usebufpool))
4543 /* Set rxctl for frame (w/optional alignment) */
4544 bus->rxctl = bus->rxbuf;
4546 bus->rxctl += firstread;
4547 if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN)))
4548 bus->rxctl += (DHD_SDALIGN - pad);
4549 bus->rxctl -= firstread;
4551 ASSERT(bus->rxctl >= bus->rxbuf);
4553 /* Copy the already-read portion over */
4554 bcopy(hdr, bus->rxctl, firstread);
4555 if (len <= firstread)
4558 /* Copy the full data pkt in gSPI case and process ioctl. */
4559 if (bus->bus == SPI_BUS) {
4560 bcopy(hdr, bus->rxctl, len);
4564 /* Raise rdlen to next SDIO block to avoid tail command */
4565 rdlen = len - firstread;
4566 if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
4567 pad = bus->blocksize - (rdlen % bus->blocksize);
4568 if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
4569 ((len + pad) < bus->dhd->maxctl))
4571 } else if (rdlen % DHD_SDALIGN) {
4572 rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
4575 /* Satisfy length-alignment requirements */
4576 if (forcealign && (rdlen & (ALIGNMENT - 1)))
4577 rdlen = ROUNDUP(rdlen, ALIGNMENT);
4579 /* Drop if the read is too big or it exceeds our maximum */
4580 if ((rdlen + firstread) > bus->dhd->maxctl) {
4581 DHD_ERROR(("%s: %d-byte control read exceeds %d-byte buffer\n",
4582 __FUNCTION__, rdlen, bus->dhd->maxctl));
4583 bus->dhd->rx_errors++;
4584 dhdsdio_rxfail(bus, FALSE, FALSE);
4588 if ((len - doff) > bus->dhd->maxctl) {
4589 DHD_ERROR(("%s: %d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n",
4590 __FUNCTION__, len, (len - doff), bus->dhd->maxctl));
4591 bus->dhd->rx_errors++; bus->rx_toolong++;
4592 dhdsdio_rxfail(bus, FALSE, FALSE);
4597 /* Read remainder of frame body into the rxctl buffer */
4598 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
4599 (bus->rxctl + firstread), rdlen, NULL, NULL, NULL);
4601 ASSERT(sdret != BCME_PENDING);
4603 /* Control frame failures need retransmission */
4605 DHD_ERROR(("%s: read %d control bytes failed: %d\n", __FUNCTION__, rdlen, sdret));
4606 bus->rxc_errors++; /* dhd.rx_ctlerrs is higher level */
4607 dhdsdio_rxfail(bus, TRUE, TRUE);
4614 if (DHD_BYTES_ON() && DHD_CTL_ON()) {
4615 prhex("RxCtrl", bus->rxctl, len);
4619 /* Point to valid data and indicate its length */
4621 bus->rxlen = len - doff;
4624 /* Awake any waiters */
4625 dhd_os_ioctl_resp_wake(bus->dhd);
4628 dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf, uint reorder_info_len,
4629 void **pkt, uint32 *pkt_count);
4632 dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq)
4634 uint16 dlen, totlen;
4635 uint8 *dptr, num = 0;
4637 uint16 sublen, check;
4638 void *pfirst, *plast, *pnext;
4639 void * list_tail[DHD_MAX_IFS] = { NULL };
4640 void * list_head[DHD_MAX_IFS] = { NULL };
4642 osl_t *osh = bus->dhd->osh;
4645 uint8 chan, seq, doff, sfdoff;
4647 uchar reorder_info_buf[WLHOST_REORDERDATA_TOTLEN];
4648 uint reorder_info_len;
4651 bool usechain = bus->use_rxchain;
4653 /* If packets, issue read(s) and send up packet chain */
4654 /* Return sequence numbers consumed? */
4656 DHD_TRACE(("dhdsdio_rxglom: start: glomd %p glom %p\n", bus->glomd, bus->glom));
4658 /* If there's a descriptor, generate the packet chain */
4660 dhd_os_sdlock_rxq(bus->dhd);
4662 pfirst = plast = pnext = NULL;
4663 dlen = (uint16)PKTLEN(osh, bus->glomd);
4664 dptr = PKTDATA(osh, bus->glomd);
4665 if (!dlen || (dlen & 1)) {
4666 DHD_ERROR(("%s: bad glomd len (%d), ignore descriptor\n",
4667 __FUNCTION__, dlen));
4671 for (totlen = num = 0; dlen; num++) {
4672 /* Get (and move past) next length */
4673 sublen = ltoh16_ua(dptr);
4674 dlen -= sizeof(uint16);
4675 dptr += sizeof(uint16);
4676 if ((sublen < SDPCM_HDRLEN) ||
4677 ((num == 0) && (sublen < (2 * SDPCM_HDRLEN)))) {
4678 DHD_ERROR(("%s: descriptor len %d bad: %d\n",
4679 __FUNCTION__, num, sublen));
4683 if (sublen % DHD_SDALIGN) {
4684 DHD_ERROR(("%s: sublen %d not a multiple of %d\n",
4685 __FUNCTION__, sublen, DHD_SDALIGN));
4690 /* For last frame, adjust read len so total is a block multiple */
4692 sublen += (ROUNDUP(totlen, bus->blocksize) - totlen);
4693 totlen = ROUNDUP(totlen, bus->blocksize);
4696 /* Allocate/chain packet for next subframe */
4697 if ((pnext = PKTGET(osh, sublen + DHD_SDALIGN, FALSE)) == NULL) {
4698 DHD_ERROR(("%s: PKTGET failed, num %d len %d\n",
4699 __FUNCTION__, num, sublen));
4702 ASSERT(!PKTLINK(pnext));
4705 pfirst = plast = pnext;
4708 PKTSETNEXT(osh, plast, pnext);
4712 /* Adhere to start alignment requirements */
4713 PKTALIGN(osh, pnext, sublen, DHD_SDALIGN);
4716 /* If all allocations succeeded, save packet chain in bus structure */
4718 DHD_GLOM(("%s: allocated %d-byte packet chain for %d subframes\n",
4719 __FUNCTION__, totlen, num));
4720 if (DHD_GLOM_ON() && bus->nextlen) {
4721 if (totlen != bus->nextlen) {
4722 DHD_GLOM(("%s: glomdesc mismatch: nextlen %d glomdesc %d "
4723 "rxseq %d\n", __FUNCTION__, bus->nextlen,
4728 pfirst = pnext = NULL;
4731 PKTFREE(osh, pfirst, FALSE);
4736 /* Done with descriptor packet */
4737 PKTFREE(osh, bus->glomd, FALSE);
4741 dhd_os_sdunlock_rxq(bus->dhd);
4744 /* Ok -- either we just generated a packet chain, or had one from before */
4746 if (DHD_GLOM_ON()) {
4747 DHD_GLOM(("%s: attempt superframe read, packet chain:\n", __FUNCTION__));
4748 for (pnext = bus->glom; pnext; pnext = PKTNEXT(osh, pnext)) {
4749 DHD_GLOM((" %p: %p len 0x%04x (%d)\n",
4750 pnext, (uint8*)PKTDATA(osh, pnext),
4751 PKTLEN(osh, pnext), PKTLEN(osh, pnext)));
4756 dlen = (uint16)pkttotlen(osh, pfirst);
4758 /* Do an SDIO read for the superframe. Configurable iovar to
4759 * read directly into the chained packet, or allocate a large
4760 * packet and and copy into the chain.
4763 errcode = dhd_bcmsdh_recv_buf(bus,
4764 bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2,
4765 F2SYNC, (uint8*)PKTDATA(osh, pfirst),
4766 dlen, pfirst, NULL, NULL);
4767 } else if (bus->dataptr) {
4768 errcode = dhd_bcmsdh_recv_buf(bus,
4769 bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2,
4770 F2SYNC, bus->dataptr,
4771 dlen, NULL, NULL, NULL);
4772 sublen = (uint16)pktfrombuf(osh, pfirst, 0, dlen, bus->dataptr);
4773 if (sublen != dlen) {
4774 DHD_ERROR(("%s: FAILED TO COPY, dlen %d sublen %d\n",
4775 __FUNCTION__, dlen, sublen));
4780 DHD_ERROR(("COULDN'T ALLOC %d-BYTE GLOM, FORCE FAILURE\n", dlen));
4784 ASSERT(errcode != BCME_PENDING);
4786 /* On failure, kill the superframe, allow a couple retries */
4788 DHD_ERROR(("%s: glom read of %d bytes failed: %d\n",
4789 __FUNCTION__, dlen, errcode));
4790 bus->dhd->rx_errors++;
4792 if (bus->glomerr++ < 3) {
4793 dhdsdio_rxfail(bus, TRUE, TRUE);
4796 dhdsdio_rxfail(bus, TRUE, FALSE);
4797 dhd_os_sdlock_rxq(bus->dhd);
4798 PKTFREE(osh, bus->glom, FALSE);
4799 dhd_os_sdunlock_rxq(bus->dhd);
4807 if (DHD_GLOM_ON()) {
4808 prhex("SUPERFRAME", PKTDATA(osh, pfirst),
4809 MIN(PKTLEN(osh, pfirst), 48));
4814 /* Validate the superframe header */
4815 dptr = (uint8 *)PKTDATA(osh, pfirst);
4816 sublen = ltoh16_ua(dptr);
4817 check = ltoh16_ua(dptr + sizeof(uint16));
4819 chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
4820 seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
4821 bus->nextlen = dptr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
4822 if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
4823 DHD_INFO(("%s: got frame w/nextlen too large (%d) seq %d\n",
4824 __FUNCTION__, bus->nextlen, seq));
4827 doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
4828 txmax = SDPCM_WINDOW_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
4831 if ((uint16)~(sublen^check)) {
4832 DHD_ERROR(("%s (superframe): HW hdr error: len/check 0x%04x/0x%04x\n",
4833 __FUNCTION__, sublen, check));
4835 } else if (ROUNDUP(sublen, bus->blocksize) != dlen) {
4836 DHD_ERROR(("%s (superframe): len 0x%04x, rounded 0x%04x, expect 0x%04x\n",
4837 __FUNCTION__, sublen, ROUNDUP(sublen, bus->blocksize), dlen));
4839 } else if (SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]) != SDPCM_GLOM_CHANNEL) {
4840 DHD_ERROR(("%s (superframe): bad channel %d\n", __FUNCTION__,
4841 SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN])));
4843 } else if (SDPCM_GLOMDESC(&dptr[SDPCM_FRAMETAG_LEN])) {
4844 DHD_ERROR(("%s (superframe): got second descriptor?\n", __FUNCTION__));
4846 } else if ((doff < SDPCM_HDRLEN) ||
4847 (doff > (PKTLEN(osh, pfirst) - SDPCM_HDRLEN))) {
4848 DHD_ERROR(("%s (superframe): Bad data offset %d: HW %d pkt %d min %d\n",
4849 __FUNCTION__, doff, sublen, PKTLEN(osh, pfirst),
4854 /* Check sequence number of superframe SW header */
4856 DHD_INFO(("%s: (superframe) rx_seq %d, expected %d\n",
4857 __FUNCTION__, seq, rxseq));
4862 /* Check window for sanity */
4863 if ((uint8)(txmax - bus->tx_seq) > 0x70) {
4864 DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
4865 __FUNCTION__, txmax, bus->tx_seq));
4866 txmax = bus->tx_max;
4868 bus->tx_max = txmax;
4870 /* Remove superframe header, remember offset */
4871 PKTPULL(osh, pfirst, doff);
4874 /* Validate all the subframe headers */
4875 for (num = 0, pnext = pfirst; pnext && !errcode;
4876 num++, pnext = PKTNEXT(osh, pnext)) {
4877 dptr = (uint8 *)PKTDATA(osh, pnext);
4878 dlen = (uint16)PKTLEN(osh, pnext);
4879 sublen = ltoh16_ua(dptr);
4880 check = ltoh16_ua(dptr + sizeof(uint16));
4881 chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
4882 doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
4884 if (DHD_GLOM_ON()) {
4885 prhex("subframe", dptr, 32);
4889 if ((uint16)~(sublen^check)) {
4890 DHD_ERROR(("%s (subframe %d): HW hdr error: "
4891 "len/check 0x%04x/0x%04x\n",
4892 __FUNCTION__, num, sublen, check));
4894 } else if ((sublen > dlen) || (sublen < SDPCM_HDRLEN)) {
4895 DHD_ERROR(("%s (subframe %d): length mismatch: "
4896 "len 0x%04x, expect 0x%04x\n",
4897 __FUNCTION__, num, sublen, dlen));
4899 } else if ((chan != SDPCM_DATA_CHANNEL) &&
4900 (chan != SDPCM_EVENT_CHANNEL)) {
4901 DHD_ERROR(("%s (subframe %d): bad channel %d\n",
4902 __FUNCTION__, num, chan));
4904 } else if ((doff < SDPCM_HDRLEN) || (doff > sublen)) {
4905 DHD_ERROR(("%s (subframe %d): Bad data offset %d: HW %d min %d\n",
4906 __FUNCTION__, num, doff, sublen, SDPCM_HDRLEN));
4912 /* Terminate frame on error, request a couple retries */
4913 if (bus->glomerr++ < 3) {
4914 /* Restore superframe header space */
4915 PKTPUSH(osh, pfirst, sfdoff);
4916 dhdsdio_rxfail(bus, TRUE, TRUE);
4919 dhdsdio_rxfail(bus, TRUE, FALSE);
4920 dhd_os_sdlock_rxq(bus->dhd);
4921 PKTFREE(osh, bus->glom, FALSE);
4922 dhd_os_sdunlock_rxq(bus->dhd);
4930 /* Basic SD framing looks ok - process each packet (header) */
4934 dhd_os_sdlock_rxq(bus->dhd);
4935 for (num = 0; pfirst; rxseq++, pfirst = pnext) {
4936 pnext = PKTNEXT(osh, pfirst);
4937 PKTSETNEXT(osh, pfirst, NULL);
4939 dptr = (uint8 *)PKTDATA(osh, pfirst);
4940 sublen = ltoh16_ua(dptr);
4941 chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
4942 seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
4943 doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
4945 DHD_GLOM(("%s: Get subframe %d, %p(%p/%d), sublen %d chan %d seq %d\n",
4946 __FUNCTION__, num, pfirst, PKTDATA(osh, pfirst),
4947 PKTLEN(osh, pfirst), sublen, chan, seq));
4949 ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL));
4952 DHD_GLOM(("%s: rx_seq %d, expected %d\n",
4953 __FUNCTION__, seq, rxseq));
4959 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
4960 prhex("Rx Subframe Data", dptr, dlen);
4964 PKTSETLEN(osh, pfirst, sublen);
4965 PKTPULL(osh, pfirst, doff);
4967 reorder_info_len = sizeof(reorder_info_buf);
4969 if (PKTLEN(osh, pfirst) == 0) {
4970 PKTFREE(bus->dhd->osh, pfirst, FALSE);
4972 } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pfirst, reorder_info_buf,
4973 &reorder_info_len) != 0) {
4974 DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__));
4975 bus->dhd->rx_errors++;
4976 PKTFREE(osh, pfirst, FALSE);
4979 if (reorder_info_len) {
4980 uint32 free_buf_count;
4984 /* Reordering info from the firmware */
4985 dhd_process_pkt_reorder_info(bus->dhd, reorder_info_buf,
4986 reorder_info_len, &ppfirst, &free_buf_count);
4988 if (free_buf_count == 0) {
4994 /* go to the end of the chain and attach the pnext there */
4996 while (PKTNEXT(osh, temp) != NULL) {
4997 temp = PKTNEXT(osh, temp);
5000 if (list_tail[ifidx] == NULL)
5001 list_head[ifidx] = ppfirst;
5003 PKTSETNEXT(osh, list_tail[ifidx], ppfirst);
5004 list_tail[ifidx] = pfirst;
5007 num += (uint8)free_buf_count;
5010 /* this packet will go up, link back into chain and count it */
5012 if (list_tail[ifidx] == NULL) {
5013 list_head[ifidx] = list_tail[ifidx] = pfirst;
5016 PKTSETNEXT(osh, list_tail[ifidx], pfirst);
5017 list_tail[ifidx] = pfirst;
5022 if (DHD_GLOM_ON()) {
5023 DHD_GLOM(("%s subframe %d to stack, %p(%p/%d) nxt/lnk %p/%p\n",
5024 __FUNCTION__, num, pfirst,
5025 PKTDATA(osh, pfirst), PKTLEN(osh, pfirst),
5026 PKTNEXT(osh, pfirst), PKTLINK(pfirst)));
5027 prhex("", (uint8 *)PKTDATA(osh, pfirst),
5028 MIN(PKTLEN(osh, pfirst), 32));
5030 #endif /* DHD_DEBUG */
5032 dhd_os_sdunlock_rxq(bus->dhd);
5034 for (idx = 0; idx < DHD_MAX_IFS; idx++) {
5035 if (list_head[idx]) {
5038 temp = list_head[idx];
5040 temp = PKTNEXT(osh, temp);
5044 dhd_os_sdunlock(bus->dhd);
5045 dhd_rx_frame(bus->dhd, idx, list_head[idx], cnt, 0);
5046 dhd_os_sdlock(bus->dhd);
5050 bus->rxglomframes++;
5051 bus->rxglompkts += num;
5057 /* Return TRUE if there may be more frames to read */
5059 dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished)
5061 osl_t *osh = bus->dhd->osh;
5062 bcmsdh_info_t *sdh = bus->sdh;
5064 uint16 len, check; /* Extracted hardware header fields */
5065 uint8 chan, seq, doff; /* Extracted software header fields */
5066 uint8 fcbits; /* Extracted fcbits from software header */
5069 void *pkt; /* Packet for event or data frames */
5070 uint16 pad; /* Number of pad bytes to read */
5071 uint16 rdlen; /* Total number of bytes to read */
5072 uint8 rxseq; /* Next sequence number to expect */
5073 uint rxleft = 0; /* Remaining number of frames allowed */
5074 int sdret; /* Return code from bcmsdh calls */
5075 uint8 txmax; /* Maximum tx sequence offered */
5076 bool len_consistent; /* Result of comparing readahead len and len from hw-hdr */
5079 uint rxcount = 0; /* Total frames read */
5080 uchar reorder_info_buf[WLHOST_REORDERDATA_TOTLEN];
5081 uint reorder_info_len;
5084 #if defined(DHD_DEBUG) || defined(SDTEST)
5085 bool sdtest = FALSE; /* To limit message spew from test mode */
5088 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5090 bus->readframes = TRUE;
5092 if (!KSO_ENAB(bus)) {
5093 DHD_ERROR(("%s: KSO off\n", __FUNCTION__));
5094 bus->readframes = FALSE;
5101 /* Allow pktgen to override maxframes */
5102 if (bus->pktgen_count && (bus->pktgen_mode == DHD_PKTGEN_RECV)) {
5103 maxframes = bus->pktgen_count;
5108 /* Not finished unless we encounter no more frames indication */
5112 for (rxseq = bus->rx_seq, rxleft = maxframes;
5113 !bus->rxskip && rxleft && bus->dhd->busstate != DHD_BUS_DOWN;
5114 rxseq++, rxleft--) {
5115 #ifdef DHDTCPACK_SUP_DBG
5116 if (bus->dhd->tcpack_sup_mode != TCPACK_SUP_DELAYTX) {
5117 if (bus->dotxinrx == FALSE)
5118 DHD_ERROR(("%s %d: dotxinrx FALSE with tcpack_sub_mode %d\n",
5119 __FUNCTION__, __LINE__, bus->dhd->tcpack_sup_mode));
5121 #ifdef DEBUG_COUNTER
5122 else if (pktq_mlen(&bus->txq, ~bus->flowcontrol) > 0) {
5123 tack_tbl.cnt[bus->dotxinrx ? 6 : 7]++;
5125 #endif /* DEBUG_COUNTER */
5126 #endif /* DHDTCPACK_SUP_DBG */
5127 /* tx more to improve rx performance */
5128 if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL)) {
5129 dhdsdio_sendpendctl(bus);
5130 } else if (bus->dotxinrx && (bus->clkstate == CLK_AVAIL) &&
5131 !bus->fcstate && DATAOK(bus) &&
5132 (pktq_mlen(&bus->txq, ~bus->flowcontrol) > bus->txinrx_thres)) {
5133 dhdsdio_sendfromq(bus, dhd_txbound);
5134 #ifdef DHDTCPACK_SUPPRESS
5135 /* In TCPACK_SUP_DELAYTX mode, do txinrx only if
5136 * 1. Any DATA packet to TX
5137 * 2. TCPACK to TCPDATA PSH packets.
5140 bus->dotxinrx = (bus->dhd->tcpack_sup_mode == TCPACK_SUP_DELAYTX) ?
5145 /* Handle glomming separately */
5146 if (bus->glom || bus->glomd) {
5148 DHD_GLOM(("%s: calling rxglom: glomd %p, glom %p\n",
5149 __FUNCTION__, bus->glomd, bus->glom));
5150 cnt = dhdsdio_rxglom(bus, rxseq);
5151 DHD_GLOM(("%s: rxglom returned %d\n", __FUNCTION__, cnt));
5153 rxleft = (rxleft > cnt) ? (rxleft - cnt) : 1;
5157 /* Try doing single read if we can */
5158 if (dhd_readahead && bus->nextlen) {
5159 uint16 nextlen = bus->nextlen;
5162 if (bus->bus == SPI_BUS) {
5163 rdlen = len = nextlen;
5166 rdlen = len = nextlen << 4;
5168 /* Pad read to blocksize for efficiency */
5169 if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
5170 pad = bus->blocksize - (rdlen % bus->blocksize);
5171 if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
5172 ((rdlen + pad + firstread) < MAX_RX_DATASZ))
5174 } else if (rdlen % DHD_SDALIGN) {
5175 rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
5179 /* We use bus->rxctl buffer in WinXP for initial control pkt receives.
5180 * Later we use buffer-poll for data as well as control packets.
5181 * This is required because dhd receives full frame in gSPI unlike SDIO.
5182 * After the frame is received we have to distinguish whether it is data
5183 * or non-data frame.
5185 /* Allocate a packet buffer */
5186 dhd_os_sdlock_rxq(bus->dhd);
5187 if (!(pkt = PKTGET(osh, rdlen + DHD_SDALIGN, FALSE))) {
5188 if (bus->bus == SPI_BUS) {
5189 bus->usebufpool = FALSE;
5190 bus->rxctl = bus->rxbuf;
5192 bus->rxctl += firstread;
5193 if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN)))
5194 bus->rxctl += (DHD_SDALIGN - pad);
5195 bus->rxctl -= firstread;
5197 ASSERT(bus->rxctl >= bus->rxbuf);
5199 /* Read the entire frame */
5200 sdret = dhd_bcmsdh_recv_buf(bus,
5201 bcmsdh_cur_sbwad(sdh),
5203 F2SYNC, rxbuf, rdlen,
5206 ASSERT(sdret != BCME_PENDING);
5209 /* Control frame failures need retransmission */
5211 DHD_ERROR(("%s: read %d control bytes failed: %d\n",
5212 __FUNCTION__, rdlen, sdret));
5213 /* dhd.rx_ctlerrs is higher level */
5215 dhd_os_sdunlock_rxq(bus->dhd);
5216 dhdsdio_rxfail(bus, TRUE,
5217 (bus->bus == SPI_BUS) ? FALSE : TRUE);
5221 /* Give up on data, request rtx of events */
5222 DHD_ERROR(("%s (nextlen): PKTGET failed: len %d rdlen %d "
5223 "expected rxseq %d\n",
5224 __FUNCTION__, len, rdlen, rxseq));
5225 /* Just go try again w/normal header read */
5226 dhd_os_sdunlock_rxq(bus->dhd);
5230 if (bus->bus == SPI_BUS)
5231 bus->usebufpool = TRUE;
5233 ASSERT(!PKTLINK(pkt));
5234 PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN);
5235 rxbuf = (uint8 *)PKTDATA(osh, pkt);
5236 /* Read the entire frame */
5237 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh),
5239 F2SYNC, rxbuf, rdlen,
5242 ASSERT(sdret != BCME_PENDING);
5245 DHD_ERROR(("%s (nextlen): read %d bytes failed: %d\n",
5246 __FUNCTION__, rdlen, sdret));
5247 PKTFREE(bus->dhd->osh, pkt, FALSE);
5248 bus->dhd->rx_errors++;
5249 dhd_os_sdunlock_rxq(bus->dhd);
5250 /* Force retry w/normal header read. Don't attempt NAK for
5253 dhdsdio_rxfail(bus, TRUE,
5254 (bus->bus == SPI_BUS) ? FALSE : TRUE);
5258 dhd_os_sdunlock_rxq(bus->dhd);
5260 /* Now check the header */
5261 bcopy(rxbuf, bus->rxhdr, SDPCM_HDRLEN);
5263 /* Extract hardware header fields */
5264 len = ltoh16_ua(bus->rxhdr);
5265 check = ltoh16_ua(bus->rxhdr + sizeof(uint16));
5267 /* All zeros means readahead info was bad */
5269 DHD_INFO(("%s (nextlen): read zeros in HW header???\n",
5271 dhd_os_sdlock_rxq(bus->dhd);
5273 dhd_os_sdunlock_rxq(bus->dhd);
5274 GSPI_PR55150_BAILOUT;
5278 /* Validate check bytes */
5279 if ((uint16)~(len^check)) {
5280 DHD_ERROR(("%s (nextlen): HW hdr error: nextlen/len/check"
5281 " 0x%04x/0x%04x/0x%04x\n", __FUNCTION__, nextlen,
5283 dhd_os_sdlock_rxq(bus->dhd);
5285 dhd_os_sdunlock_rxq(bus->dhd);
5287 dhdsdio_rxfail(bus, FALSE, FALSE);
5288 GSPI_PR55150_BAILOUT;
5292 /* Validate frame length */
5293 if (len < SDPCM_HDRLEN) {
5294 DHD_ERROR(("%s (nextlen): HW hdr length invalid: %d\n",
5295 __FUNCTION__, len));
5296 dhd_os_sdlock_rxq(bus->dhd);
5298 dhd_os_sdunlock_rxq(bus->dhd);
5299 GSPI_PR55150_BAILOUT;
5303 /* Check for consistency with readahead info */
5304 len_consistent = (nextlen != (ROUNDUP(len, 16) >> 4));
5305 if (len_consistent) {
5306 /* Mismatch, force retry w/normal header (may be >4K) */
5307 DHD_ERROR(("%s (nextlen): mismatch, nextlen %d len %d rnd %d; "
5308 "expected rxseq %d\n",
5309 __FUNCTION__, nextlen, len, ROUNDUP(len, 16), rxseq));
5310 dhd_os_sdlock_rxq(bus->dhd);
5312 dhd_os_sdunlock_rxq(bus->dhd);
5313 dhdsdio_rxfail(bus, TRUE, (bus->bus == SPI_BUS) ? FALSE : TRUE);
5314 GSPI_PR55150_BAILOUT;
5319 /* Extract software header fields */
5320 chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5321 seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5322 doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5323 txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5326 bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
5327 if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
5328 DHD_INFO(("%s (nextlen): got frame w/nextlen too large"
5329 " (%d), seq %d\n", __FUNCTION__, bus->nextlen,
5334 bus->dhd->rx_readahead_cnt ++;
5335 /* Handle Flow Control */
5336 fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5339 if (~bus->flowcontrol & fcbits) {
5343 if (bus->flowcontrol & ~fcbits) {
5350 bus->flowcontrol = fcbits;
5353 /* Check and update sequence number */
5355 DHD_INFO(("%s (nextlen): rx_seq %d, expected %d\n",
5356 __FUNCTION__, seq, rxseq));
5361 /* Check window for sanity */
5362 if ((uint8)(txmax - bus->tx_seq) > 0x70) {
5363 DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
5364 __FUNCTION__, txmax, bus->tx_seq));
5365 txmax = bus->tx_max;
5367 bus->tx_max = txmax;
5370 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
5371 prhex("Rx Data", rxbuf, len);
5372 } else if (DHD_HDRS_ON()) {
5373 prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN);
5377 if (chan == SDPCM_CONTROL_CHANNEL) {
5378 if (bus->bus == SPI_BUS) {
5379 dhdsdio_read_control(bus, rxbuf, len, doff);
5380 if (bus->usebufpool) {
5381 dhd_os_sdlock_rxq(bus->dhd);
5382 PKTFREE(bus->dhd->osh, pkt, FALSE);
5383 dhd_os_sdunlock_rxq(bus->dhd);
5387 DHD_ERROR(("%s (nextlen): readahead on control"
5388 " packet %d?\n", __FUNCTION__, seq));
5389 /* Force retry w/normal header read */
5391 dhdsdio_rxfail(bus, FALSE, TRUE);
5392 dhd_os_sdlock_rxq(bus->dhd);
5394 dhd_os_sdunlock_rxq(bus->dhd);
5399 if ((bus->bus == SPI_BUS) && !bus->usebufpool) {
5400 DHD_ERROR(("Received %d bytes on %d channel. Running out of "
5401 "rx pktbuf's or not yet malloced.\n", len, chan));
5405 /* Validate data offset */
5406 if ((doff < SDPCM_HDRLEN) || (doff > len)) {
5407 DHD_ERROR(("%s (nextlen): bad data offset %d: HW len %d min %d\n",
5408 __FUNCTION__, doff, len, SDPCM_HDRLEN));
5409 dhd_os_sdlock_rxq(bus->dhd);
5411 dhd_os_sdunlock_rxq(bus->dhd);
5413 dhdsdio_rxfail(bus, FALSE, FALSE);
5417 /* All done with this one -- now deliver the packet */
5420 /* gSPI frames should not be handled in fractions */
5421 if (bus->bus == SPI_BUS) {
5425 /* Read frame header (hardware and software) */
5426 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
5427 bus->rxhdr, firstread, NULL, NULL, NULL);
5429 ASSERT(sdret != BCME_PENDING);
5432 DHD_ERROR(("%s: RXHEADER FAILED: %d\n", __FUNCTION__, sdret));
5434 dhdsdio_rxfail(bus, TRUE, TRUE);
5439 if (DHD_BYTES_ON() || DHD_HDRS_ON()) {
5440 prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN);
5444 /* Extract hardware header fields */
5445 len = ltoh16_ua(bus->rxhdr);
5446 check = ltoh16_ua(bus->rxhdr + sizeof(uint16));
5448 /* All zeros means no more frames */
5454 /* Validate check bytes */
5455 if ((uint16)~(len^check)) {
5456 DHD_ERROR(("%s: HW hdr error: len/check 0x%04x/0x%04x\n",
5457 __FUNCTION__, len, check));
5459 dhdsdio_rxfail(bus, FALSE, FALSE);
5463 /* Validate frame length */
5464 if (len < SDPCM_HDRLEN) {
5465 DHD_ERROR(("%s: HW hdr length invalid: %d\n", __FUNCTION__, len));
5469 /* Extract software header fields */
5470 chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5471 seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5472 doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5473 txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5475 /* Validate data offset */
5476 if ((doff < SDPCM_HDRLEN) || (doff > len)) {
5477 DHD_ERROR(("%s: Bad data offset %d: HW len %d, min %d seq %d\n",
5478 __FUNCTION__, doff, len, SDPCM_HDRLEN, seq));
5481 dhdsdio_rxfail(bus, FALSE, FALSE);
5485 /* Save the readahead length if there is one */
5486 bus->nextlen = bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
5487 if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
5488 DHD_INFO(("%s (nextlen): got frame w/nextlen too large (%d), seq %d\n",
5489 __FUNCTION__, bus->nextlen, seq));
5493 /* Handle Flow Control */
5494 fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5497 if (~bus->flowcontrol & fcbits) {
5501 if (bus->flowcontrol & ~fcbits) {
5508 bus->flowcontrol = fcbits;
5511 /* Check and update sequence number */
5513 DHD_INFO(("%s: rx_seq %d, expected %d\n", __FUNCTION__, seq, rxseq));
5518 /* Check window for sanity */
5519 if ((uint8)(txmax - bus->tx_seq) > 0x70) {
5520 DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
5521 __FUNCTION__, txmax, bus->tx_seq));
5522 txmax = bus->tx_max;
5524 bus->tx_max = txmax;
5526 /* Call a separate function for control frames */
5527 if (chan == SDPCM_CONTROL_CHANNEL) {
5528 dhdsdio_read_control(bus, bus->rxhdr, len, doff);
5532 ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL) ||
5533 (chan == SDPCM_TEST_CHANNEL) || (chan == SDPCM_GLOM_CHANNEL));
5535 /* Length to read */
5536 rdlen = (len > firstread) ? (len - firstread) : 0;
5538 /* May pad read to blocksize for efficiency */
5539 if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
5540 pad = bus->blocksize - (rdlen % bus->blocksize);
5541 if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
5542 ((rdlen + pad + firstread) < MAX_RX_DATASZ))
5544 } else if (rdlen % DHD_SDALIGN) {
5545 rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
5548 /* Satisfy length-alignment requirements */
5549 if (forcealign && (rdlen & (ALIGNMENT - 1)))
5550 rdlen = ROUNDUP(rdlen, ALIGNMENT);
5552 if ((rdlen + firstread) > MAX_RX_DATASZ) {
5553 /* Too long -- skip this frame */
5554 DHD_ERROR(("%s: too long: len %d rdlen %d\n", __FUNCTION__, len, rdlen));
5555 bus->dhd->rx_errors++; bus->rx_toolong++;
5556 dhdsdio_rxfail(bus, FALSE, FALSE);
5560 dhd_os_sdlock_rxq(bus->dhd);
5561 if (!(pkt = PKTGET(osh, (rdlen + firstread + DHD_SDALIGN), FALSE))) {
5562 /* Give up on data, request rtx of events */
5563 DHD_ERROR(("%s: PKTGET failed: rdlen %d chan %d\n",
5564 __FUNCTION__, rdlen, chan));
5565 bus->dhd->rx_dropped++;
5566 dhd_os_sdunlock_rxq(bus->dhd);
5567 dhdsdio_rxfail(bus, FALSE, RETRYCHAN(chan));
5570 dhd_os_sdunlock_rxq(bus->dhd);
5572 ASSERT(!PKTLINK(pkt));
5574 /* Leave room for what we already read, and align remainder */
5575 ASSERT(firstread < (PKTLEN(osh, pkt)));
5576 PKTPULL(osh, pkt, firstread);
5577 PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN);
5579 /* Read the remaining frame data */
5580 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
5581 ((uint8 *)PKTDATA(osh, pkt)), rdlen, pkt, NULL, NULL);
5583 ASSERT(sdret != BCME_PENDING);
5586 DHD_ERROR(("%s: read %d %s bytes failed: %d\n", __FUNCTION__, rdlen,
5587 ((chan == SDPCM_EVENT_CHANNEL) ? "event" :
5588 ((chan == SDPCM_DATA_CHANNEL) ? "data" : "test")), sdret));
5589 dhd_os_sdlock_rxq(bus->dhd);
5590 PKTFREE(bus->dhd->osh, pkt, FALSE);
5591 dhd_os_sdunlock_rxq(bus->dhd);
5592 bus->dhd->rx_errors++;
5593 dhdsdio_rxfail(bus, TRUE, RETRYCHAN(chan));
5597 /* Copy the already-read portion */
5598 PKTPUSH(osh, pkt, firstread);
5599 bcopy(bus->rxhdr, PKTDATA(osh, pkt), firstread);
5602 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
5603 prhex("Rx Data", PKTDATA(osh, pkt), len);
5608 /* Save superframe descriptor and allocate packet frame */
5609 if (chan == SDPCM_GLOM_CHANNEL) {
5610 if (SDPCM_GLOMDESC(&bus->rxhdr[SDPCM_FRAMETAG_LEN])) {
5611 DHD_GLOM(("%s: got glom descriptor, %d bytes:\n",
5612 __FUNCTION__, len));
5614 if (DHD_GLOM_ON()) {
5615 prhex("Glom Data", PKTDATA(osh, pkt), len);
5618 PKTSETLEN(osh, pkt, len);
5619 ASSERT(doff == SDPCM_HDRLEN);
5620 PKTPULL(osh, pkt, SDPCM_HDRLEN);
5623 DHD_ERROR(("%s: glom superframe w/o descriptor!\n", __FUNCTION__));
5624 dhdsdio_rxfail(bus, FALSE, FALSE);
5629 /* Fill in packet len and prio, deliver upward */
5630 PKTSETLEN(osh, pkt, len);
5631 PKTPULL(osh, pkt, doff);
5634 /* Test channel packets are processed separately */
5635 if (chan == SDPCM_TEST_CHANNEL) {
5636 dhdsdio_testrcv(bus, pkt, seq);
5641 if (PKTLEN(osh, pkt) == 0) {
5642 dhd_os_sdlock_rxq(bus->dhd);
5643 PKTFREE(bus->dhd->osh, pkt, FALSE);
5644 dhd_os_sdunlock_rxq(bus->dhd);
5646 } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pkt, reorder_info_buf,
5647 &reorder_info_len) != 0) {
5648 DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__));
5649 dhd_os_sdlock_rxq(bus->dhd);
5650 PKTFREE(bus->dhd->osh, pkt, FALSE);
5651 dhd_os_sdunlock_rxq(bus->dhd);
5652 bus->dhd->rx_errors++;
5655 if (reorder_info_len) {
5656 /* Reordering info from the firmware */
5657 dhd_process_pkt_reorder_info(bus->dhd, reorder_info_buf, reorder_info_len,
5665 /* Unlock during rx call */
5666 dhd_os_sdunlock(bus->dhd);
5667 dhd_rx_frame(bus->dhd, ifidx, pkt, pkt_count, chan);
5668 dhd_os_sdlock(bus->dhd);
5670 rxcount = maxframes - rxleft;
5672 /* Message if we hit the limit */
5673 if (!rxleft && !sdtest)
5674 DHD_DATA(("%s: hit rx limit of %d frames\n", __FUNCTION__, maxframes));
5676 #endif /* DHD_DEBUG */
5677 DHD_DATA(("%s: processed %d frames\n", __FUNCTION__, rxcount));
5678 /* Back off rxseq if awaiting rtx, update rx_seq */
5681 bus->rx_seq = rxseq;
5683 if (bus->reqbussleep)
5685 dhdsdio_bussleep(bus, TRUE);
5686 bus->reqbussleep = FALSE;
5688 bus->readframes = FALSE;
5694 dhdsdio_hostmail(dhd_bus_t *bus)
5696 sdpcmd_regs_t *regs = bus->regs;
5697 uint32 intstatus = 0;
5702 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5704 /* Read mailbox data and ack that we did so */
5705 R_SDREG(hmb_data, ®s->tohostmailboxdata, retries);
5706 if (retries <= retry_limit)
5707 W_SDREG(SMB_INT_ACK, ®s->tosbmailbox, retries);
5708 bus->f1regdata += 2;
5710 /* Dongle recomposed rx frames, accept them again */
5711 if (hmb_data & HMB_DATA_NAKHANDLED) {
5712 DHD_INFO(("Dongle reports NAK handled, expect rtx of %d\n", bus->rx_seq));
5714 DHD_ERROR(("%s: unexpected NAKHANDLED!\n", __FUNCTION__));
5716 bus->rxskip = FALSE;
5717 intstatus |= FRAME_AVAIL_MASK(bus);
5721 * DEVREADY does not occur with gSPI.
5723 if (hmb_data & (HMB_DATA_DEVREADY | HMB_DATA_FWREADY)) {
5724 bus->sdpcm_ver = (hmb_data & HMB_DATA_VERSION_MASK) >> HMB_DATA_VERSION_SHIFT;
5725 if (bus->sdpcm_ver != SDPCM_PROT_VERSION)
5726 DHD_ERROR(("Version mismatch, dongle reports %d, expecting %d\n",
5727 bus->sdpcm_ver, SDPCM_PROT_VERSION));
5729 DHD_INFO(("Dongle ready, protocol version %d\n", bus->sdpcm_ver));
5730 /* make sure for the SDIO_DEVICE_RXDATAINT_MODE_1 corecontrol is proper */
5731 if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev >= 4) &&
5732 (bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_1)) {
5735 val = R_REG(bus->dhd->osh, &bus->regs->corecontrol);
5736 val &= ~CC_XMTDATAAVAIL_MODE;
5737 val |= CC_XMTDATAAVAIL_CTRL;
5738 W_REG(bus->dhd->osh, &bus->regs->corecontrol, val);
5740 val = R_REG(bus->dhd->osh, &bus->regs->corecontrol);
5744 /* Retrieve console state address now that firmware should have updated it */
5746 sdpcm_shared_t shared;
5747 if (dhdsdio_readshared(bus, &shared) == 0)
5748 bus->console_addr = shared.console_addr;
5750 #endif /* DHD_DEBUG */
5754 * Flow Control has been moved into the RX headers and this out of band
5755 * method isn't used any more. Leave this here for possibly remaining backward
5756 * compatible with older dongles
5758 if (hmb_data & HMB_DATA_FC) {
5759 fcbits = (hmb_data & HMB_DATA_FCDATA_MASK) >> HMB_DATA_FCDATA_SHIFT;
5761 if (fcbits & ~bus->flowcontrol)
5763 if (bus->flowcontrol & ~fcbits)
5767 bus->flowcontrol = fcbits;
5771 /* At least print a message if FW halted */
5772 if (hmb_data & HMB_DATA_FWHALT) {
5773 DHD_ERROR(("INTERNAL ERROR: FIRMWARE HALTED : set BUS DOWN\n"));
5774 dhdsdio_checkdied(bus, NULL, 0);
5775 bus->dhd->busstate = DHD_BUS_DOWN;
5777 #endif /* DHD_DEBUG */
5779 /* Shouldn't be any others */
5780 if (hmb_data & ~(HMB_DATA_DEVREADY |
5782 HMB_DATA_NAKHANDLED |
5785 HMB_DATA_FCDATA_MASK |
5786 HMB_DATA_VERSION_MASK)) {
5787 DHD_ERROR(("Unknown mailbox data content: 0x%02x\n", hmb_data));
5794 dhdsdio_dpc(dhd_bus_t *bus)
5796 bcmsdh_info_t *sdh = bus->sdh;
5797 sdpcmd_regs_t *regs = bus->regs;
5798 uint32 intstatus, newstatus = 0;
5800 uint rxlimit = dhd_rxbound; /* Rx frames to read before resched */
5801 uint txlimit = dhd_txbound; /* Tx frames to send before resched */
5802 uint framecnt = 0; /* Temporary counter of tx/rx frames */
5803 bool rxdone = TRUE; /* Flag for no more read data */
5804 bool resched = FALSE; /* Flag indicating resched wanted */
5805 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5807 dhd_os_sdlock(bus->dhd);
5809 if (bus->dhd->busstate == DHD_BUS_DOWN) {
5810 DHD_ERROR(("%s: Bus down, ret\n", __FUNCTION__));
5812 dhd_os_sdunlock(bus->dhd);
5816 /* Start with leftover status bits */
5817 intstatus = bus->intstatus;
5819 if (!SLPAUTO_ENAB(bus) && !KSO_ENAB(bus)) {
5820 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
5824 /* If waiting for HTAVAIL, check status */
5825 if (!SLPAUTO_ENAB(bus) && (bus->clkstate == CLK_PENDING)) {
5827 uint8 clkctl, devctl = 0;
5830 /* Check for inconsistent device control */
5831 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
5833 DHD_ERROR(("%s: error reading DEVCTL: %d\n", __FUNCTION__, err));
5834 bus->dhd->busstate = DHD_BUS_DOWN;
5836 ASSERT(devctl & SBSDIO_DEVCTL_CA_INT_ONLY);
5838 #endif /* DHD_DEBUG */
5840 /* Read CSR, if clock on switch to AVAIL, else ignore */
5841 clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
5843 DHD_ERROR(("%s: error reading CSR: %d\n", __FUNCTION__, err));
5844 bus->dhd->busstate = DHD_BUS_DOWN;
5847 DHD_INFO(("DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n", devctl, clkctl));
5849 if (SBSDIO_HTAV(clkctl)) {
5850 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
5852 DHD_ERROR(("%s: error reading DEVCTL: %d\n",
5853 __FUNCTION__, err));
5854 bus->dhd->busstate = DHD_BUS_DOWN;
5856 devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
5857 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
5859 DHD_ERROR(("%s: error writing DEVCTL: %d\n",
5860 __FUNCTION__, err));
5861 bus->dhd->busstate = DHD_BUS_DOWN;
5863 bus->clkstate = CLK_AVAIL;
5871 /* Make sure backplane clock is on */
5872 dhdsdio_clkctl(bus, CLK_AVAIL, TRUE);
5873 if (bus->clkstate != CLK_AVAIL)
5876 /* Pending interrupt indicates new device status */
5879 R_SDREG(newstatus, ®s->intstatus, retries);
5881 if (bcmsdh_regfail(bus->sdh))
5883 newstatus &= bus->hostintmask;
5884 bus->fcstate = !!(newstatus & I_HMB_FC_STATE);
5887 if ((bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_0) &&
5888 (newstatus == I_XMTDATA_AVAIL)) {
5891 W_SDREG(newstatus, ®s->intstatus, retries);
5895 /* Merge new bits with previous */
5896 intstatus |= newstatus;
5899 /* Handle flow-control change: read new state in case our ack
5900 * crossed another change interrupt. If change still set, assume
5901 * FC ON for safety, let next loop through do the debounce.
5903 if (intstatus & I_HMB_FC_CHANGE) {
5904 intstatus &= ~I_HMB_FC_CHANGE;
5905 W_SDREG(I_HMB_FC_CHANGE, ®s->intstatus, retries);
5906 R_SDREG(newstatus, ®s->intstatus, retries);
5907 bus->f1regdata += 2;
5908 bus->fcstate = !!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE));
5909 intstatus |= (newstatus & bus->hostintmask);
5912 /* Just being here means nothing more to do for chipactive */
5913 if (intstatus & I_CHIPACTIVE) {
5914 /* ASSERT(bus->clkstate == CLK_AVAIL); */
5915 intstatus &= ~I_CHIPACTIVE;
5918 /* Handle host mailbox indication */
5919 if (intstatus & I_HMB_HOST_INT) {
5920 intstatus &= ~I_HMB_HOST_INT;
5921 intstatus |= dhdsdio_hostmail(bus);
5924 /* Generally don't ask for these, can get CRC errors... */
5925 if (intstatus & I_WR_OOSYNC) {
5926 DHD_ERROR(("Dongle reports WR_OOSYNC\n"));
5927 intstatus &= ~I_WR_OOSYNC;
5930 if (intstatus & I_RD_OOSYNC) {
5931 DHD_ERROR(("Dongle reports RD_OOSYNC\n"));
5932 intstatus &= ~I_RD_OOSYNC;
5935 if (intstatus & I_SBINT) {
5936 DHD_ERROR(("Dongle reports SBINT\n"));
5937 intstatus &= ~I_SBINT;
5940 /* Would be active due to wake-wlan in gSPI */
5941 if (intstatus & I_CHIPACTIVE) {
5942 DHD_INFO(("Dongle reports CHIPACTIVE\n"));
5943 intstatus &= ~I_CHIPACTIVE;
5946 if (intstatus & I_HMB_FC_STATE) {
5947 DHD_INFO(("Dongle reports HMB_FC_STATE\n"));
5948 intstatus &= ~I_HMB_FC_STATE;
5951 /* Ignore frame indications if rxskip is set */
5953 intstatus &= ~FRAME_AVAIL_MASK(bus);
5956 /* On frame indication, read available frames */
5957 if (PKT_AVAILABLE(bus, intstatus)) {
5958 framecnt = dhdsdio_readframes(bus, rxlimit, &rxdone);
5959 if (rxdone || bus->rxskip)
5960 intstatus &= ~FRAME_AVAIL_MASK(bus);
5961 rxlimit -= MIN(framecnt, rxlimit);
5964 /* Keep still-pending events for next scheduling */
5965 bus->intstatus = intstatus;
5968 /* Re-enable interrupts to detect new device events (mailbox, rx frame)
5969 * or clock availability. (Allows tx loop to check ipend if desired.)
5970 * (Unless register access seems hosed, as we may not be able to ACK...)
5972 if (bus->intr && bus->intdis && !bcmsdh_regfail(sdh)) {
5973 DHD_INTR(("%s: enable SDIO interrupts, rxdone %d framecnt %d\n",
5974 __FUNCTION__, rxdone, framecnt));
5975 bus->intdis = FALSE;
5976 #if defined(OOB_INTR_ONLY)
5977 bcmsdh_oob_intr_set(bus->sdh, TRUE);
5978 #endif /* defined(OOB_INTR_ONLY) */
5979 #if !defined(NDISVER) || (NDISVER < 0x0630)
5980 bcmsdh_intr_enable(sdh);
5981 #endif /* !defined(NDISVER) || (NDISVER < 0x0630) */
5984 #if defined(OOB_INTR_ONLY) && !defined(HW_OOB)
5985 /* In case of SW-OOB(using edge trigger),
5986 * Check interrupt status in the dongle again after enable irq on the host.
5987 * and rechedule dpc if interrupt is pended in the dongle.
5988 * There is a chance to miss OOB interrupt while irq is disabled on the host.
5989 * No need to do this with HW-OOB(level trigger)
5991 R_SDREG(newstatus, ®s->intstatus, retries);
5992 if (bcmsdh_regfail(bus->sdh))
5994 if (newstatus & bus->hostintmask) {
5998 #endif /* defined(OOB_INTR_ONLY) && !defined(HW_OOB) */
6000 #ifdef PROP_TXSTATUS
6001 dhd_wlfc_commit_packets(bus->dhd, (f_commitpkt_t)dhd_bus_txdata, (void *)bus, NULL, FALSE);
6004 if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL))
6005 dhdsdio_sendpendctl(bus);
6007 /* Send queued frames (limit 1 if rx may still be pending) */
6008 else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate &&
6009 pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit && DATAOK(bus)) {
6010 framecnt = rxdone ? txlimit : MIN(txlimit, dhd_txminmax);
6011 framecnt = dhdsdio_sendfromq(bus, framecnt);
6012 txlimit -= framecnt;
6014 /* Resched the DPC if ctrl cmd is pending on bus credit */
6015 if (bus->ctrl_frame_stat)
6018 /* Resched if events or tx frames are pending, else await next interrupt */
6019 /* On failed register access, all bets are off: no resched or interrupts */
6020 if ((bus->dhd->busstate == DHD_BUS_DOWN) || bcmsdh_regfail(sdh)) {
6021 if ((bus->sih && bus->sih->buscorerev >= 12) && !(dhdsdio_sleepcsr_get(bus) &
6022 SBSDIO_FUNC1_SLEEPCSR_KSO_MASK)) {
6023 /* Bus failed because of KSO */
6024 DHD_ERROR(("%s: Bus failed due to KSO\n", __FUNCTION__));
6027 DHD_ERROR(("%s: failed backplane access over SDIO, halting operation\n",
6029 bus->dhd->busstate = DHD_BUS_DOWN;
6032 } else if (bus->clkstate == CLK_PENDING) {
6033 /* Awaiting I_CHIPACTIVE; don't resched */
6034 } else if (bus->intstatus || bus->ipend ||
6035 (!bus->fcstate && pktq_mlen(&bus->txq, ~bus->flowcontrol) && DATAOK(bus)) ||
6036 PKT_AVAILABLE(bus, bus->intstatus)) { /* Read multiple frames */
6040 bus->dpc_sched = resched;
6042 /* If we're done for now, turn off clock request. */
6043 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && (bus->clkstate != CLK_PENDING)) {
6044 bus->activity = FALSE;
6045 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
6050 if (!resched && dhd_dpcpoll) {
6051 if (dhdsdio_readframes(bus, dhd_rxbound, &rxdone) != 0)
6055 dhd_os_sdunlock(bus->dhd);
6060 dhd_bus_dpc(struct dhd_bus *bus)
6064 /* Call the DPC directly. */
6065 DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__));
6066 resched = dhdsdio_dpc(bus);
6072 dhdsdio_isr(void *arg)
6074 dhd_bus_t *bus = (dhd_bus_t*)arg;
6077 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
6080 DHD_ERROR(("%s : bus is null pointer , exit \n", __FUNCTION__));
6085 if (bus->dhd->busstate == DHD_BUS_DOWN) {
6086 DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__));
6090 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
6092 /* Count the interrupt call */
6096 /* Shouldn't get this interrupt if we're sleeping? */
6097 if (!SLPAUTO_ENAB(bus)) {
6098 if (bus->sleeping) {
6099 DHD_ERROR(("INTERRUPT WHILE SLEEPING??\n"));
6101 } else if (!KSO_ENAB(bus)) {
6102 DHD_ERROR(("ISR in devsleep 1\n"));
6106 /* Disable additional interrupts (is this needed now)? */
6108 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
6110 DHD_ERROR(("dhdsdio_isr() w/o interrupt configured!\n"));
6113 #if !defined(NDISVER) || (NDISVER < 0x0630)
6114 bcmsdh_intr_disable(sdh);
6115 #endif /* !defined(NDISVER) || (NDISVER < 0x0630) */
6118 #if defined(SDIO_ISR_THREAD)
6119 DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__));
6120 DHD_OS_WAKE_LOCK(bus->dhd);
6122 DHD_OS_WAKE_UNLOCK(bus->dhd);
6125 #if !defined(NDISVER) || (NDISVER < 0x0630)
6126 bus->dpc_sched = TRUE;
6127 dhd_sched_dpc(bus->dhd);
6128 #endif /* !defined(NDISVER) || (NDISVER < 0x0630) */
6130 #endif /* defined(SDIO_ISR_THREAD) */
6136 dhdsdio_pktgen_init(dhd_bus_t *bus)
6138 /* Default to specified length, or full range */
6139 if (dhd_pktgen_len) {
6140 bus->pktgen_maxlen = MIN(dhd_pktgen_len, MAX_PKTGEN_LEN);
6141 bus->pktgen_minlen = bus->pktgen_maxlen;
6143 bus->pktgen_maxlen = MAX_PKTGEN_LEN;
6144 bus->pktgen_minlen = 0;
6146 bus->pktgen_len = (uint16)bus->pktgen_minlen;
6148 /* Default to per-watchdog burst with 10s print time */
6149 bus->pktgen_freq = 1;
6150 bus->pktgen_print = dhd_watchdog_ms ? (10000 / dhd_watchdog_ms) : 0;
6151 bus->pktgen_count = (dhd_pktgen * dhd_watchdog_ms + 999) / 1000;
6153 /* Default to echo mode */
6154 bus->pktgen_mode = DHD_PKTGEN_ECHO;
6155 bus->pktgen_stop = 1;
6159 dhdsdio_pktgen(dhd_bus_t *bus)
6165 osl_t *osh = bus->dhd->osh;
6171 /* Display current count if appropriate */
6172 if (bus->pktgen_print && (++bus->pktgen_ptick >= bus->pktgen_print)) {
6173 bus->pktgen_ptick = 0;
6174 printf("%s: send attempts %d, rcvd %d, errors %d\n",
6175 __FUNCTION__, bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail);
6177 /* Print throughput stats only for constant length packet runs */
6178 if (bus->pktgen_minlen == bus->pktgen_maxlen) {
6179 time_lapse = jiffies - bus->pktgen_prev_time;
6180 bus->pktgen_prev_time = jiffies;
6181 sent_pkts = bus->pktgen_sent - bus->pktgen_prev_sent;
6182 bus->pktgen_prev_sent = bus->pktgen_sent;
6183 rcvd_pkts = bus->pktgen_rcvd - bus->pktgen_prev_rcvd;
6184 bus->pktgen_prev_rcvd = bus->pktgen_rcvd;
6186 printf("%s: Tx Throughput %d kbps, Rx Throughput %d kbps\n",
6188 (sent_pkts * bus->pktgen_len / jiffies_to_msecs(time_lapse)) * 8,
6189 (rcvd_pkts * bus->pktgen_len / jiffies_to_msecs(time_lapse)) * 8);
6193 /* For recv mode, just make sure dongle has started sending */
6194 if (bus->pktgen_mode == DHD_PKTGEN_RECV) {
6195 if (bus->pktgen_rcv_state == PKTGEN_RCV_IDLE) {
6196 bus->pktgen_rcv_state = PKTGEN_RCV_ONGOING;
6197 dhdsdio_sdtest_set(bus, bus->pktgen_total);
6202 /* Otherwise, generate or request the specified number of packets */
6203 for (pktcount = 0; pktcount < bus->pktgen_count; pktcount++) {
6204 /* Stop if total has been reached */
6205 if (bus->pktgen_total && (bus->pktgen_sent >= bus->pktgen_total)) {
6206 bus->pktgen_count = 0;
6210 /* Allocate an appropriate-sized packet */
6211 if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) {
6212 len = SDPCM_TEST_PKT_CNT_FLD_LEN;
6214 len = bus->pktgen_len;
6216 if (!(pkt = PKTGET(osh, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN),
6218 DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__));
6221 PKTALIGN(osh, pkt, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN), DHD_SDALIGN);
6222 data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
6224 /* Write test header cmd and extra based on mode */
6225 switch (bus->pktgen_mode) {
6226 case DHD_PKTGEN_ECHO:
6227 *data++ = SDPCM_TEST_ECHOREQ;
6228 *data++ = (uint8)bus->pktgen_sent;
6231 case DHD_PKTGEN_SEND:
6232 *data++ = SDPCM_TEST_DISCARD;
6233 *data++ = (uint8)bus->pktgen_sent;
6236 case DHD_PKTGEN_RXBURST:
6237 *data++ = SDPCM_TEST_BURST;
6238 *data++ = (uint8)bus->pktgen_count; /* Just for backward compatability */
6242 DHD_ERROR(("Unrecognized pktgen mode %d\n", bus->pktgen_mode));
6243 PKTFREE(osh, pkt, TRUE);
6244 bus->pktgen_count = 0;
6248 /* Write test header length field */
6249 *data++ = (bus->pktgen_len >> 0);
6250 *data++ = (bus->pktgen_len >> 8);
6252 /* Write frame count in a 4 byte field adjucent to SDPCM test header for
6255 if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) {
6256 *data++ = (uint8)(bus->pktgen_count >> 0);
6257 *data++ = (uint8)(bus->pktgen_count >> 8);
6258 *data++ = (uint8)(bus->pktgen_count >> 16);
6259 *data++ = (uint8)(bus->pktgen_count >> 24);
6262 /* Then fill in the remainder -- N/A for burst */
6263 for (fillbyte = 0; fillbyte < len; fillbyte++)
6264 *data++ = SDPCM_TEST_FILL(fillbyte, (uint8)bus->pktgen_sent);
6268 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
6269 data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
6270 prhex("dhdsdio_pktgen: Tx Data", data, PKTLEN(osh, pkt) - SDPCM_HDRLEN);
6275 if (dhdsdio_txpkt(bus, SDPCM_TEST_CHANNEL, &pkt, 1, TRUE) != BCME_OK) {
6277 if (bus->pktgen_stop && bus->pktgen_stop == bus->pktgen_fail)
6278 bus->pktgen_count = 0;
6282 /* Bump length if not fixed, wrap at max */
6283 if (++bus->pktgen_len > bus->pktgen_maxlen)
6284 bus->pktgen_len = (uint16)bus->pktgen_minlen;
6286 /* Special case for burst mode: just send one request! */
6287 if (bus->pktgen_mode == DHD_PKTGEN_RXBURST)
6293 dhdsdio_sdtest_set(dhd_bus_t *bus, uint count)
6297 osl_t *osh = bus->dhd->osh;
6299 /* Allocate the packet */
6300 if (!(pkt = PKTGET(osh, SDPCM_HDRLEN + SDPCM_TEST_HDRLEN +
6301 SDPCM_TEST_PKT_CNT_FLD_LEN + DHD_SDALIGN, TRUE))) {
6302 DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__));
6305 PKTALIGN(osh, pkt, (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN +
6306 SDPCM_TEST_PKT_CNT_FLD_LEN), DHD_SDALIGN);
6307 data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
6309 /* Fill in the test header */
6310 *data++ = SDPCM_TEST_SEND;
6311 *data++ = (count > 0)?TRUE:FALSE;
6312 *data++ = (bus->pktgen_maxlen >> 0);
6313 *data++ = (bus->pktgen_maxlen >> 8);
6314 *data++ = (uint8)(count >> 0);
6315 *data++ = (uint8)(count >> 8);
6316 *data++ = (uint8)(count >> 16);
6317 *data++ = (uint8)(count >> 24);
6320 if (dhdsdio_txpkt(bus, SDPCM_TEST_CHANNEL, &pkt, 1, TRUE) != BCME_OK)
6326 dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq)
6328 osl_t *osh = bus->dhd->osh;
6337 /* Check for min length */
6338 if ((pktlen = PKTLEN(osh, pkt)) < SDPCM_TEST_HDRLEN) {
6339 DHD_ERROR(("dhdsdio_restrcv: toss runt frame, pktlen %d\n", pktlen));
6340 PKTFREE(osh, pkt, FALSE);
6344 /* Extract header fields */
6345 data = PKTDATA(osh, pkt);
6348 len = *data++; len += *data++ << 8;
6349 DHD_TRACE(("%s:cmd:%d, xtra:%d,len:%d\n", __FUNCTION__, cmd, extra, len));
6350 /* Check length for relevant commands */
6351 if (cmd == SDPCM_TEST_DISCARD || cmd == SDPCM_TEST_ECHOREQ || cmd == SDPCM_TEST_ECHORSP) {
6352 if (pktlen != len + SDPCM_TEST_HDRLEN) {
6353 DHD_ERROR(("dhdsdio_testrcv: frame length mismatch, pktlen %d seq %d"
6354 " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len));
6355 PKTFREE(osh, pkt, FALSE);
6360 /* Process as per command */
6362 case SDPCM_TEST_ECHOREQ:
6363 /* Rx->Tx turnaround ok (even on NDIS w/current implementation) */
6364 *(uint8 *)(PKTDATA(osh, pkt)) = SDPCM_TEST_ECHORSP;
6365 if (dhdsdio_txpkt(bus, SDPCM_TEST_CHANNEL, &pkt, 1, TRUE) == BCME_OK) {
6369 PKTFREE(osh, pkt, FALSE);
6374 case SDPCM_TEST_ECHORSP:
6375 if (bus->ext_loop) {
6376 PKTFREE(osh, pkt, FALSE);
6381 for (offset = 0; offset < len; offset++, data++) {
6382 if (*data != SDPCM_TEST_FILL(offset, extra)) {
6383 DHD_ERROR(("dhdsdio_testrcv: echo data mismatch: "
6384 "offset %d (len %d) expect 0x%02x rcvd 0x%02x\n",
6385 offset, len, SDPCM_TEST_FILL(offset, extra), *data));
6389 PKTFREE(osh, pkt, FALSE);
6393 case SDPCM_TEST_DISCARD:
6397 uint8 testval = extra;
6398 for (i = 0; i < len; i++) {
6399 if (*prn != testval) {
6400 DHD_ERROR(("DIErr@Pkt#:%d,Ix:%d, expected:0x%x, got:0x%x\n",
6401 i, bus->pktgen_rcvd_rcvsession, testval, *prn));
6406 PKTFREE(osh, pkt, FALSE);
6410 case SDPCM_TEST_BURST:
6411 case SDPCM_TEST_SEND:
6413 DHD_INFO(("dhdsdio_testrcv: unsupported or unknown command, pktlen %d seq %d"
6414 " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len));
6415 PKTFREE(osh, pkt, FALSE);
6419 /* For recv mode, stop at limit (and tell dongle to stop sending) */
6420 if (bus->pktgen_mode == DHD_PKTGEN_RECV) {
6421 if (bus->pktgen_rcv_state != PKTGEN_RCV_IDLE) {
6422 bus->pktgen_rcvd_rcvsession++;
6424 if (bus->pktgen_total &&
6425 (bus->pktgen_rcvd_rcvsession >= bus->pktgen_total)) {
6426 bus->pktgen_count = 0;
6427 DHD_ERROR(("Pktgen:rcv test complete!\n"));
6428 bus->pktgen_rcv_state = PKTGEN_RCV_IDLE;
6429 dhdsdio_sdtest_set(bus, FALSE);
6430 bus->pktgen_rcvd_rcvsession = 0;
6437 int dhd_bus_oob_intr_register(dhd_pub_t *dhdp)
6441 #if defined(OOB_INTR_ONLY)
6442 err = bcmsdh_oob_intr_register(dhdp->bus->sdh, dhdsdio_isr, dhdp->bus);
6447 void dhd_bus_oob_intr_unregister(dhd_pub_t *dhdp)
6449 #if defined(OOB_INTR_ONLY)
6450 bcmsdh_oob_intr_unregister(dhdp->bus->sdh);
6454 void dhd_bus_oob_intr_set(dhd_pub_t *dhdp, bool enable)
6456 #if defined(OOB_INTR_ONLY)
6457 bcmsdh_oob_intr_set(dhdp->bus->sdh, enable);
6461 void dhd_bus_dev_pm_stay_awake(dhd_pub_t *dhdpub)
6463 bcmsdh_dev_pm_stay_awake(dhdpub->bus->sdh);
6466 void dhd_bus_dev_pm_relax(dhd_pub_t *dhdpub)
6468 bcmsdh_dev_relax(dhdpub->bus->sdh);
6471 bool dhd_bus_dev_pm_enabled(dhd_pub_t *dhdpub)
6473 bool enabled = FALSE;
6475 enabled = bcmsdh_dev_pm_enabled(dhdpub->bus->sdh);
6480 dhd_bus_watchdog(dhd_pub_t *dhdp)
6484 DHD_TIMER(("%s: Enter\n", __FUNCTION__));
6488 if (bus->dhd->dongle_reset)
6491 if (bus->dhd->hang_was_sent) {
6492 dhd_os_wd_timer(bus->dhd, 0);
6496 /* Ignore the timer if simulating bus down */
6497 if (!SLPAUTO_ENAB(bus) && bus->sleeping)
6500 if (dhdp->busstate == DHD_BUS_DOWN)
6503 dhd_os_sdlock(bus->dhd);
6505 /* Poll period: check device if appropriate. */
6506 if (!SLPAUTO_ENAB(bus) && (bus->poll && (++bus->polltick >= bus->pollrate))) {
6507 uint32 intstatus = 0;
6509 /* Reset poll tick */
6512 /* Check device if no interrupts */
6513 if (!bus->intr || (bus->intrcount == bus->lastintrs)) {
6515 if (!bus->dpc_sched) {
6517 devpend = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0,
6518 SDIOD_CCCR_INTPEND, NULL);
6519 intstatus = devpend & (INTR_STATUS_FUNC1 | INTR_STATUS_FUNC2);
6522 /* If there is something, make like the ISR and schedule the DPC */
6527 bcmsdh_intr_disable(bus->sdh);
6529 bus->dpc_sched = TRUE;
6530 dhd_sched_dpc(bus->dhd);
6534 /* Update interrupt tracking */
6535 bus->lastintrs = bus->intrcount;
6539 /* Poll for console output periodically */
6540 if (dhdp->busstate == DHD_BUS_DATA && dhd_console_ms != 0) {
6541 bus->console.count += dhd_watchdog_ms;
6542 if (bus->console.count >= dhd_console_ms) {
6543 bus->console.count -= dhd_console_ms;
6544 /* Make sure backplane clock is on */
6545 if (SLPAUTO_ENAB(bus))
6546 dhdsdio_bussleep(bus, FALSE);
6548 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
6549 if (dhdsdio_readconsole(bus) < 0)
6550 dhd_console_ms = 0; /* On error, stop trying */
6553 #endif /* DHD_DEBUG */
6556 /* Generate packets if configured */
6557 if (bus->pktgen_count && (++bus->pktgen_tick >= bus->pktgen_freq)) {
6558 /* Make sure backplane clock is on */
6559 if (SLPAUTO_ENAB(bus))
6560 dhdsdio_bussleep(bus, FALSE);
6562 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
6563 bus->pktgen_tick = 0;
6564 dhdsdio_pktgen(bus);
6568 /* On idle timeout clear activity flag and/or turn off clock */
6569 #ifdef DHD_USE_IDLECOUNT
6571 bus->activity = FALSE;
6575 if ((bus->idletime > 0) && (bus->idlecount >= bus->idletime)) {
6576 DHD_TIMER(("%s: DHD Idle state!!\n", __FUNCTION__));
6577 if (SLPAUTO_ENAB(bus)) {
6578 if (dhdsdio_bussleep(bus, TRUE) != BCME_BUSY)
6579 dhd_os_wd_timer(bus->dhd, 0);
6581 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
6587 if ((bus->idletime > 0) && (bus->clkstate == CLK_AVAIL)) {
6588 if (++bus->idlecount >= bus->idletime) {
6590 if (bus->activity) {
6591 bus->activity = FALSE;
6592 if (SLPAUTO_ENAB(bus)) {
6593 if (!bus->readframes)
6594 dhdsdio_bussleep(bus, TRUE);
6596 bus->reqbussleep = TRUE;
6599 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
6603 #endif /* DHD_USE_IDLECOUNT */
6605 dhd_os_sdunlock(bus->dhd);
6612 dhd_bus_console_in(dhd_pub_t *dhdp, uchar *msg, uint msglen)
6614 dhd_bus_t *bus = dhdp->bus;
6619 /* Address could be zero if CONSOLE := 0 in dongle Makefile */
6620 if (bus->console_addr == 0)
6621 return BCME_UNSUPPORTED;
6623 /* Exclusive bus access */
6624 dhd_os_sdlock(bus->dhd);
6626 /* Don't allow input if dongle is in reset */
6627 if (bus->dhd->dongle_reset) {
6628 dhd_os_sdunlock(bus->dhd);
6629 return BCME_NOTREADY;
6632 /* Request clock to allow SDIO accesses */
6634 /* No pend allowed since txpkt is called later, ht clk has to be on */
6635 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
6637 /* Zero cbuf_index */
6638 addr = bus->console_addr + OFFSETOF(hnd_cons_t, cbuf_idx);
6640 if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0)
6643 /* Write message into cbuf */
6644 addr = bus->console_addr + OFFSETOF(hnd_cons_t, cbuf);
6645 if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)msg, msglen)) < 0)
6648 /* Write length into vcons_in */
6649 addr = bus->console_addr + OFFSETOF(hnd_cons_t, vcons_in);
6650 val = htol32(msglen);
6651 if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0)
6654 /* Bump dongle by sending an empty packet on the event channel.
6655 * sdpcm_sendup (RX) checks for virtual console input.
6657 if ((pkt = PKTGET(bus->dhd->osh, 4 + SDPCM_RESERVE, TRUE)) != NULL)
6658 rv = dhdsdio_txpkt(bus, SDPCM_EVENT_CHANNEL, &pkt, 1, TRUE);
6661 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
6662 bus->activity = FALSE;
6663 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
6666 dhd_os_sdunlock(bus->dhd);
6670 #endif /* DHD_DEBUG */
6674 dhd_dump_cis(uint fn, uint8 *cis)
6676 uint byte, tag, tdata;
6677 DHD_INFO(("Function %d CIS:\n", fn));
6679 for (tdata = byte = 0; byte < SBSDIO_CIS_SIZE_LIMIT; byte++) {
6680 if ((byte % 16) == 0)
6682 DHD_INFO(("%02x ", cis[byte]));
6683 if ((byte % 16) == 15)
6691 else if ((byte + 1) < SBSDIO_CIS_SIZE_LIMIT)
6692 tdata = cis[byte + 1] + 1;
6697 if ((byte % 16) != 15)
6700 #endif /* DHD_DEBUG */
6703 dhdsdio_chipmatch(uint16 chipid)
6705 if (chipid == BCM4325_CHIP_ID)
6707 if (chipid == BCM4329_CHIP_ID)
6709 if (chipid == BCM4315_CHIP_ID)
6711 if (chipid == BCM4319_CHIP_ID)
6713 if (chipid == BCM4336_CHIP_ID)
6715 if (chipid == BCM4330_CHIP_ID)
6717 if (chipid == BCM43237_CHIP_ID)
6719 if (chipid == BCM43362_CHIP_ID)
6721 if (chipid == BCM4314_CHIP_ID)
6723 if (chipid == BCM43242_CHIP_ID)
6725 if (chipid == BCM43340_CHIP_ID)
6727 if (chipid == BCM43341_CHIP_ID)
6729 if (chipid == BCM43143_CHIP_ID)
6731 if (chipid == BCM43342_CHIP_ID)
6733 if (chipid == BCM4334_CHIP_ID)
6735 if (chipid == BCM43239_CHIP_ID)
6737 if (chipid == BCM4324_CHIP_ID)
6739 if (chipid == BCM4335_CHIP_ID)
6741 if (chipid == BCM4339_CHIP_ID)
6743 if (chipid == BCM43349_CHIP_ID)
6745 if (chipid == BCM4345_CHIP_ID)
6747 if (chipid == BCM4350_CHIP_ID)
6749 if (chipid == BCM4354_CHIP_ID)
6751 if (chipid == BCM4356_CHIP_ID)
6753 if (chipid == BCM4358_CHIP_ID)
6755 if (chipid == BCM43430_CHIP_ID)
6757 if (BCM4349_CHIP(chipid))
6763 dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot,
6764 uint16 func, uint bustype, void *regsva, osl_t * osh, void *sdh)
6769 #if defined(MULTIPLE_SUPPLICANT)
6770 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
6771 if (mutex_is_locked(&_dhd_sdio_mutex_lock_) == 0) {
6772 DHD_ERROR(("%s : no mutex held. set lock\n", __FUNCTION__));
6775 DHD_ERROR(("%s : mutex is locked!. wait for unlocking\n", __FUNCTION__));
6777 mutex_lock(&_dhd_sdio_mutex_lock_);
6778 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
6781 /* Init global variables at run-time, not as part of the declaration.
6782 * This is required to support init/de-init of the driver. Initialization
6783 * of globals as part of the declaration results in non-deterministic
6784 * behavior since the value of the globals may be different on the
6785 * first time that the driver is initialized vs subsequent initializations.
6787 dhd_txbound = DHD_TXBOUND;
6788 dhd_rxbound = DHD_RXBOUND;
6789 dhd_alignctl = TRUE;
6791 dhd_readahead = TRUE;
6793 #if !defined(PLATFORM_MPS)
6797 #endif /* OEM_ANDROID */
6798 dhd_dongle_ramsize = 0;
6799 dhd_txminmax = DHD_TXMINMAX;
6803 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
6804 DHD_INFO(("%s: venid 0x%04x devid 0x%04x\n", __FUNCTION__, venid, devid));
6806 /* We make assumptions about address window mappings */
6807 ASSERT((uintptr)regsva == SI_ENUM_BASE);
6809 /* BCMSDH passes venid and devid based on CIS parsing -- but low-power start
6810 * means early parse could fail, so here we should get either an ID
6811 * we recognize OR (-1) indicating we must request power first.
6813 /* Check the Vendor ID */
6816 case VENDOR_BROADCOM:
6819 DHD_ERROR(("%s: unknown vendor: 0x%04x\n",
6820 __FUNCTION__, venid));
6824 /* Check the Device ID and make sure it's one that we support */
6826 case BCM4325_D11DUAL_ID: /* 4325 802.11a/g id */
6827 case BCM4325_D11G_ID: /* 4325 802.11g 2.4Ghz band id */
6828 case BCM4325_D11A_ID: /* 4325 802.11a 5Ghz band id */
6829 DHD_INFO(("%s: found 4325 Dongle\n", __FUNCTION__));
6831 case BCM4329_D11N_ID: /* 4329 802.11n dualband device */
6832 case BCM4329_D11N2G_ID: /* 4329 802.11n 2.4G device */
6833 case BCM4329_D11N5G_ID: /* 4329 802.11n 5G device */
6835 DHD_INFO(("%s: found 4329 Dongle\n", __FUNCTION__));
6837 case BCM4315_D11DUAL_ID: /* 4315 802.11a/g id */
6838 case BCM4315_D11G_ID: /* 4315 802.11g id */
6839 case BCM4315_D11A_ID: /* 4315 802.11a id */
6840 DHD_INFO(("%s: found 4315 Dongle\n", __FUNCTION__));
6842 case BCM4319_D11N_ID: /* 4319 802.11n id */
6843 case BCM4319_D11N2G_ID: /* 4319 802.11n2g id */
6844 case BCM4319_D11N5G_ID: /* 4319 802.11n5g id */
6845 DHD_INFO(("%s: found 4319 Dongle\n", __FUNCTION__));
6848 DHD_INFO(("%s: allow device id 0, will check chip internals\n",
6853 DHD_ERROR(("%s: skipping 0x%04x/0x%04x, not a dongle\n",
6854 __FUNCTION__, venid, devid));
6859 DHD_ERROR(("%s: osh is NULL!\n", __FUNCTION__));
6863 /* Allocate private bus interface state */
6864 if (!(bus = MALLOC(osh, sizeof(dhd_bus_t)))) {
6865 DHD_ERROR(("%s: MALLOC of dhd_bus_t failed\n", __FUNCTION__));
6868 bzero(bus, sizeof(dhd_bus_t));
6870 bus->cl_devid = (uint16)devid;
6872 bus->bus_num = bus_no;
6873 bus->slot_num = slot;
6874 bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1;
6875 bus->usebufpool = FALSE; /* Use bufpool if allocated, else use locally malloced rxbuf */
6877 /* attempt to attach to the dongle */
6878 if (!(dhdsdio_probe_attach(bus, osh, sdh, regsva, devid))) {
6879 DHD_ERROR(("%s: dhdsdio_probe_attach failed\n", __FUNCTION__));
6883 #ifdef PROP_TXSTATUS
6884 // terence 20131215: disable_proptx should be set before dhd_attach
6885 if ((bus->sih->chip == BCM43362_CHIP_ID) || (bus->sih->chip == BCM4330_CHIP_ID)) {
6886 printf("%s: Disable prop_txstatus\n", __FUNCTION__);
6891 /* Attach to the dhd/OS/network interface */
6892 if (!(bus->dhd = dhd_attach(osh, bus, SDPCM_RESERVE))) {
6893 DHD_ERROR(("%s: dhd_attach failed\n", __FUNCTION__));
6897 /* Allocate buffers */
6898 if (!(dhdsdio_probe_malloc(bus, osh, sdh))) {
6899 DHD_ERROR(("%s: dhdsdio_probe_malloc failed\n", __FUNCTION__));
6903 if (!(dhdsdio_probe_init(bus, osh, sdh))) {
6904 DHD_ERROR(("%s: dhdsdio_probe_init failed\n", __FUNCTION__));
6909 /* Register interrupt callback, but mask it (not operational yet). */
6910 DHD_INTR(("%s: disable SDIO interrupts (not interested yet)\n", __FUNCTION__));
6911 bcmsdh_intr_disable(sdh);
6912 if ((ret = bcmsdh_intr_reg(sdh, dhdsdio_isr, bus)) != 0) {
6913 DHD_ERROR(("%s: FAILED: bcmsdh_intr_reg returned %d\n",
6914 __FUNCTION__, ret));
6917 DHD_INTR(("%s: registered SDIO interrupt function ok\n", __FUNCTION__));
6919 DHD_INFO(("%s: SDIO interrupt function is NOT registered due to polling mode\n",
6923 DHD_INFO(("%s: completed!!\n", __FUNCTION__));
6925 /* if firmware path present try to download and bring up bus */
6926 bus->dhd->hang_report = TRUE;
6927 if (dhd_download_fw_on_driverload) {
6928 if ((ret = dhd_bus_start(bus->dhd)) != 0) {
6929 DHD_ERROR(("%s: dhd_bus_start failed\n", __FUNCTION__));
6933 /* Ok, have the per-port tell the stack we're open for business */
6934 if (dhd_register_if(bus->dhd, 0, TRUE) != 0) {
6935 DHD_ERROR(("%s: Net attach failed!!\n", __FUNCTION__));
6940 #if defined(MULTIPLE_SUPPLICANT)
6941 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
6942 mutex_unlock(&_dhd_sdio_mutex_lock_);
6943 DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__));
6944 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
6947 init_waitqueue_head(&bus->bus_sleep);
6952 dhdsdio_release(bus, osh);
6955 #if defined(MULTIPLE_SUPPLICANT)
6956 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
6957 mutex_unlock(&_dhd_sdio_mutex_lock_);
6958 DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__));
6959 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
6965 #ifdef REGON_BP_HANG_FIX
6966 static int dhd_sdio_backplane_reset(struct dhd_bus *bus)
6969 DHD_ERROR(("Resetting the backplane to avoid failure in firmware download..\n"));
6971 temp = bcmsdh_reg_read(bus->sdh, 0x180021e0, 4);
6972 DHD_INFO(("SDIO Clk Control Reg = %x\n", temp));
6974 /* Force HT req from PMU */
6975 bcmsdh_reg_write(bus->sdh, 0x18000644, 4, 0x6000005);
6977 /* Increase the clock stretch duration. */
6978 bcmsdh_reg_write(bus->sdh, 0x18000630, 4, 0xC8FFC8);
6980 /* Setting ALP clock request in SDIOD clock control status register */
6981 bcmsdh_reg_write(bus->sdh, 0x180021e0, 4, 0x41);
6983 /* Allowing clock from SR engine to SR memory */
6984 bcmsdh_reg_write(bus->sdh, 0x18004400, 4, 0xf92f1);
6985 /* Disabling SR Engine before SR binary download. */
6986 bcmsdh_reg_write(bus->sdh, 0x18000650, 4, 0x3);
6987 bcmsdh_reg_write(bus->sdh, 0x18000654, 4, 0x0);
6989 /* Enabling clock from backplane to SR memory */
6990 bcmsdh_reg_write(bus->sdh, 0x18004400, 4, 0xf9af1);
6992 /* Initializing SR memory address register in SOCRAM */
6993 bcmsdh_reg_write(bus->sdh, 0x18004408, 4, 0x0);
6995 /* Downloading the SR binary */
6996 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
6997 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
6998 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
6999 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7000 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7001 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7002 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7003 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0xc0002000);
7004 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7005 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7006 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7007 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7008 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7009 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7010 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7011 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7012 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7013 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7014 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7015 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7016 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7017 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7018 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7019 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7020 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7021 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7022 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7023 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7024 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7025 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 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, 0x80008000);
7029 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x1051f080);
7030 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x80008000);
7031 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x1050f080);
7032 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x80008000);
7033 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x1050f080);
7034 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x80008000);
7035 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x1050f080);
7036 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000004);
7037 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
7038 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000604);
7039 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
7040 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00001604);
7041 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
7042 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00001404);
7043 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a08c80);
7044 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010001);
7045 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x14a00000);
7046 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00011404);
7047 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
7048 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00002000);
7049 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x04a00000);
7050 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00002000);
7051 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0xf8000000);
7052 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00002000);
7053 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x04a00000);
7054 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00002000);
7055 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0xf8000000);
7056 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00011604);
7057 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
7058 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010604);
7059 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
7060 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010004);
7061 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
7062 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010000);
7063 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x14a00000);
7064 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000004);
7065 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
7066 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010001);
7067 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x14a00000);
7068 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010004);
7069 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
7070 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010000);
7071 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
7072 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010000);
7073 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x14a00000);
7074 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7075 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
7076 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000008);
7077 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x04a00000);
7078 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000008);
7079 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0xfc000000);
7080 /* SR Binary Download complete */
7082 /* Allowing clock from SR engine to SR memory */
7083 bcmsdh_reg_write(bus->sdh, 0x18004400, 4, 0xf92f1);
7085 /* Turning ON SR Engine to initiate backplane reset Repeated ?? Maharana */
7086 bcmsdh_reg_write(bus->sdh, 0x18000650, 4, 0x3);
7087 bcmsdh_reg_write(bus->sdh, 0x18000654, 4, 0x0);
7088 bcmsdh_reg_write(bus->sdh, 0x18000650, 4, 0x3);
7089 bcmsdh_reg_write(bus->sdh, 0x18000654, 4, 0x2);
7090 bcmsdh_reg_write(bus->sdh, 0x18000650, 4, 0x3);
7091 bcmsdh_reg_write(bus->sdh, 0x18000654, 4, 0x3);
7092 bcmsdh_reg_write(bus->sdh, 0x18000650, 4, 0x3);
7093 bcmsdh_reg_write(bus->sdh, 0x18000654, 4, 0x37);
7094 bcmsdh_reg_write(bus->sdh, 0x18000650, 4, 0x3);
7095 temp = bcmsdh_reg_read(bus->sdh, 0x18000654, 4);
7096 DHD_INFO(("0x18000654 = %x\n", temp));
7097 bcmsdh_reg_write(bus->sdh, 0x18000654, 4, 0x800037);
7099 /* Rolling back the original values for clock stretch and PMU timers */
7100 bcmsdh_reg_write(bus->sdh, 0x18000644, 4, 0x0);
7101 bcmsdh_reg_write(bus->sdh, 0x18000630, 4, 0xC800C8);
7102 /* Removing ALP clock request in SDIOD clock control status register */
7103 bcmsdh_reg_write(bus->sdh, 0x180021e0, 4, 0x40);
7108 static int dhdsdio_sdio_hang_war(struct dhd_bus *bus)
7110 uint32 temp = 0, temp2 = 0, counter = 0, BT_pwr_up = 0, BT_ready = 0;
7111 /* Removing reset of D11 Core */
7112 bcmsdh_reg_write(bus->sdh, 0x18101408, 4, 0x3);
7113 bcmsdh_reg_write(bus->sdh, 0x18101800, 4, 0x0);
7114 bcmsdh_reg_write(bus->sdh, 0x18101408, 4, 0x1);
7115 /* Reading CLB XTAL BT cntrl register */
7116 bcmsdh_reg_write(bus->sdh, 0x180013D8, 2, 0xD1);
7117 bcmsdh_reg_write(bus->sdh, 0x180013DA, 2, 0x12);
7118 bcmsdh_reg_write(bus->sdh, 0x180013D8, 2, 0x2D0);
7119 /* Read if BT is powered up */
7120 temp = bcmsdh_reg_read(bus->sdh, 0x180013DA, 2);
7121 /* Read BT_ready from WLAN wireless register */
7122 temp2 = bcmsdh_reg_read(bus->sdh, 0x1800002C, 4);
7124 Check if the BT is powered up and ready. The duration between BT being powered up
7125 and BT becoming ready is the problematic window for WLAN. If we move ahead at this
7126 time then we may encounter a corrupted backplane later. So we wait for BT to be ready
7127 and then proceed after checking the health of the backplane. If the backplane shows
7128 indications of failure then we have to do a full reset of the backplane using SR engine
7131 (temp & 0xF0) ? (BT_pwr_up = 1):(BT_pwr_up = 0);
7132 (temp2 & (1<<17)) ? (BT_ready = 1):(BT_ready = 0);
7133 DHD_ERROR(("WARNING: Checking if BT is ready BT_pwr_up = %x"
7134 "BT_ready = %x \n", BT_pwr_up, BT_ready));
7135 while (BT_pwr_up && !BT_ready)
7138 bcmsdh_reg_write(bus->sdh, 0x180013D8, 2, 0x2D0);
7139 temp = bcmsdh_reg_read(bus->sdh, 0x180013DA, 2);
7140 temp2 = bcmsdh_reg_read(bus->sdh, 0x1800002C, 4);
7141 (temp & 0xF0) ? (BT_pwr_up = 1):(BT_pwr_up = 0);
7142 (temp2 & (1<<17)) ? (BT_ready = 1):(BT_ready = 0);
7144 if (counter == 5000)
7146 DHD_ERROR(("WARNING: Going ahead after 5 secs with"
7147 "risk of failure because BT ready is not yet set\n"));
7151 DHD_ERROR(("\nWARNING: WL Proceeding BT_pwr_up = %x BT_ready = %x"
7152 "\n", BT_pwr_up, BT_ready));
7156 Get the information of who accessed the crucial backplane entities
7157 by reading read and write access registers
7159 DHD_TRACE(("%d: Read Value @ 0x18104808 = %x."
7160 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18104808, 4)));
7161 DHD_TRACE(("%d: Read Value @ 0x1810480C = %x."
7162 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810480C, 4)));
7163 DHD_TRACE(("%d: Read Value @ 0x18106808 = %x."
7164 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18106808, 4)));
7165 DHD_TRACE(("%d: Read Value @ 0x1810680C = %x."
7166 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810680C, 4)));
7167 DHD_TRACE(("%d: Read Value @ 0x18107808 = %x."
7168 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18107808, 4)));
7169 DHD_TRACE(("%d: Read Value @ 0x1810780C = %x."
7170 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810780C, 4)));
7171 DHD_TRACE(("%d: Read Value @ 0x18108808 = %x."
7172 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18108808, 4)));
7173 DHD_TRACE(("%d: Read Value @ 0x1810880C = %x."
7174 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810880C, 4)));
7175 DHD_TRACE(("%d: Read Value @ 0x18109808 = %x."
7176 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18109808, 4)));
7177 DHD_TRACE(("%d: Read Value @ 0x1810980C = %x."
7178 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810980C, 4)));
7179 DHD_TRACE(("%d: Read Value @ 0x1810C808 = %x."
7180 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810c808, 4)));
7181 DHD_TRACE(("%d: Read Value @ 0x1810C80C = %x."
7182 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810c80C, 4)));
7184 while ((bcmsdh_reg_read(bus->sdh, 0x18104808, 4) == 5) ||
7185 (bcmsdh_reg_read(bus->sdh, 0x1810480C, 4) == 5) ||
7186 (bcmsdh_reg_read(bus->sdh, 0x18106808, 4) == 5) ||
7187 (bcmsdh_reg_read(bus->sdh, 0x1810680C, 4) == 5) ||
7188 (bcmsdh_reg_read(bus->sdh, 0x1810780C, 4) == 5) ||
7189 (bcmsdh_reg_read(bus->sdh, 0x1810780C, 4) == 5) ||
7190 (bcmsdh_reg_read(bus->sdh, 0x1810880C, 4) == 5) ||
7191 (bcmsdh_reg_read(bus->sdh, 0x1810880C, 4) == 5) ||
7192 (bcmsdh_reg_read(bus->sdh, 0x1810980C, 4) == 5) ||
7193 (bcmsdh_reg_read(bus->sdh, 0x1810980C, 4) == 5) ||
7194 (bcmsdh_reg_read(bus->sdh, 0x1810C80C, 4) == 5) ||
7195 (bcmsdh_reg_read(bus->sdh, 0x1810C80C, 4) == 5))
7199 DHD_ERROR(("Unable to recover the backkplane corruption"
7200 "..Tried %d times.. Exiting\n", counter));
7204 dhd_sdio_backplane_reset(bus);
7206 Get the information of who accessed the crucial backplane
7207 entities by reading read and write access registers
7209 DHD_ERROR(("%d: Read Value @ 0x18104808 = %x."
7210 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18104808, 4)));
7211 DHD_ERROR(("%d: Read Value @ 0x1810480C = %x."
7212 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810480C, 4)));
7213 DHD_ERROR(("%d: Read Value @ 0x18106808 = %x."
7214 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18106808, 4)));
7215 DHD_ERROR(("%d: Read Value @ 0x1810680C = %x."
7216 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810680C, 4)));
7217 DHD_ERROR(("%d: Read Value @ 0x18107808 = %x."
7218 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18107808, 4)));
7219 DHD_ERROR(("%d: Read Value @ 0x1810780C = %x."
7220 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810780C, 4)));
7221 DHD_ERROR(("%d: Read Value @ 0x18108808 = %x."
7222 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18108808, 4)));
7223 DHD_ERROR(("%d: Read Value @ 0x1810880C = %x."
7224 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810880C, 4)));
7225 DHD_ERROR(("%d: Read Value @ 0x18109808 = %x."
7226 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18109808, 4)));
7227 DHD_ERROR(("%d: Read Value @ 0x1810980C = %x."
7228 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810980C, 4)));
7229 DHD_ERROR(("%d: Read Value @ 0x1810C808 = %x."
7230 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810c808, 4)));
7231 DHD_ERROR(("%d: Read Value @ 0x1810C80C = %x."
7232 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810c80C, 4)));
7234 /* Set the WL ready to indicate BT that we are done with backplane reset */
7235 DHD_ERROR(("Setting up AXI_OK\n"));
7236 bcmsdh_reg_write(bus->sdh, 0x18000658, 4, 0x3);
7237 temp = bcmsdh_reg_read(bus->sdh, 0x1800065c, 4);
7239 bcmsdh_reg_write(bus->sdh, 0x1800065c, 4, temp);
7242 #endif /* REGON_BP_HANG_FIX */
7244 dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva,
7250 bus->alp_only = TRUE;
7253 /* Return the window to backplane enumeration space for core access */
7254 if (dhdsdio_set_siaddr_window(bus, SI_ENUM_BASE)) {
7255 DHD_ERROR(("%s: FAILED to return to SI_ENUM_BASE\n", __FUNCTION__));
7258 #if defined(DHD_DEBUG)
7259 DHD_ERROR(("F1 signature read @0x18000000=0x%4x\n",
7260 bcmsdh_reg_read(bus->sdh, SI_ENUM_BASE, 4)));
7264 /* Force PLL off until si_attach() programs PLL control regs */
7268 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, DHD_INIT_CLKCTL1, &err);
7270 clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
7272 if (err || ((clkctl & ~SBSDIO_AVBITS) != DHD_INIT_CLKCTL1)) {
7273 DHD_ERROR(("dhdsdio_probe: ChipClkCSR access: err %d wrote 0x%02x read 0x%02x\n",
7274 err, DHD_INIT_CLKCTL1, clkctl));
7279 if (DHD_INFO_ON()) {
7281 uint8 *cis[SDIOD_MAX_IOFUNCS];
7284 numfn = bcmsdh_query_iofnum(sdh);
7285 ASSERT(numfn <= SDIOD_MAX_IOFUNCS);
7287 /* Make sure ALP is available before trying to read CIS */
7288 SPINWAIT(((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
7289 SBSDIO_FUNC1_CHIPCLKCSR, NULL)),
7290 !SBSDIO_ALPAV(clkctl)), PMU_MAX_TRANSITION_DLY);
7292 /* Now request ALP be put on the bus */
7293 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
7294 DHD_INIT_CLKCTL2, &err);
7297 for (fn = 0; fn <= numfn; fn++) {
7298 if (!(cis[fn] = MALLOC(osh, SBSDIO_CIS_SIZE_LIMIT))) {
7299 DHD_INFO(("dhdsdio_probe: fn %d cis malloc failed\n", fn));
7302 bzero(cis[fn], SBSDIO_CIS_SIZE_LIMIT);
7304 if ((err = bcmsdh_cis_read(sdh, fn, cis[fn], SBSDIO_CIS_SIZE_LIMIT))) {
7305 DHD_INFO(("dhdsdio_probe: fn %d cis read err %d\n", fn, err));
7306 MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT);
7309 dhd_dump_cis(fn, cis[fn]);
7314 MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT);
7318 DHD_ERROR(("dhdsdio_probe: failure reading or parsing CIS\n"));
7322 #endif /* DHD_DEBUG */
7324 /* si_attach() will provide an SI handle and scan the backplane */
7325 if (!(bus->sih = si_attach((uint)devid, osh, regsva, DHD_BUS, sdh,
7326 &bus->vars, &bus->varsz))) {
7327 DHD_ERROR(("%s: si_attach failed!\n", __FUNCTION__));
7332 DHD_ERROR(("F1 signature OK, socitype:0x%x chip:0x%4x rev:0x%x pkg:0x%x\n",
7333 bus->sih->socitype, bus->sih->chip, bus->sih->chiprev, bus->sih->chippkg));
7334 #endif /* DHD_DEBUG */
7336 #ifdef REGON_BP_HANG_FIX
7337 /* WAR - for 43241 B0-B1-B2. B3 onwards do not need this */
7338 if (((uint16)bus->sih->chip == BCM4324_CHIP_ID) && (bus->sih->chiprev < 3))
7339 dhdsdio_sdio_hang_war(bus);
7340 #endif /* REGON_BP_HANG_FIX */
7342 bcmsdh_chipinfo(sdh, bus->sih->chip, bus->sih->chiprev);
7344 if (!dhdsdio_chipmatch((uint16)bus->sih->chip)) {
7345 DHD_ERROR(("%s: unsupported chip: 0x%04x\n",
7346 __FUNCTION__, bus->sih->chip));
7350 if (bus->sih->buscorerev >= 12)
7351 dhdsdio_clk_kso_init(bus);
7355 if (CST4330_CHIPMODE_SDIOD(bus->sih->chipst)) {
7358 si_sdiod_drive_strength_init(bus->sih, osh, dhd_sdiod_drive_strength);
7361 /* Get info on the ARM and SOCRAM cores... */
7362 if (!DHD_NOPMU(bus)) {
7363 if ((si_setcore(bus->sih, ARM7S_CORE_ID, 0)) ||
7364 (si_setcore(bus->sih, ARMCM3_CORE_ID, 0)) ||
7365 (si_setcore(bus->sih, ARMCR4_CORE_ID, 0))) {
7366 bus->armrev = si_corerev(bus->sih);
7368 DHD_ERROR(("%s: failed to find ARM core!\n", __FUNCTION__));
7372 if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
7373 if (!(bus->orig_ramsize = si_socram_size(bus->sih))) {
7374 DHD_ERROR(("%s: failed to find SOCRAM memory!\n", __FUNCTION__));
7378 /* cr4 has a different way to find the RAM size from TCM's */
7379 if (!(bus->orig_ramsize = si_tcm_size(bus->sih))) {
7380 DHD_ERROR(("%s: failed to find CR4-TCM memory!\n", __FUNCTION__));
7383 /* also populate base address */
7384 switch ((uint16)bus->sih->chip) {
7385 case BCM4335_CHIP_ID:
7386 case BCM4339_CHIP_ID:
7387 case BCM43349_CHIP_ID:
7388 bus->dongle_ram_base = CR4_4335_RAM_BASE;
7390 case BCM4350_CHIP_ID:
7391 case BCM4354_CHIP_ID:
7392 case BCM4356_CHIP_ID:
7393 case BCM4358_CHIP_ID:
7394 bus->dongle_ram_base = CR4_4350_RAM_BASE;
7396 case BCM4360_CHIP_ID:
7397 bus->dongle_ram_base = CR4_4360_RAM_BASE;
7399 case BCM4345_CHIP_ID:
7400 bus->dongle_ram_base = CR4_4345_RAM_BASE;
7402 case BCM4349_CHIP_GRPID:
7403 bus->dongle_ram_base = CR4_4349_RAM_BASE;
7406 bus->dongle_ram_base = 0;
7407 DHD_ERROR(("%s: WARNING: Using default ram base at 0x%x\n",
7408 __FUNCTION__, bus->dongle_ram_base));
7411 bus->ramsize = bus->orig_ramsize;
7412 if (dhd_dongle_ramsize)
7413 dhd_dongle_setramsize(bus, dhd_dongle_ramsize);
7415 DHD_ERROR(("DHD: dongle ram size is set to %d(orig %d) at 0x%x\n",
7416 bus->ramsize, bus->orig_ramsize, bus->dongle_ram_base));
7418 bus->srmemsize = si_socram_srmem_size(bus->sih);
7421 /* ...but normally deal with the SDPCMDEV core */
7422 if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0)) &&
7423 !(bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0))) {
7424 DHD_ERROR(("%s: failed to find SDIODEV core!\n", __FUNCTION__));
7427 bus->sdpcmrev = si_corerev(bus->sih);
7429 /* Set core control so an SDIO reset does a backplane reset */
7430 OR_REG(osh, &bus->regs->corecontrol, CC_BPRESEN);
7431 bus->rxint_mode = SDIO_DEVICE_HMB_RXINT;
7433 if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev >= 4) &&
7434 (bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_1))
7438 val = R_REG(osh, &bus->regs->corecontrol);
7439 val &= ~CC_XMTDATAAVAIL_MODE;
7440 val |= CC_XMTDATAAVAIL_CTRL;
7441 W_REG(osh, &bus->regs->corecontrol, val);
7445 pktq_init(&bus->txq, (PRIOMASK + 1), QLEN);
7447 /* Locate an appropriately-aligned portion of hdrbuf */
7448 bus->rxhdr = (uint8 *)ROUNDUP((uintptr)&bus->hdrbuf[0], DHD_SDALIGN);
7450 /* Set the poll and/or interrupt flags */
7451 bus->intr = (bool)dhd_intr;
7452 if ((bus->poll = (bool)dhd_poll))
7455 /* Setting default Glom size */
7456 bus->txglomsize = SDPCM_DEFGLOM_SIZE;
7461 if (bus->sih != NULL) {
7462 si_detach(bus->sih);
7469 dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh)
7471 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7473 if (bus->dhd->maxctl) {
7474 bus->rxblen = ROUNDUP((bus->dhd->maxctl+SDPCM_HDRLEN), ALIGNMENT) + DHD_SDALIGN;
7475 if (!(bus->rxbuf = DHD_OS_PREALLOC(bus->dhd, DHD_PREALLOC_RXBUF, bus->rxblen))) {
7476 DHD_ERROR(("%s: MALLOC of %d-byte rxbuf failed\n",
7477 __FUNCTION__, bus->rxblen));
7481 /* Allocate buffer to receive glomed packet */
7482 if (!(bus->databuf = DHD_OS_PREALLOC(bus->dhd, DHD_PREALLOC_DATABUF, MAX_DATA_BUF))) {
7483 DHD_ERROR(("%s: MALLOC of %d-byte databuf failed\n",
7484 __FUNCTION__, MAX_DATA_BUF));
7485 /* release rxbuf which was already located as above */
7487 DHD_OS_PREFREE(bus->dhd, bus->rxbuf, bus->rxblen);
7491 /* Align the buffer */
7492 if ((uintptr)bus->databuf % DHD_SDALIGN)
7493 bus->dataptr = bus->databuf + (DHD_SDALIGN - ((uintptr)bus->databuf % DHD_SDALIGN));
7495 bus->dataptr = bus->databuf;
7504 dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh)
7508 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7510 bus->_srenab = FALSE;
7513 dhdsdio_pktgen_init(bus);
7516 /* Disable F2 to clear any intermediate frame state on the dongle */
7517 bcmsdh_cfg_write(sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL);
7519 bus->dhd->busstate = DHD_BUS_DOWN;
7520 bus->sleeping = FALSE;
7521 bus->rxflow = FALSE;
7522 bus->prev_rxlim_hit = 0;
7524 /* Done with backplane-dependent accesses, can drop clock... */
7525 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
7527 /* ...and initialize clock/power states */
7528 bus->clkstate = CLK_SDONLY;
7529 bus->idletime = (int32)dhd_idletime;
7530 bus->idleclock = DHD_IDLE_ACTIVE;
7532 /* Query the SD clock speed */
7533 if (bcmsdh_iovar_op(sdh, "sd_divisor", NULL, 0,
7534 &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) {
7535 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_divisor"));
7536 bus->sd_divisor = -1;
7538 DHD_INFO(("%s: Initial value for %s is %d\n",
7539 __FUNCTION__, "sd_divisor", bus->sd_divisor));
7542 /* Query the SD bus mode */
7543 if (bcmsdh_iovar_op(sdh, "sd_mode", NULL, 0,
7544 &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) {
7545 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_mode"));
7548 DHD_INFO(("%s: Initial value for %s is %d\n",
7549 __FUNCTION__, "sd_mode", bus->sd_mode));
7552 /* Query the F2 block size, set roundup accordingly */
7554 if (bcmsdh_iovar_op(sdh, "sd_blocksize", &fnum, sizeof(int32),
7555 &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) {
7557 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize"));
7559 DHD_INFO(("%s: Initial value for %s is %d\n",
7560 __FUNCTION__, "sd_blocksize", bus->blocksize));
7562 dhdsdio_tune_fifoparam(bus);
7564 bus->roundup = MIN(max_roundup, bus->blocksize);
7566 #ifdef DHDENABLE_TAILPAD
7568 PKTFREE(osh, bus->pad_pkt, FALSE);
7569 bus->pad_pkt = PKTGET(osh, SDIO_MAX_BLOCK_SIZE, FALSE);
7570 if (bus->pad_pkt == NULL)
7571 DHD_ERROR(("failed to allocate padding packet\n"));
7573 int alignment_offset = 0;
7574 uintptr pktprt = (uintptr)PKTDATA(osh, bus->pad_pkt);
7575 if (!(pktprt&1) && (pktprt = (pktprt % DHD_SDALIGN)))
7576 PKTPUSH(osh, bus->pad_pkt, alignment_offset);
7577 PKTSETNEXT(osh, bus->pad_pkt, NULL);
7579 #endif /* DHDENABLE_TAILPAD */
7581 /* Query if bus module supports packet chaining, default to use if supported */
7582 if (bcmsdh_iovar_op(sdh, "sd_rxchain", NULL, 0,
7583 &bus->sd_rxchain, sizeof(int32), FALSE) != BCME_OK) {
7584 bus->sd_rxchain = FALSE;
7586 DHD_INFO(("%s: bus module (through bcmsdh API) %s chaining\n",
7587 __FUNCTION__, (bus->sd_rxchain ? "supports" : "does not support")));
7589 bus->use_rxchain = (bool)bus->sd_rxchain;
7590 bus->txinrx_thres = CUSTOM_TXINRX_THRES;
7591 /* TX first in dhdsdio_readframes() */
7592 bus->dotxinrx = TRUE;
7598 dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh,
7599 char *pfw_path, char *pnv_path, char *pconf_path)
7603 bus->fw_path = pfw_path;
7604 bus->nv_path = pnv_path;
7605 bus->dhd->conf_path = pconf_path;
7607 ret = dhdsdio_download_firmware(bus, osh, bus->sdh);
7614 dhdsdio_download_firmware(struct dhd_bus *bus, osl_t *osh, void *sdh)
7619 DHD_TRACE_HW4(("%s: firmware path=%s, nvram path=%s\n",
7620 __FUNCTION__, bus->fw_path, bus->nv_path));
7621 DHD_OS_WAKE_LOCK(bus->dhd);
7623 /* Download the firmware */
7624 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
7626 /* External conf takes precedence if specified */
7627 dhd_conf_preinit(bus->dhd);
7628 dhd_conf_read_config(bus->dhd);
7629 dhd_conf_set_fw_name_by_chip(bus->dhd, bus->fw_path);
7630 dhd_conf_set_fw_path(bus->dhd, bus->fw_path);
7631 dhd_conf_set_nv_path(bus->dhd, bus->nv_path);
7632 dhd_conf_set_fw_name_by_mac(bus->dhd, bus->sdh, bus->fw_path);
7633 dhd_conf_set_nv_name_by_mac(bus->dhd, bus->sdh, bus->nv_path);
7635 printk("Final fw_path=%s\n", bus->fw_path);
7636 printk("Final nv_path=%s\n", bus->nv_path);
7637 printk("Final conf_path=%s\n", bus->dhd->conf_path);
7639 ret = _dhdsdio_download_firmware(bus);
7641 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
7643 DHD_OS_WAKE_UNLOCK(bus->dhd);
7647 /* Detach and free everything */
7649 dhdsdio_release(dhd_bus_t *bus, osl_t *osh)
7651 bool dongle_isolation = FALSE;
7652 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7658 dongle_isolation = bus->dhd->dongle_isolation;
7659 dhd_detach(bus->dhd);
7662 /* De-register interrupt handler */
7663 bcmsdh_intr_disable(bus->sdh);
7664 bcmsdh_intr_dereg(bus->sdh);
7667 dhdsdio_release_dongle(bus, osh, dongle_isolation, TRUE);
7672 dhdsdio_release_malloc(bus, osh);
7675 if (bus->console.buf != NULL)
7676 MFREE(osh, bus->console.buf, bus->console.bufsize);
7679 #ifdef DHDENABLE_TAILPAD
7681 PKTFREE(osh, bus->pad_pkt, FALSE);
7682 #endif /* DHDENABLE_TAILPAD */
7684 MFREE(osh, bus, sizeof(dhd_bus_t));
7687 DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
7691 dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh)
7693 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7695 if (bus->dhd && bus->dhd->dongle_reset)
7699 #ifndef CONFIG_DHD_USE_STATIC_BUF
7700 MFREE(osh, bus->rxbuf, bus->rxblen);
7702 bus->rxctl = bus->rxbuf = NULL;
7707 #ifndef CONFIG_DHD_USE_STATIC_BUF
7708 MFREE(osh, bus->databuf, MAX_DATA_BUF);
7710 bus->databuf = NULL;
7713 if (bus->vars && bus->varsz) {
7714 MFREE(osh, bus->vars, bus->varsz);
7722 dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation, bool reset_flag)
7724 DHD_TRACE(("%s: Enter bus->dhd %p bus->dhd->dongle_reset %d \n", __FUNCTION__,
7725 bus->dhd, bus->dhd->dongle_reset));
7727 if ((bus->dhd && bus->dhd->dongle_reset) && reset_flag)
7731 #if !defined(BCMLXSDMMC)
7733 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
7735 if (KSO_ENAB(bus) && (dongle_isolation == FALSE))
7736 si_watchdog(bus->sih, 4);
7737 #endif /* !defined(BCMLXSDMMC) */
7739 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
7741 si_detach(bus->sih);
7743 if (bus->vars && bus->varsz)
7744 MFREE(osh, bus->vars, bus->varsz);
7748 DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
7752 dhdsdio_disconnect(void *ptr)
7754 dhd_bus_t *bus = (dhd_bus_t *)ptr;
7756 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7758 #if defined(MULTIPLE_SUPPLICANT)
7759 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
7760 if (mutex_is_locked(&_dhd_sdio_mutex_lock_) == 0) {
7761 DHD_ERROR(("%s : no mutex held. set lock\n", __FUNCTION__));
7764 DHD_ERROR(("%s : mutex is locked!. wait for unlocking\n", __FUNCTION__));
7766 mutex_lock(&_dhd_sdio_mutex_lock_);
7767 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
7773 dhdsdio_release(bus, bus->dhd->osh);
7776 #if defined(MULTIPLE_SUPPLICANT)
7777 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
7778 mutex_unlock(&_dhd_sdio_mutex_lock_);
7779 DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__));
7780 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
7784 DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
7788 dhdsdio_suspend(void *context)
7792 dhd_bus_t *bus = (dhd_bus_t*)context;
7794 if (bus->idletime > 0) {
7795 wait_time = msecs_to_jiffies(bus->idletime * dhd_watchdog_ms);
7798 ret = dhd_os_check_wakelock(bus->dhd);
7799 // terence 20141124: fix for suspend issue
7800 if (SLPAUTO_ENAB(bus) && (!ret) && (bus->dhd->up)) {
7801 if (wait_event_timeout(bus->bus_sleep, bus->sleeping, wait_time) == 0) {
7802 if (!bus->sleeping) {
7811 dhdsdio_resume(void *context)
7813 #if defined(OOB_INTR_ONLY)
7814 dhd_bus_t *bus = (dhd_bus_t*)context;
7816 if (dhd_os_check_if_up(bus->dhd))
7817 bcmsdh_oob_intr_set(bus->sdh, TRUE);
7823 /* Register/Unregister functions are called by the main DHD entry
7824 * point (e.g. module insertion) to link with the bus driver, in
7825 * order to look for or await the device.
7828 static bcmsdh_driver_t dhd_sdio = {
7836 dhd_bus_register(void)
7838 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7840 return bcmsdh_register(&dhd_sdio);
7844 dhd_bus_unregister(void)
7846 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7848 bcmsdh_unregister();
7851 #if defined(BCMLXSDMMC)
7852 /* Register a dummy SDIO client driver in order to be notified of new SDIO device */
7853 int dhd_bus_reg_sdio_notify(void* semaphore)
7855 return bcmsdh_reg_sdio_notify(semaphore);
7858 void dhd_bus_unreg_sdio_notify(void)
7860 bcmsdh_unreg_sdio_notify();
7862 #endif /* defined(BCMLXSDMMC) */
7864 #ifdef BCMEMBEDIMAGE
7866 dhdsdio_download_code_array(struct dhd_bus *bus)
7870 unsigned char *ularray = NULL;
7872 DHD_INFO(("%s: download embedded firmware...\n", __FUNCTION__));
7874 /* Download image */
7875 while ((offset + MEMBLOCK) < sizeof(dlarray)) {
7877 if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
7878 /* if address is 0, store the reset instruction to be written in 0 */
7881 bus->resetinstr = *(((uint32*)dlarray));
7882 /* Add start of RAM address to the address given by user */
7883 offset += bus->dongle_ram_base;
7887 bcmerror = dhdsdio_membytes(bus, TRUE, offset,
7888 (uint8 *) (dlarray + offset), MEMBLOCK);
7890 DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
7891 __FUNCTION__, bcmerror, MEMBLOCK, offset));
7898 if (offset < sizeof(dlarray)) {
7899 bcmerror = dhdsdio_membytes(bus, TRUE, offset,
7900 (uint8 *) (dlarray + offset), sizeof(dlarray) - offset);
7902 DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
7903 __FUNCTION__, bcmerror, sizeof(dlarray) - offset, offset));
7909 /* Upload and compare the downloaded code */
7911 ularray = MALLOC(bus->dhd->osh, bus->ramsize);
7912 /* Upload image to verify downloaded contents. */
7914 memset(ularray, 0xaa, bus->ramsize);
7915 while ((offset + MEMBLOCK) < sizeof(dlarray)) {
7916 bcmerror = dhdsdio_membytes(bus, FALSE, offset, ularray + offset, MEMBLOCK);
7918 DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n",
7919 __FUNCTION__, bcmerror, MEMBLOCK, offset));
7926 if (offset < sizeof(dlarray)) {
7927 bcmerror = dhdsdio_membytes(bus, FALSE, offset,
7928 ularray + offset, sizeof(dlarray) - offset);
7930 DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n",
7931 __FUNCTION__, bcmerror, sizeof(dlarray) - offset, offset));
7936 if (memcmp(dlarray, ularray, sizeof(dlarray))) {
7937 DHD_ERROR(("%s: Downloaded image is corrupted (%s, %s, %s).\n",
7938 __FUNCTION__, dlimagename, dlimagever, dlimagedate));
7941 DHD_ERROR(("%s: Download, Upload and compare succeeded (%s, %s, %s).\n",
7942 __FUNCTION__, dlimagename, dlimagever, dlimagedate));
7945 #endif /* DHD_DEBUG */
7949 MFREE(bus->dhd->osh, ularray, bus->ramsize);
7952 #endif /* BCMEMBEDIMAGE */
7955 dhdsdio_download_code_file(struct dhd_bus *bus, char *pfw_path)
7961 uint8 *memblock = NULL, *memptr;
7962 uint8 *memptr_tmp = NULL; // terence: check downloaded firmware is correct
7964 DHD_INFO(("%s: download firmware %s\n", __FUNCTION__, pfw_path));
7966 image = dhd_os_open_image(pfw_path);
7967 if (image == NULL) {
7968 printk("%s: Open firmware file failed %s\n", __FUNCTION__, pfw_path);
7972 memptr = memblock = MALLOC(bus->dhd->osh, MEMBLOCK + DHD_SDALIGN);
7973 if (memblock == NULL) {
7974 DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, MEMBLOCK));
7977 if (dhd_msg_level & DHD_TRACE_VAL) {
7978 memptr_tmp = MALLOC(bus->dhd->osh, MEMBLOCK + DHD_SDALIGN);
7979 if (memptr_tmp == NULL) {
7980 DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, MEMBLOCK));
7984 if ((uint32)(uintptr)memblock % DHD_SDALIGN)
7985 memptr += (DHD_SDALIGN - ((uint32)(uintptr)memblock % DHD_SDALIGN));
7987 /* Download image */
7988 while ((len = dhd_os_get_image_block((char*)memptr, MEMBLOCK, image))) {
7990 DHD_ERROR(("%s: dhd_os_get_image_block failed (%d)\n", __FUNCTION__, len));
7991 bcmerror = BCME_ERROR;
7995 if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
7996 /* if address is 0, store the reset instruction to be written in 0 */
7999 bus->resetinstr = *(((uint32*)memptr));
8000 /* Add start of RAM address to the address given by user */
8001 offset += bus->dongle_ram_base;
8005 bcmerror = dhdsdio_membytes(bus, TRUE, offset, memptr, len);
8007 DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
8008 __FUNCTION__, bcmerror, MEMBLOCK, offset));
8012 if (dhd_msg_level & DHD_TRACE_VAL) {
8013 bcmerror = dhdsdio_membytes(bus, FALSE, offset, memptr_tmp, len);
8015 DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n",
8016 __FUNCTION__, bcmerror, MEMBLOCK, offset));
8019 if (memcmp(memptr_tmp, memptr, len)) {
8020 DHD_ERROR(("%s: Downloaded image is corrupted.\n", __FUNCTION__));
8023 DHD_INFO(("%s: Download, Upload and compare succeeded.\n", __FUNCTION__));
8030 MFREE(bus->dhd->osh, memblock, MEMBLOCK + DHD_SDALIGN);
8031 if (dhd_msg_level & DHD_TRACE_VAL) {
8033 MFREE(bus->dhd->osh, memptr_tmp, MEMBLOCK + DHD_SDALIGN);
8037 dhd_os_close_image(image);
8043 EXAMPLE: nvram_array
8046 Use carriage return at the end of each assignment, and an empty string with
8047 carriage return at the end of array.
8050 unsigned char nvram_array[] = {"name1=value1\n", "name2=value2\n", "\n"};
8051 Hex values start with 0x, and mac addr format: xx:xx:xx:xx:xx:xx.
8053 Search "EXAMPLE: nvram_array" to see how the array is activated.
8057 dhd_bus_set_nvram_params(struct dhd_bus * bus, const char *nvram_params)
8059 bus->nvram_params = nvram_params;
8063 dhdsdio_download_nvram(struct dhd_bus *bus)
8067 void * image = NULL;
8068 char * memblock = NULL;
8071 bool nvram_file_exists;
8073 pnv_path = bus->nv_path;
8075 nvram_file_exists = ((pnv_path != NULL) && (pnv_path[0] != '\0'));
8076 if (!nvram_file_exists && (bus->nvram_params == NULL))
8079 if (nvram_file_exists) {
8080 image = dhd_os_open_image(pnv_path);
8081 if (image == NULL) {
8082 printk("%s: Open nvram file failed %s\n", __FUNCTION__, pnv_path);
8087 memblock = MALLOC(bus->dhd->osh, MAX_NVRAMBUF_SIZE);
8088 if (memblock == NULL) {
8089 DHD_ERROR(("%s: Failed to allocate memory %d bytes\n",
8090 __FUNCTION__, MAX_NVRAMBUF_SIZE));
8094 /* Download variables */
8095 if (nvram_file_exists) {
8096 len = dhd_os_get_image_block(memblock, MAX_NVRAMBUF_SIZE, image);
8099 len = strlen(bus->nvram_params);
8100 ASSERT(len <= MAX_NVRAMBUF_SIZE);
8101 memcpy(memblock, bus->nvram_params, len);
8103 if (len > 0 && len < MAX_NVRAMBUF_SIZE) {
8104 bufp = (char *)memblock;
8106 len = process_nvram_vars(bufp, len);
8108 len += 4 - (len % 4);
8113 bcmerror = dhdsdio_downloadvars(bus, memblock, len + 1);
8115 DHD_ERROR(("%s: error downloading vars: %d\n",
8116 __FUNCTION__, bcmerror));
8120 DHD_ERROR(("%s: error reading nvram file: %d\n",
8121 __FUNCTION__, len));
8122 bcmerror = BCME_SDIO_ERROR;
8127 MFREE(bus->dhd->osh, memblock, MAX_NVRAMBUF_SIZE);
8130 dhd_os_close_image(image);
8136 _dhdsdio_download_firmware(struct dhd_bus *bus)
8140 bool embed = FALSE; /* download embedded firmware */
8141 bool dlok = FALSE; /* download firmware succeeded */
8143 /* Out immediately if no image to download */
8144 if ((bus->fw_path == NULL) || (bus->fw_path[0] == '\0')) {
8145 #ifdef BCMEMBEDIMAGE
8152 /* Keep arm in reset */
8153 if (dhdsdio_download_state(bus, TRUE)) {
8154 DHD_ERROR(("%s: error placing ARM core in reset\n", __FUNCTION__));
8158 /* External image takes precedence if specified */
8159 if ((bus->fw_path != NULL) && (bus->fw_path[0] != '\0')) {
8160 if (dhdsdio_download_code_file(bus, bus->fw_path)) {
8161 DHD_ERROR(("%s: dongle image file download failed\n", __FUNCTION__));
8162 #ifdef BCMEMBEDIMAGE
8174 #ifdef BCMEMBEDIMAGE
8176 if (dhdsdio_download_code_array(bus)) {
8177 DHD_ERROR(("%s: dongle image array download failed\n", __FUNCTION__));
8185 BCM_REFERENCE(embed);
8188 DHD_ERROR(("%s: dongle image download failed\n", __FUNCTION__));
8192 /* EXAMPLE: nvram_array */
8193 /* If a valid nvram_arry is specified as above, it can be passed down to dongle */
8194 /* dhd_bus_set_nvram_params(bus, (char *)&nvram_array); */
8196 /* External nvram takes precedence if specified */
8197 if (dhdsdio_download_nvram(bus)) {
8198 DHD_ERROR(("%s: dongle nvram file download failed\n", __FUNCTION__));
8202 /* Take arm out of reset */
8203 if (dhdsdio_download_state(bus, FALSE)) {
8204 DHD_ERROR(("%s: error getting out of ARM core reset\n", __FUNCTION__));
8215 dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes,
8216 void *pkt, bcmsdh_cmplt_fn_t complete, void *handle)
8220 if (!KSO_ENAB(bus)) {
8221 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
8222 return BCME_NODEVICE;
8225 status = bcmsdh_recv_buf(bus->sdh, addr, fn, flags, buf, nbytes, pkt, complete, handle);
8231 dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes,
8232 void *pkt, bcmsdh_cmplt_fn_t complete, void *handle, int max_retry)
8239 if (!KSO_ENAB(bus)) {
8240 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
8241 return BCME_NODEVICE;
8246 ret = bcmsdh_send_buf(bus->sdh, addr, fn, flags, buf, nbytes,
8247 pkt, complete, handle);
8250 ASSERT(ret != BCME_PENDING);
8252 if (ret == BCME_NODEVICE) {
8253 DHD_ERROR(("%s: Device asleep already\n", __FUNCTION__));
8254 } else if (ret < 0) {
8255 /* On failure, abort the command and terminate the frame */
8256 DHD_ERROR(("%s: sdio error %d, abort command and terminate frame.\n",
8257 __FUNCTION__, ret));
8260 bus->dhd->tx_errors++;
8261 bcmsdh_abort(sdh, SDIO_FUNC_2);
8262 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
8264 for (i = 0; i < READ_FRM_CNT_RETRIES; i++) {
8266 hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WFRAMEBCHI,
8268 lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WFRAMEBCLO,
8270 bus->f1regdata += 2;
8271 if ((hi == 0) && (lo == 0))
8275 } while ((ret < 0) && retrydata && ++retries < max_retry);
8281 dhd_bus_chip(struct dhd_bus *bus)
8283 ASSERT(bus->sih != NULL);
8284 return bus->sih->chip;
8288 dhd_bus_chiprev(struct dhd_bus *bus)
8291 ASSERT(bus->sih != NULL);
8292 return bus->sih->chiprev;
8296 dhd_bus_pub(struct dhd_bus *bus)
8302 dhd_bus_sih(struct dhd_bus *bus)
8304 return (void *)bus->sih;
8308 dhd_bus_txq(struct dhd_bus *bus)
8314 dhd_bus_hdrlen(struct dhd_bus *bus)
8316 return (bus->txglom_enable) ? SDPCM_HDRLEN_TXGLOM : SDPCM_HDRLEN;
8320 dhd_bus_set_dotxinrx(struct dhd_bus *bus, bool val)
8322 bus->dotxinrx = val;
8326 dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag)
8334 if (!bus->dhd->dongle_reset) {
8335 dhd_os_sdlock(dhdp);
8336 dhd_os_wd_timer(dhdp, 0);
8337 #if !defined(IGNORE_ETH0_DOWN)
8338 /* Force flow control as protection when stop come before ifconfig_down */
8339 dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON);
8340 #endif /* !defined(IGNORE_ETH0_DOWN) */
8341 /* Expect app to have torn down any connection before calling */
8342 /* Stop the bus, disable F2 */
8343 dhd_bus_stop(bus, FALSE);
8345 #if defined(OOB_INTR_ONLY)
8346 /* Clean up any pending IRQ */
8347 dhd_enable_oob_intr(bus, FALSE);
8348 bcmsdh_oob_intr_set(bus->sdh, FALSE);
8349 bcmsdh_oob_intr_unregister(bus->sdh);
8352 /* Clean tx/rx buffer pointers, detach from the dongle */
8353 dhdsdio_release_dongle(bus, bus->dhd->osh, TRUE, TRUE);
8355 bus->dhd->dongle_reset = TRUE;
8356 bus->dhd->up = FALSE;
8357 dhd_txglom_enable(dhdp, FALSE);
8358 dhd_os_sdunlock(dhdp);
8360 printk("%s: WLAN OFF DONE\n", __FUNCTION__);
8361 /* App can now remove power from device */
8363 bcmerror = BCME_SDIO_ERROR;
8365 /* App must have restored power to device before calling */
8367 printk("\n\n%s: == WLAN ON ==\n", __FUNCTION__);
8369 if (bus->dhd->dongle_reset) {
8371 dhd_os_sdlock(dhdp);
8372 /* Reset SD client */
8373 bcmsdh_reset(bus->sdh);
8375 /* Attempt to re-attach & download */
8376 if (dhdsdio_probe_attach(bus, bus->dhd->osh, bus->sdh,
8377 (uint32 *)SI_ENUM_BASE,
8379 /* Attempt to download binary to the dongle */
8380 if (dhdsdio_probe_init(bus, bus->dhd->osh, bus->sdh) &&
8381 dhdsdio_download_firmware(bus, bus->dhd->osh, bus->sdh) >= 0) {
8383 /* Re-init bus, enable F2 transfer */
8384 bcmerror = dhd_bus_init((dhd_pub_t *) bus->dhd, FALSE);
8385 if (bcmerror == BCME_OK) {
8386 #if defined(OOB_INTR_ONLY)
8387 dhd_enable_oob_intr(bus, TRUE);
8388 bcmsdh_oob_intr_register(bus->sdh,
8390 bcmsdh_oob_intr_set(bus->sdh, TRUE);
8393 bus->dhd->dongle_reset = FALSE;
8394 bus->dhd->up = TRUE;
8396 #if !defined(IGNORE_ETH0_DOWN)
8397 /* Restore flow control */
8398 dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF);
8400 dhd_os_wd_timer(dhdp, dhd_watchdog_ms);
8402 DHD_TRACE(("%s: WLAN ON DONE\n", __FUNCTION__));
8404 dhd_bus_stop(bus, FALSE);
8405 dhdsdio_release_dongle(bus, bus->dhd->osh,
8409 bcmerror = BCME_SDIO_ERROR;
8411 bcmerror = BCME_SDIO_ERROR;
8413 dhd_os_sdunlock(dhdp);
8415 bcmerror = BCME_SDIO_ERROR;
8416 printk("%s called when dongle is not in reset\n",
8418 printk("Will call dhd_bus_start instead\n");
8419 dhd_bus_resume(dhdp, 1);
8421 dhd_conf_set_hw_oob_intr(bus->sdh, bus->sih->chip); // terence 20120615: fix for OOB initial issue
8423 if ((bcmerror = dhd_bus_start(dhdp)) != 0)
8424 DHD_ERROR(("%s: dhd_bus_start fail with %d\n",
8425 __FUNCTION__, bcmerror));
8431 int dhd_bus_suspend(dhd_pub_t *dhdpub)
8433 return bcmsdh_stop(dhdpub->bus->sdh);
8436 int dhd_bus_resume(dhd_pub_t *dhdpub, int stage)
8438 return bcmsdh_start(dhdpub->bus->sdh, stage);
8441 /* Get Chip ID version */
8442 uint dhd_bus_chip_id(dhd_pub_t *dhdp)
8444 dhd_bus_t *bus = dhdp->bus;
8446 if (bus && bus->sih)
8447 return bus->sih->chip;
8452 /* Get Chip Rev ID version */
8453 uint dhd_bus_chiprev_id(dhd_pub_t *dhdp)
8455 dhd_bus_t *bus = dhdp->bus;
8457 if (bus && bus->sih)
8458 return bus->sih->chiprev;
8463 /* Get Chip Pkg ID version */
8464 uint dhd_bus_chippkg_id(dhd_pub_t *dhdp)
8466 dhd_bus_t *bus = dhdp->bus;
8468 return bus->sih->chippkg;
8471 int dhd_bus_get_ids(struct dhd_bus *bus, uint32 *bus_type, uint32 *bus_num, uint32 *slot_num)
8473 *bus_type = bus->bus;
8474 *bus_num = bus->bus_num;
8475 *slot_num = bus->slot_num;
8480 dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint size)
8485 return dhdsdio_membytes(bus, set, address, data, size);
8488 #if defined(NDISVER) && (NDISVER >= 0x0630)
8490 dhd_bus_reject_ioreqs(dhd_pub_t *dhdp, bool reject)
8493 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
8495 bcmsdh_reject_ioreqs(dhdp->bus->sdh, reject);
8499 dhd_bus_waitfor_iodrain(dhd_pub_t *dhdp)
8502 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
8504 bcmsdh_waitfor_iodrain(dhdp->bus->sdh);
8506 #endif /* (NDISVER) && (NDISVER >= 0x0630) */
8509 dhd_bus_update_fw_nv_path(struct dhd_bus *bus, char *pfw_path, char *pnv_path, char *pconf_path)
8511 bus->fw_path = pfw_path;
8512 bus->nv_path = pnv_path;
8513 bus->dhd->conf_path = pconf_path;
8517 dhd_enableOOB(dhd_pub_t *dhd, bool sleep)
8519 dhd_bus_t *bus = dhd->bus;
8520 sdpcmd_regs_t *regs = bus->regs;
8524 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
8525 /* Tell device to start using OOB wakeup */
8526 W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries);
8527 if (retries > retry_limit) {
8528 DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
8531 /* Turn off our contribution to the HT clock request */
8532 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
8534 /* Make sure the controller has the bus up */
8535 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
8537 /* Send misc interrupt to indicate OOB not needed */
8538 W_SDREG(0, ®s->tosbmailboxdata, retries);
8539 if (retries <= retry_limit)
8540 W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries);
8542 if (retries > retry_limit)
8543 DHD_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n"));
8545 /* Make sure we have SD bus access */
8546 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
8552 dhd_bus_pktq_flush(dhd_pub_t *dhdp)
8554 dhd_bus_t *bus = dhdp->bus;
8555 bool wlfc_enabled = FALSE;
8557 #ifdef PROP_TXSTATUS
8558 wlfc_enabled = (dhd_wlfc_cleanup_txq(dhdp, NULL, 0) != WLFC_UNSUPPORTED);
8560 if (!wlfc_enabled) {
8561 #ifdef DHDTCPACK_SUPPRESS
8562 /* Clean tcp_ack_info_tbl in order to prevent access to flushed pkt,
8563 * when there is a newly coming packet from network stack.
8565 dhd_tcpack_info_tbl_clean(bus->dhd);
8566 #endif /* DHDTCPACK_SUPPRESS */
8567 /* Clear the data packet queues */
8568 pktq_flush(dhdp->osh, &bus->txq, TRUE, NULL, 0);
8574 dhd_sr_config(dhd_pub_t *dhd, bool on)
8576 dhd_bus_t *bus = dhd->bus;
8581 return dhdsdio_clk_devsleep_iovar(bus, on);
8585 dhd_get_chipid(dhd_pub_t *dhd)
8587 dhd_bus_t *bus = dhd->bus;
8589 if (bus && bus->sih)
8590 return (uint16)bus->sih->chip;
8594 #endif /* BCMSDIO */
8597 uint32 dhd_sdio_reg_read(void *h, uint32 addr)
8600 struct dhd_bus *bus = (struct dhd_bus *) h;
8602 dhd_os_sdlock(bus->dhd);
8606 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
8608 rval = bcmsdh_reg_read(bus->sdh, addr, 4);
8610 dhd_os_sdunlock(bus->dhd);
8615 void dhd_sdio_reg_write(void *h, uint32 addr, uint32 val)
8617 struct dhd_bus *bus = (struct dhd_bus *) h;
8619 dhd_os_sdlock(bus->dhd);
8623 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
8625 bcmsdh_reg_write(bus->sdh, addr, 4, val);
8627 dhd_os_sdunlock(bus->dhd);
8629 #endif /* DEBUGGER */
8631 #if defined(SOFTAP_TPUT_ENHANCE)
8632 void dhd_bus_setidletime(dhd_pub_t *dhdp, int idle_time)
8634 if (!dhdp || !dhdp->bus) {
8635 DHD_ERROR(("%s:Bus is Invalid\n", __FUNCTION__));
8638 dhdp->bus->idletime = idle_time;
8641 void dhd_bus_getidletime(dhd_pub_t *dhdp, int* idle_time)
8643 if (!dhdp || !dhdp->bus) {
8644 DHD_ERROR(("%s:Bus is Invalid\n", __FUNCTION__));
8649 DHD_ERROR(("%s:Arg idle_time is NULL\n", __FUNCTION__));
8652 *idle_time = dhdp->bus->idletime;
8654 #endif /* SOFTAP_TPUT_ENHANCE */