2 * DHD Bus Module for SDIO
4 * $Copyright Open Broadcom Corporation$
6 * $Id: dhd_sdio.c 419981 2013-08-23 19:49:45Z $
14 #include BCMEMBEDIMAGE
15 #endif /* BCMEMBEDIMAGE */
19 #include <bcmendian.h>
26 #if defined(DHD_DEBUG)
27 #include <hndrte_armtrap.h>
28 #include <hndrte_cons.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>
52 bool dhd_mp_halting(dhd_pub_t *dhdp);
53 extern void bcmsdh_waitfor_iodrain(void *sdh);
54 extern void bcmsdh_reject_ioreqs(void *sdh, bool reject);
55 extern bool bcmsdh_fatal_error(void *sdh);
57 #ifndef DHDSDIO_MEM_DUMP_FNAME
58 #define DHDSDIO_MEM_DUMP_FNAME "mem_dump"
61 #define QLEN 256 /* bulk rx and tx queue lengths */
62 #define FCHI (QLEN - 10)
63 #define FCLOW (FCHI / 2)
66 #define TXRETRIES 2 /* # of retries for tx frames */
68 #define DHD_RXBOUND 50 /* Default for max rx frames in one scheduling */
72 #define DHD_TXBOUND 20 /* Default for max tx frames in one scheduling */
75 #define DHD_TXMINMAX 1 /* Max tx frames if rx still pending */
77 #define MEMBLOCK 2048 /* Block size used for downloading of dongle image */
78 #define MAX_NVRAMBUF_SIZE 4096 /* max nvram buf size */
79 #define MAX_DATA_BUF (32 * 1024) /* Must be large enough to hold biggest possible glom */
82 #define DHD_FIRSTREAD 32
84 #if !ISPOWEROF2(DHD_FIRSTREAD)
85 #error DHD_FIRSTREAD is not a power of 2!
88 #ifdef BCMSDIOH_TXGLOM
89 /* Total length of TX frame header for dongle protocol */
90 #define SDPCM_HDRLEN (SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN + SDPCM_SWHEADER_LEN)
91 /* Total length of RX frame for dongle protocol */
93 /* Total length of TX frame header for dongle protocol */
94 #define SDPCM_HDRLEN (SDPCM_FRAMETAG_LEN + SDPCM_SWHEADER_LEN)
97 #define SDPCM_HDRLEN_RX (SDPCM_FRAMETAG_LEN + SDPCM_SWHEADER_LEN)
100 #define SDPCM_RESERVE (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN)
102 #define SDPCM_RESERVE (SDPCM_HDRLEN + DHD_SDALIGN)
105 /* Space for header read, limit for data packets */
107 #define MAX_HDR_READ 32
109 #if !ISPOWEROF2(MAX_HDR_READ)
110 #error MAX_HDR_READ is not a power of 2!
113 #define MAX_RX_DATASZ 2048
115 /* Maximum milliseconds to wait for F2 to come up */
116 #define DHD_WAIT_F2RDY 3000
118 /* Bump up limit on waiting for HT to account for first startup;
119 * if the image is doing a CRC calculation before programming the PMU
120 * for HT availability, it could take a couple hundred ms more, so
121 * max out at a 1 second (1000000us).
123 #if (PMU_MAX_TRANSITION_DLY <= 1000000)
124 #undef PMU_MAX_TRANSITION_DLY
125 #define PMU_MAX_TRANSITION_DLY 1000000
128 /* Value for ChipClockCSR during initial setup */
129 #define DHD_INIT_CLKCTL1 (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ)
130 #define DHD_INIT_CLKCTL2 (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP)
132 /* Flags for SDH calls */
133 #define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED)
135 /* Packet free applicable unconditionally for sdio and sdspi. Conditional if
136 * bufpool was present for gspi bus.
138 #define PKTFREE2() if ((bus->bus != SPI_BUS) || bus->usebufpool) \
139 PKTFREE(bus->dhd->osh, pkt, FALSE);
140 DHD_SPINWAIT_SLEEP_INIT(sdioh_spinwait_sleep);
141 #if defined(OOB_INTR_ONLY)
142 extern void bcmsdh_set_irq(int flag);
145 extern void dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success);
146 extern void dhd_wlfc_trigger_pktcommit(dhd_pub_t *dhd);
149 #if defined(MULTIPLE_SUPPLICANT)
150 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
151 DEFINE_MUTEX(_dhd_sdio_mutex_lock_);
152 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
156 /* Device console log buffer state */
157 #define CONSOLE_LINE_MAX 192
158 #define CONSOLE_BUFFER_MAX 2024
159 typedef struct dhd_console {
160 uint count; /* Poll interval msec counter */
161 uint log_addr; /* Log struct address (fixed) */
162 hndrte_log_t log; /* Log struct (host copy) */
163 uint bufsize; /* Size of log buffer */
164 uint8 *buf; /* Log buffer (host copy) */
165 uint last; /* Last buffer read index */
167 #endif /* DHD_DEBUG */
169 #define REMAP_ENAB(bus) ((bus)->remap)
170 #define REMAP_ISADDR(bus, a) (((a) >= ((bus)->orig_ramsize)) && ((a) < ((bus)->ramsize)))
171 #define KSO_ENAB(bus) ((bus)->kso)
172 #define SR_ENAB(bus) ((bus)->_srenab)
173 #define SLPAUTO_ENAB(bus) ((SR_ENAB(bus)) && ((bus)->_slpauto))
174 #define MIN_RSRC_ADDR (SI_ENUM_BASE + 0x618)
175 #define MIN_RSRC_SR 0x3
176 #define CORE_CAPEXT_ADDR (SI_ENUM_BASE + 0x64c)
177 #define CORE_CAPEXT_SR_SUPPORTED_MASK (1 << 1)
178 #define RCTL_MACPHY_DISABLE_MASK (1 << 26)
179 #define RCTL_LOGIC_DISABLE_MASK (1 << 27)
181 #define OOB_WAKEUP_ENAB(bus) ((bus)->_oobwakeup)
182 #define GPIO_DEV_SRSTATE 16 /* Host gpio17 mapped to device gpio0 SR state */
183 #define GPIO_DEV_SRSTATE_TIMEOUT 320000 /* 320ms */
184 #define GPIO_DEV_WAKEUP 17 /* Host gpio17 mapped to device gpio1 wakeup */
185 #define CC_CHIPCTRL2_GPIO1_WAKEUP (1 << 0)
186 #define CC_CHIPCTRL3_SR_ENG_ENABLE (1 << 2)
187 #define OVERFLOW_BLKSZ512_WM 48
188 #define OVERFLOW_BLKSZ512_MES 80
190 #define CC_PMUCC3 (0x3)
191 /* Private data for SDIO bus interaction */
192 typedef struct dhd_bus {
195 bcmsdh_info_t *sdh; /* Handle for BCMSDH calls */
196 si_t *sih; /* Handle for SI calls */
197 char *vars; /* Variables (from CIS and/or other) */
198 uint varsz; /* Size of variables buffer */
199 uint32 sbaddr; /* Current SB window pointer (-1, invalid) */
201 sdpcmd_regs_t *regs; /* Registers for SDIO core */
202 uint sdpcmrev; /* SDIO core revision */
203 uint armrev; /* CPU core revision */
204 uint ramrev; /* SOCRAM core revision */
205 uint32 ramsize; /* Size of RAM in SOCRAM (bytes) */
206 uint32 orig_ramsize; /* Size of RAM in SOCRAM (bytes) */
207 uint32 srmemsize; /* Size of SRMEM */
209 uint32 bus; /* gSPI or SDIO bus */
210 uint32 hostintmask; /* Copy of Host Interrupt Mask */
211 uint32 intstatus; /* Intstatus bits (events) pending */
212 bool dpc_sched; /* Indicates DPC schedule (intrpt rcvd) */
213 bool fcstate; /* State of dongle flow-control */
215 uint16 cl_devid; /* cached devid for dhdsdio_probe_attach() */
216 char *fw_path; /* module_param: path to firmware image */
217 char *nv_path; /* module_param: path to nvram vars file */
218 const char *nvram_params; /* user specified nvram params. */
220 uint blocksize; /* Block size of SDIO transfers */
221 uint roundup; /* Max roundup limit */
223 struct pktq txq; /* Queue length used for flow-control */
224 uint8 flowcontrol; /* per prio flow control bitmask */
225 uint8 tx_seq; /* Transmit sequence number (next) */
226 uint8 tx_max; /* Maximum transmit sequence allowed */
228 uint8 hdrbuf[MAX_HDR_READ + DHD_SDALIGN];
229 uint8 *rxhdr; /* Header of current rx frame (in hdrbuf) */
230 uint16 nextlen; /* Next Read Len from last header */
231 uint8 rx_seq; /* Receive sequence number (expected) */
232 bool rxskip; /* Skip receive (awaiting NAK ACK) */
234 void *glomd; /* Packet containing glomming descriptor */
235 void *glom; /* Packet chain for glommed superframe */
236 uint glomerr; /* Glom packet read errors */
238 uint8 *rxbuf; /* Buffer for receiving control packets */
239 uint rxblen; /* Allocated length of rxbuf */
240 uint8 *rxctl; /* Aligned pointer into rxbuf */
241 uint8 *databuf; /* Buffer for receiving big glom packet */
242 uint8 *dataptr; /* Aligned pointer into databuf */
243 uint rxlen; /* Length of valid data in buffer */
245 uint8 sdpcm_ver; /* Bus protocol reported by dongle */
247 bool intr; /* Use interrupts */
248 bool poll; /* Use polling */
249 bool ipend; /* Device interrupt is pending */
250 bool intdis; /* Interrupts disabled by isr */
251 uint intrcount; /* Count of device interrupt callbacks */
252 uint lastintrs; /* Count as of last watchdog timer */
253 uint spurious; /* Count of spurious interrupts */
254 uint pollrate; /* Ticks between device polls */
255 uint polltick; /* Tick counter */
256 uint pollcnt; /* Count of active polls */
259 dhd_console_t console; /* Console output polling support */
260 uint console_addr; /* Console address from shared struct */
261 #endif /* DHD_DEBUG */
263 uint regfails; /* Count of R_REG/W_REG failures */
265 uint clkstate; /* State of sd and backplane clock(s) */
266 bool activity; /* Activity flag for clock down */
267 int32 idletime; /* Control for activity timeout */
268 int32 idlecount; /* Activity timeout counter */
269 int32 idleclock; /* How to set bus driver when idle */
270 int32 sd_divisor; /* Speed control to bus driver */
271 int32 sd_mode; /* Mode control to bus driver */
272 int32 sd_rxchain; /* If bcmsdh api accepts PKT chains */
273 bool use_rxchain; /* If dhd should use PKT chains */
274 bool sleeping; /* Is SDIO bus sleeping? */
275 uint rxflow_mode; /* Rx flow control mode */
276 bool rxflow; /* Is rx flow control on */
277 uint prev_rxlim_hit; /* Is prev rx limit exceeded (per dpc schedule) */
278 bool alp_only; /* Don't use HT clock (ALP only) */
279 /* Field to decide if rx of control frames happen in rxbuf or lb-pool */
283 /* external loopback */
287 /* pktgen configuration */
288 uint pktgen_freq; /* Ticks between bursts */
289 uint pktgen_count; /* Packets to send each burst */
290 uint pktgen_print; /* Bursts between count displays */
291 uint pktgen_total; /* Stop after this many */
292 uint pktgen_minlen; /* Minimum packet data len */
293 uint pktgen_maxlen; /* Maximum packet data len */
294 uint pktgen_mode; /* Configured mode: tx, rx, or echo */
295 uint pktgen_stop; /* Number of tx failures causing stop */
297 /* active pktgen fields */
298 uint pktgen_tick; /* Tick counter for bursts */
299 uint pktgen_ptick; /* Burst counter for printing */
300 uint pktgen_sent; /* Number of test packets generated */
301 uint pktgen_rcvd; /* Number of test packets received */
302 uint pktgen_prev_time; /* Time at which previous stats where printed */
303 uint pktgen_prev_sent; /* Number of test packets generated when
304 * previous stats were printed
306 uint pktgen_prev_rcvd; /* Number of test packets received when
307 * previous stats were printed
309 uint pktgen_fail; /* Number of failed send attempts */
310 uint16 pktgen_len; /* Length of next packet to send */
311 #define PKTGEN_RCV_IDLE (0)
312 #define PKTGEN_RCV_ONGOING (1)
313 uint16 pktgen_rcv_state; /* receive state */
314 uint pktgen_rcvd_rcvsession; /* test pkts rcvd per rcv session. */
317 /* Some additional counters */
318 uint tx_sderrs; /* Count of tx attempts with sd errors */
319 uint fcqueued; /* Tx packets that got queued */
320 uint rxrtx; /* Count of rtx requests (NAK to dongle) */
321 uint rx_toolong; /* Receive frames too long to receive */
322 uint rxc_errors; /* SDIO errors when reading control frames */
323 uint rx_hdrfail; /* SDIO errors on header reads */
324 uint rx_badhdr; /* Bad received headers (roosync?) */
325 uint rx_badseq; /* Mismatched rx sequence number */
326 uint fc_rcvd; /* Number of flow-control events received */
327 uint fc_xoff; /* Number which turned on flow-control */
328 uint fc_xon; /* Number which turned off flow-control */
329 uint rxglomfail; /* Failed deglom attempts */
330 uint rxglomframes; /* Number of glom frames (superframes) */
331 uint rxglompkts; /* Number of packets from glom frames */
332 uint f2rxhdrs; /* Number of header reads */
333 uint f2rxdata; /* Number of frame data reads */
334 uint f2txdata; /* Number of f2 frame writes */
335 uint f1regdata; /* Number of f1 register accesses */
337 uint8 *ctrl_frame_buf;
338 uint32 ctrl_frame_len;
339 bool ctrl_frame_stat;
340 uint32 rxint_mode; /* rx interrupt mode */
341 bool remap; /* Contiguous 1MB RAM: 512K socram + 512K devram
342 * Available with socram rev 16
343 * Remap region not DMA-able
352 uint32 dongle_ram_base;
353 #ifdef BCMSDIOH_TXGLOM
354 void *glom_pkt_arr[SDPCM_MAXGLOM_SIZE]; /* Array of pkts for glomming */
355 uint16 glom_cnt; /* Number of pkts in the glom array */
356 uint16 glom_total_len; /* Total length of pkts in glom array */
357 bool glom_enable; /* Flag to indicate whether tx glom is enabled/disabled */
358 uint8 glom_mode; /* Glom mode - 0-copy mode, 1 - Multi-descriptor mode */
359 uint32 glomsize; /* Glom size limitation */
366 #define CLK_PENDING 2 /* Not used yet */
369 #define DHD_NOPMU(dhd) (FALSE)
372 static int qcount[NUMPRIO];
373 static int tx_packets[NUMPRIO];
374 #endif /* DHD_DEBUG */
376 /* Deferred transmit */
377 const uint dhd_deferred_tx = 1;
379 extern uint dhd_watchdog_ms;
381 extern void dhd_os_wd_timer(void *bus, uint wdtick);
386 uint dhd_txminmax = DHD_TXMINMAX;
388 /* override the RAM size if possible */
389 #define DONGLE_MIN_RAMSIZE (128 *1024)
390 int dhd_dongle_ramsize;
392 uint dhd_doflow = TRUE;
393 uint dhd_dpcpoll = FALSE;
395 module_param(dhd_doflow, uint, 0644);
396 module_param(dhd_dpcpoll, uint, 0644);
398 static bool dhd_alignctl;
402 static bool retrydata;
403 #define RETRYCHAN(chan) (((chan) == SDPCM_EVENT_CHANNEL) || retrydata)
405 #if defined(SDIO_CRC_ERROR_FIX)
406 static uint watermark = 48;
407 static uint mesbusyctrl = 80;
409 static const uint watermark = 8;
410 static const uint mesbusyctrl = 0;
412 static const uint firstread = DHD_FIRSTREAD;
414 #define HDATLEN (firstread - (SDPCM_HDRLEN))
416 /* Retry count for register access failures */
417 static const uint retry_limit = 2;
419 /* Force even SD lengths (some host controllers mess up on odd bytes) */
420 static bool forcealign;
424 #if defined(OOB_INTR_ONLY) && defined(HW_OOB)
425 extern void bcmsdh_enable_hw_oob_intr(void *sdh, bool enable);
428 #if defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD)
429 #error OOB_INTR_ONLY is NOT working with SDIO_ISR_THREAD
430 #endif /* defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD) */
431 #define PKTALIGN(osh, p, len, align) \
434 datalign = (uintptr)PKTDATA((osh), (p)); \
435 datalign = ROUNDUP(datalign, (align)) - datalign; \
436 ASSERT(datalign < (align)); \
437 ASSERT(PKTLEN((osh), (p)) >= ((len) + datalign)); \
439 PKTPULL((osh), (p), datalign); \
440 PKTSETLEN((osh), (p), (len)); \
443 /* Limit on rounding up frames */
444 static const uint max_roundup = 512;
446 /* Try doing readahead */
447 static bool dhd_readahead;
449 /* To check if there's window offered */
450 #define DATAOK(bus) \
451 (((uint8)(bus->tx_max - bus->tx_seq) > 1) && \
452 (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0))
454 /* To check if there's window offered for ctrl frame */
455 #define TXCTLOK(bus) \
456 (((uint8)(bus->tx_max - bus->tx_seq) != 0) && \
457 (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0))
459 /* Number of pkts available in dongle for data RX */
460 #define DATABUFCNT(bus) \
461 ((uint8)(bus->tx_max - bus->tx_seq) - 1)
463 /* Macros to get register read/write status */
464 /* NOTE: these assume a local dhdsdio_bus_t *bus! */
465 #define R_SDREG(regvar, regaddr, retryvar) \
469 regvar = R_REG(bus->dhd->osh, regaddr); \
470 } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \
472 bus->regfails += (retryvar-1); \
473 if (retryvar > retry_limit) { \
474 DHD_ERROR(("%s: FAILED" #regvar "READ, LINE %d\n", \
475 __FUNCTION__, __LINE__)); \
481 #define W_SDREG(regval, regaddr, retryvar) \
485 W_REG(bus->dhd->osh, regaddr, regval); \
486 } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \
488 bus->regfails += (retryvar-1); \
489 if (retryvar > retry_limit) \
490 DHD_ERROR(("%s: FAILED REGISTER WRITE, LINE %d\n", \
491 __FUNCTION__, __LINE__)); \
495 #define BUS_WAKE(bus) \
497 bus->idlecount = 0; \
498 if ((bus)->sleeping) \
499 dhdsdio_bussleep((bus), FALSE); \
503 * pktavail interrupts from dongle to host can be managed in 3 different ways
504 * whenever there is a packet available in dongle to transmit to host.
506 * Mode 0: Dongle writes the software host mailbox and host is interrupted.
507 * Mode 1: (sdiod core rev >= 4)
508 * Device sets a new bit in the intstatus whenever there is a packet
509 * available in fifo. Host can't clear this specific status bit until all the
510 * packets are read from the FIFO. No need to ack dongle intstatus.
511 * Mode 2: (sdiod core rev >= 4)
512 * Device sets a bit in the intstatus, and host acks this by writing
513 * one to this bit. Dongle won't generate anymore packet interrupts
514 * until host reads all the packets from the dongle and reads a zero to
515 * figure that there are no more packets. No need to disable host ints.
516 * Need to ack the intstatus.
519 #define SDIO_DEVICE_HMB_RXINT 0 /* default old way */
520 #define SDIO_DEVICE_RXDATAINT_MODE_0 1 /* from sdiod rev 4 */
521 #define SDIO_DEVICE_RXDATAINT_MODE_1 2 /* from sdiod rev 4 */
524 #define FRAME_AVAIL_MASK(bus) \
525 ((bus->rxint_mode == SDIO_DEVICE_HMB_RXINT) ? I_HMB_FRAME_IND : I_XMTDATA_AVAIL)
527 #define DHD_BUS SDIO_BUS
529 #define PKT_AVAILABLE(bus, intstatus) ((intstatus) & (FRAME_AVAIL_MASK(bus)))
531 #define HOSTINTMASK (I_HMB_SW_MASK | I_CHIPACTIVE)
533 #define GSPI_PR55150_BAILOUT
536 static void dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq);
537 static void dhdsdio_sdtest_set(dhd_bus_t *bus, uint count);
541 static int dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size);
542 static int dhd_serialconsole(dhd_bus_t *bus, bool get, bool enable, int *bcmerror);
543 #endif /* DHD_DEBUG */
545 static int dhdsdio_devcap_set(dhd_bus_t *bus, uint8 cap);
546 static int dhdsdio_download_state(dhd_bus_t *bus, bool enter);
548 static void dhdsdio_release(dhd_bus_t *bus, osl_t *osh);
549 static void dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh);
550 static void dhdsdio_disconnect(void *ptr);
551 static bool dhdsdio_chipmatch(uint16 chipid);
552 static bool dhdsdio_probe_attach(dhd_bus_t *bus, osl_t *osh, void *sdh,
553 void * regsva, uint16 devid);
554 static bool dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh);
555 static bool dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh);
556 static void dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation,
559 static void dhd_dongle_setramsize(struct dhd_bus *bus, int mem_size);
560 static int dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags,
561 uint8 *buf, uint nbytes,
562 void *pkt, bcmsdh_cmplt_fn_t complete, void *handle);
563 static int dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags,
564 uint8 *buf, uint nbytes,
565 void *pkt, bcmsdh_cmplt_fn_t complete, void *handle);
566 #ifdef BCMSDIOH_TXGLOM
567 static void dhd_bcmsdh_glom_post(dhd_bus_t *bus, uint8 *frame, void *pkt, uint len);
568 static void dhd_bcmsdh_glom_clear(dhd_bus_t *bus);
571 static bool dhdsdio_download_firmware(dhd_bus_t *bus, osl_t *osh, void *sdh);
572 static int _dhdsdio_download_firmware(dhd_bus_t *bus);
574 static int dhdsdio_download_code_file(dhd_bus_t *bus, char *image_path);
575 static int dhdsdio_download_nvram(dhd_bus_t *bus);
577 static int dhdsdio_download_code_array(dhd_bus_t *bus);
579 static int dhdsdio_bussleep(dhd_bus_t *bus, bool sleep);
580 static int dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok);
581 static uint8 dhdsdio_sleepcsr_get(dhd_bus_t *bus);
585 extern uint32 dhd_get_htsf(void *dhd, int ifidx);
586 #endif /* WLMEDIA_HTSF */
589 dhd_overflow_war(struct dhd_bus *bus)
592 uint8 devctl, wm, mes;
594 /* See .ppt in PR for these recommended values */
595 if (bus->blocksize == 512) {
596 wm = OVERFLOW_BLKSZ512_WM;
597 mes = OVERFLOW_BLKSZ512_MES;
599 mes = bus->blocksize/4;
600 wm = bus->blocksize/4;
604 /* Update watermark */
605 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, wm, &err);
607 devctl = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
608 devctl |= SBSDIO_DEVCTL_F2WM_ENAB;
609 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
612 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL,
613 (mes | SBSDIO_MESBUSYCTRL_ENAB), &err);
615 DHD_INFO(("Apply overflow WAR: 0x%02x 0x%02x 0x%02x\n",
616 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err),
617 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, &err),
618 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL, &err)));
622 dhd_dongle_setramsize(struct dhd_bus *bus, int mem_size)
624 int32 min_size = DONGLE_MIN_RAMSIZE;
625 /* Restrict the ramsize to user specified limit */
626 DHD_ERROR(("user: Restrict the dongle ram size to %d, min accepted %d\n",
627 dhd_dongle_ramsize, min_size));
628 if ((dhd_dongle_ramsize > min_size) &&
629 (dhd_dongle_ramsize < (int32)bus->orig_ramsize))
630 bus->ramsize = dhd_dongle_ramsize;
634 dhdsdio_set_siaddr_window(dhd_bus_t *bus, uint32 address)
637 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW,
638 (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err);
640 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID,
641 (address >> 16) & SBSDIO_SBADDRMID_MASK, &err);
643 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH,
644 (address >> 24) & SBSDIO_SBADDRHIGH_MASK, &err);
651 dhdsdio_oobwakeup_init(dhd_bus_t *bus)
653 uint32 val, addr, data;
655 bcmsdh_gpioouten(bus->sdh, GPIO_DEV_WAKEUP);
657 addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr);
658 data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data);
660 /* Set device for gpio1 wakeup */
661 bcmsdh_reg_write(bus->sdh, addr, 4, 2);
662 val = bcmsdh_reg_read(bus->sdh, data, 4);
663 val |= CC_CHIPCTRL2_GPIO1_WAKEUP;
664 bcmsdh_reg_write(bus->sdh, data, 4, val);
666 bus->_oobwakeup = TRUE;
670 #endif /* USE_OOB_GPIO1 */
673 * Query if FW is in SR mode
676 dhdsdio_sr_cap(dhd_bus_t *bus)
679 uint32 core_capext, addr, data;
680 if (bus->sih->chip == BCM4324_CHIP_ID) {
681 addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr);
682 data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data);
683 bcmsdh_reg_write(bus->sdh, addr, 4, 3);
684 core_capext = bcmsdh_reg_read(bus->sdh, data, 4);
685 } else if ((bus->sih->chip == BCM4330_CHIP_ID) ||
686 (bus->sih->chip == BCM43362_CHIP_ID)) {
688 } else if ((bus->sih->chip == BCM4335_CHIP_ID) ||
689 (bus->sih->chip == BCM4339_CHIP_ID) ||
690 (bus->sih->chip == BCM4350_CHIP_ID)) {
693 core_capext = bcmsdh_reg_read(bus->sdh, CORE_CAPEXT_ADDR, 4);
694 core_capext = (core_capext & CORE_CAPEXT_SR_SUPPORTED_MASK);
699 if (bus->sih->chip == BCM4324_CHIP_ID) {
700 /* FIX: Should change to query SR control register instead */
702 } else if ((bus->sih->chip == BCM4335_CHIP_ID) ||
703 (bus->sih->chip == BCM4339_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, CC_PMUCC3);
708 enabval = bcmsdh_reg_read(bus->sdh, data, 4);
710 if ((bus->sih->chip == BCM4350_CHIP_ID) ||
712 enabval &= CC_CHIPCTRL3_SR_ENG_ENABLE;
717 data = bcmsdh_reg_read(bus->sdh,
718 SI_ENUM_BASE + OFFSETOF(chipcregs_t, retention_ctl), 4);
719 if ((data & (RCTL_MACPHY_DISABLE_MASK | RCTL_LOGIC_DISABLE_MASK)) == 0)
727 dhdsdio_srwar_init(dhd_bus_t *bus)
729 bcmsdh_gpio_init(bus->sdh);
732 dhdsdio_oobwakeup_init(bus);
740 dhdsdio_sr_init(dhd_bus_t *bus)
745 if ((bus->sih->chip == BCM4334_CHIP_ID) && (bus->sih->chiprev == 2))
746 dhdsdio_srwar_init(bus);
748 val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, NULL);
749 val |= 1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT;
750 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL,
751 1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT, &err);
752 val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, NULL);
754 /* Add CMD14 Support */
755 dhdsdio_devcap_set(bus,
756 (SDIOD_CCCR_BRCM_CARDCAP_CMD14_SUPPORT | SDIOD_CCCR_BRCM_CARDCAP_CMD14_EXT));
758 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1,
759 SBSDIO_FUNC1_CHIPCLKCSR, SBSDIO_FORCE_HT, &err);
761 bus->_slpauto = dhd_slpauto ? TRUE : FALSE;
769 * FIX: Be sure KSO bit is enabled
770 * Currently, it's defaulting to 0 which should be 1.
773 dhdsdio_clk_kso_init(dhd_bus_t *bus)
782 * Enable KeepSdioOn (KSO) bit for normal operation
783 * Default is 0 (4334A0) so set it. Fixed in B0.
785 val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, NULL);
786 if (!(val & SBSDIO_FUNC1_SLEEPCSR_KSO_MASK)) {
787 val |= (SBSDIO_FUNC1_SLEEPCSR_KSO_EN << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT);
788 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, val, &err);
790 DHD_ERROR(("%s: SBSDIO_FUNC1_SLEEPCSR err: 0x%x\n", __FUNCTION__, err));
797 #define KSO_WAIT_US 50
798 #define MAX_KSO_ATTEMPTS (PMU_MAX_TRANSITION_DLY/KSO_WAIT_US)
800 dhdsdio_clk_kso_enab(dhd_bus_t *bus, bool on)
802 uint8 wr_val = 0, rd_val, cmp_val, bmask;
806 KSO_DBG(("%s> op:%s\n", __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR")));
808 wr_val |= (on << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT);
810 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, wr_val, &err);
813 cmp_val = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK | SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK;
818 /* Put device to sleep, turn off KSO */
820 bmask = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK;
824 rd_val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, &err);
825 if (((rd_val & bmask) == cmp_val) && !err)
828 KSO_DBG(("%s> KSO wr/rd retry:%d, ERR:%x \n", __FUNCTION__, try_cnt, err));
829 OSL_DELAY(KSO_WAIT_US);
831 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, wr_val, &err);
832 } while (try_cnt++ < MAX_KSO_ATTEMPTS);
836 KSO_DBG(("%s> op:%s, try_cnt:%d, rd_val:%x, ERR:%x \n",
837 __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"), try_cnt, rd_val, err));
839 if (try_cnt > MAX_KSO_ATTEMPTS) {
840 DHD_ERROR(("%s> op:%s, ERROR: try_cnt:%d, rd_val:%x, ERR:%x \n",
841 __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"), try_cnt, rd_val, err));
847 dhdsdio_clk_kso_iovar(dhd_bus_t *bus, bool on)
854 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
856 DHD_ERROR(("%s: KSO disable clk: 0x%x\n", __FUNCTION__,
857 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
858 SBSDIO_FUNC1_CHIPCLKCSR, &err)));
859 dhdsdio_clk_kso_enab(bus, FALSE);
861 DHD_ERROR(("%s: KSO enable\n", __FUNCTION__));
863 /* Make sure we have SD bus access */
864 if (bus->clkstate == CLK_NONE) {
865 DHD_ERROR(("%s: Request SD clk\n", __FUNCTION__));
866 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
869 dhdsdio_clk_kso_enab(bus, TRUE);
871 DHD_ERROR(("%s: sleepcsr: 0x%x\n", __FUNCTION__,
872 dhdsdio_sleepcsr_get(bus)));
882 dhdsdio_sleepcsr_get(dhd_bus_t *bus)
887 val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, &err);
889 DHD_TRACE(("Failed to read SLEEPCSR: %d\n", err));
895 dhdsdio_devcap_get(dhd_bus_t *bus)
897 return bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_BRCM_CARDCAP, NULL);
901 dhdsdio_devcap_set(dhd_bus_t *bus, uint8 cap)
905 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_BRCM_CARDCAP, cap, &err);
907 DHD_ERROR(("%s: devcap set err: 0x%x\n", __FUNCTION__, err));
913 dhdsdio_clk_devsleep_iovar(dhd_bus_t *bus, bool on)
922 /* Be sure we request clk before going to sleep
923 * so we can wake-up with clk request already set
924 * else device can go back to sleep immediately
926 if (!SLPAUTO_ENAB(bus))
927 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
929 val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
930 if ((val & SBSDIO_CSR_MASK) == 0) {
931 DHD_ERROR(("%s: No clock before enter sleep:0x%x\n",
934 /* Reset clock request */
935 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
936 SBSDIO_ALP_AVAIL_REQ, &err);
937 DHD_ERROR(("%s: clock before sleep:0x%x\n", __FUNCTION__,
938 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
939 SBSDIO_FUNC1_CHIPCLKCSR, &err)));
943 DHD_TRACE(("%s: clk before sleep: 0x%x\n", __FUNCTION__,
944 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
945 SBSDIO_FUNC1_CHIPCLKCSR, &err)));
947 err = bcmsdh_sleep(bus->sdh, TRUE);
949 err = dhdsdio_clk_kso_enab(bus, FALSE);
950 if (OOB_WAKEUP_ENAB(bus))
952 err = bcmsdh_gpioout(bus->sdh, GPIO_DEV_WAKEUP, FALSE); /* GPIO_1 is off */
954 #endif /* USE_CMD14 */
957 /* Make sure we have SD bus access */
958 if (bus->clkstate == CLK_NONE) {
959 DHD_TRACE(("%s: Request SD clk\n", __FUNCTION__));
960 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
963 if ((bus->sih->chip == BCM4334_CHIP_ID) && (bus->sih->chiprev == 2)) {
964 SPINWAIT_SLEEP(sdioh_spinwait_sleep,
965 (bcmsdh_gpioin(bus->sdh, GPIO_DEV_SRSTATE) != TRUE),
966 GPIO_DEV_SRSTATE_TIMEOUT);
968 if (bcmsdh_gpioin(bus->sdh, GPIO_DEV_SRSTATE) == FALSE) {
969 DHD_ERROR(("ERROR: GPIO_DEV_SRSTATE still low!\n"));
973 err = bcmsdh_sleep(bus->sdh, FALSE);
974 if (SLPAUTO_ENAB(bus) && (err != 0)) {
976 DHD_TRACE(("%s: Resync device sleep\n", __FUNCTION__));
978 /* Toggle sleep to resync with host and device */
979 err = bcmsdh_sleep(bus->sdh, TRUE);
981 err = bcmsdh_sleep(bus->sdh, FALSE);
985 DHD_ERROR(("%s: CMD14 exit failed again!\n", __FUNCTION__));
987 /* Toggle sleep to resync with host and device */
988 err = bcmsdh_sleep(bus->sdh, TRUE);
990 err = bcmsdh_sleep(bus->sdh, FALSE);
992 DHD_ERROR(("%s: CMD14 exit failed twice!\n", __FUNCTION__));
993 DHD_ERROR(("%s: FATAL: Device non-response!\n",
1000 if (OOB_WAKEUP_ENAB(bus))
1002 err = bcmsdh_gpioout(bus->sdh, GPIO_DEV_WAKEUP, TRUE); /* GPIO_1 is on */
1005 err = dhdsdio_clk_kso_enab(bus, TRUE);
1008 } while ((err != 0) && (++retry < 3));
1011 DHD_ERROR(("ERROR: kso set failed retry: %d\n", retry));
1012 err = 0; /* continue anyway */
1014 #endif /* !USE_CMD14 */
1019 /* Wait for device ready during transition to wake-up */
1020 SPINWAIT_SLEEP(sdioh_spinwait_sleep,
1021 (((csr = dhdsdio_sleepcsr_get(bus)) &
1022 SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK) !=
1023 (SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK)), (20000));
1025 DHD_TRACE(("%s: ExitSleep sleepcsr: 0x%x\n", __FUNCTION__, csr));
1027 if (!(csr & SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK)) {
1028 DHD_ERROR(("%s:ERROR: ExitSleep device NOT Ready! 0x%x\n",
1029 __FUNCTION__, csr));
1030 err = BCME_NODEVICE;
1033 SPINWAIT_SLEEP(sdioh_spinwait_sleep,
1034 (((csr = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
1035 SBSDIO_FUNC1_CHIPCLKCSR, &err)) & SBSDIO_HT_AVAIL) !=
1036 (SBSDIO_HT_AVAIL)), (10000));
1041 /* Update if successful */
1043 bus->kso = on ? FALSE : TRUE;
1045 DHD_ERROR(("%s: Sleep request failed: on:%d err:%d\n", __FUNCTION__, on, err));
1046 if (!on && retry > 2)
1053 /* Turn backplane clock on or off */
1055 dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok)
1057 #define HT_AVAIL_ERROR_MAX 10
1058 static int ht_avail_error = 0;
1060 uint8 clkctl, clkreq, devctl;
1063 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1072 if (SLPAUTO_ENAB(bus)) {
1073 bus->clkstate = (on ? CLK_AVAIL : CLK_SDONLY);
1078 /* Request HT Avail */
1079 clkreq = bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ;
1083 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
1086 if (ht_avail_error < HT_AVAIL_ERROR_MAX) {
1087 DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err));
1090 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
1091 else if (ht_avail_error == HT_AVAIL_ERROR_MAX) {
1092 dhd_os_send_hang_message(bus->dhd);
1094 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) */
1101 /* Check current status */
1102 clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
1104 DHD_ERROR(("%s: HT Avail read error: %d\n", __FUNCTION__, err));
1108 #if !defined(OOB_INTR_ONLY)
1109 /* Go to pending and await interrupt if appropriate */
1110 if (!SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) {
1111 /* Allow only clock-available interrupt */
1112 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
1114 DHD_ERROR(("%s: Devctl access error setting CA: %d\n",
1115 __FUNCTION__, err));
1119 devctl |= SBSDIO_DEVCTL_CA_INT_ONLY;
1120 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
1121 DHD_INFO(("CLKCTL: set PENDING\n"));
1122 bus->clkstate = CLK_PENDING;
1125 #endif /* !defined (OOB_INTR_ONLY) */
1127 if (bus->clkstate == CLK_PENDING) {
1128 /* Cancel CA-only interrupt filter */
1129 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
1130 devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
1131 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
1135 /* Otherwise, wait here (polling) for HT Avail */
1136 if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
1137 SPINWAIT_SLEEP(sdioh_spinwait_sleep,
1138 ((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
1139 SBSDIO_FUNC1_CHIPCLKCSR, &err)),
1140 !SBSDIO_CLKAV(clkctl, bus->alp_only)), PMU_MAX_TRANSITION_DLY);
1143 DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err));
1146 if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
1147 DHD_ERROR(("%s: HT Avail timeout (%d): clkctl 0x%02x\n",
1148 __FUNCTION__, PMU_MAX_TRANSITION_DLY, clkctl));
1152 /* Mark clock available */
1153 bus->clkstate = CLK_AVAIL;
1154 DHD_INFO(("CLKCTL: turned ON\n"));
1156 #if defined(DHD_DEBUG)
1157 if (bus->alp_only == TRUE) {
1158 #if !defined(BCMLXSDMMC)
1159 if (!SBSDIO_ALPONLY(clkctl)) {
1160 DHD_ERROR(("%s: HT Clock, when ALP Only\n", __FUNCTION__));
1162 #endif /* !defined(BCMLXSDMMC) */
1164 if (SBSDIO_ALPONLY(clkctl)) {
1165 DHD_ERROR(("%s: HT Clock should be on.\n", __FUNCTION__));
1168 #endif /* defined (DHD_DEBUG) */
1170 bus->activity = TRUE;
1171 #ifdef DHD_USE_IDLECOUNT
1173 #endif /* DHD_USE_IDLECOUNT */
1176 if (bus->clkstate == CLK_PENDING) {
1177 /* Cancel CA-only interrupt filter */
1178 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
1179 devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
1180 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
1183 bus->clkstate = CLK_SDONLY;
1184 if (!SR_ENAB(bus)) {
1185 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
1186 DHD_INFO(("CLKCTL: turned OFF\n"));
1188 DHD_ERROR(("%s: Failed access turning clock off: %d\n",
1189 __FUNCTION__, err));
1197 /* Change idle/active SD state */
1199 dhdsdio_sdclk(dhd_bus_t *bus, bool on)
1204 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1207 if (bus->idleclock == DHD_IDLE_STOP) {
1208 /* Turn on clock and restore mode */
1210 err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0,
1211 &iovalue, sizeof(iovalue), TRUE);
1213 DHD_ERROR(("%s: error enabling sd_clock: %d\n",
1214 __FUNCTION__, err));
1218 iovalue = bus->sd_mode;
1219 err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
1220 &iovalue, sizeof(iovalue), TRUE);
1222 DHD_ERROR(("%s: error changing sd_mode: %d\n",
1223 __FUNCTION__, err));
1226 } else if (bus->idleclock != DHD_IDLE_ACTIVE) {
1227 /* Restore clock speed */
1228 iovalue = bus->sd_divisor;
1229 err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
1230 &iovalue, sizeof(iovalue), TRUE);
1232 DHD_ERROR(("%s: error restoring sd_divisor: %d\n",
1233 __FUNCTION__, err));
1237 bus->clkstate = CLK_SDONLY;
1239 /* Stop or slow the SD clock itself */
1240 if ((bus->sd_divisor == -1) || (bus->sd_mode == -1)) {
1241 DHD_TRACE(("%s: can't idle clock, divisor %d mode %d\n",
1242 __FUNCTION__, bus->sd_divisor, bus->sd_mode));
1245 if (bus->idleclock == DHD_IDLE_STOP) {
1247 /* Change to SD1 mode and turn off clock */
1249 err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
1250 &iovalue, sizeof(iovalue), TRUE);
1252 DHD_ERROR(("%s: error changing sd_clock: %d\n",
1253 __FUNCTION__, err));
1259 err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0,
1260 &iovalue, sizeof(iovalue), TRUE);
1262 DHD_ERROR(("%s: error disabling sd_clock: %d\n",
1263 __FUNCTION__, err));
1266 } else if (bus->idleclock != DHD_IDLE_ACTIVE) {
1267 /* Set divisor to idle value */
1268 iovalue = bus->idleclock;
1269 err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
1270 &iovalue, sizeof(iovalue), TRUE);
1272 DHD_ERROR(("%s: error changing sd_divisor: %d\n",
1273 __FUNCTION__, err));
1277 bus->clkstate = CLK_NONE;
1283 /* Transition SD and backplane clock readiness */
1285 dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok)
1289 uint oldstate = bus->clkstate;
1290 #endif /* DHD_DEBUG */
1292 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1294 /* Early exit if we're already there */
1295 if (bus->clkstate == target) {
1296 if (target == CLK_AVAIL) {
1297 dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
1298 bus->activity = TRUE;
1299 #ifdef DHD_USE_IDLECOUNT
1301 #endif /* DHD_USE_IDLECOUNT */
1308 /* Make sure SD clock is available */
1309 if (bus->clkstate == CLK_NONE)
1310 dhdsdio_sdclk(bus, TRUE);
1311 /* Now request HT Avail on the backplane */
1312 ret = dhdsdio_htclk(bus, TRUE, pendok);
1313 if (ret == BCME_OK) {
1314 dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
1315 bus->activity = TRUE;
1316 #ifdef DHD_USE_IDLECOUNT
1318 #endif /* DHD_USE_IDLECOUNT */
1323 /* Remove HT request, or bring up SD clock */
1324 if (bus->clkstate == CLK_NONE)
1325 ret = dhdsdio_sdclk(bus, TRUE);
1326 else if (bus->clkstate == CLK_AVAIL)
1327 ret = dhdsdio_htclk(bus, FALSE, FALSE);
1329 DHD_ERROR(("dhdsdio_clkctl: request for %d -> %d\n",
1330 bus->clkstate, target));
1331 if (ret == BCME_OK) {
1332 dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
1337 /* Make sure to remove HT request */
1338 if (bus->clkstate == CLK_AVAIL)
1339 ret = dhdsdio_htclk(bus, FALSE, FALSE);
1340 /* Now remove the SD clock */
1341 ret = dhdsdio_sdclk(bus, FALSE);
1343 if (dhd_console_ms == 0)
1344 #endif /* DHD_DEBUG */
1346 dhd_os_wd_timer(bus->dhd, 0);
1350 DHD_INFO(("dhdsdio_clkctl: %d -> %d\n", oldstate, bus->clkstate));
1351 #endif /* DHD_DEBUG */
1357 dhdsdio_bussleep(dhd_bus_t *bus, bool sleep)
1360 bcmsdh_info_t *sdh = bus->sdh;
1361 sdpcmd_regs_t *regs = bus->regs;
1364 DHD_INFO(("dhdsdio_bussleep: request %s (currently %s)\n",
1365 (sleep ? "SLEEP" : "WAKE"),
1366 (bus->sleeping ? "SLEEP" : "WAKE")));
1368 /* Done if we're already in the requested state */
1369 if (sleep == bus->sleeping)
1372 /* Going to sleep: set the alarm and turn off the lights... */
1374 /* Don't sleep if something is pending */
1375 if (bus->dpc_sched || bus->rxskip || pktq_len(&bus->txq))
1379 if (!SLPAUTO_ENAB(bus)) {
1380 /* Disable SDIO interrupts (no longer interested) */
1381 bcmsdh_intr_disable(bus->sdh);
1383 /* Make sure the controller has the bus up */
1384 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
1386 /* Tell device to start using OOB wakeup */
1387 W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries);
1388 if (retries > retry_limit)
1389 DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
1391 /* Turn off our contribution to the HT clock request */
1392 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
1394 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
1395 SBSDIO_FORCE_HW_CLKREQ_OFF, NULL);
1397 /* Isolate the bus */
1398 if (bus->sih->chip != BCM4329_CHIP_ID &&
1399 bus->sih->chip != BCM4319_CHIP_ID) {
1400 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL,
1401 SBSDIO_DEVCTL_PADS_ISO, NULL);
1404 /* Leave interrupts enabled since device can exit sleep and
1407 err = dhdsdio_clk_devsleep_iovar(bus, TRUE /* sleep */);
1411 bus->sleeping = TRUE;
1414 /* Waking up: bus power up is ok, set local state */
1416 if (!SLPAUTO_ENAB(bus)) {
1417 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0, &err);
1419 /* Force pad isolation off if possible (in case power never toggled) */
1420 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, 0, NULL);
1423 /* Make sure the controller has the bus up */
1424 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
1426 /* Send misc interrupt to indicate OOB not needed */
1427 W_SDREG(0, ®s->tosbmailboxdata, retries);
1428 if (retries <= retry_limit)
1429 W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries);
1431 if (retries > retry_limit)
1432 DHD_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n"));
1434 /* Make sure we have SD bus access */
1435 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
1437 /* Enable interrupts again */
1438 if (bus->intr && (bus->dhd->busstate == DHD_BUS_DATA)) {
1439 bus->intdis = FALSE;
1440 bcmsdh_intr_enable(bus->sdh);
1443 err = dhdsdio_clk_devsleep_iovar(bus, FALSE /* wake */);
1448 bus->sleeping = FALSE;
1455 #if defined(OOB_INTR_ONLY)
1457 dhd_enable_oob_intr(struct dhd_bus *bus, bool enable)
1460 bcmsdh_enable_hw_oob_intr(bus->sdh, enable);
1462 sdpcmd_regs_t *regs = bus->regs;
1465 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
1466 if (enable == TRUE) {
1468 /* Tell device to start using OOB wakeup */
1469 W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries);
1470 if (retries > retry_limit)
1471 DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
1474 /* Send misc interrupt to indicate OOB not needed */
1475 W_SDREG(0, ®s->tosbmailboxdata, retries);
1476 if (retries <= retry_limit)
1477 W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries);
1480 /* Turn off our contribution to the HT clock request */
1481 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
1482 #endif /* !defined(HW_OOB) */
1486 #ifdef DHDTCPACK_SUPPRESS
1487 extern bool dhd_use_tcpack_suppress;
1489 /* Please be sure this function is called under dhd_os_tcpacklock() */
1490 void dhd_onoff_tcpack_sup(void *pub, bool on)
1492 dhd_pub_t *dhdp = (dhd_pub_t *)pub;
1494 if (dhd_use_tcpack_suppress != on) {
1496 DHD_ERROR(("dhd_onoff_tcpack_sup: %d -> %d\n", dhd_use_tcpack_suppress, on));
1497 dhd_use_tcpack_suppress = on;
1498 dhdp->tcp_ack_info_cnt = 0;
1499 bzero(dhdp->tcp_ack_info_tbl, sizeof(struct tcp_ack_info)*MAXTCPSTREAMS);
1502 DHD_ERROR(("dhd_onoff_tcpack_sup: alread %d\n", on));
1507 inline void dhd_tcpack_check_xmit(dhd_pub_t *dhdp, void *pkt)
1510 tcp_ack_info_t *tcp_ack_info = NULL;
1513 dhd_os_tcpacklock(dhdp);
1514 tbl_cnt = dhdp->tcp_ack_info_cnt;
1515 for (i = 0; i < tbl_cnt; i++) {
1516 tcp_ack_info = &dhdp->tcp_ack_info_tbl[i];
1517 if (tcp_ack_info->p_tcpackinqueue == pkt) {
1518 /* This pkt is being transmitted so remove the tcp_ack_info of it.
1519 * compact the array unless the last element,
1520 * then the pkt's array is removed.
1522 if (i < tbl_cnt-1) {
1523 memmove(&dhdp->tcp_ack_info_tbl[i],
1524 &dhdp->tcp_ack_info_tbl[i+1],
1525 sizeof(struct tcp_ack_info)*(tbl_cnt - (i+1)));
1527 bzero(&dhdp->tcp_ack_info_tbl[tbl_cnt-1], sizeof(struct tcp_ack_info));
1528 if (--dhdp->tcp_ack_info_cnt < 0) {
1529 DHD_ERROR(("dhdsdio_sendfromq:(ERROR) tcp_ack_info_cnt %d"
1530 " Stop using tcpack_suppress\n", dhdp->tcp_ack_info_cnt));
1531 dhd_onoff_tcpack_sup(dhdp, FALSE);
1536 dhd_os_tcpackunlock(dhdp);
1540 dhd_tcpack_suppress(dhd_pub_t *dhdp, void *pkt)
1547 uint32 cur_framelen;
1548 uint8 bdc_hdr_len = BDC_HEADER_LEN;
1549 uint8 wlfc_hdr_len = 0;
1550 uint8 *data = PKTDATA(dhdp->osh, pkt);
1551 cur_framelen = PKTLEN(dhdp->osh, pkt);
1553 #ifdef PROP_TXSTATUS
1554 /* In this case, BDC header is not pushed in dhd_sendpkt() */
1555 if (dhdp->wlfc_state) {
1560 if (cur_framelen < bdc_hdr_len + ETHER_HDR_LEN) {
1561 DHD_TRACE(("dhd_tcpack_suppress: Too short packet length %d\n", cur_framelen));
1565 /* Get rid of BDC header */
1566 eh_header = data + bdc_hdr_len;
1567 cur_framelen -= bdc_hdr_len;
1568 eh_type = eh_header[12] << 8 | eh_header[13];
1570 if (eh_type != ETHER_TYPE_IP) {
1571 DHD_TRACE(("dhd_tcpack_suppress: Not a IP packet 0x%x\n", eh_type));
1575 DHD_TRACE(("dhd_tcpack_suppress: IP pkt! 0x%x\n", eh_type));
1577 ip_header = eh_header + ETHER_HDR_LEN;
1578 cur_framelen -= ETHER_HDR_LEN;
1579 ip_hdr_len = 4 * (ip_header[0] & 0x0f);
1581 if ((ip_header[0] & 0xf0) != 0x40) {
1582 DHD_TRACE(("dhd_tcpack_suppress: Not IPv4!\n"));
1586 if (cur_framelen < ip_hdr_len) {
1587 DHD_ERROR(("dhd_tcpack_suppress: IP packet length %d wrong!\n", cur_framelen));
1592 if (ip_header[9] != 0x06) {
1593 DHD_TRACE(("dhd_tcpack_suppress: Not a TCP packet 0x%x\n", ip_header[9]));
1597 DHD_TRACE(("dhd_tcpack_suppress: TCP pkt!\n"));
1599 tcp_header = ip_header + ip_hdr_len;
1601 /* is it an ack ? */
1602 if (tcp_header[13] == 0x10) {
1603 #if defined(DHD_DEBUG)
1604 uint32 tcp_seq_num = tcp_header[4] << 24 | tcp_header[5] << 16 |
1605 tcp_header[6] << 8 | tcp_header[7];
1607 uint32 tcp_ack_num = tcp_header[8] << 24 | tcp_header[9] << 16 |
1608 tcp_header[10] << 8 | tcp_header[11];
1609 uint16 ip_tcp_ttllen = (ip_header[3] & 0xff) + (ip_header[2] << 8);
1610 uint32 tcp_hdr_len = 4*((tcp_header[12] & 0xf0) >> 4);
1611 DHD_TRACE(("dhd_tcpack_suppress: TCP ACK seq %ud ack %ud\n",
1612 tcp_seq_num, tcp_ack_num));
1616 if (ip_tcp_ttllen == ip_hdr_len + tcp_hdr_len) {
1618 tcp_ack_info_t *tcp_ack_info = NULL;
1619 DHD_TRACE(("dhd_tcpack_suppress: TCP ACK zero length\n"));
1620 /* Look for tcp_ack_info that has the same
1621 * ip src/dst addrs and tcp src/dst ports
1623 dhd_os_tcpacklock(dhdp);
1624 for (i = 0; i < dhdp->tcp_ack_info_cnt; i++) {
1625 if (dhdp->tcp_ack_info_tbl[i].p_tcpackinqueue &&
1626 !memcmp(&ip_header[12], dhdp->tcp_ack_info_tbl[i].ipaddrs, 8) &&
1627 !memcmp(tcp_header, dhdp->tcp_ack_info_tbl[i].tcpports, 4)) {
1628 tcp_ack_info = &dhdp->tcp_ack_info_tbl[i];
1633 if (i == dhdp->tcp_ack_info_cnt && i < MAXTCPSTREAMS)
1634 tcp_ack_info = &dhdp->tcp_ack_info_tbl[dhdp->tcp_ack_info_cnt++];
1636 if (!tcp_ack_info) {
1637 DHD_TRACE(("dhd_tcpack_suppress: No empty tcp ack info"
1638 "%d %d %d %d, %d %d %d %d\n",
1639 tcp_header[0], tcp_header[1], tcp_header[2], tcp_header[3],
1640 dhdp->tcp_ack_info_tbl[i].tcpports[0],
1641 dhdp->tcp_ack_info_tbl[i].tcpports[1],
1642 dhdp->tcp_ack_info_tbl[i].tcpports[2],
1643 dhdp->tcp_ack_info_tbl[i].tcpports[3]));
1644 dhd_os_tcpackunlock(dhdp);
1648 if (tcp_ack_info->p_tcpackinqueue) {
1649 if (tcp_ack_num > tcp_ack_info->tcpack_number) {
1650 void *prevpkt = tcp_ack_info->p_tcpackinqueue;
1651 uint8 pushed_len = SDPCM_HDRLEN +
1652 (BDC_HEADER_LEN - bdc_hdr_len) + wlfc_hdr_len;
1653 #ifdef PROP_TXSTATUS
1654 /* In case the prev pkt is delayenqueued
1655 * but not delayedequeued yet, it may not have
1656 * any additional header yet.
1658 if (dhdp->wlfc_state && (PKTLEN(dhdp->osh, prevpkt) ==
1659 tcp_ack_info->ip_tcp_ttllen + ETHER_HDR_LEN))
1662 if ((ip_tcp_ttllen == tcp_ack_info->ip_tcp_ttllen) &&
1663 (PKTLEN(dhdp->osh, pkt) ==
1664 PKTLEN(dhdp->osh, prevpkt) - pushed_len)) {
1665 bcopy(PKTDATA(dhdp->osh, pkt),
1666 PKTDATA(dhdp->osh, prevpkt) + pushed_len,
1667 PKTLEN(dhdp->osh, pkt));
1668 PKTFREE(dhdp->osh, pkt, FALSE);
1669 DHD_TRACE(("dhd_tcpack_suppress: pkt 0x%p"
1670 " TCP ACK replace %ud -> %ud\n", prevpkt,
1671 tcp_ack_info->tcpack_number, tcp_ack_num));
1672 tcp_ack_info->tcpack_number = tcp_ack_num;
1673 dhd_os_tcpackunlock(dhdp);
1676 DHD_TRACE(("dhd_tcpack_suppress: len mismatch"
1678 PKTLEN(dhdp->osh, pkt), ip_tcp_ttllen,
1679 PKTLEN(dhdp->osh, prevpkt),
1680 tcp_ack_info->ip_tcp_ttllen));
1683 void *prevpkt = tcp_ack_info->p_tcpackinqueue;
1685 DHD_TRACE(("dhd_tcpack_suppress: TCP ACK number reverse"
1686 " prev %ud (0x%p) new %ud (0x%p)\n",
1687 tcp_ack_info->tcpack_number,
1688 tcp_ack_info->p_tcpackinqueue,
1691 if (PKTLEN(dhdp->osh, pkt) == PKTLEN(dhdp->osh, prevpkt)) {
1692 PKTFREE(dhdp->osh, pkt, FALSE);
1693 dhd_os_tcpackunlock(dhdp);
1699 tcp_ack_info->p_tcpackinqueue = pkt;
1700 tcp_ack_info->tcpack_number = tcp_ack_num;
1701 tcp_ack_info->ip_tcp_ttllen = ip_tcp_ttllen;
1702 bcopy(&ip_header[12], tcp_ack_info->ipaddrs, 8);
1703 bcopy(tcp_header, tcp_ack_info->tcpports, 4);
1705 dhd_os_tcpackunlock(dhdp);
1707 DHD_TRACE(("dhd_tcpack_suppress: TCP ACK with DATA len %d\n",
1708 ip_tcp_ttllen - ip_hdr_len - tcp_hdr_len));
1712 #endif /* DHDTCPACK_SUPPRESS */
1713 /* Writes a HW/SW header into the packet and sends it. */
1714 /* Assumes: (a) header space already there, (b) caller holds lock */
1716 dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt, bool queue_only)
1721 uint16 len, pad1 = 0, act_len = 0;
1724 uint32 real_pad = 0;
1729 #ifdef BCMSDIOH_TXGLOM
1737 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1740 osh = bus->dhd->osh;
1742 #ifdef DHDTCPACK_SUPPRESS
1743 if (dhd_use_tcpack_suppress) {
1744 dhd_tcpack_check_xmit(bus->dhd, pkt);
1746 #endif /* DHDTCPACK_SUPPRESS */
1748 if (bus->dhd->dongle_reset) {
1749 ret = BCME_NOTREADY;
1753 frame = (uint8*)PKTDATA(osh, pkt);
1756 if (PKTLEN(osh, pkt) >= 100) {
1757 p = PKTDATA(osh, pkt);
1758 htsf_ts = (htsfts_t*) (p + HTSF_HOSTOFFSET + 12);
1759 if (htsf_ts->magic == HTSFMAGIC) {
1760 htsf_ts->c20 = get_cycles();
1761 htsf_ts->t20 = dhd_get_htsf(bus->dhd->info, 0);
1764 #endif /* WLMEDIA_HTSF */
1766 /* Add alignment padding, allocate new packet if needed */
1767 if ((pad1 = ((uintptr)frame % DHD_SDALIGN))) {
1768 if (PKTHEADROOM(osh, pkt) < pad1) {
1769 DHD_INFO(("%s: insufficient headroom %d for %d pad1\n",
1770 __FUNCTION__, (int)PKTHEADROOM(osh, pkt), pad1));
1771 bus->dhd->tx_realloc++;
1772 new = PKTGET(osh, (PKTLEN(osh, pkt) + DHD_SDALIGN), TRUE);
1774 DHD_ERROR(("%s: couldn't allocate new %d-byte packet\n",
1775 __FUNCTION__, PKTLEN(osh, pkt) + DHD_SDALIGN));
1780 PKTALIGN(osh, new, PKTLEN(osh, pkt), DHD_SDALIGN);
1781 bcopy(PKTDATA(osh, pkt), PKTDATA(osh, new), PKTLEN(osh, pkt));
1783 PKTFREE(osh, pkt, TRUE);
1784 /* free the pkt if canned one is not used */
1787 frame = (uint8*)PKTDATA(osh, pkt);
1788 ASSERT(((uintptr)frame % DHD_SDALIGN) == 0);
1791 PKTPUSH(osh, pkt, pad1);
1792 frame = (uint8*)PKTDATA(osh, pkt);
1794 ASSERT((pad1 + SDPCM_HDRLEN) <= (int) PKTLEN(osh, pkt));
1795 bzero(frame, pad1 + SDPCM_HDRLEN);
1798 ASSERT(pad1 < DHD_SDALIGN);
1800 /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
1801 len = (uint16)PKTLEN(osh, pkt);
1802 *(uint16*)frame = htol16(len);
1803 *(((uint16*)frame) + 1) = htol16(~len);
1805 #ifdef BCMSDIOH_TXGLOM
1806 if (bus->glom_enable) {
1807 uint32 hwheader1 = 0, hwheader2 = 0;
1810 /* Software tag: channel, sequence number, data offset */
1811 swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) |
1812 ((bus->tx_seq + bus->glom_cnt) % SDPCM_SEQUENCE_WRAP) |
1813 (((pad1 + SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
1814 htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN);
1815 htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN + sizeof(swheader));
1818 uint8 alignment = ALIGNMENT;
1819 if (forcealign && (len & (alignment - 1)))
1820 len = ROUNDUP(len, alignment);
1821 /* Hardware extention tag */
1822 /* 2byte frame length, 1byte-, 1byte frame flag,
1823 * 2byte-hdrlength, 2byte padlenght
1825 hwheader1 = (act_len - SDPCM_FRAMETAG_LEN) | (0 << 24);
1826 hwheader2 = (len - act_len) << 16;
1827 htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN);
1828 htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4);
1829 real_pad = len - act_len;
1830 if (PKTTAILROOM(osh, pkt) < real_pad) {
1831 DHD_INFO(("%s 1: insufficient tailroom %d for %d real_pad\n",
1832 __FUNCTION__, (int)PKTTAILROOM(osh, pkt), real_pad));
1833 if (PKTPADTAILROOM(osh, pkt, real_pad)) {
1834 DHD_ERROR(("CHK1: padding error size %d\n", real_pad));
1840 PKTSETLEN(osh, pkt, act_len);
1844 PKTSETLEN(osh, pkt, len);
1845 #endif /* BCMLXSDMMC */
1846 /* Post the frame pointer to sdio glom array */
1847 dhd_bcmsdh_glom_post(bus, frame, pkt, len);
1848 /* Save the pkt pointer in bus glom array */
1849 bus->glom_pkt_arr[bus->glom_cnt] = pkt;
1850 bus->glom_total_len += len;
1854 /* Raise len to next SDIO block to eliminate tail command */
1855 if (bus->roundup && bus->blocksize &&
1856 ((bus->glom_total_len + len) > bus->blocksize)) {
1857 uint16 pad2 = bus->blocksize -
1858 ((bus->glom_total_len + len) % bus->blocksize);
1859 if ((pad2 <= bus->roundup) && (pad2 < bus->blocksize)) {
1863 } else if ((bus->glom_total_len + len) % DHD_SDALIGN) {
1865 - ((bus->glom_total_len + len) % DHD_SDALIGN);
1867 if (forcealign && (len & (ALIGNMENT - 1))) {
1868 len = ROUNDUP(len, ALIGNMENT);
1871 /* Hardware extention tag */
1872 /* 2byte frame length, 1byte-, 1byte frame flag,
1873 * 2byte-hdrlength, 2byte padlenght
1875 hwheader1 = (act_len - SDPCM_FRAMETAG_LEN) | (1 << 24);
1876 hwheader2 = (len - act_len) << 16;
1877 htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN);
1878 htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4);
1879 real_pad = len - act_len;
1880 if (PKTTAILROOM(osh, pkt) < real_pad) {
1881 DHD_INFO(("%s 2: insufficient tailroom %d"
1882 " for %d real_pad\n",
1883 __FUNCTION__, (int)PKTTAILROOM(osh, pkt), real_pad));
1884 if (PKTPADTAILROOM(osh, pkt, real_pad)) {
1885 DHD_ERROR(("CHK2: padding error size %d."
1886 " %d more pkts are discarded together.\n",
1887 real_pad, bus->glom_cnt));
1888 /* Save the pkt pointer in bus glom array
1889 * Otherwise, this last pkt will not be
1890 * cleaned under "goto done"
1892 bus->glom_pkt_arr[bus->glom_cnt] = pkt;
1894 bus->glom_total_len += len;
1900 PKTSETLEN(osh, pkt, act_len);
1904 PKTSETLEN(osh, pkt, len);
1905 #endif /* BCMLXSDMMC */
1907 /* Post the frame pointer to sdio glom array */
1908 dhd_bcmsdh_glom_post(bus, frame, pkt, len);
1909 /* Save the pkt pointer in bus glom array */
1910 bus->glom_pkt_arr[bus->glom_cnt] = pkt;
1912 bus->glom_total_len += len;
1914 /* Update the total length on the first pkt */
1915 frame_tmp = (uint8*)PKTDATA(osh, bus->glom_pkt_arr[0]);
1916 *(uint16*)frame_tmp = htol16(bus->glom_total_len);
1917 *(((uint16*)frame_tmp) + 1) = htol16(~bus->glom_total_len);
1920 #endif /* BCMSDIOH_TXGLOM */
1923 /* Software tag: channel, sequence number, data offset */
1924 swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) | bus->tx_seq |
1925 (((pad1 + SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
1926 htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN);
1927 htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
1930 if (PKTPRIO(pkt) < ARRAYSIZE(tx_packets)) {
1931 tx_packets[PKTPRIO(pkt)]++;
1933 if (DHD_BYTES_ON() &&
1934 (((DHD_CTL_ON() && (chan == SDPCM_CONTROL_CHANNEL)) ||
1935 (DHD_DATA_ON() && (chan != SDPCM_CONTROL_CHANNEL))))) {
1936 prhex("Tx Frame", frame, len);
1937 } else if (DHD_HDRS_ON()) {
1938 prhex("TxHdr", frame, MIN(len, 16));
1942 /* Raise len to next SDIO block to eliminate tail command */
1943 if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
1944 uint16 pad2 = bus->blocksize - (len % bus->blocksize);
1945 if ((pad2 <= bus->roundup) && (pad2 < bus->blocksize))
1947 if (pad2 <= PKTTAILROOM(osh, pkt))
1948 #endif /* NOTUSED */
1950 } else if (len % DHD_SDALIGN) {
1951 len += DHD_SDALIGN - (len % DHD_SDALIGN);
1954 /* Some controllers have trouble with odd bytes -- round to even */
1955 if (forcealign && (len & (ALIGNMENT - 1))) {
1957 if (PKTTAILROOM(osh, pkt))
1959 len = ROUNDUP(len, ALIGNMENT);
1962 DHD_ERROR(("%s: sending unrounded %d-byte packet\n", __FUNCTION__, len));
1965 real_pad = len - act_len;
1966 if (PKTTAILROOM(osh, pkt) < real_pad) {
1967 DHD_INFO(("%s 3: insufficient tailroom %d for %d real_pad\n",
1968 __FUNCTION__, (int)PKTTAILROOM(osh, pkt), real_pad));
1969 if (PKTPADTAILROOM(osh, pkt, real_pad)) {
1970 DHD_ERROR(("CHK3: padding error size %d\n", real_pad));
1976 PKTSETLEN(osh, pkt, act_len);
1980 PKTSETLEN(osh, pkt, len);
1981 #endif /* BCMLXSDMMC */
1984 ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
1985 frame, len, pkt, NULL, NULL);
1987 ASSERT(ret != BCME_PENDING);
1989 if (ret == BCME_NODEVICE) {
1990 DHD_ERROR(("%s: Device asleep already\n", __FUNCTION__));
1991 } else if (ret < 0) {
1992 /* On failure, abort the command and terminate the frame */
1993 DHD_ERROR(("%s: sdio error %d, abort command and terminate frame.\n",
1994 __FUNCTION__, ret));
1997 bcmsdh_abort(sdh, SDIO_FUNC_2);
1998 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
2002 for (i = 0; i < 3; i++) {
2004 hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
2005 SBSDIO_FUNC1_WFRAMEBCHI, NULL);
2006 lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
2007 SBSDIO_FUNC1_WFRAMEBCLO, NULL);
2008 bus->f1regdata += 2;
2009 if ((hi == 0) && (lo == 0))
2014 #ifdef BCMSDIOH_TXGLOM
2015 if (bus->glom_enable) {
2016 bus->tx_seq = (bus->tx_seq + bus->glom_cnt) % SDPCM_SEQUENCE_WRAP;
2020 bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
2023 } while ((ret < 0) && retrydata && retries++ < TXRETRIES);
2027 #ifdef BCMSDIOH_TXGLOM
2028 if (bus->glom_enable && !queue_only) {
2029 dhd_bcmsdh_glom_clear(bus);
2030 pkt_cnt = bus->glom_cnt;
2036 /* restore pkt buffer pointer before calling tx complete routine */
2038 #ifdef BCMSDIOH_TXGLOM
2040 if (bus->glom_enable) {
2043 #endif /* BCMLXSDMMC */
2045 pkt = bus->glom_pkt_arr[bus->glom_cnt - pkt_cnt];
2047 frame = (uint8*)PKTDATA(osh, pkt);
2048 doff = ltoh32_ua(frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN);
2049 doff = (doff & SDPCM_DOFFSET_MASK) >> SDPCM_DOFFSET_SHIFT;
2051 pad2 = ltoh32_ua(frame + SDPCM_FRAMETAG_LEN + 4) >> 16;
2052 PKTSETLEN(osh, pkt, PKTLEN(osh, pkt) - pad2);
2053 #endif /* BCMLXSDMMC */
2054 PKTPULL(osh, pkt, doff);
2056 #endif /* BCMSDIOH_TXGLOM */
2060 PKTSETLEN(osh, pkt, act_len);
2061 #endif /* BCMLXSDMMC */
2062 PKTPULL(osh, pkt, SDPCM_HDRLEN + pad1);
2064 #ifdef PROP_TXSTATUS
2065 if (bus->dhd->wlfc_state) {
2066 dhd_os_sdunlock(bus->dhd);
2067 dhd_wlfc_txcomplete(bus->dhd, pkt, ret == 0);
2068 dhd_os_sdlock(bus->dhd);
2070 #endif /* PROP_TXSTATUS */
2072 if (chan != SDPCM_TEST_CHANNEL) {
2073 dhd_txcomplete(bus->dhd, pkt, ret != 0);
2076 dhd_txcomplete(bus->dhd, pkt, ret != 0);
2079 PKTFREE(osh, pkt, TRUE);
2081 #ifdef PROP_TXSTATUS
2087 #ifdef BCMSDIOH_TXGLOM
2088 /* Reset the glom array */
2089 if (bus->glom_enable && !queue_only) {
2091 bus->glom_total_len = 0;
2098 dhd_bus_txdata(struct dhd_bus *bus, void *pkt)
2100 int ret = BCME_ERROR;
2106 #ifdef DHD_TX_FULL_DUMP
2108 #endif /* DHD_TX_FULL_DUMP */
2109 #endif /* DHD_TX_DUMP */
2110 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2112 osh = bus->dhd->osh;
2113 datalen = PKTLEN(osh, pkt);
2116 /* Push the test header if doing loopback */
2117 if (bus->ext_loop) {
2119 PKTPUSH(osh, pkt, SDPCM_TEST_HDRLEN);
2120 data = PKTDATA(osh, pkt);
2121 *data++ = SDPCM_TEST_ECHOREQ;
2122 *data++ = (uint8)bus->loopid++;
2123 *data++ = (datalen >> 0);
2124 *data++ = (datalen >> 8);
2125 datalen += SDPCM_TEST_HDRLEN;
2130 dump_data = PKTDATA(osh, pkt);
2131 dump_data += 4; /* skip 4 bytes header */
2132 protocol = (dump_data[12] << 8) | dump_data[13];
2133 #ifdef DHD_TX_FULL_DUMP
2134 DHD_ERROR(("TX DUMP\n"));
2136 for (i = 0; i < (datalen - 4); i++) {
2137 DHD_ERROR(("%02X ", dump_data[i]));
2143 #endif /* DHD_TX_FULL_DUMP */
2144 if (protocol == ETHER_TYPE_802_1X) {
2145 DHD_ERROR(("ETHER_TYPE_802_1X: ver %d, type %d, replay %d\n",
2146 dump_data[14], dump_data[15], dump_data[30]));
2148 #endif /* DHD_TX_DUMP */
2150 /* Add space for the header */
2151 PKTPUSH(osh, pkt, SDPCM_HDRLEN);
2152 ASSERT(ISALIGNED((uintptr)PKTDATA(osh, pkt), 2));
2154 prec = PRIO2PREC((PKTPRIO(pkt) & PRIOMASK));
2156 /* Lock: we're about to use shared data/code (and SDIO) */
2157 dhd_os_sdlock(bus->dhd);
2158 #endif /* DHDTHREAD */
2160 /* Check for existing queue, current flow-control, pending event, or pending clock */
2161 if (dhd_deferred_tx || bus->fcstate || pktq_len(&bus->txq) || bus->dpc_sched ||
2162 (!DATAOK(bus)) || (bus->flowcontrol & NBITVAL(prec)) ||
2163 (bus->clkstate != CLK_AVAIL)) {
2164 DHD_TRACE(("%s: deferring pktq len %d\n", __FUNCTION__,
2165 pktq_len(&bus->txq)));
2168 /* Priority based enq */
2169 dhd_os_sdlock_txq(bus->dhd);
2170 if (dhd_prec_enq(bus->dhd, &bus->txq, pkt, prec) == FALSE) {
2171 PKTPULL(osh, pkt, SDPCM_HDRLEN);
2173 /* Need to also release txqlock before releasing sdlock.
2174 * This thread still has txqlock and releases sdlock.
2175 * Deadlock happens when dpc() grabs sdlock first then
2176 * attempts to grab txqlock.
2178 dhd_os_sdunlock_txq(bus->dhd);
2179 dhd_os_sdunlock(bus->dhd);
2181 #ifdef PROP_TXSTATUS
2182 if (bus->dhd->wlfc_state)
2183 dhd_wlfc_txcomplete(bus->dhd, pkt, FALSE);
2186 dhd_txcomplete(bus->dhd, pkt, FALSE);
2188 dhd_os_sdlock(bus->dhd);
2189 dhd_os_sdlock_txq(bus->dhd);
2191 #ifdef PROP_TXSTATUS
2192 /* let the caller decide whether to free the packet */
2193 if (!bus->dhd->wlfc_state)
2195 PKTFREE(osh, pkt, TRUE);
2196 ret = BCME_NORESOURCE;
2201 if ((pktq_len(&bus->txq) >= FCHI) && dhd_doflow)
2202 dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON);
2205 if (pktq_plen(&bus->txq, prec) > qcount[prec])
2206 qcount[prec] = pktq_plen(&bus->txq, prec);
2208 dhd_os_sdunlock_txq(bus->dhd);
2210 /* Schedule DPC if needed to send queued packet(s) */
2211 if (dhd_deferred_tx && !bus->dpc_sched) {
2212 bus->dpc_sched = TRUE;
2213 dhd_sched_dpc(bus->dhd);
2217 /* Lock: we're about to use shared data/code (and SDIO) */
2218 dhd_os_sdlock(bus->dhd);
2219 #endif /* DHDTHREAD */
2221 /* Otherwise, send it now */
2223 /* Make sure back plane ht clk is on, no pending allowed */
2224 dhdsdio_clkctl(bus, CLK_AVAIL, TRUE);
2226 ret = dhdsdio_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, TRUE, FALSE);
2228 ret = dhdsdio_txpkt(bus, pkt,
2229 (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL), TRUE, FALSE);
2232 bus->dhd->tx_errors++;
2234 bus->dhd->dstats.tx_bytes += datalen;
2236 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
2237 bus->activity = FALSE;
2238 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
2242 dhd_os_sdunlock(bus->dhd);
2243 #endif /* DHDTHREAD */
2247 dhd_os_sdunlock(bus->dhd);
2248 #endif /* DHDTHREAD */
2254 dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes)
2257 uint32 intstatus = 0;
2259 int ret = 0, prec_out;
2263 uint16 txpktqlen = 0;
2264 #ifdef BCMSDIOH_TXGLOM
2269 dhd_pub_t *dhd = bus->dhd;
2270 sdpcmd_regs_t *regs = bus->regs;
2272 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2274 if (!KSO_ENAB(bus)) {
2275 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
2276 return BCME_NODEVICE;
2279 tx_prec_map = ~bus->flowcontrol;
2281 /* Send frames until the limit or some other event */
2282 for (cnt = 0; (cnt < maxframes) && DATAOK(bus); cnt++) {
2283 #ifdef BCMSDIOH_TXGLOM
2284 if (bus->glom_enable) {
2285 void *pkttable[SDPCM_MAXGLOM_SIZE];
2286 dhd_os_sdlock_txq(bus->dhd);
2287 glom_cnt = MIN(DATABUFCNT(bus), bus->glomsize);
2288 glom_cnt = MIN(glom_cnt, pktq_mlen(&bus->txq, tx_prec_map));
2289 glom_cnt = MIN(glom_cnt, maxframes-cnt);
2291 /* Limiting the size to 2pkts in case of copy */
2292 if (bus->glom_mode == SDPCM_TXGLOM_CPY)
2293 glom_cnt = MIN(glom_cnt, 10);
2295 for (i = 0; i < glom_cnt; i++)
2296 pkttable[i] = pktq_mdeq(&bus->txq, tx_prec_map, &prec_out);
2298 txpktqlen = pktq_len(&bus->txq);
2299 dhd_os_sdunlock_txq(bus->dhd);
2304 for (i = 0; i < glom_cnt; i++) {
2305 uint datalen_tmp = 0;
2307 if ((pkt = pkttable[i]) == NULL) {
2308 /* This case should not happen */
2309 DHD_ERROR(("No pkts in the queue for glomming\n"));
2313 datalen_tmp = (PKTLEN(bus->dhd->osh, pkt) - SDPCM_HDRLEN);
2316 ret = dhdsdio_txpkt(bus,
2320 (i == (glom_cnt-1))? FALSE: TRUE);
2322 ret = dhdsdio_txpkt(bus,
2324 (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL),
2326 (i == (glom_cnt-1))? FALSE: TRUE);
2329 datalen += datalen_tmp;
2333 #endif /* BCMSDIOH_TXGLOM */
2335 dhd_os_sdlock_txq(bus->dhd);
2336 if ((pkt = pktq_mdeq(&bus->txq, tx_prec_map, &prec_out)) == NULL) {
2337 txpktqlen = pktq_len(&bus->txq);
2338 dhd_os_sdunlock_txq(bus->dhd);
2341 txpktqlen = pktq_len(&bus->txq);
2342 dhd_os_sdunlock_txq(bus->dhd);
2343 datalen = PKTLEN(bus->dhd->osh, pkt) - SDPCM_HDRLEN;
2346 ret = dhdsdio_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, TRUE, FALSE);
2348 ret = dhdsdio_txpkt(bus,
2350 (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL),
2357 bus->dhd->tx_errors++;
2359 bus->dhd->dstats.tx_bytes += datalen;
2361 /* In poll mode, need to check for other events */
2362 if (!bus->intr && cnt)
2364 /* Check device status, signal pending interrupt */
2365 R_SDREG(intstatus, ®s->intstatus, retries);
2367 if (bcmsdh_regfail(bus->sdh))
2369 if (intstatus & bus->hostintmask)
2374 /* Deflow-control stack if needed */
2375 if (dhd_doflow && dhd->up && (dhd->busstate == DHD_BUS_DATA) &&
2376 dhd->txoff && (txpktqlen < FCLOW))
2377 dhd_txflowcontrol(dhd, ALL_INTERFACES, OFF);
2383 dhdsdio_sendpendctl(dhd_bus_t *bus)
2385 bcmsdh_info_t *sdh = bus->sdh;
2387 uint8* frame_seq = bus->ctrl_frame_buf + SDPCM_FRAMETAG_LEN;
2389 #ifdef BCMSDIOH_TXGLOM
2390 if (bus->glom_enable)
2391 frame_seq += SDPCM_HWEXT_LEN;
2394 if (*frame_seq != bus->tx_seq) {
2395 DHD_INFO(("%s IOCTL frame seq lag detected!"
2396 " frm_seq:%d != bus->tx_seq:%d, corrected\n",
2397 __FUNCTION__, *frame_seq, bus->tx_seq));
2398 *frame_seq = bus->tx_seq;
2401 ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
2402 (uint8 *)bus->ctrl_frame_buf, (uint32)bus->ctrl_frame_len,
2404 ASSERT(ret != BCME_PENDING);
2405 if (ret == BCME_NODEVICE) {
2406 DHD_ERROR(("%s: Device asleep already\n", __FUNCTION__));
2407 } else if (ret < 0) {
2408 /* On failure, abort the command and terminate the frame */
2409 DHD_INFO(("%s: sdio error %d, abort command and terminate frame.\n",
2410 __FUNCTION__, ret));
2413 bcmsdh_abort(sdh, SDIO_FUNC_2);
2415 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
2419 for (i = 0; i < 3; i++) {
2421 hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
2422 SBSDIO_FUNC1_WFRAMEBCHI, NULL);
2423 lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
2424 SBSDIO_FUNC1_WFRAMEBCLO, NULL);
2425 bus->f1regdata += 2;
2426 if ((hi == 0) && (lo == 0))
2431 bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
2434 bus->ctrl_frame_stat = FALSE;
2435 dhd_wait_event_wakeup(bus->dhd);
2439 dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen)
2445 bcmsdh_info_t *sdh = bus->sdh;
2450 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2452 if (bus->dhd->dongle_reset)
2455 /* Back the pointer to make a room for bus header */
2456 frame = msg - SDPCM_HDRLEN;
2457 len = (msglen += SDPCM_HDRLEN);
2459 /* Add alignment padding (optional for ctl frames) */
2461 if ((doff = ((uintptr)frame % DHD_SDALIGN))) {
2465 bzero(frame, doff + SDPCM_HDRLEN);
2467 ASSERT(doff < DHD_SDALIGN);
2469 doff += SDPCM_HDRLEN;
2471 /* Round send length to next SDIO block */
2472 if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
2473 uint16 pad = bus->blocksize - (len % bus->blocksize);
2474 if ((pad <= bus->roundup) && (pad < bus->blocksize))
2476 } else if (len % DHD_SDALIGN) {
2477 len += DHD_SDALIGN - (len % DHD_SDALIGN);
2480 /* Satisfy length-alignment requirements */
2481 if (forcealign && (len & (ALIGNMENT - 1)))
2482 len = ROUNDUP(len, ALIGNMENT);
2484 ASSERT(ISALIGNED((uintptr)frame, 2));
2487 /* Need to lock here to protect txseq and SDIO tx calls */
2488 dhd_os_sdlock(bus->dhd);
2492 /* Make sure backplane clock is on */
2493 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
2495 /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
2496 *(uint16*)frame = htol16((uint16)msglen);
2497 *(((uint16*)frame) + 1) = htol16(~msglen);
2499 #ifdef BCMSDIOH_TXGLOM
2500 if (bus->glom_enable) {
2501 uint32 hwheader1, hwheader2;
2502 /* Software tag: channel, sequence number, data offset */
2503 swheader = ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK)
2505 | ((doff << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
2506 htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN);
2507 htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN
2508 + SDPCM_HWEXT_LEN + sizeof(swheader));
2510 hwheader1 = (msglen - SDPCM_FRAMETAG_LEN) | (1 << 24);
2511 hwheader2 = (len - (msglen)) << 16;
2512 htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN);
2513 htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4);
2515 *(uint16*)frame = htol16(len);
2516 *(((uint16*)frame) + 1) = htol16(~(len));
2518 #endif /* BCMSDIOH_TXGLOM */
2520 /* Software tag: channel, sequence number, data offset */
2521 swheader = ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK)
2522 | bus->tx_seq | ((doff << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
2523 htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN);
2524 htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
2526 if (!TXCTLOK(bus)) {
2527 DHD_INFO(("%s: No bus credit bus->tx_max %d, bus->tx_seq %d\n",
2528 __FUNCTION__, bus->tx_max, bus->tx_seq));
2529 bus->ctrl_frame_stat = TRUE;
2531 bus->ctrl_frame_buf = frame;
2532 bus->ctrl_frame_len = len;
2534 if (!bus->dpc_sched) {
2535 bus->dpc_sched = TRUE;
2536 dhd_sched_dpc(bus->dhd);
2538 if (bus->ctrl_frame_stat) {
2539 dhd_wait_for_event(bus->dhd, &bus->ctrl_frame_stat);
2542 if (bus->ctrl_frame_stat == FALSE) {
2543 DHD_INFO(("%s: ctrl_frame_stat == FALSE\n", __FUNCTION__));
2546 bus->dhd->txcnt_timeout++;
2547 if (!bus->dhd->hang_was_sent) {
2548 DHD_ERROR(("%s: ctrl_frame_stat == TRUE txcnt_timeout=%d\n",
2549 __FUNCTION__, bus->dhd->txcnt_timeout));
2552 bus->ctrl_frame_stat = FALSE;
2557 bus->dhd->txcnt_timeout = 0;
2561 if (DHD_BYTES_ON() && DHD_CTL_ON()) {
2562 prhex("Tx Frame", frame, len);
2563 } else if (DHD_HDRS_ON()) {
2564 prhex("TxHdr", frame, MIN(len, 16));
2569 ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
2570 frame, len, NULL, NULL, NULL);
2571 ASSERT(ret != BCME_PENDING);
2573 if (ret == BCME_NODEVICE) {
2574 DHD_ERROR(("%s: Device asleep already\n", __FUNCTION__));
2575 } else if (ret < 0) {
2576 /* On failure, abort the command and terminate the frame */
2577 DHD_INFO(("%s: sdio error %d, abort command and terminate frame.\n",
2578 __FUNCTION__, ret));
2581 bcmsdh_abort(sdh, SDIO_FUNC_2);
2583 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
2587 for (i = 0; i < 3; i++) {
2589 hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
2590 SBSDIO_FUNC1_WFRAMEBCHI, NULL);
2591 lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
2592 SBSDIO_FUNC1_WFRAMEBCLO, NULL);
2593 bus->f1regdata += 2;
2594 if ((hi == 0) && (lo == 0))
2599 bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
2601 } while ((ret < 0) && retries++ < TXRETRIES);
2605 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
2606 bus->activity = FALSE;
2607 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
2610 dhd_os_sdunlock(bus->dhd);
2613 bus->dhd->tx_ctlerrs++;
2615 bus->dhd->tx_ctlpkts++;
2617 if (bus->dhd->txcnt_timeout >= MAX_CNTL_TX_TIMEOUT)
2620 return ret ? -EIO : 0;
2624 dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen)
2630 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2632 if (bus->dhd->dongle_reset)
2635 /* Wait until control frame is available */
2636 timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->rxlen, &pending);
2638 dhd_os_sdlock(bus->dhd);
2640 bcopy(bus->rxctl, msg, MIN(msglen, rxlen));
2642 dhd_os_sdunlock(bus->dhd);
2645 DHD_CTL(("%s: resumed on rxctl frame, got %d expected %d\n",
2646 __FUNCTION__, rxlen, msglen));
2647 } else if (timeleft == 0) {
2649 uint32 status, retry = 0;
2650 R_SDREG(status, &bus->regs->intstatus, retry);
2651 DHD_ERROR(("%s: resumed on timeout, INT status=0x%08X\n",
2652 __FUNCTION__, status));
2654 DHD_ERROR(("%s: resumed on timeout\n", __FUNCTION__));
2655 #endif /* DHD_DEBUG */
2657 dhd_os_sdlock(bus->dhd);
2658 dhdsdio_checkdied(bus, NULL, 0);
2659 dhd_os_sdunlock(bus->dhd);
2660 #endif /* DHD_DEBUG */
2661 } else if (pending == TRUE) {
2662 /* signal pending */
2663 DHD_ERROR(("%s: signal pending\n", __FUNCTION__));
2666 DHD_CTL(("%s: resumed for unknown reason?\n", __FUNCTION__));
2668 dhd_os_sdlock(bus->dhd);
2669 dhdsdio_checkdied(bus, NULL, 0);
2670 dhd_os_sdunlock(bus->dhd);
2671 #endif /* DHD_DEBUG */
2673 if (timeleft == 0) {
2675 bus->dhd->rxcnt_timeout++;
2676 DHD_ERROR(("%s: rxcnt_timeout=%d, rxlen=%d\n", __FUNCTION__,
2677 bus->dhd->rxcnt_timeout, rxlen));
2680 bus->dhd->rxcnt_timeout = 0;
2683 bus->dhd->rx_ctlpkts++;
2685 bus->dhd->rx_ctlerrs++;
2687 if (bus->dhd->rxcnt_timeout >= MAX_CNTL_RX_TIMEOUT)
2690 if (bus->dhd->dongle_trap_occured)
2693 return rxlen ? (int)rxlen : -EIO;
2709 #endif /* DHD_DEBUG */
2710 IOV_SET_DOWNLOAD_STATE,
2720 #if defined(SDIO_CRC_ERROR_FIX)
2723 #endif /* SDIO_CRC_ERROR_FIX */
2736 IOV_DONGLEISOLATION,
2749 const bcm_iovar_t dhdsdio_iovars[] = {
2750 {"intr", IOV_INTR, 0, IOVT_BOOL, 0 },
2751 {"sleep", IOV_SLEEP, 0, IOVT_BOOL, 0 },
2752 {"pollrate", IOV_POLLRATE, 0, IOVT_UINT32, 0 },
2753 {"idletime", IOV_IDLETIME, 0, IOVT_INT32, 0 },
2754 {"idleclock", IOV_IDLECLOCK, 0, IOVT_INT32, 0 },
2755 {"sd1idle", IOV_SD1IDLE, 0, IOVT_BOOL, 0 },
2756 {"membytes", IOV_MEMBYTES, 0, IOVT_BUFFER, 2 * sizeof(int) },
2757 {"ramsize", IOV_RAMSIZE, 0, IOVT_UINT32, 0 },
2758 {"ramstart", IOV_RAMSTART, 0, IOVT_UINT32, 0 },
2759 {"dwnldstate", IOV_SET_DOWNLOAD_STATE, 0, IOVT_BOOL, 0 },
2760 {"socram_state", IOV_SOCRAM_STATE, 0, IOVT_BOOL, 0 },
2761 {"vars", IOV_VARS, 0, IOVT_BUFFER, 0 },
2762 {"sdiod_drive", IOV_SDIOD_DRIVE, 0, IOVT_UINT32, 0 },
2763 {"readahead", IOV_READAHEAD, 0, IOVT_BOOL, 0 },
2764 {"sdrxchain", IOV_SDRXCHAIN, 0, IOVT_BOOL, 0 },
2765 {"alignctl", IOV_ALIGNCTL, 0, IOVT_BOOL, 0 },
2766 {"sdalign", IOV_SDALIGN, 0, IOVT_BOOL, 0 },
2767 {"devreset", IOV_DEVRESET, 0, IOVT_BOOL, 0 },
2769 {"sdreg", IOV_SDREG, 0, IOVT_BUFFER, sizeof(sdreg_t) },
2770 {"sbreg", IOV_SBREG, 0, IOVT_BUFFER, sizeof(sdreg_t) },
2771 {"sd_cis", IOV_SDCIS, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN },
2772 {"forcealign", IOV_FORCEEVEN, 0, IOVT_BOOL, 0 },
2773 {"txbound", IOV_TXBOUND, 0, IOVT_UINT32, 0 },
2774 {"rxbound", IOV_RXBOUND, 0, IOVT_UINT32, 0 },
2775 {"txminmax", IOV_TXMINMAX, 0, IOVT_UINT32, 0 },
2776 {"cpu", IOV_CPU, 0, IOVT_BOOL, 0 },
2778 {"checkdied", IOV_CHECKDIED, 0, IOVT_BUFFER, 0 },
2779 {"serial", IOV_SERIALCONS, 0, IOVT_UINT32, 0 },
2780 #endif /* DHD_DEBUG */
2781 #endif /* DHD_DEBUG */
2783 {"extloop", IOV_EXTLOOP, 0, IOVT_BOOL, 0 },
2784 {"pktgen", IOV_PKTGEN, 0, IOVT_BUFFER, sizeof(dhd_pktgen_t) },
2786 #if defined(SDIO_CRC_ERROR_FIX)
2787 {"watermark", IOV_WATERMARK, 0, IOVT_UINT32, 0 },
2788 {"mesbusyctrl", IOV_MESBUSYCTRL, 0, IOVT_UINT32, 0 },
2789 #endif /* SDIO_CRC_ERROR_FIX */
2790 {"devcap", IOV_DEVCAP, 0, IOVT_UINT32, 0 },
2791 {"dngl_isolation", IOV_DONGLEISOLATION, 0, IOVT_UINT32, 0 },
2792 {"kso", IOV_KSO, 0, IOVT_UINT32, 0 },
2793 {"devsleep", IOV_DEVSLEEP, 0, IOVT_UINT32, 0 },
2795 {"fwpath", IOV_FWPATH, 0, IOVT_BUFFER, 0 },
2797 {"txglomsize", IOV_TXGLOMSIZE, 0, IOVT_UINT32, 0 },
2798 {"txglommode", IOV_TXGLOMMODE, 0, IOVT_UINT32, 0 },
2799 {"fw_hang_report", IOV_HANGREPORT, 0, IOVT_BOOL, 0 },
2804 dhd_dump_pct(struct bcmstrbuf *strbuf, char *desc, uint num, uint div)
2809 bcm_bprintf(strbuf, "%s N/A", desc);
2812 q2 = (100 * (num - (q1 * div))) / div;
2813 bcm_bprintf(strbuf, "%s %d.%02d", desc, q1, q2);
2818 dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf)
2820 dhd_bus_t *bus = dhdp->bus;
2822 bcm_bprintf(strbuf, "Bus SDIO structure:\n");
2823 bcm_bprintf(strbuf, "hostintmask 0x%08x intstatus 0x%08x sdpcm_ver %d\n",
2824 bus->hostintmask, bus->intstatus, bus->sdpcm_ver);
2825 bcm_bprintf(strbuf, "fcstate %d qlen %u tx_seq %d, max %d, rxskip %d rxlen %u rx_seq %d\n",
2826 bus->fcstate, pktq_len(&bus->txq), bus->tx_seq, bus->tx_max, bus->rxskip,
2827 bus->rxlen, bus->rx_seq);
2828 bcm_bprintf(strbuf, "intr %d intrcount %u lastintrs %u spurious %u\n",
2829 bus->intr, bus->intrcount, bus->lastintrs, bus->spurious);
2830 bcm_bprintf(strbuf, "pollrate %u pollcnt %u regfails %u\n",
2831 bus->pollrate, bus->pollcnt, bus->regfails);
2833 bcm_bprintf(strbuf, "\nAdditional counters:\n");
2834 bcm_bprintf(strbuf, "tx_sderrs %u fcqueued %u rxrtx %u rx_toolong %u rxc_errors %u\n",
2835 bus->tx_sderrs, bus->fcqueued, bus->rxrtx, bus->rx_toolong,
2837 bcm_bprintf(strbuf, "rx_hdrfail %u badhdr %u badseq %u\n",
2838 bus->rx_hdrfail, bus->rx_badhdr, bus->rx_badseq);
2839 bcm_bprintf(strbuf, "fc_rcvd %u, fc_xoff %u, fc_xon %u\n",
2840 bus->fc_rcvd, bus->fc_xoff, bus->fc_xon);
2841 bcm_bprintf(strbuf, "rxglomfail %u, rxglomframes %u, rxglompkts %u\n",
2842 bus->rxglomfail, bus->rxglomframes, bus->rxglompkts);
2843 bcm_bprintf(strbuf, "f2rx (hdrs/data) %u (%u/%u), f2tx %u f1regs %u\n",
2844 (bus->f2rxhdrs + bus->f2rxdata), bus->f2rxhdrs, bus->f2rxdata,
2845 bus->f2txdata, bus->f1regdata);
2847 dhd_dump_pct(strbuf, "\nRx: pkts/f2rd", bus->dhd->rx_packets,
2848 (bus->f2rxhdrs + bus->f2rxdata));
2849 dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->rx_packets, bus->f1regdata);
2850 dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->rx_packets,
2851 (bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata));
2852 dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->rx_packets, bus->intrcount);
2853 bcm_bprintf(strbuf, "\n");
2855 dhd_dump_pct(strbuf, "Rx: glom pct", (100 * bus->rxglompkts),
2856 bus->dhd->rx_packets);
2857 dhd_dump_pct(strbuf, ", pkts/glom", bus->rxglompkts, bus->rxglomframes);
2858 bcm_bprintf(strbuf, "\n");
2860 dhd_dump_pct(strbuf, "Tx: pkts/f2wr", bus->dhd->tx_packets, bus->f2txdata);
2861 dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->tx_packets, bus->f1regdata);
2862 dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->tx_packets,
2863 (bus->f2txdata + bus->f1regdata));
2864 dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->tx_packets, bus->intrcount);
2865 bcm_bprintf(strbuf, "\n");
2867 dhd_dump_pct(strbuf, "Total: pkts/f2rw",
2868 (bus->dhd->tx_packets + bus->dhd->rx_packets),
2869 (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata));
2870 dhd_dump_pct(strbuf, ", pkts/f1sd",
2871 (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->f1regdata);
2872 dhd_dump_pct(strbuf, ", pkts/sd",
2873 (bus->dhd->tx_packets + bus->dhd->rx_packets),
2874 (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata));
2875 dhd_dump_pct(strbuf, ", pkts/int",
2876 (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->intrcount);
2877 bcm_bprintf(strbuf, "\n\n");
2881 if (bus->pktgen_count) {
2882 bcm_bprintf(strbuf, "pktgen config and count:\n");
2883 bcm_bprintf(strbuf, "freq %u count %u print %u total %u min %u len %u\n",
2884 bus->pktgen_freq, bus->pktgen_count, bus->pktgen_print,
2885 bus->pktgen_total, bus->pktgen_minlen, bus->pktgen_maxlen);
2886 bcm_bprintf(strbuf, "send attempts %u rcvd %u fail %u\n",
2887 bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail);
2891 bcm_bprintf(strbuf, "dpc_sched %d host interrupt%spending\n",
2892 bus->dpc_sched, (bcmsdh_intr_pending(bus->sdh) ? " " : " not "));
2893 bcm_bprintf(strbuf, "blocksize %u roundup %u\n", bus->blocksize, bus->roundup);
2894 #endif /* DHD_DEBUG */
2895 bcm_bprintf(strbuf, "clkstate %d activity %d idletime %d idlecount %d sleeping %d\n",
2896 bus->clkstate, bus->activity, bus->idletime, bus->idlecount, bus->sleeping);
2900 dhd_bus_clearcounts(dhd_pub_t *dhdp)
2902 dhd_bus_t *bus = (dhd_bus_t *)dhdp->bus;
2904 bus->intrcount = bus->lastintrs = bus->spurious = bus->regfails = 0;
2905 bus->rxrtx = bus->rx_toolong = bus->rxc_errors = 0;
2906 bus->rx_hdrfail = bus->rx_badhdr = bus->rx_badseq = 0;
2907 bus->tx_sderrs = bus->fc_rcvd = bus->fc_xoff = bus->fc_xon = 0;
2908 bus->rxglomfail = bus->rxglomframes = bus->rxglompkts = 0;
2909 bus->f2rxhdrs = bus->f2rxdata = bus->f2txdata = bus->f1regdata = 0;
2914 dhdsdio_pktgen_get(dhd_bus_t *bus, uint8 *arg)
2916 dhd_pktgen_t pktgen;
2918 pktgen.version = DHD_PKTGEN_VERSION;
2919 pktgen.freq = bus->pktgen_freq;
2920 pktgen.count = bus->pktgen_count;
2921 pktgen.print = bus->pktgen_print;
2922 pktgen.total = bus->pktgen_total;
2923 pktgen.minlen = bus->pktgen_minlen;
2924 pktgen.maxlen = bus->pktgen_maxlen;
2925 pktgen.numsent = bus->pktgen_sent;
2926 pktgen.numrcvd = bus->pktgen_rcvd;
2927 pktgen.numfail = bus->pktgen_fail;
2928 pktgen.mode = bus->pktgen_mode;
2929 pktgen.stop = bus->pktgen_stop;
2931 bcopy(&pktgen, arg, sizeof(pktgen));
2937 dhdsdio_pktgen_set(dhd_bus_t *bus, uint8 *arg)
2939 dhd_pktgen_t pktgen;
2940 uint oldcnt, oldmode;
2942 bcopy(arg, &pktgen, sizeof(pktgen));
2943 if (pktgen.version != DHD_PKTGEN_VERSION)
2946 oldcnt = bus->pktgen_count;
2947 oldmode = bus->pktgen_mode;
2949 bus->pktgen_freq = pktgen.freq;
2950 bus->pktgen_count = pktgen.count;
2951 bus->pktgen_print = pktgen.print;
2952 bus->pktgen_total = pktgen.total;
2953 bus->pktgen_minlen = pktgen.minlen;
2954 bus->pktgen_maxlen = pktgen.maxlen;
2955 bus->pktgen_mode = pktgen.mode;
2956 bus->pktgen_stop = pktgen.stop;
2958 bus->pktgen_tick = bus->pktgen_ptick = 0;
2959 bus->pktgen_prev_time = jiffies;
2960 bus->pktgen_len = MAX(bus->pktgen_len, bus->pktgen_minlen);
2961 bus->pktgen_len = MIN(bus->pktgen_len, bus->pktgen_maxlen);
2963 /* Clear counts for a new pktgen (mode change, or was stopped) */
2964 if (bus->pktgen_count && (!oldcnt || oldmode != bus->pktgen_mode)) {
2965 bus->pktgen_sent = bus->pktgen_prev_sent = bus->pktgen_rcvd = 0;
2966 bus->pktgen_prev_rcvd = bus->pktgen_fail = 0;
2974 dhdsdio_devram_remap(dhd_bus_t *bus, bool val)
2976 uint8 enable, protect, remap;
2978 si_socdevram(bus->sih, FALSE, &enable, &protect, &remap);
2979 remap = val ? TRUE : FALSE;
2980 si_socdevram(bus->sih, TRUE, &enable, &protect, &remap);
2984 dhdsdio_membytes(dhd_bus_t *bus, bool write, uint32 address, uint8 *data, uint size)
2990 /* In remap mode, adjust address beyond socram and redirect
2991 * to devram at SOCDEVRAM_BP_ADDR since remap address > orig_ramsize
2992 * is not backplane accessible
2994 if (REMAP_ENAB(bus) && REMAP_ISADDR(bus, address)) {
2995 address -= bus->orig_ramsize;
2996 address += SOCDEVRAM_BP_ADDR;
2999 /* Determine initial transfer parameters */
3000 sdaddr = address & SBSDIO_SB_OFT_ADDR_MASK;
3001 if ((sdaddr + size) & SBSDIO_SBWINDOW_MASK)
3002 dsize = (SBSDIO_SB_OFT_ADDR_LIMIT - sdaddr);
3006 /* Set the backplane window to include the start address */
3007 if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) {
3008 DHD_ERROR(("%s: window change failed\n", __FUNCTION__));
3012 /* Do the transfer(s) */
3014 DHD_INFO(("%s: %s %d bytes at offset 0x%08x in window 0x%08x\n",
3015 __FUNCTION__, (write ? "write" : "read"), dsize, sdaddr,
3016 (address & SBSDIO_SBWINDOW_MASK)));
3017 if ((bcmerror = bcmsdh_rwdata(bus->sdh, write, sdaddr, data, dsize))) {
3018 DHD_ERROR(("%s: membytes transfer failed\n", __FUNCTION__));
3022 /* Adjust for next transfer (if any) */
3023 if ((size -= dsize)) {
3026 if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) {
3027 DHD_ERROR(("%s: window change failed\n", __FUNCTION__));
3031 dsize = MIN(SBSDIO_SB_OFT_ADDR_LIMIT, size);
3037 /* Return the window to backplane enumeration space for core access */
3038 if (dhdsdio_set_siaddr_window(bus, bcmsdh_cur_sbwad(bus->sdh))) {
3039 DHD_ERROR(("%s: FAILED to set window back to 0x%x\n", __FUNCTION__,
3040 bcmsdh_cur_sbwad(bus->sdh)));
3048 dhdsdio_readshared(dhd_bus_t *bus, sdpcm_shared_t *sh)
3054 shaddr = bus->dongle_ram_base + bus->ramsize - 4;
3057 /* Read last word in memory to determine address of sdpcm_shared structure */
3058 if ((rv = dhdsdio_membytes(bus, FALSE, shaddr, (uint8 *)&addr, 4)) < 0)
3061 addr = ltoh32(addr);
3063 DHD_INFO(("sdpcm_shared address 0x%08X\n", addr));
3066 * Check if addr is valid.
3067 * NVRAM length at the end of memory should have been overwritten.
3069 if (addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff)) {
3070 if ((bus->srmemsize > 0) && (i++ == 0)) {
3071 shaddr -= bus->srmemsize;
3073 DHD_ERROR(("%s: address (0x%08x) of sdpcm_shared invalid\n",
3074 __FUNCTION__, addr));
3081 /* Read hndrte_shared structure */
3082 if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)sh, sizeof(sdpcm_shared_t))) < 0)
3086 sh->flags = ltoh32(sh->flags);
3087 sh->trap_addr = ltoh32(sh->trap_addr);
3088 sh->assert_exp_addr = ltoh32(sh->assert_exp_addr);
3089 sh->assert_file_addr = ltoh32(sh->assert_file_addr);
3090 sh->assert_line = ltoh32(sh->assert_line);
3091 sh->console_addr = ltoh32(sh->console_addr);
3092 sh->msgtrace_addr = ltoh32(sh->msgtrace_addr);
3094 if ((sh->flags & SDPCM_SHARED_VERSION_MASK) == 3 && SDPCM_SHARED_VERSION == 1)
3097 if ((sh->flags & SDPCM_SHARED_VERSION_MASK) != SDPCM_SHARED_VERSION) {
3098 DHD_ERROR(("%s: sdpcm_shared version %d in dhd "
3099 "is different than sdpcm_shared version %d in dongle\n",
3100 __FUNCTION__, SDPCM_SHARED_VERSION,
3101 sh->flags & SDPCM_SHARED_VERSION_MASK));
3108 #define CONSOLE_LINE_MAX 192
3111 dhdsdio_readconsole(dhd_bus_t *bus)
3113 dhd_console_t *c = &bus->console;
3114 uint8 line[CONSOLE_LINE_MAX], ch;
3115 uint32 n, idx, addr;
3118 /* Don't do anything until FWREADY updates console address */
3119 if (bus->console_addr == 0)
3125 /* Read console log struct */
3126 addr = bus->console_addr + OFFSETOF(hndrte_cons_t, log);
3127 if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)&c->log, sizeof(c->log))) < 0)
3130 /* Allocate console buffer (one time only) */
3131 if (c->buf == NULL) {
3132 c->bufsize = ltoh32(c->log.buf_size);
3133 if ((c->buf = MALLOC(bus->dhd->osh, c->bufsize)) == NULL)
3137 idx = ltoh32(c->log.idx);
3139 /* Protect against corrupt value */
3140 if (idx > c->bufsize)
3143 /* Skip reading the console buffer if the index pointer has not moved */
3147 /* Read the console buffer */
3148 addr = ltoh32(c->log.buf);
3149 if ((rv = dhdsdio_membytes(bus, FALSE, addr, c->buf, c->bufsize)) < 0)
3152 while (c->last != idx) {
3153 for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) {
3154 if (c->last == idx) {
3155 /* This would output a partial line. Instead, back up
3156 * the buffer pointer and output this line next time around.
3161 c->last = c->bufsize - n;
3164 ch = c->buf[c->last];
3165 c->last = (c->last + 1) % c->bufsize;
3172 if (line[n - 1] == '\r')
3175 printf("CONSOLE: %s\n", line);
3184 dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size)
3188 char *mbuffer = NULL;
3189 char *console_buffer = NULL;
3190 uint maxstrlen = 256;
3193 sdpcm_shared_t sdpcm_shared;
3194 struct bcmstrbuf strbuf;
3195 uint32 console_ptr, console_size, console_index;
3196 uint8 line[CONSOLE_LINE_MAX], ch;
3200 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3202 if (DHD_NOCHECKDIED_ON())
3207 * Called after a rx ctrl timeout. "data" is NULL.
3208 * allocate memory to trace the trap or assert.
3211 mbuffer = data = MALLOC(bus->dhd->osh, msize);
3212 if (mbuffer == NULL) {
3213 DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, msize));
3214 bcmerror = BCME_NOMEM;
3219 if ((str = MALLOC(bus->dhd->osh, maxstrlen)) == NULL) {
3220 DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, maxstrlen));
3221 bcmerror = BCME_NOMEM;
3225 if ((bcmerror = dhdsdio_readshared(bus, &sdpcm_shared)) < 0)
3228 bcm_binit(&strbuf, data, size);
3230 bcm_bprintf(&strbuf, "msgtrace address : 0x%08X\nconsole address : 0x%08X\n",
3231 sdpcm_shared.msgtrace_addr, sdpcm_shared.console_addr);
3233 if ((sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT) == 0) {
3234 /* NOTE: Misspelled assert is intentional - DO NOT FIX.
3235 * (Avoids conflict with real asserts for programmatic parsing of output.)
3237 bcm_bprintf(&strbuf, "Assrt not built in dongle\n");
3240 if ((sdpcm_shared.flags & (SDPCM_SHARED_ASSERT|SDPCM_SHARED_TRAP)) == 0) {
3241 /* NOTE: Misspelled assert is intentional - DO NOT FIX.
3242 * (Avoids conflict with real asserts for programmatic parsing of output.)
3244 bcm_bprintf(&strbuf, "No trap%s in dongle",
3245 (sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT)
3248 if (sdpcm_shared.flags & SDPCM_SHARED_ASSERT) {
3249 /* Download assert */
3250 bcm_bprintf(&strbuf, "Dongle assert");
3251 if (sdpcm_shared.assert_exp_addr != 0) {
3253 if ((bcmerror = dhdsdio_membytes(bus, FALSE,
3254 sdpcm_shared.assert_exp_addr,
3255 (uint8 *)str, maxstrlen)) < 0)
3258 str[maxstrlen - 1] = '\0';
3259 bcm_bprintf(&strbuf, " expr \"%s\"", str);
3262 if (sdpcm_shared.assert_file_addr != 0) {
3264 if ((bcmerror = dhdsdio_membytes(bus, FALSE,
3265 sdpcm_shared.assert_file_addr,
3266 (uint8 *)str, maxstrlen)) < 0)
3269 str[maxstrlen - 1] = '\0';
3270 bcm_bprintf(&strbuf, " file \"%s\"", str);
3273 bcm_bprintf(&strbuf, " line %d ", sdpcm_shared.assert_line);
3276 if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) {
3277 bus->dhd->dongle_trap_occured = TRUE;
3278 if ((bcmerror = dhdsdio_membytes(bus, FALSE,
3279 sdpcm_shared.trap_addr,
3280 (uint8*)&tr, sizeof(trap_t))) < 0)
3283 bcm_bprintf(&strbuf,
3284 "Dongle trap type 0x%x @ epc 0x%x, cpsr 0x%x, spsr 0x%x, sp 0x%x,"
3285 "lp 0x%x, rpc 0x%x Trap offset 0x%x, "
3286 "r0 0x%x, r1 0x%x, r2 0x%x, r3 0x%x, "
3287 "r4 0x%x, r5 0x%x, r6 0x%x, r7 0x%x\n\n",
3288 ltoh32(tr.type), ltoh32(tr.epc), ltoh32(tr.cpsr), ltoh32(tr.spsr),
3289 ltoh32(tr.r13), ltoh32(tr.r14), ltoh32(tr.pc),
3290 ltoh32(sdpcm_shared.trap_addr),
3291 ltoh32(tr.r0), ltoh32(tr.r1), ltoh32(tr.r2), ltoh32(tr.r3),
3292 ltoh32(tr.r4), ltoh32(tr.r5), ltoh32(tr.r6), ltoh32(tr.r7));
3294 addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log);
3295 if ((rv = dhdsdio_membytes(bus, FALSE, addr,
3296 (uint8 *)&console_ptr, sizeof(console_ptr))) < 0)
3299 addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log.buf_size);
3300 if ((rv = dhdsdio_membytes(bus, FALSE, addr,
3301 (uint8 *)&console_size, sizeof(console_size))) < 0)
3304 addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log.idx);
3305 if ((rv = dhdsdio_membytes(bus, FALSE, addr,
3306 (uint8 *)&console_index, sizeof(console_index))) < 0)
3309 console_ptr = ltoh32(console_ptr);
3310 console_size = ltoh32(console_size);
3311 console_index = ltoh32(console_index);
3313 if (console_size > CONSOLE_BUFFER_MAX ||
3314 !(console_buffer = MALLOC(bus->dhd->osh, console_size)))
3317 if ((rv = dhdsdio_membytes(bus, FALSE, console_ptr,
3318 (uint8 *)console_buffer, console_size)) < 0)
3321 for (i = 0, n = 0; i < console_size; i += n + 1) {
3322 for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) {
3323 ch = console_buffer[(console_index + i + n) % console_size];
3331 if (line[n - 1] == '\r')
3334 /* Don't use DHD_ERROR macro since we print
3335 * a lot of information quickly. The macro
3336 * will truncate a lot of the printfs
3339 if (dhd_msg_level & DHD_ERROR_VAL)
3340 printf("CONSOLE: %s\n", line);
3347 if (sdpcm_shared.flags & (SDPCM_SHARED_ASSERT | SDPCM_SHARED_TRAP)) {
3348 DHD_ERROR(("%s: %s\n", __FUNCTION__, strbuf.origbuf));
3354 MFREE(bus->dhd->osh, mbuffer, msize);
3356 MFREE(bus->dhd->osh, str, maxstrlen);
3358 MFREE(bus->dhd->osh, console_buffer, console_size);
3362 #endif /* #ifdef DHD_DEBUG */
3366 dhdsdio_downloadvars(dhd_bus_t *bus, void *arg, int len)
3368 int bcmerror = BCME_OK;
3370 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3372 /* Basic sanity checks */
3374 bcmerror = BCME_NOTDOWN;
3378 bcmerror = BCME_BUFTOOSHORT;
3382 /* Free the old ones and replace with passed variables */
3384 MFREE(bus->dhd->osh, bus->vars, bus->varsz);
3386 bus->vars = MALLOC(bus->dhd->osh, len);
3387 bus->varsz = bus->vars ? len : 0;
3388 if (bus->vars == NULL) {
3389 bcmerror = BCME_NOMEM;
3393 /* Copy the passed variables, which should include the terminating double-null */
3394 bcopy(arg, bus->vars, bus->varsz);
3401 #define CC_PLL_CHIPCTRL_SERIAL_ENAB (1 << 24)
3402 #define CC_CHIPCTRL_JTAG_SEL (1 << 3)
3403 #define CC_CHIPCTRL_GPIO_SEL (0x3)
3404 #define CC_PLL_CHIPCTRL_SERIAL_ENAB_4334 (1 << 28)
3407 dhd_serialconsole(dhd_bus_t *bus, bool set, bool enable, int *bcmerror)
3410 uint32 addr, data, uart_enab = 0;
3411 uint32 jtag_sel = CC_CHIPCTRL_JTAG_SEL;
3412 uint32 gpio_sel = CC_CHIPCTRL_GPIO_SEL;
3414 addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr);
3415 data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data);
3418 bcmsdh_reg_write(bus->sdh, addr, 4, 1);
3419 if (bcmsdh_regfail(bus->sdh)) {
3420 *bcmerror = BCME_SDIO_ERROR;
3423 int_val = bcmsdh_reg_read(bus->sdh, data, 4);
3424 if (bcmsdh_regfail(bus->sdh)) {
3425 *bcmerror = BCME_SDIO_ERROR;
3428 if (bus->sih->chip == BCM4330_CHIP_ID) {
3429 uart_enab = CC_PLL_CHIPCTRL_SERIAL_ENAB;
3431 else if (bus->sih->chip == BCM4334_CHIP_ID ||
3432 bus->sih->chip == BCM43340_CHIP_ID ||
3433 bus->sih->chip == BCM43341_CHIP_ID ||
3436 /* Moved to PMU chipcontrol 1 from 4330 */
3437 int_val &= ~gpio_sel;
3438 int_val |= jtag_sel;
3440 int_val |= gpio_sel;
3441 int_val &= ~jtag_sel;
3443 uart_enab = CC_PLL_CHIPCTRL_SERIAL_ENAB_4334;
3447 return (int_val & uart_enab);
3449 int_val |= uart_enab;
3451 int_val &= ~uart_enab;
3452 bcmsdh_reg_write(bus->sdh, data, 4, int_val);
3453 if (bcmsdh_regfail(bus->sdh)) {
3454 *bcmerror = BCME_SDIO_ERROR;
3457 if (bus->sih->chip == BCM4330_CHIP_ID) {
3459 addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol);
3460 chipcontrol = bcmsdh_reg_read(bus->sdh, addr, 4);
3461 chipcontrol &= ~jtag_sel;
3463 chipcontrol |= jtag_sel;
3464 chipcontrol &= ~gpio_sel;
3466 bcmsdh_reg_write(bus->sdh, addr, 4, chipcontrol);
3469 return (int_val & uart_enab);
3474 dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const char *name,
3475 void *params, int plen, void *arg, int len, int val_size)
3481 DHD_TRACE(("%s: Enter, action %d name %s params %p plen %d arg %p len %d val_size %d\n",
3482 __FUNCTION__, actionid, name, params, plen, arg, len, val_size));
3484 if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0)
3487 if (plen >= (int)sizeof(int_val))
3488 bcopy(params, &int_val, sizeof(int_val));
3490 bool_val = (int_val != 0) ? TRUE : FALSE;
3493 /* Some ioctls use the bus */
3494 dhd_os_sdlock(bus->dhd);
3496 /* Check if dongle is in reset. If so, only allow DEVRESET iovars */
3497 if (bus->dhd->dongle_reset && !(actionid == IOV_SVAL(IOV_DEVRESET) ||
3498 actionid == IOV_GVAL(IOV_DEVRESET))) {
3499 bcmerror = BCME_NOTREADY;
3504 * Special handling for keepSdioOn: New SDIO Wake-up Mechanism
3506 if ((vi->varid == IOV_KSO) && (IOV_ISSET(actionid))) {
3507 dhdsdio_clk_kso_iovar(bus, bool_val);
3509 } else if ((vi->varid == IOV_DEVSLEEP) && (IOV_ISSET(actionid))) {
3511 dhdsdio_clk_devsleep_iovar(bus, bool_val);
3512 if (!SLPAUTO_ENAB(bus) && (bool_val == FALSE) && (bus->ipend)) {
3513 DHD_ERROR(("INT pending in devsleep 1, dpc_sched: %d\n",
3515 if (!bus->dpc_sched) {
3516 bus->dpc_sched = TRUE;
3517 dhd_sched_dpc(bus->dhd);
3524 /* Handle sleep stuff before any clock mucking */
3525 if (vi->varid == IOV_SLEEP) {
3526 if (IOV_ISSET(actionid)) {
3527 bcmerror = dhdsdio_bussleep(bus, bool_val);
3529 int_val = (int32)bus->sleeping;
3530 bcopy(&int_val, arg, val_size);
3535 /* Request clock to allow SDIO accesses */
3536 if (!bus->dhd->dongle_reset) {
3538 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
3542 case IOV_GVAL(IOV_INTR):
3543 int_val = (int32)bus->intr;
3544 bcopy(&int_val, arg, val_size);
3547 case IOV_SVAL(IOV_INTR):
3548 bus->intr = bool_val;
3549 bus->intdis = FALSE;
3552 DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__));
3553 bcmsdh_intr_enable(bus->sdh);
3555 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
3556 bcmsdh_intr_disable(bus->sdh);
3561 case IOV_GVAL(IOV_POLLRATE):
3562 int_val = (int32)bus->pollrate;
3563 bcopy(&int_val, arg, val_size);
3566 case IOV_SVAL(IOV_POLLRATE):
3567 bus->pollrate = (uint)int_val;
3568 bus->poll = (bus->pollrate != 0);
3571 case IOV_GVAL(IOV_IDLETIME):
3572 int_val = bus->idletime;
3573 bcopy(&int_val, arg, val_size);
3576 case IOV_SVAL(IOV_IDLETIME):
3577 if ((int_val < 0) && (int_val != DHD_IDLE_IMMEDIATE)) {
3578 bcmerror = BCME_BADARG;
3580 bus->idletime = int_val;
3584 case IOV_GVAL(IOV_IDLECLOCK):
3585 int_val = (int32)bus->idleclock;
3586 bcopy(&int_val, arg, val_size);
3589 case IOV_SVAL(IOV_IDLECLOCK):
3590 bus->idleclock = int_val;
3593 case IOV_GVAL(IOV_SD1IDLE):
3594 int_val = (int32)sd1idle;
3595 bcopy(&int_val, arg, val_size);
3598 case IOV_SVAL(IOV_SD1IDLE):
3603 case IOV_SVAL(IOV_MEMBYTES):
3604 case IOV_GVAL(IOV_MEMBYTES):
3610 bool set = (actionid == IOV_SVAL(IOV_MEMBYTES));
3612 ASSERT(plen >= 2*sizeof(int));
3614 address = (uint32)int_val;
3615 bcopy((char *)params + sizeof(int_val), &int_val, sizeof(int_val));
3616 size = (uint)int_val;
3618 /* Do some validation */
3619 dsize = set ? plen - (2 * sizeof(int)) : len;
3621 DHD_ERROR(("%s: error on %s membytes, addr 0x%08x size %d dsize %d\n",
3622 __FUNCTION__, (set ? "set" : "get"), address, size, dsize));
3623 bcmerror = BCME_BADARG;
3627 DHD_INFO(("%s: Request to %s %d bytes at address 0x%08x\n", __FUNCTION__,
3628 (set ? "write" : "read"), size, address));
3631 if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
3633 * If address is start of RAM (i.e. a downloaded image),
3634 * store the reset instruction to be written in 0
3636 if (address == bus->dongle_ram_base) {
3637 bus->resetinstr = *(((uint32*)params) + 2);
3640 /* If we know about SOCRAM, check for a fit */
3641 if ((bus->orig_ramsize) &&
3642 ((address > bus->orig_ramsize) || (address + size > bus->orig_ramsize)))
3644 uint8 enable, protect, remap;
3645 si_socdevram(bus->sih, FALSE, &enable, &protect, &remap);
3646 if (!enable || protect) {
3647 DHD_ERROR(("%s: ramsize 0x%08x doesn't have %d bytes at 0x%08x\n",
3648 __FUNCTION__, bus->orig_ramsize, size, address));
3649 DHD_ERROR(("%s: socram enable %d, protect %d\n",
3650 __FUNCTION__, enable, protect));
3651 bcmerror = BCME_BADARG;
3655 if (!REMAP_ENAB(bus) && (address >= SOCDEVRAM_ARM_ADDR)) {
3656 uint32 devramsize = si_socdevram_size(bus->sih);
3657 if ((address < SOCDEVRAM_ARM_ADDR) ||
3658 (address + size > (SOCDEVRAM_ARM_ADDR + devramsize))) {
3659 DHD_ERROR(("%s: bad address 0x%08x, size 0x%08x\n",
3660 __FUNCTION__, address, size));
3661 DHD_ERROR(("%s: socram range 0x%08x,size 0x%08x\n",
3662 __FUNCTION__, SOCDEVRAM_ARM_ADDR, devramsize));
3663 bcmerror = BCME_BADARG;
3666 /* move it such that address is real now */
3667 address -= SOCDEVRAM_ARM_ADDR;
3668 address += SOCDEVRAM_BP_ADDR;
3669 DHD_INFO(("%s: Request to %s %d bytes @ Mapped address 0x%08x\n",
3670 __FUNCTION__, (set ? "write" : "read"), size, address));
3671 } else if (REMAP_ENAB(bus) && REMAP_ISADDR(bus, address) && remap) {
3672 /* Can not access remap region while devram remap bit is set
3673 * ROM content would be returned in this case
3675 DHD_ERROR(("%s: Need to disable remap for address 0x%08x\n",
3676 __FUNCTION__, address));
3677 bcmerror = BCME_ERROR;
3683 /* Generate the actual data pointer */
3684 data = set ? (uint8*)params + 2 * sizeof(int): (uint8*)arg;
3686 /* Call to do the transfer */
3687 bcmerror = dhdsdio_membytes(bus, set, address, data, size);
3692 case IOV_GVAL(IOV_RAMSIZE):
3693 int_val = (int32)bus->ramsize;
3694 bcopy(&int_val, arg, val_size);
3697 case IOV_GVAL(IOV_RAMSTART):
3698 int_val = (int32)bus->dongle_ram_base;
3699 bcopy(&int_val, arg, val_size);
3702 case IOV_GVAL(IOV_SDIOD_DRIVE):
3703 int_val = (int32)dhd_sdiod_drive_strength;
3704 bcopy(&int_val, arg, val_size);
3707 case IOV_SVAL(IOV_SDIOD_DRIVE):
3708 dhd_sdiod_drive_strength = int_val;
3709 si_sdiod_drive_strength_init(bus->sih, bus->dhd->osh, dhd_sdiod_drive_strength);
3712 case IOV_SVAL(IOV_SET_DOWNLOAD_STATE):
3713 bcmerror = dhdsdio_download_state(bus, bool_val);
3716 case IOV_SVAL(IOV_SOCRAM_STATE):
3717 bcmerror = dhdsdio_download_state(bus, bool_val);
3720 case IOV_SVAL(IOV_VARS):
3721 bcmerror = dhdsdio_downloadvars(bus, arg, len);
3724 case IOV_GVAL(IOV_READAHEAD):
3725 int_val = (int32)dhd_readahead;
3726 bcopy(&int_val, arg, val_size);
3729 case IOV_SVAL(IOV_READAHEAD):
3730 if (bool_val && !dhd_readahead)
3732 dhd_readahead = bool_val;
3735 case IOV_GVAL(IOV_SDRXCHAIN):
3736 int_val = (int32)bus->use_rxchain;
3737 bcopy(&int_val, arg, val_size);
3740 case IOV_SVAL(IOV_SDRXCHAIN):
3741 if (bool_val && !bus->sd_rxchain)
3742 bcmerror = BCME_UNSUPPORTED;
3744 bus->use_rxchain = bool_val;
3746 case IOV_GVAL(IOV_ALIGNCTL):
3747 int_val = (int32)dhd_alignctl;
3748 bcopy(&int_val, arg, val_size);
3751 case IOV_SVAL(IOV_ALIGNCTL):
3752 dhd_alignctl = bool_val;
3755 case IOV_GVAL(IOV_SDALIGN):
3756 int_val = DHD_SDALIGN;
3757 bcopy(&int_val, arg, val_size);
3761 case IOV_GVAL(IOV_VARS):
3762 if (bus->varsz < (uint)len)
3763 bcopy(bus->vars, arg, bus->varsz);
3765 bcmerror = BCME_BUFTOOSHORT;
3767 #endif /* DHD_DEBUG */
3770 case IOV_GVAL(IOV_SDREG):
3775 sd_ptr = (sdreg_t *)params;
3777 addr = (uintptr)bus->regs + sd_ptr->offset;
3778 size = sd_ptr->func;
3779 int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size);
3780 if (bcmsdh_regfail(bus->sdh))
3781 bcmerror = BCME_SDIO_ERROR;
3782 bcopy(&int_val, arg, sizeof(int32));
3786 case IOV_SVAL(IOV_SDREG):
3791 sd_ptr = (sdreg_t *)params;
3793 addr = (uintptr)bus->regs + sd_ptr->offset;
3794 size = sd_ptr->func;
3795 bcmsdh_reg_write(bus->sdh, addr, size, sd_ptr->value);
3796 if (bcmsdh_regfail(bus->sdh))
3797 bcmerror = BCME_SDIO_ERROR;
3801 /* Same as above, but offset is not backplane (not SDIO core) */
3802 case IOV_GVAL(IOV_SBREG):
3807 bcopy(params, &sdreg, sizeof(sdreg));
3809 addr = SI_ENUM_BASE + sdreg.offset;
3811 int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size);
3812 if (bcmsdh_regfail(bus->sdh))
3813 bcmerror = BCME_SDIO_ERROR;
3814 bcopy(&int_val, arg, sizeof(int32));
3818 case IOV_SVAL(IOV_SBREG):
3823 bcopy(params, &sdreg, sizeof(sdreg));
3825 addr = SI_ENUM_BASE + sdreg.offset;
3827 bcmsdh_reg_write(bus->sdh, addr, size, sdreg.value);
3828 if (bcmsdh_regfail(bus->sdh))
3829 bcmerror = BCME_SDIO_ERROR;
3833 case IOV_GVAL(IOV_SDCIS):
3837 bcmstrcat(arg, "\nFunc 0\n");
3838 bcmsdh_cis_read(bus->sdh, 0x10, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
3839 bcmstrcat(arg, "\nFunc 1\n");
3840 bcmsdh_cis_read(bus->sdh, 0x11, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
3841 bcmstrcat(arg, "\nFunc 2\n");
3842 bcmsdh_cis_read(bus->sdh, 0x12, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
3846 case IOV_GVAL(IOV_FORCEEVEN):
3847 int_val = (int32)forcealign;
3848 bcopy(&int_val, arg, val_size);
3851 case IOV_SVAL(IOV_FORCEEVEN):
3852 forcealign = bool_val;
3855 case IOV_GVAL(IOV_TXBOUND):
3856 int_val = (int32)dhd_txbound;
3857 bcopy(&int_val, arg, val_size);
3860 case IOV_SVAL(IOV_TXBOUND):
3861 dhd_txbound = (uint)int_val;
3864 case IOV_GVAL(IOV_RXBOUND):
3865 int_val = (int32)dhd_rxbound;
3866 bcopy(&int_val, arg, val_size);
3869 case IOV_SVAL(IOV_RXBOUND):
3870 dhd_rxbound = (uint)int_val;
3873 case IOV_GVAL(IOV_TXMINMAX):
3874 int_val = (int32)dhd_txminmax;
3875 bcopy(&int_val, arg, val_size);
3878 case IOV_SVAL(IOV_TXMINMAX):
3879 dhd_txminmax = (uint)int_val;
3882 case IOV_GVAL(IOV_SERIALCONS):
3883 int_val = dhd_serialconsole(bus, FALSE, 0, &bcmerror);
3887 bcopy(&int_val, arg, val_size);
3890 case IOV_SVAL(IOV_SERIALCONS):
3891 dhd_serialconsole(bus, TRUE, bool_val, &bcmerror);
3896 #endif /* DHD_DEBUG */
3900 case IOV_GVAL(IOV_EXTLOOP):
3901 int_val = (int32)bus->ext_loop;
3902 bcopy(&int_val, arg, val_size);
3905 case IOV_SVAL(IOV_EXTLOOP):
3906 bus->ext_loop = bool_val;
3909 case IOV_GVAL(IOV_PKTGEN):
3910 bcmerror = dhdsdio_pktgen_get(bus, arg);
3913 case IOV_SVAL(IOV_PKTGEN):
3914 bcmerror = dhdsdio_pktgen_set(bus, arg);
3918 #if defined(SDIO_CRC_ERROR_FIX)
3919 case IOV_GVAL(IOV_WATERMARK):
3920 int_val = (int32)watermark;
3921 bcopy(&int_val, arg, val_size);
3924 case IOV_SVAL(IOV_WATERMARK):
3925 watermark = (uint)int_val;
3926 watermark = (watermark > SBSDIO_WATERMARK_MASK) ? SBSDIO_WATERMARK_MASK : watermark;
3927 DHD_ERROR(("Setting watermark as 0x%x.\n", watermark));
3928 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, (uint8)watermark, NULL);
3931 case IOV_GVAL(IOV_MESBUSYCTRL):
3932 int_val = (int32)mesbusyctrl;
3933 bcopy(&int_val, arg, val_size);
3936 case IOV_SVAL(IOV_MESBUSYCTRL):
3937 mesbusyctrl = (uint)int_val;
3938 mesbusyctrl = (mesbusyctrl > SBSDIO_MESBUSYCTRL_MASK)
3939 ? SBSDIO_MESBUSYCTRL_MASK : mesbusyctrl;
3940 DHD_ERROR(("Setting mesbusyctrl as 0x%x.\n", mesbusyctrl));
3941 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL,
3942 ((uint8)mesbusyctrl | 0x80), NULL);
3944 #endif /* SDIO_CRC_ERROR_FIX */
3946 case IOV_GVAL(IOV_DONGLEISOLATION):
3947 int_val = bus->dhd->dongle_isolation;
3948 bcopy(&int_val, arg, val_size);
3951 case IOV_SVAL(IOV_DONGLEISOLATION):
3952 bus->dhd->dongle_isolation = bool_val;
3955 case IOV_SVAL(IOV_DEVRESET):
3956 DHD_TRACE(("%s: Called set IOV_DEVRESET=%d dongle_reset=%d busstate=%d\n",
3957 __FUNCTION__, bool_val, bus->dhd->dongle_reset,
3958 bus->dhd->busstate));
3960 ASSERT(bus->dhd->osh);
3961 /* ASSERT(bus->cl_devid); */
3963 dhd_bus_devreset(bus->dhd, (uint8)bool_val);
3967 case IOV_GVAL(IOV_FWPATH):
3971 fw_path_len = strlen(bus->fw_path);
3972 DHD_INFO(("[softap] get fwpath, l=%d\n", len));
3974 if (fw_path_len > len-1) {
3975 bcmerror = BCME_BUFTOOSHORT;
3980 bcopy(bus->fw_path, arg, fw_path_len);
3981 ((uchar*)arg)[fw_path_len] = 0;
3986 case IOV_SVAL(IOV_FWPATH):
3987 DHD_INFO(("[softap] set fwpath, idx=%d\n", int_val));
3991 bus->fw_path = fw_path; /* ordinary one */
3994 bus->fw_path = fw_path2;
3997 bcmerror = BCME_BADARG;
4001 DHD_INFO(("[softap] new fw path: %s\n", (bus->fw_path[0] ? bus->fw_path : "NULL")));
4005 case IOV_GVAL(IOV_DEVRESET):
4006 DHD_TRACE(("%s: Called get IOV_DEVRESET\n", __FUNCTION__));
4008 /* Get its status */
4009 int_val = (bool) bus->dhd->dongle_reset;
4010 bcopy(&int_val, arg, val_size);
4014 case IOV_GVAL(IOV_KSO):
4015 int_val = dhdsdio_sleepcsr_get(bus);
4016 bcopy(&int_val, arg, val_size);
4019 case IOV_GVAL(IOV_DEVCAP):
4020 int_val = dhdsdio_devcap_get(bus);
4021 bcopy(&int_val, arg, val_size);
4024 case IOV_SVAL(IOV_DEVCAP):
4025 dhdsdio_devcap_set(bus, (uint8) int_val);
4028 #ifdef BCMSDIOH_TXGLOM
4029 case IOV_GVAL(IOV_TXGLOMSIZE):
4030 int_val = (int32)bus->glomsize;
4031 bcopy(&int_val, arg, val_size);
4034 case IOV_SVAL(IOV_TXGLOMSIZE):
4035 if (int_val > SDPCM_MAXGLOM_SIZE) {
4036 bcmerror = BCME_ERROR;
4038 bus->glomsize = (uint)int_val;
4041 case IOV_GVAL(IOV_TXGLOMMODE):
4042 int_val = (int32)bus->glom_mode;
4043 bcopy(&int_val, arg, val_size);
4046 case IOV_SVAL(IOV_TXGLOMMODE):
4047 if ((int_val != SDPCM_TXGLOM_CPY) && (int_val != SDPCM_TXGLOM_MDESC)) {
4048 bcmerror = BCME_RANGE;
4050 if ((bus->glom_mode = bcmsdh_set_mode(bus->sdh, (uint)int_val)) != int_val)
4051 bcmerror = BCME_ERROR;
4054 #endif /* BCMSDIOH_TXGLOM */
4055 case IOV_SVAL(IOV_HANGREPORT):
4056 bus->dhd->hang_report = bool_val;
4057 DHD_ERROR(("%s: Set hang_report as %d\n", __FUNCTION__, bus->dhd->hang_report));
4060 case IOV_GVAL(IOV_HANGREPORT):
4061 int_val = (int32)bus->dhd->hang_report;
4062 bcopy(&int_val, arg, val_size);
4065 bcmerror = BCME_UNSUPPORTED;
4070 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
4071 bus->activity = FALSE;
4072 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
4075 dhd_os_sdunlock(bus->dhd);
4081 dhdsdio_write_vars(dhd_bus_t *bus)
4084 uint32 varsize, phys_size;
4089 uint8 *nvram_ularray;
4090 #endif /* DHD_DEBUG */
4092 /* Even if there are no vars are to be written, we still need to set the ramsize. */
4093 varsize = bus->varsz ? ROUNDUP(bus->varsz, 4) : 0;
4094 varaddr = (bus->ramsize - 4) - varsize;
4096 varaddr += bus->dongle_ram_base;
4099 if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 7)) {
4100 if (((varaddr & 0x3C) == 0x3C) && (varsize > 4)) {
4101 DHD_ERROR(("PR85623WAR in place\n"));
4107 vbuffer = (uint8 *)MALLOC(bus->dhd->osh, varsize);
4111 bzero(vbuffer, varsize);
4112 bcopy(bus->vars, vbuffer, bus->varsz);
4114 /* Write the vars list */
4115 bcmerror = dhdsdio_membytes(bus, TRUE, varaddr, vbuffer, varsize);
4117 /* Verify NVRAM bytes */
4118 DHD_INFO(("Compare NVRAM dl & ul; varsize=%d\n", varsize));
4119 nvram_ularray = (uint8*)MALLOC(bus->dhd->osh, varsize);
4123 /* Upload image to verify downloaded contents. */
4124 memset(nvram_ularray, 0xaa, varsize);
4126 /* Read the vars list to temp buffer for comparison */
4127 bcmerror = dhdsdio_membytes(bus, FALSE, varaddr, nvram_ularray, varsize);
4129 DHD_ERROR(("%s: error %d on reading %d nvram bytes at 0x%08x\n",
4130 __FUNCTION__, bcmerror, varsize, varaddr));
4132 /* Compare the org NVRAM with the one read from RAM */
4133 if (memcmp(vbuffer, nvram_ularray, varsize)) {
4134 DHD_ERROR(("%s: Downloaded NVRAM image is corrupted.\n", __FUNCTION__));
4136 DHD_ERROR(("%s: Download, Upload and compare of NVRAM succeeded.\n",
4139 MFREE(bus->dhd->osh, nvram_ularray, varsize);
4140 #endif /* DHD_DEBUG */
4142 MFREE(bus->dhd->osh, vbuffer, varsize);
4145 phys_size = REMAP_ENAB(bus) ? bus->ramsize : bus->orig_ramsize;
4147 phys_size += bus->dongle_ram_base;
4149 /* adjust to the user specified RAM */
4150 DHD_INFO(("Physical memory size: %d, usable memory size: %d\n",
4151 phys_size, bus->ramsize));
4152 DHD_INFO(("Vars are at %d, orig varsize is %d\n",
4154 varsize = ((phys_size - 4) - varaddr);
4157 * Determine the length token:
4158 * Varsize, converted to words, in lower 16-bits, checksum in upper 16-bits.
4163 varsizew = varsize / 4;
4164 varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF);
4165 varsizew = htol32(varsizew);
4168 DHD_INFO(("New varsize is %d, length token=0x%08x\n", varsize, varsizew));
4170 /* Write the length token to the last word */
4171 bcmerror = dhdsdio_membytes(bus, TRUE, (phys_size - 4),
4172 (uint8*)&varsizew, 4);
4178 dhdsdio_download_state(dhd_bus_t *bus, bool enter)
4186 /* To enter download state, disable ARM and reset SOCRAM.
4187 * To exit download state, simply reset ARM (default is RAM boot).
4190 bus->alp_only = TRUE;
4192 if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) &&
4193 !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) {
4194 if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
4197 DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__));
4198 bcmerror = BCME_ERROR;
4204 si_core_disable(bus->sih, 0);
4205 if (bcmsdh_regfail(bus->sdh)) {
4206 bcmerror = BCME_SDIO_ERROR;
4210 if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) {
4211 DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__));
4212 bcmerror = BCME_ERROR;
4216 si_core_reset(bus->sih, 0, 0);
4217 if (bcmsdh_regfail(bus->sdh)) {
4218 DHD_ERROR(("%s: Failure trying reset SOCRAM core?\n",
4220 bcmerror = BCME_SDIO_ERROR;
4224 /* Disable remap for download */
4225 if (REMAP_ENAB(bus) && si_socdevram_remap_isenb(bus->sih))
4226 dhdsdio_devram_remap(bus, FALSE);
4228 /* Clear the top bit of memory */
4231 if (dhdsdio_membytes(bus, TRUE, bus->ramsize - 4,
4232 (uint8*)&zeros, 4) < 0) {
4233 bcmerror = BCME_SDIO_ERROR;
4241 * Read RAM base address [0x18_0000]
4242 * [next] Download firmware
4243 * [done at else] Populate the reset vector
4244 * [done at else] Remove ARM halt
4246 /* Halt ARM & remove reset */
4247 si_core_reset(bus->sih, SICF_CPUHALT, SICF_CPUHALT);
4250 if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
4251 if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) {
4252 DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__));
4253 bcmerror = BCME_ERROR;
4257 if (!si_iscoreup(bus->sih)) {
4258 DHD_ERROR(("%s: SOCRAM core is down after reset?\n", __FUNCTION__));
4259 bcmerror = BCME_ERROR;
4263 if ((bcmerror = dhdsdio_write_vars(bus))) {
4264 DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__));
4268 /* Enable remap before ARM reset but after vars.
4269 * No backplane access in remap mode
4271 if (REMAP_ENAB(bus) && !si_socdevram_remap_isenb(bus->sih))
4272 dhdsdio_devram_remap(bus, TRUE);
4274 if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) &&
4275 !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) {
4276 DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__));
4277 bcmerror = BCME_ERROR;
4280 W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries);
4283 if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) &&
4284 !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) {
4285 DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__));
4286 bcmerror = BCME_ERROR;
4290 /* cr4 has no socram, but tcm's */
4292 if ((bcmerror = dhdsdio_write_vars(bus))) {
4293 DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__));
4297 if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) &&
4298 !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) {
4299 DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__));
4300 bcmerror = BCME_ERROR;
4303 W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries);
4305 /* switch back to arm core again */
4306 if (!(si_setcore(bus->sih, ARMCR4_CORE_ID, 0))) {
4307 DHD_ERROR(("%s: Failed to find ARM CR4 core!\n", __FUNCTION__));
4308 bcmerror = BCME_ERROR;
4311 /* write address 0 with reset instruction */
4312 bcmerror = dhdsdio_membytes(bus, TRUE, 0,
4313 (uint8 *)&bus->resetinstr, sizeof(bus->resetinstr));
4315 /* now remove reset and halt and continue to run CR4 */
4318 si_core_reset(bus->sih, 0, 0);
4319 if (bcmsdh_regfail(bus->sdh)) {
4320 DHD_ERROR(("%s: Failure trying to reset ARM core?\n", __FUNCTION__));
4321 bcmerror = BCME_SDIO_ERROR;
4325 /* Allow HT Clock now that the ARM is running. */
4326 bus->alp_only = FALSE;
4328 bus->dhd->busstate = DHD_BUS_LOAD;
4332 /* Always return to SDIOD core */
4333 if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0))
4334 si_setcore(bus->sih, SDIOD_CORE_ID, 0);
4340 dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name,
4341 void *params, int plen, void *arg, int len, bool set)
4343 dhd_bus_t *bus = dhdp->bus;
4344 const bcm_iovar_t *vi = NULL;
4349 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4354 /* Get MUST have return space */
4355 ASSERT(set || (arg && len));
4357 /* Set does NOT take qualifiers */
4358 ASSERT(!set || (!params && !plen));
4360 /* Look up var locally; if not found pass to host driver */
4361 if ((vi = bcm_iovar_lookup(dhdsdio_iovars, name)) == NULL) {
4362 dhd_os_sdlock(bus->dhd);
4366 /* Turn on clock in case SD command needs backplane */
4367 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
4369 bcmerror = bcmsdh_iovar_op(bus->sdh, name, params, plen, arg, len, set);
4371 /* Check for bus configuration changes of interest */
4373 /* If it was divisor change, read the new one */
4374 if (set && strcmp(name, "sd_divisor") == 0) {
4375 if (bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
4376 &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) {
4377 bus->sd_divisor = -1;
4378 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, name));
4380 DHD_INFO(("%s: noted %s update, value now %d\n",
4381 __FUNCTION__, name, bus->sd_divisor));
4384 /* If it was a mode change, read the new one */
4385 if (set && strcmp(name, "sd_mode") == 0) {
4386 if (bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
4387 &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) {
4389 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, name));
4391 DHD_INFO(("%s: noted %s update, value now %d\n",
4392 __FUNCTION__, name, bus->sd_mode));
4395 /* Similar check for blocksize change */
4396 if (set && strcmp(name, "sd_blocksize") == 0) {
4398 if (bcmsdh_iovar_op(bus->sdh, "sd_blocksize", &fnum, sizeof(int32),
4399 &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) {
4401 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize"));
4403 DHD_INFO(("%s: noted %s update, value now %d\n",
4404 __FUNCTION__, "sd_blocksize", bus->blocksize));
4406 if ((bus->sih->chip == BCM4335_CHIP_ID) ||
4407 (bus->sih->chip == BCM4339_CHIP_ID))
4408 dhd_overflow_war(bus);
4411 bus->roundup = MIN(max_roundup, bus->blocksize);
4413 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
4414 bus->activity = FALSE;
4415 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
4418 dhd_os_sdunlock(bus->dhd);
4422 DHD_CTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__,
4423 name, (set ? "set" : "get"), len, plen));
4425 /* set up 'params' pointer in case this is a set command so that
4426 * the convenience int and bool code can be common to set and get
4428 if (params == NULL) {
4433 if (vi->type == IOVT_VOID)
4435 else if (vi->type == IOVT_BUFFER)
4438 /* all other types are integer sized */
4439 val_size = sizeof(int);
4441 actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
4442 bcmerror = dhdsdio_doiovar(bus, vi, actionid, name, params, plen, arg, len, val_size);
4449 dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex)
4452 uint32 local_hostintmask;
4459 osh = bus->dhd->osh;
4460 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4462 bcmsdh_waitlockfree(NULL);
4465 dhd_os_sdlock(bus->dhd);
4467 if ((bus->dhd->busstate == DHD_BUS_DOWN) || bus->dhd->hang_was_sent) {
4468 /* if Firmware already hangs disbale any interrupt */
4469 bus->dhd->busstate = DHD_BUS_DOWN;
4470 bus->hostintmask = 0;
4471 bcmsdh_intr_disable(bus->sdh);
4475 /* Change our idea of bus state */
4476 bus->dhd->busstate = DHD_BUS_DOWN;
4478 if (KSO_ENAB(bus)) {
4480 /* Enable clock for device interrupts */
4481 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
4483 /* Disable and clear interrupts at the chip level also */
4484 W_SDREG(0, &bus->regs->hostintmask, retries);
4485 local_hostintmask = bus->hostintmask;
4486 bus->hostintmask = 0;
4488 /* Force clocks on backplane to be sure F2 interrupt propagates */
4489 saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
4491 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
4492 (saveclk | SBSDIO_FORCE_HT), &err);
4495 DHD_ERROR(("%s: Failed to force clock for F2: err %d\n", __FUNCTION__, err));
4498 /* Turn off the bus (F2), free any pending packets */
4499 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
4500 bcmsdh_intr_disable(bus->sdh);
4501 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL);
4503 /* Clear any pending interrupts now that F2 is disabled */
4504 W_SDREG(local_hostintmask, &bus->regs->intstatus, retries);
4507 /* Turn off the backplane clock (only) */
4508 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
4511 /* Clear the data packet queues */
4512 pktq_flush(osh, &bus->txq, TRUE, NULL, 0);
4514 /* Clear any held glomming stuff */
4516 PKTFREE(osh, bus->glomd, FALSE);
4519 PKTFREE(osh, bus->glom, FALSE);
4521 bus->glom = bus->glomd = NULL;
4523 /* Clear rx control and wake any waiters */
4525 dhd_os_ioctl_resp_wake(bus->dhd);
4527 /* Reset some F2 state stuff */
4528 bus->rxskip = FALSE;
4529 bus->tx_seq = bus->rx_seq = 0;
4534 dhd_os_sdunlock(bus->dhd);
4537 #ifdef BCMSDIOH_TXGLOM
4539 dhd_txglom_enable(dhd_pub_t *dhdp, bool enable)
4541 dhd_bus_t *bus = dhdp->bus;
4547 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4551 memset(buf, 0, sizeof(buf));
4552 bcm_mkiovar("bus:rxglom",
4554 4, buf, sizeof(buf));
4555 ret = dhd_wl_ioctl_cmd(dhdp,
4557 sizeof(buf), TRUE, 0);
4559 bus->glom_enable = TRUE;
4562 bus->glom_enable = FALSE;
4565 #endif /* BCMSDIOH_TXGLOM */
4568 dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex)
4570 dhd_bus_t *bus = dhdp->bus;
4573 uint8 ready, enable;
4577 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4584 dhd_os_sdlock(bus->dhd);
4586 if (bus->sih->chip == BCM43362_CHIP_ID) {
4587 printf("%s: delay 100ms for BCM43362\n", __FUNCTION__);
4588 OSL_DELAY(100000); // terence 20131209: delay for 43362
4591 /* Make sure backplane clock is on, needed to generate F2 interrupt */
4592 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
4593 if (bus->clkstate != CLK_AVAIL) {
4594 DHD_ERROR(("%s: clock state is wrong. state = %d\n", __FUNCTION__, bus->clkstate));
4600 /* Force clocks on backplane to be sure F2 interrupt propagates */
4601 saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
4603 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
4604 (saveclk | SBSDIO_FORCE_HT), &err);
4607 DHD_ERROR(("%s: Failed to force clock for F2: err %d\n", __FUNCTION__, err));
4612 /* Enable function 2 (frame transfers) */
4613 W_SDREG((SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT),
4614 &bus->regs->tosbmailboxdata, retries);
4615 enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2);
4617 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL);
4619 /* Give the dongle some time to do its thing and set IOR2 */
4620 dhd_timeout_start(&tmo, DHD_WAIT_F2RDY * 1000);
4623 while (ready != enable && !dhd_timeout_expired(&tmo))
4624 ready = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IORDY, NULL);
4626 DHD_ERROR(("%s: enable 0x%02x, ready 0x%02x (waited %uus)\n",
4627 __FUNCTION__, enable, ready, tmo.elapsed));
4630 /* If F2 successfully enabled, set core and enable interrupts */
4631 if (ready == enable) {
4632 /* Make sure we're talking to the core. */
4633 if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0)))
4634 bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0);
4635 ASSERT(bus->regs != NULL);
4637 /* Set up the interrupt mask and enable interrupts */
4638 bus->hostintmask = HOSTINTMASK;
4639 /* corerev 4 could use the newer interrupt logic to detect the frames */
4640 if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 4) &&
4641 (bus->rxint_mode != SDIO_DEVICE_HMB_RXINT)) {
4642 bus->hostintmask &= ~I_HMB_FRAME_IND;
4643 bus->hostintmask |= I_XMTDATA_AVAIL;
4645 W_SDREG(bus->hostintmask, &bus->regs->hostintmask, retries);
4646 #ifdef SDIO_CRC_ERROR_FIX
4647 if (bus->blocksize < 512) {
4648 mesbusyctrl = watermark = bus->blocksize / 4;
4650 #endif /* SDIO_CRC_ERROR_FIX */
4651 if (!((bus->sih->chip == BCM4335_CHIP_ID) ||
4652 (bus->sih->chip == BCM4339_CHIP_ID))) {
4653 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK,
4654 (uint8)watermark, &err);
4656 #ifdef SDIO_CRC_ERROR_FIX
4657 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL,
4658 (uint8)mesbusyctrl|0x80, &err);
4659 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL,
4660 SBSDIO_DEVCTL_EN_F2_BLK_WATERMARK, NULL);
4661 #endif /* SDIO_CRC_ERROR_FIX */
4663 /* Set bus state according to enable result */
4664 dhdp->busstate = DHD_BUS_DATA;
4666 /* bcmsdh_intr_unmask(bus->sdh); */
4668 bus->intdis = FALSE;
4670 DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__));
4671 bcmsdh_intr_enable(bus->sdh);
4673 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
4674 bcmsdh_intr_disable(bus->sdh);
4681 /* Disable F2 again */
4682 enable = SDIO_FUNC_ENABLE_1;
4683 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL);
4686 if (dhdsdio_sr_cap(bus)) {
4687 dhdsdio_sr_init(bus);
4688 /* Masking the chip active interrupt permanantly */
4689 bus->hostintmask &= ~I_CHIPACTIVE;
4690 W_SDREG(bus->hostintmask, &bus->regs->hostintmask, retries);
4691 DHD_INFO(("%s: disable I_CHIPACTIVE in hostintmask[0x%08x]\n",
4692 __FUNCTION__, bus->hostintmask));
4695 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1,
4696 SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err);
4698 /* If we didn't come up, turn off backplane clock */
4699 if (dhdp->busstate != DHD_BUS_DATA)
4700 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
4704 dhd_os_sdunlock(bus->dhd);
4710 dhdsdio_rxfail(dhd_bus_t *bus, bool abort, bool rtx)
4712 bcmsdh_info_t *sdh = bus->sdh;
4713 sdpcmd_regs_t *regs = bus->regs;
4719 DHD_ERROR(("%s: %sterminate frame%s\n", __FUNCTION__,
4720 (abort ? "abort command, " : ""), (rtx ? ", send NAK" : "")));
4722 if (!KSO_ENAB(bus)) {
4723 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
4728 bcmsdh_abort(sdh, SDIO_FUNC_2);
4731 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, SFC_RF_TERM, &err);
4733 DHD_ERROR(("%s: SBSDIO_FUNC1_FRAMECTRL cmd err\n", __FUNCTION__));
4738 /* Wait until the packet has been flushed (device/FIFO stable) */
4739 for (lastrbc = retries = 0xffff; retries > 0; retries--) {
4740 hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCHI, NULL);
4741 lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCLO, &err);
4743 DHD_ERROR(("%s: SBSDIO_FUNC1_RFAMEBCLO cmd err\n", __FUNCTION__));
4747 bus->f1regdata += 2;
4749 if ((hi == 0) && (lo == 0))
4752 if ((hi > (lastrbc >> 8)) && (lo > (lastrbc & 0x00ff))) {
4753 DHD_ERROR(("%s: count growing: last 0x%04x now 0x%04x\n",
4754 __FUNCTION__, lastrbc, ((hi << 8) + lo)));
4756 lastrbc = (hi << 8) + lo;
4760 DHD_ERROR(("%s: count never zeroed: last 0x%04x\n", __FUNCTION__, lastrbc));
4762 DHD_INFO(("%s: flush took %d iterations\n", __FUNCTION__, (0xffff - retries)));
4767 W_SDREG(SMB_NAK, ®s->tosbmailbox, retries);
4769 if (retries <= retry_limit) {
4774 /* Clear partial in any case */
4778 /* If we can't reach the device, signal failure */
4779 if (err || bcmsdh_regfail(sdh))
4780 bus->dhd->busstate = DHD_BUS_DOWN;
4784 dhdsdio_read_control(dhd_bus_t *bus, uint8 *hdr, uint len, uint doff)
4786 bcmsdh_info_t *sdh = bus->sdh;
4791 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4793 /* Control data already received in aligned rxctl */
4794 if ((bus->bus == SPI_BUS) && (!bus->usebufpool))
4798 /* Set rxctl for frame (w/optional alignment) */
4799 bus->rxctl = bus->rxbuf;
4801 bus->rxctl += firstread;
4802 if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN)))
4803 bus->rxctl += (DHD_SDALIGN - pad);
4804 bus->rxctl -= firstread;
4806 ASSERT(bus->rxctl >= bus->rxbuf);
4808 /* Copy the already-read portion over */
4809 bcopy(hdr, bus->rxctl, firstread);
4810 if (len <= firstread)
4813 /* Copy the full data pkt in gSPI case and process ioctl. */
4814 if (bus->bus == SPI_BUS) {
4815 bcopy(hdr, bus->rxctl, len);
4819 /* Raise rdlen to next SDIO block to avoid tail command */
4820 rdlen = len - firstread;
4821 if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
4822 pad = bus->blocksize - (rdlen % bus->blocksize);
4823 if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
4824 ((len + pad) < bus->dhd->maxctl))
4826 } else if (rdlen % DHD_SDALIGN) {
4827 rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
4830 /* Satisfy length-alignment requirements */
4831 if (forcealign && (rdlen & (ALIGNMENT - 1)))
4832 rdlen = ROUNDUP(rdlen, ALIGNMENT);
4834 /* Drop if the read is too big or it exceeds our maximum */
4835 if ((rdlen + firstread) > bus->dhd->maxctl) {
4836 DHD_ERROR(("%s: %d-byte control read exceeds %d-byte buffer\n",
4837 __FUNCTION__, rdlen, bus->dhd->maxctl));
4838 bus->dhd->rx_errors++;
4839 dhdsdio_rxfail(bus, FALSE, FALSE);
4843 if ((len - doff) > bus->dhd->maxctl) {
4844 DHD_ERROR(("%s: %d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n",
4845 __FUNCTION__, len, (len - doff), bus->dhd->maxctl));
4846 bus->dhd->rx_errors++; bus->rx_toolong++;
4847 dhdsdio_rxfail(bus, FALSE, FALSE);
4852 /* Read remainder of frame body into the rxctl buffer */
4853 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
4854 (bus->rxctl + firstread), rdlen, NULL, NULL, NULL);
4856 ASSERT(sdret != BCME_PENDING);
4858 /* Control frame failures need retransmission */
4860 DHD_ERROR(("%s: read %d control bytes failed: %d\n", __FUNCTION__, rdlen, sdret));
4861 bus->rxc_errors++; /* dhd.rx_ctlerrs is higher level */
4862 dhdsdio_rxfail(bus, TRUE, TRUE);
4869 if (DHD_BYTES_ON() && DHD_CTL_ON()) {
4870 prhex("RxCtrl", bus->rxctl, len);
4874 /* Point to valid data and indicate its length */
4876 bus->rxlen = len - doff;
4879 /* Awake any waiters */
4880 dhd_os_ioctl_resp_wake(bus->dhd);
4883 dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf, uint reorder_info_len,
4884 void **pkt, uint32 *pkt_count);
4887 dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq)
4889 uint16 dlen, totlen;
4890 uint8 *dptr, num = 0;
4892 uint16 sublen, check;
4893 void *pfirst, *plast, *pnext;
4894 void * list_tail[DHD_MAX_IFS] = { NULL };
4895 void * list_head[DHD_MAX_IFS] = { NULL };
4897 osl_t *osh = bus->dhd->osh;
4900 uint8 chan, seq, doff, sfdoff;
4902 uchar reorder_info_buf[WLHOST_REORDERDATA_TOTLEN];
4903 uint reorder_info_len;
4906 bool usechain = bus->use_rxchain;
4908 /* If packets, issue read(s) and send up packet chain */
4909 /* Return sequence numbers consumed? */
4911 DHD_TRACE(("dhdsdio_rxglom: start: glomd %p glom %p\n", bus->glomd, bus->glom));
4913 /* If there's a descriptor, generate the packet chain */
4915 dhd_os_sdlock_rxq(bus->dhd);
4917 pfirst = plast = pnext = NULL;
4918 dlen = (uint16)PKTLEN(osh, bus->glomd);
4919 dptr = PKTDATA(osh, bus->glomd);
4920 if (!dlen || (dlen & 1)) {
4921 DHD_ERROR(("%s: bad glomd len (%d), ignore descriptor\n",
4922 __FUNCTION__, dlen));
4926 for (totlen = num = 0; dlen; num++) {
4927 /* Get (and move past) next length */
4928 sublen = ltoh16_ua(dptr);
4929 dlen -= sizeof(uint16);
4930 dptr += sizeof(uint16);
4931 if ((sublen < SDPCM_HDRLEN_RX) ||
4932 ((num == 0) && (sublen < (2 * SDPCM_HDRLEN_RX)))) {
4933 DHD_ERROR(("%s: descriptor len %d bad: %d\n",
4934 __FUNCTION__, num, sublen));
4938 if (sublen % DHD_SDALIGN) {
4939 DHD_ERROR(("%s: sublen %d not a multiple of %d\n",
4940 __FUNCTION__, sublen, DHD_SDALIGN));
4945 /* For last frame, adjust read len so total is a block multiple */
4947 sublen += (ROUNDUP(totlen, bus->blocksize) - totlen);
4948 totlen = ROUNDUP(totlen, bus->blocksize);
4951 /* Allocate/chain packet for next subframe */
4952 if ((pnext = PKTGET(osh, sublen + DHD_SDALIGN, FALSE)) == NULL) {
4953 DHD_ERROR(("%s: PKTGET failed, num %d len %d\n",
4954 __FUNCTION__, num, sublen));
4957 ASSERT(!PKTLINK(pnext));
4960 pfirst = plast = pnext;
4963 PKTSETNEXT(osh, plast, pnext);
4967 /* Adhere to start alignment requirements */
4968 PKTALIGN(osh, pnext, sublen, DHD_SDALIGN);
4971 /* If all allocations succeeded, save packet chain in bus structure */
4973 DHD_GLOM(("%s: allocated %d-byte packet chain for %d subframes\n",
4974 __FUNCTION__, totlen, num));
4975 if (DHD_GLOM_ON() && bus->nextlen) {
4976 if (totlen != bus->nextlen) {
4977 DHD_GLOM(("%s: glomdesc mismatch: nextlen %d glomdesc %d "
4978 "rxseq %d\n", __FUNCTION__, bus->nextlen,
4983 pfirst = pnext = NULL;
4986 PKTFREE(osh, pfirst, FALSE);
4991 /* Done with descriptor packet */
4992 PKTFREE(osh, bus->glomd, FALSE);
4996 dhd_os_sdunlock_rxq(bus->dhd);
4999 /* Ok -- either we just generated a packet chain, or had one from before */
5001 if (DHD_GLOM_ON()) {
5002 DHD_GLOM(("%s: attempt superframe read, packet chain:\n", __FUNCTION__));
5003 for (pnext = bus->glom; pnext; pnext = PKTNEXT(osh, pnext)) {
5004 DHD_GLOM((" %p: %p len 0x%04x (%d)\n",
5005 pnext, (uint8*)PKTDATA(osh, pnext),
5006 PKTLEN(osh, pnext), PKTLEN(osh, pnext)));
5011 dlen = (uint16)pkttotlen(osh, pfirst);
5013 /* Do an SDIO read for the superframe. Configurable iovar to
5014 * read directly into the chained packet, or allocate a large
5015 * packet and and copy into the chain.
5018 errcode = dhd_bcmsdh_recv_buf(bus,
5019 bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2,
5020 F2SYNC, (uint8*)PKTDATA(osh, pfirst),
5021 dlen, pfirst, NULL, NULL);
5022 } else if (bus->dataptr) {
5023 errcode = dhd_bcmsdh_recv_buf(bus,
5024 bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2,
5025 F2SYNC, bus->dataptr,
5026 dlen, NULL, NULL, NULL);
5027 sublen = (uint16)pktfrombuf(osh, pfirst, 0, dlen, bus->dataptr);
5028 if (sublen != dlen) {
5029 DHD_ERROR(("%s: FAILED TO COPY, dlen %d sublen %d\n",
5030 __FUNCTION__, dlen, sublen));
5035 DHD_ERROR(("COULDN'T ALLOC %d-BYTE GLOM, FORCE FAILURE\n", dlen));
5039 ASSERT(errcode != BCME_PENDING);
5041 /* On failure, kill the superframe, allow a couple retries */
5043 DHD_ERROR(("%s: glom read of %d bytes failed: %d\n",
5044 __FUNCTION__, dlen, errcode));
5045 bus->dhd->rx_errors++;
5047 if (bus->glomerr++ < 3) {
5048 dhdsdio_rxfail(bus, TRUE, TRUE);
5051 dhdsdio_rxfail(bus, TRUE, FALSE);
5052 dhd_os_sdlock_rxq(bus->dhd);
5053 PKTFREE(osh, bus->glom, FALSE);
5054 dhd_os_sdunlock_rxq(bus->dhd);
5062 if (DHD_GLOM_ON()) {
5063 prhex("SUPERFRAME", PKTDATA(osh, pfirst),
5064 MIN(PKTLEN(osh, pfirst), 48));
5069 /* Validate the superframe header */
5070 dptr = (uint8 *)PKTDATA(osh, pfirst);
5071 sublen = ltoh16_ua(dptr);
5072 check = ltoh16_ua(dptr + sizeof(uint16));
5074 chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
5075 seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
5076 bus->nextlen = dptr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
5077 if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
5078 DHD_INFO(("%s: got frame w/nextlen too large (%d) seq %d\n",
5079 __FUNCTION__, bus->nextlen, seq));
5082 doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
5083 txmax = SDPCM_WINDOW_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
5086 if ((uint16)~(sublen^check)) {
5087 DHD_ERROR(("%s (superframe): HW hdr error: len/check 0x%04x/0x%04x\n",
5088 __FUNCTION__, sublen, check));
5090 } else if (ROUNDUP(sublen, bus->blocksize) != dlen) {
5091 DHD_ERROR(("%s (superframe): len 0x%04x, rounded 0x%04x, expect 0x%04x\n",
5092 __FUNCTION__, sublen, ROUNDUP(sublen, bus->blocksize), dlen));
5094 } else if (SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]) != SDPCM_GLOM_CHANNEL) {
5095 DHD_ERROR(("%s (superframe): bad channel %d\n", __FUNCTION__,
5096 SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN])));
5098 } else if (SDPCM_GLOMDESC(&dptr[SDPCM_FRAMETAG_LEN])) {
5099 DHD_ERROR(("%s (superframe): got second descriptor?\n", __FUNCTION__));
5101 } else if ((doff < SDPCM_HDRLEN_RX) ||
5102 (doff > (PKTLEN(osh, pfirst) - SDPCM_HDRLEN_RX))) {
5103 DHD_ERROR(("%s (superframe): Bad data offset %d: HW %d pkt %d min %d\n",
5104 __FUNCTION__, doff, sublen, PKTLEN(osh, pfirst),
5109 /* Check sequence number of superframe SW header */
5111 DHD_INFO(("%s: (superframe) rx_seq %d, expected %d\n",
5112 __FUNCTION__, seq, rxseq));
5117 /* Check window for sanity */
5118 if ((uint8)(txmax - bus->tx_seq) > 0x40) {
5119 DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
5120 __FUNCTION__, txmax, bus->tx_seq));
5121 txmax = bus->tx_max;
5123 bus->tx_max = txmax;
5125 /* Remove superframe header, remember offset */
5126 PKTPULL(osh, pfirst, doff);
5129 /* Validate all the subframe headers */
5130 for (num = 0, pnext = pfirst; pnext && !errcode;
5131 num++, pnext = PKTNEXT(osh, pnext)) {
5132 dptr = (uint8 *)PKTDATA(osh, pnext);
5133 dlen = (uint16)PKTLEN(osh, pnext);
5134 sublen = ltoh16_ua(dptr);
5135 check = ltoh16_ua(dptr + sizeof(uint16));
5136 chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
5137 doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
5139 if (DHD_GLOM_ON()) {
5140 prhex("subframe", dptr, 32);
5144 if ((uint16)~(sublen^check)) {
5145 DHD_ERROR(("%s (subframe %d): HW hdr error: "
5146 "len/check 0x%04x/0x%04x\n",
5147 __FUNCTION__, num, sublen, check));
5149 } else if ((sublen > dlen) || (sublen < SDPCM_HDRLEN_RX)) {
5150 DHD_ERROR(("%s (subframe %d): length mismatch: "
5151 "len 0x%04x, expect 0x%04x\n",
5152 __FUNCTION__, num, sublen, dlen));
5154 } else if ((chan != SDPCM_DATA_CHANNEL) &&
5155 (chan != SDPCM_EVENT_CHANNEL)) {
5156 DHD_ERROR(("%s (subframe %d): bad channel %d\n",
5157 __FUNCTION__, num, chan));
5159 } else if ((doff < SDPCM_HDRLEN_RX) || (doff > sublen)) {
5160 DHD_ERROR(("%s (subframe %d): Bad data offset %d: HW %d min %d\n",
5161 __FUNCTION__, num, doff, sublen, SDPCM_HDRLEN_RX));
5167 /* Terminate frame on error, request a couple retries */
5168 if (bus->glomerr++ < 3) {
5169 /* Restore superframe header space */
5170 PKTPUSH(osh, pfirst, sfdoff);
5171 dhdsdio_rxfail(bus, TRUE, TRUE);
5174 dhdsdio_rxfail(bus, TRUE, FALSE);
5175 dhd_os_sdlock_rxq(bus->dhd);
5176 PKTFREE(osh, bus->glom, FALSE);
5177 dhd_os_sdunlock_rxq(bus->dhd);
5185 /* Basic SD framing looks ok - process each packet (header) */
5189 dhd_os_sdlock_rxq(bus->dhd);
5190 for (num = 0; pfirst; rxseq++, pfirst = pnext) {
5191 pnext = PKTNEXT(osh, pfirst);
5192 PKTSETNEXT(osh, pfirst, NULL);
5194 dptr = (uint8 *)PKTDATA(osh, pfirst);
5195 sublen = ltoh16_ua(dptr);
5196 chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
5197 seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
5198 doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
5200 DHD_GLOM(("%s: Get subframe %d, %p(%p/%d), sublen %d chan %d seq %d\n",
5201 __FUNCTION__, num, pfirst, PKTDATA(osh, pfirst),
5202 PKTLEN(osh, pfirst), sublen, chan, seq));
5204 ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL));
5207 DHD_GLOM(("%s: rx_seq %d, expected %d\n",
5208 __FUNCTION__, seq, rxseq));
5214 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
5215 prhex("Rx Subframe Data", dptr, dlen);
5219 PKTSETLEN(osh, pfirst, sublen);
5220 PKTPULL(osh, pfirst, doff);
5222 reorder_info_len = sizeof(reorder_info_buf);
5224 if (PKTLEN(osh, pfirst) == 0) {
5225 PKTFREE(bus->dhd->osh, pfirst, FALSE);
5227 } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pfirst, reorder_info_buf,
5228 &reorder_info_len) != 0) {
5229 DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__));
5230 bus->dhd->rx_errors++;
5231 PKTFREE(osh, pfirst, FALSE);
5234 if (reorder_info_len) {
5235 uint32 free_buf_count;
5239 /* Reordering info from the firmware */
5240 dhd_process_pkt_reorder_info(bus->dhd, reorder_info_buf,
5241 reorder_info_len, &ppfirst, &free_buf_count);
5243 if (free_buf_count == 0) {
5249 /* go to the end of the chain and attach the pnext there */
5251 while (PKTNEXT(osh, temp) != NULL) {
5252 temp = PKTNEXT(osh, temp);
5255 if (list_tail[ifidx] == NULL)
5256 list_head[ifidx] = ppfirst;
5258 PKTSETNEXT(osh, list_tail[ifidx], ppfirst);
5259 list_tail[ifidx] = pfirst;
5262 num += (uint8)free_buf_count;
5265 /* this packet will go up, link back into chain and count it */
5267 if (list_tail[ifidx] == NULL) {
5268 list_head[ifidx] = list_tail[ifidx] = pfirst;
5271 PKTSETNEXT(osh, list_tail[ifidx], pfirst);
5272 list_tail[ifidx] = pfirst;
5277 if (DHD_GLOM_ON()) {
5278 DHD_GLOM(("%s subframe %d to stack, %p(%p/%d) nxt/lnk %p/%p\n",
5279 __FUNCTION__, num, pfirst,
5280 PKTDATA(osh, pfirst), PKTLEN(osh, pfirst),
5281 PKTNEXT(osh, pfirst), PKTLINK(pfirst)));
5282 prhex("", (uint8 *)PKTDATA(osh, pfirst),
5283 MIN(PKTLEN(osh, pfirst), 32));
5285 #endif /* DHD_DEBUG */
5287 dhd_os_sdunlock_rxq(bus->dhd);
5289 for (idx = 0; idx < DHD_MAX_IFS; idx++) {
5290 if (list_head[idx]) {
5293 temp = list_head[idx];
5295 temp = PKTNEXT(osh, temp);
5299 dhd_os_sdunlock(bus->dhd);
5300 dhd_rx_frame(bus->dhd, idx, list_head[idx], cnt, 0);
5301 dhd_os_sdlock(bus->dhd);
5305 bus->rxglomframes++;
5306 bus->rxglompkts += num;
5312 /* Return TRUE if there may be more frames to read */
5314 dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished)
5316 osl_t *osh = bus->dhd->osh;
5317 bcmsdh_info_t *sdh = bus->sdh;
5319 uint16 len, check; /* Extracted hardware header fields */
5320 uint8 chan, seq, doff; /* Extracted software header fields */
5321 uint8 fcbits; /* Extracted fcbits from software header */
5324 void *pkt; /* Packet for event or data frames */
5325 uint16 pad; /* Number of pad bytes to read */
5326 uint16 rdlen; /* Total number of bytes to read */
5327 uint8 rxseq; /* Next sequence number to expect */
5328 uint rxleft = 0; /* Remaining number of frames allowed */
5329 int sdret; /* Return code from bcmsdh calls */
5330 uint8 txmax; /* Maximum tx sequence offered */
5331 bool len_consistent; /* Result of comparing readahead len and len from hw-hdr */
5334 uint rxcount = 0; /* Total frames read */
5335 uchar reorder_info_buf[WLHOST_REORDERDATA_TOTLEN];
5336 uint reorder_info_len;
5339 #if defined(DHD_DEBUG) || defined(SDTEST)
5340 bool sdtest = FALSE; /* To limit message spew from test mode */
5343 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5345 bus->readframes = TRUE;
5347 if (!KSO_ENAB(bus)) {
5348 DHD_ERROR(("%s: KSO off\n", __FUNCTION__));
5349 bus->readframes = FALSE;
5356 /* Allow pktgen to override maxframes */
5357 if (bus->pktgen_count && (bus->pktgen_mode == DHD_PKTGEN_RECV)) {
5358 maxframes = bus->pktgen_count;
5363 /* Not finished unless we encounter no more frames indication */
5367 for (rxseq = bus->rx_seq, rxleft = maxframes;
5368 !bus->rxskip && rxleft && bus->dhd->busstate != DHD_BUS_DOWN;
5369 rxseq++, rxleft--) {
5372 /* tx more to improve rx performance */
5373 if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL)) {
5374 dhdsdio_sendpendctl(bus);
5375 } else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate &&
5376 pktq_mlen(&bus->txq, ~bus->flowcontrol) && DATAOK(bus)) {
5377 dhdsdio_sendfromq(bus, dhd_txbound);
5379 #endif /* DHDTHREAD */
5381 /* Handle glomming separately */
5382 if (bus->glom || bus->glomd) {
5384 DHD_GLOM(("%s: calling rxglom: glomd %p, glom %p\n",
5385 __FUNCTION__, bus->glomd, bus->glom));
5386 cnt = dhdsdio_rxglom(bus, rxseq);
5387 DHD_GLOM(("%s: rxglom returned %d\n", __FUNCTION__, cnt));
5389 rxleft = (rxleft > cnt) ? (rxleft - cnt) : 1;
5393 /* Try doing single read if we can */
5394 if (dhd_readahead && bus->nextlen) {
5395 uint16 nextlen = bus->nextlen;
5398 if (bus->bus == SPI_BUS) {
5399 rdlen = len = nextlen;
5402 rdlen = len = nextlen << 4;
5404 /* Pad read to blocksize for efficiency */
5405 if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
5406 pad = bus->blocksize - (rdlen % bus->blocksize);
5407 if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
5408 ((rdlen + pad + firstread) < MAX_RX_DATASZ))
5410 } else if (rdlen % DHD_SDALIGN) {
5411 rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
5415 /* We use bus->rxctl buffer in WinXP for initial control pkt receives.
5416 * Later we use buffer-poll for data as well as control packets.
5417 * This is required because dhd receives full frame in gSPI unlike SDIO.
5418 * After the frame is received we have to distinguish whether it is data
5419 * or non-data frame.
5421 /* Allocate a packet buffer */
5422 dhd_os_sdlock_rxq(bus->dhd);
5423 if (!(pkt = PKTGET(osh, rdlen + DHD_SDALIGN, FALSE))) {
5424 if (bus->bus == SPI_BUS) {
5425 bus->usebufpool = FALSE;
5426 bus->rxctl = bus->rxbuf;
5428 bus->rxctl += firstread;
5429 if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN)))
5430 bus->rxctl += (DHD_SDALIGN - pad);
5431 bus->rxctl -= firstread;
5433 ASSERT(bus->rxctl >= bus->rxbuf);
5435 /* Read the entire frame */
5436 sdret = dhd_bcmsdh_recv_buf(bus,
5437 bcmsdh_cur_sbwad(sdh),
5439 F2SYNC, rxbuf, rdlen,
5442 ASSERT(sdret != BCME_PENDING);
5445 /* Control frame failures need retransmission */
5447 DHD_ERROR(("%s: read %d control bytes failed: %d\n",
5448 __FUNCTION__, rdlen, sdret));
5449 /* dhd.rx_ctlerrs is higher level */
5451 dhd_os_sdunlock_rxq(bus->dhd);
5452 dhdsdio_rxfail(bus, TRUE,
5453 (bus->bus == SPI_BUS) ? FALSE : TRUE);
5457 /* Give up on data, request rtx of events */
5458 DHD_ERROR(("%s (nextlen): PKTGET failed: len %d rdlen %d "
5459 "expected rxseq %d\n",
5460 __FUNCTION__, len, rdlen, rxseq));
5461 /* Just go try again w/normal header read */
5462 dhd_os_sdunlock_rxq(bus->dhd);
5466 if (bus->bus == SPI_BUS)
5467 bus->usebufpool = TRUE;
5469 ASSERT(!PKTLINK(pkt));
5470 PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN);
5471 rxbuf = (uint8 *)PKTDATA(osh, pkt);
5472 /* Read the entire frame */
5473 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh),
5475 F2SYNC, rxbuf, rdlen,
5478 ASSERT(sdret != BCME_PENDING);
5481 DHD_ERROR(("%s (nextlen): read %d bytes failed: %d\n",
5482 __FUNCTION__, rdlen, sdret));
5483 PKTFREE(bus->dhd->osh, pkt, FALSE);
5484 bus->dhd->rx_errors++;
5485 dhd_os_sdunlock_rxq(bus->dhd);
5486 /* Force retry w/normal header read. Don't attempt NAK for
5489 dhdsdio_rxfail(bus, TRUE,
5490 (bus->bus == SPI_BUS) ? FALSE : TRUE);
5494 dhd_os_sdunlock_rxq(bus->dhd);
5496 /* Now check the header */
5497 bcopy(rxbuf, bus->rxhdr, SDPCM_HDRLEN_RX);
5499 /* Extract hardware header fields */
5500 len = ltoh16_ua(bus->rxhdr);
5501 check = ltoh16_ua(bus->rxhdr + sizeof(uint16));
5503 /* All zeros means readahead info was bad */
5505 DHD_INFO(("%s (nextlen): read zeros in HW header???\n",
5507 dhd_os_sdlock_rxq(bus->dhd);
5509 dhd_os_sdunlock_rxq(bus->dhd);
5510 GSPI_PR55150_BAILOUT;
5514 /* Validate check bytes */
5515 if ((uint16)~(len^check)) {
5516 DHD_ERROR(("%s (nextlen): HW hdr error: nextlen/len/check"
5517 " 0x%04x/0x%04x/0x%04x\n", __FUNCTION__, nextlen,
5519 dhd_os_sdlock_rxq(bus->dhd);
5521 dhd_os_sdunlock_rxq(bus->dhd);
5523 dhdsdio_rxfail(bus, FALSE, FALSE);
5524 GSPI_PR55150_BAILOUT;
5528 /* Validate frame length */
5529 if (len < SDPCM_HDRLEN_RX) {
5530 DHD_ERROR(("%s (nextlen): HW hdr length invalid: %d\n",
5531 __FUNCTION__, len));
5532 dhd_os_sdlock_rxq(bus->dhd);
5534 dhd_os_sdunlock_rxq(bus->dhd);
5535 GSPI_PR55150_BAILOUT;
5539 /* Check for consistency with readahead info */
5540 len_consistent = (nextlen != (ROUNDUP(len, 16) >> 4));
5541 if (len_consistent) {
5542 /* Mismatch, force retry w/normal header (may be >4K) */
5543 DHD_ERROR(("%s (nextlen): mismatch, nextlen %d len %d rnd %d; "
5544 "expected rxseq %d\n",
5545 __FUNCTION__, nextlen, len, ROUNDUP(len, 16), rxseq));
5546 dhd_os_sdlock_rxq(bus->dhd);
5548 dhd_os_sdunlock_rxq(bus->dhd);
5549 dhdsdio_rxfail(bus, TRUE, (bus->bus == SPI_BUS) ? FALSE : TRUE);
5550 GSPI_PR55150_BAILOUT;
5555 /* Extract software header fields */
5556 chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5557 seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5558 doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5559 txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5562 bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
5563 if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
5564 DHD_INFO(("%s (nextlen): got frame w/nextlen too large"
5565 " (%d), seq %d\n", __FUNCTION__, bus->nextlen,
5570 bus->dhd->rx_readahead_cnt ++;
5571 /* Handle Flow Control */
5572 fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5575 if (~bus->flowcontrol & fcbits) {
5579 if (bus->flowcontrol & ~fcbits) {
5586 bus->flowcontrol = fcbits;
5589 /* Check and update sequence number */
5591 DHD_INFO(("%s (nextlen): rx_seq %d, expected %d\n",
5592 __FUNCTION__, seq, rxseq));
5597 /* Check window for sanity */
5598 if ((uint8)(txmax - bus->tx_seq) > 0x40) {
5599 DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
5600 __FUNCTION__, txmax, bus->tx_seq));
5601 txmax = bus->tx_max;
5603 bus->tx_max = txmax;
5606 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
5607 prhex("Rx Data", rxbuf, len);
5608 } else if (DHD_HDRS_ON()) {
5609 prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN_RX);
5613 if (chan == SDPCM_CONTROL_CHANNEL) {
5614 if (bus->bus == SPI_BUS) {
5615 dhdsdio_read_control(bus, rxbuf, len, doff);
5616 if (bus->usebufpool) {
5617 dhd_os_sdlock_rxq(bus->dhd);
5618 PKTFREE(bus->dhd->osh, pkt, FALSE);
5619 dhd_os_sdunlock_rxq(bus->dhd);
5623 DHD_ERROR(("%s (nextlen): readahead on control"
5624 " packet %d?\n", __FUNCTION__, seq));
5625 /* Force retry w/normal header read */
5627 dhdsdio_rxfail(bus, FALSE, TRUE);
5628 dhd_os_sdlock_rxq(bus->dhd);
5630 dhd_os_sdunlock_rxq(bus->dhd);
5635 if ((bus->bus == SPI_BUS) && !bus->usebufpool) {
5636 DHD_ERROR(("Received %d bytes on %d channel. Running out of "
5637 "rx pktbuf's or not yet malloced.\n", len, chan));
5641 /* Validate data offset */
5642 if ((doff < SDPCM_HDRLEN_RX) || (doff > len)) {
5643 DHD_ERROR(("%s (nextlen): bad data offset %d: HW len %d min %d\n",
5644 __FUNCTION__, doff, len, SDPCM_HDRLEN_RX));
5645 dhd_os_sdlock_rxq(bus->dhd);
5647 dhd_os_sdunlock_rxq(bus->dhd);
5649 dhdsdio_rxfail(bus, FALSE, FALSE);
5653 /* All done with this one -- now deliver the packet */
5656 /* gSPI frames should not be handled in fractions */
5657 if (bus->bus == SPI_BUS) {
5661 /* Read frame header (hardware and software) */
5662 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
5663 bus->rxhdr, firstread, NULL, NULL, NULL);
5665 ASSERT(sdret != BCME_PENDING);
5668 DHD_ERROR(("%s: RXHEADER FAILED: %d\n", __FUNCTION__, sdret));
5670 dhdsdio_rxfail(bus, TRUE, TRUE);
5675 if (DHD_BYTES_ON() || DHD_HDRS_ON()) {
5676 prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN_RX);
5680 /* Extract hardware header fields */
5681 len = ltoh16_ua(bus->rxhdr);
5682 check = ltoh16_ua(bus->rxhdr + sizeof(uint16));
5684 /* All zeros means no more frames */
5690 /* Validate check bytes */
5691 if ((uint16)~(len^check)) {
5692 DHD_ERROR(("%s: HW hdr error: len/check 0x%04x/0x%04x\n",
5693 __FUNCTION__, len, check));
5695 dhdsdio_rxfail(bus, FALSE, FALSE);
5699 /* Validate frame length */
5700 if (len < SDPCM_HDRLEN_RX) {
5701 DHD_ERROR(("%s: HW hdr length invalid: %d\n", __FUNCTION__, len));
5705 /* Extract software header fields */
5706 chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5707 seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5708 doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5709 txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5711 /* Validate data offset */
5712 if ((doff < SDPCM_HDRLEN_RX) || (doff > len)) {
5713 DHD_ERROR(("%s: Bad data offset %d: HW len %d, min %d seq %d\n",
5714 __FUNCTION__, doff, len, SDPCM_HDRLEN_RX, seq));
5717 dhdsdio_rxfail(bus, FALSE, FALSE);
5721 /* Save the readahead length if there is one */
5722 bus->nextlen = bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
5723 if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
5724 DHD_INFO(("%s (nextlen): got frame w/nextlen too large (%d), seq %d\n",
5725 __FUNCTION__, bus->nextlen, seq));
5729 /* Handle Flow Control */
5730 fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5733 if (~bus->flowcontrol & fcbits) {
5737 if (bus->flowcontrol & ~fcbits) {
5744 bus->flowcontrol = fcbits;
5747 /* Check and update sequence number */
5749 DHD_INFO(("%s: rx_seq %d, expected %d\n", __FUNCTION__, seq, rxseq));
5754 /* Check window for sanity */
5755 if ((uint8)(txmax - bus->tx_seq) > 0x40) {
5756 DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
5757 __FUNCTION__, txmax, bus->tx_seq));
5758 txmax = bus->tx_max;
5760 bus->tx_max = txmax;
5762 /* Call a separate function for control frames */
5763 if (chan == SDPCM_CONTROL_CHANNEL) {
5764 dhdsdio_read_control(bus, bus->rxhdr, len, doff);
5768 ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL) ||
5769 (chan == SDPCM_TEST_CHANNEL) || (chan == SDPCM_GLOM_CHANNEL));
5771 /* Length to read */
5772 rdlen = (len > firstread) ? (len - firstread) : 0;
5774 /* May pad read to blocksize for efficiency */
5775 if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
5776 pad = bus->blocksize - (rdlen % bus->blocksize);
5777 if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
5778 ((rdlen + pad + firstread) < MAX_RX_DATASZ))
5780 } else if (rdlen % DHD_SDALIGN) {
5781 rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
5784 /* Satisfy length-alignment requirements */
5785 if (forcealign && (rdlen & (ALIGNMENT - 1)))
5786 rdlen = ROUNDUP(rdlen, ALIGNMENT);
5788 if ((rdlen + firstread) > MAX_RX_DATASZ) {
5789 /* Too long -- skip this frame */
5790 DHD_ERROR(("%s: too long: len %d rdlen %d\n", __FUNCTION__, len, rdlen));
5791 bus->dhd->rx_errors++; bus->rx_toolong++;
5792 dhdsdio_rxfail(bus, FALSE, FALSE);
5796 dhd_os_sdlock_rxq(bus->dhd);
5797 if (!(pkt = PKTGET(osh, (rdlen + firstread + DHD_SDALIGN), FALSE))) {
5798 /* Give up on data, request rtx of events */
5799 DHD_ERROR(("%s: PKTGET failed: rdlen %d chan %d\n",
5800 __FUNCTION__, rdlen, chan));
5801 bus->dhd->rx_dropped++;
5802 dhd_os_sdunlock_rxq(bus->dhd);
5803 dhdsdio_rxfail(bus, FALSE, RETRYCHAN(chan));
5806 dhd_os_sdunlock_rxq(bus->dhd);
5808 ASSERT(!PKTLINK(pkt));
5810 /* Leave room for what we already read, and align remainder */
5811 ASSERT(firstread < (PKTLEN(osh, pkt)));
5812 PKTPULL(osh, pkt, firstread);
5813 PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN);
5815 /* Read the remaining frame data */
5816 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
5817 ((uint8 *)PKTDATA(osh, pkt)), rdlen, pkt, NULL, NULL);
5819 ASSERT(sdret != BCME_PENDING);
5822 DHD_ERROR(("%s: read %d %s bytes failed: %d\n", __FUNCTION__, rdlen,
5823 ((chan == SDPCM_EVENT_CHANNEL) ? "event" :
5824 ((chan == SDPCM_DATA_CHANNEL) ? "data" : "test")), sdret));
5825 dhd_os_sdlock_rxq(bus->dhd);
5826 PKTFREE(bus->dhd->osh, pkt, FALSE);
5827 dhd_os_sdunlock_rxq(bus->dhd);
5828 bus->dhd->rx_errors++;
5829 dhdsdio_rxfail(bus, TRUE, RETRYCHAN(chan));
5833 /* Copy the already-read portion */
5834 PKTPUSH(osh, pkt, firstread);
5835 bcopy(bus->rxhdr, PKTDATA(osh, pkt), firstread);
5838 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
5839 prhex("Rx Data", PKTDATA(osh, pkt), len);
5844 /* Save superframe descriptor and allocate packet frame */
5845 if (chan == SDPCM_GLOM_CHANNEL) {
5846 if (SDPCM_GLOMDESC(&bus->rxhdr[SDPCM_FRAMETAG_LEN])) {
5847 DHD_GLOM(("%s: got glom descriptor, %d bytes:\n",
5848 __FUNCTION__, len));
5850 if (DHD_GLOM_ON()) {
5851 prhex("Glom Data", PKTDATA(osh, pkt), len);
5854 PKTSETLEN(osh, pkt, len);
5855 ASSERT(doff == SDPCM_HDRLEN_RX);
5856 PKTPULL(osh, pkt, SDPCM_HDRLEN_RX);
5859 DHD_ERROR(("%s: glom superframe w/o descriptor!\n", __FUNCTION__));
5860 dhdsdio_rxfail(bus, FALSE, FALSE);
5865 /* Fill in packet len and prio, deliver upward */
5866 PKTSETLEN(osh, pkt, len);
5867 PKTPULL(osh, pkt, doff);
5870 /* Test channel packets are processed separately */
5871 if (chan == SDPCM_TEST_CHANNEL) {
5872 dhdsdio_testrcv(bus, pkt, seq);
5877 if (PKTLEN(osh, pkt) == 0) {
5878 dhd_os_sdlock_rxq(bus->dhd);
5879 PKTFREE(bus->dhd->osh, pkt, FALSE);
5880 dhd_os_sdunlock_rxq(bus->dhd);
5882 } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pkt, reorder_info_buf,
5883 &reorder_info_len) != 0) {
5884 DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__));
5885 dhd_os_sdlock_rxq(bus->dhd);
5886 PKTFREE(bus->dhd->osh, pkt, FALSE);
5887 dhd_os_sdunlock_rxq(bus->dhd);
5888 bus->dhd->rx_errors++;
5891 if (reorder_info_len) {
5892 /* Reordering info from the firmware */
5893 dhd_process_pkt_reorder_info(bus->dhd, reorder_info_buf, reorder_info_len,
5901 /* Unlock during rx call */
5902 dhd_os_sdunlock(bus->dhd);
5903 dhd_rx_frame(bus->dhd, ifidx, pkt, pkt_count, chan);
5904 dhd_os_sdlock(bus->dhd);
5906 rxcount = maxframes - rxleft;
5908 /* Message if we hit the limit */
5909 if (!rxleft && !sdtest)
5910 DHD_DATA(("%s: hit rx limit of %d frames\n", __FUNCTION__, maxframes));
5912 #endif /* DHD_DEBUG */
5913 DHD_DATA(("%s: processed %d frames\n", __FUNCTION__, rxcount));
5914 /* Back off rxseq if awaiting rtx, update rx_seq */
5917 bus->rx_seq = rxseq;
5919 if (bus->reqbussleep)
5921 dhdsdio_bussleep(bus, TRUE);
5922 bus->reqbussleep = FALSE;
5924 bus->readframes = FALSE;
5930 dhdsdio_hostmail(dhd_bus_t *bus)
5932 sdpcmd_regs_t *regs = bus->regs;
5933 uint32 intstatus = 0;
5938 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5940 /* Read mailbox data and ack that we did so */
5941 R_SDREG(hmb_data, ®s->tohostmailboxdata, retries);
5942 if (retries <= retry_limit)
5943 W_SDREG(SMB_INT_ACK, ®s->tosbmailbox, retries);
5944 bus->f1regdata += 2;
5946 /* Dongle recomposed rx frames, accept them again */
5947 if (hmb_data & HMB_DATA_NAKHANDLED) {
5948 DHD_INFO(("Dongle reports NAK handled, expect rtx of %d\n", bus->rx_seq));
5950 DHD_ERROR(("%s: unexpected NAKHANDLED!\n", __FUNCTION__));
5952 bus->rxskip = FALSE;
5953 intstatus |= FRAME_AVAIL_MASK(bus);
5957 * DEVREADY does not occur with gSPI.
5959 if (hmb_data & (HMB_DATA_DEVREADY | HMB_DATA_FWREADY)) {
5960 bus->sdpcm_ver = (hmb_data & HMB_DATA_VERSION_MASK) >> HMB_DATA_VERSION_SHIFT;
5961 if (bus->sdpcm_ver != SDPCM_PROT_VERSION)
5962 DHD_ERROR(("Version mismatch, dongle reports %d, expecting %d\n",
5963 bus->sdpcm_ver, SDPCM_PROT_VERSION));
5965 DHD_INFO(("Dongle ready, protocol version %d\n", bus->sdpcm_ver));
5966 /* make sure for the SDIO_DEVICE_RXDATAINT_MODE_1 corecontrol is proper */
5967 if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev >= 4) &&
5968 (bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_1)) {
5971 val = R_REG(bus->dhd->osh, &bus->regs->corecontrol);
5972 val &= ~CC_XMTDATAAVAIL_MODE;
5973 val |= CC_XMTDATAAVAIL_CTRL;
5974 W_REG(bus->dhd->osh, &bus->regs->corecontrol, val);
5976 val = R_REG(bus->dhd->osh, &bus->regs->corecontrol);
5980 /* Retrieve console state address now that firmware should have updated it */
5982 sdpcm_shared_t shared;
5983 if (dhdsdio_readshared(bus, &shared) == 0)
5984 bus->console_addr = shared.console_addr;
5986 #endif /* DHD_DEBUG */
5990 * Flow Control has been moved into the RX headers and this out of band
5991 * method isn't used any more. Leave this here for possibly remaining backward
5992 * compatible with older dongles
5994 if (hmb_data & HMB_DATA_FC) {
5995 fcbits = (hmb_data & HMB_DATA_FCDATA_MASK) >> HMB_DATA_FCDATA_SHIFT;
5997 if (fcbits & ~bus->flowcontrol)
5999 if (bus->flowcontrol & ~fcbits)
6003 bus->flowcontrol = fcbits;
6007 /* At least print a message if FW halted */
6008 if (hmb_data & HMB_DATA_FWHALT) {
6009 DHD_ERROR(("INTERNAL ERROR: FIRMWARE HALTED : set BUS DOWN\n"));
6010 dhdsdio_checkdied(bus, NULL, 0);
6011 bus->dhd->busstate = DHD_BUS_DOWN;
6013 #endif /* DHD_DEBUG */
6015 /* Shouldn't be any others */
6016 if (hmb_data & ~(HMB_DATA_DEVREADY |
6018 HMB_DATA_NAKHANDLED |
6021 HMB_DATA_FCDATA_MASK |
6022 HMB_DATA_VERSION_MASK)) {
6023 DHD_ERROR(("Unknown mailbox data content: 0x%02x\n", hmb_data));
6030 dhdsdio_dpc(dhd_bus_t *bus)
6032 bcmsdh_info_t *sdh = bus->sdh;
6033 sdpcmd_regs_t *regs = bus->regs;
6034 uint32 intstatus, newstatus = 0;
6036 uint rxlimit = dhd_rxbound; /* Rx frames to read before resched */
6037 uint txlimit = dhd_txbound; /* Tx frames to send before resched */
6038 uint framecnt = 0; /* Temporary counter of tx/rx frames */
6039 bool rxdone = TRUE; /* Flag for no more read data */
6040 bool resched = FALSE; /* Flag indicating resched wanted */
6041 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
6043 if (bus->dhd->busstate == DHD_BUS_DOWN) {
6044 DHD_ERROR(("%s: Bus down, ret\n", __FUNCTION__));
6049 /* Start with leftover status bits */
6050 intstatus = bus->intstatus;
6052 dhd_os_sdlock(bus->dhd);
6054 // terence 20131025: fix kernel panic issue if user is enabling and disabling Wi-Fi
6055 if (bus->dhd->busstate == DHD_BUS_DOWN) {
6056 DHD_ERROR(("%s: Bus down 2, ret\n", __FUNCTION__));
6058 dhd_os_sdunlock(bus->dhd);
6062 if (!SLPAUTO_ENAB(bus) && !KSO_ENAB(bus)) {
6063 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
6067 /* If waiting for HTAVAIL, check status */
6068 if (!SLPAUTO_ENAB(bus) && (bus->clkstate == CLK_PENDING)) {
6070 uint8 clkctl, devctl = 0;
6073 /* Check for inconsistent device control */
6074 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
6076 DHD_ERROR(("%s: error reading DEVCTL: %d\n", __FUNCTION__, err));
6077 bus->dhd->busstate = DHD_BUS_DOWN;
6079 ASSERT(devctl & SBSDIO_DEVCTL_CA_INT_ONLY);
6081 #endif /* DHD_DEBUG */
6083 /* Read CSR, if clock on switch to AVAIL, else ignore */
6084 clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
6086 DHD_ERROR(("%s: error reading CSR: %d\n", __FUNCTION__, err));
6087 bus->dhd->busstate = DHD_BUS_DOWN;
6090 DHD_INFO(("DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n", devctl, clkctl));
6092 if (SBSDIO_HTAV(clkctl)) {
6093 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
6095 DHD_ERROR(("%s: error reading DEVCTL: %d\n",
6096 __FUNCTION__, err));
6097 bus->dhd->busstate = DHD_BUS_DOWN;
6099 devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
6100 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
6102 DHD_ERROR(("%s: error writing DEVCTL: %d\n",
6103 __FUNCTION__, err));
6104 bus->dhd->busstate = DHD_BUS_DOWN;
6106 bus->clkstate = CLK_AVAIL;
6114 /* Make sure backplane clock is on */
6115 dhdsdio_clkctl(bus, CLK_AVAIL, TRUE);
6116 if (bus->clkstate != CLK_AVAIL)
6119 /* Pending interrupt indicates new device status */
6122 R_SDREG(newstatus, ®s->intstatus, retries);
6124 if (bcmsdh_regfail(bus->sdh))
6126 newstatus &= bus->hostintmask;
6127 bus->fcstate = !!(newstatus & I_HMB_FC_STATE);
6130 if ((bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_0) &&
6131 (newstatus == I_XMTDATA_AVAIL)) {
6134 W_SDREG(newstatus, ®s->intstatus, retries);
6138 /* Merge new bits with previous */
6139 intstatus |= newstatus;
6142 /* Handle flow-control change: read new state in case our ack
6143 * crossed another change interrupt. If change still set, assume
6144 * FC ON for safety, let next loop through do the debounce.
6146 if (intstatus & I_HMB_FC_CHANGE) {
6147 intstatus &= ~I_HMB_FC_CHANGE;
6148 W_SDREG(I_HMB_FC_CHANGE, ®s->intstatus, retries);
6149 R_SDREG(newstatus, ®s->intstatus, retries);
6150 bus->f1regdata += 2;
6151 bus->fcstate = !!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE));
6152 intstatus |= (newstatus & bus->hostintmask);
6155 /* Just being here means nothing more to do for chipactive */
6156 if (intstatus & I_CHIPACTIVE) {
6157 /* ASSERT(bus->clkstate == CLK_AVAIL); */
6158 intstatus &= ~I_CHIPACTIVE;
6161 /* Handle host mailbox indication */
6162 if (intstatus & I_HMB_HOST_INT) {
6163 intstatus &= ~I_HMB_HOST_INT;
6164 intstatus |= dhdsdio_hostmail(bus);
6167 /* Generally don't ask for these, can get CRC errors... */
6168 if (intstatus & I_WR_OOSYNC) {
6169 DHD_ERROR(("Dongle reports WR_OOSYNC\n"));
6170 intstatus &= ~I_WR_OOSYNC;
6173 if (intstatus & I_RD_OOSYNC) {
6174 DHD_ERROR(("Dongle reports RD_OOSYNC\n"));
6175 intstatus &= ~I_RD_OOSYNC;
6178 if (intstatus & I_SBINT) {
6179 DHD_ERROR(("Dongle reports SBINT\n"));
6180 intstatus &= ~I_SBINT;
6183 /* Would be active due to wake-wlan in gSPI */
6184 if (intstatus & I_CHIPACTIVE) {
6185 DHD_INFO(("Dongle reports CHIPACTIVE\n"));
6186 intstatus &= ~I_CHIPACTIVE;
6189 /* Ignore frame indications if rxskip is set */
6191 intstatus &= ~FRAME_AVAIL_MASK(bus);
6194 /* On frame indication, read available frames */
6195 if (PKT_AVAILABLE(bus, intstatus)) {
6196 framecnt = dhdsdio_readframes(bus, rxlimit, &rxdone);
6197 if (rxdone || bus->rxskip)
6198 intstatus &= ~FRAME_AVAIL_MASK(bus);
6199 rxlimit -= MIN(framecnt, rxlimit);
6202 /* Keep still-pending events for next scheduling */
6203 bus->intstatus = intstatus;
6206 /* Re-enable interrupts to detect new device events (mailbox, rx frame)
6207 * or clock availability. (Allows tx loop to check ipend if desired.)
6208 * (Unless register access seems hosed, as we may not be able to ACK...)
6210 if (bus->intr && bus->intdis && !bcmsdh_regfail(sdh)) {
6211 DHD_INTR(("%s: enable SDIO interrupts, rxdone %d framecnt %d\n",
6212 __FUNCTION__, rxdone, framecnt));
6213 bus->intdis = FALSE;
6214 #if defined(OOB_INTR_ONLY)
6215 bcmsdh_oob_intr_set(1);
6216 #endif /* defined(OOB_INTR_ONLY) */
6217 bcmsdh_intr_enable(sdh);
6220 #if defined(OOB_INTR_ONLY) && !defined(HW_OOB)
6221 /* In case of SW-OOB(using edge trigger),
6222 * Check interrupt status in the dongle again after enable irq on the host.
6223 * and rechedule dpc if interrupt is pended in the dongle.
6224 * There is a chance to miss OOB interrupt while irq is disabled on the host.
6225 * No need to do this with HW-OOB(level trigger)
6227 R_SDREG(newstatus, ®s->intstatus, retries);
6228 if (bcmsdh_regfail(bus->sdh))
6230 if (newstatus & bus->hostintmask) {
6234 #endif /* defined(OOB_INTR_ONLY) && !defined(HW_OOB) */
6236 #ifdef PROP_TXSTATUS
6237 dhd_wlfc_trigger_pktcommit(bus->dhd);
6240 if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL))
6241 dhdsdio_sendpendctl(bus);
6243 /* Send queued frames (limit 1 if rx may still be pending) */
6244 else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate &&
6245 pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit && DATAOK(bus)) {
6246 framecnt = rxdone ? txlimit : MIN(txlimit, dhd_txminmax);
6247 framecnt = dhdsdio_sendfromq(bus, framecnt);
6248 txlimit -= framecnt;
6250 /* Resched the DPC if ctrl cmd is pending on bus credit */
6251 if (bus->ctrl_frame_stat)
6254 /* Resched if events or tx frames are pending, else await next interrupt */
6255 /* On failed register access, all bets are off: no resched or interrupts */
6256 if ((bus->dhd->busstate == DHD_BUS_DOWN) || bcmsdh_regfail(sdh)) {
6257 if ((bus->sih && bus->sih->buscorerev >= 12) && !(dhdsdio_sleepcsr_get(bus) &
6258 SBSDIO_FUNC1_SLEEPCSR_KSO_MASK)) {
6259 /* Bus failed because of KSO */
6260 DHD_ERROR(("%s: Bus failed due to KSO\n", __FUNCTION__));
6263 DHD_ERROR(("%s: failed backplane access over SDIO, halting operation\n",
6265 bus->dhd->busstate = DHD_BUS_DOWN;
6268 } else if (bus->clkstate == CLK_PENDING) {
6269 /* Awaiting I_CHIPACTIVE; don't resched */
6270 } else if (bus->intstatus || bus->ipend ||
6271 (!bus->fcstate && pktq_mlen(&bus->txq, ~bus->flowcontrol) && DATAOK(bus)) ||
6272 PKT_AVAILABLE(bus, bus->intstatus)) { /* Read multiple frames */
6276 bus->dpc_sched = resched;
6278 /* If we're done for now, turn off clock request. */
6279 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && (bus->clkstate != CLK_PENDING)) {
6280 bus->activity = FALSE;
6281 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
6286 if (!resched && dhd_dpcpoll) {
6287 if (dhdsdio_readframes(bus, dhd_rxbound, &rxdone) != 0) {
6292 dhd_os_sdunlock(bus->dhd);
6297 dhd_bus_dpc(struct dhd_bus *bus)
6301 /* Call the DPC directly. */
6302 DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__));
6303 resched = dhdsdio_dpc(bus);
6309 dhdsdio_isr(void *arg)
6311 dhd_bus_t *bus = (dhd_bus_t*)arg;
6314 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
6317 DHD_ERROR(("%s : bus is null pointer , exit \n", __FUNCTION__));
6322 if (bus->dhd->busstate == DHD_BUS_DOWN) {
6323 DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__));
6327 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
6329 /* Count the interrupt call */
6333 /* Shouldn't get this interrupt if we're sleeping? */
6334 if (!SLPAUTO_ENAB(bus)) {
6335 if (bus->sleeping) {
6336 DHD_ERROR(("INTERRUPT WHILE SLEEPING??\n"));
6338 } else if (!KSO_ENAB(bus)) {
6339 DHD_ERROR(("ISR in devsleep 1\n"));
6343 /* Disable additional interrupts (is this needed now)? */
6345 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
6347 DHD_ERROR(("dhdsdio_isr() w/o interrupt configured!\n"));
6350 bcmsdh_intr_disable(sdh);
6353 #if defined(SDIO_ISR_THREAD)
6354 DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__));
6355 DHD_OS_WAKE_LOCK(bus->dhd);
6357 DHD_OS_WAKE_UNLOCK(bus->dhd);
6360 bus->dpc_sched = TRUE;
6361 dhd_sched_dpc(bus->dhd);
6369 dhdsdio_pktgen_init(dhd_bus_t *bus)
6371 /* Default to specified length, or full range */
6372 if (dhd_pktgen_len) {
6373 bus->pktgen_maxlen = MIN(dhd_pktgen_len, MAX_PKTGEN_LEN);
6374 bus->pktgen_minlen = bus->pktgen_maxlen;
6376 bus->pktgen_maxlen = MAX_PKTGEN_LEN;
6377 bus->pktgen_minlen = 0;
6379 bus->pktgen_len = (uint16)bus->pktgen_minlen;
6381 /* Default to per-watchdog burst with 10s print time */
6382 bus->pktgen_freq = 1;
6383 bus->pktgen_print = dhd_watchdog_ms ? (10000 / dhd_watchdog_ms) : 0;
6384 bus->pktgen_count = (dhd_pktgen * dhd_watchdog_ms + 999) / 1000;
6386 /* Default to echo mode */
6387 bus->pktgen_mode = DHD_PKTGEN_ECHO;
6388 bus->pktgen_stop = 1;
6392 dhdsdio_pktgen(dhd_bus_t *bus)
6398 osl_t *osh = bus->dhd->osh;
6404 /* Display current count if appropriate */
6405 if (bus->pktgen_print && (++bus->pktgen_ptick >= bus->pktgen_print)) {
6406 bus->pktgen_ptick = 0;
6407 printf("%s: send attempts %d, rcvd %d, errors %d\n",
6408 __FUNCTION__, bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail);
6410 /* Print throughput stats only for constant length packet runs */
6411 if (bus->pktgen_minlen == bus->pktgen_maxlen) {
6412 time_lapse = jiffies - bus->pktgen_prev_time;
6413 bus->pktgen_prev_time = jiffies;
6414 sent_pkts = bus->pktgen_sent - bus->pktgen_prev_sent;
6415 bus->pktgen_prev_sent = bus->pktgen_sent;
6416 rcvd_pkts = bus->pktgen_rcvd - bus->pktgen_prev_rcvd;
6417 bus->pktgen_prev_rcvd = bus->pktgen_rcvd;
6419 printf("%s: Tx Throughput %d kbps, Rx Throughput %d kbps\n",
6421 (sent_pkts * bus->pktgen_len / jiffies_to_msecs(time_lapse)) * 8,
6422 (rcvd_pkts * bus->pktgen_len / jiffies_to_msecs(time_lapse)) * 8);
6426 /* For recv mode, just make sure dongle has started sending */
6427 if (bus->pktgen_mode == DHD_PKTGEN_RECV) {
6428 if (bus->pktgen_rcv_state == PKTGEN_RCV_IDLE) {
6429 bus->pktgen_rcv_state = PKTGEN_RCV_ONGOING;
6430 dhdsdio_sdtest_set(bus, bus->pktgen_total);
6435 /* Otherwise, generate or request the specified number of packets */
6436 for (pktcount = 0; pktcount < bus->pktgen_count; pktcount++) {
6437 /* Stop if total has been reached */
6438 if (bus->pktgen_total && (bus->pktgen_sent >= bus->pktgen_total)) {
6439 bus->pktgen_count = 0;
6443 /* Allocate an appropriate-sized packet */
6444 if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) {
6445 len = SDPCM_TEST_PKT_CNT_FLD_LEN;
6447 len = bus->pktgen_len;
6449 if (!(pkt = PKTGET(osh, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN),
6451 DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__));
6454 PKTALIGN(osh, pkt, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN), DHD_SDALIGN);
6455 data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
6457 /* Write test header cmd and extra based on mode */
6458 switch (bus->pktgen_mode) {
6459 case DHD_PKTGEN_ECHO:
6460 *data++ = SDPCM_TEST_ECHOREQ;
6461 *data++ = (uint8)bus->pktgen_sent;
6464 case DHD_PKTGEN_SEND:
6465 *data++ = SDPCM_TEST_DISCARD;
6466 *data++ = (uint8)bus->pktgen_sent;
6469 case DHD_PKTGEN_RXBURST:
6470 *data++ = SDPCM_TEST_BURST;
6471 *data++ = (uint8)bus->pktgen_count; /* Just for backward compatability */
6475 DHD_ERROR(("Unrecognized pktgen mode %d\n", bus->pktgen_mode));
6476 PKTFREE(osh, pkt, TRUE);
6477 bus->pktgen_count = 0;
6481 /* Write test header length field */
6482 *data++ = (bus->pktgen_len >> 0);
6483 *data++ = (bus->pktgen_len >> 8);
6485 /* Write frame count in a 4 byte field adjucent to SDPCM test header for
6488 if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) {
6489 *data++ = (uint8)(bus->pktgen_count >> 0);
6490 *data++ = (uint8)(bus->pktgen_count >> 8);
6491 *data++ = (uint8)(bus->pktgen_count >> 16);
6492 *data++ = (uint8)(bus->pktgen_count >> 24);
6495 /* Then fill in the remainder -- N/A for burst */
6496 for (fillbyte = 0; fillbyte < len; fillbyte++)
6497 *data++ = SDPCM_TEST_FILL(fillbyte, (uint8)bus->pktgen_sent);
6501 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
6502 data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
6503 prhex("dhdsdio_pktgen: Tx Data", data, PKTLEN(osh, pkt) - SDPCM_HDRLEN);
6508 if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE, FALSE)) {
6510 if (bus->pktgen_stop && bus->pktgen_stop == bus->pktgen_fail)
6511 bus->pktgen_count = 0;
6515 /* Bump length if not fixed, wrap at max */
6516 if (++bus->pktgen_len > bus->pktgen_maxlen)
6517 bus->pktgen_len = (uint16)bus->pktgen_minlen;
6519 /* Special case for burst mode: just send one request! */
6520 if (bus->pktgen_mode == DHD_PKTGEN_RXBURST)
6526 dhdsdio_sdtest_set(dhd_bus_t *bus, uint count)
6530 osl_t *osh = bus->dhd->osh;
6532 /* Allocate the packet */
6533 if (!(pkt = PKTGET(osh, SDPCM_HDRLEN + SDPCM_TEST_HDRLEN +
6534 SDPCM_TEST_PKT_CNT_FLD_LEN + DHD_SDALIGN, TRUE))) {
6535 DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__));
6538 PKTALIGN(osh, pkt, (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN +
6539 SDPCM_TEST_PKT_CNT_FLD_LEN), DHD_SDALIGN);
6540 data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
6542 /* Fill in the test header */
6543 *data++ = SDPCM_TEST_SEND;
6544 *data++ = (count > 0)?TRUE:FALSE;
6545 *data++ = (bus->pktgen_maxlen >> 0);
6546 *data++ = (bus->pktgen_maxlen >> 8);
6547 *data++ = (uint8)(count >> 0);
6548 *data++ = (uint8)(count >> 8);
6549 *data++ = (uint8)(count >> 16);
6550 *data++ = (uint8)(count >> 24);
6553 if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE, FALSE))
6559 dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq)
6561 osl_t *osh = bus->dhd->osh;
6570 /* Check for min length */
6571 if ((pktlen = PKTLEN(osh, pkt)) < SDPCM_TEST_HDRLEN) {
6572 DHD_ERROR(("dhdsdio_restrcv: toss runt frame, pktlen %d\n", pktlen));
6573 PKTFREE(osh, pkt, FALSE);
6577 /* Extract header fields */
6578 data = PKTDATA(osh, pkt);
6581 len = *data++; len += *data++ << 8;
6582 DHD_TRACE(("%s:cmd:%d, xtra:%d,len:%d\n", __FUNCTION__, cmd, extra, len));
6583 /* Check length for relevant commands */
6584 if (cmd == SDPCM_TEST_DISCARD || cmd == SDPCM_TEST_ECHOREQ || cmd == SDPCM_TEST_ECHORSP) {
6585 if (pktlen != len + SDPCM_TEST_HDRLEN) {
6586 DHD_ERROR(("dhdsdio_testrcv: frame length mismatch, pktlen %d seq %d"
6587 " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len));
6588 PKTFREE(osh, pkt, FALSE);
6593 /* Process as per command */
6595 case SDPCM_TEST_ECHOREQ:
6596 /* Rx->Tx turnaround ok (even on NDIS w/current implementation) */
6597 *(uint8 *)(PKTDATA(osh, pkt)) = SDPCM_TEST_ECHORSP;
6598 if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE, FALSE) == 0) {
6602 PKTFREE(osh, pkt, FALSE);
6607 case SDPCM_TEST_ECHORSP:
6608 if (bus->ext_loop) {
6609 PKTFREE(osh, pkt, FALSE);
6614 for (offset = 0; offset < len; offset++, data++) {
6615 if (*data != SDPCM_TEST_FILL(offset, extra)) {
6616 DHD_ERROR(("dhdsdio_testrcv: echo data mismatch: "
6617 "offset %d (len %d) expect 0x%02x rcvd 0x%02x\n",
6618 offset, len, SDPCM_TEST_FILL(offset, extra), *data));
6622 PKTFREE(osh, pkt, FALSE);
6626 case SDPCM_TEST_DISCARD:
6630 uint8 testval = extra;
6631 for (i = 0; i < len; i++) {
6632 if (*prn != testval) {
6633 DHD_ERROR(("DIErr@Pkt#:%d,Ix:%d, expected:0x%x, got:0x%x\n",
6634 i, bus->pktgen_rcvd_rcvsession, testval, *prn));
6639 PKTFREE(osh, pkt, FALSE);
6643 case SDPCM_TEST_BURST:
6644 case SDPCM_TEST_SEND:
6646 DHD_INFO(("dhdsdio_testrcv: unsupported or unknown command, pktlen %d seq %d"
6647 " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len));
6648 PKTFREE(osh, pkt, FALSE);
6652 /* For recv mode, stop at limit (and tell dongle to stop sending) */
6653 if (bus->pktgen_mode == DHD_PKTGEN_RECV) {
6654 if (bus->pktgen_rcv_state != PKTGEN_RCV_IDLE) {
6655 bus->pktgen_rcvd_rcvsession++;
6657 if (bus->pktgen_total &&
6658 (bus->pktgen_rcvd_rcvsession >= bus->pktgen_total)) {
6659 bus->pktgen_count = 0;
6660 DHD_ERROR(("Pktgen:rcv test complete!\n"));
6661 bus->pktgen_rcv_state = PKTGEN_RCV_IDLE;
6662 dhdsdio_sdtest_set(bus, FALSE);
6663 bus->pktgen_rcvd_rcvsession = 0;
6671 dhd_disable_intr(dhd_pub_t *dhdp)
6675 bcmsdh_intr_disable(bus->sdh);
6679 dhd_bus_watchdog(dhd_pub_t *dhdp)
6683 DHD_TIMER(("%s: Enter\n", __FUNCTION__));
6687 if (bus->dhd->dongle_reset)
6690 /* Ignore the timer if simulating bus down */
6691 if (!SLPAUTO_ENAB(bus) && bus->sleeping)
6694 if (dhdp->busstate == DHD_BUS_DOWN)
6697 /* Poll period: check device if appropriate. */
6698 if (!SLPAUTO_ENAB(bus) && (bus->poll && (++bus->polltick >= bus->pollrate))) {
6699 uint32 intstatus = 0;
6701 /* Reset poll tick */
6704 /* Check device if no interrupts */
6705 if (!bus->intr || (bus->intrcount == bus->lastintrs)) {
6707 if (!bus->dpc_sched) {
6709 devpend = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0,
6710 SDIOD_CCCR_INTPEND, NULL);
6711 intstatus = devpend & (INTR_STATUS_FUNC1 | INTR_STATUS_FUNC2);
6714 /* If there is something, make like the ISR and schedule the DPC */
6719 bcmsdh_intr_disable(bus->sdh);
6721 bus->dpc_sched = TRUE;
6722 dhd_sched_dpc(bus->dhd);
6727 /* Update interrupt tracking */
6728 bus->lastintrs = bus->intrcount;
6732 /* Poll for console output periodically */
6733 if (dhdp->busstate == DHD_BUS_DATA && dhd_console_ms != 0) {
6734 bus->console.count += dhd_watchdog_ms;
6735 if (bus->console.count >= dhd_console_ms) {
6736 bus->console.count -= dhd_console_ms;
6737 /* Make sure backplane clock is on */
6738 if (SLPAUTO_ENAB(bus))
6739 dhdsdio_bussleep(bus, FALSE);
6741 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
6742 if (dhdsdio_readconsole(bus) < 0)
6743 dhd_console_ms = 0; /* On error, stop trying */
6746 #endif /* DHD_DEBUG */
6749 /* Generate packets if configured */
6750 if (bus->pktgen_count && (++bus->pktgen_tick >= bus->pktgen_freq)) {
6751 /* Make sure backplane clock is on */
6752 if (SLPAUTO_ENAB(bus))
6753 dhdsdio_bussleep(bus, FALSE);
6755 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
6756 bus->pktgen_tick = 0;
6757 dhdsdio_pktgen(bus);
6761 /* On idle timeout clear activity flag and/or turn off clock */
6762 #ifdef DHD_USE_IDLECOUNT
6764 bus->activity = FALSE;
6768 if ((bus->idletime > 0) && (bus->idlecount >= bus->idletime)) {
6769 DHD_TIMER(("%s: DHD Idle state!!\n", __FUNCTION__));
6770 if (SLPAUTO_ENAB(bus)) {
6771 if (dhdsdio_bussleep(bus, TRUE) != BCME_BUSY)
6772 dhd_os_wd_timer(bus->dhd, 0);
6774 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
6780 if ((bus->idletime > 0) && (bus->clkstate == CLK_AVAIL)) {
6781 if (++bus->idlecount > bus->idletime) {
6783 if (bus->activity) {
6784 bus->activity = FALSE;
6785 if (SLPAUTO_ENAB(bus)) {
6786 if (!bus->readframes)
6787 dhdsdio_bussleep(bus, TRUE);
6789 bus->reqbussleep = TRUE;
6792 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
6796 #endif /* DHD_USE_IDLECOUNT */
6803 dhd_bus_console_in(dhd_pub_t *dhdp, uchar *msg, uint msglen)
6805 dhd_bus_t *bus = dhdp->bus;
6810 /* Address could be zero if CONSOLE := 0 in dongle Makefile */
6811 if (bus->console_addr == 0)
6812 return BCME_UNSUPPORTED;
6814 /* Exclusive bus access */
6815 dhd_os_sdlock(bus->dhd);
6817 /* Don't allow input if dongle is in reset */
6818 if (bus->dhd->dongle_reset) {
6819 dhd_os_sdunlock(bus->dhd);
6820 return BCME_NOTREADY;
6823 /* Request clock to allow SDIO accesses */
6825 /* No pend allowed since txpkt is called later, ht clk has to be on */
6826 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
6828 /* Zero cbuf_index */
6829 addr = bus->console_addr + OFFSETOF(hndrte_cons_t, cbuf_idx);
6831 if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0)
6834 /* Write message into cbuf */
6835 addr = bus->console_addr + OFFSETOF(hndrte_cons_t, cbuf);
6836 if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)msg, msglen)) < 0)
6839 /* Write length into vcons_in */
6840 addr = bus->console_addr + OFFSETOF(hndrte_cons_t, vcons_in);
6841 val = htol32(msglen);
6842 if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0)
6845 /* Bump dongle by sending an empty packet on the event channel.
6846 * sdpcm_sendup (RX) checks for virtual console input.
6848 if ((pkt = PKTGET(bus->dhd->osh, 4 + SDPCM_RESERVE, TRUE)) != NULL)
6849 dhdsdio_txpkt(bus, pkt, SDPCM_EVENT_CHANNEL, TRUE, FALSE);
6852 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
6853 bus->activity = FALSE;
6854 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
6857 dhd_os_sdunlock(bus->dhd);
6861 #endif /* DHD_DEBUG */
6865 dhd_dump_cis(uint fn, uint8 *cis)
6867 uint byte, tag, tdata;
6868 DHD_INFO(("Function %d CIS:\n", fn));
6870 for (tdata = byte = 0; byte < SBSDIO_CIS_SIZE_LIMIT; byte++) {
6871 if ((byte % 16) == 0)
6873 DHD_INFO(("%02x ", cis[byte]));
6874 if ((byte % 16) == 15)
6882 else if ((byte + 1) < SBSDIO_CIS_SIZE_LIMIT)
6883 tdata = cis[byte + 1] + 1;
6888 if ((byte % 16) != 15)
6891 #endif /* DHD_DEBUG */
6894 dhdsdio_chipmatch(uint16 chipid)
6896 if (chipid == BCM4325_CHIP_ID)
6898 if (chipid == BCM4329_CHIP_ID)
6900 if (chipid == BCM4315_CHIP_ID)
6902 if (chipid == BCM4319_CHIP_ID)
6904 if (chipid == BCM4336_CHIP_ID)
6906 if (chipid == BCM4330_CHIP_ID)
6908 if (chipid == BCM43237_CHIP_ID)
6910 if (chipid == BCM43362_CHIP_ID)
6912 if (chipid == BCM4314_CHIP_ID)
6914 if (chipid == BCM43242_CHIP_ID)
6916 if (chipid == BCM43340_CHIP_ID)
6918 if (chipid == BCM43341_CHIP_ID)
6920 if (chipid == BCM43143_CHIP_ID)
6922 if (chipid == BCM43342_CHIP_ID)
6924 if (chipid == BCM4334_CHIP_ID)
6926 if (chipid == BCM43239_CHIP_ID)
6928 if (chipid == BCM4324_CHIP_ID)
6930 if (chipid == BCM4335_CHIP_ID)
6932 if (chipid == BCM4339_CHIP_ID)
6934 if (chipid == BCM4350_CHIP_ID)
6940 dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot,
6941 uint16 func, uint bustype, void *regsva, osl_t * osh, void *sdh)
6945 #ifdef GET_CUSTOM_MAC_ENABLE
6946 struct ether_addr ea_addr;
6947 #endif /* GET_CUSTOM_MAC_ENABLE */
6949 #if defined(MULTIPLE_SUPPLICANT)
6950 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
6951 if (mutex_is_locked(&_dhd_sdio_mutex_lock_) == 0) {
6952 DHD_ERROR(("%s : no mutex held. set lock\n", __FUNCTION__));
6955 DHD_ERROR(("%s : mutex is locked!. wait for unlocking\n", __FUNCTION__));
6957 mutex_lock(&_dhd_sdio_mutex_lock_);
6958 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
6961 /* Init global variables at run-time, not as part of the declaration.
6962 * This is required to support init/de-init of the driver. Initialization
6963 * of globals as part of the declaration results in non-deterministic
6964 * behavior since the value of the globals may be different on the
6965 * first time that the driver is initialized vs subsequent initializations.
6967 dhd_txbound = DHD_TXBOUND;
6968 dhd_rxbound = DHD_RXBOUND;
6969 dhd_alignctl = TRUE;
6971 dhd_readahead = TRUE;
6973 #if !defined(PLATFORM_MPS)
6977 #endif /* OEM_ANDROID */
6978 dhd_dongle_ramsize = 0;
6979 dhd_txminmax = DHD_TXMINMAX;
6983 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
6984 DHD_INFO(("%s: venid 0x%04x devid 0x%04x\n", __FUNCTION__, venid, devid));
6986 /* We make assumptions about address window mappings */
6987 ASSERT((uintptr)regsva == SI_ENUM_BASE);
6989 /* BCMSDH passes venid and devid based on CIS parsing -- but low-power start
6990 * means early parse could fail, so here we should get either an ID
6991 * we recognize OR (-1) indicating we must request power first.
6993 /* Check the Vendor ID */
6996 case VENDOR_BROADCOM:
6999 DHD_ERROR(("%s: unknown vendor: 0x%04x\n",
7000 __FUNCTION__, venid));
7004 /* Check the Device ID and make sure it's one that we support */
7006 case BCM4325_D11DUAL_ID: /* 4325 802.11a/g id */
7007 case BCM4325_D11G_ID: /* 4325 802.11g 2.4Ghz band id */
7008 case BCM4325_D11A_ID: /* 4325 802.11a 5Ghz band id */
7009 DHD_INFO(("%s: found 4325 Dongle\n", __FUNCTION__));
7011 case BCM4329_D11N_ID: /* 4329 802.11n dualband device */
7012 case BCM4329_D11N2G_ID: /* 4329 802.11n 2.4G device */
7013 case BCM4329_D11N5G_ID: /* 4329 802.11n 5G device */
7015 DHD_INFO(("%s: found 4329 Dongle\n", __FUNCTION__));
7017 case BCM4315_D11DUAL_ID: /* 4315 802.11a/g id */
7018 case BCM4315_D11G_ID: /* 4315 802.11g id */
7019 case BCM4315_D11A_ID: /* 4315 802.11a id */
7020 DHD_INFO(("%s: found 4315 Dongle\n", __FUNCTION__));
7022 case BCM4319_D11N_ID: /* 4319 802.11n id */
7023 case BCM4319_D11N2G_ID: /* 4319 802.11n2g id */
7024 case BCM4319_D11N5G_ID: /* 4319 802.11n5g id */
7025 DHD_INFO(("%s: found 4319 Dongle\n", __FUNCTION__));
7028 DHD_INFO(("%s: allow device id 0, will check chip internals\n",
7033 DHD_ERROR(("%s: skipping 0x%04x/0x%04x, not a dongle\n",
7034 __FUNCTION__, venid, devid));
7039 /* Ask the OS interface part for an OSL handle */
7040 if (!(osh = dhd_osl_attach(sdh, DHD_BUS))) {
7041 DHD_ERROR(("%s: osl_attach failed!\n", __FUNCTION__));
7046 /* Allocate private bus interface state */
7047 if (!(bus = MALLOC(osh, sizeof(dhd_bus_t)))) {
7048 DHD_ERROR(("%s: MALLOC of dhd_bus_t failed\n", __FUNCTION__));
7051 bzero(bus, sizeof(dhd_bus_t));
7053 bus->cl_devid = (uint16)devid;
7055 bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1;
7056 bus->usebufpool = FALSE; /* Use bufpool if allocated, else use locally malloced rxbuf */
7058 /* attach the common module */
7059 dhd_common_init(osh);
7061 /* attempt to attach to the dongle */
7062 if (!(dhdsdio_probe_attach(bus, osh, sdh, regsva, devid))) {
7063 DHD_ERROR(("%s: dhdsdio_probe_attach failed\n", __FUNCTION__));
7067 #ifdef PROP_TXSTATUS
7068 if (bus->sih->chip == BCM4330_CHIP_ID ||
7069 bus->sih->chip == BCM43362_CHIP_ID ) {
7070 // terence 20131215: disable_proptx should be set before dhd_attach
7071 printf("%s: disable prop_txstatus\n", __FUNCTION__);
7072 disable_proptx = TRUE;
7076 /* Attach to the dhd/OS/network interface */
7077 if (!(bus->dhd = dhd_attach(osh, bus, SDPCM_RESERVE))) {
7078 DHD_ERROR(("%s: dhd_attach failed\n", __FUNCTION__));
7082 /* Allocate buffers */
7083 if (!(dhdsdio_probe_malloc(bus, osh, sdh))) {
7084 DHD_ERROR(("%s: dhdsdio_probe_malloc failed\n", __FUNCTION__));
7088 if (!(dhdsdio_probe_init(bus, osh, sdh))) {
7089 DHD_ERROR(("%s: dhdsdio_probe_init failed\n", __FUNCTION__));
7094 /* Register interrupt callback, but mask it (not operational yet). */
7095 DHD_INTR(("%s: disable SDIO interrupts (not interested yet)\n", __FUNCTION__));
7096 bcmsdh_intr_disable(sdh);
7097 if ((ret = bcmsdh_intr_reg(sdh, dhdsdio_isr, bus)) != 0) {
7098 DHD_ERROR(("%s: FAILED: bcmsdh_intr_reg returned %d\n",
7099 __FUNCTION__, ret));
7102 DHD_INTR(("%s: registered SDIO interrupt function ok\n", __FUNCTION__));
7104 DHD_INFO(("%s: SDIO interrupt function is NOT registered due to polling mode\n",
7108 DHD_INFO(("%s: completed!!\n", __FUNCTION__));
7110 #ifdef GET_CUSTOM_MAC_ENABLE
7111 /* Read MAC address from external customer place */
7112 memset(&ea_addr, 0, sizeof(ea_addr));
7113 ret = dhd_custom_get_mac_address(ea_addr.octet);
7115 memcpy(bus->dhd->mac.octet, (void *)&ea_addr, ETHER_ADDR_LEN);
7117 #endif /* GET_CUSTOM_MAC_ENABLE */
7119 /* if firmware path present try to download and bring up bus */
7120 bus->dhd->hang_report = TRUE;
7121 if (dhd_download_fw_on_driverload) {
7122 if ((ret = dhd_bus_start(bus->dhd)) != 0) {
7123 DHD_ERROR(("%s: dhd_bus_start failed\n", __FUNCTION__));
7127 /* Ok, have the per-port tell the stack we're open for business */
7128 if (dhd_net_attach(bus->dhd, 0) != 0) {
7129 DHD_ERROR(("%s: Net attach failed!!\n", __FUNCTION__));
7133 #if defined(MULTIPLE_SUPPLICANT)
7134 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
7135 mutex_unlock(&_dhd_sdio_mutex_lock_);
7136 DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__));
7137 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
7143 dhdsdio_release(bus, osh);
7146 #if defined(MULTIPLE_SUPPLICANT)
7147 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
7148 mutex_unlock(&_dhd_sdio_mutex_lock_);
7149 DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__));
7150 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
7156 #ifdef REGON_BP_HANG_FIX
7157 static int dhd_sdio_backplane_reset(struct dhd_bus *bus)
7160 DHD_ERROR(("Resetting the backplane to avoid failure in firmware download..\n"));
7162 temp = bcmsdh_reg_read(bus->sdh, 0x180021e0, 4);
7163 DHD_INFO(("SDIO Clk Control Reg = %x\n", temp));
7165 /* Force HT req from PMU */
7166 bcmsdh_reg_write(bus->sdh, 0x18000644, 4, 0x6000005);
7168 /* Increase the clock stretch duration. */
7169 bcmsdh_reg_write(bus->sdh, 0x18000630, 4, 0xC8FFC8);
7171 /* Setting ALP clock request in SDIOD clock control status register */
7172 bcmsdh_reg_write(bus->sdh, 0x180021e0, 4, 0x41);
7174 /* Allowing clock from SR engine to SR memory */
7175 bcmsdh_reg_write(bus->sdh, 0x18004400, 4, 0xf92f1);
7176 /* Disabling SR Engine before SR binary download. */
7177 bcmsdh_reg_write(bus->sdh, 0x18000650, 4, 0x3);
7178 bcmsdh_reg_write(bus->sdh, 0x18000654, 4, 0x0);
7180 /* Enabling clock from backplane to SR memory */
7181 bcmsdh_reg_write(bus->sdh, 0x18004400, 4, 0xf9af1);
7183 /* Initializing SR memory address register in SOCRAM */
7184 bcmsdh_reg_write(bus->sdh, 0x18004408, 4, 0x0);
7186 /* Downloading the SR binary */
7187 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7188 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7189 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7190 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7191 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7192 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7193 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7194 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0xc0002000);
7195 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7196 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7197 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7198 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7199 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7200 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7201 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7202 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7203 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7204 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7205 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7206 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7207 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7208 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7209 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7210 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7211 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7212 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7213 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7214 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7215 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7216 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7217 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7218 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7219 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x80008000);
7220 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x1051f080);
7221 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x80008000);
7222 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x1050f080);
7223 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x80008000);
7224 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x1050f080);
7225 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x80008000);
7226 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x1050f080);
7227 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000004);
7228 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
7229 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000604);
7230 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
7231 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00001604);
7232 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
7233 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00001404);
7234 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a08c80);
7235 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010001);
7236 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x14a00000);
7237 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00011404);
7238 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
7239 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00002000);
7240 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x04a00000);
7241 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00002000);
7242 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0xf8000000);
7243 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00002000);
7244 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x04a00000);
7245 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00002000);
7246 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0xf8000000);
7247 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00011604);
7248 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
7249 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010604);
7250 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
7251 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010004);
7252 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
7253 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010000);
7254 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x14a00000);
7255 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000004);
7256 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
7257 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010001);
7258 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x14a00000);
7259 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010004);
7260 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
7261 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010000);
7262 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
7263 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010000);
7264 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x14a00000);
7265 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
7266 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
7267 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000008);
7268 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x04a00000);
7269 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000008);
7270 bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0xfc000000);
7271 /* SR Binary Download complete */
7273 /* Allowing clock from SR engine to SR memory */
7274 bcmsdh_reg_write(bus->sdh, 0x18004400, 4, 0xf92f1);
7276 /* Turning ON SR Engine to initiate backplane reset Repeated ?? Maharana */
7277 bcmsdh_reg_write(bus->sdh, 0x18000650, 4, 0x3);
7278 bcmsdh_reg_write(bus->sdh, 0x18000654, 4, 0x0);
7279 bcmsdh_reg_write(bus->sdh, 0x18000650, 4, 0x3);
7280 bcmsdh_reg_write(bus->sdh, 0x18000654, 4, 0x2);
7281 bcmsdh_reg_write(bus->sdh, 0x18000650, 4, 0x3);
7282 bcmsdh_reg_write(bus->sdh, 0x18000654, 4, 0x3);
7283 bcmsdh_reg_write(bus->sdh, 0x18000650, 4, 0x3);
7284 bcmsdh_reg_write(bus->sdh, 0x18000654, 4, 0x37);
7285 bcmsdh_reg_write(bus->sdh, 0x18000650, 4, 0x3);
7286 temp = bcmsdh_reg_read(bus->sdh, 0x18000654, 4);
7287 DHD_INFO(("0x18000654 = %x\n", temp));
7288 bcmsdh_reg_write(bus->sdh, 0x18000654, 4, 0x800037);
7290 /* Rolling back the original values for clock stretch and PMU timers */
7291 bcmsdh_reg_write(bus->sdh, 0x18000644, 4, 0x0);
7292 bcmsdh_reg_write(bus->sdh, 0x18000630, 4, 0xC800C8);
7293 /* Removing ALP clock request in SDIOD clock control status register */
7294 bcmsdh_reg_write(bus->sdh, 0x180021e0, 4, 0x40);
7299 static int dhdsdio_sdio_hang_war(struct dhd_bus *bus)
7301 uint32 temp = 0, temp2 = 0, counter = 0, BT_pwr_up = 0, BT_ready = 0;
7302 /* Removing reset of D11 Core */
7303 bcmsdh_reg_write(bus->sdh, 0x18101408, 4, 0x3);
7304 bcmsdh_reg_write(bus->sdh, 0x18101800, 4, 0x0);
7305 bcmsdh_reg_write(bus->sdh, 0x18101408, 4, 0x1);
7306 /* Reading CLB XTAL BT cntrl register */
7307 bcmsdh_reg_write(bus->sdh, 0x180013D8, 2, 0xD1);
7308 bcmsdh_reg_write(bus->sdh, 0x180013DA, 2, 0x12);
7309 bcmsdh_reg_write(bus->sdh, 0x180013D8, 2, 0x2D0);
7310 /* Read if BT is powered up */
7311 temp = bcmsdh_reg_read(bus->sdh, 0x180013DA, 2);
7312 /* Read BT_ready from WLAN wireless register */
7313 temp2 = bcmsdh_reg_read(bus->sdh, 0x1800002C, 4);
7315 Check if the BT is powered up and ready. The duration between BT being powered up
7316 and BT becoming ready is the problematic window for WLAN. If we move ahead at this
7317 time then we may encounter a corrupted backplane later. So we wait for BT to be ready
7318 and then proceed after checking the health of the backplane. If the backplane shows
7319 indications of failure then we have to do a full reset of the backplane using SR engine
7322 (temp & 0xF0) ? (BT_pwr_up = 1):(BT_pwr_up = 0);
7323 (temp2 & (1<<17)) ? (BT_ready = 1):(BT_ready = 0);
7324 DHD_ERROR(("WARNING: Checking if BT is ready BT_pwr_up = %x"
7325 "BT_ready = %x \n", BT_pwr_up, BT_ready));
7326 while (BT_pwr_up && !BT_ready)
7329 bcmsdh_reg_write(bus->sdh, 0x180013D8, 2, 0x2D0);
7330 temp = bcmsdh_reg_read(bus->sdh, 0x180013DA, 2);
7331 temp2 = bcmsdh_reg_read(bus->sdh, 0x1800002C, 4);
7332 (temp & 0xF0) ? (BT_pwr_up = 1):(BT_pwr_up = 0);
7333 (temp2 & (1<<17)) ? (BT_ready = 1):(BT_ready = 0);
7335 if (counter == 5000)
7337 DHD_ERROR(("WARNING: Going ahead after 5 secs with"
7338 "risk of failure because BT ready is not yet set\n"));
7342 DHD_ERROR(("\nWARNING: WL Proceeding BT_pwr_up = %x BT_ready = %x"
7343 "\n", BT_pwr_up, BT_ready));
7347 Get the information of who accessed the crucial backplane entities
7348 by reading read and write access registers
7350 DHD_TRACE(("%d: Read Value @ 0x18104808 = %x."
7351 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18104808, 4)));
7352 DHD_TRACE(("%d: Read Value @ 0x1810480C = %x."
7353 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810480C, 4)));
7354 DHD_TRACE(("%d: Read Value @ 0x18106808 = %x."
7355 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18106808, 4)));
7356 DHD_TRACE(("%d: Read Value @ 0x1810680C = %x."
7357 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810680C, 4)));
7358 DHD_TRACE(("%d: Read Value @ 0x18107808 = %x."
7359 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18107808, 4)));
7360 DHD_TRACE(("%d: Read Value @ 0x1810780C = %x."
7361 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810780C, 4)));
7362 DHD_TRACE(("%d: Read Value @ 0x18108808 = %x."
7363 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18108808, 4)));
7364 DHD_TRACE(("%d: Read Value @ 0x1810880C = %x."
7365 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810880C, 4)));
7366 DHD_TRACE(("%d: Read Value @ 0x18109808 = %x."
7367 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18109808, 4)));
7368 DHD_TRACE(("%d: Read Value @ 0x1810980C = %x."
7369 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810980C, 4)));
7370 DHD_TRACE(("%d: Read Value @ 0x1810C808 = %x."
7371 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810c808, 4)));
7372 DHD_TRACE(("%d: Read Value @ 0x1810C80C = %x."
7373 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810c80C, 4)));
7375 while ((bcmsdh_reg_read(bus->sdh, 0x18104808, 4) == 5) ||
7376 (bcmsdh_reg_read(bus->sdh, 0x1810480C, 4) == 5) ||
7377 (bcmsdh_reg_read(bus->sdh, 0x18106808, 4) == 5) ||
7378 (bcmsdh_reg_read(bus->sdh, 0x1810680C, 4) == 5) ||
7379 (bcmsdh_reg_read(bus->sdh, 0x1810780C, 4) == 5) ||
7380 (bcmsdh_reg_read(bus->sdh, 0x1810780C, 4) == 5) ||
7381 (bcmsdh_reg_read(bus->sdh, 0x1810880C, 4) == 5) ||
7382 (bcmsdh_reg_read(bus->sdh, 0x1810880C, 4) == 5) ||
7383 (bcmsdh_reg_read(bus->sdh, 0x1810980C, 4) == 5) ||
7384 (bcmsdh_reg_read(bus->sdh, 0x1810980C, 4) == 5) ||
7385 (bcmsdh_reg_read(bus->sdh, 0x1810C80C, 4) == 5) ||
7386 (bcmsdh_reg_read(bus->sdh, 0x1810C80C, 4) == 5))
7390 DHD_ERROR(("Unable to recover the backkplane corruption"
7391 "..Tried %d times.. Exiting\n", counter));
7395 dhd_sdio_backplane_reset(bus);
7397 Get the information of who accessed the crucial backplane
7398 entities by reading read and write access registers
7400 DHD_ERROR(("%d: Read Value @ 0x18104808 = %x."
7401 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18104808, 4)));
7402 DHD_ERROR(("%d: Read Value @ 0x1810480C = %x."
7403 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810480C, 4)));
7404 DHD_ERROR(("%d: Read Value @ 0x18106808 = %x."
7405 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18106808, 4)));
7406 DHD_ERROR(("%d: Read Value @ 0x1810680C = %x."
7407 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810680C, 4)));
7408 DHD_ERROR(("%d: Read Value @ 0x18107808 = %x."
7409 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18107808, 4)));
7410 DHD_ERROR(("%d: Read Value @ 0x1810780C = %x."
7411 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810780C, 4)));
7412 DHD_ERROR(("%d: Read Value @ 0x18108808 = %x."
7413 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18108808, 4)));
7414 DHD_ERROR(("%d: Read Value @ 0x1810880C = %x."
7415 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810880C, 4)));
7416 DHD_ERROR(("%d: Read Value @ 0x18109808 = %x."
7417 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18109808, 4)));
7418 DHD_ERROR(("%d: Read Value @ 0x1810980C = %x."
7419 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810980C, 4)));
7420 DHD_ERROR(("%d: Read Value @ 0x1810C808 = %x."
7421 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810c808, 4)));
7422 DHD_ERROR(("%d: Read Value @ 0x1810C80C = %x."
7423 "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810c80C, 4)));
7425 /* Set the WL ready to indicate BT that we are done with backplane reset */
7426 DHD_ERROR(("Setting up AXI_OK\n"));
7427 bcmsdh_reg_write(bus->sdh, 0x18000658, 4, 0x3);
7428 temp = bcmsdh_reg_read(bus->sdh, 0x1800065c, 4);
7430 bcmsdh_reg_write(bus->sdh, 0x1800065c, 4, temp);
7433 #endif /* REGON_BP_HANG_FIX */
7436 dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva,
7442 bus->alp_only = TRUE;
7445 /* Return the window to backplane enumeration space for core access */
7446 if (dhdsdio_set_siaddr_window(bus, SI_ENUM_BASE)) {
7447 DHD_ERROR(("%s: FAILED to return to SI_ENUM_BASE\n", __FUNCTION__));
7451 /* Force PLL off until si_attach() programs PLL control regs */
7455 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, DHD_INIT_CLKCTL1, &err);
7457 clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
7459 if (err || ((clkctl & ~SBSDIO_AVBITS) != DHD_INIT_CLKCTL1)) {
7460 DHD_ERROR(("dhdsdio_probe: ChipClkCSR access: err %d wrote 0x%02x read 0x%02x\n",
7461 err, DHD_INIT_CLKCTL1, clkctl));
7466 if (DHD_INFO_ON()) {
7468 uint8 *cis[SDIOD_MAX_IOFUNCS];
7471 numfn = bcmsdh_query_iofnum(sdh);
7472 ASSERT(numfn <= SDIOD_MAX_IOFUNCS);
7474 /* Make sure ALP is available before trying to read CIS */
7475 SPINWAIT(((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
7476 SBSDIO_FUNC1_CHIPCLKCSR, NULL)),
7477 !SBSDIO_ALPAV(clkctl)), PMU_MAX_TRANSITION_DLY);
7479 /* Now request ALP be put on the bus */
7480 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
7481 DHD_INIT_CLKCTL2, &err);
7484 for (fn = 0; fn <= numfn; fn++) {
7485 if (!(cis[fn] = MALLOC(osh, SBSDIO_CIS_SIZE_LIMIT))) {
7486 DHD_INFO(("dhdsdio_probe: fn %d cis malloc failed\n", fn));
7489 bzero(cis[fn], SBSDIO_CIS_SIZE_LIMIT);
7491 if ((err = bcmsdh_cis_read(sdh, fn, cis[fn], SBSDIO_CIS_SIZE_LIMIT))) {
7492 DHD_INFO(("dhdsdio_probe: fn %d cis read err %d\n", fn, err));
7493 MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT);
7496 dhd_dump_cis(fn, cis[fn]);
7501 MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT);
7505 DHD_ERROR(("dhdsdio_probe: failure reading or parsing CIS\n"));
7509 #endif /* DHD_DEBUG */
7511 /* si_attach() will provide an SI handle and scan the backplane */
7512 if (!(bus->sih = si_attach((uint)devid, osh, regsva, DHD_BUS, sdh,
7513 &bus->vars, &bus->varsz))) {
7514 DHD_ERROR(("%s: si_attach failed!\n", __FUNCTION__));
7520 DHD_ERROR(("F1 signature OK, socitype:0x%x chip:0x%4x rev:0x%x pkg:0x%x\n",
7521 bus->sih->socitype, bus->sih->chip, bus->sih->chiprev,
7522 bus->sih->chippkg));
7523 #endif /* DHD_DEBUG */
7525 #ifdef REGON_BP_HANG_FIX
7526 /* WAR - for 43241 B0-B1-B2. B3 onwards do not need this */
7527 if (((uint16)bus->sih->chip == BCM4324_CHIP_ID) && (bus->sih->chiprev < 3))
7528 dhdsdio_sdio_hang_war(bus);
7529 #endif /* REGON_BP_HANG_FIX */
7531 bcmsdh_chipinfo(sdh, bus->sih->chip, bus->sih->chiprev);
7533 if (!dhdsdio_chipmatch((uint16)bus->sih->chip)) {
7534 DHD_ERROR(("%s: unsupported chip: 0x%04x\n",
7535 __FUNCTION__, bus->sih->chip));
7539 if (bus->sih->buscorerev >= 12)
7540 dhdsdio_clk_kso_init(bus);
7544 if (CST4330_CHIPMODE_SDIOD(bus->sih->chipst)) {
7547 si_sdiod_drive_strength_init(bus->sih, osh, dhd_sdiod_drive_strength);
7550 /* Get info on the ARM and SOCRAM cores... */
7551 if (!DHD_NOPMU(bus)) {
7552 if ((si_setcore(bus->sih, ARM7S_CORE_ID, 0)) ||
7553 (si_setcore(bus->sih, ARMCM3_CORE_ID, 0)) ||
7554 (si_setcore(bus->sih, ARMCR4_CORE_ID, 0))) {
7555 bus->armrev = si_corerev(bus->sih);
7557 DHD_ERROR(("%s: failed to find ARM core!\n", __FUNCTION__));
7561 if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
7562 if (!(bus->orig_ramsize = si_socram_size(bus->sih))) {
7563 DHD_ERROR(("%s: failed to find SOCRAM memory!\n", __FUNCTION__));
7567 /* cr4 has a different way to find the RAM size from TCM's */
7568 if (!(bus->orig_ramsize = si_tcm_size(bus->sih))) {
7569 DHD_ERROR(("%s: failed to find CR4-TCM memory!\n", __FUNCTION__));
7572 /* also populate base address */
7573 switch ((uint16)bus->sih->chip) {
7574 case BCM4335_CHIP_ID:
7575 case BCM4339_CHIP_ID:
7576 bus->dongle_ram_base = CR4_4335_RAM_BASE;
7578 case BCM4350_CHIP_ID:
7579 bus->dongle_ram_base = CR4_4350_RAM_BASE;
7581 case BCM4360_CHIP_ID:
7582 bus->dongle_ram_base = CR4_4360_RAM_BASE;
7585 bus->dongle_ram_base = 0;
7586 DHD_ERROR(("%s: WARNING: Using default ram base at 0x%x\n",
7587 __FUNCTION__, bus->dongle_ram_base));
7590 bus->ramsize = bus->orig_ramsize;
7591 if (dhd_dongle_ramsize)
7592 dhd_dongle_setramsize(bus, dhd_dongle_ramsize);
7594 DHD_ERROR(("DHD: dongle ram size is set to %d(orig %d) at 0x%x\n",
7595 bus->ramsize, bus->orig_ramsize, bus->dongle_ram_base));
7597 bus->srmemsize = si_socram_srmem_size(bus->sih);
7600 /* ...but normally deal with the SDPCMDEV core */
7601 if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0)) &&
7602 !(bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0))) {
7603 DHD_ERROR(("%s: failed to find SDIODEV core!\n", __FUNCTION__));
7606 bus->sdpcmrev = si_corerev(bus->sih);
7608 /* Set core control so an SDIO reset does a backplane reset */
7609 OR_REG(osh, &bus->regs->corecontrol, CC_BPRESEN);
7610 bus->rxint_mode = SDIO_DEVICE_HMB_RXINT;
7612 if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev >= 4) &&
7613 (bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_1))
7617 val = R_REG(osh, &bus->regs->corecontrol);
7618 val &= ~CC_XMTDATAAVAIL_MODE;
7619 val |= CC_XMTDATAAVAIL_CTRL;
7620 W_REG(osh, &bus->regs->corecontrol, val);
7624 pktq_init(&bus->txq, (PRIOMASK + 1), QLEN);
7626 /* Locate an appropriately-aligned portion of hdrbuf */
7627 bus->rxhdr = (uint8 *)ROUNDUP((uintptr)&bus->hdrbuf[0], DHD_SDALIGN);
7629 /* Set the poll and/or interrupt flags */
7630 bus->intr = (bool)dhd_intr;
7631 if ((bus->poll = (bool)dhd_poll))
7634 #ifdef BCMSDIOH_TXGLOM
7635 /* Setting default Glom mode */
7636 bus->glom_mode = bcmsdh_set_mode(bus->sdh, SDPCM_DEFGLOM_MODE);
7637 /* Setting default Glom size */
7638 bus->glomsize = SDPCM_DEFGLOM_SIZE;
7644 if (bus->sih != NULL) {
7645 si_detach(bus->sih);
7652 dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh)
7654 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7656 if (bus->dhd->maxctl) {
7657 bus->rxblen = ROUNDUP((bus->dhd->maxctl + SDPCM_HDRLEN), ALIGNMENT) + DHD_SDALIGN;
7658 if (!(bus->rxbuf = DHD_OS_PREALLOC(osh, DHD_PREALLOC_RXBUF, bus->rxblen))) {
7659 DHD_ERROR(("%s: MALLOC of %d-byte rxbuf failed\n",
7660 __FUNCTION__, bus->rxblen));
7664 /* Allocate buffer to receive glomed packet */
7665 if (!(bus->databuf = DHD_OS_PREALLOC(osh, DHD_PREALLOC_DATABUF, MAX_DATA_BUF))) {
7666 DHD_ERROR(("%s: MALLOC of %d-byte databuf failed\n",
7667 __FUNCTION__, MAX_DATA_BUF));
7668 /* release rxbuf which was already located as above */
7670 DHD_OS_PREFREE(osh, bus->rxbuf, bus->rxblen);
7674 /* Align the buffer */
7675 if ((uintptr)bus->databuf % DHD_SDALIGN)
7676 bus->dataptr = bus->databuf + (DHD_SDALIGN - ((uintptr)bus->databuf % DHD_SDALIGN));
7678 bus->dataptr = bus->databuf;
7687 dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh)
7691 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7694 dhdsdio_pktgen_init(bus);
7697 /* Disable F2 to clear any intermediate frame state on the dongle */
7698 bcmsdh_cfg_write(sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL);
7700 bus->dhd->busstate = DHD_BUS_DOWN;
7701 bus->sleeping = FALSE;
7702 bus->rxflow = FALSE;
7703 bus->prev_rxlim_hit = 0;
7705 /* Done with backplane-dependent accesses, can drop clock... */
7706 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
7708 /* ...and initialize clock/power states */
7709 bus->clkstate = CLK_SDONLY;
7710 bus->idletime = (int32)dhd_idletime;
7711 bus->idleclock = DHD_IDLE_ACTIVE;
7713 /* Query the SD clock speed */
7714 if (bcmsdh_iovar_op(sdh, "sd_divisor", NULL, 0,
7715 &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) {
7716 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_divisor"));
7717 bus->sd_divisor = -1;
7719 DHD_INFO(("%s: Initial value for %s is %d\n",
7720 __FUNCTION__, "sd_divisor", bus->sd_divisor));
7723 /* Query the SD bus mode */
7724 if (bcmsdh_iovar_op(sdh, "sd_mode", NULL, 0,
7725 &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) {
7726 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_mode"));
7729 DHD_INFO(("%s: Initial value for %s is %d\n",
7730 __FUNCTION__, "sd_mode", bus->sd_mode));
7733 /* Query the F2 block size, set roundup accordingly */
7735 if (bcmsdh_iovar_op(sdh, "sd_blocksize", &fnum, sizeof(int32),
7736 &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) {
7738 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize"));
7740 DHD_INFO(("%s: Initial value for %s is %d\n",
7741 __FUNCTION__, "sd_blocksize", bus->blocksize));
7743 if ((bus->sih->chip == BCM4335_CHIP_ID) ||
7744 (bus->sih->chip == BCM4339_CHIP_ID))
7745 dhd_overflow_war(bus);
7747 bus->roundup = MIN(max_roundup, bus->blocksize);
7749 /* Query if bus module supports packet chaining, default to use if supported */
7750 if (bcmsdh_iovar_op(sdh, "sd_rxchain", NULL, 0,
7751 &bus->sd_rxchain, sizeof(int32), FALSE) != BCME_OK) {
7752 bus->sd_rxchain = FALSE;
7754 DHD_INFO(("%s: bus module (through bcmsdh API) %s chaining\n",
7755 __FUNCTION__, (bus->sd_rxchain ? "supports" : "does not support")));
7757 bus->use_rxchain = (bool)bus->sd_rxchain;
7763 dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh,
7764 char *pfw_path, char *pnv_path, char *pconf_path)
7767 bus->fw_path = pfw_path;
7768 bus->nv_path = pnv_path;
7769 bus->dhd->conf_path = pconf_path;
7771 ret = dhdsdio_download_firmware(bus, osh, bus->sdh);
7778 dhdsdio_download_firmware(struct dhd_bus *bus, osl_t *osh, void *sdh)
7782 DHD_OS_WAKE_LOCK(bus->dhd);
7784 /* Download the firmware */
7785 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
7787 /* External conf takes precedence if specified */
7788 dhd_conf_preinit(bus->dhd);
7789 dhd_conf_download_config(bus->dhd);
7790 dhd_conf_set_fw_path(bus->dhd, bus->fw_path);
7791 dhd_conf_set_nv_path(bus->dhd, bus->nv_path);
7793 printk("Final fw_path=%s\n", bus->fw_path);
7794 printk("Final nv_path=%s\n", bus->nv_path);
7795 printk("Final conf_path=%s\n", bus->dhd->conf_path);
7797 ret = _dhdsdio_download_firmware(bus) == 0;
7799 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
7801 DHD_OS_WAKE_UNLOCK(bus->dhd);
7805 /* Detach and free everything */
7807 dhdsdio_release(dhd_bus_t *bus, osl_t *osh)
7809 bool dongle_isolation = FALSE;
7810 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7816 dongle_isolation = bus->dhd->dongle_isolation;
7817 dhd_detach(bus->dhd);
7820 /* De-register interrupt handler */
7821 bcmsdh_intr_disable(bus->sdh);
7822 bcmsdh_intr_dereg(bus->sdh);
7825 dhdsdio_release_dongle(bus, osh, dongle_isolation, TRUE);
7830 dhdsdio_release_malloc(bus, osh);
7833 if (bus->console.buf != NULL)
7834 MFREE(osh, bus->console.buf, bus->console.bufsize);
7837 MFREE(osh, bus, sizeof(dhd_bus_t));
7841 dhd_osl_detach(osh);
7843 DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
7847 dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh)
7849 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7851 if (bus->dhd && bus->dhd->dongle_reset)
7855 #ifndef CONFIG_DHD_USE_STATIC_BUF
7856 MFREE(osh, bus->rxbuf, bus->rxblen);
7858 bus->rxctl = bus->rxbuf = NULL;
7863 #ifndef CONFIG_DHD_USE_STATIC_BUF
7864 MFREE(osh, bus->databuf, MAX_DATA_BUF);
7866 bus->databuf = NULL;
7869 if (bus->vars && bus->varsz) {
7870 MFREE(osh, bus->vars, bus->varsz);
7878 dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation, bool reset_flag)
7880 DHD_TRACE(("%s: Enter bus->dhd %p bus->dhd->dongle_reset %d \n", __FUNCTION__,
7881 bus->dhd, bus->dhd->dongle_reset));
7883 if ((bus->dhd && bus->dhd->dongle_reset) && reset_flag)
7887 #if !defined(BCMLXSDMMC)
7889 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
7891 if (KSO_ENAB(bus) && (dongle_isolation == FALSE))
7892 si_watchdog(bus->sih, 4);
7893 #endif /* !defined(BCMLXSDMMC) */
7895 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
7897 si_detach(bus->sih);
7899 if (bus->vars && bus->varsz)
7900 MFREE(osh, bus->vars, bus->varsz);
7904 DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
7908 dhdsdio_disconnect(void *ptr)
7910 dhd_bus_t *bus = (dhd_bus_t *)ptr;
7912 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7914 #if defined(MULTIPLE_SUPPLICANT)
7915 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
7916 if (mutex_is_locked(&_dhd_sdio_mutex_lock_) == 0) {
7917 DHD_ERROR(("%s : no mutex held. set lock\n", __FUNCTION__));
7920 DHD_ERROR(("%s : mutex is locked!. wait for unlocking\n", __FUNCTION__));
7922 mutex_lock(&_dhd_sdio_mutex_lock_);
7923 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
7929 dhdsdio_release(bus, bus->dhd->osh);
7932 #if defined(MULTIPLE_SUPPLICANT)
7933 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
7934 mutex_unlock(&_dhd_sdio_mutex_lock_);
7935 DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__));
7936 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
7939 DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
7943 /* Register/Unregister functions are called by the main DHD entry
7944 * point (e.g. module insertion) to link with the bus driver, in
7945 * order to look for or await the device.
7948 static bcmsdh_driver_t dhd_sdio = {
7954 dhd_bus_register(void)
7956 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7958 return bcmsdh_register(&dhd_sdio);
7962 dhd_bus_unregister(void)
7964 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7966 bcmsdh_unregister();
7969 #if defined(BCMLXSDMMC)
7970 /* Register a dummy SDIO client driver in order to be notified of new SDIO device */
7971 int dhd_bus_reg_sdio_notify(void* semaphore)
7973 return bcmsdh_reg_sdio_notify(semaphore);
7976 void dhd_bus_unreg_sdio_notify(void)
7978 bcmsdh_unreg_sdio_notify();
7980 #endif /* defined(BCMLXSDMMC) */
7982 #ifdef BCMEMBEDIMAGE
7984 dhdsdio_download_code_array(struct dhd_bus *bus)
7988 unsigned char *ularray = NULL;
7990 DHD_INFO(("%s: download embedded firmware...\n", __FUNCTION__));
7992 /* Download image */
7993 while ((offset + MEMBLOCK) < sizeof(dlarray)) {
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*)dlarray));
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,
8006 (uint8 *) (dlarray + offset), MEMBLOCK);
8008 DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
8009 __FUNCTION__, bcmerror, MEMBLOCK, offset));
8016 if (offset < sizeof(dlarray)) {
8017 bcmerror = dhdsdio_membytes(bus, TRUE, offset,
8018 (uint8 *) (dlarray + offset), sizeof(dlarray) - offset);
8020 DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
8021 __FUNCTION__, bcmerror, sizeof(dlarray) - offset, offset));
8027 /* Upload and compare the downloaded code */
8029 ularray = MALLOC(bus->dhd->osh, bus->ramsize);
8030 /* Upload image to verify downloaded contents. */
8032 memset(ularray, 0xaa, bus->ramsize);
8033 while ((offset + MEMBLOCK) < sizeof(dlarray)) {
8034 bcmerror = dhdsdio_membytes(bus, FALSE, offset, ularray + offset, MEMBLOCK);
8036 DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n",
8037 __FUNCTION__, bcmerror, MEMBLOCK, offset));
8044 if (offset < sizeof(dlarray)) {
8045 bcmerror = dhdsdio_membytes(bus, FALSE, offset,
8046 ularray + offset, sizeof(dlarray) - offset);
8048 DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n",
8049 __FUNCTION__, bcmerror, sizeof(dlarray) - offset, offset));
8054 if (memcmp(dlarray, ularray, sizeof(dlarray))) {
8055 DHD_ERROR(("%s: Downloaded image is corrupted (%s, %s, %s).\n",
8056 __FUNCTION__, dlimagename, dlimagever, dlimagedate));
8059 DHD_ERROR(("%s: Download, Upload and compare succeeded (%s, %s, %s).\n",
8060 __FUNCTION__, dlimagename, dlimagever, dlimagedate));
8063 #endif /* DHD_DEBUG */
8067 MFREE(bus->dhd->osh, ularray, bus->ramsize);
8070 #endif /* BCMEMBEDIMAGE */
8073 dhdsdio_download_code_file(struct dhd_bus *bus, char *pfw_path)
8079 uint8 *memblock = NULL, *memptr;
8080 uint8 *memptr_tmp = NULL; // terence: check downloaded firmware is correct
8082 DHD_INFO(("%s: download firmware %s\n", __FUNCTION__, pfw_path));
8084 image = dhd_os_open_image(pfw_path);
8085 if (image == NULL) {
8086 printk("%s: Open firmware file failed %s\n", __FUNCTION__, pfw_path);
8090 memptr = memblock = MALLOC(bus->dhd->osh, MEMBLOCK + DHD_SDALIGN);
8091 if (memblock == NULL) {
8092 DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, MEMBLOCK));
8095 if (dhd_msg_level & DHD_TRACE_VAL) {
8096 memptr_tmp = MALLOC(bus->dhd->osh, MEMBLOCK + DHD_SDALIGN);
8097 if (memptr_tmp == NULL) {
8098 DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, MEMBLOCK));
8102 if ((uint32)(uintptr)memblock % DHD_SDALIGN)
8103 memptr += (DHD_SDALIGN - ((uint32)(uintptr)memblock % DHD_SDALIGN));
8105 /* Download image */
8106 while ((len = dhd_os_get_image_block((char*)memptr, MEMBLOCK, image))) {
8108 DHD_ERROR(("%s: dhd_os_get_image_block failed (%d)\n", __FUNCTION__, len));
8109 bcmerror = BCME_ERROR;
8113 if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
8114 /* if address is 0, store the reset instruction to be written in 0 */
8117 bus->resetinstr = *(((uint32*)memptr));
8118 /* Add start of RAM address to the address given by user */
8119 offset += bus->dongle_ram_base;
8123 bcmerror = dhdsdio_membytes(bus, TRUE, offset, memptr, len);
8125 DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
8126 __FUNCTION__, bcmerror, MEMBLOCK, offset));
8130 if (dhd_msg_level & DHD_TRACE_VAL) {
8131 bcmerror = dhdsdio_membytes(bus, FALSE, offset, memptr_tmp, len);
8133 DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n",
8134 __FUNCTION__, bcmerror, MEMBLOCK, offset));
8137 if (memcmp(memptr_tmp, memptr, len)) {
8138 DHD_ERROR(("%s: Downloaded image is corrupted.\n", __FUNCTION__));
8141 DHD_INFO(("%s: Download, Upload and compare succeeded.\n", __FUNCTION__));
8148 MFREE(bus->dhd->osh, memblock, MEMBLOCK + DHD_SDALIGN);
8149 if (dhd_msg_level & DHD_TRACE_VAL) {
8151 MFREE(bus->dhd->osh, memptr_tmp, MEMBLOCK + DHD_SDALIGN);
8155 dhd_os_close_image(image);
8161 EXAMPLE: nvram_array
8164 Use carriage return at the end of each assignment, and an empty string with
8165 carriage return at the end of array.
8168 unsigned char nvram_array[] = {"name1=value1\n", "name2=value2\n", "\n"};
8169 Hex values start with 0x, and mac addr format: xx:xx:xx:xx:xx:xx.
8171 Search "EXAMPLE: nvram_array" to see how the array is activated.
8175 dhd_bus_set_nvram_params(struct dhd_bus * bus, const char *nvram_params)
8177 bus->nvram_params = nvram_params;
8181 dhdsdio_download_nvram(struct dhd_bus *bus)
8185 void * image = NULL;
8186 char * memblock = NULL;
8189 bool nvram_file_exists;
8191 pnv_path = bus->nv_path;
8193 nvram_file_exists = ((pnv_path != NULL) && (pnv_path[0] != '\0'));
8194 if (!nvram_file_exists && (bus->nvram_params == NULL))
8197 if (nvram_file_exists) {
8198 image = dhd_os_open_image(pnv_path);
8199 if (image == NULL) {
8200 printk("%s: Open nvram file failed %s\n", __FUNCTION__, pnv_path);
8205 memblock = MALLOC(bus->dhd->osh, MAX_NVRAMBUF_SIZE);
8206 if (memblock == NULL) {
8207 DHD_ERROR(("%s: Failed to allocate memory %d bytes\n",
8208 __FUNCTION__, MAX_NVRAMBUF_SIZE));
8212 /* Download variables */
8213 if (nvram_file_exists) {
8214 len = dhd_os_get_image_block(memblock, MAX_NVRAMBUF_SIZE, image);
8217 len = strlen(bus->nvram_params);
8218 ASSERT(len <= MAX_NVRAMBUF_SIZE);
8219 memcpy(memblock, bus->nvram_params, len);
8221 if (len > 0 && len < MAX_NVRAMBUF_SIZE) {
8222 bufp = (char *)memblock;
8224 len = process_nvram_vars(bufp, len);
8226 len += 4 - (len % 4);
8231 bcmerror = dhdsdio_downloadvars(bus, memblock, len + 1);
8233 DHD_ERROR(("%s: error downloading vars: %d\n",
8234 __FUNCTION__, bcmerror));
8238 DHD_ERROR(("%s: error reading nvram file: %d\n",
8239 __FUNCTION__, len));
8240 bcmerror = BCME_SDIO_ERROR;
8245 MFREE(bus->dhd->osh, memblock, MAX_NVRAMBUF_SIZE);
8248 dhd_os_close_image(image);
8254 _dhdsdio_download_firmware(struct dhd_bus *bus)
8258 bool embed = FALSE; /* download embedded firmware */
8259 bool dlok = FALSE; /* download firmware succeeded */
8261 /* Out immediately if no image to download */
8262 if ((bus->fw_path == NULL) || (bus->fw_path[0] == '\0')) {
8263 #ifdef BCMEMBEDIMAGE
8270 /* Keep arm in reset */
8271 if (dhdsdio_download_state(bus, TRUE)) {
8272 DHD_ERROR(("%s: error placing ARM core in reset\n", __FUNCTION__));
8276 /* External image takes precedence if specified */
8277 if ((bus->fw_path != NULL) && (bus->fw_path[0] != '\0')) {
8278 if (dhdsdio_download_code_file(bus, bus->fw_path)) {
8279 DHD_ERROR(("%s: dongle image file download failed\n", __FUNCTION__));
8280 #ifdef BCMEMBEDIMAGE
8292 #ifdef BCMEMBEDIMAGE
8294 if (dhdsdio_download_code_array(bus)) {
8295 DHD_ERROR(("%s: dongle image array download failed\n", __FUNCTION__));
8303 BCM_REFERENCE(embed);
8306 DHD_ERROR(("%s: dongle image download failed\n", __FUNCTION__));
8310 /* EXAMPLE: nvram_array */
8311 /* If a valid nvram_arry is specified as above, it can be passed down to dongle */
8312 /* dhd_bus_set_nvram_params(bus, (char *)&nvram_array); */
8314 /* External nvram takes precedence if specified */
8315 if (dhdsdio_download_nvram(bus)) {
8316 DHD_ERROR(("%s: dongle nvram file download failed\n", __FUNCTION__));
8320 /* Take arm out of reset */
8321 if (dhdsdio_download_state(bus, FALSE)) {
8322 DHD_ERROR(("%s: error getting out of ARM core reset\n", __FUNCTION__));
8333 dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes,
8334 void *pkt, bcmsdh_cmplt_fn_t complete, void *handle)
8338 if (!KSO_ENAB(bus)) {
8339 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
8340 return BCME_NODEVICE;
8343 status = bcmsdh_recv_buf(bus->sdh, addr, fn, flags, buf, nbytes, pkt, complete, handle);
8349 dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes,
8350 void *pkt, bcmsdh_cmplt_fn_t complete, void *handle)
8352 if (!KSO_ENAB(bus)) {
8353 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
8354 return BCME_NODEVICE;
8357 return (bcmsdh_send_buf(bus->sdh, addr, fn, flags, buf, nbytes, pkt, complete, handle));
8360 #ifdef BCMSDIOH_TXGLOM
8362 dhd_bcmsdh_glom_post(dhd_bus_t *bus, uint8 *frame, void *pkt, uint len)
8364 bcmsdh_glom_post(bus->sdh, frame, pkt, len);
8368 dhd_bcmsdh_glom_clear(dhd_bus_t *bus)
8370 bcmsdh_glom_clear(bus->sdh);
8375 dhd_bus_chip(struct dhd_bus *bus)
8377 ASSERT(bus->sih != NULL);
8378 return bus->sih->chip;
8382 dhd_bus_pub(struct dhd_bus *bus)
8388 dhd_bus_txq(struct dhd_bus *bus)
8394 dhd_bus_hdrlen(struct dhd_bus *bus)
8396 return SDPCM_HDRLEN;
8400 dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag)
8408 if (!bus->dhd->dongle_reset) {
8409 dhd_os_sdlock(dhdp);
8410 dhd_os_wd_timer(dhdp, 0);
8411 #if !defined(IGNORE_ETH0_DOWN)
8412 /* Force flow control as protection when stop come before ifconfig_down */
8413 dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON);
8414 #endif /* !defined(IGNORE_ETH0_DOWN) */
8415 /* Expect app to have torn down any connection before calling */
8416 /* Stop the bus, disable F2 */
8417 dhd_bus_stop(bus, FALSE);
8419 #if defined(OOB_INTR_ONLY)
8420 /* Clean up any pending IRQ */
8421 bcmsdh_set_irq(FALSE);
8424 /* Clean tx/rx buffer pointers, detach from the dongle */
8425 dhdsdio_release_dongle(bus, bus->dhd->osh, TRUE, TRUE);
8427 bus->dhd->dongle_reset = TRUE;
8428 bus->dhd->up = FALSE;
8429 #ifdef BCMSDIOH_TXGLOM
8430 dhd_txglom_enable(dhdp, FALSE);
8432 dhd_os_sdunlock(dhdp);
8434 DHD_ERROR(("%s: WLAN OFF DONE\n", __FUNCTION__));
8435 /* App can now remove power from device */
8437 bcmerror = BCME_SDIO_ERROR;
8439 /* App must have restored power to device before calling */
8441 DHD_ERROR(("\n\n%s: == WLAN ON ==\n", __FUNCTION__));
8443 if (bus->dhd->dongle_reset) {
8446 dhd_os_sdlock(dhdp);
8447 #endif /* DHDTHREAD */
8448 /* Reset SD client */
8449 bcmsdh_reset(bus->sdh);
8451 /* Attempt to re-attach & download */
8452 if (dhdsdio_probe_attach(bus, bus->dhd->osh, bus->sdh,
8453 (uint32 *)SI_ENUM_BASE,
8455 /* Attempt to download binary to the dongle */
8456 dhd_conf_set_fw_name_by_chip(dhdp, fw_path, firmware_path); // terence
8457 if (dhdsdio_probe_init(bus, bus->dhd->osh, bus->sdh) &&
8458 dhdsdio_download_firmware(bus, bus->dhd->osh, bus->sdh)) {
8460 /* Re-init bus, enable F2 transfer */
8461 bcmerror = dhd_bus_init((dhd_pub_t *) bus->dhd, FALSE);
8462 if (bcmerror == BCME_OK) {
8463 bcmsdh_set_drvdata(dhdp); // terence 20131214: fix for null pointer issue
8464 #if defined(OOB_INTR_ONLY)
8465 /* make sure oob intr get registered */
8466 if (!bcmsdh_is_oob_intr_registered()) {
8467 sdioh_start(NULL, 1);
8468 bcmsdh_register_oob_intr(dhdp);
8472 bcmsdh_set_irq(TRUE);
8473 dhd_enable_oob_intr(bus, TRUE);
8476 bus->dhd->dongle_reset = FALSE;
8477 bus->dhd->up = TRUE;
8479 #if !defined(IGNORE_ETH0_DOWN)
8480 /* Restore flow control */
8481 dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF);
8483 dhd_os_wd_timer(dhdp, dhd_watchdog_ms);
8485 DHD_TRACE(("%s: WLAN ON DONE\n", __FUNCTION__));
8487 dhd_bus_stop(bus, FALSE);
8488 dhdsdio_release_dongle(bus, bus->dhd->osh,
8492 bcmerror = BCME_SDIO_ERROR;
8494 bcmerror = BCME_SDIO_ERROR;
8497 dhd_os_sdunlock(dhdp);
8498 #endif /* DHDTHREAD */
8500 bcmerror = BCME_SDIO_ERROR;
8501 DHD_ERROR(("%s called when dongle is not in reset\n",
8503 DHD_ERROR(("Will call dhd_bus_start instead\n"));
8504 sdioh_start(NULL, 1);
8506 dhd_conf_set_hw_oob_intr(bus->sdh, bus->sih->chip); // terence 20120615: fix for OOB initial issue
8508 dhd_conf_set_fw_name_by_chip(dhdp, fw_path, firmware_path);
8509 if ((bcmerror = dhd_bus_start(dhdp)) != 0)
8510 DHD_ERROR(("%s: dhd_bus_start fail with %d\n",
8511 __FUNCTION__, bcmerror));
8517 /* Get Chip ID version */
8518 uint dhd_bus_chip_id(dhd_pub_t *dhdp)
8520 dhd_bus_t *bus = dhdp->bus;
8522 return bus->sih->chip;
8525 /* Get Chip Rev ID version */
8526 uint dhd_bus_chiprev_id(dhd_pub_t *dhdp)
8528 dhd_bus_t *bus = dhdp->bus;
8530 return bus->sih->chiprev;
8533 /* Get Chip Pkg ID version */
8534 uint dhd_bus_chippkg_id(dhd_pub_t *dhdp)
8536 dhd_bus_t *bus = dhdp->bus;
8538 return bus->sih->chippkg;
8542 dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint size)
8547 return dhdsdio_membytes(bus, set, address, data, size);
8551 dhd_enableOOB(dhd_pub_t *dhd, bool sleep)
8553 dhd_bus_t *bus = dhd->bus;
8554 sdpcmd_regs_t *regs = bus->regs;
8558 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
8559 /* Tell device to start using OOB wakeup */
8560 W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries);
8561 if (retries > retry_limit) {
8562 DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
8565 /* Turn off our contribution to the HT clock request */
8566 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
8568 /* Make sure the controller has the bus up */
8569 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
8571 /* Send misc interrupt to indicate OOB not needed */
8572 W_SDREG(0, ®s->tosbmailboxdata, retries);
8573 if (retries <= retry_limit)
8574 W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries);
8576 if (retries > retry_limit)
8577 DHD_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n"));
8579 /* Make sure we have SD bus access */
8580 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
8586 dhd_bus_pktq_flush(dhd_pub_t *dhdp)
8588 dhd_bus_t *bus = dhdp->bus;
8589 /* Clear the data packet queues */
8590 pktq_flush(dhdp->osh, &bus->txq, TRUE, NULL, 0);
8594 dhd_sr_config(dhd_pub_t *dhd, bool on)
8596 dhd_bus_t *bus = dhd->bus;
8601 return dhdsdio_clk_devsleep_iovar(bus, on);
8605 dhd_get_chipid(dhd_pub_t *dhd)
8607 dhd_bus_t *bus = dhd->bus;
8609 if (bus && bus->sih)
8610 return (uint16)bus->sih->chip;