2 * DHD Bus Module for SDIO
4 * Copyright (C) 1999-2016, Broadcom Corporation
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
25 * <<Broadcom-WL-IPTag/Open:>>
27 * $Id: dhd_sdio.c 593728 2015-10-19 09:20:32Z $
35 #include BCMEMBEDIMAGE
36 #endif /* BCMEMBEDIMAGE */
40 #include <bcmendian.h>
47 #include <hnd_armtrap.h>
54 #include <sbsdpcmdev.h>
58 #include <proto/ethernet.h>
59 #include <proto/802.1d.h>
60 #include <proto/802.11.h>
62 #include <dngl_stats.h>
65 #include <dhd_proto.h>
69 #include <dhd_config.h>
74 #ifdef DHDTCPACK_SUPPRESS
76 #endif /* DHDTCPACK_SUPPRESS */
78 bool dhd_mp_halting(dhd_pub_t *dhdp);
79 extern void bcmsdh_waitfor_iodrain(void *sdh);
80 extern void bcmsdh_reject_ioreqs(void *sdh, bool reject);
81 extern bool bcmsdh_fatal_error(void *sdh);
83 #ifndef DHDSDIO_MEM_DUMP_FNAME
84 #define DHDSDIO_MEM_DUMP_FNAME "mem_dump"
87 #define QLEN (1024) /* bulk rx and tx queue lengths */
88 #define FCHI (QLEN - 10)
89 #define FCLOW (FCHI / 2)
92 #define TXRETRIES 2 /* # of retries for tx frames */
93 #define READ_FRM_CNT_RETRIES 3
95 #define DHD_RXBOUND 50 /* Default for max rx frames in one scheduling */
99 #define DHD_TXBOUND 20 /* Default for max tx frames in one scheduling */
102 #define DHD_TXMINMAX 1 /* Max tx frames if rx still pending */
104 #define MEMBLOCK 2048 /* Block size used for downloading of dongle image */
105 #define MAX_DATA_BUF (64 * 1024) /* Must be large enough to hold biggest possible glom */
107 #ifndef DHD_FIRSTREAD
108 #define DHD_FIRSTREAD 32
110 #if !ISPOWEROF2(DHD_FIRSTREAD)
111 #error DHD_FIRSTREAD is not a power of 2!
114 /* Total length of frame header for dongle protocol */
115 #define SDPCM_HDRLEN (SDPCM_FRAMETAG_LEN + SDPCM_SWHEADER_LEN)
116 #define SDPCM_HDRLEN_TXGLOM (SDPCM_HDRLEN + SDPCM_HWEXT_LEN)
117 #define MAX_TX_PKTCHAIN_CNT SDPCM_MAXGLOM_SIZE
120 #define SDPCM_RESERVE (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN)
122 #define SDPCM_RESERVE (SDPCM_HDRLEN + DHD_SDALIGN)
125 /* Space for header read, limit for data packets */
127 #define MAX_HDR_READ 32
129 #if !ISPOWEROF2(MAX_HDR_READ)
130 #error MAX_HDR_READ is not a power of 2!
133 #define MAX_RX_DATASZ 2048
135 /* Maximum milliseconds to wait for F2 to come up */
136 #define DHD_WAIT_F2RDY 3000
138 /* Bump up limit on waiting for HT to account for first startup;
139 * if the image is doing a CRC calculation before programming the PMU
140 * for HT availability, it could take a couple hundred ms more, so
141 * max out at a 1 second (1000000us).
143 #if (PMU_MAX_TRANSITION_DLY <= 1000000)
144 #undef PMU_MAX_TRANSITION_DLY
145 #define PMU_MAX_TRANSITION_DLY 1000000
148 /* hooks for limiting threshold custom tx num in rx processing */
149 #define DEFAULT_TXINRX_THRES 0
150 #ifndef CUSTOM_TXINRX_THRES
151 #define CUSTOM_TXINRX_THRES DEFAULT_TXINRX_THRES
154 /* Value for ChipClockCSR during initial setup */
155 #define DHD_INIT_CLKCTL1 (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ)
156 #define DHD_INIT_CLKCTL2 (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP)
158 /* Flags for SDH calls */
159 #define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED)
161 /* Packet free applicable unconditionally for sdio and sdspi. Conditional if
162 * bufpool was present for gspi bus.
164 #define PKTFREE2() if ((bus->bus != SPI_BUS) || bus->usebufpool) \
165 PKTFREE(bus->dhd->osh, pkt, FALSE);
168 pkt_statics_t tx_statics = {0};
171 DHD_SPINWAIT_SLEEP_INIT(sdioh_spinwait_sleep);
173 #if defined(MULTIPLE_SUPPLICANT)
174 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
175 DEFINE_MUTEX(_dhd_sdio_mutex_lock_);
176 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
179 /* Device console log buffer state */
180 #define CONSOLE_LINE_MAX 192
181 #define CONSOLE_BUFFER_MAX 2024
182 typedef struct dhd_console {
183 uint count; /* Poll interval msec counter */
184 uint log_addr; /* Log struct address (fixed) */
185 hnd_log_t log; /* Log struct (host copy) */
186 uint bufsize; /* Size of log buffer */
187 uint8 *buf; /* Log buffer (host copy) */
188 uint last; /* Last buffer read index */
191 #define REMAP_ENAB(bus) ((bus)->remap)
192 #define REMAP_ISADDR(bus, a) (((a) >= ((bus)->orig_ramsize)) && ((a) < ((bus)->ramsize)))
193 #define KSO_ENAB(bus) ((bus)->kso)
194 #define SR_ENAB(bus) ((bus)->_srenab)
195 #define SLPAUTO_ENAB(bus) ((SR_ENAB(bus)) && ((bus)->_slpauto))
196 #define MIN_RSRC_ADDR (SI_ENUM_BASE + 0x618)
197 #define MIN_RSRC_SR 0x3
198 #define CORE_CAPEXT_ADDR (SI_ENUM_BASE + 0x64c)
199 #define CORE_CAPEXT_SR_SUPPORTED_MASK (1 << 1)
200 #define RCTL_MACPHY_DISABLE_MASK (1 << 26)
201 #define RCTL_LOGIC_DISABLE_MASK (1 << 27)
203 #define OOB_WAKEUP_ENAB(bus) ((bus)->_oobwakeup)
204 #define GPIO_DEV_SRSTATE 16 /* Host gpio17 mapped to device gpio0 SR state */
205 #define GPIO_DEV_SRSTATE_TIMEOUT 320000 /* 320ms */
206 #define GPIO_DEV_WAKEUP 17 /* Host gpio17 mapped to device gpio1 wakeup */
207 #define CC_CHIPCTRL2_GPIO1_WAKEUP (1 << 0)
208 #define CC_CHIPCTRL3_SR_ENG_ENABLE (1 << 2)
209 #define OVERFLOW_BLKSZ512_WM 96
210 #define OVERFLOW_BLKSZ512_MES 80
212 #define CC_PMUCC3 (0x3)
213 /* Private data for SDIO bus interaction */
214 typedef struct dhd_bus {
217 bcmsdh_info_t *sdh; /* Handle for BCMSDH calls */
218 si_t *sih; /* Handle for SI calls */
219 char *vars; /* Variables (from CIS and/or other) */
220 uint varsz; /* Size of variables buffer */
221 uint32 sbaddr; /* Current SB window pointer (-1, invalid) */
223 sdpcmd_regs_t *regs; /* Registers for SDIO core */
224 uint sdpcmrev; /* SDIO core revision */
225 uint armrev; /* CPU core revision */
226 uint ramrev; /* SOCRAM core revision */
227 uint32 ramsize; /* Size of RAM in SOCRAM (bytes) */
228 uint32 orig_ramsize; /* Size of RAM in SOCRAM (bytes) */
229 uint32 srmemsize; /* Size of SRMEM */
231 uint32 bus; /* gSPI or SDIO bus */
232 uint32 bus_num; /* bus number */
233 uint32 slot_num; /* slot ID */
234 uint32 hostintmask; /* Copy of Host Interrupt Mask */
235 uint32 intstatus; /* Intstatus bits (events) pending */
236 bool dpc_sched; /* Indicates DPC schedule (intrpt rcvd) */
237 bool fcstate; /* State of dongle flow-control */
239 uint16 cl_devid; /* cached devid for dhdsdio_probe_attach() */
240 char *fw_path; /* module_param: path to firmware image */
241 char *nv_path; /* module_param: path to nvram vars file */
243 uint blocksize; /* Block size of SDIO transfers */
244 uint roundup; /* Max roundup limit */
246 struct pktq txq; /* Queue length used for flow-control */
247 uint8 flowcontrol; /* per prio flow control bitmask */
248 uint8 tx_seq; /* Transmit sequence number (next) */
249 uint8 tx_max; /* Maximum transmit sequence allowed */
251 uint8 hdrbuf[MAX_HDR_READ + DHD_SDALIGN];
252 uint8 *rxhdr; /* Header of current rx frame (in hdrbuf) */
253 uint16 nextlen; /* Next Read Len from last header */
254 uint8 rx_seq; /* Receive sequence number (expected) */
255 bool rxskip; /* Skip receive (awaiting NAK ACK) */
257 void *glomd; /* Packet containing glomming descriptor */
258 void *glom; /* Packet chain for glommed superframe */
259 uint glomerr; /* Glom packet read errors */
261 uint8 *rxbuf; /* Buffer for receiving control packets */
262 uint rxblen; /* Allocated length of rxbuf */
263 uint8 *rxctl; /* Aligned pointer into rxbuf */
264 uint8 *databuf; /* Buffer for receiving big glom packet */
265 uint8 *dataptr; /* Aligned pointer into databuf */
266 uint rxlen; /* Length of valid data in buffer */
268 uint8 sdpcm_ver; /* Bus protocol reported by dongle */
270 bool intr; /* Use interrupts */
271 bool poll; /* Use polling */
272 bool ipend; /* Device interrupt is pending */
273 bool intdis; /* Interrupts disabled by isr */
274 uint intrcount; /* Count of device interrupt callbacks */
275 uint lastintrs; /* Count as of last watchdog timer */
276 uint spurious; /* Count of spurious interrupts */
277 uint pollrate; /* Ticks between device polls */
278 uint polltick; /* Tick counter */
279 uint pollcnt; /* Count of active polls */
282 dhd_console_t console; /* Console output polling support */
283 uint console_addr; /* Console address from shared struct */
284 #endif /* DHD_DEBUG */
286 uint regfails; /* Count of R_REG/W_REG failures */
288 uint clkstate; /* State of sd and backplane clock(s) */
289 bool activity; /* Activity flag for clock down */
290 int32 idletime; /* Control for activity timeout */
291 int32 idlecount; /* Activity timeout counter */
292 int32 idleclock; /* How to set bus driver when idle */
293 int32 sd_divisor; /* Speed control to bus driver */
294 int32 sd_mode; /* Mode control to bus driver */
295 int32 sd_rxchain; /* If bcmsdh api accepts PKT chains */
296 bool use_rxchain; /* If dhd should use PKT chains */
297 bool sleeping; /* Is SDIO bus sleeping? */
298 #if defined(SUPPORT_P2P_GO_PS)
299 wait_queue_head_t bus_sleep;
300 #endif /* LINUX && SUPPORT_P2P_GO_PS */
301 uint rxflow_mode; /* Rx flow control mode */
302 bool rxflow; /* Is rx flow control on */
303 uint prev_rxlim_hit; /* Is prev rx limit exceeded (per dpc schedule) */
304 bool alp_only; /* Don't use HT clock (ALP only) */
305 /* Field to decide if rx of control frames happen in rxbuf or lb-pool */
307 int32 txinrx_thres; /* num of in-queued pkts */
308 int32 dotxinrx; /* tx first in dhdsdio_readframes */
310 /* external loopback */
314 /* pktgen configuration */
315 uint pktgen_freq; /* Ticks between bursts */
316 uint pktgen_count; /* Packets to send each burst */
317 uint pktgen_print; /* Bursts between count displays */
318 uint pktgen_total; /* Stop after this many */
319 uint pktgen_minlen; /* Minimum packet data len */
320 uint pktgen_maxlen; /* Maximum packet data len */
321 uint pktgen_mode; /* Configured mode: tx, rx, or echo */
322 uint pktgen_stop; /* Number of tx failures causing stop */
324 /* active pktgen fields */
325 uint pktgen_tick; /* Tick counter for bursts */
326 uint pktgen_ptick; /* Burst counter for printing */
327 uint pktgen_sent; /* Number of test packets generated */
328 uint pktgen_rcvd; /* Number of test packets received */
329 uint pktgen_prev_time; /* Time at which previous stats where printed */
330 uint pktgen_prev_sent; /* Number of test packets generated when
331 * previous stats were printed
333 uint pktgen_prev_rcvd; /* Number of test packets received when
334 * previous stats were printed
336 uint pktgen_fail; /* Number of failed send attempts */
337 uint16 pktgen_len; /* Length of next packet to send */
338 #define PKTGEN_RCV_IDLE (0)
339 #define PKTGEN_RCV_ONGOING (1)
340 uint16 pktgen_rcv_state; /* receive state */
341 uint pktgen_rcvd_rcvsession; /* test pkts rcvd per rcv session. */
344 /* Some additional counters */
345 uint tx_sderrs; /* Count of tx attempts with sd errors */
346 uint fcqueued; /* Tx packets that got queued */
347 uint rxrtx; /* Count of rtx requests (NAK to dongle) */
348 uint rx_toolong; /* Receive frames too long to receive */
349 uint rxc_errors; /* SDIO errors when reading control frames */
350 uint rx_hdrfail; /* SDIO errors on header reads */
351 uint rx_badhdr; /* Bad received headers (roosync?) */
352 uint rx_badseq; /* Mismatched rx sequence number */
353 uint fc_rcvd; /* Number of flow-control events received */
354 uint fc_xoff; /* Number which turned on flow-control */
355 uint fc_xon; /* Number which turned off flow-control */
356 uint rxglomfail; /* Failed deglom attempts */
357 uint rxglomframes; /* Number of glom frames (superframes) */
358 uint rxglompkts; /* Number of packets from glom frames */
359 uint f2rxhdrs; /* Number of header reads */
360 uint f2rxdata; /* Number of frame data reads */
361 uint f2txdata; /* Number of f2 frame writes */
362 uint f1regdata; /* Number of f1 register accesses */
363 #ifdef DHDENABLE_TAILPAD
364 uint tx_tailpad_chain; /* Number of tail padding by chaining pad_pkt */
365 uint tx_tailpad_pktget; /* Number of tail padding by new PKTGET */
366 #endif /* DHDENABLE_TAILPAD */
367 uint8 *ctrl_frame_buf;
368 uint32 ctrl_frame_len;
369 bool ctrl_frame_stat;
370 uint32 rxint_mode; /* rx interrupt mode */
371 bool remap; /* Contiguous 1MB RAM: 512K socram + 512K devram
372 * Available with socram rev 16
373 * Remap region not DMA-able
382 uint32 dongle_ram_base;
384 void *glom_pkt_arr[SDPCM_MAXGLOM_SIZE]; /* Array of pkts for glomming */
385 uint32 txglom_cnt; /* Number of pkts in the glom array */
386 uint32 txglom_total_len; /* Total length of pkts in glom array */
387 bool txglom_enable; /* Flag to indicate whether tx glom is enabled/disabled */
388 uint32 txglomsize; /* Glom size limitation */
389 #ifdef DHDENABLE_TAILPAD
391 #endif /* DHDENABLE_TAILPAD */
392 uint txglomframes; /* Number of tx glom frames (superframes) */
393 uint txglompkts; /* Number of packets from tx glom frames */
399 #define CLK_PENDING 2 /* Not used yet */
402 #define DHD_NOPMU(dhd) (FALSE)
404 #if defined(BCMSDIOH_STD)
405 #define BLK_64_MAXTXGLOM 20
406 #endif /* BCMSDIOH_STD */
409 static int qcount[NUMPRIO];
410 static int tx_packets[NUMPRIO];
411 #endif /* DHD_DEBUG */
413 /* Deferred transmit */
414 const uint dhd_deferred_tx = 1;
416 extern uint dhd_watchdog_ms;
418 extern void dhd_os_wd_timer(void *bus, uint wdtick);
419 int dhd_enableOOB(dhd_pub_t *dhd, bool sleep);
424 uint dhd_txminmax = DHD_TXMINMAX;
426 /* override the RAM size if possible */
427 #define DONGLE_MIN_RAMSIZE (128 *1024)
428 int dhd_dongle_ramsize;
430 uint dhd_doflow = TRUE;
431 uint dhd_dpcpoll = FALSE;
433 module_param(dhd_doflow, uint, 0644);
434 module_param(dhd_dpcpoll, uint, 0644);
436 static bool dhd_alignctl;
440 static bool retrydata;
441 #define RETRYCHAN(chan) (((chan) == SDPCM_EVENT_CHANNEL) || retrydata)
443 static uint watermark = 8;
444 static uint mesbusyctrl = 0;
445 static const uint firstread = DHD_FIRSTREAD;
447 /* Retry count for register access failures */
448 static const uint retry_limit = 2;
450 /* Force even SD lengths (some host controllers mess up on odd bytes) */
451 static bool forcealign;
455 #if (defined(OOB_INTR_ONLY) && defined(HW_OOB)) || defined(FORCE_WOWLAN)
456 extern void bcmsdh_enable_hw_oob_intr(void *sdh, bool enable);
459 #if defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD)
460 #error OOB_INTR_ONLY is NOT working with SDIO_ISR_THREAD
461 #endif /* defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD) */
462 #define PKTALIGN(osh, p, len, align) \
465 datalign = (uintptr)PKTDATA((osh), (p)); \
466 datalign = ROUNDUP(datalign, (align)) - datalign; \
467 ASSERT(datalign < (align)); \
468 ASSERT(PKTLEN((osh), (p)) >= ((len) + datalign)); \
470 PKTPULL((osh), (p), (uint)datalign); \
471 PKTSETLEN((osh), (p), (len)); \
474 /* Limit on rounding up frames */
475 static const uint max_roundup = 512;
477 /* Try doing readahead */
478 static bool dhd_readahead;
480 #if defined(SWTXGLOM) || defined(BCMSDIOH_TXGLOM_EXT)
482 dhdsdio_is_dataok(dhd_bus_t *bus) {
483 return (((uint8)(bus->tx_max - bus->tx_seq) - bus->dhd->conf->tx_max_offset > 1) && \
484 (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0));
488 dhdsdio_get_databufcnt(dhd_bus_t *bus) {
489 return ((uint8)(bus->tx_max - bus->tx_seq) - 1 - bus->dhd->conf->tx_max_offset);
493 /* To check if there's window offered */
494 #if defined(SWTXGLOM) || defined(BCMSDIOH_TXGLOM_EXT)
495 #define DATAOK(bus) dhdsdio_is_dataok(bus)
497 #define DATAOK(bus) \
498 (((uint8)(bus->tx_max - bus->tx_seq) > 1) && \
499 (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0))
502 /* To check if there's window offered for ctrl frame */
503 #define TXCTLOK(bus) \
504 (((uint8)(bus->tx_max - bus->tx_seq) != 0) && \
505 (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0))
507 /* Number of pkts available in dongle for data RX */
508 #if defined(SWTXGLOM) || defined(BCMSDIOH_TXGLOM_EXT)
509 #define DATABUFCNT(bus) dhdsdio_get_databufcnt(bus)
511 #define DATABUFCNT(bus) \
512 ((uint8)(bus->tx_max - bus->tx_seq) - 1)
515 /* Macros to get register read/write status */
516 /* NOTE: these assume a local dhdsdio_bus_t *bus! */
517 #define R_SDREG(regvar, regaddr, retryvar) \
521 regvar = R_REG(bus->dhd->osh, regaddr); \
522 } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \
524 bus->regfails += (retryvar-1); \
525 if (retryvar > retry_limit) { \
526 DHD_ERROR(("%s: FAILED" #regvar "READ, LINE %d\n", \
527 __FUNCTION__, __LINE__)); \
533 #define W_SDREG(regval, regaddr, retryvar) \
537 W_REG(bus->dhd->osh, regaddr, regval); \
538 } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \
540 bus->regfails += (retryvar-1); \
541 if (retryvar > retry_limit) \
542 DHD_ERROR(("%s: FAILED REGISTER WRITE, LINE %d\n", \
543 __FUNCTION__, __LINE__)); \
547 #define BUS_WAKE(bus) \
549 bus->idlecount = 0; \
550 if ((bus)->sleeping) \
551 dhdsdio_bussleep((bus), FALSE); \
555 * pktavail interrupts from dongle to host can be managed in 3 different ways
556 * whenever there is a packet available in dongle to transmit to host.
558 * Mode 0: Dongle writes the software host mailbox and host is interrupted.
559 * Mode 1: (sdiod core rev >= 4)
560 * Device sets a new bit in the intstatus whenever there is a packet
561 * available in fifo. Host can't clear this specific status bit until all the
562 * packets are read from the FIFO. No need to ack dongle intstatus.
563 * Mode 2: (sdiod core rev >= 4)
564 * Device sets a bit in the intstatus, and host acks this by writing
565 * one to this bit. Dongle won't generate anymore packet interrupts
566 * until host reads all the packets from the dongle and reads a zero to
567 * figure that there are no more packets. No need to disable host ints.
568 * Need to ack the intstatus.
571 #define SDIO_DEVICE_HMB_RXINT 0 /* default old way */
572 #define SDIO_DEVICE_RXDATAINT_MODE_0 1 /* from sdiod rev 4 */
573 #define SDIO_DEVICE_RXDATAINT_MODE_1 2 /* from sdiod rev 4 */
576 #define FRAME_AVAIL_MASK(bus) \
577 ((bus->rxint_mode == SDIO_DEVICE_HMB_RXINT) ? I_HMB_FRAME_IND : I_XMTDATA_AVAIL)
579 #define DHD_BUS SDIO_BUS
581 #define PKT_AVAILABLE(bus, intstatus) ((intstatus) & (FRAME_AVAIL_MASK(bus)))
583 #define HOSTINTMASK (I_HMB_SW_MASK | I_CHIPACTIVE)
585 #define GSPI_PR55150_BAILOUT
588 static void dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq);
589 static void dhdsdio_sdtest_set(dhd_bus_t *bus, uint count);
592 static int dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size);
594 static int dhd_serialconsole(dhd_bus_t *bus, bool get, bool enable, int *bcmerror);
595 #endif /* DHD_DEBUG */
597 #if defined(DHD_FW_COREDUMP)
598 static int dhdsdio_mem_dump(dhd_bus_t *bus);
599 #endif /* DHD_FW_COREDUMP */
600 static int dhdsdio_devcap_set(dhd_bus_t *bus, uint8 cap);
601 static int dhdsdio_download_state(dhd_bus_t *bus, bool enter);
603 static void dhdsdio_release(dhd_bus_t *bus, osl_t *osh);
604 static void dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh);
605 static void dhdsdio_disconnect(void *ptr);
606 static bool dhdsdio_chipmatch(uint16 chipid);
607 static bool dhdsdio_probe_attach(dhd_bus_t *bus, osl_t *osh, void *sdh,
608 void * regsva, uint16 devid);
609 static bool dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh);
610 static bool dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh);
611 static void dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation,
614 static void dhd_dongle_setramsize(struct dhd_bus *bus, int mem_size);
615 static int dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags,
616 uint8 *buf, uint nbytes,
617 void *pkt, bcmsdh_cmplt_fn_t complete, void *handle);
618 static int dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags,
619 uint8 *buf, uint nbytes,
620 void *pkt, bcmsdh_cmplt_fn_t complete, void *handle, int max_retry);
621 static int dhdsdio_txpkt(dhd_bus_t *bus, uint chan, void** pkts, int num_pkt, bool free_pkt);
622 static int dhdsdio_txpkt_preprocess(dhd_bus_t *bus, void *pkt, int chan, int txseq,
623 int prev_chain_total_len, bool last_chained_pkt,
624 int *pad_pkt_len, void **new_pkt
625 #if defined(BCMSDIOH_TXGLOM_EXT)
629 static int dhdsdio_txpkt_postprocess(dhd_bus_t *bus, void *pkt);
631 static int dhdsdio_download_firmware(dhd_bus_t *bus, osl_t *osh, void *sdh);
632 static int _dhdsdio_download_firmware(dhd_bus_t *bus);
634 static int dhdsdio_download_code_file(dhd_bus_t *bus, char *image_path);
635 static int dhdsdio_download_nvram(dhd_bus_t *bus);
637 static int dhdsdio_download_code_array(dhd_bus_t *bus);
639 static int dhdsdio_bussleep(dhd_bus_t *bus, bool sleep);
640 static int dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok);
641 static uint8 dhdsdio_sleepcsr_get(dhd_bus_t *bus);
645 extern uint32 dhd_get_htsf(void *dhd, int ifidx);
646 #endif /* WLMEDIA_HTSF */
649 dhdsdio_tune_fifoparam(struct dhd_bus *bus)
652 uint8 devctl, wm, mes;
654 if (bus->sih->buscorerev >= 15) {
655 /* See .ppt in PR for these recommended values */
656 if (bus->blocksize == 512) {
657 wm = OVERFLOW_BLKSZ512_WM;
658 mes = OVERFLOW_BLKSZ512_MES;
660 mes = bus->blocksize/4;
661 wm = bus->blocksize/4;
667 DHD_INFO(("skip fifotune: SdioRev(%d) is lower than minimal requested ver\n",
668 bus->sih->buscorerev));
672 /* Update watermark */
674 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, wm, &err);
676 devctl = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
677 devctl |= SBSDIO_DEVCTL_F2WM_ENAB;
678 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
683 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL,
684 (mes | SBSDIO_MESBUSYCTRL_ENAB), &err);
687 DHD_INFO(("Apply overflow WAR: 0x%02x 0x%02x 0x%02x\n",
688 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err),
689 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, &err),
690 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL, &err)));
694 dhd_dongle_setramsize(struct dhd_bus *bus, int mem_size)
696 int32 min_size = DONGLE_MIN_RAMSIZE;
697 /* Restrict the ramsize to user specified limit */
698 DHD_ERROR(("user: Restrict the dongle ram size to %d, min accepted %d\n",
699 dhd_dongle_ramsize, min_size));
700 if ((dhd_dongle_ramsize > min_size) &&
701 (dhd_dongle_ramsize < (int32)bus->orig_ramsize))
702 bus->ramsize = dhd_dongle_ramsize;
706 dhdsdio_set_siaddr_window(dhd_bus_t *bus, uint32 address)
709 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW,
710 (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err);
712 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID,
713 (address >> 16) & SBSDIO_SBADDRMID_MASK, &err);
715 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH,
716 (address >> 24) & SBSDIO_SBADDRHIGH_MASK, &err);
723 dhdsdio_oobwakeup_init(dhd_bus_t *bus)
725 uint32 val, addr, data;
727 bcmsdh_gpioouten(bus->sdh, GPIO_DEV_WAKEUP);
729 addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr);
730 data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data);
732 /* Set device for gpio1 wakeup */
733 bcmsdh_reg_write(bus->sdh, addr, 4, 2);
734 val = bcmsdh_reg_read(bus->sdh, data, 4);
735 val |= CC_CHIPCTRL2_GPIO1_WAKEUP;
736 bcmsdh_reg_write(bus->sdh, data, 4, val);
738 bus->_oobwakeup = TRUE;
742 #endif /* USE_OOB_GPIO1 */
745 * Query if FW is in SR mode
748 dhdsdio_sr_cap(dhd_bus_t *bus)
751 uint32 core_capext, addr, data;
753 if (bus->sih->chip == BCM43430_CHIP_ID) {
754 /* check if fw initialized sr engine */
755 addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, sr_control1);
756 if (bcmsdh_reg_read(bus->sdh, addr, 4) != 0)
761 if (bus->sih->chip == BCM4324_CHIP_ID) {
762 addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr);
763 data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data);
764 bcmsdh_reg_write(bus->sdh, addr, 4, 3);
765 core_capext = bcmsdh_reg_read(bus->sdh, data, 4);
766 } else if ((bus->sih->chip == BCM4330_CHIP_ID) ||
767 (bus->sih->chip == BCM43362_CHIP_ID)) {
769 } else if ((bus->sih->chip == BCM4335_CHIP_ID) ||
770 (bus->sih->chip == BCM4339_CHIP_ID) ||
771 (bus->sih->chip == BCM43349_CHIP_ID) ||
772 (bus->sih->chip == BCM4345_CHIP_ID) ||
773 (bus->sih->chip == BCM43454_CHIP_ID) ||
774 (bus->sih->chip == BCM4354_CHIP_ID) ||
775 (bus->sih->chip == BCM4356_CHIP_ID) ||
776 (bus->sih->chip == BCM4358_CHIP_ID) ||
777 (bus->sih->chip == BCM4371_CHIP_ID) ||
778 (BCM4349_CHIP(bus->sih->chip)) ||
779 (bus->sih->chip == BCM4350_CHIP_ID)) {
782 core_capext = bcmsdh_reg_read(bus->sdh, CORE_CAPEXT_ADDR, 4);
783 core_capext = (core_capext & CORE_CAPEXT_SR_SUPPORTED_MASK);
788 if (bus->sih->chip == BCM4324_CHIP_ID) {
789 /* FIX: Should change to query SR control register instead */
791 } else if ((bus->sih->chip == BCM4335_CHIP_ID) ||
792 (bus->sih->chip == BCM4339_CHIP_ID) ||
793 (bus->sih->chip == BCM43349_CHIP_ID) ||
794 (bus->sih->chip == BCM4345_CHIP_ID) ||
795 (bus->sih->chip == BCM43454_CHIP_ID) ||
796 (bus->sih->chip == BCM4354_CHIP_ID) ||
797 (bus->sih->chip == BCM4356_CHIP_ID) ||
798 (bus->sih->chip == BCM4358_CHIP_ID) ||
799 (bus->sih->chip == BCM4371_CHIP_ID) ||
800 (bus->sih->chip == BCM4350_CHIP_ID)) {
802 addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr);
803 data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data);
804 bcmsdh_reg_write(bus->sdh, addr, 4, CC_PMUCC3);
805 enabval = bcmsdh_reg_read(bus->sdh, data, 4);
807 if ((bus->sih->chip == BCM4350_CHIP_ID) ||
808 (bus->sih->chip == BCM4345_CHIP_ID) ||
809 (bus->sih->chip == BCM43454_CHIP_ID) ||
810 (bus->sih->chip == BCM4354_CHIP_ID) ||
811 (bus->sih->chip == BCM4356_CHIP_ID) ||
812 (bus->sih->chip == BCM4358_CHIP_ID) ||
813 (bus->sih->chip == BCM4371_CHIP_ID))
814 enabval &= CC_CHIPCTRL3_SR_ENG_ENABLE;
819 data = bcmsdh_reg_read(bus->sdh,
820 SI_ENUM_BASE + OFFSETOF(chipcregs_t, retention_ctl), 4);
821 if ((data & (RCTL_MACPHY_DISABLE_MASK | RCTL_LOGIC_DISABLE_MASK)) == 0)
829 dhdsdio_srwar_init(dhd_bus_t *bus)
831 bcmsdh_gpio_init(bus->sdh);
834 dhdsdio_oobwakeup_init(bus);
842 dhdsdio_sr_init(dhd_bus_t *bus)
847 if ((bus->sih->chip == BCM4334_CHIP_ID) && (bus->sih->chiprev == 2))
848 dhdsdio_srwar_init(bus);
850 val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, NULL);
851 val |= 1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT;
852 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL,
853 1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT, &err);
854 val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, NULL);
857 /* Add CMD14 Support */
858 dhdsdio_devcap_set(bus,
859 (SDIOD_CCCR_BRCM_CARDCAP_CMD14_SUPPORT | SDIOD_CCCR_BRCM_CARDCAP_CMD14_EXT));
860 #endif /* USE_CMD14 */
862 dhdsdio_devcap_set(bus, SDIOD_CCCR_BRCM_CARDCAP_CMD_NODEC);
864 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1,
865 SBSDIO_FUNC1_CHIPCLKCSR, SBSDIO_FORCE_HT, &err);
867 bus->_slpauto = dhd_slpauto ? TRUE : FALSE;
875 * FIX: Be sure KSO bit is enabled
876 * Currently, it's defaulting to 0 which should be 1.
879 dhdsdio_clk_kso_init(dhd_bus_t *bus)
888 * Enable KeepSdioOn (KSO) bit for normal operation
889 * Default is 0 (4334A0) so set it. Fixed in B0.
891 val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, NULL);
892 if (!(val & SBSDIO_FUNC1_SLEEPCSR_KSO_MASK)) {
893 val |= (SBSDIO_FUNC1_SLEEPCSR_KSO_EN << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT);
894 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, val, &err);
896 DHD_ERROR(("%s: SBSDIO_FUNC1_SLEEPCSR err: 0x%x\n", __FUNCTION__, err));
903 #define KSO_WAIT_US 50
904 #define KSO_WAIT_MS 1
905 #define KSO_SLEEP_RETRY_COUNT 20
906 #define KSO_WAKE_RETRY_COUNT 100
907 #define ERROR_BCME_NODEVICE_MAX 1
909 #define DEFAULT_MAX_KSO_ATTEMPTS (PMU_MAX_TRANSITION_DLY/KSO_WAIT_US)
910 #ifndef CUSTOM_MAX_KSO_ATTEMPTS
911 #define CUSTOM_MAX_KSO_ATTEMPTS DEFAULT_MAX_KSO_ATTEMPTS
915 dhdsdio_clk_kso_enab(dhd_bus_t *bus, bool on)
917 uint8 wr_val = 0, rd_val, cmp_val, bmask;
921 KSO_DBG(("%s> op:%s\n", __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR")));
923 wr_val |= (on << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT);
925 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, wr_val, &err);
928 cmp_val = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK | SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK;
934 /* Put device to sleep, turn off KSO */
936 bmask = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK;
940 rd_val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, &err);
941 if (((rd_val & bmask) == cmp_val) && !err)
944 KSO_DBG(("%s> KSO wr/rd retry:%d, ERR:%x \n", __FUNCTION__, try_cnt, err));
946 if (((try_cnt + 1) % KSO_SLEEP_RETRY_COUNT) == 0) {
947 OSL_SLEEP(KSO_WAIT_MS);
949 OSL_DELAY(KSO_WAIT_US);
951 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, wr_val, &err);
952 } while (try_cnt++ < CUSTOM_MAX_KSO_ATTEMPTS);
956 KSO_DBG(("%s> op:%s, try_cnt:%d, rd_val:%x, ERR:%x \n",
957 __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"), try_cnt, rd_val, err));
959 if (try_cnt > CUSTOM_MAX_KSO_ATTEMPTS) {
960 DHD_ERROR(("%s> op:%s, ERROR: try_cnt:%d, rd_val:%x, ERR:%x \n",
961 __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"), try_cnt, rd_val, err));
968 dhdsdio_clk_kso_iovar(dhd_bus_t *bus, bool on)
975 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
977 DHD_ERROR(("%s: KSO disable clk: 0x%x\n", __FUNCTION__,
978 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
979 SBSDIO_FUNC1_CHIPCLKCSR, &err)));
980 dhdsdio_clk_kso_enab(bus, FALSE);
982 DHD_ERROR(("%s: KSO enable\n", __FUNCTION__));
984 /* Make sure we have SD bus access */
985 if (bus->clkstate == CLK_NONE) {
986 DHD_ERROR(("%s: Request SD clk\n", __FUNCTION__));
987 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
990 dhdsdio_clk_kso_enab(bus, TRUE);
992 DHD_ERROR(("%s: sleepcsr: 0x%x\n", __FUNCTION__,
993 dhdsdio_sleepcsr_get(bus)));
1003 dhdsdio_sleepcsr_get(dhd_bus_t *bus)
1008 val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, &err);
1010 DHD_TRACE(("Failed to read SLEEPCSR: %d\n", err));
1016 dhdsdio_devcap_get(dhd_bus_t *bus)
1018 return bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_BRCM_CARDCAP, NULL);
1022 dhdsdio_devcap_set(dhd_bus_t *bus, uint8 cap)
1026 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_BRCM_CARDCAP, cap, &err);
1028 DHD_ERROR(("%s: devcap set err: 0x%x\n", __FUNCTION__, err));
1034 dhdsdio_clk_devsleep_iovar(dhd_bus_t *bus, bool on)
1043 /* Be sure we request clk before going to sleep
1044 * so we can wake-up with clk request already set
1045 * else device can go back to sleep immediately
1047 if (!SLPAUTO_ENAB(bus))
1048 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
1050 val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
1051 if ((val & SBSDIO_CSR_MASK) == 0) {
1052 DHD_ERROR(("%s: No clock before enter sleep:0x%x\n",
1053 __FUNCTION__, val));
1055 /* Reset clock request */
1056 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
1057 SBSDIO_ALP_AVAIL_REQ, &err);
1058 DHD_ERROR(("%s: clock before sleep:0x%x\n", __FUNCTION__,
1059 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
1060 SBSDIO_FUNC1_CHIPCLKCSR, &err)));
1064 DHD_TRACE(("%s: clk before sleep: 0x%x\n", __FUNCTION__,
1065 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
1066 SBSDIO_FUNC1_CHIPCLKCSR, &err)));
1068 err = bcmsdh_sleep(bus->sdh, TRUE);
1072 err = dhdsdio_clk_kso_enab(bus, FALSE);
1073 if (OOB_WAKEUP_ENAB(bus))
1075 err = bcmsdh_gpioout(bus->sdh, GPIO_DEV_WAKEUP, FALSE); /* GPIO_1 is off */
1077 #endif /* USE_CMD14 */
1080 /* Make sure we have SD bus access */
1081 if (bus->clkstate == CLK_NONE) {
1082 DHD_TRACE(("%s: Request SD clk\n", __FUNCTION__));
1083 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
1086 if ((bus->sih->chip == BCM4334_CHIP_ID) && (bus->sih->chiprev == 2)) {
1087 SPINWAIT_SLEEP(sdioh_spinwait_sleep,
1088 (bcmsdh_gpioin(bus->sdh, GPIO_DEV_SRSTATE) != TRUE),
1089 GPIO_DEV_SRSTATE_TIMEOUT);
1091 if (bcmsdh_gpioin(bus->sdh, GPIO_DEV_SRSTATE) == FALSE) {
1092 DHD_ERROR(("ERROR: GPIO_DEV_SRSTATE still low!\n"));
1096 err = bcmsdh_sleep(bus->sdh, FALSE);
1097 if (SLPAUTO_ENAB(bus) && (err != 0)) {
1099 DHD_TRACE(("%s: Resync device sleep\n", __FUNCTION__));
1101 /* Toggle sleep to resync with host and device */
1102 err = bcmsdh_sleep(bus->sdh, TRUE);
1104 err = bcmsdh_sleep(bus->sdh, FALSE);
1108 DHD_ERROR(("%s: CMD14 exit failed again!\n", __FUNCTION__));
1110 /* Toggle sleep to resync with host and device */
1111 err = bcmsdh_sleep(bus->sdh, TRUE);
1113 err = bcmsdh_sleep(bus->sdh, FALSE);
1115 DHD_ERROR(("%s: CMD14 exit failed twice!\n", __FUNCTION__));
1116 DHD_ERROR(("%s: FATAL: Device non-response!\n",
1123 if (OOB_WAKEUP_ENAB(bus))
1125 err = bcmsdh_gpioout(bus->sdh, GPIO_DEV_WAKEUP, TRUE); /* GPIO_1 is on */
1128 err = dhdsdio_clk_kso_enab(bus, TRUE);
1131 } while ((err != 0) && (++retry < 3));
1134 DHD_ERROR(("ERROR: kso set failed retry: %d\n", retry));
1135 err = 0; /* continue anyway */
1139 #endif /* !USE_CMD14 */
1144 /* Wait for device ready during transition to wake-up */
1145 SPINWAIT_SLEEP(sdioh_spinwait_sleep,
1146 (((csr = dhdsdio_sleepcsr_get(bus)) &
1147 SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK) !=
1148 (SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK)), (20000));
1150 DHD_TRACE(("%s: ExitSleep sleepcsr: 0x%x\n", __FUNCTION__, csr));
1152 if (!(csr & SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK)) {
1153 DHD_ERROR(("%s:ERROR: ExitSleep device NOT Ready! 0x%x\n",
1154 __FUNCTION__, csr));
1155 err = BCME_NODEVICE;
1158 SPINWAIT_SLEEP(sdioh_spinwait_sleep,
1159 (((csr = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
1160 SBSDIO_FUNC1_CHIPCLKCSR, &err)) & SBSDIO_HT_AVAIL) !=
1161 (SBSDIO_HT_AVAIL)), (10000));
1163 DHD_TRACE(("%s: SBSDIO_FUNC1_CHIPCLKCSR : 0x%x\n", __FUNCTION__, csr));
1164 if (!err && ((csr & SBSDIO_HT_AVAIL) != SBSDIO_HT_AVAIL)) {
1165 DHD_ERROR(("%s:ERROR: device NOT Ready! 0x%x\n",
1166 __FUNCTION__, csr));
1167 err = BCME_NODEVICE;
1172 /* Update if successful */
1174 bus->kso = on ? FALSE : TRUE;
1176 DHD_ERROR(("%s: Sleep request failed: kso:%d on:%d err:%d\n",
1177 __FUNCTION__, bus->kso, on, err));
1178 if (!on && retry > 2)
1185 /* Turn backplane clock on or off */
1187 dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok)
1189 #define HT_AVAIL_ERROR_MAX 10
1190 static int ht_avail_error = 0;
1192 uint8 clkctl, clkreq, devctl;
1195 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1204 if (SLPAUTO_ENAB(bus)) {
1205 bus->clkstate = (on ? CLK_AVAIL : CLK_SDONLY);
1210 /* Request HT Avail */
1211 clkreq = bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ;
1215 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
1218 if (ht_avail_error < HT_AVAIL_ERROR_MAX) {
1219 DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err));
1222 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
1223 else if (ht_avail_error == HT_AVAIL_ERROR_MAX) {
1224 bus->dhd->hang_reason = HANG_REASON_HT_AVAIL_ERROR;
1225 dhd_os_send_hang_message(bus->dhd);
1227 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) */
1234 /* Check current status */
1235 clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
1237 DHD_ERROR(("%s: HT Avail read error: %d\n", __FUNCTION__, err));
1241 #if !defined(OOB_INTR_ONLY)
1242 /* Go to pending and await interrupt if appropriate */
1243 if (!SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) {
1244 /* Allow only clock-available interrupt */
1245 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
1247 DHD_ERROR(("%s: Devctl access error setting CA: %d\n",
1248 __FUNCTION__, err));
1252 devctl |= SBSDIO_DEVCTL_CA_INT_ONLY;
1253 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
1254 DHD_INFO(("CLKCTL: set PENDING\n"));
1255 bus->clkstate = CLK_PENDING;
1258 #endif /* !defined (OOB_INTR_ONLY) */
1260 if (bus->clkstate == CLK_PENDING) {
1261 /* Cancel CA-only interrupt filter */
1262 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
1263 devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
1264 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
1268 /* Otherwise, wait here (polling) for HT Avail */
1269 if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
1270 SPINWAIT_SLEEP(sdioh_spinwait_sleep,
1271 ((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
1272 SBSDIO_FUNC1_CHIPCLKCSR, &err)),
1273 !SBSDIO_CLKAV(clkctl, bus->alp_only)), PMU_MAX_TRANSITION_DLY);
1276 DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err));
1279 if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
1280 DHD_ERROR(("%s: HT Avail timeout (%d): clkctl 0x%02x\n",
1281 __FUNCTION__, PMU_MAX_TRANSITION_DLY, clkctl));
1285 /* Mark clock available */
1286 bus->clkstate = CLK_AVAIL;
1287 DHD_INFO(("CLKCTL: turned ON\n"));
1289 #if defined(DHD_DEBUG)
1290 if (bus->alp_only == TRUE) {
1291 #if !defined(BCMLXSDMMC)
1292 if (!SBSDIO_ALPONLY(clkctl)) {
1293 DHD_ERROR(("%s: HT Clock, when ALP Only\n", __FUNCTION__));
1295 #endif /* !defined(BCMLXSDMMC) */
1297 if (SBSDIO_ALPONLY(clkctl)) {
1298 DHD_ERROR(("%s: HT Clock should be on.\n", __FUNCTION__));
1301 #endif /* defined (DHD_DEBUG) */
1303 bus->activity = TRUE;
1304 #ifdef DHD_USE_IDLECOUNT
1306 #endif /* DHD_USE_IDLECOUNT */
1310 if (bus->clkstate == CLK_PENDING) {
1311 /* Cancel CA-only interrupt filter */
1312 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
1313 devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
1314 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
1317 bus->clkstate = CLK_SDONLY;
1318 if (!SR_ENAB(bus)) {
1319 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
1320 DHD_INFO(("CLKCTL: turned OFF\n"));
1322 DHD_ERROR(("%s: Failed access turning clock off: %d\n",
1323 __FUNCTION__, err));
1331 /* Change idle/active SD state */
1333 dhdsdio_sdclk(dhd_bus_t *bus, bool on)
1338 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1341 if (bus->idleclock == DHD_IDLE_STOP) {
1342 /* Turn on clock and restore mode */
1344 err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0,
1345 &iovalue, sizeof(iovalue), TRUE);
1347 DHD_ERROR(("%s: error enabling sd_clock: %d\n",
1348 __FUNCTION__, err));
1352 iovalue = bus->sd_mode;
1353 err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
1354 &iovalue, sizeof(iovalue), TRUE);
1356 DHD_ERROR(("%s: error changing sd_mode: %d\n",
1357 __FUNCTION__, err));
1360 } else if (bus->idleclock != DHD_IDLE_ACTIVE) {
1361 /* Restore clock speed */
1362 iovalue = bus->sd_divisor;
1363 err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
1364 &iovalue, sizeof(iovalue), TRUE);
1366 DHD_ERROR(("%s: error restoring sd_divisor: %d\n",
1367 __FUNCTION__, err));
1371 bus->clkstate = CLK_SDONLY;
1373 /* Stop or slow the SD clock itself */
1374 if ((bus->sd_divisor == -1) || (bus->sd_mode == -1)) {
1375 DHD_TRACE(("%s: can't idle clock, divisor %d mode %d\n",
1376 __FUNCTION__, bus->sd_divisor, bus->sd_mode));
1379 if (bus->idleclock == DHD_IDLE_STOP) {
1381 /* Change to SD1 mode and turn off clock */
1383 err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
1384 &iovalue, sizeof(iovalue), TRUE);
1386 DHD_ERROR(("%s: error changing sd_clock: %d\n",
1387 __FUNCTION__, err));
1393 err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0,
1394 &iovalue, sizeof(iovalue), TRUE);
1396 DHD_ERROR(("%s: error disabling sd_clock: %d\n",
1397 __FUNCTION__, err));
1400 } else if (bus->idleclock != DHD_IDLE_ACTIVE) {
1401 /* Set divisor to idle value */
1402 iovalue = bus->idleclock;
1403 err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
1404 &iovalue, sizeof(iovalue), TRUE);
1406 DHD_ERROR(("%s: error changing sd_divisor: %d\n",
1407 __FUNCTION__, err));
1411 bus->clkstate = CLK_NONE;
1417 /* Transition SD and backplane clock readiness */
1419 dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok)
1423 uint oldstate = bus->clkstate;
1424 #endif /* DHD_DEBUG */
1426 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1428 /* Early exit if we're already there */
1429 if (bus->clkstate == target) {
1430 if (target == CLK_AVAIL) {
1431 dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
1432 bus->activity = TRUE;
1433 #ifdef DHD_USE_IDLECOUNT
1435 #endif /* DHD_USE_IDLECOUNT */
1442 /* Make sure SD clock is available */
1443 if (bus->clkstate == CLK_NONE)
1444 dhdsdio_sdclk(bus, TRUE);
1445 /* Now request HT Avail on the backplane */
1446 ret = dhdsdio_htclk(bus, TRUE, pendok);
1447 if (ret == BCME_OK) {
1448 dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
1449 bus->activity = TRUE;
1450 #ifdef DHD_USE_IDLECOUNT
1452 #endif /* DHD_USE_IDLECOUNT */
1457 /* Remove HT request, or bring up SD clock */
1458 if (bus->clkstate == CLK_NONE)
1459 ret = dhdsdio_sdclk(bus, TRUE);
1460 else if (bus->clkstate == CLK_AVAIL)
1461 ret = dhdsdio_htclk(bus, FALSE, FALSE);
1463 DHD_ERROR(("dhdsdio_clkctl: request for %d -> %d\n",
1464 bus->clkstate, target));
1465 if (ret == BCME_OK) {
1466 dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
1471 /* Make sure to remove HT request */
1472 if (bus->clkstate == CLK_AVAIL)
1473 ret = dhdsdio_htclk(bus, FALSE, FALSE);
1474 /* Now remove the SD clock */
1475 ret = dhdsdio_sdclk(bus, FALSE);
1477 if (dhd_console_ms == 0)
1478 #endif /* DHD_DEBUG */
1480 dhd_os_wd_timer(bus->dhd, 0);
1484 DHD_INFO(("dhdsdio_clkctl: %d -> %d\n", oldstate, bus->clkstate));
1485 #endif /* DHD_DEBUG */
1491 dhdsdio_bussleep(dhd_bus_t *bus, bool sleep)
1494 bcmsdh_info_t *sdh = bus->sdh;
1495 sdpcmd_regs_t *regs = bus->regs;
1498 DHD_INFO(("dhdsdio_bussleep: request %s (currently %s)\n",
1499 (sleep ? "SLEEP" : "WAKE"),
1500 (bus->sleeping ? "SLEEP" : "WAKE")));
1502 if (bus->dhd->hang_was_sent)
1505 /* Done if we're already in the requested state */
1506 if (sleep == bus->sleeping)
1509 /* Going to sleep: set the alarm and turn off the lights... */
1511 /* Don't sleep if something is pending */
1512 #ifdef DHD_USE_IDLECOUNT
1513 if (bus->dpc_sched || bus->rxskip || pktq_len(&bus->txq) || bus->readframes ||
1514 bus->ctrl_frame_stat)
1516 if (bus->dpc_sched || bus->rxskip || pktq_len(&bus->txq))
1517 #endif /* DHD_USE_IDLECOUNT */
1521 if (!SLPAUTO_ENAB(bus)) {
1522 /* Disable SDIO interrupts (no longer interested) */
1523 bcmsdh_intr_disable(bus->sdh);
1525 /* Make sure the controller has the bus up */
1526 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
1528 /* Tell device to start using OOB wakeup */
1529 W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries);
1530 if (retries > retry_limit)
1531 DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
1533 /* Turn off our contribution to the HT clock request */
1534 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
1536 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
1537 SBSDIO_FORCE_HW_CLKREQ_OFF, NULL);
1539 /* Isolate the bus */
1540 if (bus->sih->chip != BCM4329_CHIP_ID &&
1541 bus->sih->chip != BCM4319_CHIP_ID) {
1542 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL,
1543 SBSDIO_DEVCTL_PADS_ISO, NULL);
1546 /* Leave interrupts enabled since device can exit sleep and
1549 err = dhdsdio_clk_devsleep_iovar(bus, TRUE /* sleep */);
1553 bus->sleeping = TRUE;
1554 #if defined(SUPPORT_P2P_GO_PS)
1555 wake_up(&bus->bus_sleep);
1556 #endif /* LINUX && SUPPORT_P2P_GO_PS */
1558 /* Waking up: bus power up is ok, set local state */
1560 if (!SLPAUTO_ENAB(bus)) {
1561 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0, &err);
1563 /* Force pad isolation off if possible (in case power never toggled) */
1564 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, 0, NULL);
1567 /* Make sure the controller has the bus up */
1568 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
1570 /* Send misc interrupt to indicate OOB not needed */
1571 W_SDREG(0, ®s->tosbmailboxdata, retries);
1572 if (retries <= retry_limit)
1573 W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries);
1575 if (retries > retry_limit)
1576 DHD_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n"));
1578 /* Make sure we have SD bus access */
1579 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
1581 /* Enable interrupts again */
1582 if (bus->intr && (bus->dhd->busstate == DHD_BUS_DATA)) {
1583 bus->intdis = FALSE;
1584 bcmsdh_intr_enable(bus->sdh);
1587 err = dhdsdio_clk_devsleep_iovar(bus, FALSE /* wake */);
1592 bus->sleeping = FALSE;
1599 #ifdef USE_DYNAMIC_F2_BLKSIZE
1600 int dhdsdio_func_blocksize(dhd_pub_t *dhd, int function_num, int block_size)
1602 int func_blk_size = function_num;
1606 bcmerr = dhd_bus_iovar_op(dhd, "sd_blocksize", &func_blk_size,
1607 sizeof(int), &result, sizeof(int), IOV_GET);
1609 if (bcmerr != BCME_OK) {
1610 DHD_ERROR(("%s: Get F%d Block size error\n", __FUNCTION__, function_num));
1614 if (result != block_size) {
1615 DHD_TRACE_HW4(("%s: F%d Block size set from %d to %d\n",
1616 __FUNCTION__, function_num, result, block_size));
1617 func_blk_size = function_num << 16 | block_size;
1618 bcmerr = dhd_bus_iovar_op(dhd, "sd_blocksize", NULL,
1619 0, &func_blk_size, sizeof(int32), IOV_SET);
1620 if (bcmerr != BCME_OK) {
1621 DHD_ERROR(("%s: Set F2 Block size error\n", __FUNCTION__));
1628 #endif /* USE_DYNAMIC_F2_BLKSIZE */
1630 #if defined(OOB_INTR_ONLY) || defined(FORCE_WOWLAN)
1632 dhd_enable_oob_intr(struct dhd_bus *bus, bool enable)
1634 #if defined(HW_OOB) || defined(FORCE_WOWLAN)
1635 bcmsdh_enable_hw_oob_intr(bus->sdh, enable);
1637 sdpcmd_regs_t *regs = bus->regs;
1640 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
1641 if (enable == TRUE) {
1643 /* Tell device to start using OOB wakeup */
1644 W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries);
1645 if (retries > retry_limit)
1646 DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
1649 /* Send misc interrupt to indicate OOB not needed */
1650 W_SDREG(0, ®s->tosbmailboxdata, retries);
1651 if (retries <= retry_limit)
1652 W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries);
1655 /* Turn off our contribution to the HT clock request */
1656 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
1657 #endif /* !defined(HW_OOB) */
1662 dhd_bus_txdata(struct dhd_bus *bus, void *pkt)
1664 int ret = BCME_ERROR;
1668 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1670 osh = bus->dhd->osh;
1671 datalen = PKTLEN(osh, pkt);
1674 /* Push the test header if doing loopback */
1675 if (bus->ext_loop) {
1677 PKTPUSH(osh, pkt, SDPCM_TEST_HDRLEN);
1678 data = PKTDATA(osh, pkt);
1679 *data++ = SDPCM_TEST_ECHOREQ;
1680 *data++ = (uint8)bus->loopid++;
1681 *data++ = (datalen >> 0);
1682 *data++ = (datalen >> 8);
1683 datalen += SDPCM_TEST_HDRLEN;
1686 BCM_REFERENCE(datalen);
1689 prec = PRIO2PREC((PKTPRIO(pkt) & PRIOMASK));
1691 /* Check for existing queue, current flow-control, pending event, or pending clock */
1692 if (dhd_deferred_tx || bus->fcstate || pktq_len(&bus->txq) || bus->dpc_sched ||
1693 (!DATAOK(bus)) || (bus->flowcontrol & NBITVAL(prec)) ||
1694 (bus->clkstate != CLK_AVAIL)) {
1698 DHD_TRACE(("%s: deferring pktq len %d\n", __FUNCTION__, pktq_len(&bus->txq)));
1701 /* Priority based enq */
1702 dhd_os_sdlock_txq(bus->dhd);
1703 deq_ret = dhd_prec_enq(bus->dhd, &bus->txq, pkt, prec);
1704 dhd_os_sdunlock_txq(bus->dhd);
1707 #ifdef PROP_TXSTATUS
1708 if (DHD_PKTTAG_WLFCPKT(PKTTAG(pkt)) == 0)
1709 #endif /* PROP_TXSTATUS */
1711 #ifdef DHDTCPACK_SUPPRESS
1712 if (dhd_tcpack_check_xmit(bus->dhd, pkt) == BCME_ERROR) {
1713 DHD_ERROR(("%s %d: tcpack_suppress ERROR!!! Stop using\n",
1714 __FUNCTION__, __LINE__));
1715 dhd_tcpack_suppress_set(bus->dhd, TCPACK_SUP_OFF);
1717 #endif /* DHDTCPACK_SUPPRESS */
1718 dhd_txcomplete(bus->dhd, pkt, FALSE);
1719 PKTFREE(osh, pkt, TRUE);
1721 ret = BCME_NORESOURCE;
1725 dhd_os_sdlock_txq(bus->dhd);
1726 pkq_len = pktq_len(&bus->txq);
1727 dhd_os_sdunlock_txq(bus->dhd);
1728 if (pkq_len >= FCHI) {
1729 bool wlfc_enabled = FALSE;
1730 #ifdef PROP_TXSTATUS
1731 wlfc_enabled = (dhd_wlfc_flowcontrol(bus->dhd, ON, FALSE) !=
1734 if (!wlfc_enabled && dhd_doflow) {
1735 dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON);
1740 dhd_os_sdlock_txq(bus->dhd);
1741 if (pktq_plen(&bus->txq, prec) > qcount[prec])
1742 qcount[prec] = pktq_plen(&bus->txq, prec);
1743 dhd_os_sdunlock_txq(bus->dhd);
1746 /* Schedule DPC if needed to send queued packet(s) */
1747 if (dhd_deferred_tx && !bus->dpc_sched) {
1748 if (bus->dhd->conf->deferred_tx_len) {
1749 if(dhd_os_wd_timer_enabled(bus->dhd) == FALSE) {
1750 bus->dpc_sched = TRUE;
1751 dhd_sched_dpc(bus->dhd);
1753 if(pktq_len(&bus->txq) >= bus->dhd->conf->deferred_tx_len &&
1754 dhd_os_wd_timer_enabled(bus->dhd) == FALSE) {
1755 bus->dpc_sched = TRUE;
1756 dhd_sched_dpc(bus->dhd);
1759 bus->dpc_sched = TRUE;
1760 dhd_sched_dpc(bus->dhd);
1764 int chan = SDPCM_DATA_CHANNEL;
1767 chan = (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL);
1769 /* Lock: we're about to use shared data/code (and SDIO) */
1770 dhd_os_sdlock(bus->dhd);
1772 /* Otherwise, send it now */
1774 /* Make sure back plane ht clk is on, no pending allowed */
1775 dhdsdio_clkctl(bus, CLK_AVAIL, TRUE);
1777 ret = dhdsdio_txpkt(bus, chan, &pkt, 1, TRUE);
1780 bus->dhd->tx_errors++;
1782 bus->dhd->dstats.tx_bytes += datalen;
1784 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
1785 bus->activity = FALSE;
1786 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
1789 dhd_os_sdunlock(bus->dhd);
1795 /* align packet data pointer and packet length to n-byte boundary, process packet headers,
1796 * a new packet may be allocated if there is not enough head and/or tail from for padding.
1797 * the caller is responsible for updating the glom size in the head packet (when glom is
1800 * pad_pkt_len: returns the length of extra padding needed from the padding packet, this parameter
1801 * is taken in tx glom mode only
1803 * new_pkt: out, pointer of the new packet allocated due to insufficient head room for alignment
1804 * padding, NULL if not needed, the caller is responsible for freeing the new packet
1806 * return: positive value - length of the packet, including head and tail padding
1807 * negative value - errors
1809 static int dhdsdio_txpkt_preprocess(dhd_bus_t *bus, void *pkt, int chan, int txseq,
1810 int prev_chain_total_len, bool last_chained_pkt,
1811 int *pad_pkt_len, void **new_pkt
1812 #if defined(BCMSDIOH_TXGLOM_EXT)
1822 int tail_padding = 0;
1824 uint32 swhdr_offset;
1825 bool alloc_new_pkt = FALSE;
1826 uint8 sdpcm_hdrlen = bus->txglom_enable ? SDPCM_HDRLEN_TXGLOM : SDPCM_HDRLEN;
1832 osh = bus->dhd->osh;
1834 #ifdef DHDTCPACK_SUPPRESS
1835 if (dhd_tcpack_check_xmit(bus->dhd, pkt) == BCME_ERROR) {
1836 DHD_ERROR(("%s %d: tcpack_suppress ERROR!!! Stop using it\n",
1837 __FUNCTION__, __LINE__));
1838 dhd_tcpack_suppress_set(bus->dhd, TCPACK_SUP_OFF);
1840 #endif /* DHDTCPACK_SUPPRESS */
1842 /* Add space for the SDPCM hardware/software headers */
1843 PKTPUSH(osh, pkt, sdpcm_hdrlen);
1844 ASSERT(ISALIGNED((uintptr)PKTDATA(osh, pkt), 2));
1846 frame = (uint8*)PKTDATA(osh, pkt);
1847 pkt_len = (uint16)PKTLEN(osh, pkt);
1850 frame = (uint8*)PKTDATA(osh, pkt);
1851 if (PKTLEN(osh, pkt) >= 100) {
1852 htsf_ts = (htsfts_t*) (frame + HTSF_HOSTOFFSET + 12);
1853 if (htsf_ts->magic == HTSFMAGIC) {
1854 htsf_ts->c20 = get_cycles();
1855 htsf_ts->t20 = dhd_get_htsf(bus->dhd->info, 0);
1858 #endif /* WLMEDIA_HTSF */
1860 len = (uint16)PKTLEN(osh, pkt);
1862 case SDPCM_CONTROL_CHANNEL:
1863 tx_statics.ctrl_count++;
1864 tx_statics.ctrl_size += len;
1866 case SDPCM_DATA_CHANNEL:
1867 tx_statics.data_count++;
1868 tx_statics.data_size += len;
1870 case SDPCM_GLOM_CHANNEL:
1871 tx_statics.glom_count++;
1872 tx_statics.glom_size += len;
1874 case SDPCM_EVENT_CHANNEL:
1875 tx_statics.event_count++;
1876 tx_statics.event_size += len;
1878 case SDPCM_TEST_CHANNEL:
1879 tx_statics.test_count++;
1880 tx_statics.test_size += len;
1886 #endif /* PKT_STATICS */
1888 if (PKTPRIO(pkt) < ARRAYSIZE(tx_packets))
1889 tx_packets[PKTPRIO(pkt)]++;
1890 #endif /* DHD_DEBUG */
1892 /* align the data pointer, allocate a new packet if there is not enough space (new
1893 * packet data pointer will be aligned thus no padding will be needed)
1895 head_padding = (ulong)frame % DHD_SDALIGN;
1896 if (PKTHEADROOM(osh, pkt) < head_padding) {
1898 alloc_new_pkt = TRUE;
1900 uint cur_chain_total_len;
1901 int chain_tail_padding = 0;
1903 /* All packets need to be aligned by DHD_SDALIGN */
1904 modulo = (pkt_len + head_padding) % DHD_SDALIGN;
1905 tail_padding = modulo > 0 ? (DHD_SDALIGN - modulo) : 0;
1907 /* Total pkt chain length needs to be aligned by block size,
1908 * unless it is a single pkt chain with total length less than one block size,
1909 * which we prefer sending by byte mode.
1911 * Do the chain alignment here if
1912 * 1. This is the last pkt of the chain of multiple pkts or a single pkt.
1913 * 2-1. This chain is of multiple pkts, or
1914 * 2-2. This is a single pkt whose size is longer than one block size.
1916 cur_chain_total_len = prev_chain_total_len +
1917 (head_padding + pkt_len + tail_padding);
1918 if (last_chained_pkt && bus->blocksize != 0 &&
1919 (cur_chain_total_len > (int)bus->blocksize || prev_chain_total_len > 0)) {
1920 modulo = cur_chain_total_len % bus->blocksize;
1921 chain_tail_padding = modulo > 0 ? (bus->blocksize - modulo) : 0;
1924 #ifdef DHDENABLE_TAILPAD
1925 if (PKTTAILROOM(osh, pkt) < tail_padding) {
1926 /* We don't have tail room to align by DHD_SDALIGN */
1927 alloc_new_pkt = TRUE;
1928 bus->tx_tailpad_pktget++;
1929 } else if (PKTTAILROOM(osh, pkt) < tail_padding + chain_tail_padding) {
1930 /* We have tail room for tail_padding of this pkt itself, but not for
1931 * total pkt chain alignment by block size.
1932 * Use the padding packet to avoid memory copy if applicable,
1933 * otherwise, just allocate a new pkt.
1936 *pad_pkt_len = chain_tail_padding;
1937 bus->tx_tailpad_chain++;
1939 alloc_new_pkt = TRUE;
1940 bus->tx_tailpad_pktget++;
1943 /* This last pkt's tailroom is sufficient to hold both tail_padding
1944 * of the pkt itself and chain_tail_padding of total pkt chain
1946 #endif /* DHDENABLE_TAILPAD */
1947 tail_padding += chain_tail_padding;
1950 DHD_INFO(("%s sdhdr len + orig_pkt_len %d h_pad %d t_pad %d pad_pkt_len %d\n",
1951 __FUNCTION__, pkt_len, head_padding, tail_padding, *pad_pkt_len));
1953 if (alloc_new_pkt) {
1958 ASSERT(*pad_pkt_len == 0);
1960 DHD_INFO(("%s allocating new packet for padding\n", __FUNCTION__));
1962 /* head pointer is aligned now, no padding needed */
1965 /* update the tail padding as it depends on the head padding, since a new packet is
1966 * allocated, the head padding is non longer needed and packet length is chagned
1969 cur_total_len = prev_chain_total_len + pkt_len;
1970 if (last_chained_pkt && bus->blocksize != 0 &&
1971 (cur_total_len > (int)bus->blocksize || prev_chain_total_len > 0)) {
1972 modulo = cur_total_len % bus->blocksize;
1973 tail_padding = modulo > 0 ? (bus->blocksize - modulo) : 0;
1976 modulo = pkt_len % DHD_SDALIGN;
1977 tail_padding = modulo > 0 ? (DHD_SDALIGN - modulo) : 0;
1980 newpkt_size = PKTLEN(osh, pkt) + bus->blocksize + DHD_SDALIGN;
1981 bus->dhd->tx_realloc++;
1982 tmp_pkt = PKTGET(osh, newpkt_size, TRUE);
1983 if (tmp_pkt == NULL) {
1984 DHD_ERROR(("failed to alloc new %d byte packet\n", newpkt_size));
1987 PKTALIGN(osh, tmp_pkt, PKTLEN(osh, pkt), DHD_SDALIGN);
1988 bcopy(PKTDATA(osh, pkt), PKTDATA(osh, tmp_pkt), PKTLEN(osh, pkt));
1994 PKTPUSH(osh, pkt, head_padding);
1996 frame = (uint8*)PKTDATA(osh, pkt);
1997 bzero(frame, head_padding + sdpcm_hdrlen);
1998 pkt_len = (uint16)PKTLEN(osh, pkt);
2000 /* the header has the followming format
2001 * 4-byte HW frame tag: length, ~length (for glom this is the total length)
2003 * 8-byte HW extesion flags (glom mode only) as the following:
2004 * 2-byte packet length, excluding HW tag and padding
2005 * 2-byte frame channel and frame flags (e.g. next frame following)
2006 * 2-byte header length
2007 * 2-byte tail padding size
2009 * 8-byte SW frame tags as the following
2010 * 4-byte flags: host tx seq, channel, data offset
2014 swhdr_offset = SDPCM_FRAMETAG_LEN;
2016 /* hardware frame tag:
2018 * in tx-glom mode, dongle only checks the hardware frame tag in the first
2019 * packet and sees it as the total lenght of the glom (including tail padding),
2020 * for each packet in the glom, the packet length needs to be updated, (see
2023 * in non tx-glom mode, PKTLEN still need to include tail padding as to be
2024 * referred to in sdioh_request_buffer(). The tail length will be excluded in
2025 * dhdsdio_txpkt_postprocess().
2027 #if defined(BCMSDIOH_TXGLOM_EXT)
2028 if (bus->dhd->conf->txglom_bucket_size)
2031 *(uint16*)frame = (uint16)htol16(pkt_len);
2032 *(((uint16*)frame) + 1) = (uint16)htol16(~pkt_len);
2033 pkt_len += tail_padding;
2035 /* hardware extesion flags */
2036 if (bus->txglom_enable) {
2039 #ifdef BCMSDIOH_TXGLOM_EXT
2040 uint32 act_len = pkt_len - tail_padding;
2041 uint32 real_pad = 0;
2042 if(bus->dhd->conf->txglom_ext && !last_chained_pkt) {
2044 if(first_frame == 0) {
2045 // first pkt, add pad to bucket size - recv offset
2046 pkt_len = bus->dhd->conf->txglom_bucket_size - TXGLOM_RECV_OFFSET;
2048 // add pad to bucket size
2049 pkt_len = bus->dhd->conf->txglom_bucket_size;
2051 swhdr_offset += SDPCM_HWEXT_LEN;
2052 hwheader1 = (act_len - SDPCM_FRAMETAG_LEN) | (last_chained_pkt << 24);
2053 hwheader2 = (pkt_len - act_len) << 16;
2054 htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN);
2055 htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4);
2056 real_pad = pkt_len - act_len;
2058 if (PKTTAILROOM(osh, pkt) < real_pad) {
2059 DHD_INFO(("%s : insufficient tailroom %d for %d real_pad\n",
2060 __func__, (int)PKTTAILROOM(osh, pkt), real_pad));
2061 if (PKTPADTAILROOM(osh, pkt, real_pad)) {
2062 DHD_ERROR(("CHK1: padding error size %d\n", real_pad));
2064 frame = (uint8 *)PKTDATA(osh, pkt);
2069 swhdr_offset += SDPCM_HWEXT_LEN;
2070 hwheader1 = (pkt_len - SDPCM_FRAMETAG_LEN - tail_padding) |
2071 (last_chained_pkt << 24);
2072 hwheader2 = (tail_padding) << 16;
2073 htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN);
2074 htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4);
2077 PKTSETLEN((osh), (pkt), (pkt_len));
2079 /* software frame tags */
2080 swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK)
2081 | (txseq % SDPCM_SEQUENCE_WRAP) |
2082 (((head_padding + sdpcm_hdrlen) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
2083 htol32_ua_store(swheader, frame + swhdr_offset);
2084 htol32_ua_store(0, frame + swhdr_offset + sizeof(swheader));
2089 static int dhdsdio_txpkt_postprocess(dhd_bus_t *bus, void *pkt)
2095 int swhdr_offset = SDPCM_FRAMETAG_LEN + (bus->txglom_enable ? SDPCM_HWEXT_LEN : 0);
2098 osh = bus->dhd->osh;
2100 /* restore pkt buffer pointer, but keeps the header pushed by dhd_prot_hdrpush */
2101 frame = (uint8*)PKTDATA(osh, pkt);
2103 DHD_INFO(("%s PKTLEN before postprocess %d",
2104 __FUNCTION__, PKTLEN(osh, pkt)));
2106 /* PKTLEN still includes tail_padding, so exclude it.
2107 * We shall have head_padding + original pkt_len for PKTLEN afterwards.
2109 if (bus->txglom_enable) {
2110 /* txglom pkts have tail_padding length in HW ext header */
2111 tail_padding = ltoh32_ua(frame + SDPCM_FRAMETAG_LEN + 4) >> 16;
2112 PKTSETLEN(osh, pkt, PKTLEN(osh, pkt) - tail_padding);
2113 DHD_INFO((" txglom pkt: tail_padding %d PKTLEN %d\n",
2114 tail_padding, PKTLEN(osh, pkt)));
2116 /* non-txglom pkts have head_padding + original pkt length in HW frame tag.
2117 * We cannot refer to this field for txglom pkts as the first pkt of the chain will
2118 * have the field for the total length of the chain.
2120 PKTSETLEN(osh, pkt, *(uint16*)frame);
2121 DHD_INFO((" non-txglom pkt: HW frame tag len %d after PKTLEN %d\n",
2122 *(uint16*)frame, PKTLEN(osh, pkt)));
2125 data_offset = ltoh32_ua(frame + swhdr_offset);
2126 data_offset = (data_offset & SDPCM_DOFFSET_MASK) >> SDPCM_DOFFSET_SHIFT;
2127 /* Get rid of sdpcm header + head_padding */
2128 PKTPULL(osh, pkt, data_offset);
2130 DHD_INFO(("%s data_offset %d, PKTLEN %d\n",
2131 __FUNCTION__, data_offset, PKTLEN(osh, pkt)));
2136 #if defined(SWTXGLOM)
2138 dhd_bcmsdh_send_swtxglom_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes,
2139 void *pkt, bcmsdh_cmplt_fn_t complete, void *handle, int max_retry)
2146 if (!KSO_ENAB(bus)) {
2147 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
2148 return BCME_NODEVICE;
2153 ret = bcmsdh_send_swtxglom_buf(bus->sdh, addr, fn, flags, buf, nbytes,
2154 pkt, complete, handle);
2157 ASSERT(ret != BCME_PENDING);
2159 if (ret == BCME_NODEVICE) {
2160 DHD_ERROR(("%s: Device asleep already\n", __FUNCTION__));
2161 } else if (ret < 0) {
2162 /* On failure, abort the command and terminate the frame */
2163 DHD_ERROR(("%s: sdio error %d, abort command and terminate frame.\n",
2164 __FUNCTION__, ret));
2167 bus->dhd->tx_errors++;
2168 bcmsdh_abort(sdh, SDIO_FUNC_2);
2169 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
2171 for (i = 0; i < READ_FRM_CNT_RETRIES; i++) {
2173 hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WFRAMEBCHI,
2175 lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WFRAMEBCLO,
2177 bus->f1regdata += 2;
2178 if ((hi == 0) && (lo == 0))
2183 #ifdef BCMSDIOH_TXGLOM
2184 if (bus->txglom_enable) {
2185 bus->tx_seq = (bus->tx_seq + bus->txglom_cnt) % SDPCM_SEQUENCE_WRAP;
2189 bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
2192 } while ((ret < 0) && retrydata && ++retries < max_retry);
2197 /* Writes a HW/SW header into the packet and sends it. */
2198 /* Assumes: (a) header space already there, (b) caller holds lock */
2200 dhdsdio_txpkt_swtxglom(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt, bool queue_only)
2205 uint16 len, pad1 = 0, act_len = 0;
2207 uint32 real_pad = 0;
2211 #ifdef BCMSDIOH_TXGLOM
2219 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2222 osh = bus->dhd->osh;
2224 #ifdef DHDTCPACK_SUPPRESS
2225 if (dhd_tcpack_check_xmit(bus->dhd, pkt) == BCME_ERROR) {
2226 DHD_ERROR(("%s %d: tcpack_suppress ERROR!!! Stop using it\n",
2227 __FUNCTION__, __LINE__));
2228 dhd_tcpack_suppress_set(bus->dhd, TCPACK_SUP_OFF);
2230 #endif /* DHDTCPACK_SUPPRESS */
2232 /* Add space for the header */
2233 PKTPUSH(osh, pkt, SDPCM_HDRLEN_TXGLOM);
2234 ASSERT(ISALIGNED((uintptr)PKTDATA(osh, pkt), 2));
2236 if (bus->dhd->dongle_reset) {
2237 ret = BCME_NOTREADY;
2241 frame = (uint8*)PKTDATA(osh, pkt);
2244 if (PKTLEN(osh, pkt) >= 100) {
2245 p = PKTDATA(osh, pkt);
2246 htsf_ts = (htsfts_t*) (p + HTSF_HOSTOFFSET + 12);
2247 if (htsf_ts->magic == HTSFMAGIC) {
2248 htsf_ts->c20 = get_cycles();
2249 htsf_ts->t20 = dhd_get_htsf(bus->dhd->info, 0);
2252 #endif /* WLMEDIA_HTSF */
2255 len = (uint16)PKTLEN(osh, pkt);
2257 case SDPCM_CONTROL_CHANNEL:
2258 tx_statics.ctrl_count++;
2259 tx_statics.ctrl_size += len;
2261 case SDPCM_DATA_CHANNEL:
2262 tx_statics.data_count++;
2263 tx_statics.data_size += len;
2265 case SDPCM_GLOM_CHANNEL:
2266 tx_statics.glom_count++;
2267 tx_statics.glom_size += len;
2269 case SDPCM_EVENT_CHANNEL:
2270 tx_statics.event_count++;
2271 tx_statics.event_size += len;
2273 case SDPCM_TEST_CHANNEL:
2274 tx_statics.test_count++;
2275 tx_statics.test_size += len;
2281 #endif /* PKT_STATICS */
2283 /* Add alignment padding, allocate new packet if needed */
2284 if ((pad1 = ((uintptr)frame % DHD_SDALIGN))) {
2285 if (PKTHEADROOM(osh, pkt) < pad1) {
2286 DHD_INFO(("%s: insufficient headroom %d for %d pad1\n",
2287 __FUNCTION__, (int)PKTHEADROOM(osh, pkt), pad1));
2288 bus->dhd->tx_realloc++;
2289 new = PKTGET(osh, (PKTLEN(osh, pkt) + DHD_SDALIGN), TRUE);
2291 DHD_ERROR(("%s: couldn't allocate new %d-byte packet\n",
2292 __FUNCTION__, PKTLEN(osh, pkt) + DHD_SDALIGN));
2297 PKTALIGN(osh, new, PKTLEN(osh, pkt), DHD_SDALIGN);
2298 bcopy(PKTDATA(osh, pkt), PKTDATA(osh, new), PKTLEN(osh, pkt));
2300 PKTFREE(osh, pkt, TRUE);
2301 /* free the pkt if canned one is not used */
2304 frame = (uint8*)PKTDATA(osh, pkt);
2305 ASSERT(((uintptr)frame % DHD_SDALIGN) == 0);
2308 PKTPUSH(osh, pkt, pad1);
2309 frame = (uint8*)PKTDATA(osh, pkt);
2311 ASSERT((pad1 + SDPCM_HDRLEN_TXGLOM) <= (int) PKTLEN(osh, pkt));
2312 bzero(frame, pad1 + SDPCM_HDRLEN_TXGLOM);
2315 ASSERT(pad1 < DHD_SDALIGN);
2317 /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
2318 len = (uint16)PKTLEN(osh, pkt);
2319 *(uint16*)frame = htol16(len);
2320 *(((uint16*)frame) + 1) = htol16(~len);
2322 #ifdef BCMSDIOH_TXGLOM
2323 if (bus->txglom_enable) {
2324 uint32 hwheader1 = 0, hwheader2 = 0;
2327 /* Software tag: channel, sequence number, data offset */
2328 swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) |
2329 ((bus->tx_seq + bus->txglom_cnt) % SDPCM_SEQUENCE_WRAP) |
2330 (((pad1 + SDPCM_HDRLEN_TXGLOM) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
2331 htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN);
2332 htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN + sizeof(swheader));
2335 if (bus->dhd->conf->txglom_ext) {
2336 if(bus->txglom_cnt == 0) {
2337 // first pkt, add pad to bucket size - recv offset
2338 len = bus->dhd->conf->txglom_bucket_size - TXGLOM_RECV_OFFSET;
2340 // add pad to bucket size
2341 len = bus->dhd->conf->txglom_bucket_size;
2344 uint8 alignment = ALIGNMENT;
2345 if (forcealign && (len & (alignment - 1)))
2346 len = ROUNDUP(len, alignment);
2348 /* Hardware extention tag */
2349 /* 2byte frame length, 1byte-, 1byte frame flag,
2350 * 2byte-hdrlength, 2byte padlenght
2352 hwheader1 = (act_len - SDPCM_FRAMETAG_LEN) | (0 << 24);
2353 hwheader2 = (len - act_len) << 16;
2354 htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN);
2355 htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4);
2356 real_pad = len - act_len;
2357 if (PKTTAILROOM(osh, pkt) < real_pad) {
2358 DHD_INFO(("%s 1: insufficient tailroom %d for %d real_pad\n",
2359 __FUNCTION__, (int)PKTTAILROOM(osh, pkt), real_pad));
2360 if (PKTPADTAILROOM(osh, pkt, real_pad)) {
2361 DHD_ERROR(("CHK1: padding error size %d\n", real_pad));
2367 PKTSETLEN(osh, pkt, act_len);
2371 PKTSETLEN(osh, pkt, len);
2372 #endif /* BCMLXSDMMC */
2373 /* Post the frame pointer to sdio glom array */
2374 bcmsdh_glom_post(bus->sdh, frame, pkt, len);
2375 /* Save the pkt pointer in bus glom array */
2376 bus->glom_pkt_arr[bus->txglom_cnt] = pkt;
2377 bus->txglom_total_len += len;
2381 /* Raise len to next SDIO block to eliminate tail command */
2382 if (bus->roundup && bus->blocksize &&
2383 ((bus->txglom_total_len + len) > bus->blocksize)) {
2384 uint16 pad2 = bus->blocksize -
2385 ((bus->txglom_total_len + len) % bus->blocksize);
2386 if ((pad2 <= bus->roundup) && (pad2 < bus->blocksize)) {
2390 } else if ((bus->txglom_total_len + len) % DHD_SDALIGN) {
2392 - ((bus->txglom_total_len + len) % DHD_SDALIGN);
2394 if (forcealign && (len & (ALIGNMENT - 1))) {
2395 len = ROUNDUP(len, ALIGNMENT);
2398 /* Hardware extention tag */
2399 /* 2byte frame length, 1byte-, 1byte frame flag,
2400 * 2byte-hdrlength, 2byte padlenght
2402 if (bus->dhd->conf->txglom_ext) {
2403 // copy way, the last packet pad2 is set to 0 it will be dropped by HW
2404 hwheader1 = (act_len - SDPCM_FRAMETAG_LEN) | (1 << 24);
2406 htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN);
2407 htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4);
2409 hwheader1 = (act_len - SDPCM_FRAMETAG_LEN) | (1 << 24);
2410 hwheader2 = (len - act_len) << 16;
2411 htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN);
2412 htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4);
2414 real_pad = len - act_len;
2415 if (PKTTAILROOM(osh, pkt) < real_pad) {
2416 DHD_INFO(("%s 2: insufficient tailroom %d"
2417 " for %d real_pad\n",
2418 __FUNCTION__, (int)PKTTAILROOM(osh, pkt), real_pad));
2419 if (PKTPADTAILROOM(osh, pkt, real_pad)) {
2420 DHD_ERROR(("CHK2: padding error size %d."
2421 " %d more pkts are discarded together.\n",
2422 real_pad, bus->txglom_cnt));
2423 /* Save the pkt pointer in bus glom array
2424 * Otherwise, this last pkt will not be
2425 * cleaned under "goto done"
2427 bus->glom_pkt_arr[bus->txglom_cnt] = pkt;
2429 bus->txglom_total_len += len;
2435 PKTSETLEN(osh, pkt, act_len);
2439 PKTSETLEN(osh, pkt, len);
2440 #endif /* BCMLXSDMMC */
2442 /* Post the frame pointer to sdio glom array */
2443 bcmsdh_glom_post(bus->sdh, frame, pkt, len);
2444 /* Save the pkt pointer in bus glom array */
2445 bus->glom_pkt_arr[bus->txglom_cnt] = pkt;
2447 if (bus->dhd->conf->txglom_ext)
2448 //copy way, the last buffer padding is not need add to len
2449 bus->txglom_total_len += act_len;
2451 bus->txglom_total_len += len;
2453 /* Update the total length on the first pkt */
2454 frame_tmp = (uint8*)PKTDATA(osh, bus->glom_pkt_arr[0]);
2455 *(uint16*)frame_tmp = htol16(bus->txglom_total_len);
2456 *(((uint16*)frame_tmp) + 1) = htol16(~bus->txglom_total_len);
2459 #endif /* BCMSDIOH_TXGLOM */
2462 /* Software tag: channel, sequence number, data offset */
2463 swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) | bus->tx_seq |
2464 (((pad1 + SDPCM_HDRLEN_TXGLOM) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
2465 htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN);
2466 htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
2469 if (PKTPRIO(pkt) < ARRAYSIZE(tx_packets)) {
2470 tx_packets[PKTPRIO(pkt)]++;
2472 if (DHD_BYTES_ON() &&
2473 (((DHD_CTL_ON() && (chan == SDPCM_CONTROL_CHANNEL)) ||
2474 (DHD_DATA_ON() && (chan != SDPCM_CONTROL_CHANNEL))))) {
2475 prhex("Tx Frame", frame, len);
2476 } else if (DHD_HDRS_ON()) {
2477 prhex("TxHdr", frame, MIN(len, 16));
2481 /* Raise len to next SDIO block to eliminate tail command */
2482 if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
2483 uint16 pad2 = bus->blocksize - (len % bus->blocksize);
2484 if ((pad2 <= bus->roundup) && (pad2 < bus->blocksize))
2486 if (pad2 <= PKTTAILROOM(osh, pkt))
2487 #endif /* NOTUSED */
2489 } else if (len % DHD_SDALIGN) {
2490 len += DHD_SDALIGN - (len % DHD_SDALIGN);
2493 /* Some controllers have trouble with odd bytes -- round to even */
2494 if (forcealign && (len & (ALIGNMENT - 1))) {
2496 if (PKTTAILROOM(osh, pkt))
2498 len = ROUNDUP(len, ALIGNMENT);
2501 DHD_ERROR(("%s: sending unrounded %d-byte packet\n", __FUNCTION__, len));
2504 real_pad = len - act_len;
2505 if (PKTTAILROOM(osh, pkt) < real_pad) {
2506 DHD_INFO(("%s 3: insufficient tailroom %d for %d real_pad\n",
2507 __FUNCTION__, (int)PKTTAILROOM(osh, pkt), real_pad));
2508 if (PKTPADTAILROOM(osh, pkt, real_pad)) {
2509 DHD_ERROR(("CHK3: padding error size %d\n", real_pad));
2515 PKTSETLEN(osh, pkt, act_len);
2519 PKTSETLEN(osh, pkt, len);
2520 #endif /* BCMLXSDMMC */
2523 if (PKTPRIO(pkt) < ARRAYSIZE(tx_packets)) {
2524 tx_packets[PKTPRIO(pkt)]++;
2527 ret = dhd_bcmsdh_send_swtxglom_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
2528 frame, len, pkt, NULL, NULL, TXRETRIES);
2532 #ifdef BCMSDIOH_TXGLOM
2533 if (bus->txglom_enable && !queue_only) {
2534 bcmsdh_glom_clear(bus->sdh);
2535 pkt_cnt = bus->txglom_cnt;
2541 /* restore pkt buffer pointer before calling tx complete routine */
2543 #ifdef BCMSDIOH_TXGLOM
2545 if (bus->txglom_enable) {
2548 #endif /* BCMLXSDMMC */
2550 pkt = bus->glom_pkt_arr[bus->txglom_cnt - pkt_cnt];
2552 frame = (uint8*)PKTDATA(osh, pkt);
2553 doff = ltoh32_ua(frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN);
2554 doff = (doff & SDPCM_DOFFSET_MASK) >> SDPCM_DOFFSET_SHIFT;
2556 pad2 = ltoh32_ua(frame + SDPCM_FRAMETAG_LEN + 4) >> 16;
2557 PKTSETLEN(osh, pkt, PKTLEN(osh, pkt) - pad2);
2558 #endif /* BCMLXSDMMC */
2559 PKTPULL(osh, pkt, doff);
2561 #endif /* BCMSDIOH_TXGLOM */
2565 PKTSETLEN(osh, pkt, act_len);
2566 #endif /* BCMLXSDMMC */
2567 PKTPULL(osh, pkt, SDPCM_HDRLEN_TXGLOM + pad1);
2569 #ifdef PROP_TXSTATUS
2570 if (bus->dhd->wlfc_state) {
2571 dhd_os_sdunlock(bus->dhd);
2572 dhd_wlfc_txcomplete(bus->dhd, pkt, ret == 0);
2573 dhd_os_sdlock(bus->dhd);
2575 #endif /* PROP_TXSTATUS */
2577 if (chan != SDPCM_TEST_CHANNEL) {
2578 dhd_txcomplete(bus->dhd, pkt, ret != 0);
2581 dhd_txcomplete(bus->dhd, pkt, ret != 0);
2584 PKTFREE(osh, pkt, TRUE);
2585 #ifdef PROP_TXSTATUS
2591 #ifdef BCMSDIOH_TXGLOM
2592 /* Reset the glom array */
2593 if (bus->txglom_enable && !queue_only) {
2594 bus->txglom_cnt = 0;
2595 bus->txglom_total_len = 0;
2602 dhdsdio_sendfromq_swtxglom(dhd_bus_t *bus, uint maxframes)
2605 uint32 intstatus = 0;
2607 int ret = 0, prec_out;
2611 uint16 txpktqlen = 0;
2612 #ifdef BCMSDIOH_TXGLOM
2617 dhd_pub_t *dhd = bus->dhd;
2618 sdpcmd_regs_t *regs = bus->regs;
2620 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2622 if (!KSO_ENAB(bus)) {
2623 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
2624 return BCME_NODEVICE;
2627 tx_prec_map = ~bus->flowcontrol;
2628 /* Send frames until the limit or some other event */
2629 for (cnt = 0; (cnt < maxframes) && DATAOK(bus); cnt++) {
2630 #ifdef BCMSDIOH_TXGLOM
2631 if (bus->txglom_enable) {
2632 void *pkttable[SDPCM_MAXGLOM_SIZE];
2633 dhd_os_sdlock_txq(bus->dhd);
2634 txglom_cnt = MIN(DATABUFCNT(bus), bus->txglomsize);
2635 txglom_cnt = MIN(txglom_cnt, pktq_mlen(&bus->txq, tx_prec_map));
2636 txglom_cnt = MIN(txglom_cnt, maxframes-cnt);
2638 /* Limiting the size to 2pkts in case of copy */
2639 if (bus->dhd->conf->txglom_ext)
2640 txglom_cnt = MIN(txglom_cnt, SDPCM_MAXGLOM_SIZE);
2642 txglom_cnt = MIN(txglom_cnt, 10);
2644 for (i = 0; i < txglom_cnt; i++)
2645 pkttable[i] = pktq_mdeq(&bus->txq, tx_prec_map, &prec_out);
2647 txpktqlen = pktq_len(&bus->txq);
2648 dhd_os_sdunlock_txq(bus->dhd);
2650 if (txglom_cnt == 0)
2656 tx_statics.glom_1_count++;
2657 else if (txglom_cnt < 3)
2658 tx_statics.glom_3_count++;
2659 else if (txglom_cnt < 8)
2660 tx_statics.glom_3_8_count++;
2662 tx_statics.glom_8_count++;
2663 if (txglom_cnt > tx_statics.glom_max)
2664 tx_statics.glom_max = txglom_cnt;
2666 for (i = 0; i < txglom_cnt; i++) {
2667 uint datalen_tmp = 0;
2669 if ((pkt = pkttable[i]) == NULL) {
2670 /* This case should not happen */
2671 DHD_ERROR(("No pkts in the queue for glomming\n"));
2675 datalen_tmp = (PKTLEN(bus->dhd->osh, pkt) - SDPCM_HDRLEN_TXGLOM);
2678 ret = dhdsdio_txpkt_swtxglom(bus,
2682 (i == (txglom_cnt-1))? FALSE: TRUE);
2684 ret = dhdsdio_txpkt_swtxglom(bus,
2686 (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL),
2688 (i == (txglom_cnt-1))? FALSE: TRUE);
2691 datalen += datalen_tmp;
2695 #endif /* BCMSDIOH_TXGLOM */
2697 dhd_os_sdlock_txq(bus->dhd);
2698 if ((pkt = pktq_mdeq(&bus->txq, tx_prec_map, &prec_out)) == NULL) {
2699 txpktqlen = pktq_len(&bus->txq);
2700 dhd_os_sdunlock_txq(bus->dhd);
2703 txpktqlen = pktq_len(&bus->txq);
2704 dhd_os_sdunlock_txq(bus->dhd);
2705 datalen = PKTLEN(bus->dhd->osh, pkt) - SDPCM_HDRLEN_TXGLOM;
2708 ret = dhdsdio_txpkt_swtxglom(bus, pkt, SDPCM_DATA_CHANNEL, TRUE, FALSE);
2710 ret = dhdsdio_txpkt_swtxglom(bus,
2712 (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL),
2719 bus->dhd->tx_errors++;
2721 bus->dhd->dstats.tx_bytes += datalen;
2723 /* In poll mode, need to check for other events */
2724 if (!bus->intr && cnt)
2726 /* Check device status, signal pending interrupt */
2727 R_SDREG(intstatus, ®s->intstatus, retries);
2729 if (bcmsdh_regfail(bus->sdh))
2731 if (intstatus & bus->hostintmask)
2736 /* Deflow-control stack if needed */
2737 if (dhd_doflow && dhd->up && (dhd->busstate == DHD_BUS_DATA) &&
2738 dhd->txoff && (txpktqlen < FCLOW))
2739 dhd_txflowcontrol(dhd, ALL_INTERFACES, OFF);
2745 static int dhdsdio_txpkt(dhd_bus_t *bus, uint chan, void** pkts, int num_pkt, bool free_pkt)
2754 void *head_pkt = NULL;
2755 void *prev_pkt = NULL;
2756 int pad_pkt_len = 0;
2757 int new_pkt_num = 0;
2758 void *new_pkts[MAX_TX_PKTCHAIN_CNT];
2759 bool wlfc_enabled = FALSE;
2761 if (bus->dhd->dongle_reset)
2762 return BCME_NOTREADY;
2765 osh = bus->dhd->osh;
2766 /* init new_pkts[0] to make some compiler happy, not necessary as we check new_pkt_num */
2769 for (i = 0; i < num_pkt; i++) {
2772 void *new_pkt = NULL;
2776 last_pkt = (i == num_pkt - 1);
2777 pkt_len = dhdsdio_txpkt_preprocess(bus, pkt, chan, bus->tx_seq + i,
2778 total_len, last_pkt, &pad_pkt_len, &new_pkt
2779 #if defined(BCMSDIOH_TXGLOM_EXT)
2787 new_pkts[new_pkt_num++] = new_pkt;
2789 total_len += pkt_len;
2791 PKTSETNEXT(osh, pkt, NULL);
2792 /* insert the packet into the list */
2793 head_pkt ? PKTSETNEXT(osh, prev_pkt, pkt) : (head_pkt = pkt);
2798 /* Update the HW frame tag (total length) in the first pkt of the glom */
2799 if (bus->txglom_enable) {
2802 total_len += pad_pkt_len;
2803 frame = (uint8*)PKTDATA(osh, head_pkt);
2804 *(uint16*)frame = (uint16)htol16(total_len);
2805 *(((uint16*)frame) + 1) = (uint16)htol16(~total_len);
2809 #ifdef DHDENABLE_TAILPAD
2810 /* if a padding packet if needed, insert it to the end of the link list */
2812 PKTSETLEN(osh, bus->pad_pkt, pad_pkt_len);
2813 PKTSETNEXT(osh, pkt, bus->pad_pkt);
2815 #endif /* DHDENABLE_TAILPAD */
2817 /* dhd_bcmsdh_send_buf ignores the buffer pointer if he packet
2818 * parameter is not NULL, for non packet chian we pass NULL pkt pointer
2819 * so it will take the aligned length and buffer pointer.
2821 pkt_chain = PKTNEXT(osh, head_pkt) ? head_pkt : NULL;
2822 #if defined(SWTXGLOM)
2823 if (bus->dhd->conf->swtxglom)
2824 ret = dhd_bcmsdh_send_swtxglom_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
2825 PKTDATA(osh, head_pkt), total_len, pkt_chain, NULL, NULL, TXRETRIES);
2828 ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
2829 PKTDATA(osh, head_pkt), total_len, pkt_chain, NULL, NULL, TXRETRIES);
2831 bus->tx_seq = (bus->tx_seq + num_pkt) % SDPCM_SEQUENCE_WRAP;
2833 /* if a padding packet was needed, remove it from the link list as it not a data pkt */
2834 if (pad_pkt_len && pkt)
2835 PKTSETNEXT(osh, pkt, NULL);
2840 void *pkt_next = PKTNEXT(osh, pkt);
2841 PKTSETNEXT(osh, pkt, NULL);
2842 dhdsdio_txpkt_postprocess(bus, pkt);
2846 /* new packets might be allocated due to insufficient room for padding, but we
2847 * still have to indicate the original packets to upper layer
2849 for (i = 0; i < num_pkt; i++) {
2851 wlfc_enabled = FALSE;
2852 #ifdef PROP_TXSTATUS
2853 if (DHD_PKTTAG_WLFCPKT(PKTTAG(pkt))) {
2854 wlfc_enabled = (dhd_wlfc_txcomplete(bus->dhd, pkt, ret == 0) !=
2857 #endif /* PROP_TXSTATUS */
2858 if (!wlfc_enabled) {
2859 PKTSETNEXT(osh, pkt, NULL);
2860 dhd_txcomplete(bus->dhd, pkt, ret != 0);
2862 PKTFREE(osh, pkt, TRUE);
2866 for (i = 0; i < new_pkt_num; i++)
2867 PKTFREE(osh, new_pkts[i], TRUE);
2873 dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes)
2877 uint16 txpktqlen = 0;
2878 uint32 intstatus = 0;
2882 dhd_pub_t *dhd = bus->dhd;
2883 sdpcmd_regs_t *regs = bus->regs;
2885 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2887 if (!KSO_ENAB(bus)) {
2888 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
2889 return BCME_NODEVICE;
2893 tx_prec_map = ~bus->flowcontrol;
2894 #ifdef DHD_LOSSLESS_ROAMING
2895 tx_prec_map &= dhd->dequeue_prec_map;
2897 for (cnt = 0; (cnt < maxframes) && DATAOK(bus);) {
2900 void *pkts[MAX_TX_PKTCHAIN_CNT];
2903 dhd_os_sdlock_txq(bus->dhd);
2904 if (bus->txglom_enable) {
2905 uint32 glomlimit = (uint32)bus->txglomsize;
2906 #if defined(BCMSDIOH_STD)
2907 if (bus->blocksize == 64) {
2908 glomlimit = MIN((uint32)bus->txglomsize, BLK_64_MAXTXGLOM);
2910 #endif /* BCMSDIOH_STD */
2911 num_pkt = MIN((uint32)DATABUFCNT(bus), glomlimit);
2912 num_pkt = MIN(num_pkt, ARRAYSIZE(pkts));
2914 num_pkt = MIN(num_pkt, pktq_mlen(&bus->txq, tx_prec_map));
2915 for (i = 0; i < num_pkt; i++) {
2916 pkts[i] = pktq_mdeq(&bus->txq, tx_prec_map, &prec_out);
2918 DHD_ERROR(("%s: pktq_mlen non-zero when no pkt\n",
2924 datalen += PKTLEN(osh, pkts[i]);
2926 dhd_os_sdunlock_txq(bus->dhd);
2930 if (dhdsdio_txpkt(bus, SDPCM_DATA_CHANNEL, pkts, i, TRUE) != BCME_OK)
2933 dhd->dstats.tx_bytes += datalen;
2934 bus->txglomframes++;
2935 bus->txglompkts += num_pkt;
2940 tx_statics.glom_1_count++;
2941 else if (num_pkt < 3)
2942 tx_statics.glom_3_count++;
2943 else if (num_pkt < 8)
2944 tx_statics.glom_3_8_count++;
2946 tx_statics.glom_8_count++;
2947 if (num_pkt > tx_statics.glom_max)
2948 tx_statics.glom_max = num_pkt;
2951 /* In poll mode, need to check for other events */
2952 if (!bus->intr && cnt)
2954 /* Check device status, signal pending interrupt */
2955 R_SDREG(intstatus, ®s->intstatus, retries);
2957 if (bcmsdh_regfail(bus->sdh))
2959 if (intstatus & bus->hostintmask)
2965 dhd_os_sdlock_txq(bus->dhd);
2966 txpktqlen = pktq_len(&bus->txq);
2967 dhd_os_sdunlock_txq(bus->dhd);
2969 /* Do flow-control if needed */
2970 if (dhd->up && (dhd->busstate == DHD_BUS_DATA) && (txpktqlen < FCLOW)) {
2971 bool wlfc_enabled = FALSE;
2972 #ifdef PROP_TXSTATUS
2973 wlfc_enabled = (dhd_wlfc_flowcontrol(dhd, OFF, TRUE) != WLFC_UNSUPPORTED);
2975 if (!wlfc_enabled && dhd_doflow && dhd->txoff) {
2976 dhd_txflowcontrol(dhd, ALL_INTERFACES, OFF);
2984 dhdsdio_sendpendctl(dhd_bus_t *bus)
2986 bcmsdh_info_t *sdh = bus->sdh;
2988 uint8* frame_seq = bus->ctrl_frame_buf + SDPCM_FRAMETAG_LEN;
2990 if (bus->txglom_enable)
2991 frame_seq += SDPCM_HWEXT_LEN;
2993 if (*frame_seq != bus->tx_seq) {
2994 DHD_INFO(("%s IOCTL frame seq lag detected!"
2995 " frm_seq:%d != bus->tx_seq:%d, corrected\n",
2996 __FUNCTION__, *frame_seq, bus->tx_seq));
2997 *frame_seq = bus->tx_seq;
3000 #if defined(SWTXGLOM)
3001 if (bus->dhd->conf->swtxglom)
3002 ret = dhd_bcmsdh_send_swtxglom_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
3003 (uint8 *)bus->ctrl_frame_buf, (uint32)bus->ctrl_frame_len,
3004 NULL, NULL, NULL, 1);
3007 ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
3008 (uint8 *)bus->ctrl_frame_buf, (uint32)bus->ctrl_frame_len,
3009 NULL, NULL, NULL, 1);
3011 bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
3013 bus->ctrl_frame_stat = FALSE;
3014 dhd_wait_event_wakeup(bus->dhd);
3018 dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen)
3020 static int err_nodevice = 0;
3024 bcmsdh_info_t *sdh = bus->sdh;
3027 uint8 sdpcm_hdrlen = bus->txglom_enable ? SDPCM_HDRLEN_TXGLOM : SDPCM_HDRLEN;
3029 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3031 if (bus->dhd->dongle_reset)
3034 /* Back the pointer to make a room for bus header */
3035 frame = msg - sdpcm_hdrlen;
3036 len = (msglen += sdpcm_hdrlen);
3038 /* Add alignment padding (optional for ctl frames) */
3040 if ((doff = ((uintptr)frame % DHD_SDALIGN))) {
3044 bzero(frame, doff + sdpcm_hdrlen);
3046 ASSERT(doff < DHD_SDALIGN);
3048 doff += sdpcm_hdrlen;
3050 /* Round send length to next SDIO block */
3051 if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
3052 uint16 pad = bus->blocksize - (len % bus->blocksize);
3053 if ((pad <= bus->roundup) && (pad < bus->blocksize))
3055 } else if (len % DHD_SDALIGN) {
3056 len += DHD_SDALIGN - (len % DHD_SDALIGN);
3059 /* Satisfy length-alignment requirements */
3060 if (forcealign && (len & (ALIGNMENT - 1)))
3061 len = ROUNDUP(len, ALIGNMENT);
3063 ASSERT(ISALIGNED((uintptr)frame, 2));
3066 /* Need to lock here to protect txseq and SDIO tx calls */
3067 dhd_os_sdlock(bus->dhd);
3071 /* Make sure backplane clock is on */
3072 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
3074 /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
3075 *(uint16*)frame = htol16((uint16)msglen);
3076 *(((uint16*)frame) + 1) = htol16(~msglen);
3078 if (bus->txglom_enable) {
3079 uint32 hwheader1, hwheader2;
3080 /* Software tag: channel, sequence number, data offset */
3081 swheader = ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK)
3083 | ((doff << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
3084 htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN);
3085 htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN
3086 + SDPCM_HWEXT_LEN + sizeof(swheader));
3088 hwheader1 = (msglen - SDPCM_FRAMETAG_LEN) | (1 << 24);
3089 hwheader2 = (len - (msglen)) << 16;
3090 htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN);
3091 htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4);
3093 *(uint16*)frame = htol16(len);
3094 *(((uint16*)frame) + 1) = htol16(~(len));
3096 /* Software tag: channel, sequence number, data offset */
3097 swheader = ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK)
3098 | bus->tx_seq | ((doff << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
3099 htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN);
3100 htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
3102 if (!TXCTLOK(bus)) {
3103 DHD_INFO(("%s: No bus credit bus->tx_max %d, bus->tx_seq %d\n",
3104 __FUNCTION__, bus->tx_max, bus->tx_seq));
3105 bus->ctrl_frame_stat = TRUE;
3107 bus->ctrl_frame_buf = frame;
3108 bus->ctrl_frame_len = len;
3110 if (!bus->dpc_sched) {
3111 bus->dpc_sched = TRUE;
3112 dhd_sched_dpc(bus->dhd);
3114 if (bus->ctrl_frame_stat) {
3115 dhd_wait_for_event(bus->dhd, &bus->ctrl_frame_stat);
3118 if (bus->ctrl_frame_stat == FALSE) {
3119 DHD_INFO(("%s: ctrl_frame_stat == FALSE\n", __FUNCTION__));
3122 bus->dhd->txcnt_timeout++;
3123 if (!bus->dhd->hang_was_sent) {
3124 #ifdef CUSTOMER_HW4_DEBUG
3125 uint32 status, retry = 0;
3126 R_SDREG(status, &bus->regs->intstatus, retry);
3127 DHD_TRACE_HW4(("%s: txcnt_timeout, INT status=0x%08X\n",
3128 __FUNCTION__, status));
3129 DHD_TRACE_HW4(("%s : tx_max : %d, tx_seq : %d, clkstate : %d \n",
3130 __FUNCTION__, bus->tx_max, bus->tx_seq, bus->clkstate));
3131 #endif /* CUSTOMER_HW4_DEBUG */
3132 DHD_ERROR(("%s: ctrl_frame_stat == TRUE txcnt_timeout=%d\n",
3133 __FUNCTION__, bus->dhd->txcnt_timeout));
3136 bus->ctrl_frame_stat = FALSE;
3141 bus->dhd->txcnt_timeout = 0;
3142 bus->ctrl_frame_stat = TRUE;
3146 if (DHD_BYTES_ON() && DHD_CTL_ON()) {
3147 prhex("Tx Frame", frame, len);
3148 } else if (DHD_HDRS_ON()) {
3149 prhex("TxHdr", frame, MIN(len, 16));
3153 tx_statics.ctrl_count++;
3154 tx_statics.ctrl_size += len;
3156 #if defined(SWTXGLOM)
3157 if (bus->dhd->conf->swtxglom)
3158 ret = dhd_bcmsdh_send_swtxglom_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
3159 frame, len, NULL, NULL, NULL, TXRETRIES);
3162 ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
3163 frame, len, NULL, NULL, NULL, TXRETRIES);
3165 bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
3167 bus->ctrl_frame_stat = FALSE;
3170 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
3171 bus->activity = FALSE;
3172 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
3175 dhd_os_sdunlock(bus->dhd);
3178 bus->dhd->tx_ctlerrs++;
3180 bus->dhd->tx_ctlpkts++;
3182 if (bus->dhd->txcnt_timeout >= MAX_CNTL_TX_TIMEOUT)
3185 if (ret == BCME_NODEVICE)
3190 return ret ? err_nodevice >= ERROR_BCME_NODEVICE_MAX ? -ETIMEDOUT : -EIO : 0;
3194 dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen)
3199 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3201 if (bus->dhd->dongle_reset)
3204 /* Wait until control frame is available */
3205 timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->rxlen);
3207 dhd_os_sdlock(bus->dhd);
3209 bcopy(bus->rxctl, msg, MIN(msglen, rxlen));
3211 dhd_os_sdunlock(bus->dhd);
3214 DHD_CTL(("%s: resumed on rxctl frame, got %d expected %d\n",
3215 __FUNCTION__, rxlen, msglen));
3216 } else if (timeleft == 0) {
3218 uint32 status, retry = 0;
3219 R_SDREG(status, &bus->regs->intstatus, retry);
3220 DHD_ERROR(("%s: resumed on timeout, INT status=0x%08X\n",
3221 __FUNCTION__, status));
3223 DHD_ERROR(("%s: resumed on timeout\n", __FUNCTION__));
3224 #endif /* DHD_DEBUG */
3225 dhd_os_sdlock(bus->dhd);
3226 dhdsdio_checkdied(bus, NULL, 0);
3227 dhd_os_sdunlock(bus->dhd);
3229 DHD_CTL(("%s: resumed for unknown reason?\n", __FUNCTION__));
3230 dhd_os_sdlock(bus->dhd);
3231 dhdsdio_checkdied(bus, NULL, 0);
3232 dhd_os_sdunlock(bus->dhd);
3234 if (timeleft == 0) {
3236 bus->dhd->rxcnt_timeout++;
3237 DHD_ERROR(("%s: rxcnt_timeout=%d, rxlen=%d\n", __FUNCTION__,
3238 bus->dhd->rxcnt_timeout, rxlen));
3241 bus->dhd->rxcnt_timeout = 0;
3244 bus->dhd->rx_ctlpkts++;
3246 bus->dhd->rx_ctlerrs++;
3248 if (bus->dhd->rxcnt_timeout >= MAX_CNTL_RX_TIMEOUT)
3251 if (bus->dhd->dongle_trap_occured)
3254 return rxlen ? (int)rxlen : -EIO;
3270 #endif /* DHD_DEBUG */
3271 IOV_SET_DOWNLOAD_STATE,
3281 #if defined(USE_SDIOFIFO_IOVAR)
3284 #endif /* USE_SDIOFIFO_IOVAR */
3297 IOV_DONGLEISOLATION,
3311 const bcm_iovar_t dhdsdio_iovars[] = {
3312 {"intr", IOV_INTR, 0, IOVT_BOOL, 0 },
3313 {"sleep", IOV_SLEEP, 0, IOVT_BOOL, 0 },
3314 {"pollrate", IOV_POLLRATE, 0, IOVT_UINT32, 0 },
3315 {"idletime", IOV_IDLETIME, 0, IOVT_INT32, 0 },
3316 {"idleclock", IOV_IDLECLOCK, 0, IOVT_INT32, 0 },
3317 {"sd1idle", IOV_SD1IDLE, 0, IOVT_BOOL, 0 },
3318 {"membytes", IOV_MEMBYTES, 0, IOVT_BUFFER, 2 * sizeof(int) },
3319 {"ramsize", IOV_RAMSIZE, 0, IOVT_UINT32, 0 },
3320 {"ramstart", IOV_RAMSTART, 0, IOVT_UINT32, 0 },
3321 {"dwnldstate", IOV_SET_DOWNLOAD_STATE, 0, IOVT_BOOL, 0 },
3322 {"socram_state", IOV_SOCRAM_STATE, 0, IOVT_BOOL, 0 },
3323 {"vars", IOV_VARS, 0, IOVT_BUFFER, 0 },
3324 {"sdiod_drive", IOV_SDIOD_DRIVE, 0, IOVT_UINT32, 0 },
3325 {"readahead", IOV_READAHEAD, 0, IOVT_BOOL, 0 },
3326 {"sdrxchain", IOV_SDRXCHAIN, 0, IOVT_BOOL, 0 },
3327 {"alignctl", IOV_ALIGNCTL, 0, IOVT_BOOL, 0 },
3328 {"sdalign", IOV_SDALIGN, 0, IOVT_BOOL, 0 },
3329 {"devreset", IOV_DEVRESET, 0, IOVT_BOOL, 0 },
3331 {"sdreg", IOV_SDREG, 0, IOVT_BUFFER, sizeof(sdreg_t) },
3332 {"sbreg", IOV_SBREG, 0, IOVT_BUFFER, sizeof(sdreg_t) },
3333 {"sd_cis", IOV_SDCIS, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN },
3334 {"forcealign", IOV_FORCEEVEN, 0, IOVT_BOOL, 0 },
3335 {"txbound", IOV_TXBOUND, 0, IOVT_UINT32, 0 },
3336 {"rxbound", IOV_RXBOUND, 0, IOVT_UINT32, 0 },
3337 {"txminmax", IOV_TXMINMAX, 0, IOVT_UINT32, 0 },
3338 {"cpu", IOV_CPU, 0, IOVT_BOOL, 0 },
3340 {"checkdied", IOV_CHECKDIED, 0, IOVT_BUFFER, 0 },
3341 {"serial", IOV_SERIALCONS, 0, IOVT_UINT32, 0 },
3342 #endif /* DHD_DEBUG */
3343 #endif /* DHD_DEBUG */
3345 {"extloop", IOV_EXTLOOP, 0, IOVT_BOOL, 0 },
3346 {"pktgen", IOV_PKTGEN, 0, IOVT_BUFFER, sizeof(dhd_pktgen_t) },
3348 #if defined(USE_SDIOFIFO_IOVAR)
3349 {"watermark", IOV_WATERMARK, 0, IOVT_UINT32, 0 },
3350 {"mesbusyctrl", IOV_MESBUSYCTRL, 0, IOVT_UINT32, 0 },
3351 #endif /* USE_SDIOFIFO_IOVAR */
3352 {"devcap", IOV_DEVCAP, 0, IOVT_UINT32, 0 },
3353 {"dngl_isolation", IOV_DONGLEISOLATION, 0, IOVT_UINT32, 0 },
3354 {"kso", IOV_KSO, 0, IOVT_UINT32, 0 },
3355 {"devsleep", IOV_DEVSLEEP, 0, IOVT_UINT32, 0 },
3357 {"fwpath", IOV_FWPATH, 0, IOVT_BUFFER, 0 },
3359 {"txglomsize", IOV_TXGLOMSIZE, 0, IOVT_UINT32, 0 },
3360 {"fw_hang_report", IOV_HANGREPORT, 0, IOVT_BOOL, 0 },
3361 {"txinrx_thres", IOV_TXINRX_THRES, 0, IOVT_INT32, 0 },
3366 dhd_dump_pct(struct bcmstrbuf *strbuf, char *desc, uint num, uint div)
3371 bcm_bprintf(strbuf, "%s N/A", desc);
3374 q2 = (100 * (num - (q1 * div))) / div;
3375 bcm_bprintf(strbuf, "%s %d.%02d", desc, q1, q2);
3380 dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf)
3382 dhd_bus_t *bus = dhdp->bus;
3384 bcm_bprintf(strbuf, "Bus SDIO structure:\n");
3385 bcm_bprintf(strbuf, "hostintmask 0x%08x intstatus 0x%08x sdpcm_ver %d\n",
3386 bus->hostintmask, bus->intstatus, bus->sdpcm_ver);
3387 bcm_bprintf(strbuf, "fcstate %d qlen %u tx_seq %d, max %d, rxskip %d rxlen %u rx_seq %d\n",
3388 bus->fcstate, pktq_len(&bus->txq), bus->tx_seq, bus->tx_max, bus->rxskip,
3389 bus->rxlen, bus->rx_seq);
3390 bcm_bprintf(strbuf, "intr %d intrcount %u lastintrs %u spurious %u\n",
3391 bus->intr, bus->intrcount, bus->lastintrs, bus->spurious);
3392 bcm_bprintf(strbuf, "pollrate %u pollcnt %u regfails %u\n",
3393 bus->pollrate, bus->pollcnt, bus->regfails);
3395 bcm_bprintf(strbuf, "\nAdditional counters:\n");
3396 #ifdef DHDENABLE_TAILPAD
3397 bcm_bprintf(strbuf, "tx_tailpad_chain %u tx_tailpad_pktget %u\n",
3398 bus->tx_tailpad_chain, bus->tx_tailpad_pktget);
3399 #endif /* DHDENABLE_TAILPAD */
3400 bcm_bprintf(strbuf, "tx_sderrs %u fcqueued %u rxrtx %u rx_toolong %u rxc_errors %u\n",
3401 bus->tx_sderrs, bus->fcqueued, bus->rxrtx, bus->rx_toolong,
3403 bcm_bprintf(strbuf, "rx_hdrfail %u badhdr %u badseq %u\n",
3404 bus->rx_hdrfail, bus->rx_badhdr, bus->rx_badseq);
3405 bcm_bprintf(strbuf, "fc_rcvd %u, fc_xoff %u, fc_xon %u\n",
3406 bus->fc_rcvd, bus->fc_xoff, bus->fc_xon);
3407 bcm_bprintf(strbuf, "rxglomfail %u, rxglomframes %u, rxglompkts %u\n",
3408 bus->rxglomfail, bus->rxglomframes, bus->rxglompkts);
3409 bcm_bprintf(strbuf, "f2rx (hdrs/data) %u (%u/%u), f2tx %u f1regs %u\n",
3410 (bus->f2rxhdrs + bus->f2rxdata), bus->f2rxhdrs, bus->f2rxdata,
3411 bus->f2txdata, bus->f1regdata);
3413 dhd_dump_pct(strbuf, "\nRx: pkts/f2rd", bus->dhd->rx_packets,
3414 (bus->f2rxhdrs + bus->f2rxdata));
3415 dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->rx_packets, bus->f1regdata);
3416 dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->rx_packets,
3417 (bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata));
3418 dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->rx_packets, bus->intrcount);
3419 bcm_bprintf(strbuf, "\n");
3421 dhd_dump_pct(strbuf, "Rx: glom pct", (100 * bus->rxglompkts),
3422 bus->dhd->rx_packets);
3423 dhd_dump_pct(strbuf, ", pkts/glom", bus->rxglompkts, bus->rxglomframes);
3424 bcm_bprintf(strbuf, "\n");
3426 dhd_dump_pct(strbuf, "Tx: pkts/f2wr", bus->dhd->tx_packets, bus->f2txdata);
3427 dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->tx_packets, bus->f1regdata);
3428 dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->tx_packets,
3429 (bus->f2txdata + bus->f1regdata));
3430 dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->tx_packets, bus->intrcount);
3431 bcm_bprintf(strbuf, "\n");
3433 dhd_dump_pct(strbuf, "Total: pkts/f2rw",
3434 (bus->dhd->tx_packets + bus->dhd->rx_packets),
3435 (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata));
3436 dhd_dump_pct(strbuf, ", pkts/f1sd",
3437 (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->f1regdata);
3438 dhd_dump_pct(strbuf, ", pkts/sd",
3439 (bus->dhd->tx_packets + bus->dhd->rx_packets),
3440 (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata));
3441 dhd_dump_pct(strbuf, ", pkts/int",
3442 (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->intrcount);
3443 bcm_bprintf(strbuf, "\n\n");
3447 if (bus->pktgen_count) {
3448 bcm_bprintf(strbuf, "pktgen config and count:\n");
3449 bcm_bprintf(strbuf, "freq %u count %u print %u total %u min %u len %u\n",
3450 bus->pktgen_freq, bus->pktgen_count, bus->pktgen_print,
3451 bus->pktgen_total, bus->pktgen_minlen, bus->pktgen_maxlen);
3452 bcm_bprintf(strbuf, "send attempts %u rcvd %u fail %u\n",
3453 bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail);
3457 bcm_bprintf(strbuf, "dpc_sched %d host interrupt%spending\n",
3458 bus->dpc_sched, (bcmsdh_intr_pending(bus->sdh) ? " " : " not "));
3459 bcm_bprintf(strbuf, "blocksize %u roundup %u\n", bus->blocksize, bus->roundup);
3460 #endif /* DHD_DEBUG */
3461 bcm_bprintf(strbuf, "clkstate %d activity %d idletime %d idlecount %d sleeping %d\n",
3462 bus->clkstate, bus->activity, bus->idletime, bus->idlecount, bus->sleeping);
3463 dhd_dump_pct(strbuf, "Tx: glom pct", (100 * bus->txglompkts), bus->dhd->tx_packets);
3464 dhd_dump_pct(strbuf, ", pkts/glom", bus->txglompkts, bus->txglomframes);
3465 bcm_bprintf(strbuf, "\n");
3466 bcm_bprintf(strbuf, "txglomframes %u, txglompkts %u\n", bus->txglomframes, bus->txglompkts);
3467 bcm_bprintf(strbuf, "\n");
3471 dhd_bus_clearcounts(dhd_pub_t *dhdp)
3473 dhd_bus_t *bus = (dhd_bus_t *)dhdp->bus;
3475 bus->intrcount = bus->lastintrs = bus->spurious = bus->regfails = 0;
3476 bus->rxrtx = bus->rx_toolong = bus->rxc_errors = 0;
3477 bus->rx_hdrfail = bus->rx_badhdr = bus->rx_badseq = 0;
3478 #ifdef DHDENABLE_TAILPAD
3479 bus->tx_tailpad_chain = bus->tx_tailpad_pktget = 0;
3480 #endif /* DHDENABLE_TAILPAD */
3481 bus->tx_sderrs = bus->fc_rcvd = bus->fc_xoff = bus->fc_xon = 0;
3482 bus->rxglomfail = bus->rxglomframes = bus->rxglompkts = 0;
3483 bus->f2rxhdrs = bus->f2rxdata = bus->f2txdata = bus->f1regdata = 0;
3484 bus->txglomframes = bus->txglompkts = 0;
3489 dhdsdio_pktgen_get(dhd_bus_t *bus, uint8 *arg)
3491 dhd_pktgen_t pktgen;
3493 pktgen.version = DHD_PKTGEN_VERSION;
3494 pktgen.freq = bus->pktgen_freq;
3495 pktgen.count = bus->pktgen_count;
3496 pktgen.print = bus->pktgen_print;
3497 pktgen.total = bus->pktgen_total;
3498 pktgen.minlen = bus->pktgen_minlen;
3499 pktgen.maxlen = bus->pktgen_maxlen;
3500 pktgen.numsent = bus->pktgen_sent;
3501 pktgen.numrcvd = bus->pktgen_rcvd;
3502 pktgen.numfail = bus->pktgen_fail;
3503 pktgen.mode = bus->pktgen_mode;
3504 pktgen.stop = bus->pktgen_stop;
3506 bcopy(&pktgen, arg, sizeof(pktgen));
3512 dhdsdio_pktgen_set(dhd_bus_t *bus, uint8 *arg)
3514 dhd_pktgen_t pktgen;
3515 uint oldcnt, oldmode;
3517 bcopy(arg, &pktgen, sizeof(pktgen));
3518 if (pktgen.version != DHD_PKTGEN_VERSION)
3521 oldcnt = bus->pktgen_count;
3522 oldmode = bus->pktgen_mode;
3524 bus->pktgen_freq = pktgen.freq;
3525 bus->pktgen_count = pktgen.count;
3526 bus->pktgen_print = pktgen.print;
3527 bus->pktgen_total = pktgen.total;
3528 bus->pktgen_minlen = pktgen.minlen;
3529 bus->pktgen_maxlen = pktgen.maxlen;
3530 bus->pktgen_mode = pktgen.mode;
3531 bus->pktgen_stop = pktgen.stop;
3533 bus->pktgen_tick = bus->pktgen_ptick = 0;
3534 bus->pktgen_prev_time = jiffies;
3535 bus->pktgen_len = MAX(bus->pktgen_len, bus->pktgen_minlen);
3536 bus->pktgen_len = MIN(bus->pktgen_len, bus->pktgen_maxlen);
3538 /* Clear counts for a new pktgen (mode change, or was stopped) */
3539 if (bus->pktgen_count && (!oldcnt || oldmode != bus->pktgen_mode)) {
3540 bus->pktgen_sent = bus->pktgen_prev_sent = bus->pktgen_rcvd = 0;
3541 bus->pktgen_prev_rcvd = bus->pktgen_fail = 0;
3549 dhdsdio_devram_remap(dhd_bus_t *bus, bool val)
3551 uint8 enable, protect, remap;
3553 si_socdevram(bus->sih, FALSE, &enable, &protect, &remap);
3554 remap = val ? TRUE : FALSE;
3555 si_socdevram(bus->sih, TRUE, &enable, &protect, &remap);
3559 dhdsdio_membytes(dhd_bus_t *bus, bool write, uint32 address, uint8 *data, uint size)
3565 /* In remap mode, adjust address beyond socram and redirect
3566 * to devram at SOCDEVRAM_BP_ADDR since remap address > orig_ramsize
3567 * is not backplane accessible
3569 if (REMAP_ENAB(bus) && REMAP_ISADDR(bus, address)) {
3570 address -= bus->orig_ramsize;
3571 address += SOCDEVRAM_BP_ADDR;
3574 /* Determine initial transfer parameters */
3575 sdaddr = address & SBSDIO_SB_OFT_ADDR_MASK;
3576 if ((sdaddr + size) & SBSDIO_SBWINDOW_MASK)
3577 dsize = (SBSDIO_SB_OFT_ADDR_LIMIT - sdaddr);
3581 /* Set the backplane window to include the start address */
3582 if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) {
3583 DHD_ERROR(("%s: window change failed\n", __FUNCTION__));
3587 /* Do the transfer(s) */
3589 DHD_INFO(("%s: %s %d bytes at offset 0x%08x in window 0x%08x\n",
3590 __FUNCTION__, (write ? "write" : "read"), dsize, sdaddr,
3591 (address & SBSDIO_SBWINDOW_MASK)));
3592 if ((bcmerror = bcmsdh_rwdata(bus->sdh, write, sdaddr, data, dsize))) {
3593 DHD_ERROR(("%s: membytes transfer failed\n", __FUNCTION__));
3597 /* Adjust for next transfer (if any) */
3598 if ((size -= dsize)) {
3601 if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) {
3602 DHD_ERROR(("%s: window change failed\n", __FUNCTION__));
3606 dsize = MIN(SBSDIO_SB_OFT_ADDR_LIMIT, size);
3612 /* Return the window to backplane enumeration space for core access */
3613 if (dhdsdio_set_siaddr_window(bus, bcmsdh_cur_sbwad(bus->sdh))) {
3614 DHD_ERROR(("%s: FAILED to set window back to 0x%x\n", __FUNCTION__,
3615 bcmsdh_cur_sbwad(bus->sdh)));
3622 dhdsdio_readshared(dhd_bus_t *bus, sdpcm_shared_t *sh)
3628 if (bus->sih == NULL) {
3629 if (bus->dhd && bus->dhd->dongle_reset) {
3630 DHD_ERROR(("%s: Dongle is in reset state\n", __FUNCTION__));
3631 return BCME_NOTREADY;
3635 DHD_ERROR(("%s: The address of sih is invalid\n", __FUNCTION__));
3639 if (CHIPID(bus->sih->chip) == BCM43430_CHIP_ID && !dhdsdio_sr_cap(bus))
3642 shaddr = bus->dongle_ram_base + bus->ramsize - 4;
3645 /* Read last word in memory to determine address of sdpcm_shared structure */
3646 if ((rv = dhdsdio_membytes(bus, FALSE, shaddr, (uint8 *)&addr, 4)) < 0)
3649 addr = ltoh32(addr);
3651 DHD_INFO(("sdpcm_shared address 0x%08X\n", addr));
3654 * Check if addr is valid.
3655 * NVRAM length at the end of memory should have been overwritten.
3657 if (addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff)) {
3658 if ((bus->srmemsize > 0) && (i++ == 0)) {
3659 shaddr -= bus->srmemsize;
3661 DHD_ERROR(("%s: address (0x%08x) of sdpcm_shared invalid\n",
3662 __FUNCTION__, addr));
3669 /* Read hndrte_shared structure */
3670 if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)sh, sizeof(sdpcm_shared_t))) < 0)
3674 sh->flags = ltoh32(sh->flags);
3675 sh->trap_addr = ltoh32(sh->trap_addr);
3676 sh->assert_exp_addr = ltoh32(sh->assert_exp_addr);
3677 sh->assert_file_addr = ltoh32(sh->assert_file_addr);
3678 sh->assert_line = ltoh32(sh->assert_line);
3679 sh->console_addr = ltoh32(sh->console_addr);
3680 sh->msgtrace_addr = ltoh32(sh->msgtrace_addr);
3682 if ((sh->flags & SDPCM_SHARED_VERSION_MASK) == 3 && SDPCM_SHARED_VERSION == 1)
3685 if ((sh->flags & SDPCM_SHARED_VERSION_MASK) != SDPCM_SHARED_VERSION) {
3686 DHD_ERROR(("%s: sdpcm_shared version %d in dhd "
3687 "is different than sdpcm_shared version %d in dongle\n",
3688 __FUNCTION__, SDPCM_SHARED_VERSION,
3689 sh->flags & SDPCM_SHARED_VERSION_MASK));
3696 #define CONSOLE_LINE_MAX 192
3700 dhdsdio_readconsole(dhd_bus_t *bus)
3702 dhd_console_t *c = &bus->console;
3703 uint8 line[CONSOLE_LINE_MAX], ch;
3704 uint32 n, idx, addr;
3707 /* Don't do anything until FWREADY updates console address */
3708 if (bus->console_addr == 0)
3714 /* Read console log struct */
3715 addr = bus->console_addr + OFFSETOF(hnd_cons_t, log);
3716 if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)&c->log, sizeof(c->log))) < 0)
3719 /* Allocate console buffer (one time only) */
3720 if (c->buf == NULL) {
3721 c->bufsize = ltoh32(c->log.buf_size);
3722 if ((c->buf = MALLOC(bus->dhd->osh, c->bufsize)) == NULL)
3726 idx = ltoh32(c->log.idx);
3728 /* Protect against corrupt value */
3729 if (idx > c->bufsize)
3732 /* Skip reading the console buffer if the index pointer has not moved */
3736 /* Read the console buffer */
3737 addr = ltoh32(c->log.buf);
3738 if ((rv = dhdsdio_membytes(bus, FALSE, addr, c->buf, c->bufsize)) < 0)
3741 while (c->last != idx) {
3742 for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) {
3743 if (c->last == idx) {
3744 /* This would output a partial line. Instead, back up
3745 * the buffer pointer and output this line next time around.
3750 c->last = c->bufsize - n;
3753 ch = c->buf[c->last];
3754 c->last = (c->last + 1) % c->bufsize;
3761 if (line[n - 1] == '\r')
3764 printf("CONSOLE: %s\n", line);
3765 #ifdef LOG_INTO_TCPDUMP
3766 dhd_sendup_log(bus->dhd, line, n);
3767 #endif /* LOG_INTO_TCPDUMP */
3774 #endif /* DHD_DEBUG */
3777 dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size)
3781 char *mbuffer = NULL;
3782 char *console_buffer = NULL;
3783 uint maxstrlen = 256;
3786 sdpcm_shared_t sdpcm_shared;
3787 struct bcmstrbuf strbuf;
3788 uint32 console_ptr, console_size, console_index;
3789 uint8 line[CONSOLE_LINE_MAX], ch;
3793 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3795 if (DHD_NOCHECKDIED_ON())
3800 * Called after a rx ctrl timeout. "data" is NULL.
3801 * allocate memory to trace the trap or assert.
3804 mbuffer = data = MALLOC(bus->dhd->osh, msize);
3805 if (mbuffer == NULL) {
3806 DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, msize));
3807 bcmerror = BCME_NOMEM;
3812 if ((str = MALLOC(bus->dhd->osh, maxstrlen)) == NULL) {
3813 DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, maxstrlen));
3814 bcmerror = BCME_NOMEM;
3818 if ((bcmerror = dhdsdio_readshared(bus, &sdpcm_shared)) < 0)
3821 bcm_binit(&strbuf, data, size);
3823 bcm_bprintf(&strbuf, "msgtrace address : 0x%08X\nconsole address : 0x%08X\n",
3824 sdpcm_shared.msgtrace_addr, sdpcm_shared.console_addr);
3826 if ((sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT) == 0) {
3827 /* NOTE: Misspelled assert is intentional - DO NOT FIX.
3828 * (Avoids conflict with real asserts for programmatic parsing of output.)
3830 bcm_bprintf(&strbuf, "Assrt not built in dongle\n");
3833 if ((sdpcm_shared.flags & (SDPCM_SHARED_ASSERT|SDPCM_SHARED_TRAP)) == 0) {
3834 /* NOTE: Misspelled assert is intentional - DO NOT FIX.
3835 * (Avoids conflict with real asserts for programmatic parsing of output.)
3837 bcm_bprintf(&strbuf, "No trap%s in dongle",
3838 (sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT)
3841 if (sdpcm_shared.flags & SDPCM_SHARED_ASSERT) {
3842 /* Download assert */
3843 bcm_bprintf(&strbuf, "Dongle assert");
3844 if (sdpcm_shared.assert_exp_addr != 0) {
3846 if ((bcmerror = dhdsdio_membytes(bus, FALSE,
3847 sdpcm_shared.assert_exp_addr,
3848 (uint8 *)str, maxstrlen)) < 0)
3851 str[maxstrlen - 1] = '\0';
3852 bcm_bprintf(&strbuf, " expr \"%s\"", str);
3855 if (sdpcm_shared.assert_file_addr != 0) {
3857 if ((bcmerror = dhdsdio_membytes(bus, FALSE,
3858 sdpcm_shared.assert_file_addr,
3859 (uint8 *)str, maxstrlen)) < 0)
3862 str[maxstrlen - 1] = '\0';
3863 bcm_bprintf(&strbuf, " file \"%s\"", str);
3866 bcm_bprintf(&strbuf, " line %d ", sdpcm_shared.assert_line);
3869 if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) {
3870 bus->dhd->dongle_trap_occured = TRUE;
3871 if ((bcmerror = dhdsdio_membytes(bus, FALSE,
3872 sdpcm_shared.trap_addr,
3873 (uint8*)&tr, sizeof(trap_t))) < 0)
3876 bcm_bprintf(&strbuf,
3877 "Dongle trap type 0x%x @ epc 0x%x, cpsr 0x%x, spsr 0x%x, sp 0x%x,"
3878 "lp 0x%x, rpc 0x%x Trap offset 0x%x, "
3879 "r0 0x%x, r1 0x%x, r2 0x%x, r3 0x%x, "
3880 "r4 0x%x, r5 0x%x, r6 0x%x, r7 0x%x\n\n",
3881 ltoh32(tr.type), ltoh32(tr.epc), ltoh32(tr.cpsr), ltoh32(tr.spsr),
3882 ltoh32(tr.r13), ltoh32(tr.r14), ltoh32(tr.pc),
3883 ltoh32(sdpcm_shared.trap_addr),
3884 ltoh32(tr.r0), ltoh32(tr.r1), ltoh32(tr.r2), ltoh32(tr.r3),
3885 ltoh32(tr.r4), ltoh32(tr.r5), ltoh32(tr.r6), ltoh32(tr.r7));
3887 addr = sdpcm_shared.console_addr + OFFSETOF(hnd_cons_t, log);
3888 if ((rv = dhdsdio_membytes(bus, FALSE, addr,
3889 (uint8 *)&console_ptr, sizeof(console_ptr))) < 0)
3892 addr = sdpcm_shared.console_addr + OFFSETOF(hnd_cons_t, log.buf_size);
3893 if ((rv = dhdsdio_membytes(bus, FALSE, addr,
3894 (uint8 *)&console_size, sizeof(console_size))) < 0)
3897 addr = sdpcm_shared.console_addr + OFFSETOF(hnd_cons_t, log.idx);
3898 if ((rv = dhdsdio_membytes(bus, FALSE, addr,
3899 (uint8 *)&console_index, sizeof(console_index))) < 0)
3902 console_ptr = ltoh32(console_ptr);
3903 console_size = ltoh32(console_size);
3904 console_index = ltoh32(console_index);
3906 if (console_size > CONSOLE_BUFFER_MAX ||
3907 !(console_buffer = MALLOC(bus->dhd->osh, console_size)))
3910 if ((rv = dhdsdio_membytes(bus, FALSE, console_ptr,
3911 (uint8 *)console_buffer, console_size)) < 0)
3914 for (i = 0, n = 0; i < console_size; i += n + 1) {
3915 for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) {
3916 ch = console_buffer[(console_index + i + n) % console_size];
3924 if (line[n - 1] == '\r')
3927 /* Don't use DHD_ERROR macro since we print
3928 * a lot of information quickly. The macro
3929 * will truncate a lot of the printfs
3932 if (dhd_msg_level & DHD_ERROR_VAL)
3933 printf("CONSOLE: %s\n", line);
3940 if (sdpcm_shared.flags & (SDPCM_SHARED_ASSERT | SDPCM_SHARED_TRAP)) {
3941 DHD_ERROR(("%s: %s\n", __FUNCTION__, strbuf.origbuf));
3944 #if defined(DHD_FW_COREDUMP)
3945 if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) {
3946 /* Mem dump to a file on device */
3947 dhdsdio_mem_dump(bus);
3949 #endif /* #if defined(DHD_FW_COREDUMP) */
3953 MFREE(bus->dhd->osh, mbuffer, msize);
3955 MFREE(bus->dhd->osh, str, maxstrlen);
3957 MFREE(bus->dhd->osh, console_buffer, console_size);
3962 #if defined(DHD_FW_COREDUMP)
3964 dhdsdio_mem_dump(dhd_bus_t *bus)
3967 int size; /* Full mem size */
3968 int start = bus->dongle_ram_base; /* Start address */
3969 int read_size = 0; /* Read size of each iteration */
3970 uint8 *buf = NULL, *databuf = NULL;
3972 /* Get full mem size */
3973 size = bus->ramsize;
3974 buf = MALLOC(bus->dhd->osh, size);
3976 printf("%s: Out of memory (%d bytes)\n", __FUNCTION__, size);
3980 /* Read mem content */
3981 printf("Dump dongle memory");
3985 read_size = MIN(MEMBLOCK, size);
3986 if ((ret = dhdsdio_membytes(bus, FALSE, start, databuf, read_size)))
3988 printf("%s: Error membytes %d\n", __FUNCTION__, ret);
3990 MFREE(bus->dhd->osh, buf, size);
3994 /* Decrement size and increment start address */
3997 databuf += read_size;
4001 dhd_save_fwdump(bus->dhd, buf, bus->ramsize);
4002 /* free buf before return !!! */
4003 if (write_to_file(bus->dhd, buf, bus->ramsize))
4005 printf("%s: Error writing to files\n", __FUNCTION__);
4009 /* buf free handled in write_to_file, not here */
4012 #endif /* DHD_FW_COREDUMP */
4015 dhd_socram_dump(dhd_bus_t * bus)
4017 #if defined(DHD_FW_COREDUMP)
4018 return (dhdsdio_mem_dump(bus));
4025 dhdsdio_downloadvars(dhd_bus_t *bus, void *arg, int len)
4027 int bcmerror = BCME_OK;
4029 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4031 /* Basic sanity checks */
4033 bcmerror = BCME_NOTDOWN;
4037 bcmerror = BCME_BUFTOOSHORT;
4041 /* Free the old ones and replace with passed variables */
4043 MFREE(bus->dhd->osh, bus->vars, bus->varsz);
4045 bus->vars = MALLOC(bus->dhd->osh, len);
4046 bus->varsz = bus->vars ? len : 0;
4047 if (bus->vars == NULL) {
4048 bcmerror = BCME_NOMEM;
4052 /* Copy the passed variables, which should include the terminating double-null */
4053 bcopy(arg, bus->vars, bus->varsz);
4060 #define CC_PLL_CHIPCTRL_SERIAL_ENAB (1 << 24)
4061 #define CC_CHIPCTRL_JTAG_SEL (1 << 3)
4062 #define CC_CHIPCTRL_GPIO_SEL (0x3)
4063 #define CC_PLL_CHIPCTRL_SERIAL_ENAB_4334 (1 << 28)
4066 dhd_serialconsole(dhd_bus_t *bus, bool set, bool enable, int *bcmerror)
4069 uint32 addr, data, uart_enab = 0;
4070 uint32 jtag_sel = CC_CHIPCTRL_JTAG_SEL;
4071 uint32 gpio_sel = CC_CHIPCTRL_GPIO_SEL;
4073 addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr);
4074 data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data);
4077 bcmsdh_reg_write(bus->sdh, addr, 4, 1);
4078 if (bcmsdh_regfail(bus->sdh)) {
4079 *bcmerror = BCME_SDIO_ERROR;
4082 int_val = bcmsdh_reg_read(bus->sdh, data, 4);
4083 if (bcmsdh_regfail(bus->sdh)) {
4084 *bcmerror = BCME_SDIO_ERROR;
4087 if (bus->sih->chip == BCM4330_CHIP_ID) {
4088 uart_enab = CC_PLL_CHIPCTRL_SERIAL_ENAB;
4090 else if (bus->sih->chip == BCM4334_CHIP_ID ||
4091 bus->sih->chip == BCM43340_CHIP_ID ||
4092 bus->sih->chip == BCM43341_CHIP_ID ||
4093 bus->sih->chip == BCM43342_CHIP_ID ||
4096 /* Moved to PMU chipcontrol 1 from 4330 */
4097 int_val &= ~gpio_sel;
4098 int_val |= jtag_sel;
4100 int_val |= gpio_sel;
4101 int_val &= ~jtag_sel;
4103 uart_enab = CC_PLL_CHIPCTRL_SERIAL_ENAB_4334;
4107 return (int_val & uart_enab);
4109 int_val |= uart_enab;
4111 int_val &= ~uart_enab;
4112 bcmsdh_reg_write(bus->sdh, data, 4, int_val);
4113 if (bcmsdh_regfail(bus->sdh)) {
4114 *bcmerror = BCME_SDIO_ERROR;
4117 if (bus->sih->chip == BCM4330_CHIP_ID) {
4119 addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol);
4120 chipcontrol = bcmsdh_reg_read(bus->sdh, addr, 4);
4121 chipcontrol &= ~jtag_sel;
4123 chipcontrol |= jtag_sel;
4124 chipcontrol &= ~gpio_sel;
4126 bcmsdh_reg_write(bus->sdh, addr, 4, chipcontrol);
4129 return (int_val & uart_enab);
4134 dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const char *name,
4135 void *params, int plen, void *arg, int len, int val_size)
4141 DHD_TRACE(("%s: Enter, action %d name %s params %p plen %d arg %p len %d val_size %d\n",
4142 __FUNCTION__, actionid, name, params, plen, arg, len, val_size));
4144 if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0)
4147 if (plen >= (int)sizeof(int_val))
4148 bcopy(params, &int_val, sizeof(int_val));
4150 bool_val = (int_val != 0) ? TRUE : FALSE;
4153 /* Some ioctls use the bus */
4154 dhd_os_sdlock(bus->dhd);
4156 /* Check if dongle is in reset. If so, only allow DEVRESET iovars */
4157 if (bus->dhd->dongle_reset && !(actionid == IOV_SVAL(IOV_DEVRESET) ||
4158 actionid == IOV_GVAL(IOV_DEVRESET))) {
4159 bcmerror = BCME_NOTREADY;
4164 * Special handling for keepSdioOn: New SDIO Wake-up Mechanism
4166 if ((vi->varid == IOV_KSO) && (IOV_ISSET(actionid))) {
4167 dhdsdio_clk_kso_iovar(bus, bool_val);
4169 } else if ((vi->varid == IOV_DEVSLEEP) && (IOV_ISSET(actionid))) {
4171 dhdsdio_clk_devsleep_iovar(bus, bool_val);
4172 if (!SLPAUTO_ENAB(bus) && (bool_val == FALSE) && (bus->ipend)) {
4173 DHD_ERROR(("INT pending in devsleep 1, dpc_sched: %d\n",
4175 if (!bus->dpc_sched) {
4176 bus->dpc_sched = TRUE;
4177 dhd_sched_dpc(bus->dhd);
4184 /* Handle sleep stuff before any clock mucking */
4185 if (vi->varid == IOV_SLEEP) {
4186 if (IOV_ISSET(actionid)) {
4187 bcmerror = dhdsdio_bussleep(bus, bool_val);
4189 int_val = (int32)bus->sleeping;
4190 bcopy(&int_val, arg, val_size);
4195 /* Request clock to allow SDIO accesses */
4196 if (!bus->dhd->dongle_reset) {
4198 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
4202 case IOV_GVAL(IOV_INTR):
4203 int_val = (int32)bus->intr;
4204 bcopy(&int_val, arg, val_size);
4207 case IOV_SVAL(IOV_INTR):
4208 bus->intr = bool_val;
4209 bus->intdis = FALSE;
4212 DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__));
4213 // terence 20141207: enbale intdis
4215 bcmsdh_intr_enable(bus->sdh);
4217 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
4218 bcmsdh_intr_disable(bus->sdh);
4223 case IOV_GVAL(IOV_POLLRATE):
4224 int_val = (int32)bus->pollrate;
4225 bcopy(&int_val, arg, val_size);
4228 case IOV_SVAL(IOV_POLLRATE):
4229 bus->pollrate = (uint)int_val;
4230 bus->poll = (bus->pollrate != 0);
4233 case IOV_GVAL(IOV_IDLETIME):
4234 int_val = bus->idletime;
4235 bcopy(&int_val, arg, val_size);
4238 case IOV_SVAL(IOV_IDLETIME):
4239 if ((int_val < 0) && (int_val != DHD_IDLE_IMMEDIATE)) {
4240 bcmerror = BCME_BADARG;
4242 bus->idletime = int_val;
4246 case IOV_GVAL(IOV_IDLECLOCK):
4247 int_val = (int32)bus->idleclock;
4248 bcopy(&int_val, arg, val_size);
4251 case IOV_SVAL(IOV_IDLECLOCK):
4252 bus->idleclock = int_val;
4255 case IOV_GVAL(IOV_SD1IDLE):
4256 int_val = (int32)sd1idle;
4257 bcopy(&int_val, arg, val_size);
4260 case IOV_SVAL(IOV_SD1IDLE):
4265 case IOV_SVAL(IOV_MEMBYTES):
4266 case IOV_GVAL(IOV_MEMBYTES):
4272 bool set = (actionid == IOV_SVAL(IOV_MEMBYTES));
4274 ASSERT(plen >= 2*sizeof(int));
4276 address = (uint32)int_val;
4277 bcopy((char *)params + sizeof(int_val), &int_val, sizeof(int_val));
4278 size = (uint)int_val;
4280 /* Do some validation */
4281 dsize = set ? plen - (2 * sizeof(int)) : len;
4283 DHD_ERROR(("%s: error on %s membytes, addr 0x%08x size %d dsize %d\n",
4284 __FUNCTION__, (set ? "set" : "get"), address, size, dsize));
4285 bcmerror = BCME_BADARG;
4289 DHD_INFO(("%s: Request to %s %d bytes at address 0x%08x\n", __FUNCTION__,
4290 (set ? "write" : "read"), size, address));
4293 if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
4295 * If address is start of RAM (i.e. a downloaded image),
4296 * store the reset instruction to be written in 0
4298 if (set && address == bus->dongle_ram_base) {
4299 bus->resetinstr = *(((uint32*)params) + 2);
4302 /* If we know about SOCRAM, check for a fit */
4303 if ((bus->orig_ramsize) &&
4304 ((address > bus->orig_ramsize) || (address + size > bus->orig_ramsize)))
4306 uint8 enable, protect, remap;
4307 si_socdevram(bus->sih, FALSE, &enable, &protect, &remap);
4308 if (!enable || protect) {
4309 DHD_ERROR(("%s: ramsize 0x%08x doesn't have %d bytes at 0x%08x\n",
4310 __FUNCTION__, bus->orig_ramsize, size, address));
4311 DHD_ERROR(("%s: socram enable %d, protect %d\n",
4312 __FUNCTION__, enable, protect));
4313 bcmerror = BCME_BADARG;
4317 if (!REMAP_ENAB(bus) && (address >= SOCDEVRAM_ARM_ADDR)) {
4318 uint32 devramsize = si_socdevram_size(bus->sih);
4319 if ((address < SOCDEVRAM_ARM_ADDR) ||
4320 (address + size > (SOCDEVRAM_ARM_ADDR + devramsize))) {
4321 DHD_ERROR(("%s: bad address 0x%08x, size 0x%08x\n",
4322 __FUNCTION__, address, size));
4323 DHD_ERROR(("%s: socram range 0x%08x,size 0x%08x\n",
4324 __FUNCTION__, SOCDEVRAM_ARM_ADDR, devramsize));
4325 bcmerror = BCME_BADARG;
4328 /* move it such that address is real now */
4329 address -= SOCDEVRAM_ARM_ADDR;
4330 address += SOCDEVRAM_BP_ADDR;
4331 DHD_INFO(("%s: Request to %s %d bytes @ Mapped address 0x%08x\n",
4332 __FUNCTION__, (set ? "write" : "read"), size, address));
4333 } else if (REMAP_ENAB(bus) && REMAP_ISADDR(bus, address) && remap) {
4334 /* Can not access remap region while devram remap bit is set
4335 * ROM content would be returned in this case
4337 DHD_ERROR(("%s: Need to disable remap for address 0x%08x\n",
4338 __FUNCTION__, address));
4339 bcmerror = BCME_ERROR;
4345 /* Generate the actual data pointer */
4346 data = set ? (uint8*)params + 2 * sizeof(int): (uint8*)arg;
4348 /* Call to do the transfer */
4349 bcmerror = dhdsdio_membytes(bus, set, address, data, size);
4354 case IOV_GVAL(IOV_RAMSIZE):
4355 int_val = (int32)bus->ramsize;
4356 bcopy(&int_val, arg, val_size);
4359 case IOV_GVAL(IOV_RAMSTART):
4360 int_val = (int32)bus->dongle_ram_base;
4361 bcopy(&int_val, arg, val_size);
4364 case IOV_GVAL(IOV_SDIOD_DRIVE):
4365 int_val = (int32)dhd_sdiod_drive_strength;
4366 bcopy(&int_val, arg, val_size);
4369 case IOV_SVAL(IOV_SDIOD_DRIVE):
4370 dhd_sdiod_drive_strength = int_val;
4371 si_sdiod_drive_strength_init(bus->sih, bus->dhd->osh, dhd_sdiod_drive_strength);
4374 case IOV_SVAL(IOV_SET_DOWNLOAD_STATE):
4375 bcmerror = dhdsdio_download_state(bus, bool_val);
4378 case IOV_SVAL(IOV_SOCRAM_STATE):
4379 bcmerror = dhdsdio_download_state(bus, bool_val);
4382 case IOV_SVAL(IOV_VARS):
4383 bcmerror = dhdsdio_downloadvars(bus, arg, len);
4386 case IOV_GVAL(IOV_READAHEAD):
4387 int_val = (int32)dhd_readahead;
4388 bcopy(&int_val, arg, val_size);
4391 case IOV_SVAL(IOV_READAHEAD):
4392 if (bool_val && !dhd_readahead)
4394 dhd_readahead = bool_val;
4397 case IOV_GVAL(IOV_SDRXCHAIN):
4398 int_val = (int32)bus->use_rxchain;
4399 bcopy(&int_val, arg, val_size);
4402 case IOV_SVAL(IOV_SDRXCHAIN):
4403 if (bool_val && !bus->sd_rxchain)
4404 bcmerror = BCME_UNSUPPORTED;
4406 bus->use_rxchain = bool_val;
4408 case IOV_GVAL(IOV_ALIGNCTL):
4409 int_val = (int32)dhd_alignctl;
4410 bcopy(&int_val, arg, val_size);
4413 case IOV_SVAL(IOV_ALIGNCTL):
4414 dhd_alignctl = bool_val;
4417 case IOV_GVAL(IOV_SDALIGN):
4418 int_val = DHD_SDALIGN;
4419 bcopy(&int_val, arg, val_size);
4423 case IOV_GVAL(IOV_VARS):
4424 if (bus->varsz < (uint)len)
4425 bcopy(bus->vars, arg, bus->varsz);
4427 bcmerror = BCME_BUFTOOSHORT;
4429 #endif /* DHD_DEBUG */
4432 case IOV_GVAL(IOV_SDREG):
4437 sd_ptr = (sdreg_t *)params;
4439 addr = (uint32)((ulong)bus->regs + sd_ptr->offset);
4440 size = sd_ptr->func;
4441 int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size);
4442 if (bcmsdh_regfail(bus->sdh))
4443 bcmerror = BCME_SDIO_ERROR;
4444 bcopy(&int_val, arg, sizeof(int32));
4448 case IOV_SVAL(IOV_SDREG):
4453 sd_ptr = (sdreg_t *)params;
4455 addr = (uint32)((ulong)bus->regs + sd_ptr->offset);
4456 size = sd_ptr->func;
4457 bcmsdh_reg_write(bus->sdh, addr, size, sd_ptr->value);
4458 if (bcmsdh_regfail(bus->sdh))
4459 bcmerror = BCME_SDIO_ERROR;
4463 /* Same as above, but offset is not backplane (not SDIO core) */
4464 case IOV_GVAL(IOV_SBREG):
4469 bcopy(params, &sdreg, sizeof(sdreg));
4471 addr = SI_ENUM_BASE + sdreg.offset;
4473 int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size);
4474 if (bcmsdh_regfail(bus->sdh))
4475 bcmerror = BCME_SDIO_ERROR;
4476 bcopy(&int_val, arg, sizeof(int32));
4480 case IOV_SVAL(IOV_SBREG):
4485 bcopy(params, &sdreg, sizeof(sdreg));
4487 addr = SI_ENUM_BASE + sdreg.offset;
4489 bcmsdh_reg_write(bus->sdh, addr, size, sdreg.value);
4490 if (bcmsdh_regfail(bus->sdh))
4491 bcmerror = BCME_SDIO_ERROR;
4495 case IOV_GVAL(IOV_SDCIS):
4499 bcmstrcat(arg, "\nFunc 0\n");
4500 bcmsdh_cis_read(bus->sdh, 0x10, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
4501 bcmstrcat(arg, "\nFunc 1\n");
4502 bcmsdh_cis_read(bus->sdh, 0x11, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
4503 bcmstrcat(arg, "\nFunc 2\n");
4504 bcmsdh_cis_read(bus->sdh, 0x12, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
4508 case IOV_GVAL(IOV_FORCEEVEN):
4509 int_val = (int32)forcealign;
4510 bcopy(&int_val, arg, val_size);
4513 case IOV_SVAL(IOV_FORCEEVEN):
4514 forcealign = bool_val;
4517 case IOV_GVAL(IOV_TXBOUND):
4518 int_val = (int32)dhd_txbound;
4519 bcopy(&int_val, arg, val_size);
4522 case IOV_SVAL(IOV_TXBOUND):
4523 dhd_txbound = (uint)int_val;
4526 case IOV_GVAL(IOV_RXBOUND):
4527 int_val = (int32)dhd_rxbound;
4528 bcopy(&int_val, arg, val_size);
4531 case IOV_SVAL(IOV_RXBOUND):
4532 dhd_rxbound = (uint)int_val;
4535 case IOV_GVAL(IOV_TXMINMAX):
4536 int_val = (int32)dhd_txminmax;
4537 bcopy(&int_val, arg, val_size);
4540 case IOV_SVAL(IOV_TXMINMAX):
4541 dhd_txminmax = (uint)int_val;
4544 case IOV_GVAL(IOV_SERIALCONS):
4545 int_val = dhd_serialconsole(bus, FALSE, 0, &bcmerror);
4549 bcopy(&int_val, arg, val_size);
4552 case IOV_SVAL(IOV_SERIALCONS):
4553 dhd_serialconsole(bus, TRUE, bool_val, &bcmerror);
4557 #endif /* DHD_DEBUG */
4561 case IOV_GVAL(IOV_EXTLOOP):
4562 int_val = (int32)bus->ext_loop;
4563 bcopy(&int_val, arg, val_size);
4566 case IOV_SVAL(IOV_EXTLOOP):
4567 bus->ext_loop = bool_val;
4570 case IOV_GVAL(IOV_PKTGEN):
4571 bcmerror = dhdsdio_pktgen_get(bus, arg);
4574 case IOV_SVAL(IOV_PKTGEN):
4575 bcmerror = dhdsdio_pktgen_set(bus, arg);
4579 #if defined(USE_SDIOFIFO_IOVAR)
4580 case IOV_GVAL(IOV_WATERMARK):
4581 int_val = (int32)watermark;
4582 bcopy(&int_val, arg, val_size);
4585 case IOV_SVAL(IOV_WATERMARK):
4586 watermark = (uint)int_val;
4587 watermark = (watermark > SBSDIO_WATERMARK_MASK) ? SBSDIO_WATERMARK_MASK : watermark;
4588 DHD_ERROR(("Setting watermark as 0x%x.\n", watermark));
4589 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, (uint8)watermark, NULL);
4592 case IOV_GVAL(IOV_MESBUSYCTRL):
4593 int_val = (int32)mesbusyctrl;
4594 bcopy(&int_val, arg, val_size);
4597 case IOV_SVAL(IOV_MESBUSYCTRL):
4598 mesbusyctrl = (uint)int_val;
4599 mesbusyctrl = (mesbusyctrl > SBSDIO_MESBUSYCTRL_MASK)
4600 ? SBSDIO_MESBUSYCTRL_MASK : mesbusyctrl;
4601 DHD_ERROR(("Setting mesbusyctrl as 0x%x.\n", mesbusyctrl));
4602 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL,
4603 ((uint8)mesbusyctrl | 0x80), NULL);
4608 case IOV_GVAL(IOV_DONGLEISOLATION):
4609 int_val = bus->dhd->dongle_isolation;
4610 bcopy(&int_val, arg, val_size);
4613 case IOV_SVAL(IOV_DONGLEISOLATION):
4614 bus->dhd->dongle_isolation = bool_val;
4617 case IOV_SVAL(IOV_DEVRESET):
4618 DHD_TRACE(("%s: Called set IOV_DEVRESET=%d dongle_reset=%d busstate=%d\n",
4619 __FUNCTION__, bool_val, bus->dhd->dongle_reset,
4620 bus->dhd->busstate));
4622 ASSERT(bus->dhd->osh);
4623 /* ASSERT(bus->cl_devid); */
4625 dhd_bus_devreset(bus->dhd, (uint8)bool_val);
4629 * softap firmware is updated through module parameter or android private command
4632 case IOV_GVAL(IOV_DEVRESET):
4633 DHD_TRACE(("%s: Called get IOV_DEVRESET\n", __FUNCTION__));
4635 /* Get its status */
4636 int_val = (bool) bus->dhd->dongle_reset;
4637 bcopy(&int_val, arg, val_size);
4641 case IOV_GVAL(IOV_KSO):
4642 int_val = dhdsdio_sleepcsr_get(bus);
4643 bcopy(&int_val, arg, val_size);
4646 case IOV_GVAL(IOV_DEVCAP):
4647 int_val = dhdsdio_devcap_get(bus);
4648 bcopy(&int_val, arg, val_size);
4651 case IOV_SVAL(IOV_DEVCAP):
4652 dhdsdio_devcap_set(bus, (uint8) int_val);
4654 case IOV_GVAL(IOV_TXGLOMSIZE):
4655 int_val = (int32)bus->txglomsize;
4656 bcopy(&int_val, arg, val_size);
4659 case IOV_SVAL(IOV_TXGLOMSIZE):
4660 if (int_val > SDPCM_MAXGLOM_SIZE) {
4661 bcmerror = BCME_ERROR;
4663 bus->txglomsize = (uint)int_val;
4666 case IOV_SVAL(IOV_HANGREPORT):
4667 bus->dhd->hang_report = bool_val;
4668 DHD_ERROR(("%s: Set hang_report as %d\n", __FUNCTION__, bus->dhd->hang_report));
4671 case IOV_GVAL(IOV_HANGREPORT):
4672 int_val = (int32)bus->dhd->hang_report;
4673 bcopy(&int_val, arg, val_size);
4676 case IOV_GVAL(IOV_TXINRX_THRES):
4677 int_val = bus->txinrx_thres;
4678 bcopy(&int_val, arg, val_size);
4680 case IOV_SVAL(IOV_TXINRX_THRES):
4682 bcmerror = BCME_BADARG;
4684 bus->txinrx_thres = int_val;
4689 bcmerror = BCME_UNSUPPORTED;
4694 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
4695 bus->activity = FALSE;
4696 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
4699 dhd_os_sdunlock(bus->dhd);
4705 dhdsdio_write_vars(dhd_bus_t *bus)
4708 uint32 varsize, phys_size;
4713 uint8 *nvram_ularray;
4714 #endif /* DHD_DEBUG */
4716 /* Even if there are no vars are to be written, we still need to set the ramsize. */
4717 varsize = bus->varsz ? ROUNDUP(bus->varsz, 4) : 0;
4718 varaddr = (bus->ramsize - 4) - varsize;
4720 // terence 20150412: fix for nvram failed to download
4721 if (bus->dhd->conf->chip == BCM43340_CHIP_ID ||
4722 bus->dhd->conf->chip == BCM43341_CHIP_ID) {
4723 varsize = varsize ? ROUNDUP(varsize, 64) : 0;
4724 varaddr = (bus->ramsize - 64) - varsize;
4727 varaddr += bus->dongle_ram_base;
4730 if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 7)) {
4731 if (((varaddr & 0x3C) == 0x3C) && (varsize > 4)) {
4732 DHD_ERROR(("PR85623WAR in place\n"));
4738 vbuffer = (uint8 *)MALLOC(bus->dhd->osh, varsize);
4742 bzero(vbuffer, varsize);
4743 bcopy(bus->vars, vbuffer, bus->varsz);
4745 /* Write the vars list */
4746 bcmerror = dhdsdio_membytes(bus, TRUE, varaddr, vbuffer, varsize);
4748 /* Verify NVRAM bytes */
4749 DHD_INFO(("Compare NVRAM dl & ul; varsize=%d\n", varsize));
4750 nvram_ularray = (uint8*)MALLOC(bus->dhd->osh, varsize);
4754 /* Upload image to verify downloaded contents. */
4755 memset(nvram_ularray, 0xaa, varsize);
4757 /* Read the vars list to temp buffer for comparison */
4758 bcmerror = dhdsdio_membytes(bus, FALSE, varaddr, nvram_ularray, varsize);
4760 DHD_ERROR(("%s: error %d on reading %d nvram bytes at 0x%08x\n",
4761 __FUNCTION__, bcmerror, varsize, varaddr));
4763 /* Compare the org NVRAM with the one read from RAM */
4764 if (memcmp(vbuffer, nvram_ularray, varsize)) {
4765 DHD_ERROR(("%s: Downloaded NVRAM image is corrupted.\n", __FUNCTION__));
4767 DHD_ERROR(("%s: Download, Upload and compare of NVRAM succeeded.\n",
4770 MFREE(bus->dhd->osh, nvram_ularray, varsize);
4771 #endif /* DHD_DEBUG */
4773 MFREE(bus->dhd->osh, vbuffer, varsize);
4776 phys_size = REMAP_ENAB(bus) ? bus->ramsize : bus->orig_ramsize;
4778 phys_size += bus->dongle_ram_base;
4780 /* adjust to the user specified RAM */
4781 DHD_INFO(("Physical memory size: %d, usable memory size: %d\n",
4782 phys_size, bus->ramsize));
4783 DHD_INFO(("Vars are at %d, orig varsize is %d\n",
4785 varsize = ((phys_size - 4) - varaddr);
4788 * Determine the length token:
4789 * Varsize, converted to words, in lower 16-bits, checksum in upper 16-bits.
4794 varsizew = varsize / 4;
4795 varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF);
4796 varsizew = htol32(varsizew);
4799 DHD_INFO(("New varsize is %d, length token=0x%08x\n", varsize, varsizew));
4801 /* Write the length token to the last word */
4802 bcmerror = dhdsdio_membytes(bus, TRUE, (phys_size - 4),
4803 (uint8*)&varsizew, 4);
4809 dhdsdio_download_state(dhd_bus_t *bus, bool enter)
4817 /* To enter download state, disable ARM and reset SOCRAM.
4818 * To exit download state, simply reset ARM (default is RAM boot).
4821 bus->alp_only = TRUE;
4823 if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) &&
4824 !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) {
4825 if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
4828 DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__));
4829 bcmerror = BCME_ERROR;
4835 si_core_disable(bus->sih, 0);
4836 if (bcmsdh_regfail(bus->sdh)) {
4837 bcmerror = BCME_SDIO_ERROR;
4841 if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) {
4842 DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__));
4843 bcmerror = BCME_ERROR;
4847 si_core_reset(bus->sih, 0, 0);
4848 if (bcmsdh_regfail(bus->sdh)) {
4849 DHD_ERROR(("%s: Failure trying reset SOCRAM core?\n",
4851 bcmerror = BCME_SDIO_ERROR;
4855 /* Disable remap for download */
4856 if (REMAP_ENAB(bus) && si_socdevram_remap_isenb(bus->sih))
4857 dhdsdio_devram_remap(bus, FALSE);
4859 if (CHIPID(bus->sih->chip) == BCM43430_CHIP_ID) {
4860 /* Disabling Remap for SRAM_3 */
4861 si_socram_set_bankpda(bus->sih, 0x3, 0x0);
4864 /* Clear the top bit of memory */
4867 if (dhdsdio_membytes(bus, TRUE, bus->ramsize - 4,
4868 (uint8*)&zeros, 4) < 0) {
4869 bcmerror = BCME_SDIO_ERROR;
4877 * Read RAM base address [0x18_0000]
4878 * [next] Download firmware
4879 * [done at else] Populate the reset vector
4880 * [done at else] Remove ARM halt
4882 /* Halt ARM & remove reset */
4883 si_core_reset(bus->sih, SICF_CPUHALT, SICF_CPUHALT);
4886 if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
4887 if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) {
4888 DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__));
4889 bcmerror = BCME_ERROR;
4893 if (!si_iscoreup(bus->sih)) {
4894 DHD_ERROR(("%s: SOCRAM core is down after reset?\n", __FUNCTION__));
4895 bcmerror = BCME_ERROR;
4899 if ((bcmerror = dhdsdio_write_vars(bus))) {
4900 DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__));
4904 /* Enable remap before ARM reset but after vars.
4905 * No backplane access in remap mode
4907 if (REMAP_ENAB(bus) && !si_socdevram_remap_isenb(bus->sih))
4908 dhdsdio_devram_remap(bus, TRUE);
4910 if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) &&
4911 !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) {
4912 DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__));
4913 bcmerror = BCME_ERROR;
4916 W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries);
4919 if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) &&
4920 !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) {
4921 DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__));
4922 bcmerror = BCME_ERROR;
4926 /* cr4 has no socram, but tcm's */
4928 if ((bcmerror = dhdsdio_write_vars(bus))) {
4929 DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__));
4933 if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) &&
4934 !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) {
4935 DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__));
4936 bcmerror = BCME_ERROR;
4939 W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries);
4941 /* switch back to arm core again */
4942 if (!(si_setcore(bus->sih, ARMCR4_CORE_ID, 0))) {
4943 DHD_ERROR(("%s: Failed to find ARM CR4 core!\n", __FUNCTION__));
4944 bcmerror = BCME_ERROR;
4947 /* write address 0 with reset instruction */
4948 bcmerror = dhdsdio_membytes(bus, TRUE, 0,
4949 (uint8 *)&bus->resetinstr, sizeof(bus->resetinstr));
4951 if (bcmerror == BCME_OK) {
4955 bcmerror = dhdsdio_membytes(bus, FALSE, 0,
4956 (uint8 *)&tmp, sizeof(tmp));
4958 if (bcmerror == BCME_OK && tmp != bus->resetinstr) {
4959 DHD_ERROR(("%s: Failed to write 0x%08x to addr 0\n",
4960 __FUNCTION__, bus->resetinstr));
4961 DHD_ERROR(("%s: contents of addr 0 is 0x%08x\n",
4962 __FUNCTION__, tmp));
4963 bcmerror = BCME_SDIO_ERROR;
4968 /* now remove reset and halt and continue to run CR4 */
4971 si_core_reset(bus->sih, 0, 0);
4972 if (bcmsdh_regfail(bus->sdh)) {
4973 DHD_ERROR(("%s: Failure trying to reset ARM core?\n", __FUNCTION__));
4974 bcmerror = BCME_SDIO_ERROR;
4978 /* Allow HT Clock now that the ARM is running. */
4979 bus->alp_only = FALSE;
4981 bus->dhd->busstate = DHD_BUS_LOAD;
4985 /* Always return to SDIOD core */
4986 if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0))
4987 si_setcore(bus->sih, SDIOD_CORE_ID, 0);
4993 dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name,
4994 void *params, int plen, void *arg, int len, bool set)
4996 dhd_bus_t *bus = dhdp->bus;
4997 const bcm_iovar_t *vi = NULL;
5002 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5007 /* Get MUST have return space */
5008 ASSERT(set || (arg && len));
5010 /* Set does NOT take qualifiers */
5011 ASSERT(!set || (!params && !plen));
5013 /* Look up var locally; if not found pass to host driver */
5014 if ((vi = bcm_iovar_lookup(dhdsdio_iovars, name)) == NULL) {
5015 dhd_os_sdlock(bus->dhd);
5019 /* Turn on clock in case SD command needs backplane */
5020 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
5022 bcmerror = bcmsdh_iovar_op(bus->sdh, name, params, plen, arg, len, set);
5024 /* Check for bus configuration changes of interest */
5026 /* If it was divisor change, read the new one */
5027 if (set && strcmp(name, "sd_divisor") == 0) {
5028 if (bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
5029 &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) {
5030 bus->sd_divisor = -1;
5031 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, name));
5033 DHD_INFO(("%s: noted %s update, value now %d\n",
5034 __FUNCTION__, name, bus->sd_divisor));
5037 /* If it was a mode change, read the new one */
5038 if (set && strcmp(name, "sd_mode") == 0) {
5039 if (bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
5040 &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) {
5042 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, name));
5044 DHD_INFO(("%s: noted %s update, value now %d\n",
5045 __FUNCTION__, name, bus->sd_mode));
5048 /* Similar check for blocksize change */
5049 if (set && strcmp(name, "sd_blocksize") == 0) {
5051 if (bcmsdh_iovar_op(bus->sdh, "sd_blocksize", &fnum, sizeof(int32),
5052 &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) {
5054 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize"));
5056 DHD_INFO(("%s: noted %s update, value now %d\n",
5057 __FUNCTION__, "sd_blocksize", bus->blocksize));
5059 dhdsdio_tune_fifoparam(bus);
5062 bus->roundup = MIN(max_roundup, bus->blocksize);
5064 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
5065 bus->activity = FALSE;
5066 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
5069 dhd_os_sdunlock(bus->dhd);
5073 DHD_CTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__,
5074 name, (set ? "set" : "get"), len, plen));
5076 /* set up 'params' pointer in case this is a set command so that
5077 * the convenience int and bool code can be common to set and get
5079 if (params == NULL) {
5084 if (vi->type == IOVT_VOID)
5086 else if (vi->type == IOVT_BUFFER)
5089 /* all other types are integer sized */
5090 val_size = sizeof(int);
5092 actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
5093 bcmerror = dhdsdio_doiovar(bus, vi, actionid, name, params, plen, arg, len, val_size);
5100 dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex)
5103 uint32 local_hostintmask;
5107 bool wlfc_enabled = FALSE;
5112 osh = bus->dhd->osh;
5113 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5115 bcmsdh_waitlockfree(bus->sdh);
5118 dhd_os_sdlock(bus->dhd);
5120 if ((bus->dhd->busstate == DHD_BUS_DOWN) || bus->dhd->hang_was_sent) {
5121 /* if Firmware already hangs disbale any interrupt */
5122 bus->dhd->busstate = DHD_BUS_DOWN;
5123 bus->hostintmask = 0;
5124 bcmsdh_intr_disable(bus->sdh);
5129 if (KSO_ENAB(bus)) {
5131 /* Enable clock for device interrupts */
5132 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
5134 /* Disable and clear interrupts at the chip level also */
5135 W_SDREG(0, &bus->regs->hostintmask, retries);
5136 local_hostintmask = bus->hostintmask;
5137 bus->hostintmask = 0;
5139 /* Force clocks on backplane to be sure F2 interrupt propagates */
5140 saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
5142 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
5143 (saveclk | SBSDIO_FORCE_HT), &err);
5146 DHD_ERROR(("%s: Failed to force clock for F2: err %d\n",
5147 __FUNCTION__, err));
5150 /* Turn off the bus (F2), free any pending packets */
5151 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
5152 bcmsdh_intr_disable(bus->sdh);
5153 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL);
5155 /* Clear any pending interrupts now that F2 is disabled */
5156 W_SDREG(local_hostintmask, &bus->regs->intstatus, retries);
5159 /* Turn off the backplane clock (only) */
5160 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
5162 /* Change our idea of bus state */
5163 bus->dhd->busstate = DHD_BUS_DOWN;
5166 #ifdef PROP_TXSTATUS
5167 wlfc_enabled = (dhd_wlfc_cleanup_txq(bus->dhd, NULL, 0) != WLFC_UNSUPPORTED);
5169 if (!wlfc_enabled) {
5170 #ifdef DHDTCPACK_SUPPRESS
5171 /* Clean tcp_ack_info_tbl in order to prevent access to flushed pkt,
5172 * when there is a newly coming packet from network stack.
5174 dhd_tcpack_info_tbl_clean(bus->dhd);
5175 #endif /* DHDTCPACK_SUPPRESS */
5176 /* Clear the data packet queues */
5177 pktq_flush(osh, &bus->txq, TRUE, NULL, 0);
5180 /* Clear any held glomming stuff */
5182 PKTFREE(osh, bus->glomd, FALSE);
5185 PKTFREE(osh, bus->glom, FALSE);
5187 bus->glom = bus->glomd = NULL;
5189 /* Clear rx control and wake any waiters */
5191 dhd_os_ioctl_resp_wake(bus->dhd);
5193 /* Reset some F2 state stuff */
5194 bus->rxskip = FALSE;
5195 bus->tx_seq = bus->rx_seq = 0;
5200 dhd_os_sdunlock(bus->dhd);
5203 #if defined(BCMSDIOH_TXGLOM) && defined(BCMSDIOH_STD)
5204 extern uint sd_txglom;
5207 dhd_txglom_enable(dhd_pub_t *dhdp, bool enable)
5209 /* can't enable host txglom by default, some platforms have no
5210 * (or crappy) ADMA support and txglom will cause kernel assertions (e.g.
5213 dhd_bus_t *bus = dhdp->bus;
5214 #ifdef BCMSDIOH_TXGLOM
5219 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5224 #endif /* BCMSDIOH_STD */
5228 memset(buf, 0, sizeof(buf));
5229 bcm_mkiovar("bus:rxglom", (void *)&rxglom, 4, buf, sizeof(buf));
5230 ret = dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0);
5232 bus->txglom_enable = TRUE;
5236 #endif /* BCMSDIOH_STD */
5237 bus->txglom_enable = FALSE;
5240 #endif /* BCMSDIOH_TXGLOM */
5241 bus->txglom_enable = FALSE;
5242 printf("%s: enable %d\n", __FUNCTION__, bus->txglom_enable);
5243 dhd_conf_set_txglom_params(bus->dhd, bus->txglom_enable);
5247 dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex)
5249 dhd_bus_t *bus = dhdp->bus;
5252 uint8 ready, enable;
5256 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5263 dhd_os_sdlock(bus->dhd);
5265 if (bus->sih->chip == BCM43362_CHIP_ID) {
5266 printf("%s: delay 100ms for BCM43362\n", __FUNCTION__);
5267 OSL_DELAY(100000); // terence 20131209: delay for 43362
5270 /* Make sure backplane clock is on, needed to generate F2 interrupt */
5271 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
5272 if (bus->clkstate != CLK_AVAIL) {
5273 DHD_ERROR(("%s: clock state is wrong. state = %d\n", __FUNCTION__, bus->clkstate));
5279 /* Force clocks on backplane to be sure F2 interrupt propagates */
5280 saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
5282 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
5283 (saveclk | SBSDIO_FORCE_HT), &err);
5286 DHD_ERROR(("%s: Failed to force clock for F2: err %d\n", __FUNCTION__, err));
5291 /* Enable function 2 (frame transfers) */
5292 W_SDREG((SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT),
5293 &bus->regs->tosbmailboxdata, retries);
5294 enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2);
5296 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL);
5298 /* Give the dongle some time to do its thing and set IOR2 */
5299 dhd_timeout_start(&tmo, DHD_WAIT_F2RDY * 1000);
5302 while (ready != enable && !dhd_timeout_expired(&tmo))
5303 ready = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IORDY, NULL);
5305 DHD_ERROR(("%s: enable 0x%02x, ready 0x%02x (waited %uus)\n",
5306 __FUNCTION__, enable, ready, tmo.elapsed));
5309 /* If F2 successfully enabled, set core and enable interrupts */
5310 if (ready == enable) {
5311 /* Make sure we're talking to the core. */
5312 if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0)))
5313 bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0);
5314 ASSERT(bus->regs != NULL);
5316 /* Set up the interrupt mask and enable interrupts */
5317 bus->hostintmask = HOSTINTMASK;
5318 /* corerev 4 could use the newer interrupt logic to detect the frames */
5319 if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 4) &&
5320 (bus->rxint_mode != SDIO_DEVICE_HMB_RXINT)) {
5321 bus->hostintmask &= ~I_HMB_FRAME_IND;
5322 bus->hostintmask |= I_XMTDATA_AVAIL;
5324 W_SDREG(bus->hostintmask, &bus->regs->hostintmask, retries);
5326 if (bus->sih->buscorerev < 15) {
5327 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK,
5328 (uint8)watermark, &err);
5331 /* Set bus state according to enable result */
5332 dhdp->busstate = DHD_BUS_DATA;
5334 /* Need to set fn2 block size to match fn1 block size.
5335 * Requests to fn2 go thru fn1. *
5336 * faltwig has this code contitioned with #if !BCMSPI_ANDROID.
5337 * It would be cleaner to use the ->sdh->block_sz[fno] instead of
5338 * 64, but this layer has no access to sdh types.
5341 /* bcmsdh_intr_unmask(bus->sdh); */
5343 bus->intdis = FALSE;
5345 DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__));
5346 bcmsdh_intr_enable(bus->sdh);
5348 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
5349 bcmsdh_intr_disable(bus->sdh);
5356 if (dhdp->conf->chip == BCM4354_CHIP_ID) {
5360 /* Disable F2 again */
5361 enable = SDIO_FUNC_ENABLE_1;
5362 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL);
5365 if (dhdsdio_sr_cap(bus)) {
5366 dhdsdio_sr_init(bus);
5367 /* Masking the chip active interrupt permanantly */
5368 bus->hostintmask &= ~I_CHIPACTIVE;
5369 W_SDREG(bus->hostintmask, &bus->regs->hostintmask, retries);
5370 DHD_INFO(("%s: disable I_CHIPACTIVE in hostintmask[0x%08x]\n",
5371 __FUNCTION__, bus->hostintmask));
5374 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1,
5375 SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err);
5377 /* If we didn't come up, turn off backplane clock */
5378 if (dhdp->busstate != DHD_BUS_DATA)
5379 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
5383 dhd_os_sdunlock(bus->dhd);
5389 dhdsdio_rxfail(dhd_bus_t *bus, bool abort, bool rtx)
5391 bcmsdh_info_t *sdh = bus->sdh;
5392 sdpcmd_regs_t *regs = bus->regs;
5398 DHD_ERROR(("%s: %sterminate frame%s\n", __FUNCTION__,
5399 (abort ? "abort command, " : ""), (rtx ? ", send NAK" : "")));
5401 if (!KSO_ENAB(bus)) {
5402 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
5407 bcmsdh_abort(sdh, SDIO_FUNC_2);
5410 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, SFC_RF_TERM, &err);
5412 DHD_ERROR(("%s: SBSDIO_FUNC1_FRAMECTRL cmd err\n", __FUNCTION__));
5417 /* Wait until the packet has been flushed (device/FIFO stable) */
5418 for (lastrbc = retries = 0xffff; retries > 0; retries--) {
5419 hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCHI, NULL);
5420 lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCLO, &err);
5422 DHD_ERROR(("%s: SBSDIO_FUNC1_RFAMEBCLO cmd err\n", __FUNCTION__));
5426 bus->f1regdata += 2;
5428 if ((hi == 0) && (lo == 0))
5431 if ((hi > (lastrbc >> 8)) && (lo > (lastrbc & 0x00ff))) {
5432 DHD_ERROR(("%s: count growing: last 0x%04x now 0x%04x\n",
5433 __FUNCTION__, lastrbc, ((hi << 8) + lo)));
5435 lastrbc = (hi << 8) + lo;
5439 DHD_ERROR(("%s: count never zeroed: last 0x%04x\n", __FUNCTION__, lastrbc));
5441 DHD_INFO(("%s: flush took %d iterations\n", __FUNCTION__, (0xffff - retries)));
5446 W_SDREG(SMB_NAK, ®s->tosbmailbox, retries);
5448 if (retries <= retry_limit) {
5453 /* Clear partial in any case */
5457 /* If we can't reach the device, signal failure */
5458 if (err || bcmsdh_regfail(sdh))
5459 bus->dhd->busstate = DHD_BUS_DOWN;
5463 dhdsdio_read_control(dhd_bus_t *bus, uint8 *hdr, uint len, uint doff)
5465 bcmsdh_info_t *sdh = bus->sdh;
5470 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5472 /* Control data already received in aligned rxctl */
5473 if ((bus->bus == SPI_BUS) && (!bus->usebufpool))
5477 /* Set rxctl for frame (w/optional alignment) */
5478 bus->rxctl = bus->rxbuf;
5480 bus->rxctl += firstread;
5481 if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN)))
5482 bus->rxctl += (DHD_SDALIGN - pad);
5483 bus->rxctl -= firstread;
5485 ASSERT(bus->rxctl >= bus->rxbuf);
5487 /* Copy the already-read portion over */
5488 bcopy(hdr, bus->rxctl, firstread);
5489 if (len <= firstread)
5492 /* Copy the full data pkt in gSPI case and process ioctl. */
5493 if (bus->bus == SPI_BUS) {
5494 bcopy(hdr, bus->rxctl, len);
5498 /* Raise rdlen to next SDIO block to avoid tail command */
5499 rdlen = len - firstread;
5500 if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
5501 pad = bus->blocksize - (rdlen % bus->blocksize);
5502 if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
5503 ((len + pad) < bus->dhd->maxctl))
5505 } else if (rdlen % DHD_SDALIGN) {
5506 rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
5509 /* Satisfy length-alignment requirements */
5510 if (forcealign && (rdlen & (ALIGNMENT - 1)))
5511 rdlen = ROUNDUP(rdlen, ALIGNMENT);
5513 /* Drop if the read is too big or it exceeds our maximum */
5514 if ((rdlen + firstread) > bus->dhd->maxctl) {
5515 DHD_ERROR(("%s: %d-byte control read exceeds %d-byte buffer\n",
5516 __FUNCTION__, rdlen, bus->dhd->maxctl));
5517 bus->dhd->rx_errors++;
5518 dhdsdio_rxfail(bus, FALSE, FALSE);
5522 if ((len - doff) > bus->dhd->maxctl) {
5523 DHD_ERROR(("%s: %d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n",
5524 __FUNCTION__, len, (len - doff), bus->dhd->maxctl));
5525 bus->dhd->rx_errors++; bus->rx_toolong++;
5526 dhdsdio_rxfail(bus, FALSE, FALSE);
5531 /* Read remainder of frame body into the rxctl buffer */
5532 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
5533 (bus->rxctl + firstread), rdlen, NULL, NULL, NULL);
5535 ASSERT(sdret != BCME_PENDING);
5537 /* Control frame failures need retransmission */
5539 DHD_ERROR(("%s: read %d control bytes failed: %d\n", __FUNCTION__, rdlen, sdret));
5540 bus->rxc_errors++; /* dhd.rx_ctlerrs is higher level */
5541 dhdsdio_rxfail(bus, TRUE, TRUE);
5548 if (DHD_BYTES_ON() && DHD_CTL_ON()) {
5549 prhex("RxCtrl", bus->rxctl, len);
5553 /* Point to valid data and indicate its length */
5555 bus->rxlen = len - doff;
5558 /* Awake any waiters */
5559 dhd_os_ioctl_resp_wake(bus->dhd);
5562 dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf, uint reorder_info_len,
5563 void **pkt, uint32 *pkt_count);
5566 dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq)
5568 uint16 dlen, totlen;
5569 uint8 *dptr, num = 0;
5571 uint16 sublen, check;
5572 void *pfirst, *plast, *pnext;
5573 void * list_tail[DHD_MAX_IFS] = { NULL };
5574 void * list_head[DHD_MAX_IFS] = { NULL };
5576 osl_t *osh = bus->dhd->osh;
5579 uint8 chan, seq, doff, sfdoff;
5581 uchar reorder_info_buf[WLHOST_REORDERDATA_TOTLEN];
5582 uint reorder_info_len;
5585 bool usechain = bus->use_rxchain;
5587 /* If packets, issue read(s) and send up packet chain */
5588 /* Return sequence numbers consumed? */
5590 DHD_TRACE(("dhdsdio_rxglom: start: glomd %p glom %p\n", bus->glomd, bus->glom));
5592 /* If there's a descriptor, generate the packet chain */
5594 dhd_os_sdlock_rxq(bus->dhd);
5596 pfirst = plast = pnext = NULL;
5597 dlen = (uint16)PKTLEN(osh, bus->glomd);
5598 dptr = PKTDATA(osh, bus->glomd);
5599 if (!dlen || (dlen & 1)) {
5600 DHD_ERROR(("%s: bad glomd len (%d), ignore descriptor\n",
5601 __FUNCTION__, dlen));
5605 for (totlen = num = 0; dlen; num++) {
5606 /* Get (and move past) next length */
5607 sublen = ltoh16_ua(dptr);
5608 dlen -= sizeof(uint16);
5609 dptr += sizeof(uint16);
5610 if ((sublen < SDPCM_HDRLEN) ||
5611 ((num == 0) && (sublen < (2 * SDPCM_HDRLEN)))) {
5612 DHD_ERROR(("%s: descriptor len %d bad: %d\n",
5613 __FUNCTION__, num, sublen));
5617 if (sublen % DHD_SDALIGN) {
5618 DHD_ERROR(("%s: sublen %d not a multiple of %d\n",
5619 __FUNCTION__, sublen, DHD_SDALIGN));
5624 /* For last frame, adjust read len so total is a block multiple */
5626 sublen += (ROUNDUP(totlen, bus->blocksize) - totlen);
5627 totlen = ROUNDUP(totlen, bus->blocksize);
5630 /* Allocate/chain packet for next subframe */
5631 if ((pnext = PKTGET(osh, sublen + DHD_SDALIGN, FALSE)) == NULL) {
5632 DHD_ERROR(("%s: PKTGET failed, num %d len %d\n",
5633 __FUNCTION__, num, sublen));
5636 ASSERT(!PKTLINK(pnext));
5639 pfirst = plast = pnext;
5642 PKTSETNEXT(osh, plast, pnext);
5646 /* Adhere to start alignment requirements */
5647 PKTALIGN(osh, pnext, sublen, DHD_SDALIGN);
5650 /* If all allocations succeeded, save packet chain in bus structure */
5652 DHD_GLOM(("%s: allocated %d-byte packet chain for %d subframes\n",
5653 __FUNCTION__, totlen, num));
5654 if (DHD_GLOM_ON() && bus->nextlen) {
5655 if (totlen != bus->nextlen) {
5656 DHD_GLOM(("%s: glomdesc mismatch: nextlen %d glomdesc %d "
5657 "rxseq %d\n", __FUNCTION__, bus->nextlen,
5662 pfirst = pnext = NULL;
5665 PKTFREE(osh, pfirst, FALSE);
5670 /* Done with descriptor packet */
5671 PKTFREE(osh, bus->glomd, FALSE);
5675 dhd_os_sdunlock_rxq(bus->dhd);
5678 /* Ok -- either we just generated a packet chain, or had one from before */
5680 if (DHD_GLOM_ON()) {
5681 DHD_GLOM(("%s: attempt superframe read, packet chain:\n", __FUNCTION__));
5682 for (pnext = bus->glom; pnext; pnext = PKTNEXT(osh, pnext)) {
5683 DHD_GLOM((" %p: %p len 0x%04x (%d)\n",
5684 pnext, (uint8*)PKTDATA(osh, pnext),
5685 PKTLEN(osh, pnext), PKTLEN(osh, pnext)));
5690 dlen = (uint16)pkttotlen(osh, pfirst);
5692 /* Do an SDIO read for the superframe. Configurable iovar to
5693 * read directly into the chained packet, or allocate a large
5694 * packet and and copy into the chain.
5697 errcode = dhd_bcmsdh_recv_buf(bus,
5698 bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2,
5699 F2SYNC, (uint8*)PKTDATA(osh, pfirst),
5700 dlen, pfirst, NULL, NULL);
5701 } else if (bus->dataptr) {
5702 errcode = dhd_bcmsdh_recv_buf(bus,
5703 bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2,
5704 F2SYNC, bus->dataptr,
5705 dlen, NULL, NULL, NULL);
5706 sublen = (uint16)pktfrombuf(osh, pfirst, 0, dlen, bus->dataptr);
5707 if (sublen != dlen) {
5708 DHD_ERROR(("%s: FAILED TO COPY, dlen %d sublen %d\n",
5709 __FUNCTION__, dlen, sublen));
5714 DHD_ERROR(("COULDN'T ALLOC %d-BYTE GLOM, FORCE FAILURE\n", dlen));
5718 ASSERT(errcode != BCME_PENDING);
5720 /* On failure, kill the superframe, allow a couple retries */
5722 DHD_ERROR(("%s: glom read of %d bytes failed: %d\n",
5723 __FUNCTION__, dlen, errcode));
5724 bus->dhd->rx_errors++;
5726 if (bus->glomerr++ < 3) {
5727 dhdsdio_rxfail(bus, TRUE, TRUE);
5730 dhdsdio_rxfail(bus, TRUE, FALSE);
5731 dhd_os_sdlock_rxq(bus->dhd);
5732 PKTFREE(osh, bus->glom, FALSE);
5733 dhd_os_sdunlock_rxq(bus->dhd);
5741 if (DHD_GLOM_ON()) {
5742 prhex("SUPERFRAME", PKTDATA(osh, pfirst),
5743 MIN(PKTLEN(osh, pfirst), 48));
5748 /* Validate the superframe header */
5749 dptr = (uint8 *)PKTDATA(osh, pfirst);
5750 sublen = ltoh16_ua(dptr);
5751 check = ltoh16_ua(dptr + sizeof(uint16));
5753 chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
5754 seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
5755 bus->nextlen = dptr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
5756 if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
5757 DHD_INFO(("%s: got frame w/nextlen too large (%d) seq %d\n",
5758 __FUNCTION__, bus->nextlen, seq));
5761 doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
5762 txmax = SDPCM_WINDOW_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
5765 if ((uint16)~(sublen^check)) {
5766 DHD_ERROR(("%s (superframe): HW hdr error: len/check 0x%04x/0x%04x\n",
5767 __FUNCTION__, sublen, check));
5769 } else if (ROUNDUP(sublen, bus->blocksize) != dlen) {
5770 DHD_ERROR(("%s (superframe): len 0x%04x, rounded 0x%04x, expect 0x%04x\n",
5771 __FUNCTION__, sublen, ROUNDUP(sublen, bus->blocksize), dlen));
5773 } else if (SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]) != SDPCM_GLOM_CHANNEL) {
5774 DHD_ERROR(("%s (superframe): bad channel %d\n", __FUNCTION__,
5775 SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN])));
5777 } else if (SDPCM_GLOMDESC(&dptr[SDPCM_FRAMETAG_LEN])) {
5778 DHD_ERROR(("%s (superframe): got second descriptor?\n", __FUNCTION__));
5780 } else if ((doff < SDPCM_HDRLEN) ||
5781 (doff > (PKTLEN(osh, pfirst) - SDPCM_HDRLEN))) {
5782 DHD_ERROR(("%s (superframe): Bad data offset %d: HW %d pkt %d min %d\n",
5783 __FUNCTION__, doff, sublen, PKTLEN(osh, pfirst),
5788 /* Check sequence number of superframe SW header */
5790 DHD_INFO(("%s: (superframe) rx_seq %d, expected %d\n",
5791 __FUNCTION__, seq, rxseq));
5796 /* Check window for sanity */
5797 if ((uint8)(txmax - bus->tx_seq) > 0x70) {
5798 DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
5799 __FUNCTION__, txmax, bus->tx_seq));
5800 txmax = bus->tx_max;
5802 bus->tx_max = txmax;
5804 /* Remove superframe header, remember offset */
5805 PKTPULL(osh, pfirst, doff);
5808 /* Validate all the subframe headers */
5809 for (num = 0, pnext = pfirst; pnext && !errcode;
5810 num++, pnext = PKTNEXT(osh, pnext)) {
5811 dptr = (uint8 *)PKTDATA(osh, pnext);
5812 dlen = (uint16)PKTLEN(osh, pnext);
5813 sublen = ltoh16_ua(dptr);
5814 check = ltoh16_ua(dptr + sizeof(uint16));
5815 chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
5816 doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
5818 if (DHD_GLOM_ON()) {
5819 prhex("subframe", dptr, 32);
5823 if ((uint16)~(sublen^check)) {
5824 DHD_ERROR(("%s (subframe %d): HW hdr error: "
5825 "len/check 0x%04x/0x%04x\n",
5826 __FUNCTION__, num, sublen, check));
5828 } else if ((sublen > dlen) || (sublen < SDPCM_HDRLEN)) {
5829 DHD_ERROR(("%s (subframe %d): length mismatch: "
5830 "len 0x%04x, expect 0x%04x\n",
5831 __FUNCTION__, num, sublen, dlen));
5833 } else if ((chan != SDPCM_DATA_CHANNEL) &&
5834 (chan != SDPCM_EVENT_CHANNEL)) {
5835 DHD_ERROR(("%s (subframe %d): bad channel %d\n",
5836 __FUNCTION__, num, chan));
5838 } else if ((doff < SDPCM_HDRLEN) || (doff > sublen)) {
5839 DHD_ERROR(("%s (subframe %d): Bad data offset %d: HW %d min %d\n",
5840 __FUNCTION__, num, doff, sublen, SDPCM_HDRLEN));
5846 /* Terminate frame on error, request a couple retries */
5847 if (bus->glomerr++ < 3) {
5848 /* Restore superframe header space */
5849 PKTPUSH(osh, pfirst, sfdoff);
5850 dhdsdio_rxfail(bus, TRUE, TRUE);
5853 dhdsdio_rxfail(bus, TRUE, FALSE);
5854 dhd_os_sdlock_rxq(bus->dhd);
5855 PKTFREE(osh, bus->glom, FALSE);
5856 dhd_os_sdunlock_rxq(bus->dhd);
5864 /* Basic SD framing looks ok - process each packet (header) */
5868 dhd_os_sdlock_rxq(bus->dhd);
5869 for (num = 0; pfirst; rxseq++, pfirst = pnext) {
5870 pnext = PKTNEXT(osh, pfirst);
5871 PKTSETNEXT(osh, pfirst, NULL);
5873 dptr = (uint8 *)PKTDATA(osh, pfirst);
5874 sublen = ltoh16_ua(dptr);
5875 chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
5876 seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
5877 doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
5879 DHD_GLOM(("%s: Get subframe %d, %p(%p/%d), sublen %d chan %d seq %d\n",
5880 __FUNCTION__, num, pfirst, PKTDATA(osh, pfirst),
5881 PKTLEN(osh, pfirst), sublen, chan, seq));
5883 ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL));
5886 DHD_GLOM(("%s: rx_seq %d, expected %d\n",
5887 __FUNCTION__, seq, rxseq));
5893 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
5894 prhex("Rx Subframe Data", dptr, dlen);
5898 PKTSETLEN(osh, pfirst, sublen);
5899 PKTPULL(osh, pfirst, doff);
5901 reorder_info_len = sizeof(reorder_info_buf);
5903 if (PKTLEN(osh, pfirst) == 0) {
5904 PKTFREE(bus->dhd->osh, pfirst, FALSE);
5906 } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pfirst, reorder_info_buf,
5907 &reorder_info_len) != 0) {
5908 DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__));
5909 bus->dhd->rx_errors++;
5910 PKTFREE(osh, pfirst, FALSE);
5913 if (reorder_info_len) {
5914 uint32 free_buf_count;
5918 /* Reordering info from the firmware */
5919 dhd_process_pkt_reorder_info(bus->dhd, reorder_info_buf,
5920 reorder_info_len, &ppfirst, &free_buf_count);
5922 if (free_buf_count == 0) {
5928 /* go to the end of the chain and attach the pnext there */
5930 while (PKTNEXT(osh, temp) != NULL) {
5931 temp = PKTNEXT(osh, temp);
5934 if (list_tail[ifidx] == NULL)
5935 list_head[ifidx] = ppfirst;
5937 PKTSETNEXT(osh, list_tail[ifidx], ppfirst);
5938 list_tail[ifidx] = pfirst;
5941 num += (uint8)free_buf_count;
5944 /* this packet will go up, link back into chain and count it */
5946 if (list_tail[ifidx] == NULL) {
5947 list_head[ifidx] = list_tail[ifidx] = pfirst;
5950 PKTSETNEXT(osh, list_tail[ifidx], pfirst);
5951 list_tail[ifidx] = pfirst;
5956 if (DHD_GLOM_ON()) {
5957 DHD_GLOM(("%s subframe %d to stack, %p(%p/%d) nxt/lnk %p/%p\n",
5958 __FUNCTION__, num, pfirst,
5959 PKTDATA(osh, pfirst), PKTLEN(osh, pfirst),
5960 PKTNEXT(osh, pfirst), PKTLINK(pfirst)));
5961 prhex("", (uint8 *)PKTDATA(osh, pfirst),
5962 MIN(PKTLEN(osh, pfirst), 32));
5964 #endif /* DHD_DEBUG */
5966 dhd_os_sdunlock_rxq(bus->dhd);
5968 for (idx = 0; idx < DHD_MAX_IFS; idx++) {
5969 if (list_head[idx]) {
5972 temp = list_head[idx];
5974 temp = PKTNEXT(osh, temp);
5978 dhd_os_sdunlock(bus->dhd);
5979 dhd_rx_frame(bus->dhd, idx, list_head[idx], cnt, 0);
5980 dhd_os_sdlock(bus->dhd);
5984 bus->rxglomframes++;
5985 bus->rxglompkts += num;
5991 /* Return TRUE if there may be more frames to read */
5993 dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished)
5995 osl_t *osh = bus->dhd->osh;
5996 bcmsdh_info_t *sdh = bus->sdh;
5998 uint16 len, check; /* Extracted hardware header fields */
5999 uint8 chan, seq, doff; /* Extracted software header fields */
6000 uint8 fcbits; /* Extracted fcbits from software header */
6003 void *pkt; /* Packet for event or data frames */
6004 uint16 pad; /* Number of pad bytes to read */
6005 uint16 rdlen; /* Total number of bytes to read */
6006 uint8 rxseq; /* Next sequence number to expect */
6007 uint rxleft = 0; /* Remaining number of frames allowed */
6008 int sdret; /* Return code from bcmsdh calls */
6009 uint8 txmax; /* Maximum tx sequence offered */
6010 bool len_consistent; /* Result of comparing readahead len and len from hw-hdr */
6013 uint rxcount = 0; /* Total frames read */
6014 uchar reorder_info_buf[WLHOST_REORDERDATA_TOTLEN];
6015 uint reorder_info_len;
6018 #if defined(DHD_DEBUG) || defined(SDTEST)
6019 bool sdtest = FALSE; /* To limit message spew from test mode */
6022 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
6024 bus->readframes = TRUE;
6026 if (!KSO_ENAB(bus)) {
6027 DHD_ERROR(("%s: KSO off\n", __FUNCTION__));
6028 bus->readframes = FALSE;
6035 /* Allow pktgen to override maxframes */
6036 if (bus->pktgen_count && (bus->pktgen_mode == DHD_PKTGEN_RECV)) {
6037 maxframes = bus->pktgen_count;
6042 /* Not finished unless we encounter no more frames indication */
6046 for (rxseq = bus->rx_seq, rxleft = maxframes;
6047 !bus->rxskip && rxleft && bus->dhd->busstate != DHD_BUS_DOWN;
6048 rxseq++, rxleft--) {
6049 #ifdef DHDTCPACK_SUP_DBG
6050 if (bus->dhd->tcpack_sup_mode != TCPACK_SUP_DELAYTX) {
6051 if (bus->dotxinrx == FALSE)
6052 DHD_ERROR(("%s %d: dotxinrx FALSE with tcpack_sub_mode %d\n",
6053 __FUNCTION__, __LINE__, bus->dhd->tcpack_sup_mode));
6055 #ifdef DEBUG_COUNTER
6056 else if (pktq_mlen(&bus->txq, ~bus->flowcontrol) > 0) {
6057 tack_tbl.cnt[bus->dotxinrx ? 6 : 7]++;
6059 #endif /* DEBUG_COUNTER */
6060 #endif /* DHDTCPACK_SUP_DBG */
6061 /* tx more to improve rx performance */
6062 if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL)) {
6063 dhdsdio_sendpendctl(bus);
6064 } else if (bus->dotxinrx && (bus->clkstate == CLK_AVAIL) &&
6065 !bus->fcstate && DATAOK(bus) &&
6066 (pktq_mlen(&bus->txq, ~bus->flowcontrol) > bus->txinrx_thres) &&
6067 bus->dhd->conf->tx_in_rx) {
6068 #if defined(SWTXGLOM)
6069 if (bus->dhd->conf->swtxglom)
6070 dhdsdio_sendfromq_swtxglom(bus, dhd_txbound);
6073 dhdsdio_sendfromq(bus, dhd_txbound);
6074 #ifdef DHDTCPACK_SUPPRESS
6075 /* In TCPACK_SUP_DELAYTX mode, do txinrx only if
6076 * 1. Any DATA packet to TX
6077 * 2. TCPACK to TCPDATA PSH packets.
6080 bus->dotxinrx = (bus->dhd->tcpack_sup_mode == TCPACK_SUP_DELAYTX) ?
6085 /* Handle glomming separately */
6086 if (bus->glom || bus->glomd) {
6088 DHD_GLOM(("%s: calling rxglom: glomd %p, glom %p\n",
6089 __FUNCTION__, bus->glomd, bus->glom));
6090 cnt = dhdsdio_rxglom(bus, rxseq);
6091 DHD_GLOM(("%s: rxglom returned %d\n", __FUNCTION__, cnt));
6093 rxleft = (rxleft > cnt) ? (rxleft - cnt) : 1;
6097 /* Try doing single read if we can */
6098 if (dhd_readahead && bus->nextlen) {
6099 uint16 nextlen = bus->nextlen;
6102 if (bus->bus == SPI_BUS) {
6103 rdlen = len = nextlen;
6106 rdlen = len = nextlen << 4;
6108 /* Pad read to blocksize for efficiency */
6109 if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
6110 pad = bus->blocksize - (rdlen % bus->blocksize);
6111 if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
6112 ((rdlen + pad + firstread) < MAX_RX_DATASZ))
6114 } else if (rdlen % DHD_SDALIGN) {
6115 rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
6119 /* We use bus->rxctl buffer in WinXP for initial control pkt receives.
6120 * Later we use buffer-poll for data as well as control packets.
6121 * This is required because dhd receives full frame in gSPI unlike SDIO.
6122 * After the frame is received we have to distinguish whether it is data
6123 * or non-data frame.
6125 /* Allocate a packet buffer */
6126 dhd_os_sdlock_rxq(bus->dhd);
6127 if (!(pkt = PKTGET(osh, rdlen + DHD_SDALIGN, FALSE))) {
6128 if (bus->bus == SPI_BUS) {
6129 bus->usebufpool = FALSE;
6130 bus->rxctl = bus->rxbuf;
6132 bus->rxctl += firstread;
6133 if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN)))
6134 bus->rxctl += (DHD_SDALIGN - pad);
6135 bus->rxctl -= firstread;
6137 ASSERT(bus->rxctl >= bus->rxbuf);
6139 /* Read the entire frame */
6140 sdret = dhd_bcmsdh_recv_buf(bus,
6141 bcmsdh_cur_sbwad(sdh),
6143 F2SYNC, rxbuf, rdlen,
6146 ASSERT(sdret != BCME_PENDING);
6149 /* Control frame failures need retransmission */
6151 DHD_ERROR(("%s: read %d control bytes failed: %d\n",
6152 __FUNCTION__, rdlen, sdret));
6153 /* dhd.rx_ctlerrs is higher level */
6155 dhd_os_sdunlock_rxq(bus->dhd);
6156 dhdsdio_rxfail(bus, TRUE,
6157 (bus->bus == SPI_BUS) ? FALSE : TRUE);
6161 /* Give up on data, request rtx of events */
6162 DHD_ERROR(("%s (nextlen): PKTGET failed: len %d rdlen %d "
6163 "expected rxseq %d\n",
6164 __FUNCTION__, len, rdlen, rxseq));
6165 /* Just go try again w/normal header read */
6166 dhd_os_sdunlock_rxq(bus->dhd);
6170 if (bus->bus == SPI_BUS)
6171 bus->usebufpool = TRUE;
6173 ASSERT(!PKTLINK(pkt));
6174 PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN);
6175 rxbuf = (uint8 *)PKTDATA(osh, pkt);
6176 /* Read the entire frame */
6177 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh),
6179 F2SYNC, rxbuf, rdlen,
6182 ASSERT(sdret != BCME_PENDING);
6185 DHD_ERROR(("%s (nextlen): read %d bytes failed: %d\n",
6186 __FUNCTION__, rdlen, sdret));
6187 PKTFREE(bus->dhd->osh, pkt, FALSE);
6188 bus->dhd->rx_errors++;
6189 dhd_os_sdunlock_rxq(bus->dhd);
6190 /* Force retry w/normal header read. Don't attempt NAK for
6193 dhdsdio_rxfail(bus, TRUE,
6194 (bus->bus == SPI_BUS) ? FALSE : TRUE);
6198 dhd_os_sdunlock_rxq(bus->dhd);
6200 /* Now check the header */
6201 bcopy(rxbuf, bus->rxhdr, SDPCM_HDRLEN);
6203 /* Extract hardware header fields */
6204 len = ltoh16_ua(bus->rxhdr);
6205 check = ltoh16_ua(bus->rxhdr + sizeof(uint16));
6207 /* All zeros means readahead info was bad */
6209 DHD_INFO(("%s (nextlen): read zeros in HW header???\n",
6211 dhd_os_sdlock_rxq(bus->dhd);
6213 dhd_os_sdunlock_rxq(bus->dhd);
6214 GSPI_PR55150_BAILOUT;
6218 /* Validate check bytes */
6219 if ((uint16)~(len^check)) {
6220 DHD_ERROR(("%s (nextlen): HW hdr error: nextlen/len/check"
6221 " 0x%04x/0x%04x/0x%04x\n", __FUNCTION__, nextlen,
6223 dhd_os_sdlock_rxq(bus->dhd);
6225 dhd_os_sdunlock_rxq(bus->dhd);
6227 dhdsdio_rxfail(bus, FALSE, FALSE);
6228 GSPI_PR55150_BAILOUT;
6232 /* Validate frame length */
6233 if (len < SDPCM_HDRLEN) {
6234 DHD_ERROR(("%s (nextlen): HW hdr length invalid: %d\n",
6235 __FUNCTION__, len));
6236 dhd_os_sdlock_rxq(bus->dhd);
6238 dhd_os_sdunlock_rxq(bus->dhd);
6239 GSPI_PR55150_BAILOUT;
6243 /* Check for consistency with readahead info */
6244 len_consistent = (nextlen != (ROUNDUP(len, 16) >> 4));
6245 if (len_consistent) {
6246 /* Mismatch, force retry w/normal header (may be >4K) */
6247 DHD_ERROR(("%s (nextlen): mismatch, nextlen %d len %d rnd %d; "
6248 "expected rxseq %d\n",
6249 __FUNCTION__, nextlen, len, ROUNDUP(len, 16), rxseq));
6250 dhd_os_sdlock_rxq(bus->dhd);
6252 dhd_os_sdunlock_rxq(bus->dhd);
6253 dhdsdio_rxfail(bus, TRUE, (bus->bus == SPI_BUS) ? FALSE : TRUE);
6254 GSPI_PR55150_BAILOUT;
6259 /* Extract software header fields */
6260 chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
6261 seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
6262 doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
6263 txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
6266 bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
6267 if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
6268 DHD_INFO(("%s (nextlen): got frame w/nextlen too large"
6269 " (%d), seq %d\n", __FUNCTION__, bus->nextlen,
6274 bus->dhd->rx_readahead_cnt ++;
6275 /* Handle Flow Control */
6276 fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
6279 if (~bus->flowcontrol & fcbits) {
6283 if (bus->flowcontrol & ~fcbits) {
6290 bus->flowcontrol = fcbits;
6293 /* Check and update sequence number */
6295 DHD_INFO(("%s (nextlen): rx_seq %d, expected %d\n",
6296 __FUNCTION__, seq, rxseq));
6301 /* Check window for sanity */
6302 if ((uint8)(txmax - bus->tx_seq) > 0x70) {
6303 DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
6304 __FUNCTION__, txmax, bus->tx_seq));
6305 txmax = bus->tx_max;
6307 bus->tx_max = txmax;
6310 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
6311 prhex("Rx Data", rxbuf, len);
6312 } else if (DHD_HDRS_ON()) {
6313 prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN);
6317 if (chan == SDPCM_CONTROL_CHANNEL) {
6318 if (bus->bus == SPI_BUS) {
6319 dhdsdio_read_control(bus, rxbuf, len, doff);
6320 if (bus->usebufpool) {
6321 dhd_os_sdlock_rxq(bus->dhd);
6322 PKTFREE(bus->dhd->osh, pkt, FALSE);
6323 dhd_os_sdunlock_rxq(bus->dhd);
6327 DHD_ERROR(("%s (nextlen): readahead on control"
6328 " packet %d?\n", __FUNCTION__, seq));
6329 /* Force retry w/normal header read */
6331 dhdsdio_rxfail(bus, FALSE, TRUE);
6332 dhd_os_sdlock_rxq(bus->dhd);
6334 dhd_os_sdunlock_rxq(bus->dhd);
6339 if ((bus->bus == SPI_BUS) && !bus->usebufpool) {
6340 DHD_ERROR(("Received %d bytes on %d channel. Running out of "
6341 "rx pktbuf's or not yet malloced.\n", len, chan));
6345 /* Validate data offset */
6346 if ((doff < SDPCM_HDRLEN) || (doff > len)) {
6347 DHD_ERROR(("%s (nextlen): bad data offset %d: HW len %d min %d\n",
6348 __FUNCTION__, doff, len, SDPCM_HDRLEN));
6349 dhd_os_sdlock_rxq(bus->dhd);
6351 dhd_os_sdunlock_rxq(bus->dhd);
6353 dhdsdio_rxfail(bus, FALSE, FALSE);
6357 /* All done with this one -- now deliver the packet */
6360 /* gSPI frames should not be handled in fractions */
6361 if (bus->bus == SPI_BUS) {
6365 /* Read frame header (hardware and software) */
6366 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
6367 bus->rxhdr, firstread, NULL, NULL, NULL);
6369 ASSERT(sdret != BCME_PENDING);
6372 DHD_ERROR(("%s: RXHEADER FAILED: %d\n", __FUNCTION__, sdret));
6374 dhdsdio_rxfail(bus, TRUE, TRUE);
6379 if (DHD_BYTES_ON() || DHD_HDRS_ON()) {
6380 prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN);
6384 /* Extract hardware header fields */
6385 len = ltoh16_ua(bus->rxhdr);
6386 check = ltoh16_ua(bus->rxhdr + sizeof(uint16));
6388 /* All zeros means no more frames */
6394 /* Validate check bytes */
6395 if ((uint16)~(len^check)) {
6396 DHD_ERROR(("%s: HW hdr error: len/check 0x%04x/0x%04x\n",
6397 __FUNCTION__, len, check));
6399 dhdsdio_rxfail(bus, FALSE, FALSE);
6403 /* Validate frame length */
6404 if (len < SDPCM_HDRLEN) {
6405 DHD_ERROR(("%s: HW hdr length invalid: %d\n", __FUNCTION__, len));
6409 /* Extract software header fields */
6410 chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
6411 seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
6412 doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
6413 txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
6415 /* Validate data offset */
6416 if ((doff < SDPCM_HDRLEN) || (doff > len)) {
6417 DHD_ERROR(("%s: Bad data offset %d: HW len %d, min %d seq %d\n",
6418 __FUNCTION__, doff, len, SDPCM_HDRLEN, seq));
6421 dhdsdio_rxfail(bus, FALSE, FALSE);
6425 /* Save the readahead length if there is one */
6426 bus->nextlen = bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
6427 if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
6428 DHD_INFO(("%s (nextlen): got frame w/nextlen too large (%d), seq %d\n",
6429 __FUNCTION__, bus->nextlen, seq));
6433 /* Handle Flow Control */
6434 fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
6437 if (~bus->flowcontrol & fcbits) {
6441 if (bus->flowcontrol & ~fcbits) {
6448 bus->flowcontrol = fcbits;
6451 /* Check and update sequence number */
6453 DHD_INFO(("%s: rx_seq %d, expected %d\n", __FUNCTION__, seq, rxseq));
6458 /* Check window for sanity */
6459 if ((uint8)(txmax - bus->tx_seq) > 0x70) {
6460 DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
6461 __FUNCTION__, txmax, bus->tx_seq));
6462 txmax = bus->tx_max;
6464 bus->tx_max = txmax;
6466 /* Call a separate function for control frames */
6467 if (chan == SDPCM_CONTROL_CHANNEL) {
6468 dhdsdio_read_control(bus, bus->rxhdr, len, doff);
6472 ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL) ||
6473 (chan == SDPCM_TEST_CHANNEL) || (chan == SDPCM_GLOM_CHANNEL));
6475 /* Length to read */
6476 rdlen = (len > firstread) ? (len - firstread) : 0;
6478 /* May pad read to blocksize for efficiency */
6479 if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
6480 pad = bus->blocksize - (rdlen % bus->blocksize);
6481 if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
6482 ((rdlen + pad + firstread) < MAX_RX_DATASZ))
6484 } else if (rdlen % DHD_SDALIGN) {
6485 rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
6488 /* Satisfy length-alignment requirements */
6489 if (forcealign && (rdlen & (ALIGNMENT - 1)))
6490 rdlen = ROUNDUP(rdlen, ALIGNMENT);
6492 if ((rdlen + firstread) > MAX_RX_DATASZ) {
6493 /* Too long -- skip this frame */
6494 DHD_ERROR(("%s: too long: len %d rdlen %d\n", __FUNCTION__, len, rdlen));
6495 bus->dhd->rx_errors++; bus->rx_toolong++;
6496 dhdsdio_rxfail(bus, FALSE, FALSE);
6500 dhd_os_sdlock_rxq(bus->dhd);
6501 if (!(pkt = PKTGET(osh, (rdlen + firstread + DHD_SDALIGN), FALSE))) {
6502 /* Give up on data, request rtx of events */
6503 DHD_ERROR(("%s: PKTGET failed: rdlen %d chan %d\n",
6504 __FUNCTION__, rdlen, chan));
6505 bus->dhd->rx_dropped++;
6506 dhd_os_sdunlock_rxq(bus->dhd);
6507 dhdsdio_rxfail(bus, FALSE, RETRYCHAN(chan));
6510 dhd_os_sdunlock_rxq(bus->dhd);
6512 ASSERT(!PKTLINK(pkt));
6514 /* Leave room for what we already read, and align remainder */
6515 ASSERT(firstread < (PKTLEN(osh, pkt)));
6516 PKTPULL(osh, pkt, firstread);
6517 PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN);
6519 /* Read the remaining frame data */
6520 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
6521 ((uint8 *)PKTDATA(osh, pkt)), rdlen, pkt, NULL, NULL);
6523 ASSERT(sdret != BCME_PENDING);
6526 DHD_ERROR(("%s: read %d %s bytes failed: %d\n", __FUNCTION__, rdlen,
6527 ((chan == SDPCM_EVENT_CHANNEL) ? "event" :
6528 ((chan == SDPCM_DATA_CHANNEL) ? "data" : "test")), sdret));
6529 dhd_os_sdlock_rxq(bus->dhd);
6530 PKTFREE(bus->dhd->osh, pkt, FALSE);
6531 dhd_os_sdunlock_rxq(bus->dhd);
6532 bus->dhd->rx_errors++;
6533 dhdsdio_rxfail(bus, TRUE, RETRYCHAN(chan));
6537 /* Copy the already-read portion */
6538 PKTPUSH(osh, pkt, firstread);
6539 bcopy(bus->rxhdr, PKTDATA(osh, pkt), firstread);
6542 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
6543 prhex("Rx Data", PKTDATA(osh, pkt), len);
6548 /* Save superframe descriptor and allocate packet frame */
6549 if (chan == SDPCM_GLOM_CHANNEL) {
6550 if (SDPCM_GLOMDESC(&bus->rxhdr[SDPCM_FRAMETAG_LEN])) {
6551 DHD_GLOM(("%s: got glom descriptor, %d bytes:\n",
6552 __FUNCTION__, len));
6554 if (DHD_GLOM_ON()) {
6555 prhex("Glom Data", PKTDATA(osh, pkt), len);
6558 PKTSETLEN(osh, pkt, len);
6559 ASSERT(doff == SDPCM_HDRLEN);
6560 PKTPULL(osh, pkt, SDPCM_HDRLEN);
6563 DHD_ERROR(("%s: glom superframe w/o descriptor!\n", __FUNCTION__));
6564 dhdsdio_rxfail(bus, FALSE, FALSE);
6569 /* Fill in packet len and prio, deliver upward */
6570 PKTSETLEN(osh, pkt, len);
6571 PKTPULL(osh, pkt, doff);
6574 /* Test channel packets are processed separately */
6575 if (chan == SDPCM_TEST_CHANNEL) {
6576 dhdsdio_testrcv(bus, pkt, seq);
6581 if (PKTLEN(osh, pkt) == 0) {
6582 dhd_os_sdlock_rxq(bus->dhd);
6583 PKTFREE(bus->dhd->osh, pkt, FALSE);
6584 dhd_os_sdunlock_rxq(bus->dhd);
6586 } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pkt, reorder_info_buf,
6587 &reorder_info_len) != 0) {
6588 DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__));
6589 dhd_os_sdlock_rxq(bus->dhd);
6590 PKTFREE(bus->dhd->osh, pkt, FALSE);
6591 dhd_os_sdunlock_rxq(bus->dhd);
6592 bus->dhd->rx_errors++;
6595 if (reorder_info_len) {
6596 /* Reordering info from the firmware */
6597 dhd_process_pkt_reorder_info(bus->dhd, reorder_info_buf, reorder_info_len,
6605 /* Unlock during rx call */
6606 dhd_os_sdunlock(bus->dhd);
6607 dhd_rx_frame(bus->dhd, ifidx, pkt, pkt_count, chan);
6608 dhd_os_sdlock(bus->dhd);
6609 #if defined(SDIO_ISR_THREAD)
6610 /* terence 20150615: fix for below error due to bussleep in watchdog after dhd_os_sdunlock here,
6611 * so call BUS_WAKE to wake up bus again
6612 * dhd_bcmsdh_recv_buf: Device asleep
6613 * dhdsdio_readframes: RXHEADER FAILED: -40
6614 * dhdsdio_rxfail: abort command, terminate frame, send NAK
6619 rxcount = maxframes - rxleft;
6621 /* Message if we hit the limit */
6622 if (!rxleft && !sdtest)
6623 DHD_DATA(("%s: hit rx limit of %d frames\n", __FUNCTION__, maxframes));
6625 #endif /* DHD_DEBUG */
6626 DHD_DATA(("%s: processed %d frames\n", __FUNCTION__, rxcount));
6627 /* Back off rxseq if awaiting rtx, update rx_seq */
6630 bus->rx_seq = rxseq;
6632 if (bus->reqbussleep)
6634 dhdsdio_bussleep(bus, TRUE);
6635 bus->reqbussleep = FALSE;
6637 bus->readframes = FALSE;
6643 dhdsdio_hostmail(dhd_bus_t *bus)
6645 sdpcmd_regs_t *regs = bus->regs;
6646 uint32 intstatus = 0;
6651 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
6653 /* Read mailbox data and ack that we did so */
6654 R_SDREG(hmb_data, ®s->tohostmailboxdata, retries);
6655 if (retries <= retry_limit)
6656 W_SDREG(SMB_INT_ACK, ®s->tosbmailbox, retries);
6657 bus->f1regdata += 2;
6659 /* Dongle recomposed rx frames, accept them again */
6660 if (hmb_data & HMB_DATA_NAKHANDLED) {
6661 DHD_INFO(("Dongle reports NAK handled, expect rtx of %d\n", bus->rx_seq));
6663 DHD_ERROR(("%s: unexpected NAKHANDLED!\n", __FUNCTION__));
6665 bus->rxskip = FALSE;
6666 intstatus |= FRAME_AVAIL_MASK(bus);
6670 * DEVREADY does not occur with gSPI.
6672 if (hmb_data & (HMB_DATA_DEVREADY | HMB_DATA_FWREADY)) {
6673 bus->sdpcm_ver = (hmb_data & HMB_DATA_VERSION_MASK) >> HMB_DATA_VERSION_SHIFT;
6674 if (bus->sdpcm_ver != SDPCM_PROT_VERSION)
6675 DHD_ERROR(("Version mismatch, dongle reports %d, expecting %d\n",
6676 bus->sdpcm_ver, SDPCM_PROT_VERSION));
6678 DHD_INFO(("Dongle ready, protocol version %d\n", bus->sdpcm_ver));
6679 /* make sure for the SDIO_DEVICE_RXDATAINT_MODE_1 corecontrol is proper */
6680 if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev >= 4) &&
6681 (bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_1)) {
6684 val = R_REG(bus->dhd->osh, &bus->regs->corecontrol);
6685 val &= ~CC_XMTDATAAVAIL_MODE;
6686 val |= CC_XMTDATAAVAIL_CTRL;
6687 W_REG(bus->dhd->osh, &bus->regs->corecontrol, val);
6689 val = R_REG(bus->dhd->osh, &bus->regs->corecontrol);
6693 /* Retrieve console state address now that firmware should have updated it */
6695 sdpcm_shared_t shared;
6696 if (dhdsdio_readshared(bus, &shared) == 0)
6697 bus->console_addr = shared.console_addr;
6699 #endif /* DHD_DEBUG */
6703 * Flow Control has been moved into the RX headers and this out of band
6704 * method isn't used any more. Leave this here for possibly remaining backward
6705 * compatible with older dongles
6707 if (hmb_data & HMB_DATA_FC) {
6708 fcbits = (hmb_data & HMB_DATA_FCDATA_MASK) >> HMB_DATA_FCDATA_SHIFT;
6710 if (fcbits & ~bus->flowcontrol)
6712 if (bus->flowcontrol & ~fcbits)
6716 bus->flowcontrol = fcbits;
6719 /* At least print a message if FW halted */
6720 if (hmb_data & HMB_DATA_FWHALT) {
6721 DHD_ERROR(("INTERNAL ERROR: FIRMWARE HALTED : set BUS DOWN\n"));
6722 dhdsdio_checkdied(bus, NULL, 0);
6723 bus->dhd->busstate = DHD_BUS_DOWN;
6726 /* Shouldn't be any others */
6727 if (hmb_data & ~(HMB_DATA_DEVREADY |
6729 HMB_DATA_NAKHANDLED |
6732 HMB_DATA_FCDATA_MASK |
6733 HMB_DATA_VERSION_MASK)) {
6734 DHD_ERROR(("Unknown mailbox data content: 0x%02x\n", hmb_data));
6741 dhdsdio_dpc(dhd_bus_t *bus)
6743 bcmsdh_info_t *sdh = bus->sdh;
6744 sdpcmd_regs_t *regs = bus->regs;
6745 uint32 intstatus, newstatus = 0;
6747 uint rxlimit = dhd_rxbound; /* Rx frames to read before resched */
6748 uint txlimit = dhd_txbound; /* Tx frames to send before resched */
6749 uint framecnt = 0; /* Temporary counter of tx/rx frames */
6750 bool rxdone = TRUE; /* Flag for no more read data */
6751 bool resched = FALSE; /* Flag indicating resched wanted */
6752 #ifdef DEBUG_DPC_THREAD_WATCHDOG
6753 bool is_resched_by_readframe = FALSE;
6754 #endif /* DEBUG_DPC_THREAD_WATCHDOG */
6755 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
6757 dhd_os_sdlock(bus->dhd);
6759 if (bus->dhd->busstate == DHD_BUS_DOWN) {
6760 DHD_ERROR(("%s: Bus down, ret\n", __FUNCTION__));
6762 dhd_os_sdunlock(bus->dhd);
6766 /* Start with leftover status bits */
6767 intstatus = bus->intstatus;
6769 if (!SLPAUTO_ENAB(bus) && !KSO_ENAB(bus)) {
6770 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
6774 /* If waiting for HTAVAIL, check status */
6775 if (!SLPAUTO_ENAB(bus) && (bus->clkstate == CLK_PENDING)) {
6777 uint8 clkctl, devctl = 0;
6780 /* Check for inconsistent device control */
6781 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
6783 DHD_ERROR(("%s: error reading DEVCTL: %d\n", __FUNCTION__, err));
6784 bus->dhd->busstate = DHD_BUS_DOWN;
6786 ASSERT(devctl & SBSDIO_DEVCTL_CA_INT_ONLY);
6788 #endif /* DHD_DEBUG */
6790 /* Read CSR, if clock on switch to AVAIL, else ignore */
6791 clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
6793 DHD_ERROR(("%s: error reading CSR: %d\n", __FUNCTION__, err));
6794 bus->dhd->busstate = DHD_BUS_DOWN;
6797 DHD_INFO(("DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n", devctl, clkctl));
6799 if (SBSDIO_HTAV(clkctl)) {
6800 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
6802 DHD_ERROR(("%s: error reading DEVCTL: %d\n",
6803 __FUNCTION__, err));
6804 bus->dhd->busstate = DHD_BUS_DOWN;
6806 devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
6807 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
6809 DHD_ERROR(("%s: error writing DEVCTL: %d\n",
6810 __FUNCTION__, err));
6811 bus->dhd->busstate = DHD_BUS_DOWN;
6813 bus->clkstate = CLK_AVAIL;
6821 /* Make sure backplane clock is on */
6822 dhdsdio_clkctl(bus, CLK_AVAIL, TRUE);
6823 if (bus->clkstate != CLK_AVAIL)
6826 /* Pending interrupt indicates new device status */
6829 R_SDREG(newstatus, ®s->intstatus, retries);
6831 if (bcmsdh_regfail(bus->sdh))
6833 newstatus &= bus->hostintmask;
6834 bus->fcstate = !!(newstatus & I_HMB_FC_STATE);
6837 if ((bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_0) &&
6838 (newstatus == I_XMTDATA_AVAIL)) {
6841 W_SDREG(newstatus, ®s->intstatus, retries);
6845 /* Merge new bits with previous */
6846 intstatus |= newstatus;
6849 /* Handle flow-control change: read new state in case our ack
6850 * crossed another change interrupt. If change still set, assume
6851 * FC ON for safety, let next loop through do the debounce.
6853 if (intstatus & I_HMB_FC_CHANGE) {
6854 intstatus &= ~I_HMB_FC_CHANGE;
6855 W_SDREG(I_HMB_FC_CHANGE, ®s->intstatus, retries);
6856 R_SDREG(newstatus, ®s->intstatus, retries);
6857 bus->f1regdata += 2;
6858 bus->fcstate = !!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE));
6859 intstatus |= (newstatus & bus->hostintmask);
6862 /* Just being here means nothing more to do for chipactive */
6863 if (intstatus & I_CHIPACTIVE) {
6864 /* ASSERT(bus->clkstate == CLK_AVAIL); */
6865 intstatus &= ~I_CHIPACTIVE;
6868 /* Handle host mailbox indication */
6869 if (intstatus & I_HMB_HOST_INT) {
6870 intstatus &= ~I_HMB_HOST_INT;
6871 intstatus |= dhdsdio_hostmail(bus);
6874 /* Generally don't ask for these, can get CRC errors... */
6875 if (intstatus & I_WR_OOSYNC) {
6876 DHD_ERROR(("Dongle reports WR_OOSYNC\n"));
6877 intstatus &= ~I_WR_OOSYNC;
6880 if (intstatus & I_RD_OOSYNC) {
6881 DHD_ERROR(("Dongle reports RD_OOSYNC\n"));
6882 intstatus &= ~I_RD_OOSYNC;
6885 if (intstatus & I_SBINT) {
6886 DHD_ERROR(("Dongle reports SBINT\n"));
6887 intstatus &= ~I_SBINT;
6890 /* Would be active due to wake-wlan in gSPI */
6891 if (intstatus & I_CHIPACTIVE) {
6892 DHD_INFO(("Dongle reports CHIPACTIVE\n"));
6893 intstatus &= ~I_CHIPACTIVE;
6896 if (intstatus & I_HMB_FC_STATE) {
6897 DHD_INFO(("Dongle reports HMB_FC_STATE\n"));
6898 intstatus &= ~I_HMB_FC_STATE;
6901 /* Ignore frame indications if rxskip is set */
6903 intstatus &= ~FRAME_AVAIL_MASK(bus);
6906 /* On frame indication, read available frames */
6907 if (PKT_AVAILABLE(bus, intstatus)) {
6908 framecnt = dhdsdio_readframes(bus, rxlimit, &rxdone);
6909 if (rxdone || bus->rxskip)
6910 intstatus &= ~FRAME_AVAIL_MASK(bus);
6911 rxlimit -= MIN(framecnt, rxlimit);
6914 /* Keep still-pending events for next scheduling */
6915 bus->intstatus = intstatus;
6918 /* Re-enable interrupts to detect new device events (mailbox, rx frame)
6919 * or clock availability. (Allows tx loop to check ipend if desired.)
6920 * (Unless register access seems hosed, as we may not be able to ACK...)
6922 if (bus->intr && bus->intdis && !bcmsdh_regfail(sdh)) {
6923 DHD_INTR(("%s: enable SDIO interrupts, rxdone %d framecnt %d\n",
6924 __FUNCTION__, rxdone, framecnt));
6925 bus->intdis = FALSE;
6926 #if defined(OOB_INTR_ONLY)
6927 bcmsdh_oob_intr_set(bus->sdh, TRUE);
6928 #endif /* defined(OOB_INTR_ONLY) */
6929 bcmsdh_intr_enable(sdh);
6932 #if defined(OOB_INTR_ONLY) && !defined(HW_OOB)
6933 /* In case of SW-OOB(using edge trigger),
6934 * Check interrupt status in the dongle again after enable irq on the host.
6935 * and rechedule dpc if interrupt is pended in the dongle.
6936 * There is a chance to miss OOB interrupt while irq is disabled on the host.
6937 * No need to do this with HW-OOB(level trigger)
6939 R_SDREG(newstatus, ®s->intstatus, retries);
6940 if (bcmsdh_regfail(bus->sdh))
6942 if (newstatus & bus->hostintmask) {
6946 #endif /* defined(OOB_INTR_ONLY) && !defined(HW_OOB) */
6948 #ifdef PROP_TXSTATUS
6949 dhd_wlfc_commit_packets(bus->dhd, (f_commitpkt_t)dhd_bus_txdata, (void *)bus, NULL, FALSE);
6952 if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL))
6953 dhdsdio_sendpendctl(bus);
6955 /* Send queued frames (limit 1 if rx may still be pending) */
6956 else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate &&
6957 pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit && DATAOK(bus)) {
6958 framecnt = rxdone ? txlimit : MIN(txlimit, dhd_txminmax);
6959 #if defined(SWTXGLOM)
6960 if (bus->dhd->conf->swtxglom)
6961 framecnt = dhdsdio_sendfromq_swtxglom(bus, framecnt);
6964 framecnt = dhdsdio_sendfromq(bus, framecnt);
6965 txlimit -= framecnt;
6967 /* Resched the DPC if ctrl cmd is pending on bus credit */
6968 if (bus->ctrl_frame_stat) {
6969 if (bus->dhd->conf->txctl_tmo_fix) {
6970 set_current_state(TASK_INTERRUPTIBLE);
6971 if (!kthread_should_stop())
6972 schedule_timeout(1);
6973 set_current_state(TASK_RUNNING);
6978 /* Resched if events or tx frames are pending, else await next interrupt */
6979 /* On failed register access, all bets are off: no resched or interrupts */
6980 if ((bus->dhd->busstate == DHD_BUS_DOWN) || bcmsdh_regfail(sdh)) {
6981 if ((bus->sih && bus->sih->buscorerev >= 12) && !(dhdsdio_sleepcsr_get(bus) &
6982 SBSDIO_FUNC1_SLEEPCSR_KSO_MASK)) {
6983 /* Bus failed because of KSO */
6984 DHD_ERROR(("%s: Bus failed due to KSO\n", __FUNCTION__));
6987 DHD_ERROR(("%s: failed backplane access over SDIO, halting operation\n",
6989 bus->dhd->busstate = DHD_BUS_DOWN;
6992 } else if (bus->clkstate == CLK_PENDING) {
6993 /* Awaiting I_CHIPACTIVE; don't resched */
6994 } else if (bus->intstatus || bus->ipend ||
6995 (!bus->fcstate && pktq_mlen(&bus->txq, ~bus->flowcontrol) && DATAOK(bus)) ||
6996 PKT_AVAILABLE(bus, bus->intstatus)) { /* Read multiple frames */
7000 bus->dpc_sched = resched;
7002 /* If we're done for now, turn off clock request. */
7003 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && (bus->clkstate != CLK_PENDING)) {
7004 bus->activity = FALSE;
7005 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
7010 if (!resched && dhd_dpcpoll) {
7011 if (dhdsdio_readframes(bus, dhd_rxbound, &rxdone) != 0) {
7013 #ifdef DEBUG_DPC_THREAD_WATCHDOG
7014 is_resched_by_readframe = TRUE;
7015 #endif /* DEBUG_DPC_THREAD_WATCHDOG */
7019 dhd_os_sdunlock(bus->dhd);
7020 #ifdef DEBUG_DPC_THREAD_WATCHDOG
7021 if (bus->dhd->dhd_bug_on) {
7022 DHD_INFO(("%s: resched = %d ctrl_frame_stat = %d intstatus 0x%08x"
7023 " ipend = %d pktq_mlen = %d is_resched_by_readframe = %d \n",
7024 __FUNCTION__, resched, bus->ctrl_frame_stat,
7025 bus->intstatus, bus->ipend,
7026 pktq_mlen(&bus->txq, ~bus->flowcontrol), is_resched_by_readframe));
7028 bus->dhd->dhd_bug_on = FALSE;
7030 #endif /* DEBUG_DPC_THREAD_WATCHDOG */
7035 dhd_bus_dpc(struct dhd_bus *bus)
7039 /* Call the DPC directly. */
7040 DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__));
7041 resched = dhdsdio_dpc(bus);
7047 dhdsdio_isr(void *arg)
7049 dhd_bus_t *bus = (dhd_bus_t*)arg;
7052 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7055 DHD_ERROR(("%s : bus is null pointer , exit \n", __FUNCTION__));
7060 if (bus->dhd->busstate == DHD_BUS_DOWN) {
7061 DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__));
7065 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7067 /* Count the interrupt call */
7071 /* Shouldn't get this interrupt if we're sleeping? */
7072 if (!SLPAUTO_ENAB(bus)) {
7073 if (bus->sleeping) {
7074 DHD_ERROR(("INTERRUPT WHILE SLEEPING??\n"));
7076 } else if (!KSO_ENAB(bus)) {
7077 DHD_ERROR(("ISR in devsleep 1\n"));
7081 /* Disable additional interrupts (is this needed now)? */
7083 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
7085 DHD_ERROR(("dhdsdio_isr() w/o interrupt configured!\n"));
7088 bcmsdh_intr_disable(sdh);
7091 #if defined(SDIO_ISR_THREAD)
7092 DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__));
7093 DHD_OS_WAKE_LOCK(bus->dhd);
7094 /* terence 20150209: dpc should be scheded again if dpc_sched is TRUE or dhd_bus_txdata can
7095 not schedule anymore because dpc_sched is TRUE now.
7097 if (dhdsdio_dpc(bus)) {
7098 bus->dpc_sched = TRUE;
7099 dhd_sched_dpc(bus->dhd);
7101 DHD_OS_WAKE_UNLOCK(bus->dhd);
7103 bus->dpc_sched = TRUE;
7104 dhd_sched_dpc(bus->dhd);
7106 #endif /* defined(SDIO_ISR_THREAD) */
7111 void dhdsdio_txpktstatics(void)
7113 uint total, f1, f2, f3, f4;
7114 printf("Randy: TYPE EVENT: %d pkts (size=%d) transfered\n", tx_statics.event_count, tx_statics.event_size);
7115 printf("Randy: TYPE CTRL: %d pkts (size=%d) transfered\n", tx_statics.ctrl_count, tx_statics.ctrl_size);
7116 printf("Randy: TYPE DATA: %d pkts (size=%d) transfered\n", tx_statics.data_count, tx_statics.data_size);
7117 if(tx_statics.glom_1_count || tx_statics.glom_3_count || tx_statics.glom_3_8_count || tx_statics.glom_8_count) {
7118 total = tx_statics.glom_1_count + tx_statics.glom_3_count + tx_statics.glom_3_8_count + tx_statics.glom_8_count;
7119 f1 = (tx_statics.glom_1_count*100) / total;
7120 f2 = (tx_statics.glom_3_count*100) / total;
7121 f3 = (tx_statics.glom_3_8_count*100) / total;
7122 f4 = (tx_statics.glom_8_count*100) / total;
7123 printf("Randy: glomsize==1: %d(%d), tglomsize==2: %d(%d), pkts 3<=glomsize<8: %d(%d), pkts glomszie>=8: %d(%d)\n",
7124 tx_statics.glom_1_count, f1, tx_statics.glom_3_count, f2, tx_statics.glom_3_8_count, f3, tx_statics.glom_8_count, f4);
7125 printf("Randy: data/glom=%d, glom_max=%d\n", tx_statics.data_count/total, tx_statics.glom_max);
7127 printf("Randy: TYPE RX GLOM: %d pkts (size=%d) transfered\n", tx_statics.glom_count, tx_statics.glom_size);
7128 printf("Randy: TYPE TEST: %d pkts (size=%d) transfered\n\n\n", tx_statics.test_count, tx_statics.test_size);
7134 dhdsdio_pktgen_init(dhd_bus_t *bus)
7136 /* Default to specified length, or full range */
7137 if (dhd_pktgen_len) {
7138 bus->pktgen_maxlen = MIN(dhd_pktgen_len, MAX_PKTGEN_LEN);
7139 bus->pktgen_minlen = bus->pktgen_maxlen;
7141 bus->pktgen_maxlen = MAX_PKTGEN_LEN;
7142 bus->pktgen_minlen = 0;
7144 bus->pktgen_len = (uint16)bus->pktgen_minlen;
7146 /* Default to per-watchdog burst with 10s print time */
7147 bus->pktgen_freq = 1;
7148 bus->pktgen_print = dhd_watchdog_ms ? (10000 / dhd_watchdog_ms) : 0;
7149 bus->pktgen_count = (dhd_pktgen * dhd_watchdog_ms + 999) / 1000;
7151 /* Default to echo mode */
7152 bus->pktgen_mode = DHD_PKTGEN_ECHO;
7153 bus->pktgen_stop = 1;
7157 dhdsdio_pktgen(dhd_bus_t *bus)
7163 osl_t *osh = bus->dhd->osh;
7169 /* Display current count if appropriate */
7170 if (bus->pktgen_print && (++bus->pktgen_ptick >= bus->pktgen_print)) {
7171 bus->pktgen_ptick = 0;
7172 printf("%s: send attempts %d, rcvd %d, errors %d\n",
7173 __FUNCTION__, bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail);
7175 /* Print throughput stats only for constant length packet runs */
7176 if (bus->pktgen_minlen == bus->pktgen_maxlen) {
7177 time_lapse = jiffies - bus->pktgen_prev_time;
7178 bus->pktgen_prev_time = jiffies;
7179 sent_pkts = bus->pktgen_sent - bus->pktgen_prev_sent;
7180 bus->pktgen_prev_sent = bus->pktgen_sent;
7181 rcvd_pkts = bus->pktgen_rcvd - bus->pktgen_prev_rcvd;
7182 bus->pktgen_prev_rcvd = bus->pktgen_rcvd;
7184 printf("%s: Tx Throughput %d kbps, Rx Throughput %d kbps\n",
7186 (sent_pkts * bus->pktgen_len / jiffies_to_msecs(time_lapse)) * 8,
7187 (rcvd_pkts * bus->pktgen_len / jiffies_to_msecs(time_lapse)) * 8);
7191 /* For recv mode, just make sure dongle has started sending */
7192 if (bus->pktgen_mode == DHD_PKTGEN_RECV) {
7193 if (bus->pktgen_rcv_state == PKTGEN_RCV_IDLE) {
7194 bus->pktgen_rcv_state = PKTGEN_RCV_ONGOING;
7195 dhdsdio_sdtest_set(bus, bus->pktgen_total);
7200 /* Otherwise, generate or request the specified number of packets */
7201 for (pktcount = 0; pktcount < bus->pktgen_count; pktcount++) {
7202 /* Stop if total has been reached */
7203 if (bus->pktgen_total && (bus->pktgen_sent >= bus->pktgen_total)) {
7204 bus->pktgen_count = 0;
7208 /* Allocate an appropriate-sized packet */
7209 if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) {
7210 len = SDPCM_TEST_PKT_CNT_FLD_LEN;
7212 len = bus->pktgen_len;
7214 if (!(pkt = PKTGET(osh, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN),
7216 DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__));
7219 PKTALIGN(osh, pkt, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN), DHD_SDALIGN);
7220 data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
7222 /* Write test header cmd and extra based on mode */
7223 switch (bus->pktgen_mode) {
7224 case DHD_PKTGEN_ECHO:
7225 *data++ = SDPCM_TEST_ECHOREQ;
7226 *data++ = (uint8)bus->pktgen_sent;
7229 case DHD_PKTGEN_SEND:
7230 *data++ = SDPCM_TEST_DISCARD;
7231 *data++ = (uint8)bus->pktgen_sent;
7234 case DHD_PKTGEN_RXBURST:
7235 *data++ = SDPCM_TEST_BURST;
7236 *data++ = (uint8)bus->pktgen_count; /* Just for backward compatability */
7240 DHD_ERROR(("Unrecognized pktgen mode %d\n", bus->pktgen_mode));
7241 PKTFREE(osh, pkt, TRUE);
7242 bus->pktgen_count = 0;
7246 /* Write test header length field */
7247 *data++ = (bus->pktgen_len >> 0);
7248 *data++ = (bus->pktgen_len >> 8);
7250 /* Write frame count in a 4 byte field adjucent to SDPCM test header for
7253 if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) {
7254 *data++ = (uint8)(bus->pktgen_count >> 0);
7255 *data++ = (uint8)(bus->pktgen_count >> 8);
7256 *data++ = (uint8)(bus->pktgen_count >> 16);
7257 *data++ = (uint8)(bus->pktgen_count >> 24);
7260 /* Then fill in the remainder -- N/A for burst */
7261 for (fillbyte = 0; fillbyte < len; fillbyte++)
7262 *data++ = SDPCM_TEST_FILL(fillbyte, (uint8)bus->pktgen_sent);
7266 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
7267 data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
7268 prhex("dhdsdio_pktgen: Tx Data", data, PKTLEN(osh, pkt) - SDPCM_HDRLEN);
7273 if (dhdsdio_txpkt(bus, SDPCM_TEST_CHANNEL, &pkt, 1, TRUE) != BCME_OK) {
7275 if (bus->pktgen_stop && bus->pktgen_stop == bus->pktgen_fail)
7276 bus->pktgen_count = 0;
7280 /* Bump length if not fixed, wrap at max */
7281 if (++bus->pktgen_len > bus->pktgen_maxlen)
7282 bus->pktgen_len = (uint16)bus->pktgen_minlen;
7284 /* Special case for burst mode: just send one request! */
7285 if (bus->pktgen_mode == DHD_PKTGEN_RXBURST)
7291 dhdsdio_sdtest_set(dhd_bus_t *bus, uint count)
7295 osl_t *osh = bus->dhd->osh;
7297 /* Allocate the packet */
7298 if (!(pkt = PKTGET(osh, SDPCM_HDRLEN + SDPCM_TEST_HDRLEN +
7299 SDPCM_TEST_PKT_CNT_FLD_LEN + DHD_SDALIGN, TRUE))) {
7300 DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__));
7303 PKTALIGN(osh, pkt, (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN +
7304 SDPCM_TEST_PKT_CNT_FLD_LEN), DHD_SDALIGN);
7305 data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
7307 /* Fill in the test header */
7308 *data++ = SDPCM_TEST_SEND;
7309 *data++ = (count > 0)?TRUE:FALSE;
7310 *data++ = (bus->pktgen_maxlen >> 0);
7311 *data++ = (bus->pktgen_maxlen >> 8);
7312 *data++ = (uint8)(count >> 0);
7313 *data++ = (uint8)(count >> 8);
7314 *data++ = (uint8)(count >> 16);
7315 *data++ = (uint8)(count >> 24);
7318 if (dhdsdio_txpkt(bus, SDPCM_TEST_CHANNEL, &pkt, 1, TRUE) != BCME_OK)
7324 dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq)
7326 osl_t *osh = bus->dhd->osh;
7335 /* Check for min length */
7336 if ((pktlen = PKTLEN(osh, pkt)) < SDPCM_TEST_HDRLEN) {
7337 DHD_ERROR(("dhdsdio_restrcv: toss runt frame, pktlen %d\n", pktlen));
7338 PKTFREE(osh, pkt, FALSE);
7342 /* Extract header fields */
7343 data = PKTDATA(osh, pkt);
7346 len = *data++; len += *data++ << 8;
7347 DHD_TRACE(("%s:cmd:%d, xtra:%d,len:%d\n", __FUNCTION__, cmd, extra, len));
7348 /* Check length for relevant commands */
7349 if (cmd == SDPCM_TEST_DISCARD || cmd == SDPCM_TEST_ECHOREQ || cmd == SDPCM_TEST_ECHORSP) {
7350 if (pktlen != len + SDPCM_TEST_HDRLEN) {
7351 DHD_ERROR(("dhdsdio_testrcv: frame length mismatch, pktlen %d seq %d"
7352 " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len));
7353 PKTFREE(osh, pkt, FALSE);
7358 /* Process as per command */
7360 case SDPCM_TEST_ECHOREQ:
7361 /* Rx->Tx turnaround ok (even on NDIS w/current implementation) */
7362 *(uint8 *)(PKTDATA(osh, pkt)) = SDPCM_TEST_ECHORSP;
7363 if (dhdsdio_txpkt(bus, SDPCM_TEST_CHANNEL, &pkt, 1, TRUE) == BCME_OK) {
7367 PKTFREE(osh, pkt, FALSE);
7372 case SDPCM_TEST_ECHORSP:
7373 if (bus->ext_loop) {
7374 PKTFREE(osh, pkt, FALSE);
7379 for (offset = 0; offset < len; offset++, data++) {
7380 if (*data != SDPCM_TEST_FILL(offset, extra)) {
7381 DHD_ERROR(("dhdsdio_testrcv: echo data mismatch: "
7382 "offset %d (len %d) expect 0x%02x rcvd 0x%02x\n",
7383 offset, len, SDPCM_TEST_FILL(offset, extra), *data));
7387 PKTFREE(osh, pkt, FALSE);
7391 case SDPCM_TEST_DISCARD:
7395 uint8 testval = extra;
7396 for (i = 0; i < len; i++) {
7397 if (*prn != testval) {
7398 DHD_ERROR(("DIErr@Pkt#:%d,Ix:%d, expected:0x%x, got:0x%x\n",
7399 i, bus->pktgen_rcvd_rcvsession, testval, *prn));
7404 PKTFREE(osh, pkt, FALSE);
7408 case SDPCM_TEST_BURST:
7409 case SDPCM_TEST_SEND:
7411 DHD_INFO(("dhdsdio_testrcv: unsupported or unknown command, pktlen %d seq %d"
7412 " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len));
7413 PKTFREE(osh, pkt, FALSE);
7417 /* For recv mode, stop at limit (and tell dongle to stop sending) */
7418 if (bus->pktgen_mode == DHD_PKTGEN_RECV) {
7419 if (bus->pktgen_rcv_state != PKTGEN_RCV_IDLE) {
7420 bus->pktgen_rcvd_rcvsession++;
7422 if (bus->pktgen_total &&
7423 (bus->pktgen_rcvd_rcvsession >= bus->pktgen_total)) {
7424 bus->pktgen_count = 0;
7425 DHD_ERROR(("Pktgen:rcv test complete!\n"));
7426 bus->pktgen_rcv_state = PKTGEN_RCV_IDLE;
7427 dhdsdio_sdtest_set(bus, FALSE);
7428 bus->pktgen_rcvd_rcvsession = 0;
7435 int dhd_bus_oob_intr_register(dhd_pub_t *dhdp)
7439 #if defined(OOB_INTR_ONLY)
7440 err = bcmsdh_oob_intr_register(dhdp->bus->sdh, dhdsdio_isr, dhdp->bus);
7445 void dhd_bus_oob_intr_unregister(dhd_pub_t *dhdp)
7447 #if defined(OOB_INTR_ONLY)
7448 bcmsdh_oob_intr_unregister(dhdp->bus->sdh);
7452 void dhd_bus_oob_intr_set(dhd_pub_t *dhdp, bool enable)
7454 #if defined(OOB_INTR_ONLY)
7455 bcmsdh_oob_intr_set(dhdp->bus->sdh, enable);
7459 void dhd_bus_dev_pm_stay_awake(dhd_pub_t *dhdpub)
7461 bcmsdh_dev_pm_stay_awake(dhdpub->bus->sdh);
7464 void dhd_bus_dev_pm_relax(dhd_pub_t *dhdpub)
7466 bcmsdh_dev_relax(dhdpub->bus->sdh);
7469 bool dhd_bus_dev_pm_enabled(dhd_pub_t *dhdpub)
7471 bool enabled = FALSE;
7473 enabled = bcmsdh_dev_pm_enabled(dhdpub->bus->sdh);
7478 dhd_bus_watchdog(dhd_pub_t *dhdp)
7482 DHD_TIMER(("%s: Enter\n", __FUNCTION__));
7486 if (bus->dhd->dongle_reset)
7489 if (bus->dhd->hang_was_sent) {
7490 dhd_os_wd_timer(bus->dhd, 0);
7494 /* Ignore the timer if simulating bus down */
7495 if (!SLPAUTO_ENAB(bus) && bus->sleeping)
7498 if (dhdp->busstate == DHD_BUS_DOWN)
7501 dhd_os_sdlock(bus->dhd);
7503 /* Poll period: check device if appropriate. */
7504 if (!SLPAUTO_ENAB(bus) && (bus->poll && (++bus->polltick >= bus->pollrate))) {
7505 uint32 intstatus = 0;
7507 /* Reset poll tick */
7510 /* Check device if no interrupts */
7511 if (!bus->intr || (bus->intrcount == bus->lastintrs)) {
7513 if (!bus->dpc_sched) {
7515 devpend = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0,
7516 SDIOD_CCCR_INTPEND, NULL);
7517 intstatus = devpend & (INTR_STATUS_FUNC1 | INTR_STATUS_FUNC2);
7520 /* If there is something, make like the ISR and schedule the DPC */
7525 bcmsdh_intr_disable(bus->sdh);
7527 bus->dpc_sched = TRUE;
7528 dhd_sched_dpc(bus->dhd);
7532 /* Update interrupt tracking */
7533 bus->lastintrs = bus->intrcount;
7536 if ((!bus->dpc_sched) && pktq_len(&bus->txq)) {
7537 bus->dpc_sched = TRUE;
7538 dhd_sched_dpc(bus->dhd);
7542 /* Poll for console output periodically */
7543 if (dhdp->busstate == DHD_BUS_DATA && dhd_console_ms != 0) {
7544 bus->console.count += dhd_watchdog_ms;
7545 if (bus->console.count >= dhd_console_ms) {
7546 bus->console.count -= dhd_console_ms;
7547 /* Make sure backplane clock is on */
7548 if (SLPAUTO_ENAB(bus))
7549 dhdsdio_bussleep(bus, FALSE);
7551 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
7552 if (dhdsdio_readconsole(bus) < 0)
7553 dhd_console_ms = 0; /* On error, stop trying */
7556 #endif /* DHD_DEBUG */
7559 /* Generate packets if configured */
7560 if (bus->pktgen_count && (++bus->pktgen_tick >= bus->pktgen_freq)) {
7561 /* Make sure backplane clock is on */
7562 if (SLPAUTO_ENAB(bus))
7563 dhdsdio_bussleep(bus, FALSE);
7565 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
7566 bus->pktgen_tick = 0;
7567 dhdsdio_pktgen(bus);
7571 /* On idle timeout clear activity flag and/or turn off clock */
7572 #ifdef DHD_USE_IDLECOUNT
7574 bus->activity = FALSE;
7578 if ((bus->idletime > 0) && (bus->idlecount >= bus->idletime)) {
7579 DHD_TIMER(("%s: DHD Idle state!!\n", __FUNCTION__));
7580 if (!bus->poll && SLPAUTO_ENAB(bus)) {
7581 if (dhdsdio_bussleep(bus, TRUE) != BCME_BUSY)
7582 dhd_os_wd_timer(bus->dhd, 0);
7584 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
7590 if ((bus->idletime > 0) && (bus->clkstate == CLK_AVAIL)) {
7591 if (++bus->idlecount >= bus->idletime) {
7593 if (bus->activity) {
7594 bus->activity = FALSE;
7595 if (!bus->poll && SLPAUTO_ENAB(bus)) {
7596 if (!bus->readframes)
7597 dhdsdio_bussleep(bus, TRUE);
7599 bus->reqbussleep = TRUE;
7602 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
7606 #endif /* DHD_USE_IDLECOUNT */
7608 dhd_os_sdunlock(bus->dhd);
7615 dhd_bus_console_in(dhd_pub_t *dhdp, uchar *msg, uint msglen)
7617 dhd_bus_t *bus = dhdp->bus;
7622 /* Address could be zero if CONSOLE := 0 in dongle Makefile */
7623 if (bus->console_addr == 0)
7624 return BCME_UNSUPPORTED;
7626 /* Exclusive bus access */
7627 dhd_os_sdlock(bus->dhd);
7629 /* Don't allow input if dongle is in reset */
7630 if (bus->dhd->dongle_reset) {
7631 dhd_os_sdunlock(bus->dhd);
7632 return BCME_NOTREADY;
7635 /* Request clock to allow SDIO accesses */
7637 /* No pend allowed since txpkt is called later, ht clk has to be on */
7638 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
7640 /* Zero cbuf_index */
7641 addr = bus->console_addr + OFFSETOF(hnd_cons_t, cbuf_idx);
7643 if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0)
7646 /* Write message into cbuf */
7647 addr = bus->console_addr + OFFSETOF(hnd_cons_t, cbuf);
7648 if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)msg, msglen)) < 0)
7651 /* Write length into vcons_in */
7652 addr = bus->console_addr + OFFSETOF(hnd_cons_t, vcons_in);
7653 val = htol32(msglen);
7654 if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0)
7657 /* Bump dongle by sending an empty packet on the event channel.
7658 * sdpcm_sendup (RX) checks for virtual console input.
7660 if ((pkt = PKTGET(bus->dhd->osh, 4 + SDPCM_RESERVE, TRUE)) != NULL)
7661 rv = dhdsdio_txpkt(bus, SDPCM_EVENT_CHANNEL, &pkt, 1, TRUE);
7664 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
7665 bus->activity = FALSE;
7666 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
7669 dhd_os_sdunlock(bus->dhd);
7673 #endif /* DHD_DEBUG */
7677 dhd_dump_cis(uint fn, uint8 *cis)
7679 uint byte, tag, tdata;
7680 DHD_INFO(("Function %d CIS:\n", fn));
7682 for (tdata = byte = 0; byte < SBSDIO_CIS_SIZE_LIMIT; byte++) {
7683 if ((byte % 16) == 0)
7685 DHD_INFO(("%02x ", cis[byte]));
7686 if ((byte % 16) == 15)
7694 else if ((byte + 1) < SBSDIO_CIS_SIZE_LIMIT)
7695 tdata = cis[byte + 1] + 1;
7700 if ((byte % 16) != 15)
7703 #endif /* DHD_DEBUG */
7706 dhdsdio_chipmatch(uint16 chipid)
7708 if (chipid == BCM4325_CHIP_ID)
7710 if (chipid == BCM4329_CHIP_ID)
7712 if (chipid == BCM4315_CHIP_ID)
7714 if (chipid == BCM4319_CHIP_ID)
7716 if (chipid == BCM4336_CHIP_ID)
7718 if (chipid == BCM4330_CHIP_ID)
7720 if (chipid == BCM43237_CHIP_ID)
7722 if (chipid == BCM43362_CHIP_ID)
7724 if (chipid == BCM4314_CHIP_ID)
7726 if (chipid == BCM43242_CHIP_ID)
7728 if (chipid == BCM43340_CHIP_ID)
7730 if (chipid == BCM43341_CHIP_ID)
7732 if (chipid == BCM43143_CHIP_ID)
7734 if (chipid == BCM43342_CHIP_ID)
7736 if (chipid == BCM4334_CHIP_ID)
7738 if (chipid == BCM43239_CHIP_ID)
7740 if (chipid == BCM4324_CHIP_ID)
7742 if (chipid == BCM4335_CHIP_ID)
7744 if (chipid == BCM4339_CHIP_ID)
7746 if (chipid == BCM43349_CHIP_ID)
7748 if (chipid == BCM4345_CHIP_ID || chipid == BCM43454_CHIP_ID)
7750 if (chipid == BCM4350_CHIP_ID)
7752 if (chipid == BCM4354_CHIP_ID)
7754 if (chipid == BCM4356_CHIP_ID)
7756 if (chipid == BCM4358_CHIP_ID)
7758 if (chipid == BCM4371_CHIP_ID)
7760 if (chipid == BCM43430_CHIP_ID)
7762 if (BCM4349_CHIP(chipid))
7767 #if defined(MULTIPLE_SUPPLICANT)
7768 extern void wl_android_post_init(void); // terence 20120530: fix critical section in dhd_open and dhdsdio_probe
7772 dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot,
7773 uint16 func, uint bustype, void *regsva, osl_t * osh, void *sdh)
7777 #ifdef GET_OTP_MAC_ENABLE
7778 struct ether_addr ea_addr;
7781 #if defined(MULTIPLE_SUPPLICANT)
7782 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
7783 if (mutex_is_locked(&_dhd_sdio_mutex_lock_) == 0) {
7784 DHD_ERROR(("%s : no mutex held. set lock\n", __FUNCTION__));
7787 DHD_ERROR(("%s : mutex is locked!. wait for unlocking\n", __FUNCTION__));
7789 mutex_lock(&_dhd_sdio_mutex_lock_);
7790 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
7793 /* Init global variables at run-time, not as part of the declaration.
7794 * This is required to support init/de-init of the driver. Initialization
7795 * of globals as part of the declaration results in non-deterministic
7796 * behavior since the value of the globals may be different on the
7797 * first time that the driver is initialized vs subsequent initializations.
7799 dhd_txbound = DHD_TXBOUND;
7800 dhd_rxbound = DHD_RXBOUND;
7801 dhd_alignctl = TRUE;
7803 dhd_readahead = TRUE;
7806 #ifdef DISABLE_FLOW_CONTROL
7808 #endif /* DISABLE_FLOW_CONTROL */
7809 dhd_dongle_ramsize = 0;
7810 dhd_txminmax = DHD_TXMINMAX;
7814 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7815 DHD_INFO(("%s: venid 0x%04x devid 0x%04x\n", __FUNCTION__, venid, devid));
7817 /* We make assumptions about address window mappings */
7818 ASSERT((uintptr)regsva == SI_ENUM_BASE);
7820 /* BCMSDH passes venid and devid based on CIS parsing -- but low-power start
7821 * means early parse could fail, so here we should get either an ID
7822 * we recognize OR (-1) indicating we must request power first.
7824 /* Check the Vendor ID */
7827 case VENDOR_BROADCOM:
7830 DHD_ERROR(("%s: unknown vendor: 0x%04x\n",
7831 __FUNCTION__, venid));
7835 /* Check the Device ID and make sure it's one that we support */
7837 case BCM4325_D11DUAL_ID: /* 4325 802.11a/g id */
7838 case BCM4325_D11G_ID: /* 4325 802.11g 2.4Ghz band id */
7839 case BCM4325_D11A_ID: /* 4325 802.11a 5Ghz band id */
7840 DHD_INFO(("%s: found 4325 Dongle\n", __FUNCTION__));
7842 case BCM4329_D11N_ID: /* 4329 802.11n dualband device */
7843 case BCM4329_D11N2G_ID: /* 4329 802.11n 2.4G device */
7844 case BCM4329_D11N5G_ID: /* 4329 802.11n 5G device */
7846 DHD_INFO(("%s: found 4329 Dongle\n", __FUNCTION__));
7848 case BCM4315_D11DUAL_ID: /* 4315 802.11a/g id */
7849 case BCM4315_D11G_ID: /* 4315 802.11g id */
7850 case BCM4315_D11A_ID: /* 4315 802.11a id */
7851 DHD_INFO(("%s: found 4315 Dongle\n", __FUNCTION__));
7853 case BCM4319_D11N_ID: /* 4319 802.11n id */
7854 case BCM4319_D11N2G_ID: /* 4319 802.11n2g id */
7855 case BCM4319_D11N5G_ID: /* 4319 802.11n5g id */
7856 DHD_INFO(("%s: found 4319 Dongle\n", __FUNCTION__));
7859 DHD_INFO(("%s: allow device id 0, will check chip internals\n",
7864 DHD_ERROR(("%s: skipping 0x%04x/0x%04x, not a dongle\n",
7865 __FUNCTION__, venid, devid));
7870 DHD_ERROR(("%s: osh is NULL!\n", __FUNCTION__));
7874 /* Allocate private bus interface state */
7875 if (!(bus = MALLOC(osh, sizeof(dhd_bus_t)))) {
7876 DHD_ERROR(("%s: MALLOC of dhd_bus_t failed\n", __FUNCTION__));
7879 bzero(bus, sizeof(dhd_bus_t));
7881 bus->cl_devid = (uint16)devid;
7883 bus->bus_num = bus_no;
7884 bus->slot_num = slot;
7885 bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1;
7886 bus->usebufpool = FALSE; /* Use bufpool if allocated, else use locally malloced rxbuf */
7888 #if defined(SUPPORT_P2P_GO_PS)
7889 init_waitqueue_head(&bus->bus_sleep);
7890 #endif /* LINUX && SUPPORT_P2P_GO_PS */
7892 /* attempt to attach to the dongle */
7893 if (!(dhdsdio_probe_attach(bus, osh, sdh, regsva, devid))) {
7894 DHD_ERROR(("%s: dhdsdio_probe_attach failed\n", __FUNCTION__));
7898 /* Attach to the dhd/OS/network interface */
7899 if (!(bus->dhd = dhd_attach(osh, bus, SDPCM_RESERVE))) {
7900 DHD_ERROR(("%s: dhd_attach failed\n", __FUNCTION__));
7904 /* Allocate buffers */
7905 if (!(dhdsdio_probe_malloc(bus, osh, sdh))) {
7906 DHD_ERROR(("%s: dhdsdio_probe_malloc failed\n", __FUNCTION__));
7910 if (!(dhdsdio_probe_init(bus, osh, sdh))) {
7911 DHD_ERROR(("%s: dhdsdio_probe_init failed\n", __FUNCTION__));
7916 /* Register interrupt callback, but mask it (not operational yet). */
7917 DHD_INTR(("%s: disable SDIO interrupts (not interested yet)\n", __FUNCTION__));
7918 bcmsdh_intr_disable(sdh);
7919 if ((ret = bcmsdh_intr_reg(sdh, dhdsdio_isr, bus)) != 0) {
7920 DHD_ERROR(("%s: FAILED: bcmsdh_intr_reg returned %d\n",
7921 __FUNCTION__, ret));
7924 DHD_INTR(("%s: registered SDIO interrupt function ok\n", __FUNCTION__));
7926 DHD_INFO(("%s: SDIO interrupt function is NOT registered due to polling mode\n",
7930 DHD_INFO(("%s: completed!!\n", __FUNCTION__));
7932 /* if firmware path present try to download and bring up bus */
7933 bus->dhd->hang_report = TRUE;
7934 #if 0 // terence 20150325: fix for WPA/WPA2 4-way handshake fail in hostapd
7935 if (dhd_download_fw_on_driverload) {
7936 if ((ret = dhd_bus_start(bus->dhd)) != 0) {
7937 DHD_ERROR(("%s: dhd_bus_start failed\n", __FUNCTION__));
7942 /* Set random MAC address during boot time */
7943 get_random_bytes(&bus->dhd->mac.octet[3], 3);
7944 /* Adding BRCM OUI */
7945 bus->dhd->mac.octet[0] = 0;
7946 bus->dhd->mac.octet[1] = 0x90;
7947 bus->dhd->mac.octet[2] = 0x4C;
7951 #ifdef GET_OTP_MAC_ENABLE
7952 if (dhd_conf_get_mac(bus->dhd, sdh, ea_addr.octet)) {
7953 DHD_TRACE(("%s: Can not read MAC address\n", __FUNCTION__));
7955 memcpy(bus->dhd->mac.octet, (void *)&ea_addr, ETHER_ADDR_LEN);
7956 #endif /* GET_CUSTOM_MAC_ENABLE */
7958 /* Ok, have the per-port tell the stack we're open for business */
7959 if (dhd_register_if(bus->dhd, 0, TRUE) != 0) {
7960 DHD_ERROR(("%s: Net attach failed!!\n", __FUNCTION__));
7964 #ifdef BCMHOST_XTAL_PU_TIME_MOD
7965 bcmsdh_reg_write(bus->sdh, 0x18000620, 2, 11);
7967 bcmsdh_reg_write(bus->sdh, 0x18000628, 4, 0x0000F801);
7969 bcmsdh_reg_write(bus->sdh, 0x18000628, 4, 0x00F80001);
7970 #endif /* BCM4330_CHIP */
7971 #endif /* BCMHOST_XTAL_PU_TIME_MOD */
7973 #if defined(MULTIPLE_SUPPLICANT)
7974 wl_android_post_init(); // terence 20120530: fix critical section in dhd_open and dhdsdio_probe
7975 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
7976 mutex_unlock(&_dhd_sdio_mutex_lock_);
7977 DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__));
7978 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
7984 dhdsdio_release(bus, osh);
7987 #if defined(MULTIPLE_SUPPLICANT)
7988 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
7989 mutex_unlock(&_dhd_sdio_mutex_lock_);
7990 DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__));
7991 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
7998 dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva,
8004 bus->alp_only = TRUE;
8007 /* Return the window to backplane enumeration space for core access */
8008 if (dhdsdio_set_siaddr_window(bus, SI_ENUM_BASE)) {
8009 DHD_ERROR(("%s: FAILED to return to SI_ENUM_BASE\n", __FUNCTION__));
8012 #if defined(DHD_DEBUG) && !defined(CUSTOMER_HW4_DEBUG)
8013 DHD_ERROR(("F1 signature read @0x18000000=0x%4x\n",
8014 bcmsdh_reg_read(bus->sdh, SI_ENUM_BASE, 4)));
8015 #endif /* DHD_DEBUG && !CUSTOMER_HW4_DEBUG */
8018 /* Force PLL off until si_attach() programs PLL control regs */
8022 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, DHD_INIT_CLKCTL1, &err);
8024 clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
8026 if (err || ((clkctl & ~SBSDIO_AVBITS) != DHD_INIT_CLKCTL1)) {
8027 DHD_ERROR(("dhdsdio_probe: ChipClkCSR access: err %d wrote 0x%02x read 0x%02x\n",
8028 err, DHD_INIT_CLKCTL1, clkctl));
8033 if (DHD_INFO_ON()) {
8035 uint8 *cis[SDIOD_MAX_IOFUNCS];
8038 numfn = bcmsdh_query_iofnum(sdh);
8039 ASSERT(numfn <= SDIOD_MAX_IOFUNCS);
8041 /* Make sure ALP is available before trying to read CIS */
8042 SPINWAIT(((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
8043 SBSDIO_FUNC1_CHIPCLKCSR, NULL)),
8044 !SBSDIO_ALPAV(clkctl)), PMU_MAX_TRANSITION_DLY);
8046 /* Now request ALP be put on the bus */
8047 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
8048 DHD_INIT_CLKCTL2, &err);
8051 for (fn = 0; fn <= numfn; fn++) {
8052 if (!(cis[fn] = MALLOC(osh, SBSDIO_CIS_SIZE_LIMIT))) {
8053 DHD_INFO(("dhdsdio_probe: fn %d cis malloc failed\n", fn));
8056 bzero(cis[fn], SBSDIO_CIS_SIZE_LIMIT);
8058 if ((err = bcmsdh_cis_read(sdh, fn, cis[fn], SBSDIO_CIS_SIZE_LIMIT))) {
8059 DHD_INFO(("dhdsdio_probe: fn %d cis read err %d\n", fn, err));
8060 MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT);
8063 dhd_dump_cis(fn, cis[fn]);
8068 MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT);
8072 DHD_ERROR(("dhdsdio_probe: failure reading or parsing CIS\n"));
8076 #endif /* DHD_DEBUG */
8078 /* si_attach() will provide an SI handle and scan the backplane */
8079 if (!(bus->sih = si_attach((uint)devid, osh, regsva, DHD_BUS, sdh,
8080 &bus->vars, &bus->varsz))) {
8081 DHD_ERROR(("%s: si_attach failed!\n", __FUNCTION__));
8086 DHD_ERROR(("F1 signature OK, socitype:0x%x chip:0x%4x rev:0x%x pkg:0x%x\n",
8087 bus->sih->socitype, bus->sih->chip, bus->sih->chiprev, bus->sih->chippkg));
8088 #endif /* DHD_DEBUG */
8091 bcmsdh_chipinfo(sdh, bus->sih->chip, bus->sih->chiprev);
8093 if (!dhdsdio_chipmatch((uint16)bus->sih->chip)) {
8094 DHD_ERROR(("%s: unsupported chip: 0x%04x\n",
8095 __FUNCTION__, bus->sih->chip));
8099 if (bus->sih->buscorerev >= 12)
8100 dhdsdio_clk_kso_init(bus);
8104 if (CST4330_CHIPMODE_SDIOD(bus->sih->chipst)) {
8107 si_sdiod_drive_strength_init(bus->sih, osh, dhd_sdiod_drive_strength);
8110 /* Get info on the ARM and SOCRAM cores... */
8111 if (!DHD_NOPMU(bus)) {
8112 if ((si_setcore(bus->sih, ARM7S_CORE_ID, 0)) ||
8113 (si_setcore(bus->sih, ARMCM3_CORE_ID, 0)) ||
8114 (si_setcore(bus->sih, ARMCR4_CORE_ID, 0))) {
8115 bus->armrev = si_corerev(bus->sih);
8117 DHD_ERROR(("%s: failed to find ARM core!\n", __FUNCTION__));
8121 if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
8122 if (!(bus->orig_ramsize = si_socram_size(bus->sih))) {
8123 DHD_ERROR(("%s: failed to find SOCRAM memory!\n", __FUNCTION__));
8127 /* cr4 has a different way to find the RAM size from TCM's */
8128 if (!(bus->orig_ramsize = si_tcm_size(bus->sih))) {
8129 DHD_ERROR(("%s: failed to find CR4-TCM memory!\n", __FUNCTION__));
8132 /* also populate base address */
8133 switch ((uint16)bus->sih->chip) {
8134 case BCM4335_CHIP_ID:
8135 case BCM4339_CHIP_ID:
8136 case BCM43349_CHIP_ID:
8137 bus->dongle_ram_base = CR4_4335_RAM_BASE;
8139 case BCM4350_CHIP_ID:
8140 case BCM4354_CHIP_ID:
8141 case BCM4356_CHIP_ID:
8142 case BCM4358_CHIP_ID:
8143 case BCM4371_CHIP_ID:
8144 bus->dongle_ram_base = CR4_4350_RAM_BASE;
8146 case BCM4360_CHIP_ID:
8147 bus->dongle_ram_base = CR4_4360_RAM_BASE;
8149 case BCM4345_CHIP_ID:
8150 case BCM43454_CHIP_ID:
8151 bus->dongle_ram_base = (bus->sih->chiprev < 6) /* from 4345C0 */
8152 ? CR4_4345_LT_C0_RAM_BASE : CR4_4345_GE_C0_RAM_BASE;
8154 case BCM4349_CHIP_GRPID:
8155 /* RAM base changed from 4349c0(revid=9) onwards */
8156 bus->dongle_ram_base = ((bus->sih->chiprev < 9) ?
8157 CR4_4349_RAM_BASE: CR4_4349_RAM_BASE_FROM_REV_9);
8160 bus->dongle_ram_base = 0;
8161 DHD_ERROR(("%s: WARNING: Using default ram base at 0x%x\n",
8162 __FUNCTION__, bus->dongle_ram_base));
8165 bus->ramsize = bus->orig_ramsize;
8166 if (dhd_dongle_ramsize)
8167 dhd_dongle_setramsize(bus, dhd_dongle_ramsize);
8169 DHD_ERROR(("DHD: dongle ram size is set to %d(orig %d) at 0x%x\n",
8170 bus->ramsize, bus->orig_ramsize, bus->dongle_ram_base));
8172 bus->srmemsize = si_socram_srmem_size(bus->sih);
8175 /* ...but normally deal with the SDPCMDEV core */
8176 if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0)) &&
8177 !(bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0))) {
8178 DHD_ERROR(("%s: failed to find SDIODEV core!\n", __FUNCTION__));
8181 bus->sdpcmrev = si_corerev(bus->sih);
8183 /* Set core control so an SDIO reset does a backplane reset */
8184 OR_REG(osh, &bus->regs->corecontrol, CC_BPRESEN);
8185 bus->rxint_mode = SDIO_DEVICE_HMB_RXINT;
8187 if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev >= 4) &&
8188 (bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_1))
8192 val = R_REG(osh, &bus->regs->corecontrol);
8193 val &= ~CC_XMTDATAAVAIL_MODE;
8194 val |= CC_XMTDATAAVAIL_CTRL;
8195 W_REG(osh, &bus->regs->corecontrol, val);
8199 pktq_init(&bus->txq, (PRIOMASK + 1), QLEN);
8201 /* Locate an appropriately-aligned portion of hdrbuf */
8202 bus->rxhdr = (uint8 *)ROUNDUP((uintptr)&bus->hdrbuf[0], DHD_SDALIGN);
8204 /* Set the poll and/or interrupt flags */
8205 bus->intr = (bool)dhd_intr;
8206 if ((bus->poll = (bool)dhd_poll))
8209 /* Setting default Glom size */
8210 bus->txglomsize = SDPCM_DEFGLOM_SIZE;
8215 if (bus->sih != NULL) {
8216 si_detach(bus->sih);
8223 dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh)
8225 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
8227 if (bus->dhd->maxctl) {
8228 bus->rxblen = ROUNDUP((bus->dhd->maxctl+SDPCM_HDRLEN), ALIGNMENT) + DHD_SDALIGN;
8229 if (!(bus->rxbuf = DHD_OS_PREALLOC(bus->dhd, DHD_PREALLOC_RXBUF, bus->rxblen))) {
8230 DHD_ERROR(("%s: MALLOC of %d-byte rxbuf failed\n",
8231 __FUNCTION__, bus->rxblen));
8235 /* Allocate buffer to receive glomed packet */
8236 if (!(bus->databuf = DHD_OS_PREALLOC(bus->dhd, DHD_PREALLOC_DATABUF, MAX_DATA_BUF))) {
8237 DHD_ERROR(("%s: MALLOC of %d-byte databuf failed\n",
8238 __FUNCTION__, MAX_DATA_BUF));
8239 /* release rxbuf which was already located as above */
8241 DHD_OS_PREFREE(bus->dhd, bus->rxbuf, bus->rxblen);
8245 /* Align the buffer */
8246 if ((uintptr)bus->databuf % DHD_SDALIGN)
8247 bus->dataptr = bus->databuf + (DHD_SDALIGN - ((uintptr)bus->databuf % DHD_SDALIGN));
8249 bus->dataptr = bus->databuf;
8258 dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh)
8262 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
8264 bus->_srenab = FALSE;
8267 dhdsdio_pktgen_init(bus);
8270 /* Disable F2 to clear any intermediate frame state on the dongle */
8271 bcmsdh_cfg_write(sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL);
8273 bus->dhd->busstate = DHD_BUS_DOWN;
8274 bus->sleeping = FALSE;
8275 bus->rxflow = FALSE;
8276 bus->prev_rxlim_hit = 0;
8278 /* Done with backplane-dependent accesses, can drop clock... */
8279 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
8281 /* ...and initialize clock/power states */
8282 bus->clkstate = CLK_SDONLY;
8283 bus->idletime = (int32)dhd_idletime;
8284 bus->idleclock = DHD_IDLE_ACTIVE;
8286 /* Query the SD clock speed */
8287 if (bcmsdh_iovar_op(sdh, "sd_divisor", NULL, 0,
8288 &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) {
8289 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_divisor"));
8290 bus->sd_divisor = -1;
8292 DHD_INFO(("%s: Initial value for %s is %d\n",
8293 __FUNCTION__, "sd_divisor", bus->sd_divisor));
8296 /* Query the SD bus mode */
8297 if (bcmsdh_iovar_op(sdh, "sd_mode", NULL, 0,
8298 &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) {
8299 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_mode"));
8302 DHD_INFO(("%s: Initial value for %s is %d\n",
8303 __FUNCTION__, "sd_mode", bus->sd_mode));
8306 /* Query the F2 block size, set roundup accordingly */
8308 if (bcmsdh_iovar_op(sdh, "sd_blocksize", &fnum, sizeof(int32),
8309 &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) {
8311 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize"));
8313 DHD_INFO(("%s: Initial value for %s is %d\n",
8314 __FUNCTION__, "sd_blocksize", bus->blocksize));
8316 dhdsdio_tune_fifoparam(bus);
8318 bus->roundup = MIN(max_roundup, bus->blocksize);
8320 #ifdef DHDENABLE_TAILPAD
8322 PKTFREE(osh, bus->pad_pkt, FALSE);
8323 bus->pad_pkt = PKTGET(osh, SDIO_MAX_BLOCK_SIZE, FALSE);
8324 if (bus->pad_pkt == NULL)
8325 DHD_ERROR(("failed to allocate padding packet\n"));
8327 int alignment_offset = 0;
8328 uintptr pktprt = (uintptr)PKTDATA(osh, bus->pad_pkt);
8329 if (!(pktprt&1) && (pktprt = (pktprt % DHD_SDALIGN)))
8330 PKTPUSH(osh, bus->pad_pkt, alignment_offset);
8331 PKTSETNEXT(osh, bus->pad_pkt, NULL);
8333 #endif /* DHDENABLE_TAILPAD */
8335 /* Query if bus module supports packet chaining, default to use if supported */
8336 if (bcmsdh_iovar_op(sdh, "sd_rxchain", NULL, 0,
8337 &bus->sd_rxchain, sizeof(int32), FALSE) != BCME_OK) {
8338 bus->sd_rxchain = FALSE;
8340 DHD_INFO(("%s: bus module (through bcmsdh API) %s chaining\n",
8341 __FUNCTION__, (bus->sd_rxchain ? "supports" : "does not support")));
8343 bus->use_rxchain = (bool)bus->sd_rxchain;
8344 bus->txinrx_thres = CUSTOM_TXINRX_THRES;
8345 /* TX first in dhdsdio_readframes() */
8346 bus->dotxinrx = TRUE;
8349 memset((uint8*) &tx_statics, 0, sizeof(pkt_statics_t));
8356 dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh,
8357 char *pfw_path, char *pnv_path, char *pconf_path)
8361 bus->fw_path = pfw_path;
8362 bus->nv_path = pnv_path;
8363 bus->dhd->conf_path = pconf_path;
8365 ret = dhdsdio_download_firmware(bus, osh, bus->sdh);
8372 dhdsdio_download_firmware(struct dhd_bus *bus, osl_t *osh, void *sdh)
8377 DHD_TRACE_HW4(("%s: firmware path=%s, nvram path=%s\n",
8378 __FUNCTION__, bus->fw_path, bus->nv_path));
8379 DHD_OS_WAKE_LOCK(bus->dhd);
8381 /* Download the firmware */
8382 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
8384 /* External conf takes precedence if specified */
8385 dhd_conf_preinit(bus->dhd);
8386 dhd_conf_read_config(bus->dhd, bus->dhd->conf_path);
8387 dhd_conf_set_fw_name_by_chip(bus->dhd, bus->fw_path, bus->nv_path);
8388 dhd_conf_set_nv_name_by_chip(bus->dhd, bus->nv_path);
8389 dhd_conf_set_fw_name_by_mac(bus->dhd, bus->sdh, bus->fw_path);
8390 dhd_conf_set_nv_name_by_mac(bus->dhd, bus->sdh, bus->nv_path);
8391 if (bus->dhd->conf->dhd_poll >= 0) {
8392 printf("%s: set polling mode %d\n", __FUNCTION__, bus->dhd->conf->dhd_poll);
8397 if (bus->dhd->conf->use_rxchain >= 0) {
8398 printf("%s: set use_rxchain %d\n", __FUNCTION__, bus->dhd->conf->use_rxchain);
8399 bus->use_rxchain = (bool)bus->dhd->conf->use_rxchain;
8401 if (bus->dhd->conf->txglomsize >= 0) {
8402 printf("%s: set txglomsize %d\n", __FUNCTION__, bus->dhd->conf->txglomsize);
8403 bus->txglomsize = bus->dhd->conf->txglomsize;
8405 bcmsdh_set_mode(sdh, bus->dhd->conf->txglom_mode);
8407 printf("Final fw_path=%s\n", bus->fw_path);
8408 printf("Final nv_path=%s\n", bus->nv_path);
8409 printf("Final conf_path=%s\n", bus->dhd->conf_path);
8411 ret = _dhdsdio_download_firmware(bus);
8413 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
8415 DHD_OS_WAKE_UNLOCK(bus->dhd);
8419 /* Detach and free everything */
8421 dhdsdio_release(dhd_bus_t *bus, osl_t *osh)
8423 bool dongle_isolation = FALSE;
8424 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
8430 dongle_isolation = bus->dhd->dongle_isolation;
8431 dhd_detach(bus->dhd);
8434 /* De-register interrupt handler */
8435 bcmsdh_intr_disable(bus->sdh);
8436 bcmsdh_intr_dereg(bus->sdh);
8439 dhdsdio_release_dongle(bus, osh, dongle_isolation, TRUE);
8444 dhdsdio_release_malloc(bus, osh);
8447 if (bus->console.buf != NULL)
8448 MFREE(osh, bus->console.buf, bus->console.bufsize);
8451 #ifdef DHDENABLE_TAILPAD
8453 PKTFREE(osh, bus->pad_pkt, FALSE);
8454 #endif /* DHDENABLE_TAILPAD */
8456 MFREE(osh, bus, sizeof(dhd_bus_t));
8459 DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
8463 dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh)
8465 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
8467 if (bus->dhd && bus->dhd->dongle_reset)
8471 #ifndef CONFIG_DHD_USE_STATIC_BUF
8472 MFREE(osh, bus->rxbuf, bus->rxblen);
8474 bus->rxctl = bus->rxbuf = NULL;
8479 #ifndef CONFIG_DHD_USE_STATIC_BUF
8480 MFREE(osh, bus->databuf, MAX_DATA_BUF);
8482 bus->databuf = NULL;
8485 if (bus->vars && bus->varsz) {
8486 MFREE(osh, bus->vars, bus->varsz);
8494 dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation, bool reset_flag)
8496 DHD_TRACE(("%s: Enter bus->dhd %p bus->dhd->dongle_reset %d \n", __FUNCTION__,
8497 bus->dhd, bus->dhd->dongle_reset));
8499 if ((bus->dhd && bus->dhd->dongle_reset) && reset_flag)
8503 #if !defined(BCMLXSDMMC)
8505 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
8507 if (KSO_ENAB(bus) && (dongle_isolation == FALSE))
8508 si_watchdog(bus->sih, 4);
8509 #endif /* !defined(BCMLXSDMMC) */
8511 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
8513 si_detach(bus->sih);
8515 if (bus->vars && bus->varsz)
8516 MFREE(osh, bus->vars, bus->varsz);
8520 DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
8524 dhdsdio_disconnect(void *ptr)
8526 dhd_bus_t *bus = (dhd_bus_t *)ptr;
8528 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
8530 #if defined(MULTIPLE_SUPPLICANT)
8531 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
8532 if (mutex_is_locked(&_dhd_sdio_mutex_lock_) == 0) {
8533 DHD_ERROR(("%s : no mutex held. set lock\n", __FUNCTION__));
8536 DHD_ERROR(("%s : mutex is locked!. wait for unlocking\n", __FUNCTION__));
8538 mutex_lock(&_dhd_sdio_mutex_lock_);
8539 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
8545 dhdsdio_release(bus, bus->dhd->osh);
8548 #if defined(MULTIPLE_SUPPLICANT)
8549 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
8550 mutex_unlock(&_dhd_sdio_mutex_lock_);
8551 DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__));
8552 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
8556 DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
8560 dhdsdio_suspend(void *context)
8564 dhd_bus_t *bus = (dhd_bus_t*)context;
8565 #ifdef SUPPORT_P2P_GO_PS
8568 if (bus->idletime > 0) {
8569 wait_time = msecs_to_jiffies(bus->idletime * dhd_watchdog_ms);
8571 #endif /* SUPPORT_P2P_GO_PS */
8572 ret = dhd_os_check_wakelock(bus->dhd);
8573 #ifdef SUPPORT_P2P_GO_PS
8574 // terence 20141124: fix for suspend issue
8575 if (SLPAUTO_ENAB(bus) && (!ret) && (bus->dhd->up) && (bus->dhd->op_mode != DHD_FLAG_HOSTAP_MODE)) {
8576 if (wait_event_timeout(bus->bus_sleep, bus->sleeping, wait_time) == 0) {
8577 if (!bus->sleeping) {
8582 #endif /* SUPPORT_P2P_GO_PS */
8587 dhdsdio_resume(void *context)
8589 #if defined(OOB_INTR_ONLY)
8590 dhd_bus_t *bus = (dhd_bus_t*)context;
8592 if (dhd_os_check_if_up(bus->dhd))
8593 bcmsdh_oob_intr_set(bus->sdh, TRUE);
8599 /* Register/Unregister functions are called by the main DHD entry
8600 * point (e.g. module insertion) to link with the bus driver, in
8601 * order to look for or await the device.
8604 static bcmsdh_driver_t dhd_sdio = {
8612 dhd_bus_register(void)
8614 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
8616 return bcmsdh_register(&dhd_sdio);
8620 dhd_bus_unregister(void)
8622 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
8624 bcmsdh_unregister();
8627 #if defined(BCMLXSDMMC)
8628 /* Register a dummy SDIO client driver in order to be notified of new SDIO device */
8629 int dhd_bus_reg_sdio_notify(void* semaphore)
8631 return bcmsdh_reg_sdio_notify(semaphore);
8634 void dhd_bus_unreg_sdio_notify(void)
8636 bcmsdh_unreg_sdio_notify();
8638 #endif /* defined(BCMLXSDMMC) */
8640 #ifdef BCMEMBEDIMAGE
8642 dhdsdio_download_code_array(struct dhd_bus *bus)
8646 unsigned char *ularray = NULL;
8648 DHD_INFO(("%s: download embedded firmware...\n", __FUNCTION__));
8650 /* Download image */
8651 while ((offset + MEMBLOCK) < sizeof(dlarray)) {
8653 if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
8654 /* if address is 0, store the reset instruction to be written in 0 */
8657 bus->resetinstr = *(((uint32*)dlarray));
8658 /* Add start of RAM address to the address given by user */
8659 offset += bus->dongle_ram_base;
8663 bcmerror = dhdsdio_membytes(bus, TRUE, offset,
8664 (uint8 *) (dlarray + offset), MEMBLOCK);
8666 DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
8667 __FUNCTION__, bcmerror, MEMBLOCK, offset));
8674 if (offset < sizeof(dlarray)) {
8675 bcmerror = dhdsdio_membytes(bus, TRUE, offset,
8676 (uint8 *) (dlarray + offset), sizeof(dlarray) - offset);
8678 DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
8679 __FUNCTION__, bcmerror, sizeof(dlarray) - offset, offset));
8685 /* Upload and compare the downloaded code */
8687 ularray = MALLOC(bus->dhd->osh, bus->ramsize);
8688 /* Upload image to verify downloaded contents. */
8690 memset(ularray, 0xaa, bus->ramsize);
8691 while ((offset + MEMBLOCK) < sizeof(dlarray)) {
8692 bcmerror = dhdsdio_membytes(bus, FALSE, offset, ularray + offset, MEMBLOCK);
8694 DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n",
8695 __FUNCTION__, bcmerror, MEMBLOCK, offset));
8702 if (offset < sizeof(dlarray)) {
8703 bcmerror = dhdsdio_membytes(bus, FALSE, offset,
8704 ularray + offset, sizeof(dlarray) - offset);
8706 DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n",
8707 __FUNCTION__, bcmerror, sizeof(dlarray) - offset, offset));
8712 if (memcmp(dlarray, ularray, sizeof(dlarray))) {
8713 DHD_ERROR(("%s: Downloaded image is corrupted (%s, %s, %s).\n",
8714 __FUNCTION__, dlimagename, dlimagever, dlimagedate));
8717 DHD_ERROR(("%s: Download, Upload and compare succeeded (%s, %s, %s).\n",
8718 __FUNCTION__, dlimagename, dlimagever, dlimagedate));
8721 #endif /* DHD_DEBUG */
8725 MFREE(bus->dhd->osh, ularray, bus->ramsize);
8728 #endif /* BCMEMBEDIMAGE */
8731 dhdsdio_download_code_file(struct dhd_bus *bus, char *pfw_path)
8737 uint8 *memblock = NULL, *memptr;
8738 uint8 *memptr_tmp = NULL; // terence: check downloaded firmware is correct
8740 DHD_INFO(("%s: download firmware %s\n", __FUNCTION__, pfw_path));
8742 image = dhd_os_open_image(pfw_path);
8743 if (image == NULL) {
8744 printf("%s: Open firmware file failed %s\n", __FUNCTION__, pfw_path);
8748 memptr = memblock = MALLOC(bus->dhd->osh, MEMBLOCK + DHD_SDALIGN);
8749 if (memblock == NULL) {
8750 DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, MEMBLOCK));
8753 if (dhd_msg_level & DHD_TRACE_VAL) {
8754 memptr_tmp = MALLOC(bus->dhd->osh, MEMBLOCK + DHD_SDALIGN);
8755 if (memptr_tmp == NULL) {
8756 DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, MEMBLOCK));
8760 if ((uint32)(uintptr)memblock % DHD_SDALIGN)
8761 memptr += (DHD_SDALIGN - ((uint32)(uintptr)memblock % DHD_SDALIGN));
8763 /* Download image */
8764 while ((len = dhd_os_get_image_block((char*)memptr, MEMBLOCK, image))) {
8765 // terence 20150412: fix for firmware failed to download
8766 if (bus->dhd->conf->chip == BCM43340_CHIP_ID ||
8767 bus->dhd->conf->chip == BCM43341_CHIP_ID) {
8769 memset(memptr+len, 0, len%64);
8770 len += (64 - len%64);
8774 DHD_ERROR(("%s: dhd_os_get_image_block failed (%d)\n", __FUNCTION__, len));
8775 bcmerror = BCME_ERROR;
8779 if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
8780 /* if address is 0, store the reset instruction to be written in 0 */
8783 bus->resetinstr = *(((uint32*)memptr));
8784 /* Add start of RAM address to the address given by user */
8785 offset += bus->dongle_ram_base;
8789 bcmerror = dhdsdio_membytes(bus, TRUE, offset, memptr, len);
8791 DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
8792 __FUNCTION__, bcmerror, MEMBLOCK, offset));
8796 if (dhd_msg_level & DHD_TRACE_VAL) {
8797 bcmerror = dhdsdio_membytes(bus, FALSE, offset, memptr_tmp, len);
8799 DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n",
8800 __FUNCTION__, bcmerror, MEMBLOCK, offset));
8803 if (memcmp(memptr_tmp, memptr, len)) {
8804 DHD_ERROR(("%s: Downloaded image is corrupted.\n", __FUNCTION__));
8807 DHD_INFO(("%s: Download, Upload and compare succeeded.\n", __FUNCTION__));
8814 MFREE(bus->dhd->osh, memblock, MEMBLOCK + DHD_SDALIGN);
8815 if (dhd_msg_level & DHD_TRACE_VAL) {
8817 MFREE(bus->dhd->osh, memptr_tmp, MEMBLOCK + DHD_SDALIGN);
8821 dhd_os_close_image(image);
8827 dhdsdio_download_nvram(struct dhd_bus *bus)
8831 void * image = NULL;
8832 char * memblock = NULL;
8835 bool nvram_file_exists;
8837 pnv_path = bus->nv_path;
8839 nvram_file_exists = ((pnv_path != NULL) && (pnv_path[0] != '\0'));
8841 /* For Get nvram from UEFI */
8842 if (nvram_file_exists) {
8843 image = dhd_os_open_image(pnv_path);
8844 if (image == NULL) {
8845 printf("%s: Open nvram file failed %s\n", __FUNCTION__, pnv_path);
8850 memblock = MALLOC(bus->dhd->osh, MAX_NVRAMBUF_SIZE);
8851 if (memblock == NULL) {
8852 DHD_ERROR(("%s: Failed to allocate memory %d bytes\n",
8853 __FUNCTION__, MAX_NVRAMBUF_SIZE));
8857 /* For Get nvram from image or UEFI (when image == NULL ) */
8858 len = dhd_os_get_image_block(memblock, MAX_NVRAMBUF_SIZE, image);
8860 if (len > 0 && len < MAX_NVRAMBUF_SIZE) {
8861 bufp = (char *)memblock;
8863 len = process_nvram_vars(bufp, len);
8865 len += 4 - (len % 4);
8870 bcmerror = dhdsdio_downloadvars(bus, memblock, len + 1);
8872 DHD_ERROR(("%s: error downloading vars: %d\n",
8873 __FUNCTION__, bcmerror));
8877 DHD_ERROR(("%s: error reading nvram file: %d\n",
8878 __FUNCTION__, len));
8879 bcmerror = BCME_SDIO_ERROR;
8884 MFREE(bus->dhd->osh, memblock, MAX_NVRAMBUF_SIZE);
8887 dhd_os_close_image(image);
8893 _dhdsdio_download_firmware(struct dhd_bus *bus)
8897 bool embed = FALSE; /* download embedded firmware */
8898 bool dlok = FALSE; /* download firmware succeeded */
8900 /* Out immediately if no image to download */
8901 if ((bus->fw_path == NULL) || (bus->fw_path[0] == '\0')) {
8902 #ifdef BCMEMBEDIMAGE
8909 /* Keep arm in reset */
8910 if (dhdsdio_download_state(bus, TRUE)) {
8911 DHD_ERROR(("%s: error placing ARM core in reset\n", __FUNCTION__));
8915 /* External image takes precedence if specified */
8916 if ((bus->fw_path != NULL) && (bus->fw_path[0] != '\0')) {
8917 if (dhdsdio_download_code_file(bus, bus->fw_path)) {
8918 DHD_ERROR(("%s: dongle image file download failed\n", __FUNCTION__));
8919 #ifdef BCMEMBEDIMAGE
8931 #ifdef BCMEMBEDIMAGE
8933 if (dhdsdio_download_code_array(bus)) {
8934 DHD_ERROR(("%s: dongle image array download failed\n", __FUNCTION__));
8942 BCM_REFERENCE(embed);
8945 DHD_ERROR(("%s: dongle image download failed\n", __FUNCTION__));
8949 /* External nvram takes precedence if specified */
8950 if (dhdsdio_download_nvram(bus)) {
8951 DHD_ERROR(("%s: dongle nvram file download failed\n", __FUNCTION__));
8955 /* Take arm out of reset */
8956 if (dhdsdio_download_state(bus, FALSE)) {
8957 DHD_ERROR(("%s: error getting out of ARM core reset\n", __FUNCTION__));
8968 dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes,
8969 void *pkt, bcmsdh_cmplt_fn_t complete, void *handle)
8973 if (!KSO_ENAB(bus)) {
8974 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
8975 return BCME_NODEVICE;
8978 status = bcmsdh_recv_buf(bus->sdh, addr, fn, flags, buf, nbytes, pkt, complete, handle);
8984 dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes,
8985 void *pkt, bcmsdh_cmplt_fn_t complete, void *handle, int max_retry)
8992 if (!KSO_ENAB(bus)) {
8993 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
8994 return BCME_NODEVICE;
8999 ret = bcmsdh_send_buf(bus->sdh, addr, fn, flags, buf, nbytes,
9000 pkt, complete, handle);
9003 ASSERT(ret != BCME_PENDING);
9005 if (ret == BCME_NODEVICE) {
9006 DHD_ERROR(("%s: Device asleep already\n", __FUNCTION__));
9007 } else if (ret < 0) {
9008 /* On failure, abort the command and terminate the frame */
9009 DHD_ERROR(("%s: sdio error %d, abort command and terminate frame.\n",
9010 __FUNCTION__, ret));
9013 bus->dhd->tx_errors++;
9014 bcmsdh_abort(sdh, SDIO_FUNC_2);
9015 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
9017 for (i = 0; i < READ_FRM_CNT_RETRIES; i++) {
9019 hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WFRAMEBCHI,
9021 lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WFRAMEBCLO,
9023 bus->f1regdata += 2;
9024 if ((hi == 0) && (lo == 0))
9028 } while ((ret < 0) && retrydata && ++retries < max_retry);
9034 dhd_bus_is_ioready(struct dhd_bus *bus)
9039 ASSERT(bus->sih != NULL);
9040 enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2);
9042 return (enable == bcmsdh_cfg_read(sdh, SDIO_FUNC_0, SDIOD_CCCR_IORDY, NULL));
9046 dhd_bus_chip(struct dhd_bus *bus)
9048 ASSERT(bus->sih != NULL);
9049 return bus->sih->chip;
9053 dhd_bus_chiprev(struct dhd_bus *bus)
9056 ASSERT(bus->sih != NULL);
9057 return bus->sih->chiprev;
9061 dhd_bus_pub(struct dhd_bus *bus)
9067 dhd_bus_sih(struct dhd_bus *bus)
9069 return (void *)bus->sih;
9073 dhd_bus_txq(struct dhd_bus *bus)
9079 dhd_bus_hdrlen(struct dhd_bus *bus)
9081 return (bus->txglom_enable) ? SDPCM_HDRLEN_TXGLOM : SDPCM_HDRLEN;
9085 dhd_bus_set_dotxinrx(struct dhd_bus *bus, bool val)
9087 bus->dotxinrx = val;
9091 dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag)
9099 if (!bus->dhd->dongle_reset) {
9100 dhd_os_sdlock(dhdp);
9101 dhd_os_wd_timer(dhdp, 0);
9102 #if !defined(IGNORE_ETH0_DOWN)
9103 /* Force flow control as protection when stop come before ifconfig_down */
9104 dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON);
9105 #endif /* !defined(IGNORE_ETH0_DOWN) */
9106 /* Expect app to have torn down any connection before calling */
9107 /* Stop the bus, disable F2 */
9108 dhd_bus_stop(bus, FALSE);
9110 #if defined(OOB_INTR_ONLY)
9111 /* Clean up any pending IRQ */
9112 dhd_enable_oob_intr(bus, FALSE);
9113 bcmsdh_oob_intr_set(bus->sdh, FALSE);
9114 bcmsdh_oob_intr_unregister(bus->sdh);
9117 /* Clean tx/rx buffer pointers, detach from the dongle */
9118 dhdsdio_release_dongle(bus, bus->dhd->osh, TRUE, TRUE);
9120 bus->dhd->dongle_reset = TRUE;
9121 bus->dhd->up = FALSE;
9122 dhd_txglom_enable(dhdp, FALSE);
9123 dhd_os_sdunlock(dhdp);
9125 printf("%s: WLAN OFF DONE\n", __FUNCTION__);
9126 /* App can now remove power from device */
9128 bcmerror = BCME_SDIO_ERROR;
9130 /* App must have restored power to device before calling */
9132 printf("\n\n%s: == WLAN ON ==\n", __FUNCTION__);
9134 if (bus->dhd->dongle_reset) {
9136 dhd_os_sdlock(dhdp);
9137 /* Reset SD client */
9138 bcmsdh_reset(bus->sdh);
9140 /* Attempt to re-attach & download */
9141 if (dhdsdio_probe_attach(bus, bus->dhd->osh, bus->sdh,
9142 (uint32 *)SI_ENUM_BASE,
9144 /* Attempt to download binary to the dongle */
9145 if (dhdsdio_probe_init(bus, bus->dhd->osh, bus->sdh) &&
9146 dhdsdio_download_firmware(bus, bus->dhd->osh, bus->sdh) >= 0) {
9148 /* Re-init bus, enable F2 transfer */
9149 bcmerror = dhd_bus_init((dhd_pub_t *) bus->dhd, FALSE);
9150 if (bcmerror == BCME_OK) {
9151 #if defined(OOB_INTR_ONLY)
9152 dhd_enable_oob_intr(bus, TRUE);
9153 bcmsdh_oob_intr_register(bus->sdh,
9155 bcmsdh_oob_intr_set(bus->sdh, TRUE);
9156 #elif defined(FORCE_WOWLAN)
9157 dhd_enable_oob_intr(bus, TRUE);
9160 bus->dhd->dongle_reset = FALSE;
9161 bus->dhd->up = TRUE;
9163 #if !defined(IGNORE_ETH0_DOWN)
9164 /* Restore flow control */
9165 dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF);
9167 dhd_os_wd_timer(dhdp, dhd_watchdog_ms);
9169 DHD_TRACE(("%s: WLAN ON DONE\n", __FUNCTION__));
9171 dhd_bus_stop(bus, FALSE);
9172 dhdsdio_release_dongle(bus, bus->dhd->osh,
9176 DHD_ERROR(("%s Failed to download binary to the dongle\n",
9178 if (bus->sih != NULL) {
9179 si_detach(bus->sih);
9182 bcmerror = BCME_SDIO_ERROR;
9185 bcmerror = BCME_SDIO_ERROR;
9187 dhd_os_sdunlock(dhdp);
9189 bcmerror = BCME_SDIO_ERROR;
9190 printf("%s called when dongle is not in reset\n",
9192 printf("Will call dhd_bus_start instead\n");
9193 dhd_bus_resume(dhdp, 1);
9194 #if defined(HW_OOB) || defined(FORCE_WOWLAN)
9195 dhd_conf_set_hw_oob_intr(bus->sdh, bus->sih->chip); // terence 20120615: fix for OOB initial issue
9197 if ((bcmerror = dhd_bus_start(dhdp)) != 0)
9198 DHD_ERROR(("%s: dhd_bus_start fail with %d\n",
9199 __FUNCTION__, bcmerror));
9204 memset((uint8*) &tx_statics, 0, sizeof(pkt_statics_t));
9209 int dhd_bus_suspend(dhd_pub_t *dhdpub)
9211 return bcmsdh_stop(dhdpub->bus->sdh);
9214 int dhd_bus_resume(dhd_pub_t *dhdpub, int stage)
9216 return bcmsdh_start(dhdpub->bus->sdh, stage);
9219 /* Get Chip ID version */
9220 uint dhd_bus_chip_id(dhd_pub_t *dhdp)
9222 dhd_bus_t *bus = dhdp->bus;
9224 if (bus && bus->sih)
9225 return bus->sih->chip;
9230 /* Get Chip Rev ID version */
9231 uint dhd_bus_chiprev_id(dhd_pub_t *dhdp)
9233 dhd_bus_t *bus = dhdp->bus;
9235 if (bus && bus->sih)
9236 return bus->sih->chiprev;
9241 /* Get Chip Pkg ID version */
9242 uint dhd_bus_chippkg_id(dhd_pub_t *dhdp)
9244 dhd_bus_t *bus = dhdp->bus;
9246 return bus->sih->chippkg;
9249 int dhd_bus_get_ids(struct dhd_bus *bus, uint32 *bus_type, uint32 *bus_num, uint32 *slot_num)
9251 *bus_type = bus->bus;
9252 *bus_num = bus->bus_num;
9253 *slot_num = bus->slot_num;
9258 dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint size)
9263 return dhdsdio_membytes(bus, set, address, data, size);
9268 dhd_bus_update_fw_nv_path(struct dhd_bus *bus, char *pfw_path, char *pnv_path, char *pconf_path)
9270 bus->fw_path = pfw_path;
9271 bus->nv_path = pnv_path;
9272 bus->dhd->conf_path = pconf_path;
9276 dhd_enableOOB(dhd_pub_t *dhd, bool sleep)
9278 dhd_bus_t *bus = dhd->bus;
9279 sdpcmd_regs_t *regs = bus->regs;
9283 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
9284 /* Tell device to start using OOB wakeup */
9285 W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries);
9286 if (retries > retry_limit) {
9287 DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
9290 /* Turn off our contribution to the HT clock request */
9291 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
9293 /* Make sure the controller has the bus up */
9294 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
9296 /* Send misc interrupt to indicate OOB not needed */
9297 W_SDREG(0, ®s->tosbmailboxdata, retries);
9298 if (retries <= retry_limit)
9299 W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries);
9301 if (retries > retry_limit)
9302 DHD_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n"));
9304 /* Make sure we have SD bus access */
9305 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
9311 dhd_bus_pktq_flush(dhd_pub_t *dhdp)
9313 dhd_bus_t *bus = dhdp->bus;
9314 bool wlfc_enabled = FALSE;
9316 #ifdef PROP_TXSTATUS
9317 wlfc_enabled = (dhd_wlfc_cleanup_txq(dhdp, NULL, 0) != WLFC_UNSUPPORTED);
9319 if (!wlfc_enabled) {
9320 #ifdef DHDTCPACK_SUPPRESS
9321 /* Clean tcp_ack_info_tbl in order to prevent access to flushed pkt,
9322 * when there is a newly coming packet from network stack.
9324 dhd_tcpack_info_tbl_clean(bus->dhd);
9325 #endif /* DHDTCPACK_SUPPRESS */
9326 /* Clear the data packet queues */
9327 pktq_flush(dhdp->osh, &bus->txq, TRUE, NULL, 0);
9333 dhd_sr_config(dhd_pub_t *dhd, bool on)
9335 dhd_bus_t *bus = dhd->bus;
9340 return dhdsdio_clk_devsleep_iovar(bus, on);
9344 dhd_get_chipid(dhd_pub_t *dhd)
9346 dhd_bus_t *bus = dhd->bus;
9348 if (bus && bus->sih)
9349 return (uint16)bus->sih->chip;
9353 #endif /* BCMSDIO */
9356 uint32 dhd_sdio_reg_read(void *h, uint32 addr)
9359 struct dhd_bus *bus = (struct dhd_bus *) h;
9361 dhd_os_sdlock(bus->dhd);
9365 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
9367 rval = bcmsdh_reg_read(bus->sdh, addr, 4);
9369 dhd_os_sdunlock(bus->dhd);
9374 void dhd_sdio_reg_write(void *h, uint32 addr, uint32 val)
9376 struct dhd_bus *bus = (struct dhd_bus *) h;
9378 dhd_os_sdlock(bus->dhd);
9382 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
9384 bcmsdh_reg_write(bus->sdh, addr, 4, val);
9386 dhd_os_sdunlock(bus->dhd);
9388 #endif /* DEBUGGER */