2 * DHD Bus Module for SDIO
4 * Copyright (C) 1999-2019, Broadcom.
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 796833 2018-12-27 05:52:37Z $
36 #include <bcmendian.h>
43 #include <hnd_armtrap.h>
53 #include <sbsdpcmdev.h>
61 #include <dngl_stats.h>
64 #include <dhd_proto.h>
72 #ifdef DHDTCPACK_SUPPRESS
74 #endif /* DHDTCPACK_SUPPRESS */
77 #include <dhd_bt_interface.h>
78 #endif /* BT_OVER_SDIO */
80 #if defined(DEBUGGER) || defined(DHD_DSCOPE)
82 #endif /* DEBUGGER || DHD_DSCOPE */
84 bool dhd_mp_halting(dhd_pub_t
*dhdp
);
85 extern void bcmsdh_waitfor_iodrain(void *sdh
);
86 extern void bcmsdh_reject_ioreqs(void *sdh
, bool reject
);
87 extern bool bcmsdh_fatal_error(void *sdh
);
88 static int dhdsdio_suspend(void *context
);
89 static int dhdsdio_resume(void *context
);
91 #ifndef DHDSDIO_MEM_DUMP_FNAME
92 #define DHDSDIO_MEM_DUMP_FNAME "mem_dump"
95 #define QLEN (1024) /* bulk rx and tx queue lengths */
96 #define FCHI (QLEN - 10)
97 #define FCLOW (FCHI / 2)
100 #define F0_BLOCK_SIZE 32
101 #define TXRETRIES 2 /* # of retries for tx frames */
102 #define READ_FRM_CNT_RETRIES 3
104 #define DHD_RXBOUND 50 /* Default for max rx frames in one scheduling */
108 #define DHD_TXBOUND 20 /* Default for max tx frames in one scheduling */
111 #define DHD_TXMINMAX 1 /* Max tx frames if rx still pending */
113 #define MEMBLOCK 2048 /* Block size used for downloading of dongle image */
114 #define MAX_MEMBLOCK (32 * 1024) /* Block size used for downloading of dongle image */
116 #define MAX_DATA_BUF (64 * 1024) /* Must be large enough to hold biggest possible glom */
118 #ifndef DHD_FIRSTREAD
119 #define DHD_FIRSTREAD 32
121 #if !ISPOWEROF2(DHD_FIRSTREAD)
122 #error DHD_FIRSTREAD is not a power of 2!
125 /* Total length of frame header for dongle protocol */
126 #define SDPCM_HDRLEN (SDPCM_FRAMETAG_LEN + SDPCM_SWHEADER_LEN)
127 #define SDPCM_HDRLEN_TXGLOM (SDPCM_HDRLEN + SDPCM_HWEXT_LEN)
128 #define MAX_TX_PKTCHAIN_CNT SDPCM_MAXGLOM_SIZE
131 #define SDPCM_RESERVE (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN)
133 #define SDPCM_RESERVE (SDPCM_HDRLEN + DHD_SDALIGN)
136 /* Space for header read, limit for data packets */
138 #define MAX_HDR_READ 32
140 #if !ISPOWEROF2(MAX_HDR_READ)
141 #error MAX_HDR_READ is not a power of 2!
144 #define MAX_RX_DATASZ 2048
146 /* Maximum milliseconds to wait for F2 to come up */
147 #define DHD_WAIT_F2RDY 3000
149 /* Maximum usec to wait for HTAVAIL to come up */
150 #define DHD_WAIT_HTAVAIL 10000
152 /* Bump up limit on waiting for HT to account for first startup;
153 * if the image is doing a CRC calculation before programming the PMU
154 * for HT availability, it could take a couple hundred ms more, so
155 * max out at a 1 second (1000000us).
157 #if (PMU_MAX_TRANSITION_DLY <= 1000000)
158 #undef PMU_MAX_TRANSITION_DLY
159 #define PMU_MAX_TRANSITION_DLY 1000000
162 /* hooks for limiting threshold custom tx num in rx processing */
163 #define DEFAULT_TXINRX_THRES 0
164 #ifndef CUSTOM_TXINRX_THRES
165 #define CUSTOM_TXINRX_THRES DEFAULT_TXINRX_THRES
168 /* Value for ChipClockCSR during initial setup */
169 #define DHD_INIT_CLKCTL1 (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ)
170 #define DHD_INIT_CLKCTL2 (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP)
172 /* Flags for SDH calls */
173 #define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED)
175 /* Packet free applicable unconditionally for sdio and sdspi. Conditional if
176 * bufpool was present for gspi bus.
178 #define PKTFREE2() if ((bus->bus != SPI_BUS) || bus->usebufpool) \
179 PKTFREE(bus->dhd->osh, pkt, FALSE);
180 DHD_SPINWAIT_SLEEP_INIT(sdioh_spinwait_sleep
);
182 #if defined(MULTIPLE_SUPPLICANT)
183 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
184 DEFINE_MUTEX(_dhd_sdio_mutex_lock_
);
185 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
188 #ifdef SUPPORT_MULTIPLE_BOARD_REV_FROM_HW
189 extern unsigned int system_hw_rev
;
190 #endif /* SUPPORT_MULTIPLE_BOARD_REV_FROM_HW */
192 /* Device console log buffer state */
193 #define CONSOLE_LINE_MAX 192
194 #define CONSOLE_BUFFER_MAX 2024
195 typedef struct dhd_console
{
196 uint count
; /* Poll interval msec counter */
197 uint log_addr
; /* Log struct address (fixed) */
198 hnd_log_t log
; /* Log struct (host copy) */
199 uint bufsize
; /* Size of log buffer */
200 uint8
*buf
; /* Log buffer (host copy) */
201 uint last
; /* Last buffer read index */
204 #define REMAP_ENAB(bus) ((bus)->remap)
205 #define REMAP_ISADDR(bus, a) (((a) >= ((bus)->orig_ramsize)) && ((a) < ((bus)->ramsize)))
206 #define KSO_ENAB(bus) ((bus)->kso)
207 #define SR_ENAB(bus) ((bus)->_srenab)
208 #define SLPAUTO_ENAB(bus) ((SR_ENAB(bus)) && ((bus)->_slpauto))
210 #define MIN_RSRC_SR 0x3
211 #define CORE_CAPEXT_ADDR_OFFSET (0x64c)
212 #define CORE_CAPEXT_SR_SUPPORTED_MASK (1 << 1)
213 #define RCTL_MACPHY_DISABLE_MASK (1 << 26)
214 #define RCTL_LOGIC_DISABLE_MASK (1 << 27)
216 #define OOB_WAKEUP_ENAB(bus) ((bus)->_oobwakeup)
217 #define GPIO_DEV_SRSTATE 16 /* Host gpio17 mapped to device gpio0 SR state */
218 #define GPIO_DEV_SRSTATE_TIMEOUT 320000 /* 320ms */
219 #define GPIO_DEV_WAKEUP 17 /* Host gpio17 mapped to device gpio1 wakeup */
220 #define CC_CHIPCTRL2_GPIO1_WAKEUP (1 << 0)
221 #define CC_CHIPCTRL3_SR_ENG_ENABLE (1 << 2)
222 #define OVERFLOW_BLKSZ512_WM 96
223 #define OVERFLOW_BLKSZ512_MES 80
225 #define CC_PMUCC3 (0x3)
227 #ifdef DHD_UCODE_DOWNLOAD
228 /* Ucode host download related macros */
229 #define UCODE_DOWNLOAD_REQUEST 0xCAFECAFE
230 #define UCODE_DOWNLOAD_COMPLETE 0xABCDABCD
231 #endif /* DHD_UCODE_DOWNLOAD */
233 #if defined(BT_OVER_SDIO)
234 #define BTMEM_OFFSET 0x19000000
235 /* BIT0 => WLAN Power UP and BIT1=> WLAN Wake */
236 #define BT2WLAN_PWRUP_WAKE 0x03
237 #define BT2WLAN_PWRUP_ADDR 0x640894 /* This address is specific to 43012B0 */
239 #define BTFW_MAX_STR_LEN 600
240 #define BTFW_DOWNLOAD_BLK_SIZE (BTFW_MAX_STR_LEN/2 + 8)
242 #define BTFW_ADDR_MODE_UNKNOWN 0
243 #define BTFW_ADDR_MODE_EXTENDED 1
244 #define BTFW_ADDR_MODE_SEGMENT 2
245 #define BTFW_ADDR_MODE_LINEAR32 3
247 #define BTFW_HEX_LINE_TYPE_DATA 0
248 #define BTFW_HEX_LINE_TYPE_END_OF_DATA 1
249 #define BTFW_HEX_LINE_TYPE_EXTENDED_SEGMENT_ADDRESS 2
250 #define BTFW_HEX_LINE_TYPE_EXTENDED_ADDRESS 4
251 #define BTFW_HEX_LINE_TYPE_ABSOLUTE_32BIT_ADDRESS 5
253 #endif /* defined (BT_OVER_SDIO) */
255 /* Private data for SDIO bus interaction */
256 typedef struct dhd_bus
{
259 bcmsdh_info_t
*sdh
; /* Handle for BCMSDH calls */
260 si_t
*sih
; /* Handle for SI calls */
261 char *vars
; /* Variables (from CIS and/or other) */
262 uint varsz
; /* Size of variables buffer */
263 uint32 sbaddr
; /* Current SB window pointer (-1, invalid) */
265 sdpcmd_regs_t
*regs
; /* Registers for SDIO core */
266 uint sdpcmrev
; /* SDIO core revision */
267 uint armrev
; /* CPU core revision */
268 uint ramrev
; /* SOCRAM core revision */
269 uint32 ramsize
; /* Size of RAM in SOCRAM (bytes) */
270 uint32 orig_ramsize
; /* Size of RAM in SOCRAM (bytes) */
271 uint32 srmemsize
; /* Size of SRMEM */
273 uint32 bus
; /* gSPI or SDIO bus */
274 uint32 bus_num
; /* bus number */
275 uint32 slot_num
; /* slot ID */
276 uint32 hostintmask
; /* Copy of Host Interrupt Mask */
277 uint32 intstatus
; /* Intstatus bits (events) pending */
278 bool dpc_sched
; /* Indicates DPC schedule (intrpt rcvd) */
279 bool fcstate
; /* State of dongle flow-control */
281 uint16 cl_devid
; /* cached devid for dhdsdio_probe_attach() */
282 char *fw_path
; /* module_param: path to firmware image */
283 char *nv_path
; /* module_param: path to nvram vars file */
285 uint blocksize
; /* Block size of SDIO transfers */
286 uint roundup
; /* Max roundup limit */
288 struct pktq txq
; /* Queue length used for flow-control */
289 uint8 flowcontrol
; /* per prio flow control bitmask */
290 uint8 tx_seq
; /* Transmit sequence number (next) */
291 uint8 tx_max
; /* Maximum transmit sequence allowed */
293 uint8 hdrbuf
[MAX_HDR_READ
+ DHD_SDALIGN
];
294 uint8
*rxhdr
; /* Header of current rx frame (in hdrbuf) */
295 uint16 nextlen
; /* Next Read Len from last header */
296 uint8 rx_seq
; /* Receive sequence number (expected) */
297 bool rxskip
; /* Skip receive (awaiting NAK ACK) */
299 void *glomd
; /* Packet containing glomming descriptor */
300 void *glom
; /* Packet chain for glommed superframe */
301 uint glomerr
; /* Glom packet read errors */
303 uint8
*rxbuf
; /* Buffer for receiving control packets */
304 uint rxblen
; /* Allocated length of rxbuf */
305 uint8
*rxctl
; /* Aligned pointer into rxbuf */
306 uint8
*databuf
; /* Buffer for receiving big glom packet */
307 uint8
*dataptr
; /* Aligned pointer into databuf */
308 uint rxlen
; /* Length of valid data in buffer */
310 uint8 sdpcm_ver
; /* Bus protocol reported by dongle */
312 bool intr
; /* Use interrupts */
313 bool poll
; /* Use polling */
314 bool ipend
; /* Device interrupt is pending */
315 bool intdis
; /* Interrupts disabled by isr */
316 uint intrcount
; /* Count of device interrupt callbacks */
317 uint lastintrs
; /* Count as of last watchdog timer */
318 uint spurious
; /* Count of spurious interrupts */
319 uint pollrate
; /* Ticks between device polls */
320 uint polltick
; /* Tick counter */
321 uint pollcnt
; /* Count of active polls */
323 dhd_console_t console
; /* Console output polling support */
324 uint console_addr
; /* Console address from shared struct */
326 uint regfails
; /* Count of R_REG/W_REG failures */
328 uint clkstate
; /* State of sd and backplane clock(s) */
329 bool activity
; /* Activity flag for clock down */
330 int32 idletime
; /* Control for activity timeout */
331 int32 idlecount
; /* Activity timeout counter */
332 int32 idleclock
; /* How to set bus driver when idle */
333 int32 sd_divisor
; /* Speed control to bus driver */
334 int32 sd_mode
; /* Mode control to bus driver */
335 int32 sd_rxchain
; /* If bcmsdh api accepts PKT chains */
336 bool use_rxchain
; /* If dhd should use PKT chains */
337 bool sleeping
; /* Is SDIO bus sleeping? */
338 #if defined(SUPPORT_P2P_GO_PS)
339 wait_queue_head_t bus_sleep
;
340 #endif /* LINUX && SUPPORT_P2P_GO_PS */
341 uint rxflow_mode
; /* Rx flow control mode */
342 bool rxflow
; /* Is rx flow control on */
343 uint prev_rxlim_hit
; /* Is prev rx limit exceeded (per dpc schedule) */
344 bool alp_only
; /* Don't use HT clock (ALP only) */
345 /* Field to decide if rx of control frames happen in rxbuf or lb-pool */
347 int32 txinrx_thres
; /* num of in-queued pkts */
348 int32 dotxinrx
; /* tx first in dhdsdio_readframes */
350 /* external loopback */
354 /* pktgen configuration */
355 uint pktgen_freq
; /* Ticks between bursts */
356 uint pktgen_count
; /* Packets to send each burst */
357 uint pktgen_print
; /* Bursts between count displays */
358 uint pktgen_total
; /* Stop after this many */
359 uint pktgen_minlen
; /* Minimum packet data len */
360 uint pktgen_maxlen
; /* Maximum packet data len */
361 uint pktgen_mode
; /* Configured mode: tx, rx, or echo */
362 uint pktgen_stop
; /* Number of tx failures causing stop */
364 /* active pktgen fields */
365 uint pktgen_tick
; /* Tick counter for bursts */
366 uint pktgen_ptick
; /* Burst counter for printing */
367 uint pktgen_sent
; /* Number of test packets generated */
368 uint pktgen_rcvd
; /* Number of test packets received */
369 uint pktgen_prev_time
; /* Time at which previous stats where printed */
370 uint pktgen_prev_sent
; /* Number of test packets generated when
371 * previous stats were printed
373 uint pktgen_prev_rcvd
; /* Number of test packets received when
374 * previous stats were printed
376 uint pktgen_fail
; /* Number of failed send attempts */
377 uint16 pktgen_len
; /* Length of next packet to send */
378 #define PKTGEN_RCV_IDLE (0)
379 #define PKTGEN_RCV_ONGOING (1)
380 uint16 pktgen_rcv_state
; /* receive state */
381 uint pktgen_rcvd_rcvsession
; /* test pkts rcvd per rcv session. */
384 /* Some additional counters */
385 uint tx_sderrs
; /* Count of tx attempts with sd errors */
386 uint fcqueued
; /* Tx packets that got queued */
387 uint rxrtx
; /* Count of rtx requests (NAK to dongle) */
388 uint rx_toolong
; /* Receive frames too long to receive */
389 uint rxc_errors
; /* SDIO errors when reading control frames */
390 uint rx_hdrfail
; /* SDIO errors on header reads */
391 uint rx_badhdr
; /* Bad received headers (roosync?) */
392 uint rx_badseq
; /* Mismatched rx sequence number */
393 uint fc_rcvd
; /* Number of flow-control events received */
394 uint fc_xoff
; /* Number which turned on flow-control */
395 uint fc_xon
; /* Number which turned off flow-control */
396 uint rxglomfail
; /* Failed deglom attempts */
397 uint rxglomframes
; /* Number of glom frames (superframes) */
398 uint rxglompkts
; /* Number of packets from glom frames */
399 uint f2rxhdrs
; /* Number of header reads */
400 uint f2rxdata
; /* Number of frame data reads */
401 uint f2txdata
; /* Number of f2 frame writes */
402 uint f1regdata
; /* Number of f1 register accesses */
403 wake_counts_t wake_counts
; /* Wake up counter */
407 #ifdef DHDENABLE_TAILPAD
408 uint tx_tailpad_chain
; /* Number of tail padding by chaining pad_pkt */
409 uint tx_tailpad_pktget
; /* Number of tail padding by new PKTGET */
410 #endif /* DHDENABLE_TAILPAD */
411 uint8
*ctrl_frame_buf
;
412 uint32 ctrl_frame_len
;
413 bool ctrl_frame_stat
;
415 uint32 rxint_mode
; /* rx interrupt mode */
417 bool remap
; /* Contiguous 1MB RAM: 512K socram + 512K devram
418 * Available with socram rev 16
419 * Remap region not DMA-able
428 uint32 dongle_ram_base
;
430 void *glom_pkt_arr
[SDPCM_MAXGLOM_SIZE
]; /* Array of pkts for glomming */
431 uint32 txglom_cnt
; /* Number of pkts in the glom array */
432 uint32 txglom_total_len
; /* Total length of pkts in glom array */
433 bool txglom_enable
; /* Flag to indicate whether tx glom is enabled/disabled */
434 uint32 txglomsize
; /* Glom size limitation */
435 #ifdef DHDENABLE_TAILPAD
437 #endif /* DHDENABLE_TAILPAD */
438 uint32 dongle_trap_addr
; /* device trap addr location in device memory */
439 #if defined(BT_OVER_SDIO)
440 char *btfw_path
; /* module_param: path to BT firmware image */
441 uint32 bt_use_count
; /* Counter that tracks whether BT is using the bus */
442 #endif /* defined (BT_OVER_SDIO) */
446 * Whenever DHD_IDLE_IMMEDIATE condition is handled, we have to now check if
447 * BT is active too. Instead of adding #ifdef code in all the places, we thought
448 * of adding one macro check as part of the if condition that checks for DHD_IDLE_IMMEDIATE
449 * In case of non BT over SDIO builds, this macro will always return TRUE. In case
450 * of the builds where BT_OVER_SDIO is enabled, it will expand to a condition check
451 * that checks if bt_use_count is zero. So this macro will return equate to 1 if
452 * bt_use_count is 0, indicating that there are no active users and if bt_use_count
453 * is non zero it would return 0 there by preventing the caller from executing the
457 #define NO_OTHER_ACTIVE_BUS_USER(bus) (bus->bt_use_count == 0)
459 #define NO_OTHER_ACTIVE_BUS_USER(bus) (1)
460 #endif /* BT_OVER_SDIO */
465 #define CLK_PENDING 2 /* Not used yet */
468 #define DHD_NOPMU(dhd) (FALSE)
470 #if defined(BCMSDIOH_STD)
471 #define BLK_64_MAXTXGLOM 20
472 #endif /* BCMSDIOH_STD */
475 static int qcount
[NUMPRIO
];
476 static int tx_packets
[NUMPRIO
];
477 #endif /* DHD_DEBUG */
479 /* Deferred transmit */
480 const uint dhd_deferred_tx
= 1;
482 extern uint dhd_watchdog_ms
;
483 extern uint sd_f1_blocksize
;
485 #ifdef BCMSPI_ANDROID
486 extern uint
*dhd_spi_lockcount
;
487 #endif /* BCMSPI_ANDROID */
489 extern void dhd_os_wd_timer(void *bus
, uint wdtick
);
490 int dhd_enableOOB(dhd_pub_t
*dhd
, bool sleep
);
492 #ifdef DHD_PM_CONTROL_FROM_FILE
493 extern bool g_pm_control
;
494 #endif /* DHD_PM_CONTROL_FROM_FILE */
499 uint dhd_txminmax
= DHD_TXMINMAX
;
501 /* override the RAM size if possible */
502 #define DONGLE_MIN_RAMSIZE (128 *1024)
503 int dhd_dongle_ramsize
;
505 uint dhd_doflow
= TRUE
;
506 uint dhd_dpcpoll
= FALSE
;
508 module_param(dhd_doflow
, uint
, 0644);
509 module_param(dhd_dpcpoll
, uint
, 0644);
511 static bool dhd_alignctl
;
515 static bool retrydata
;
516 #define RETRYCHAN(chan) (((chan) == SDPCM_EVENT_CHANNEL) || retrydata)
519 /* At a watermark around 8 the spid hits underflow error. */
520 static uint watermark
= 32;
521 static uint mesbusyctrl
= 0;
523 static uint watermark
= 8;
524 static uint mesbusyctrl
= 0;
526 static const uint firstread
= DHD_FIRSTREAD
;
528 /* Retry count for register access failures */
529 static const uint retry_limit
= 2;
531 /* Force even SD lengths (some host controllers mess up on odd bytes) */
532 static bool forcealign
;
534 #if defined(DEBUGGER)
535 static uint32
dhd_sdio_reg_read(struct dhd_bus
*bus
, ulong addr
);
536 static void dhd_sdio_reg_write(struct dhd_bus
*bus
, ulong addr
, uint32 val
);
538 /** the debugger layer will call back into this (bus) layer to read/write dongle memory */
539 static struct dhd_dbg_bus_ops_s bus_ops
= {
541 .read_u32
= dhd_sdio_reg_read
,
542 .write_u32
= dhd_sdio_reg_write
,
544 #endif /* DEBUGGER */
548 #if defined(OOB_INTR_ONLY) && defined(HW_OOB)
549 extern void bcmsdh_enable_hw_oob_intr(void *sdh
, bool enable
);
552 #if defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD)
553 #error OOB_INTR_ONLY is NOT working with SDIO_ISR_THREAD
554 #endif /* defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD) */
555 #define PKTALIGN(osh, p, len, align) \
558 datalign = (uintptr)PKTDATA((osh), (p)); \
559 datalign = ROUNDUP(datalign, (align)) - datalign; \
560 ASSERT(datalign < (align)); \
561 ASSERT(PKTLEN((osh), (p)) >= ((len) + datalign)); \
563 PKTPULL((osh), (p), (uint)datalign); \
564 PKTSETLEN((osh), (p), (len)); \
567 /* Limit on rounding up frames */
568 static const uint max_roundup
= 512;
570 /* Try doing readahead */
571 static bool dhd_readahead
;
573 /* To check if there's window offered */
574 #define DATAOK(bus) \
575 (((uint8)(bus->tx_max - bus->tx_seq) > 1) && \
576 (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0))
578 /* To check if there's window offered for ctrl frame */
579 #define TXCTLOK(bus) \
580 (((uint8)(bus->tx_max - bus->tx_seq) != 0) && \
581 (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0))
583 /* Number of pkts available in dongle for data RX */
584 #define DATABUFCNT(bus) \
585 ((uint8)(bus->tx_max - bus->tx_seq) - 1)
587 /* Macros to get register read/write status */
588 /* NOTE: these assume a local dhdsdio_bus_t *bus! */
589 #define R_SDREG(regvar, regaddr, retryvar) \
593 regvar = R_REG(bus->dhd->osh, regaddr); \
594 } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \
596 bus->regfails += (retryvar-1); \
597 if (retryvar > retry_limit) { \
598 DHD_ERROR(("%s: FAILED" #regvar "READ, LINE %d\n", \
599 __FUNCTION__, __LINE__)); \
605 #define W_SDREG(regval, regaddr, retryvar) \
609 W_REG(bus->dhd->osh, regaddr, regval); \
610 } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \
612 bus->regfails += (retryvar-1); \
613 if (retryvar > retry_limit) \
614 DHD_ERROR(("%s: FAILED REGISTER WRITE, LINE %d\n", \
615 __FUNCTION__, __LINE__)); \
619 #define BUS_WAKE(bus) \
621 bus->idlecount = 0; \
622 if ((bus)->sleeping) \
623 dhdsdio_bussleep((bus), FALSE); \
627 * pktavail interrupts from dongle to host can be managed in 3 different ways
628 * whenever there is a packet available in dongle to transmit to host.
630 * Mode 0: Dongle writes the software host mailbox and host is interrupted.
631 * Mode 1: (sdiod core rev >= 4)
632 * Device sets a new bit in the intstatus whenever there is a packet
633 * available in fifo. Host can't clear this specific status bit until all the
634 * packets are read from the FIFO. No need to ack dongle intstatus.
635 * Mode 2: (sdiod core rev >= 4)
636 * Device sets a bit in the intstatus, and host acks this by writing
637 * one to this bit. Dongle won't generate anymore packet interrupts
638 * until host reads all the packets from the dongle and reads a zero to
639 * figure that there are no more packets. No need to disable host ints.
640 * Need to ack the intstatus.
643 #define SDIO_DEVICE_HMB_RXINT 0 /* default old way */
644 #define SDIO_DEVICE_RXDATAINT_MODE_0 1 /* from sdiod rev 4 */
645 #define SDIO_DEVICE_RXDATAINT_MODE_1 2 /* from sdiod rev 4 */
649 #define FRAME_AVAIL_MASK(bus) I_HMB_FRAME_IND
651 #define DHD_BUS SPI_BUS
653 /* check packet-available-interrupt in piggybacked dstatus */
654 #define PKT_AVAILABLE(bus, intstatus) (bcmsdh_get_dstatus(bus->sdh) & STATUS_F2_PKT_AVAILABLE)
656 #define HOSTINTMASK (I_HMB_FC_CHANGE | I_HMB_HOST_INT)
658 #define GSPI_PR55150_BAILOUT \
660 uint32 dstatussw = bcmsdh_get_dstatus((void *)bus->sdh); \
661 uint32 dstatushw = bcmsdh_cfg_read_word(bus->sdh, SDIO_FUNC_0, SPID_STATUS_REG, NULL); \
662 uint32 intstatuserr = 0; \
665 R_SDREG(intstatuserr, &bus->regs->intstatus, retries); \
666 printf("dstatussw = 0x%x, dstatushw = 0x%x, intstatus = 0x%x\n", \
667 dstatussw, dstatushw, intstatuserr); \
675 #define FRAME_AVAIL_MASK(bus) \
676 ((bus->rxint_mode == SDIO_DEVICE_HMB_RXINT) ? I_HMB_FRAME_IND : I_XMTDATA_AVAIL)
678 #define DHD_BUS SDIO_BUS
680 #define PKT_AVAILABLE(bus, intstatus) ((intstatus) & (FRAME_AVAIL_MASK(bus)))
682 #define HOSTINTMASK (I_HMB_SW_MASK | I_CHIPACTIVE)
684 #define GSPI_PR55150_BAILOUT
689 static void dhdsdio_testrcv(dhd_bus_t
*bus
, void *pkt
, uint seq
);
690 static void dhdsdio_sdtest_set(dhd_bus_t
*bus
, uint count
);
693 static int dhdsdio_checkdied(dhd_bus_t
*bus
, char *data
, uint size
);
695 static int dhd_serialconsole(dhd_bus_t
*bus
, bool get
, bool enable
, int *bcmerror
);
696 #endif /* DHD_DEBUG */
698 #if defined(DHD_FW_COREDUMP)
699 static int dhdsdio_mem_dump(dhd_bus_t
*bus
);
700 #endif /* DHD_FW_COREDUMP */
701 static int dhdsdio_devcap_set(dhd_bus_t
*bus
, uint8 cap
);
702 static int dhdsdio_download_state(dhd_bus_t
*bus
, bool enter
);
704 static void dhdsdio_release(dhd_bus_t
*bus
, osl_t
*osh
);
705 static void dhdsdio_release_malloc(dhd_bus_t
*bus
, osl_t
*osh
);
706 static void dhdsdio_disconnect(void *ptr
);
707 static bool dhdsdio_chipmatch(uint16 chipid
);
708 static bool dhdsdio_probe_attach(dhd_bus_t
*bus
, osl_t
*osh
, void *sdh
,
709 void * regsva
, uint16 devid
);
710 static bool dhdsdio_probe_malloc(dhd_bus_t
*bus
, osl_t
*osh
, void *sdh
);
711 static bool dhdsdio_probe_init(dhd_bus_t
*bus
, osl_t
*osh
, void *sdh
);
712 static void dhdsdio_release_dongle(dhd_bus_t
*bus
, osl_t
*osh
, bool dongle_isolation
,
715 static void dhd_dongle_setramsize(struct dhd_bus
*bus
, int mem_size
);
716 static int dhd_bcmsdh_recv_buf(dhd_bus_t
*bus
, uint32 addr
, uint fn
, uint flags
,
717 uint8
*buf
, uint nbytes
,
718 void *pkt
, bcmsdh_cmplt_fn_t complete
, void *handle
);
719 static int dhd_bcmsdh_send_buf(dhd_bus_t
*bus
, uint32 addr
, uint fn
, uint flags
,
720 uint8
*buf
, uint nbytes
,
721 void *pkt
, bcmsdh_cmplt_fn_t complete
, void *handle
, int max_retry
);
722 static int dhdsdio_txpkt(dhd_bus_t
*bus
, uint chan
, void** pkts
, int num_pkt
, bool free_pkt
);
723 static int dhdsdio_txpkt_preprocess(dhd_bus_t
*bus
, void *pkt
, int chan
, int txseq
,
724 int prev_chain_total_len
, bool last_chained_pkt
,
725 int *pad_pkt_len
, void **new_pkt
);
726 static int dhdsdio_txpkt_postprocess(dhd_bus_t
*bus
, void *pkt
);
728 static int dhdsdio_download_firmware(dhd_bus_t
*bus
, osl_t
*osh
, void *sdh
);
729 static int _dhdsdio_download_firmware(dhd_bus_t
*bus
);
731 #ifdef DHD_UCODE_DOWNLOAD
732 static int dhdsdio_download_ucode_file(struct dhd_bus
*bus
, char *ucode_path
);
733 #endif /* DHD_UCODE_DOWNLOAD */
734 static int dhdsdio_download_code_file(dhd_bus_t
*bus
, char *image_path
);
735 static int dhdsdio_download_nvram(dhd_bus_t
*bus
);
736 static int dhdsdio_bussleep(dhd_bus_t
*bus
, bool sleep
);
737 static int dhdsdio_clkctl(dhd_bus_t
*bus
, uint target
, bool pendok
);
738 static uint8
dhdsdio_sleepcsr_get(dhd_bus_t
*bus
);
739 static bool dhdsdio_dpc(dhd_bus_t
*bus
);
740 static int dhd_bcmsdh_send_buffer(void *bus
, uint8
*frame
, uint16 len
);
741 static int dhdsdio_set_sdmode(dhd_bus_t
*bus
, int32 sd_mode
);
742 static int dhdsdio_sdclk(dhd_bus_t
*bus
, bool on
);
743 static void dhdsdio_advertise_bus_cleanup(dhd_pub_t
*dhdp
);
745 #if defined(BT_OVER_SDIO)
746 static int extract_hex_field(char * line
, uint16 start_pos
, uint16 num_chars
, uint16
* value
);
747 static int read_more_btbytes(struct dhd_bus
*bus
, void * file
, char *line
, int * addr_mode
,
748 uint16
* hi_addr
, uint32
* dest_addr
, uint8
*data_bytes
, uint32
* num_bytes
);
749 static int dhdsdio_download_btfw(struct dhd_bus
*bus
, osl_t
*osh
, void *sdh
);
750 static int _dhdsdio_download_btfw(struct dhd_bus
*bus
);
751 #endif /* defined (BT_OVER_SDIO) */
755 static int dhd_bus_ulp_reinit_fw(dhd_bus_t
*bus
);
759 dhdsdio_tune_fifoparam(struct dhd_bus
*bus
)
762 uint8 devctl
, wm
, mes
;
764 if (bus
->sih
->buscorerev
>= 15) {
765 /* See .ppt in PR for these recommended values */
766 if (bus
->blocksize
== 512) {
767 wm
= OVERFLOW_BLKSZ512_WM
;
768 mes
= OVERFLOW_BLKSZ512_MES
;
770 mes
= bus
->blocksize
/4;
771 wm
= bus
->blocksize
/4;
777 DHD_INFO(("skip fifotune: SdioRev(%d) is lower than minimal requested ver\n",
778 bus
->sih
->buscorerev
));
782 /* Update watermark */
784 bcmsdh_cfg_write(bus
->sdh
, SDIO_FUNC_1
, SBSDIO_WATERMARK
, wm
, &err
);
786 devctl
= bcmsdh_cfg_read(bus
->sdh
, SDIO_FUNC_1
, SBSDIO_DEVICE_CTL
, &err
);
787 devctl
|= SBSDIO_DEVCTL_F2WM_ENAB
;
788 bcmsdh_cfg_write(bus
->sdh
, SDIO_FUNC_1
, SBSDIO_DEVICE_CTL
, devctl
, &err
);
793 bcmsdh_cfg_write(bus
->sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_MESBUSYCTRL
,
794 (mes
| SBSDIO_MESBUSYCTRL_ENAB
), &err
);
797 DHD_INFO(("Apply overflow WAR: 0x%02x 0x%02x 0x%02x\n",
798 bcmsdh_cfg_read(bus
->sdh
, SDIO_FUNC_1
, SBSDIO_DEVICE_CTL
, &err
),
799 bcmsdh_cfg_read(bus
->sdh
, SDIO_FUNC_1
, SBSDIO_WATERMARK
, &err
),
800 bcmsdh_cfg_read(bus
->sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_MESBUSYCTRL
, &err
)));
804 dhd_dongle_setramsize(struct dhd_bus
*bus
, int mem_size
)
806 int32 min_size
= DONGLE_MIN_RAMSIZE
;
807 /* Restrict the ramsize to user specified limit */
808 DHD_ERROR(("user: Restrict the dongle ram size to %d, min accepted %d\n",
809 dhd_dongle_ramsize
, min_size
));
810 if ((dhd_dongle_ramsize
> min_size
) &&
811 (dhd_dongle_ramsize
< (int32
)bus
->orig_ramsize
))
812 bus
->ramsize
= dhd_dongle_ramsize
;
816 dhdsdio_set_siaddr_window(dhd_bus_t
*bus
, uint32 address
)
819 bcmsdh_cfg_write(bus
->sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_SBADDRLOW
,
820 (address
>> 8) & SBSDIO_SBADDRLOW_MASK
, &err
);
822 bcmsdh_cfg_write(bus
->sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_SBADDRMID
,
823 (address
>> 16) & SBSDIO_SBADDRMID_MASK
, &err
);
825 bcmsdh_cfg_write(bus
->sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_SBADDRHIGH
,
826 (address
>> 24) & SBSDIO_SBADDRHIGH_MASK
, &err
);
832 dhdsdio_wkwlan(dhd_bus_t
*bus
, bool on
)
836 bcmsdh_info_t
*sdh
= bus
->sdh
;
838 if (bus
->sih
->buscoretype
== SDIOD_CORE_ID
) {
839 /* wake up wlan function :WAKE_UP goes as ht_avail_request and alp_avail_request */
840 regdata
= bcmsdh_cfg_read_word(sdh
, SDIO_FUNC_0
, SPID_CONFIG
, NULL
);
841 DHD_INFO(("F0 REG0 rd = 0x%x\n", regdata
));
848 bcmsdh_cfg_write_word(sdh
, SDIO_FUNC_0
, SPID_CONFIG
, regdata
, &err
);
855 dhdsdio_oobwakeup_init(dhd_bus_t
*bus
)
857 uint32 val
, addr
, data
;
859 bcmsdh_gpioouten(bus
->sdh
, GPIO_DEV_WAKEUP
);
861 addr
= SI_ENUM_BASE(bus
->sih
) + OFFSETOF(chipcregs_t
, chipcontrol_addr
);
862 data
= SI_ENUM_BASE(bus
->sih
) + OFFSETOF(chipcregs_t
, chipcontrol_data
);
864 /* Set device for gpio1 wakeup */
865 bcmsdh_reg_write(bus
->sdh
, addr
, 4, 2);
866 val
= bcmsdh_reg_read(bus
->sdh
, data
, 4);
867 val
|= CC_CHIPCTRL2_GPIO1_WAKEUP
;
868 bcmsdh_reg_write(bus
->sdh
, data
, 4, val
);
870 bus
->_oobwakeup
= TRUE
;
874 #endif /* USE_OOB_GPIO1 */
878 * Query if FW is in SR mode
881 dhdsdio_sr_cap(dhd_bus_t
*bus
)
884 uint32 core_capext
, addr
, data
;
886 if (bus
->sih
->chip
== BCM43430_CHIP_ID
||
887 bus
->sih
->chip
== BCM43018_CHIP_ID
) {
888 /* check if fw initialized sr engine */
889 addr
= SI_ENUM_BASE(bus
->sih
) + OFFSETOF(chipcregs_t
, sr_control1
);
890 if (bcmsdh_reg_read(bus
->sdh
, addr
, 4) != 0)
898 } else if ((bus
->sih
->chip
== BCM4335_CHIP_ID
) ||
899 (bus
->sih
->chip
== BCM4339_CHIP_ID
) ||
900 BCM4345_CHIP(bus
->sih
->chip
) ||
901 (bus
->sih
->chip
== BCM4354_CHIP_ID
) ||
902 (bus
->sih
->chip
== BCM4358_CHIP_ID
) ||
903 (BCM4349_CHIP(bus
->sih
->chip
)) ||
904 (bus
->sih
->chip
== BCM4350_CHIP_ID
) ||
905 (bus
->sih
->chip
== BCM43012_CHIP_ID
) ||
906 (bus
->sih
->chip
== BCM43014_CHIP_ID
)) {
909 core_capext
= bcmsdh_reg_read(bus
->sdh
,
910 si_get_pmu_reg_addr(bus
->sih
, OFFSETOF(chipcregs_t
, core_cap_ext
)),
913 core_capext
= (core_capext
& CORE_CAPEXT_SR_SUPPORTED_MASK
);
918 if ((bus
->sih
->chip
== BCM4335_CHIP_ID
) ||
919 (bus
->sih
->chip
== BCM4339_CHIP_ID
) ||
920 BCM4345_CHIP(bus
->sih
->chip
) ||
921 (bus
->sih
->chip
== BCM4354_CHIP_ID
) ||
922 (bus
->sih
->chip
== BCM4358_CHIP_ID
) ||
923 (bus
->sih
->chip
== BCM4350_CHIP_ID
)) {
925 addr
= SI_ENUM_BASE(bus
->sih
) + OFFSETOF(chipcregs_t
, chipcontrol_addr
);
926 data
= SI_ENUM_BASE(bus
->sih
) + OFFSETOF(chipcregs_t
, chipcontrol_data
);
927 bcmsdh_reg_write(bus
->sdh
, addr
, 4, CC_PMUCC3
);
928 enabval
= bcmsdh_reg_read(bus
->sdh
, data
, 4);
930 if ((bus
->sih
->chip
== BCM4350_CHIP_ID
) ||
931 BCM4345_CHIP(bus
->sih
->chip
) ||
932 (bus
->sih
->chip
== BCM4354_CHIP_ID
) ||
933 (bus
->sih
->chip
== BCM4358_CHIP_ID
))
934 enabval
&= CC_CHIPCTRL3_SR_ENG_ENABLE
;
939 data
= bcmsdh_reg_read(bus
->sdh
,
940 si_get_pmu_reg_addr(bus
->sih
, OFFSETOF(chipcregs_t
, retention_ctl
)),
942 if ((data
& (RCTL_MACPHY_DISABLE_MASK
| RCTL_LOGIC_DISABLE_MASK
)) == 0)
950 dhdsdio_sr_init(dhd_bus_t
*bus
)
955 if (bus
->sih
->chip
== BCM43012_CHIP_ID
) {
956 val
= bcmsdh_cfg_read(bus
->sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_WAKEUPCTRL
, NULL
);
957 val
|= 1 << SBSDIO_FUNC1_WCTRL_ALPWAIT_SHIFT
;
958 bcmsdh_cfg_write(bus
->sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_WAKEUPCTRL
,
959 1 << SBSDIO_FUNC1_WCTRL_ALPWAIT_SHIFT
, &err
);
960 val
= bcmsdh_cfg_read(bus
->sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_WAKEUPCTRL
, NULL
);
962 val
= bcmsdh_cfg_read(bus
->sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_WAKEUPCTRL
, NULL
);
963 val
|= 1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT
;
964 bcmsdh_cfg_write(bus
->sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_WAKEUPCTRL
,
965 1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT
, &err
);
966 val
= bcmsdh_cfg_read(bus
->sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_WAKEUPCTRL
, NULL
);
970 /* Add CMD14 Support */
971 dhdsdio_devcap_set(bus
,
972 (SDIOD_CCCR_BRCM_CARDCAP_CMD14_SUPPORT
| SDIOD_CCCR_BRCM_CARDCAP_CMD14_EXT
));
973 #endif /* USE_CMD14 */
975 if (CHIPID(bus
->sih
->chip
) == BCM43430_CHIP_ID
||
976 CHIPID(bus
->sih
->chip
) == BCM43018_CHIP_ID
||
977 CHIPID(bus
->sih
->chip
) == BCM4339_CHIP_ID
||
978 CHIPID(bus
->sih
->chip
) == BCM43012_CHIP_ID
||
979 CHIPID(bus
->sih
->chip
) == BCM43014_CHIP_ID
)
980 dhdsdio_devcap_set(bus
, SDIOD_CCCR_BRCM_CARDCAP_CMD_NODEC
);
982 if (bus
->sih
->chip
== BCM43012_CHIP_ID
) {
983 bcmsdh_cfg_write(bus
->sdh
, SDIO_FUNC_1
,
984 SBSDIO_FUNC1_CHIPCLKCSR
, SBSDIO_HT_AVAIL_REQ
, &err
);
986 bcmsdh_cfg_write(bus
->sdh
, SDIO_FUNC_1
,
987 SBSDIO_FUNC1_CHIPCLKCSR
, SBSDIO_FORCE_HT
, &err
);
989 bus
->_slpauto
= dhd_slpauto
? TRUE
: FALSE
;
998 * FIX: Be sure KSO bit is enabled
999 * Currently, it's defaulting to 0 which should be 1.
1002 dhdsdio_clk_kso_init(dhd_bus_t
*bus
)
1011 * Enable KeepSdioOn (KSO) bit for normal operation
1012 * Default is 0 (4334A0) so set it. Fixed in B0.
1014 val
= bcmsdh_cfg_read(bus
->sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_SLEEPCSR
, NULL
);
1015 if (!(val
& SBSDIO_FUNC1_SLEEPCSR_KSO_MASK
)) {
1016 val
|= (SBSDIO_FUNC1_SLEEPCSR_KSO_EN
<< SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT
);
1017 bcmsdh_cfg_write(bus
->sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_SLEEPCSR
, val
, &err
);
1019 DHD_ERROR(("%s: SBSDIO_FUNC1_SLEEPCSR err: 0x%x\n", __FUNCTION__
, err
));
1026 #define KSO_WAIT_US 50
1027 #define KSO_WAIT_MS 1
1028 #define KSO_SLEEP_RETRY_COUNT 20
1029 #define KSO_WAKE_RETRY_COUNT 100
1030 #define ERROR_BCME_NODEVICE_MAX 1
1032 #define DEFAULT_MAX_KSO_ATTEMPTS (PMU_MAX_TRANSITION_DLY/KSO_WAIT_US)
1033 #ifndef CUSTOM_MAX_KSO_ATTEMPTS
1034 #define CUSTOM_MAX_KSO_ATTEMPTS DEFAULT_MAX_KSO_ATTEMPTS
1038 dhdsdio_clk_kso_enab(dhd_bus_t
*bus
, bool on
)
1040 uint8 wr_val
= 0, rd_val
, cmp_val
, bmask
;
1044 KSO_DBG(("%s> op:%s\n", __FUNCTION__
, (on
? "KSO_SET" : "KSO_CLR")));
1046 wr_val
|= (on
<< SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT
);
1048 bcmsdh_cfg_write(bus
->sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_SLEEPCSR
, wr_val
, &err
);
1050 /* In case of 43012 chip, the chip could go down immediately after KSO bit is cleared.
1051 * So the further reads of KSO register could fail. Thereby just bailing out immediately
1052 * after clearing KSO bit, to avoid polling of KSO bit.
1054 if ((!on
) && (bus
->sih
->chip
== BCM43012_CHIP_ID
)) {
1059 cmp_val
= SBSDIO_FUNC1_SLEEPCSR_KSO_MASK
| SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK
;
1065 /* Put device to sleep, turn off KSO */
1067 bmask
= SBSDIO_FUNC1_SLEEPCSR_KSO_MASK
;
1071 rd_val
= bcmsdh_cfg_read(bus
->sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_SLEEPCSR
, &err
);
1072 if (((rd_val
& bmask
) == cmp_val
) && !err
)
1075 KSO_DBG(("%s> KSO wr/rd retry:%d, ERR:%x \n", __FUNCTION__
, try_cnt
, err
));
1077 if (((try_cnt
+ 1) % KSO_SLEEP_RETRY_COUNT
) == 0) {
1078 OSL_SLEEP(KSO_WAIT_MS
);
1080 OSL_DELAY(KSO_WAIT_US
);
1082 bcmsdh_cfg_write(bus
->sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_SLEEPCSR
, wr_val
, &err
);
1083 } while (try_cnt
++ < CUSTOM_MAX_KSO_ATTEMPTS
);
1086 KSO_DBG(("%s> op:%s, try_cnt:%d, rd_val:%x, ERR:%x \n",
1087 __FUNCTION__
, (on
? "KSO_SET" : "KSO_CLR"), try_cnt
, rd_val
, err
));
1089 if (try_cnt
> CUSTOM_MAX_KSO_ATTEMPTS
) {
1090 DHD_ERROR(("%s> op:%s, ERROR: try_cnt:%d, rd_val:%x, ERR:%x \n",
1091 __FUNCTION__
, (on
? "KSO_SET" : "KSO_CLR"), try_cnt
, rd_val
, err
));
1098 dhdsdio_clk_kso_iovar(dhd_bus_t
*bus
, bool on
)
1105 dhdsdio_clkctl(bus
, CLK_AVAIL
, FALSE
);
1107 DHD_ERROR(("%s: KSO disable clk: 0x%x\n", __FUNCTION__
,
1108 bcmsdh_cfg_read(bus
->sdh
, SDIO_FUNC_1
,
1109 SBSDIO_FUNC1_CHIPCLKCSR
, &err
)));
1110 dhdsdio_clk_kso_enab(bus
, FALSE
);
1112 DHD_ERROR(("%s: KSO enable\n", __FUNCTION__
));
1114 /* Make sure we have SD bus access */
1115 if (bus
->clkstate
== CLK_NONE
) {
1116 DHD_ERROR(("%s: Request SD clk\n", __FUNCTION__
));
1117 dhdsdio_clkctl(bus
, CLK_SDONLY
, FALSE
);
1120 dhdsdio_clk_kso_enab(bus
, TRUE
);
1122 DHD_ERROR(("%s: sleepcsr: 0x%x\n", __FUNCTION__
,
1123 dhdsdio_sleepcsr_get(bus
)));
1133 dhdsdio_sleepcsr_get(dhd_bus_t
*bus
)
1138 val
= bcmsdh_cfg_read(bus
->sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_SLEEPCSR
, &err
);
1140 DHD_TRACE(("Failed to read SLEEPCSR: %d\n", err
));
1146 dhdsdio_devcap_get(dhd_bus_t
*bus
)
1148 return bcmsdh_cfg_read(bus
->sdh
, SDIO_FUNC_0
, SDIOD_CCCR_BRCM_CARDCAP
, NULL
);
1152 dhdsdio_devcap_set(dhd_bus_t
*bus
, uint8 cap
)
1156 bcmsdh_cfg_write(bus
->sdh
, SDIO_FUNC_0
, SDIOD_CCCR_BRCM_CARDCAP
, cap
, &err
);
1158 DHD_ERROR(("%s: devcap set err: 0x%x\n", __FUNCTION__
, err
));
1164 dhdsdio_clk_devsleep_iovar(dhd_bus_t
*bus
, bool on
)
1173 /* Be sure we request clk before going to sleep
1174 * so we can wake-up with clk request already set
1175 * else device can go back to sleep immediately
1177 if (!SLPAUTO_ENAB(bus
))
1178 dhdsdio_clkctl(bus
, CLK_AVAIL
, FALSE
);
1180 val
= bcmsdh_cfg_read(bus
->sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_CHIPCLKCSR
, &err
);
1181 if ((val
& SBSDIO_CSR_MASK
) == 0) {
1182 DHD_ERROR(("%s: No clock before enter sleep:0x%x\n",
1183 __FUNCTION__
, val
));
1185 /* Reset clock request */
1186 bcmsdh_cfg_write(bus
->sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_CHIPCLKCSR
,
1187 SBSDIO_ALP_AVAIL_REQ
, &err
);
1188 DHD_ERROR(("%s: clock before sleep:0x%x\n", __FUNCTION__
,
1189 bcmsdh_cfg_read(bus
->sdh
, SDIO_FUNC_1
,
1190 SBSDIO_FUNC1_CHIPCLKCSR
, &err
)));
1194 DHD_TRACE(("%s: clk before sleep: 0x%x\n", __FUNCTION__
,
1195 bcmsdh_cfg_read(bus
->sdh
, SDIO_FUNC_1
,
1196 SBSDIO_FUNC1_CHIPCLKCSR
, &err
)));
1198 err
= bcmsdh_sleep(bus
->sdh
, TRUE
);
1200 if ((SLPAUTO_ENAB(bus
)) && (bus
->idleclock
== DHD_IDLE_STOP
)) {
1202 /* Change to SD1 mode */
1203 dhdsdio_set_sdmode(bus
, 1);
1207 err
= dhdsdio_clk_kso_enab(bus
, FALSE
);
1208 if (OOB_WAKEUP_ENAB(bus
))
1210 err
= bcmsdh_gpioout(bus
->sdh
, GPIO_DEV_WAKEUP
, FALSE
); /* GPIO_1 is off */
1212 #endif /* USE_CMD14 */
1214 if ((SLPAUTO_ENAB(bus
)) && (bus
->idleclock
!= DHD_IDLE_ACTIVE
)) {
1215 DHD_TRACE(("%s: Turnoff SD clk\n", __FUNCTION__
));
1216 /* Now remove the SD clock */
1217 err
= dhdsdio_sdclk(bus
, FALSE
);
1221 /* Make sure we have SD bus access */
1222 if (bus
->clkstate
== CLK_NONE
) {
1223 DHD_TRACE(("%s: Request SD clk\n", __FUNCTION__
));
1224 dhdsdio_clkctl(bus
, CLK_SDONLY
, FALSE
);
1227 err
= bcmsdh_sleep(bus
->sdh
, FALSE
);
1228 if (SLPAUTO_ENAB(bus
) && (err
!= 0)) {
1230 DHD_TRACE(("%s: Resync device sleep\n", __FUNCTION__
));
1232 /* Toggle sleep to resync with host and device */
1233 err
= bcmsdh_sleep(bus
->sdh
, TRUE
);
1235 err
= bcmsdh_sleep(bus
->sdh
, FALSE
);
1239 DHD_ERROR(("%s: CMD14 exit failed again!\n", __FUNCTION__
));
1241 /* Toggle sleep to resync with host and device */
1242 err
= bcmsdh_sleep(bus
->sdh
, TRUE
);
1244 err
= bcmsdh_sleep(bus
->sdh
, FALSE
);
1246 DHD_ERROR(("%s: CMD14 exit failed twice!\n", __FUNCTION__
));
1247 DHD_ERROR(("%s: FATAL: Device non-response!\n",
1254 if (OOB_WAKEUP_ENAB(bus
))
1256 err
= bcmsdh_gpioout(bus
->sdh
, GPIO_DEV_WAKEUP
, TRUE
); /* GPIO_1 is on */
1259 err
= dhdsdio_clk_kso_enab(bus
, TRUE
);
1262 } while ((err
!= 0) && (++retry
< 3));
1265 DHD_ERROR(("ERROR: kso set failed retry: %d\n", retry
));
1266 #ifndef BT_OVER_SDIO
1267 err
= 0; /* continue anyway */
1268 #endif /* BT_OVER_SDIO */
1271 if ((SLPAUTO_ENAB(bus
)) && (bus
->idleclock
== DHD_IDLE_STOP
)) {
1272 dhdsdio_set_sdmode(bus
, bus
->sd_mode
);
1274 #endif /* !USE_CMD14 */
1279 /* Wait for device ready during transition to wake-up */
1280 SPINWAIT_SLEEP(sdioh_spinwait_sleep
,
1281 (((csr
= dhdsdio_sleepcsr_get(bus
)) &
1282 SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK
) !=
1283 (SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK
)), (20000));
1285 DHD_TRACE(("%s: ExitSleep sleepcsr: 0x%x\n", __FUNCTION__
, csr
));
1287 if (!(csr
& SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK
)) {
1288 DHD_ERROR(("%s:ERROR: ExitSleep device NOT Ready! 0x%x\n",
1289 __FUNCTION__
, csr
));
1290 err
= BCME_NODEVICE
;
1293 SPINWAIT_SLEEP(sdioh_spinwait_sleep
,
1294 (((csr
= bcmsdh_cfg_read(bus
->sdh
, SDIO_FUNC_1
,
1295 SBSDIO_FUNC1_CHIPCLKCSR
, &err
)) & SBSDIO_HT_AVAIL
) !=
1296 (SBSDIO_HT_AVAIL
)), (DHD_WAIT_HTAVAIL
));
1298 DHD_TRACE(("%s: SBSDIO_FUNC1_CHIPCLKCSR : 0x%x\n", __FUNCTION__
, csr
));
1299 if (!err
&& ((csr
& SBSDIO_HT_AVAIL
) != SBSDIO_HT_AVAIL
)) {
1300 DHD_ERROR(("%s:ERROR: device NOT Ready! 0x%x\n",
1301 __FUNCTION__
, csr
));
1302 err
= BCME_NODEVICE
;
1307 /* Update if successful */
1309 bus
->kso
= on
? FALSE
: TRUE
;
1311 DHD_ERROR(("%s: Sleep request failed: kso:%d on:%d err:%d\n",
1312 __FUNCTION__
, bus
->kso
, on
, err
));
1313 if (!on
&& retry
> 2)
1320 /* Turn backplane clock on or off */
1322 dhdsdio_htclk(dhd_bus_t
*bus
, bool on
, bool pendok
)
1324 #define HT_AVAIL_ERROR_MAX 10
1325 static int ht_avail_error
= 0;
1327 uint8 clkctl
, clkreq
, devctl
;
1330 DHD_TRACE(("%s: Enter\n", __FUNCTION__
));
1338 if (SLPAUTO_ENAB(bus
)) {
1339 bus
->clkstate
= (on
? CLK_AVAIL
: CLK_SDONLY
);
1344 /* Request HT Avail */
1345 clkreq
= bus
->alp_only
? SBSDIO_ALP_AVAIL_REQ
: SBSDIO_HT_AVAIL_REQ
;
1348 dhdsdio_wkwlan(bus
, TRUE
);
1351 bcmsdh_cfg_write(sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_CHIPCLKCSR
, clkreq
, &err
);
1354 if (ht_avail_error
< HT_AVAIL_ERROR_MAX
) {
1355 DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__
, err
));
1358 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
1359 else if (ht_avail_error
== HT_AVAIL_ERROR_MAX
) {
1360 bus
->dhd
->hang_reason
= HANG_REASON_HT_AVAIL_ERROR
;
1361 dhd_os_send_hang_message(bus
->dhd
);
1363 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) */
1369 /* Check current status */
1370 clkctl
= bcmsdh_cfg_read(sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_CHIPCLKCSR
, &err
);
1372 DHD_ERROR(("%s: HT Avail read error: %d\n", __FUNCTION__
, err
));
1376 #if !defined(OOB_INTR_ONLY)
1377 /* Go to pending and await interrupt if appropriate */
1378 if (!SBSDIO_CLKAV(clkctl
, bus
->alp_only
) && pendok
) {
1379 /* Allow only clock-available interrupt */
1380 devctl
= bcmsdh_cfg_read(sdh
, SDIO_FUNC_1
, SBSDIO_DEVICE_CTL
, &err
);
1382 DHD_ERROR(("%s: Devctl access error setting CA: %d\n",
1383 __FUNCTION__
, err
));
1387 devctl
|= SBSDIO_DEVCTL_CA_INT_ONLY
;
1388 bcmsdh_cfg_write(sdh
, SDIO_FUNC_1
, SBSDIO_DEVICE_CTL
, devctl
, &err
);
1389 DHD_INFO(("CLKCTL: set PENDING\n"));
1390 bus
->clkstate
= CLK_PENDING
;
1393 #endif /* !defined (OOB_INTR_ONLY) */
1395 if (bus
->clkstate
== CLK_PENDING
) {
1396 /* Cancel CA-only interrupt filter */
1397 devctl
= bcmsdh_cfg_read(sdh
, SDIO_FUNC_1
, SBSDIO_DEVICE_CTL
, &err
);
1398 devctl
&= ~SBSDIO_DEVCTL_CA_INT_ONLY
;
1399 bcmsdh_cfg_write(sdh
, SDIO_FUNC_1
, SBSDIO_DEVICE_CTL
, devctl
, &err
);
1403 /* Otherwise, wait here (polling) for HT Avail */
1404 if (!SBSDIO_CLKAV(clkctl
, bus
->alp_only
)) {
1405 SPINWAIT_SLEEP(sdioh_spinwait_sleep
,
1406 ((clkctl
= bcmsdh_cfg_read(sdh
, SDIO_FUNC_1
,
1407 SBSDIO_FUNC1_CHIPCLKCSR
, &err
)),
1408 !SBSDIO_CLKAV(clkctl
, bus
->alp_only
)), PMU_MAX_TRANSITION_DLY
);
1411 DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__
, err
));
1414 if (!SBSDIO_CLKAV(clkctl
, bus
->alp_only
)) {
1415 DHD_ERROR(("%s: HT Avail timeout (%d): clkctl 0x%02x\n",
1416 __FUNCTION__
, PMU_MAX_TRANSITION_DLY
, clkctl
));
1419 #endif /* BCMSDIOLITE */
1420 /* Mark clock available */
1421 bus
->clkstate
= CLK_AVAIL
;
1422 DHD_INFO(("CLKCTL: turned ON\n"));
1424 #if defined(DHD_DEBUG)
1425 if (bus
->alp_only
== TRUE
) {
1426 #if !defined(BCMLXSDMMC)
1427 if (!SBSDIO_ALPONLY(clkctl
)) {
1428 DHD_ERROR(("%s: HT Clock, when ALP Only\n", __FUNCTION__
));
1430 #endif /* !defined(BCMLXSDMMC) */
1432 if (SBSDIO_ALPONLY(clkctl
)) {
1433 DHD_ERROR(("%s: HT Clock should be on.\n", __FUNCTION__
));
1436 #endif /* defined (DHD_DEBUG) */
1438 bus
->activity
= TRUE
;
1439 #ifdef DHD_USE_IDLECOUNT
1441 #endif /* DHD_USE_IDLECOUNT */
1445 if (bus
->clkstate
== CLK_PENDING
) {
1446 /* Cancel CA-only interrupt filter */
1447 devctl
= bcmsdh_cfg_read(sdh
, SDIO_FUNC_1
, SBSDIO_DEVICE_CTL
, &err
);
1448 devctl
&= ~SBSDIO_DEVCTL_CA_INT_ONLY
;
1449 bcmsdh_cfg_write(sdh
, SDIO_FUNC_1
, SBSDIO_DEVICE_CTL
, devctl
, &err
);
1452 bus
->clkstate
= CLK_SDONLY
;
1453 if (!SR_ENAB(bus
)) {
1454 bcmsdh_cfg_write(sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_CHIPCLKCSR
, clkreq
, &err
);
1455 DHD_INFO(("CLKCTL: turned OFF\n"));
1457 DHD_ERROR(("%s: Failed access turning clock off: %d\n",
1458 __FUNCTION__
, err
));
1463 dhdsdio_wkwlan(bus
, FALSE
);
1469 /* Change SD1/SD4 bus mode */
1471 dhdsdio_set_sdmode(dhd_bus_t
*bus
, int32 sd_mode
)
1475 err
= bcmsdh_iovar_op(bus
->sdh
, "sd_mode", NULL
, 0,
1476 &sd_mode
, sizeof(sd_mode
), TRUE
);
1478 DHD_ERROR(("%s: error changing sd_mode: %d\n",
1479 __FUNCTION__
, err
));
1485 /* Change idle/active SD state */
1487 dhdsdio_sdclk(dhd_bus_t
*bus
, bool on
)
1493 DHD_TRACE(("%s: Enter\n", __FUNCTION__
));
1496 if (bus
->idleclock
== DHD_IDLE_STOP
) {
1497 /* Turn on clock and restore mode */
1499 err
= bcmsdh_iovar_op(bus
->sdh
, "sd_clock", NULL
, 0,
1500 &iovalue
, sizeof(iovalue
), TRUE
);
1502 DHD_ERROR(("%s: error enabling sd_clock: %d\n",
1503 __FUNCTION__
, err
));
1507 } else if (bus
->idleclock
!= DHD_IDLE_ACTIVE
) {
1508 /* Restore clock speed */
1509 iovalue
= bus
->sd_divisor
;
1510 err
= bcmsdh_iovar_op(bus
->sdh
, "sd_divisor", NULL
, 0,
1511 &iovalue
, sizeof(iovalue
), TRUE
);
1513 DHD_ERROR(("%s: error restoring sd_divisor: %d\n",
1514 __FUNCTION__
, err
));
1518 bus
->clkstate
= CLK_SDONLY
;
1520 /* Stop or slow the SD clock itself */
1521 if ((bus
->sd_divisor
== -1) || (bus
->sd_mode
== -1)) {
1522 DHD_TRACE(("%s: can't idle clock, divisor %d mode %d\n",
1523 __FUNCTION__
, bus
->sd_divisor
, bus
->sd_mode
));
1526 if (bus
->idleclock
== DHD_IDLE_STOP
) {
1528 err
= bcmsdh_iovar_op(bus
->sdh
, "sd_clock", NULL
, 0,
1529 &iovalue
, sizeof(iovalue
), TRUE
);
1531 DHD_ERROR(("%s: error disabling sd_clock: %d\n",
1532 __FUNCTION__
, err
));
1535 } else if (bus
->idleclock
!= DHD_IDLE_ACTIVE
) {
1536 /* Set divisor to idle value */
1537 iovalue
= bus
->idleclock
;
1538 err
= bcmsdh_iovar_op(bus
->sdh
, "sd_divisor", NULL
, 0,
1539 &iovalue
, sizeof(iovalue
), TRUE
);
1541 DHD_ERROR(("%s: error changing sd_divisor: %d\n",
1542 __FUNCTION__
, err
));
1546 bus
->clkstate
= CLK_NONE
;
1553 /* Transition SD and backplane clock readiness */
1555 dhdsdio_clkctl(dhd_bus_t
*bus
, uint target
, bool pendok
)
1559 uint oldstate
= bus
->clkstate
;
1560 #endif /* DHD_DEBUG */
1562 DHD_TRACE(("%s: Enter\n", __FUNCTION__
));
1564 /* Early exit if we're already there */
1565 if (bus
->clkstate
== target
) {
1566 if (target
== CLK_AVAIL
) {
1567 dhd_os_wd_timer(bus
->dhd
, dhd_watchdog_ms
);
1568 bus
->activity
= TRUE
;
1569 #ifdef DHD_USE_IDLECOUNT
1571 #endif /* DHD_USE_IDLECOUNT */
1578 /* Make sure SD clock is available */
1579 if (bus
->clkstate
== CLK_NONE
)
1580 dhdsdio_sdclk(bus
, TRUE
);
1581 /* Now request HT Avail on the backplane */
1582 ret
= dhdsdio_htclk(bus
, TRUE
, pendok
);
1583 if (ret
== BCME_OK
) {
1584 dhd_os_wd_timer(bus
->dhd
, dhd_watchdog_ms
);
1585 bus
->activity
= TRUE
;
1586 #ifdef DHD_USE_IDLECOUNT
1588 #endif /* DHD_USE_IDLECOUNT */
1596 * If the request is to switch off Back plane clock,
1597 * confirm that BT is inactive before doing so.
1598 * If this call had come from Non Watchdog context any way
1599 * the Watchdog would switch off the clock again when
1600 * nothing is to be done & Bt has finished using the bus.
1602 if (bus
->bt_use_count
!= 0) {
1603 DHD_INFO(("%s(): Req CLK_SDONLY, BT is active %d not switching off \r\n",
1604 __FUNCTION__
, bus
->bt_use_count
));
1606 dhd_os_wd_timer(bus
->dhd
, dhd_watchdog_ms
);
1610 DHD_INFO(("%s(): Request CLK_NONE BT is NOT active switching off \r\n",
1612 #endif /* BT_OVER_SDIO */
1614 /* Remove HT request, or bring up SD clock */
1615 if (bus
->clkstate
== CLK_NONE
)
1616 ret
= dhdsdio_sdclk(bus
, TRUE
);
1617 else if (bus
->clkstate
== CLK_AVAIL
)
1618 ret
= dhdsdio_htclk(bus
, FALSE
, FALSE
);
1620 DHD_ERROR(("dhdsdio_clkctl: request for %d -> %d\n",
1621 bus
->clkstate
, target
));
1622 if (ret
== BCME_OK
) {
1623 dhd_os_wd_timer(bus
->dhd
, dhd_watchdog_ms
);
1631 * If the request is to switch off Back plane clock,
1632 * confirm that BT is inactive before doing so.
1633 * If this call had come from Non Watchdog context any way
1634 * the Watchdog would switch off the clock again when
1635 * nothing is to be done & Bt has finished using the bus.
1637 if (bus
->bt_use_count
!= 0) {
1638 DHD_INFO(("%s(): Request CLK_NONE BT is active %d not switching off \r\n",
1639 __FUNCTION__
, bus
->bt_use_count
));
1644 DHD_INFO(("%s(): Request CLK_NONE BT is NOT active switching off \r\n",
1646 #endif /* BT_OVER_SDIO */
1648 /* Make sure to remove HT request */
1649 if (bus
->clkstate
== CLK_AVAIL
)
1650 ret
= dhdsdio_htclk(bus
, FALSE
, FALSE
);
1651 /* Now remove the SD clock */
1652 ret
= dhdsdio_sdclk(bus
, FALSE
);
1654 if (bus
->dhd
->dhd_console_ms
== 0)
1655 #endif /* DHD_DEBUG */
1657 dhd_os_wd_timer(bus
->dhd
, 0);
1661 DHD_INFO(("dhdsdio_clkctl: %d -> %d\n", oldstate
, bus
->clkstate
));
1662 #endif /* DHD_DEBUG */
1668 dhdsdio_bussleep(dhd_bus_t
*bus
, bool sleep
)
1671 bcmsdh_info_t
*sdh
= bus
->sdh
;
1672 sdpcmd_regs_t
*regs
= bus
->regs
;
1675 DHD_INFO(("dhdsdio_bussleep: request %s (currently %s)\n",
1676 (sleep
? "SLEEP" : "WAKE"),
1677 (bus
->sleeping
? "SLEEP" : "WAKE")));
1679 if (bus
->dhd
->hang_was_sent
)
1682 /* Done if we're already in the requested state */
1683 if (sleep
== bus
->sleeping
)
1686 /* Going to sleep: set the alarm and turn off the lights... */
1688 /* Don't sleep if something is pending */
1689 #ifdef DHD_USE_IDLECOUNT
1690 if (bus
->dpc_sched
|| bus
->rxskip
|| pktq_n_pkts_tot(&bus
->txq
) ||
1691 bus
->readframes
|| bus
->ctrl_frame_stat
)
1693 if (bus
->dpc_sched
|| bus
->rxskip
|| pktq_n_pkts_tot(&bus
->txq
))
1694 #endif /* DHD_USE_IDLECOUNT */
1699 * The following is the assumption based on which the hook is placed.
1700 * From WLAN driver, either from the active contexts OR from the Watchdog contexts
1701 * we will be attempting to Go to Sleep. AT that moment if we see that BT is still
1702 * actively using the bus, we will return BCME_BUSY from here, but the bus->sleeping
1703 * state would not have changed. So the caller can then schedule the Watchdog again
1704 * which will come and attempt to sleep at a later point.
1706 * In case if BT is the only one and is the last user, we don't switch off the clock
1707 * immediately, we allow the WLAN to decide when to sleep i.e from the watchdog.
1708 * Now if the watchdog becomes active and attempts to switch off the clock and if
1709 * another WLAN context is active they are any way serialized with sdlock.
1711 if (bus
->bt_use_count
!= 0) {
1712 DHD_INFO(("%s(): Cannot sleep BT is active \r\n", __FUNCTION__
));
1715 #endif /* !BT_OVER_SDIO */
1717 if (!SLPAUTO_ENAB(bus
)) {
1718 /* Disable SDIO interrupts (no longer interested) */
1719 bcmsdh_intr_disable(bus
->sdh
);
1721 /* Make sure the controller has the bus up */
1722 dhdsdio_clkctl(bus
, CLK_AVAIL
, FALSE
);
1724 /* Tell device to start using OOB wakeup */
1725 W_SDREG(SMB_USE_OOB
, ®s
->tosbmailbox
, retries
);
1726 if (retries
> retry_limit
)
1727 DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
1729 /* Turn off our contribution to the HT clock request */
1730 dhdsdio_clkctl(bus
, CLK_SDONLY
, FALSE
);
1732 bcmsdh_cfg_write(sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_CHIPCLKCSR
,
1733 SBSDIO_FORCE_HW_CLKREQ_OFF
, NULL
);
1735 /* Isolate the bus */
1736 bcmsdh_cfg_write(sdh
, SDIO_FUNC_1
, SBSDIO_DEVICE_CTL
,
1737 SBSDIO_DEVCTL_PADS_ISO
, NULL
);
1739 /* Leave interrupts enabled since device can exit sleep and
1742 err
= dhdsdio_clk_devsleep_iovar(bus
, TRUE
/* sleep */);
1746 bus
->sleeping
= TRUE
;
1747 #if defined(SUPPORT_P2P_GO_PS)
1748 wake_up(&bus
->bus_sleep
);
1749 #endif /* LINUX && SUPPORT_P2P_GO_PS */
1751 /* Waking up: bus power up is ok, set local state */
1753 if (!SLPAUTO_ENAB(bus
)) {
1754 bcmsdh_cfg_write(sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_CHIPCLKCSR
, 0, &err
);
1756 /* Force pad isolation off if possible (in case power never toggled) */
1757 bcmsdh_cfg_write(sdh
, SDIO_FUNC_1
, SBSDIO_DEVICE_CTL
, 0, NULL
);
1759 /* Make sure the controller has the bus up */
1760 dhdsdio_clkctl(bus
, CLK_AVAIL
, FALSE
);
1762 /* Send misc interrupt to indicate OOB not needed */
1763 W_SDREG(0, ®s
->tosbmailboxdata
, retries
);
1764 if (retries
<= retry_limit
)
1765 W_SDREG(SMB_DEV_INT
, ®s
->tosbmailbox
, retries
);
1767 if (retries
> retry_limit
)
1768 DHD_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n"));
1770 /* Make sure we have SD bus access */
1771 dhdsdio_clkctl(bus
, CLK_SDONLY
, FALSE
);
1773 /* Enable interrupts again */
1774 if (bus
->intr
&& (bus
->dhd
->busstate
== DHD_BUS_DATA
)) {
1775 bus
->intdis
= FALSE
;
1776 bcmsdh_intr_enable(bus
->sdh
);
1779 err
= dhdsdio_clk_devsleep_iovar(bus
, FALSE
/* wake */);
1782 struct net_device
*net
= NULL
;
1783 dhd_pub_t
*dhd
= bus
->dhd
;
1784 net
= dhd_idx2net(dhd
, 0);
1786 DHD_ERROR(("<< WIFI HANG by KSO Enabled failure\n"));
1787 dhd_os_sdunlock(dhd
);
1788 net_os_send_hang_message(net
);
1791 DHD_ERROR(("<< WIFI HANG Fail because net is NULL\n"));
1794 #endif /* BT_OVER_SDIO */
1799 bus
->sleeping
= FALSE
;
1808 * Call this function to Get the Clock running.
1809 * Assumes that the caller holds the sdlock.
1810 * bus - Pointer to the dhd_bus handle
1811 * can_wait - TRUE if the caller can wait until the clock becomes ready
1812 * FALSE if the caller cannot wait
1814 int __dhdsdio_clk_enable(struct dhd_bus
*bus
, bus_owner_t owner
, int can_wait
)
1816 int ret
= BCME_ERROR
;
1818 BCM_REFERENCE(owner
);
1820 bus
->bt_use_count
++;
1823 * We can call BUS_WAKE, clkctl multiple times, both of the items
1824 * have states and if its already ON, no new configuration is done
1827 /* Wake up the Dongle FW from SR */
1831 * Make sure back plane ht clk is on
1832 * CLK_AVAIL - Turn On both SD & HT clock
1834 ret
= dhdsdio_clkctl(bus
, CLK_AVAIL
, can_wait
);
1836 DHD_INFO(("%s():bt_use_count %d \r\n", __FUNCTION__
,
1837 bus
->bt_use_count
));
1842 * Call this function to relinquish the Clock.
1843 * Assumes that the caller holds the sdlock.
1844 * bus - Pointer to the dhd_bus handle
1845 * can_wait - TRUE if the caller can wait until the clock becomes ready
1846 * FALSE if the caller cannot wait
1848 int __dhdsdio_clk_disable(struct dhd_bus
*bus
, bus_owner_t owner
, int can_wait
)
1850 int ret
= BCME_ERROR
;
1852 BCM_REFERENCE(owner
);
1853 BCM_REFERENCE(can_wait
);
1855 if (bus
->bt_use_count
== 0) {
1856 DHD_ERROR(("%s(): Clocks are already turned off \r\n",
1861 bus
->bt_use_count
--;
1864 * When the SDIO Bus is shared between BT & WLAN, we turn Off the clock
1865 * once the last user has relinqushed the same. But there are two schemes
1866 * in that too. We consider WLAN as the bus master (even if its not
1867 * active). Even when the WLAN is OFF the DHD Watchdog is active.
1868 * So this Bus Watchdog is the context whill put the Bus to sleep.
1869 * Refer dhd_bus_watchdog function
1873 DHD_INFO(("%s():bt_use_count %d \r\n", __FUNCTION__
,
1874 bus
->bt_use_count
));
1878 void dhdsdio_reset_bt_use_count(struct dhd_bus
*bus
)
1880 /* reset bt use count */
1881 bus
->bt_use_count
= 0;
1883 #endif /* BT_OVER_SDIO */
1885 #ifdef USE_DYNAMIC_F2_BLKSIZE
1886 int dhdsdio_func_blocksize(dhd_pub_t
*dhd
, int function_num
, int block_size
)
1888 int func_blk_size
= function_num
;
1892 bcmerr
= dhd_bus_iovar_op(dhd
, "sd_blocksize", &func_blk_size
,
1893 sizeof(int), &result
, sizeof(int), IOV_GET
);
1895 if (bcmerr
!= BCME_OK
) {
1896 DHD_ERROR(("%s: Get F%d Block size error\n", __FUNCTION__
, function_num
));
1900 if (result
!= block_size
) {
1901 DHD_TRACE_HW4(("%s: F%d Block size set from %d to %d\n",
1902 __FUNCTION__
, function_num
, result
, block_size
));
1903 func_blk_size
= function_num
<< 16 | block_size
;
1904 bcmerr
= dhd_bus_iovar_op(dhd
, "sd_blocksize", NULL
,
1905 0, &func_blk_size
, sizeof(int32
), IOV_SET
);
1906 if (bcmerr
!= BCME_OK
) {
1907 DHD_ERROR(("%s: Set F2 Block size error\n", __FUNCTION__
));
1914 #endif /* USE_DYNAMIC_F2_BLKSIZE */
1916 #if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
1918 dhd_enable_oob_intr(struct dhd_bus
*bus
, bool enable
)
1920 #if defined(BCMSPI_ANDROID)
1921 bcmsdh_intr_enable(bus
->sdh
);
1922 #elif defined(HW_OOB)
1923 bcmsdh_enable_hw_oob_intr(bus
->sdh
, enable
);
1925 sdpcmd_regs_t
*regs
= bus
->regs
;
1928 dhdsdio_clkctl(bus
, CLK_AVAIL
, FALSE
);
1929 if (enable
== TRUE
) {
1931 /* Tell device to start using OOB wakeup */
1932 W_SDREG(SMB_USE_OOB
, ®s
->tosbmailbox
, retries
);
1933 if (retries
> retry_limit
)
1934 DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
1937 /* Send misc interrupt to indicate OOB not needed */
1938 W_SDREG(0, ®s
->tosbmailboxdata
, retries
);
1939 if (retries
<= retry_limit
)
1940 W_SDREG(SMB_DEV_INT
, ®s
->tosbmailbox
, retries
);
1943 /* Turn off our contribution to the HT clock request */
1944 dhdsdio_clkctl(bus
, CLK_SDONLY
, FALSE
);
1945 #endif /* !defined(HW_OOB) */
1947 #endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */
1950 dhd_bus_txdata(struct dhd_bus
*bus
, void *pkt
)
1952 int ret
= BCME_ERROR
;
1955 #if defined(DHD_TX_DUMP)
1957 #endif /* DHD_TX_DUMP */
1959 DHD_TRACE(("%s: Enter\n", __FUNCTION__
));
1961 osh
= bus
->dhd
->osh
;
1962 datalen
= PKTLEN(osh
, pkt
);
1965 /* Push the test header if doing loopback */
1966 if (bus
->ext_loop
) {
1968 PKTPUSH(osh
, pkt
, SDPCM_TEST_HDRLEN
);
1969 data
= PKTDATA(osh
, pkt
);
1970 *data
++ = SDPCM_TEST_ECHOREQ
;
1971 *data
++ = (uint8
)bus
->loopid
++;
1972 *data
++ = (datalen
>> 0);
1973 *data
++ = (datalen
>> 8);
1974 datalen
+= SDPCM_TEST_HDRLEN
;
1977 BCM_REFERENCE(datalen
);
1981 dhd_ulp_set_path(bus
->dhd
, DHD_ULP_TX_DATA
);
1982 #endif /* DHD_ULP */
1984 #if defined(DHD_TX_DUMP) && defined(DHD_TX_FULL_DUMP)
1985 dump_data
= PKTDATA(osh
, pkt
);
1986 dump_data
+= 4; /* skip 4 bytes header */
1989 DHD_ERROR(("TX DUMP\n"));
1991 for (i
= 0; i
< (datalen
- 4); i
++) {
1992 DHD_ERROR(("%02X ", dump_data
[i
]));
1998 #endif /* DHD_TX_DUMP && DHD_TX_FULL_DUMP */
2000 prec
= PRIO2PREC((PKTPRIO(pkt
) & PRIOMASK
));
2002 /* Check for existing queue, current flow-control, pending event, or pending clock */
2003 if (dhd_deferred_tx
|| bus
->fcstate
|| pktq_n_pkts_tot(&bus
->txq
) || bus
->dpc_sched
||
2004 (!DATAOK(bus
)) || (bus
->flowcontrol
& NBITVAL(prec
)) ||
2005 (bus
->clkstate
!= CLK_AVAIL
)) {
2009 DHD_TRACE(("%s: deferring pktq len %d\n", __FUNCTION__
,
2010 pktq_n_pkts_tot(&bus
->txq
)));
2013 /* Priority based enq */
2014 dhd_os_sdlock_txq(bus
->dhd
);
2015 deq_ret
= dhd_prec_enq(bus
->dhd
, &bus
->txq
, pkt
, prec
);
2016 dhd_os_sdunlock_txq(bus
->dhd
);
2019 #ifdef PROP_TXSTATUS
2020 if (DHD_PKTTAG_WLFCPKT(PKTTAG(pkt
)) == 0)
2021 #endif /* PROP_TXSTATUS */
2023 #ifdef DHDTCPACK_SUPPRESS
2024 if (dhd_tcpack_check_xmit(bus
->dhd
, pkt
) == BCME_ERROR
) {
2025 DHD_ERROR(("%s %d: tcpack_suppress ERROR!!! Stop using\n",
2026 __FUNCTION__
, __LINE__
));
2027 dhd_tcpack_suppress_set(bus
->dhd
, TCPACK_SUP_OFF
);
2029 #endif /* DHDTCPACK_SUPPRESS */
2030 dhd_txcomplete(bus
->dhd
, pkt
, FALSE
);
2031 PKTFREE(osh
, pkt
, TRUE
);
2033 ret
= BCME_NORESOURCE
;
2037 dhd_os_sdlock_txq(bus
->dhd
);
2038 pkq_len
= pktq_n_pkts_tot(&bus
->txq
);
2039 dhd_os_sdunlock_txq(bus
->dhd
);
2040 if (pkq_len
>= FCHI
) {
2041 bool wlfc_enabled
= FALSE
;
2042 #ifdef PROP_TXSTATUS
2043 wlfc_enabled
= (dhd_wlfc_flowcontrol(bus
->dhd
, ON
, FALSE
) !=
2046 if (!wlfc_enabled
&& dhd_doflow
) {
2047 dhd_txflowcontrol(bus
->dhd
, ALL_INTERFACES
, ON
);
2052 dhd_os_sdlock_txq(bus
->dhd
);
2053 if (pktqprec_n_pkts(&bus
->txq
, prec
) > qcount
[prec
])
2054 qcount
[prec
] = pktqprec_n_pkts(&bus
->txq
, prec
);
2055 dhd_os_sdunlock_txq(bus
->dhd
);
2058 /* Schedule DPC if needed to send queued packet(s) */
2059 if (dhd_deferred_tx
&& !bus
->dpc_sched
) {
2060 bus
->dpc_sched
= TRUE
;
2061 dhd_sched_dpc(bus
->dhd
);
2064 int chan
= SDPCM_DATA_CHANNEL
;
2067 chan
= (bus
->ext_loop
? SDPCM_TEST_CHANNEL
: SDPCM_DATA_CHANNEL
);
2069 /* Lock: we're about to use shared data/code (and SDIO) */
2070 dhd_os_sdlock(bus
->dhd
);
2072 /* Otherwise, send it now */
2074 /* Make sure back plane ht clk is on, no pending allowed */
2075 dhdsdio_clkctl(bus
, CLK_AVAIL
, TRUE
);
2077 ret
= dhdsdio_txpkt(bus
, chan
, &pkt
, 1, TRUE
);
2080 bus
->dhd
->tx_errors
++;
2082 bus
->dhd
->dstats
.tx_bytes
+= datalen
;
2084 if ((bus
->idletime
== DHD_IDLE_IMMEDIATE
) && !bus
->dpc_sched
&&
2085 NO_OTHER_ACTIVE_BUS_USER(bus
)) {
2086 bus
->activity
= FALSE
;
2087 dhdsdio_bussleep(bus
, TRUE
);
2088 dhdsdio_clkctl(bus
, CLK_NONE
, FALSE
);
2091 dhd_os_sdunlock(bus
->dhd
);
2097 /* align packet data pointer and packet length to n-byte boundary, process packet headers,
2098 * a new packet may be allocated if there is not enough head and/or tail from for padding.
2099 * the caller is responsible for updating the glom size in the head packet (when glom is
2102 * pad_pkt_len: returns the length of extra padding needed from the padding packet, this parameter
2103 * is taken in tx glom mode only
2105 * new_pkt: out, pointer of the new packet allocated due to insufficient head room for alignment
2106 * padding, NULL if not needed, the caller is responsible for freeing the new packet
2108 * return: positive value - length of the packet, including head and tail padding
2109 * negative value - errors
2111 static int dhdsdio_txpkt_preprocess(dhd_bus_t
*bus
, void *pkt
, int chan
, int txseq
,
2112 int prev_chain_total_len
, bool last_chained_pkt
,
2113 int *pad_pkt_len
, void **new_pkt
)
2120 int tail_padding
= 0;
2122 uint32 swhdr_offset
;
2123 bool alloc_new_pkt
= FALSE
;
2124 uint8 sdpcm_hdrlen
= bus
->txglom_enable
? SDPCM_HDRLEN_TXGLOM
: SDPCM_HDRLEN
;
2127 osh
= bus
->dhd
->osh
;
2129 #ifdef DHDTCPACK_SUPPRESS
2130 if (dhd_tcpack_check_xmit(bus
->dhd
, pkt
) == BCME_ERROR
) {
2131 DHD_ERROR(("%s %d: tcpack_suppress ERROR!!! Stop using it\n",
2132 __FUNCTION__
, __LINE__
));
2133 dhd_tcpack_suppress_set(bus
->dhd
, TCPACK_SUP_OFF
);
2135 #endif /* DHDTCPACK_SUPPRESS */
2137 /* Add space for the SDPCM hardware/software headers */
2138 PKTPUSH(osh
, pkt
, sdpcm_hdrlen
);
2139 ASSERT(ISALIGNED((uintptr
)PKTDATA(osh
, pkt
), 2));
2141 frame
= (uint8
*)PKTDATA(osh
, pkt
);
2142 pkt_len
= (uint16
)PKTLEN(osh
, pkt
);
2145 if (PKTPRIO(pkt
) < ARRAYSIZE(tx_packets
))
2146 tx_packets
[PKTPRIO(pkt
)]++;
2147 #endif /* DHD_DEBUG */
2149 /* align the data pointer, allocate a new packet if there is not enough space (new
2150 * packet data pointer will be aligned thus no padding will be needed)
2152 head_padding
= (uintptr
)frame
% DHD_SDALIGN
;
2153 if (PKTHEADROOM(osh
, pkt
) < head_padding
) {
2155 alloc_new_pkt
= TRUE
;
2157 uint cur_chain_total_len
;
2158 int chain_tail_padding
= 0;
2160 /* All packets need to be aligned by DHD_SDALIGN */
2161 modulo
= (pkt_len
+ head_padding
) % DHD_SDALIGN
;
2162 tail_padding
= modulo
> 0 ? (DHD_SDALIGN
- modulo
) : 0;
2164 /* Total pkt chain length needs to be aligned by block size,
2165 * unless it is a single pkt chain with total length less than one block size,
2166 * which we prefer sending by byte mode.
2168 * Do the chain alignment here if
2169 * 1. This is the last pkt of the chain of multiple pkts or a single pkt.
2170 * 2-1. This chain is of multiple pkts, or
2171 * 2-2. This is a single pkt whose size is longer than one block size.
2173 cur_chain_total_len
= prev_chain_total_len
+
2174 (head_padding
+ pkt_len
+ tail_padding
);
2175 if (last_chained_pkt
&& bus
->blocksize
!= 0 &&
2176 (cur_chain_total_len
> (int)bus
->blocksize
|| prev_chain_total_len
> 0)) {
2177 modulo
= cur_chain_total_len
% bus
->blocksize
;
2178 chain_tail_padding
= modulo
> 0 ? (bus
->blocksize
- modulo
) : 0;
2181 #ifdef DHDENABLE_TAILPAD
2182 if (PKTTAILROOM(osh
, pkt
) < tail_padding
) {
2183 /* We don't have tail room to align by DHD_SDALIGN */
2184 alloc_new_pkt
= TRUE
;
2185 bus
->tx_tailpad_pktget
++;
2186 } else if (PKTTAILROOM(osh
, pkt
) < tail_padding
+ chain_tail_padding
) {
2187 /* We have tail room for tail_padding of this pkt itself, but not for
2188 * total pkt chain alignment by block size.
2189 * Use the padding packet to avoid memory copy if applicable,
2190 * otherwise, just allocate a new pkt.
2193 *pad_pkt_len
= chain_tail_padding
;
2194 bus
->tx_tailpad_chain
++;
2196 alloc_new_pkt
= TRUE
;
2197 bus
->tx_tailpad_pktget
++;
2200 /* This last pkt's tailroom is sufficient to hold both tail_padding
2201 * of the pkt itself and chain_tail_padding of total pkt chain
2203 #endif /* DHDENABLE_TAILPAD */
2204 tail_padding
+= chain_tail_padding
;
2207 DHD_INFO(("%s sdhdr len + orig_pkt_len %d h_pad %d t_pad %d pad_pkt_len %d\n",
2208 __FUNCTION__
, pkt_len
, head_padding
, tail_padding
, *pad_pkt_len
));
2210 if (alloc_new_pkt
) {
2215 ASSERT(*pad_pkt_len
== 0);
2217 DHD_INFO(("%s allocating new packet for padding\n", __FUNCTION__
));
2219 /* head pointer is aligned now, no padding needed */
2222 /* update the tail padding as it depends on the head padding, since a new packet is
2223 * allocated, the head padding is non longer needed and packet length is chagned
2226 cur_total_len
= prev_chain_total_len
+ pkt_len
;
2227 if (last_chained_pkt
&& bus
->blocksize
!= 0 &&
2228 (cur_total_len
> (int)bus
->blocksize
|| prev_chain_total_len
> 0)) {
2229 modulo
= cur_total_len
% bus
->blocksize
;
2230 tail_padding
= modulo
> 0 ? (bus
->blocksize
- modulo
) : 0;
2232 modulo
= pkt_len
% DHD_SDALIGN
;
2233 tail_padding
= modulo
> 0 ? (DHD_SDALIGN
- modulo
) : 0;
2236 newpkt_size
= PKTLEN(osh
, pkt
) + bus
->blocksize
+ DHD_SDALIGN
;
2237 bus
->dhd
->tx_realloc
++;
2238 tmp_pkt
= PKTGET(osh
, newpkt_size
, TRUE
);
2239 if (tmp_pkt
== NULL
) {
2240 DHD_ERROR(("failed to alloc new %d byte packet\n", newpkt_size
));
2243 PKTALIGN(osh
, tmp_pkt
, PKTLEN(osh
, pkt
), DHD_SDALIGN
);
2244 bcopy(PKTDATA(osh
, pkt
), PKTDATA(osh
, tmp_pkt
), PKTLEN(osh
, pkt
));
2250 PKTPUSH(osh
, pkt
, head_padding
);
2252 frame
= (uint8
*)PKTDATA(osh
, pkt
);
2253 bzero(frame
, head_padding
+ sdpcm_hdrlen
);
2254 pkt_len
= (uint16
)PKTLEN(osh
, pkt
);
2256 /* the header has the followming format
2257 * 4-byte HW frame tag: length, ~length (for glom this is the total length)
2259 * 8-byte HW extesion flags (glom mode only) as the following:
2260 * 2-byte packet length, excluding HW tag and padding
2261 * 2-byte frame channel and frame flags (e.g. next frame following)
2262 * 2-byte header length
2263 * 2-byte tail padding size
2265 * 8-byte SW frame tags as the following
2266 * 4-byte flags: host tx seq, channel, data offset
2270 swhdr_offset
= SDPCM_FRAMETAG_LEN
;
2272 /* hardware frame tag:
2274 * in tx-glom mode, dongle only checks the hardware frame tag in the first
2275 * packet and sees it as the total lenght of the glom (including tail padding),
2276 * for each packet in the glom, the packet length needs to be updated, (see
2279 * in non tx-glom mode, PKTLEN still need to include tail padding as to be
2280 * referred to in sdioh_request_buffer(). The tail length will be excluded in
2281 * dhdsdio_txpkt_postprocess().
2283 *(uint16
*)frame
= (uint16
)htol16(pkt_len
);
2284 *(((uint16
*)frame
) + 1) = (uint16
)htol16(~pkt_len
);
2285 pkt_len
+= tail_padding
;
2287 /* hardware extesion flags */
2288 if (bus
->txglom_enable
) {
2292 swhdr_offset
+= SDPCM_HWEXT_LEN
;
2293 hwheader1
= (pkt_len
- SDPCM_FRAMETAG_LEN
- tail_padding
) |
2294 (last_chained_pkt
<< 24);
2295 hwheader2
= (tail_padding
) << 16;
2296 htol32_ua_store(hwheader1
, frame
+ SDPCM_FRAMETAG_LEN
);
2297 htol32_ua_store(hwheader2
, frame
+ SDPCM_FRAMETAG_LEN
+ 4);
2299 PKTSETLEN((osh
), (pkt
), (pkt_len
));
2301 /* software frame tags */
2302 swheader
= ((chan
<< SDPCM_CHANNEL_SHIFT
) & SDPCM_CHANNEL_MASK
)
2303 | (txseq
% SDPCM_SEQUENCE_WRAP
) |
2304 (((head_padding
+ sdpcm_hdrlen
) << SDPCM_DOFFSET_SHIFT
) & SDPCM_DOFFSET_MASK
);
2305 htol32_ua_store(swheader
, frame
+ swhdr_offset
);
2306 htol32_ua_store(0, frame
+ swhdr_offset
+ sizeof(swheader
));
2311 static int dhdsdio_txpkt_postprocess(dhd_bus_t
*bus
, void *pkt
)
2317 int swhdr_offset
= SDPCM_FRAMETAG_LEN
+ (bus
->txglom_enable
? SDPCM_HWEXT_LEN
: 0);
2320 osh
= bus
->dhd
->osh
;
2322 /* restore pkt buffer pointer, but keeps the header pushed by dhd_prot_hdrpush */
2323 frame
= (uint8
*)PKTDATA(osh
, pkt
);
2325 DHD_INFO(("%s PKTLEN before postprocess %d",
2326 __FUNCTION__
, PKTLEN(osh
, pkt
)));
2328 /* PKTLEN still includes tail_padding, so exclude it.
2329 * We shall have head_padding + original pkt_len for PKTLEN afterwards.
2331 if (bus
->txglom_enable
) {
2332 /* txglom pkts have tail_padding length in HW ext header */
2333 tail_padding
= ltoh32_ua(frame
+ SDPCM_FRAMETAG_LEN
+ 4) >> 16;
2334 PKTSETLEN(osh
, pkt
, PKTLEN(osh
, pkt
) - tail_padding
);
2335 DHD_INFO((" txglom pkt: tail_padding %d PKTLEN %d\n",
2336 tail_padding
, PKTLEN(osh
, pkt
)));
2338 /* non-txglom pkts have head_padding + original pkt length in HW frame tag.
2339 * We cannot refer to this field for txglom pkts as the first pkt of the chain will
2340 * have the field for the total length of the chain.
2342 PKTSETLEN(osh
, pkt
, *(uint16
*)frame
);
2343 DHD_INFO((" non-txglom pkt: HW frame tag len %d after PKTLEN %d\n",
2344 *(uint16
*)frame
, PKTLEN(osh
, pkt
)));
2347 data_offset
= ltoh32_ua(frame
+ swhdr_offset
);
2348 data_offset
= (data_offset
& SDPCM_DOFFSET_MASK
) >> SDPCM_DOFFSET_SHIFT
;
2349 /* Get rid of sdpcm header + head_padding */
2350 PKTPULL(osh
, pkt
, data_offset
);
2352 DHD_INFO(("%s data_offset %d, PKTLEN %d\n",
2353 __FUNCTION__
, data_offset
, PKTLEN(osh
, pkt
)));
2358 static int dhdsdio_txpkt(dhd_bus_t
*bus
, uint chan
, void** pkts
, int num_pkt
, bool free_pkt
)
2367 void *head_pkt
= NULL
;
2368 void *prev_pkt
= NULL
;
2369 int pad_pkt_len
= 0;
2370 int new_pkt_num
= 0;
2371 void *new_pkts
[MAX_TX_PKTCHAIN_CNT
];
2372 bool wlfc_enabled
= FALSE
;
2374 if (bus
->dhd
->dongle_reset
)
2375 return BCME_NOTREADY
;
2381 osh
= bus
->dhd
->osh
;
2382 /* init new_pkts[0] to make some compiler happy, not necessary as we check new_pkt_num */
2385 for (i
= 0; i
< num_pkt
; i
++) {
2388 void *new_pkt
= NULL
;
2392 last_pkt
= (i
== num_pkt
- 1);
2393 pkt_len
= dhdsdio_txpkt_preprocess(bus
, pkt
, chan
, bus
->tx_seq
+ i
,
2394 total_len
, last_pkt
, &pad_pkt_len
, &new_pkt
);
2399 new_pkts
[new_pkt_num
++] = new_pkt
;
2401 total_len
+= pkt_len
;
2403 PKTSETNEXT(osh
, pkt
, NULL
);
2404 /* insert the packet into the list */
2405 head_pkt
? PKTSETNEXT(osh
, prev_pkt
, pkt
) : (head_pkt
= pkt
);
2410 /* Update the HW frame tag (total length) in the first pkt of the glom */
2411 if (bus
->txglom_enable
) {
2414 total_len
+= pad_pkt_len
;
2415 frame
= (uint8
*)PKTDATA(osh
, head_pkt
);
2416 *(uint16
*)frame
= (uint16
)htol16(total_len
);
2417 *(((uint16
*)frame
) + 1) = (uint16
)htol16(~total_len
);
2421 #ifdef DHDENABLE_TAILPAD
2422 /* if a padding packet if needed, insert it to the end of the link list */
2424 PKTSETLEN(osh
, bus
->pad_pkt
, pad_pkt_len
);
2425 PKTSETNEXT(osh
, pkt
, bus
->pad_pkt
);
2427 #endif /* DHDENABLE_TAILPAD */
2429 /* dhd_bcmsdh_send_buf ignores the buffer pointer if he packet
2430 * parameter is not NULL, for non packet chian we pass NULL pkt pointer
2431 * so it will take the aligned length and buffer pointer.
2433 pkt_chain
= PKTNEXT(osh
, head_pkt
) ? head_pkt
: NULL
;
2434 ret
= dhd_bcmsdh_send_buf(bus
, bcmsdh_cur_sbwad(sdh
), SDIO_FUNC_2
, F2SYNC
,
2435 PKTDATA(osh
, head_pkt
), total_len
, pkt_chain
, NULL
, NULL
, TXRETRIES
);
2437 bus
->tx_seq
= (bus
->tx_seq
+ num_pkt
) % SDPCM_SEQUENCE_WRAP
;
2439 /* if a padding packet was needed, remove it from the link list as it not a data pkt */
2440 if (pad_pkt_len
&& pkt
)
2441 PKTSETNEXT(osh
, pkt
, NULL
);
2446 void *pkt_next
= PKTNEXT(osh
, pkt
);
2447 PKTSETNEXT(osh
, pkt
, NULL
);
2448 dhdsdio_txpkt_postprocess(bus
, pkt
);
2452 /* new packets might be allocated due to insufficient room for padding, but we
2453 * still have to indicate the original packets to upper layer
2455 for (i
= 0; i
< num_pkt
; i
++) {
2457 wlfc_enabled
= FALSE
;
2458 #ifdef PROP_TXSTATUS
2459 if (DHD_PKTTAG_WLFCPKT(PKTTAG(pkt
))) {
2460 wlfc_enabled
= (dhd_wlfc_txcomplete(bus
->dhd
, pkt
, ret
== 0) !=
2463 #endif /* PROP_TXSTATUS */
2464 if (!wlfc_enabled
) {
2465 PKTSETNEXT(osh
, pkt
, NULL
);
2466 dhd_txcomplete(bus
->dhd
, pkt
, ret
!= 0);
2468 PKTFREE(osh
, pkt
, TRUE
);
2472 for (i
= 0; i
< new_pkt_num
; i
++)
2473 PKTFREE(osh
, new_pkts
[i
], TRUE
);
2479 dhdsdio_sendfromq(dhd_bus_t
*bus
, uint maxframes
)
2483 uint16 txpktqlen
= 0;
2484 uint32 intstatus
= 0;
2488 dhd_pub_t
*dhd
= bus
->dhd
;
2489 sdpcmd_regs_t
*regs
= bus
->regs
;
2490 #ifdef DHD_LOSSLESS_ROAMING
2492 struct ether_header
*eh
;
2493 #endif /* DHD_LOSSLESS_ROAMING */
2495 DHD_TRACE(("%s: Enter\n", __FUNCTION__
));
2497 if (!KSO_ENAB(bus
)) {
2498 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__
));
2499 return BCME_NODEVICE
;
2503 tx_prec_map
= ~bus
->flowcontrol
;
2504 #ifdef DHD_LOSSLESS_ROAMING
2505 tx_prec_map
&= dhd
->dequeue_prec_map
;
2506 #endif /* DHD_LOSSLESS_ROAMING */
2507 for (cnt
= 0; (cnt
< maxframes
) && DATAOK(bus
);) {
2510 void *pkts
[MAX_TX_PKTCHAIN_CNT
];
2513 dhd_os_sdlock_txq(bus
->dhd
);
2514 if (bus
->txglom_enable
) {
2515 uint32 glomlimit
= (uint32
)bus
->txglomsize
;
2516 #if defined(BCMSDIOH_STD)
2517 if (bus
->blocksize
== 64) {
2518 glomlimit
= MIN((uint32
)bus
->txglomsize
, BLK_64_MAXTXGLOM
);
2520 #endif /* BCMSDIOH_STD */
2521 num_pkt
= MIN((uint32
)DATABUFCNT(bus
), glomlimit
);
2522 num_pkt
= MIN(num_pkt
, ARRAYSIZE(pkts
));
2524 num_pkt
= MIN(num_pkt
, pktq_mlen(&bus
->txq
, tx_prec_map
));
2525 for (i
= 0; i
< num_pkt
; i
++) {
2526 pkts
[i
] = pktq_mdeq(&bus
->txq
, tx_prec_map
, &prec_out
);
2528 DHD_ERROR(("%s: pktq_mlen non-zero when no pkt\n",
2533 #ifdef DHD_LOSSLESS_ROAMING
2534 pktdata
= (uint8
*)PKTDATA(osh
, pkts
[i
]);
2536 /* Skip BDC header */
2537 pktdata
+= BDC_HEADER_LEN
+ ((struct bdc_header
*)pktdata
)->dataOffset
;
2539 eh
= (struct ether_header
*)pktdata
;
2540 if (eh
->ether_type
== hton16(ETHER_TYPE_802_1X
)) {
2541 uint8 prio
= (uint8
)PKTPRIO(pkts
[i
]);
2543 /* Restore to original priority for 802.1X packet */
2544 if (prio
== PRIO_8021D_NC
) {
2545 PKTSETPRIO(pkts
[i
], dhd
->prio_8021x
);
2548 #endif /* DHD_LOSSLESS_ROAMING */
2550 datalen
+= PKTLEN(osh
, pkts
[i
]);
2552 dhd_os_sdunlock_txq(bus
->dhd
);
2556 if (dhdsdio_txpkt(bus
, SDPCM_DATA_CHANNEL
, pkts
, i
, TRUE
) != BCME_OK
)
2559 dhd
->dstats
.tx_bytes
+= datalen
;
2562 /* In poll mode, need to check for other events */
2563 if (!bus
->intr
&& cnt
)
2565 /* Check device status, signal pending interrupt */
2566 R_SDREG(intstatus
, ®s
->intstatus
, retries
);
2568 if (bcmsdh_regfail(bus
->sdh
))
2570 if (intstatus
& bus
->hostintmask
)
2576 dhd_os_sdlock_txq(bus
->dhd
);
2577 txpktqlen
= pktq_n_pkts_tot(&bus
->txq
);
2578 dhd_os_sdunlock_txq(bus
->dhd
);
2580 /* Do flow-control if needed */
2581 if (dhd
->up
&& (dhd
->busstate
== DHD_BUS_DATA
) && (txpktqlen
< FCLOW
)) {
2582 bool wlfc_enabled
= FALSE
;
2583 #ifdef PROP_TXSTATUS
2584 wlfc_enabled
= (dhd_wlfc_flowcontrol(dhd
, OFF
, TRUE
) != WLFC_UNSUPPORTED
);
2586 if (!wlfc_enabled
&& dhd_doflow
&& dhd
->txoff
) {
2587 dhd_txflowcontrol(dhd
, ALL_INTERFACES
, OFF
);
2595 dhdsdio_sendpendctl(dhd_bus_t
*bus
)
2597 bcmsdh_info_t
*sdh
= bus
->sdh
;
2599 uint8
* frame_seq
= bus
->ctrl_frame_buf
+ SDPCM_FRAMETAG_LEN
;
2601 if (bus
->txglom_enable
)
2602 frame_seq
+= SDPCM_HWEXT_LEN
;
2604 if (*frame_seq
!= bus
->tx_seq
) {
2605 DHD_INFO(("%s IOCTL frame seq lag detected!"
2606 " frm_seq:%d != bus->tx_seq:%d, corrected\n",
2607 __FUNCTION__
, *frame_seq
, bus
->tx_seq
));
2608 *frame_seq
= bus
->tx_seq
;
2611 ret
= dhd_bcmsdh_send_buf(bus
, bcmsdh_cur_sbwad(sdh
), SDIO_FUNC_2
, F2SYNC
,
2612 (uint8
*)bus
->ctrl_frame_buf
, (uint32
)bus
->ctrl_frame_len
,
2613 NULL
, NULL
, NULL
, 1);
2615 bus
->tx_seq
= (bus
->tx_seq
+ 1) % SDPCM_SEQUENCE_WRAP
;
2617 bus
->ctrl_frame_stat
= FALSE
;
2618 dhd_wait_event_wakeup(bus
->dhd
);
2622 dhd_bus_txctl(struct dhd_bus
*bus
, uchar
*msg
, uint msglen
)
2624 static int err_nodevice
= 0;
2630 uint8 sdpcm_hdrlen
= bus
->txglom_enable
? SDPCM_HDRLEN_TXGLOM
: SDPCM_HDRLEN
;
2632 DHD_TRACE(("%s: Enter\n", __FUNCTION__
));
2634 if (bus
->dhd
->dongle_reset
)
2637 /* Back the pointer to make a room for bus header */
2638 frame
= msg
- sdpcm_hdrlen
;
2639 len
= (msglen
+= sdpcm_hdrlen
);
2641 /* Add alignment padding (optional for ctl frames) */
2643 if ((doff
= ((uintptr
)frame
% DHD_SDALIGN
))) {
2647 bzero(frame
, doff
+ sdpcm_hdrlen
);
2649 ASSERT(doff
< DHD_SDALIGN
);
2651 doff
+= sdpcm_hdrlen
;
2654 /* Round send length to next SDIO block */
2655 if (bus
->roundup
&& bus
->blocksize
&& (len
> bus
->blocksize
)) {
2656 uint16 pad
= bus
->blocksize
- (len
% bus
->blocksize
);
2657 if ((pad
<= bus
->roundup
) && (pad
< bus
->blocksize
))
2659 } else if (len
% DHD_SDALIGN
) {
2660 len
+= DHD_SDALIGN
- (len
% DHD_SDALIGN
);
2664 /* Satisfy length-alignment requirements */
2665 if (forcealign
&& (len
& (ALIGNMENT
- 1)))
2666 len
= ROUNDUP(len
, ALIGNMENT
);
2668 ASSERT(ISALIGNED((uintptr
)frame
, 2));
2670 /* Need to lock here to protect txseq and SDIO tx calls */
2671 dhd_os_sdlock(bus
->dhd
);
2675 /* Make sure backplane clock is on */
2676 dhdsdio_clkctl(bus
, CLK_AVAIL
, FALSE
);
2678 /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
2679 *(uint16
*)frame
= htol16((uint16
)msglen
);
2680 *(((uint16
*)frame
) + 1) = htol16(~msglen
);
2682 if (bus
->txglom_enable
) {
2683 uint32 hwheader1
, hwheader2
;
2684 /* Software tag: channel, sequence number, data offset */
2685 swheader
= ((SDPCM_CONTROL_CHANNEL
<< SDPCM_CHANNEL_SHIFT
) & SDPCM_CHANNEL_MASK
)
2687 | ((doff
<< SDPCM_DOFFSET_SHIFT
) & SDPCM_DOFFSET_MASK
);
2688 htol32_ua_store(swheader
, frame
+ SDPCM_FRAMETAG_LEN
+ SDPCM_HWEXT_LEN
);
2689 htol32_ua_store(0, frame
+ SDPCM_FRAMETAG_LEN
2690 + SDPCM_HWEXT_LEN
+ sizeof(swheader
));
2692 hwheader1
= (msglen
- SDPCM_FRAMETAG_LEN
) | (1 << 24);
2693 hwheader2
= (len
- (msglen
)) << 16;
2694 htol32_ua_store(hwheader1
, frame
+ SDPCM_FRAMETAG_LEN
);
2695 htol32_ua_store(hwheader2
, frame
+ SDPCM_FRAMETAG_LEN
+ 4);
2697 *(uint16
*)frame
= htol16(len
);
2698 *(((uint16
*)frame
) + 1) = htol16(~(len
));
2700 /* Software tag: channel, sequence number, data offset */
2701 swheader
= ((SDPCM_CONTROL_CHANNEL
<< SDPCM_CHANNEL_SHIFT
) & SDPCM_CHANNEL_MASK
)
2702 | bus
->tx_seq
| ((doff
<< SDPCM_DOFFSET_SHIFT
) & SDPCM_DOFFSET_MASK
);
2703 htol32_ua_store(swheader
, frame
+ SDPCM_FRAMETAG_LEN
);
2704 htol32_ua_store(0, frame
+ SDPCM_FRAMETAG_LEN
+ sizeof(swheader
));
2708 dhd_ulp_set_path(bus
->dhd
, DHD_ULP_TX_CTRL
);
2710 if (!TXCTLOK(bus
) || !dhd_ulp_f2_ready(bus
->dhd
, bus
->sdh
))
2715 DHD_INFO(("%s: No bus credit bus->tx_max %d, bus->tx_seq %d\n",
2716 __FUNCTION__
, bus
->tx_max
, bus
->tx_seq
));
2717 bus
->ctrl_frame_stat
= TRUE
;
2719 bus
->ctrl_frame_buf
= frame
;
2720 bus
->ctrl_frame_len
= len
;
2722 if (!bus
->dpc_sched
) {
2723 bus
->dpc_sched
= TRUE
;
2724 dhd_sched_dpc(bus
->dhd
);
2726 if (bus
->ctrl_frame_stat
) {
2727 dhd_wait_for_event(bus
->dhd
, &bus
->ctrl_frame_stat
);
2730 if (bus
->ctrl_frame_stat
== FALSE
) {
2731 DHD_INFO(("%s: ctrl_frame_stat == FALSE\n", __FUNCTION__
));
2734 bus
->dhd
->txcnt_timeout
++;
2735 if (!bus
->dhd
->hang_was_sent
) {
2736 #ifdef CUSTOMER_HW4_DEBUG
2737 uint32 status
, retry
= 0;
2738 R_SDREG(status
, &bus
->regs
->intstatus
, retry
);
2739 DHD_TRACE_HW4(("%s: txcnt_timeout, INT status=0x%08X\n",
2740 __FUNCTION__
, status
));
2741 DHD_TRACE_HW4(("%s : tx_max : %d, tx_seq : %d, clkstate : %d \n",
2742 __FUNCTION__
, bus
->tx_max
, bus
->tx_seq
, bus
->clkstate
));
2743 #endif /* CUSTOMER_HW4_DEBUG */
2744 DHD_ERROR(("%s: ctrl_frame_stat == TRUE txcnt_timeout=%d\n",
2745 __FUNCTION__
, bus
->dhd
->txcnt_timeout
));
2747 #ifdef DHD_FW_COREDUMP
2748 /* Collect socram dump */
2749 if ((bus
->dhd
->memdump_enabled
) &&
2750 (bus
->dhd
->txcnt_timeout
>= MAX_CNTL_TX_TIMEOUT
)) {
2751 /* collect core dump */
2752 bus
->dhd
->memdump_type
= DUMP_TYPE_RESUMED_ON_TIMEOUT_TX
;
2753 dhd_os_sdunlock(bus
->dhd
);
2754 dhd_bus_mem_dump(bus
->dhd
);
2755 dhd_os_sdlock(bus
->dhd
);
2757 #endif /* DHD_FW_COREDUMP */
2759 bus
->ctrl_frame_stat
= FALSE
;
2764 bus
->dhd
->txcnt_timeout
= 0;
2765 bus
->ctrl_frame_stat
= TRUE
;
2769 if (DHD_BYTES_ON() && DHD_CTL_ON()) {
2770 prhex("Tx Frame", frame
, len
);
2771 } else if (DHD_HDRS_ON()) {
2772 prhex("TxHdr", frame
, MIN(len
, 16));
2775 ret
= dhd_bcmsdh_send_buffer(bus
, frame
, len
);
2777 bus
->ctrl_frame_stat
= FALSE
;
2779 dhd_ulp_enable_cached_sbwad(bus
->dhd
, bus
->sdh
);
2780 #endif /* DHD_ULP */
2783 if ((bus
->idletime
== DHD_IDLE_IMMEDIATE
) && !bus
->dpc_sched
&&
2784 NO_OTHER_ACTIVE_BUS_USER(bus
)) {
2785 bus
->activity
= FALSE
;
2786 dhdsdio_bussleep(bus
, TRUE
);
2787 dhdsdio_clkctl(bus
, CLK_NONE
, FALSE
);
2790 dhd_os_sdunlock(bus
->dhd
);
2793 bus
->dhd
->tx_ctlerrs
++;
2795 bus
->dhd
->tx_ctlpkts
++;
2797 if (bus
->dhd
->txcnt_timeout
>= MAX_CNTL_TX_TIMEOUT
) {
2798 #ifdef DHD_PM_CONTROL_FROM_FILE
2799 if (g_pm_control
== TRUE
) {
2806 #endif /* DHD_PM_CONTROL_FROM_FILE */
2808 if (ret
== BCME_NODEVICE
)
2813 return ret
? err_nodevice
>= ERROR_BCME_NODEVICE_MAX
? -ETIMEDOUT
: -EIO
: 0;
2817 dhd_bus_rxctl(struct dhd_bus
*bus
, uchar
*msg
, uint msglen
)
2822 DHD_TRACE(("%s: Enter\n", __FUNCTION__
));
2824 if (bus
->dhd
->dongle_reset
)
2827 /* Wait until control frame is available */
2828 timeleft
= dhd_os_ioctl_resp_wait(bus
->dhd
, &bus
->rxlen
);
2830 dhd_os_sdlock(bus
->dhd
);
2832 bcopy(bus
->rxctl
, msg
, MIN(msglen
, rxlen
));
2834 dhd_os_sdunlock(bus
->dhd
);
2837 DHD_CTL(("%s: resumed on rxctl frame, got %d expected %d\n",
2838 __FUNCTION__
, rxlen
, msglen
));
2840 if (timeleft
== 0) {
2842 uint32 status
, retry
= 0;
2843 R_SDREG(status
, &bus
->regs
->intstatus
, retry
);
2844 DHD_ERROR(("%s: resumed on timeout, INT status=0x%08X\n",
2845 __FUNCTION__
, status
));
2847 DHD_ERROR(("%s: resumed on timeout\n", __FUNCTION__
));
2848 #endif /* DHD_DEBUG */
2849 if (!bus
->dhd
->dongle_trap_occured
) {
2850 #ifdef DHD_FW_COREDUMP
2851 bus
->dhd
->memdump_type
= DUMP_TYPE_RESUMED_ON_TIMEOUT
;
2852 #endif /* DHD_FW_COREDUMP */
2853 dhd_os_sdlock(bus
->dhd
);
2854 dhdsdio_checkdied(bus
, NULL
, 0);
2855 dhd_os_sdunlock(bus
->dhd
);
2858 DHD_CTL(("%s: resumed for unknown reason?\n", __FUNCTION__
));
2859 if (!bus
->dhd
->dongle_trap_occured
) {
2860 #ifdef DHD_FW_COREDUMP
2861 bus
->dhd
->memdump_type
= DUMP_TYPE_RESUMED_UNKNOWN
;
2862 #endif /* DHD_FW_COREDUMP */
2863 dhd_os_sdlock(bus
->dhd
);
2864 dhdsdio_checkdied(bus
, NULL
, 0);
2865 dhd_os_sdunlock(bus
->dhd
);
2868 #ifdef DHD_FW_COREDUMP
2869 /* Dump the ram image */
2870 if (bus
->dhd
->memdump_enabled
&& !bus
->dhd
->dongle_trap_occured
)
2871 dhdsdio_mem_dump(bus
);
2872 #endif /* DHD_FW_COREDUMP */
2874 if (timeleft
== 0) {
2876 bus
->dhd
->rxcnt_timeout
++;
2877 DHD_ERROR(("%s: rxcnt_timeout=%d, rxlen=%d\n", __FUNCTION__
,
2878 bus
->dhd
->rxcnt_timeout
, rxlen
));
2879 #ifdef DHD_FW_COREDUMP
2880 /* collect socram dump */
2881 if (bus
->dhd
->memdump_enabled
) {
2882 bus
->dhd
->memdump_type
= DUMP_TYPE_RESUMED_ON_TIMEOUT_RX
;
2883 dhd_bus_mem_dump(bus
->dhd
);
2885 #endif /* DHD_FW_COREDUMP */
2887 bus
->dhd
->rxcnt_timeout
= 0;
2891 bus
->dhd
->rx_ctlpkts
++;
2893 bus
->dhd
->rx_ctlerrs
++;
2895 if (bus
->dhd
->rxcnt_timeout
>= MAX_CNTL_RX_TIMEOUT
) {
2896 #ifdef DHD_PM_CONTROL_FROM_FILE
2897 if (g_pm_control
== TRUE
) {
2904 #endif /* DHD_PM_CONTROL_FROM_FILE */
2906 if (bus
->dhd
->dongle_trap_occured
)
2909 return rxlen
? (int)rxlen
: -EIO
;
2924 #endif /* DHD_DEBUG */
2925 IOV_SET_DOWNLOAD_STATE
,
2935 #if defined(USE_SDIOFIFO_IOVAR)
2938 #endif /* USE_SDIOFIFO_IOVAR */
2951 IOV_DONGLEISOLATION
,
2964 #if defined(DEBUGGER) || defined(DHD_DSCOPE)
2965 IOV_GDB_SERVER
, /**< starts gdb server on given interface */
2966 #endif /* DEBUGGER || DHD_DSCOPE */
2969 const bcm_iovar_t dhdsdio_iovars
[] = {
2970 {"intr", IOV_INTR
, 0, 0, IOVT_BOOL
, 0 },
2971 {"sleep", IOV_SLEEP
, 0, 0, IOVT_BOOL
, 0 },
2972 {"pollrate", IOV_POLLRATE
, 0, 0, IOVT_UINT32
, 0 },
2973 {"idletime", IOV_IDLETIME
, 0, 0, IOVT_INT32
, 0 },
2974 {"idleclock", IOV_IDLECLOCK
, 0, 0, IOVT_INT32
, 0 },
2975 {"sd1idle", IOV_SD1IDLE
, 0, 0, IOVT_BOOL
, 0 },
2976 {"ramsize", IOV_RAMSIZE
, 0, 0, IOVT_UINT32
, 0 },
2977 {"ramstart", IOV_RAMSTART
, 0, 0, IOVT_UINT32
, 0 },
2978 {"dwnldstate", IOV_SET_DOWNLOAD_STATE
, 0, 0, IOVT_BOOL
, 0 },
2979 {"socram_state", IOV_SOCRAM_STATE
, 0, 0, IOVT_BOOL
, 0 },
2980 {"vars", IOV_VARS
, 0, 0, IOVT_BUFFER
, 0 },
2981 {"sdiod_drive", IOV_SDIOD_DRIVE
, 0, 0, IOVT_UINT32
, 0 },
2982 {"readahead", IOV_READAHEAD
, 0, 0, IOVT_BOOL
, 0 },
2983 {"sdrxchain", IOV_SDRXCHAIN
, 0, 0, IOVT_BOOL
, 0 },
2984 {"alignctl", IOV_ALIGNCTL
, 0, 0, IOVT_BOOL
, 0 },
2985 {"sdalign", IOV_SDALIGN
, 0, 0, IOVT_BOOL
, 0 },
2986 {"devreset", IOV_DEVRESET
, 0, 0, IOVT_BOOL
, 0 },
2988 {"sdreg", IOV_SDREG
, 0, 0, IOVT_BUFFER
, sizeof(sdreg_t
) },
2989 {"sbreg", IOV_SBREG
, 0, 0, IOVT_BUFFER
, sizeof(sdreg_t
) },
2990 {"sd_cis", IOV_SDCIS
, 0, 0, IOVT_BUFFER
, DHD_IOCTL_MAXLEN
},
2991 {"forcealign", IOV_FORCEEVEN
, 0, 0, IOVT_BOOL
, 0 },
2992 {"txbound", IOV_TXBOUND
, 0, 0, IOVT_UINT32
, 0 },
2993 {"rxbound", IOV_RXBOUND
, 0, 0, IOVT_UINT32
, 0 },
2994 {"txminmax", IOV_TXMINMAX
, 0, 0, IOVT_UINT32
, 0 },
2995 {"cpu", IOV_CPU
, 0, 0, IOVT_BOOL
, 0 },
2997 {"checkdied", IOV_CHECKDIED
, 0, 0, IOVT_BUFFER
, 0 },
2998 {"serial", IOV_SERIALCONS
, 0, 0, IOVT_UINT32
, 0 },
2999 #endif /* DHD_DEBUG */
3000 #endif /* DHD_DEBUG */
3002 {"extloop", IOV_EXTLOOP
, 0, 0, IOVT_BOOL
, 0 },
3003 {"pktgen", IOV_PKTGEN
, 0, 0, IOVT_BUFFER
, sizeof(dhd_pktgen_t
) },
3005 #if defined(USE_SDIOFIFO_IOVAR)
3006 {"watermark", IOV_WATERMARK
, 0, 0, IOVT_UINT32
, 0 },
3007 {"mesbusyctrl", IOV_MESBUSYCTRL
, 0, 0, IOVT_UINT32
, 0 },
3008 #endif /* USE_SDIOFIFO_IOVAR */
3009 {"devcap", IOV_DEVCAP
, 0, 0, IOVT_UINT32
, 0 },
3010 {"dngl_isolation", IOV_DONGLEISOLATION
, 0, 0, IOVT_UINT32
, 0 },
3011 {"kso", IOV_KSO
, 0, 0, IOVT_UINT32
, 0 },
3012 {"devsleep", IOV_DEVSLEEP
, 0, 0, IOVT_UINT32
, 0 },
3014 {"fwpath", IOV_FWPATH
, 0, 0, IOVT_BUFFER
, 0 },
3016 {"txglomsize", IOV_TXGLOMSIZE
, 0, 0, IOVT_UINT32
, 0 },
3017 {"fw_hang_report", IOV_HANGREPORT
, 0, 0, IOVT_BOOL
, 0 },
3018 {"txinrx_thres", IOV_TXINRX_THRES
, 0, 0, IOVT_INT32
, 0 },
3019 {"sdio_suspend", IOV_SDIO_SUSPEND
, 0, 0, IOVT_UINT32
, 0 },
3020 #if defined(DEBUGGER) || defined(DHD_DSCOPE)
3021 {"gdb_server", IOV_GDB_SERVER
, 0, 0, IOVT_UINT32
, 0 },
3022 #endif /* DEBUGGER || DHD_DSCOPE */
3023 {NULL
, 0, 0, 0, 0, 0 }
3027 dhd_dump_pct(struct bcmstrbuf
*strbuf
, char *desc
, uint num
, uint div
)
3032 bcm_bprintf(strbuf
, "%s N/A", desc
);
3035 q2
= (100 * (num
- (q1
* div
))) / div
;
3036 bcm_bprintf(strbuf
, "%s %d.%02d", desc
, q1
, q2
);
3041 dhd_bus_dump(dhd_pub_t
*dhdp
, struct bcmstrbuf
*strbuf
)
3043 dhd_bus_t
*bus
= dhdp
->bus
;
3044 #if defined(DHD_WAKE_STATUS) && defined(DHD_WAKE_EVENT_STATUS)
3048 bcm_bprintf(strbuf
, "Bus SDIO structure:\n");
3049 bcm_bprintf(strbuf
, "hostintmask 0x%08x intstatus 0x%08x sdpcm_ver %d\n",
3050 bus
->hostintmask
, bus
->intstatus
, bus
->sdpcm_ver
);
3051 bcm_bprintf(strbuf
, "fcstate %d qlen %u tx_seq %d, max %d, rxskip %d rxlen %u rx_seq %d\n",
3052 bus
->fcstate
, pktq_n_pkts_tot(&bus
->txq
), bus
->tx_seq
, bus
->tx_max
, bus
->rxskip
,
3053 bus
->rxlen
, bus
->rx_seq
);
3054 bcm_bprintf(strbuf
, "intr %d intrcount %u lastintrs %u spurious %u\n",
3055 bus
->intr
, bus
->intrcount
, bus
->lastintrs
, bus
->spurious
);
3057 #ifdef DHD_WAKE_STATUS
3058 bcm_bprintf(strbuf
, "wake %u rxwake %u readctrlwake %u\n",
3059 bcmsdh_get_total_wake(bus
->sdh
), bus
->wake_counts
.rxwake
,
3060 bus
->wake_counts
.rcwake
);
3061 #ifdef DHD_WAKE_RX_STATUS
3062 bcm_bprintf(strbuf
, " unicast %u multicast %u broadcast %u arp %u\n",
3063 bus
->wake_counts
.rx_ucast
, bus
->wake_counts
.rx_mcast
,
3064 bus
->wake_counts
.rx_bcast
, bus
->wake_counts
.rx_arp
);
3065 bcm_bprintf(strbuf
, " multi4 %u multi6 %u icmp6 %u multiother %u\n",
3066 bus
->wake_counts
.rx_multi_ipv4
, bus
->wake_counts
.rx_multi_ipv6
,
3067 bus
->wake_counts
.rx_icmpv6
, bus
->wake_counts
.rx_multi_other
);
3068 bcm_bprintf(strbuf
, " icmp6_ra %u, icmp6_na %u, icmp6_ns %u\n",
3069 bus
->wake_counts
.rx_icmpv6_ra
, bus
->wake_counts
.rx_icmpv6_na
,
3070 bus
->wake_counts
.rx_icmpv6_ns
);
3071 #endif /* DHD_WAKE_RX_STATUS */
3072 #ifdef DHD_WAKE_EVENT_STATUS
3073 for (i
= 0; i
< WLC_E_LAST
; i
++)
3074 if (bus
->wake_counts
.rc_event
[i
] != 0)
3075 bcm_bprintf(strbuf
, " %s = %u\n", bcmevent_get_name(i
),
3076 bus
->wake_counts
.rc_event
[i
]);
3077 bcm_bprintf(strbuf
, "\n");
3078 #endif /* DHD_WAKE_EVENT_STATUS */
3079 #endif /* DHD_WAKE_STATUS */
3081 bcm_bprintf(strbuf
, "pollrate %u pollcnt %u regfails %u\n",
3082 bus
->pollrate
, bus
->pollcnt
, bus
->regfails
);
3084 bcm_bprintf(strbuf
, "\nAdditional counters:\n");
3085 #ifdef DHDENABLE_TAILPAD
3086 bcm_bprintf(strbuf
, "tx_tailpad_chain %u tx_tailpad_pktget %u\n",
3087 bus
->tx_tailpad_chain
, bus
->tx_tailpad_pktget
);
3088 #endif /* DHDENABLE_TAILPAD */
3089 bcm_bprintf(strbuf
, "tx_sderrs %u fcqueued %u rxrtx %u rx_toolong %u rxc_errors %u\n",
3090 bus
->tx_sderrs
, bus
->fcqueued
, bus
->rxrtx
, bus
->rx_toolong
,
3092 bcm_bprintf(strbuf
, "rx_hdrfail %u badhdr %u badseq %u\n",
3093 bus
->rx_hdrfail
, bus
->rx_badhdr
, bus
->rx_badseq
);
3094 bcm_bprintf(strbuf
, "fc_rcvd %u, fc_xoff %u, fc_xon %u\n",
3095 bus
->fc_rcvd
, bus
->fc_xoff
, bus
->fc_xon
);
3096 bcm_bprintf(strbuf
, "rxglomfail %u, rxglomframes %u, rxglompkts %u\n",
3097 bus
->rxglomfail
, bus
->rxglomframes
, bus
->rxglompkts
);
3098 bcm_bprintf(strbuf
, "f2rx (hdrs/data) %u (%u/%u), f2tx %u f1regs %u\n",
3099 (bus
->f2rxhdrs
+ bus
->f2rxdata
), bus
->f2rxhdrs
, bus
->f2rxdata
,
3100 bus
->f2txdata
, bus
->f1regdata
);
3102 dhd_dump_pct(strbuf
, "\nRx: pkts/f2rd", bus
->dhd
->rx_packets
,
3103 (bus
->f2rxhdrs
+ bus
->f2rxdata
));
3104 dhd_dump_pct(strbuf
, ", pkts/f1sd", bus
->dhd
->rx_packets
, bus
->f1regdata
);
3105 dhd_dump_pct(strbuf
, ", pkts/sd", bus
->dhd
->rx_packets
,
3106 (bus
->f2rxhdrs
+ bus
->f2rxdata
+ bus
->f1regdata
));
3107 dhd_dump_pct(strbuf
, ", pkts/int", bus
->dhd
->rx_packets
, bus
->intrcount
);
3108 bcm_bprintf(strbuf
, "\n");
3110 dhd_dump_pct(strbuf
, "Rx: glom pct", (100 * bus
->rxglompkts
),
3111 bus
->dhd
->rx_packets
);
3112 dhd_dump_pct(strbuf
, ", pkts/glom", bus
->rxglompkts
, bus
->rxglomframes
);
3113 bcm_bprintf(strbuf
, "\n");
3115 dhd_dump_pct(strbuf
, "Tx: pkts/f2wr", bus
->dhd
->tx_packets
, bus
->f2txdata
);
3116 dhd_dump_pct(strbuf
, ", pkts/f1sd", bus
->dhd
->tx_packets
, bus
->f1regdata
);
3117 dhd_dump_pct(strbuf
, ", pkts/sd", bus
->dhd
->tx_packets
,
3118 (bus
->f2txdata
+ bus
->f1regdata
));
3119 dhd_dump_pct(strbuf
, ", pkts/int", bus
->dhd
->tx_packets
, bus
->intrcount
);
3120 bcm_bprintf(strbuf
, "\n");
3122 dhd_dump_pct(strbuf
, "Total: pkts/f2rw",
3123 (bus
->dhd
->tx_packets
+ bus
->dhd
->rx_packets
),
3124 (bus
->f2txdata
+ bus
->f2rxhdrs
+ bus
->f2rxdata
));
3125 dhd_dump_pct(strbuf
, ", pkts/f1sd",
3126 (bus
->dhd
->tx_packets
+ bus
->dhd
->rx_packets
), bus
->f1regdata
);
3127 dhd_dump_pct(strbuf
, ", pkts/sd",
3128 (bus
->dhd
->tx_packets
+ bus
->dhd
->rx_packets
),
3129 (bus
->f2txdata
+ bus
->f2rxhdrs
+ bus
->f2rxdata
+ bus
->f1regdata
));
3130 dhd_dump_pct(strbuf
, ", pkts/int",
3131 (bus
->dhd
->tx_packets
+ bus
->dhd
->rx_packets
), bus
->intrcount
);
3132 bcm_bprintf(strbuf
, "\n\n");
3136 if (bus
->pktgen_count
) {
3137 bcm_bprintf(strbuf
, "pktgen config and count:\n");
3138 bcm_bprintf(strbuf
, "freq %u count %u print %u total %u min %u len %u\n",
3139 bus
->pktgen_freq
, bus
->pktgen_count
, bus
->pktgen_print
,
3140 bus
->pktgen_total
, bus
->pktgen_minlen
, bus
->pktgen_maxlen
);
3141 bcm_bprintf(strbuf
, "send attempts %u rcvd %u fail %u\n",
3142 bus
->pktgen_sent
, bus
->pktgen_rcvd
, bus
->pktgen_fail
);
3146 bcm_bprintf(strbuf
, "dpc_sched %d host interrupt%spending\n",
3147 bus
->dpc_sched
, (bcmsdh_intr_pending(bus
->sdh
) ? " " : " not "));
3148 bcm_bprintf(strbuf
, "blocksize %u roundup %u\n", bus
->blocksize
, bus
->roundup
);
3149 #endif /* DHD_DEBUG */
3150 bcm_bprintf(strbuf
, "clkstate %d activity %d idletime %d idlecount %d sleeping %d\n",
3151 bus
->clkstate
, bus
->activity
, bus
->idletime
, bus
->idlecount
, bus
->sleeping
);
3155 dhd_bus_clearcounts(dhd_pub_t
*dhdp
)
3157 dhd_bus_t
*bus
= (dhd_bus_t
*)dhdp
->bus
;
3159 bus
->intrcount
= bus
->lastintrs
= bus
->spurious
= bus
->regfails
= 0;
3160 bus
->rxrtx
= bus
->rx_toolong
= bus
->rxc_errors
= 0;
3161 bus
->rx_hdrfail
= bus
->rx_badhdr
= bus
->rx_badseq
= 0;
3162 #ifdef DHDENABLE_TAILPAD
3163 bus
->tx_tailpad_chain
= bus
->tx_tailpad_pktget
= 0;
3164 #endif /* DHDENABLE_TAILPAD */
3165 bus
->tx_sderrs
= bus
->fc_rcvd
= bus
->fc_xoff
= bus
->fc_xon
= 0;
3166 bus
->rxglomfail
= bus
->rxglomframes
= bus
->rxglompkts
= 0;
3167 bus
->f2rxhdrs
= bus
->f2rxdata
= bus
->f2txdata
= bus
->f1regdata
= 0;
3172 dhdsdio_pktgen_get(dhd_bus_t
*bus
, uint8
*arg
)
3174 dhd_pktgen_t pktgen
;
3176 pktgen
.version
= DHD_PKTGEN_VERSION
;
3177 pktgen
.freq
= bus
->pktgen_freq
;
3178 pktgen
.count
= bus
->pktgen_count
;
3179 pktgen
.print
= bus
->pktgen_print
;
3180 pktgen
.total
= bus
->pktgen_total
;
3181 pktgen
.minlen
= bus
->pktgen_minlen
;
3182 pktgen
.maxlen
= bus
->pktgen_maxlen
;
3183 pktgen
.numsent
= bus
->pktgen_sent
;
3184 pktgen
.numrcvd
= bus
->pktgen_rcvd
;
3185 pktgen
.numfail
= bus
->pktgen_fail
;
3186 pktgen
.mode
= bus
->pktgen_mode
;
3187 pktgen
.stop
= bus
->pktgen_stop
;
3189 bcopy(&pktgen
, arg
, sizeof(pktgen
));
3195 dhdsdio_pktgen_set(dhd_bus_t
*bus
, uint8
*arg
)
3197 dhd_pktgen_t pktgen
;
3198 uint oldcnt
, oldmode
;
3200 bcopy(arg
, &pktgen
, sizeof(pktgen
));
3201 if (pktgen
.version
!= DHD_PKTGEN_VERSION
)
3204 oldcnt
= bus
->pktgen_count
;
3205 oldmode
= bus
->pktgen_mode
;
3207 bus
->pktgen_freq
= pktgen
.freq
;
3208 bus
->pktgen_count
= pktgen
.count
;
3209 bus
->pktgen_print
= pktgen
.print
;
3210 bus
->pktgen_total
= pktgen
.total
;
3211 bus
->pktgen_minlen
= pktgen
.minlen
;
3212 bus
->pktgen_maxlen
= pktgen
.maxlen
;
3213 bus
->pktgen_mode
= pktgen
.mode
;
3214 bus
->pktgen_stop
= pktgen
.stop
;
3216 bus
->pktgen_tick
= bus
->pktgen_ptick
= 0;
3217 bus
->pktgen_prev_time
= jiffies
;
3218 bus
->pktgen_len
= MAX(bus
->pktgen_len
, bus
->pktgen_minlen
);
3219 bus
->pktgen_len
= MIN(bus
->pktgen_len
, bus
->pktgen_maxlen
);
3221 /* Clear counts for a new pktgen (mode change, or was stopped) */
3222 if (bus
->pktgen_count
&& (!oldcnt
|| oldmode
!= bus
->pktgen_mode
)) {
3223 bus
->pktgen_sent
= bus
->pktgen_prev_sent
= bus
->pktgen_rcvd
= 0;
3224 bus
->pktgen_prev_rcvd
= bus
->pktgen_fail
= 0;
3232 dhdsdio_devram_remap(dhd_bus_t
*bus
, bool val
)
3234 uint8 enable
, protect
, remap
;
3236 si_socdevram(bus
->sih
, FALSE
, &enable
, &protect
, &remap
);
3237 remap
= val
? TRUE
: FALSE
;
3238 si_socdevram(bus
->sih
, TRUE
, &enable
, &protect
, &remap
);
3242 dhdsdio_membytes(dhd_bus_t
*bus
, bool write
, uint32 address
, uint8
*data
, uint size
)
3248 /* In remap mode, adjust address beyond socram and redirect
3249 * to devram at SOCDEVRAM_BP_ADDR since remap address > orig_ramsize
3250 * is not backplane accessible
3252 if (REMAP_ENAB(bus
) && REMAP_ISADDR(bus
, address
)) {
3253 address
-= bus
->orig_ramsize
;
3254 address
+= SOCDEVRAM_BP_ADDR
;
3257 /* Determine initial transfer parameters */
3258 sdaddr
= address
& SBSDIO_SB_OFT_ADDR_MASK
;
3259 if ((sdaddr
+ size
) & SBSDIO_SBWINDOW_MASK
)
3260 dsize
= (SBSDIO_SB_OFT_ADDR_LIMIT
- sdaddr
);
3264 /* Set the backplane window to include the start address */
3265 if ((bcmerror
= dhdsdio_set_siaddr_window(bus
, address
))) {
3266 DHD_ERROR(("%s: window change failed\n", __FUNCTION__
));
3270 /* Do the transfer(s) */
3272 DHD_INFO(("%s: %s %d bytes at offset 0x%08x in window 0x%08x\n",
3273 __FUNCTION__
, (write
? "write" : "read"), dsize
, sdaddr
,
3274 (address
& SBSDIO_SBWINDOW_MASK
)));
3275 if ((bcmerror
= bcmsdh_rwdata(bus
->sdh
, write
, sdaddr
, data
, dsize
))) {
3276 DHD_ERROR(("%s: membytes transfer failed\n", __FUNCTION__
));
3280 /* Adjust for next transfer (if any) */
3281 if ((size
-= dsize
)) {
3284 if ((bcmerror
= dhdsdio_set_siaddr_window(bus
, address
))) {
3285 DHD_ERROR(("%s: window change failed\n", __FUNCTION__
));
3289 dsize
= MIN(SBSDIO_SB_OFT_ADDR_LIMIT
, size
);
3295 /* Return the window to backplane enumeration space for core access */
3296 if (dhdsdio_set_siaddr_window(bus
, bcmsdh_cur_sbwad(bus
->sdh
))) {
3297 DHD_ERROR(("%s: FAILED to set window back to 0x%x\n", __FUNCTION__
,
3298 bcmsdh_cur_sbwad(bus
->sdh
)));
3305 dhdsdio_readshared(dhd_bus_t
*bus
, sdpcm_shared_t
*sh
)
3311 if (bus
->sih
== NULL
) {
3312 if (bus
->dhd
&& bus
->dhd
->dongle_reset
) {
3313 DHD_ERROR(("%s: Dongle is in reset state\n", __FUNCTION__
));
3314 return BCME_NOTREADY
;
3318 DHD_ERROR(("%s: The address of sih is invalid\n", __FUNCTION__
));
3322 if ((CHIPID(bus
->sih
->chip
) == BCM43430_CHIP_ID
||
3323 CHIPID(bus
->sih
->chip
) == BCM43018_CHIP_ID
) && !dhdsdio_sr_cap(bus
))
3326 shaddr
= bus
->dongle_ram_base
+ bus
->ramsize
- 4;
3329 /* Read last word in memory to determine address of sdpcm_shared structure */
3330 if ((rv
= dhdsdio_membytes(bus
, FALSE
, shaddr
, (uint8
*)&addr
, 4)) < 0)
3333 addr
= ltoh32(addr
);
3335 DHD_INFO(("sdpcm_shared address 0x%08X\n", addr
));
3338 * Check if addr is valid.
3339 * NVRAM length at the end of memory should have been overwritten.
3341 if (addr
== 0 || ((~addr
>> 16) & 0xffff) == (addr
& 0xffff)) {
3342 if ((bus
->srmemsize
> 0) && (i
++ == 0)) {
3343 shaddr
-= bus
->srmemsize
;
3345 DHD_ERROR(("%s: address (0x%08x) of sdpcm_shared invalid\n",
3346 __FUNCTION__
, addr
));
3353 /* Read hndrte_shared structure */
3354 if ((rv
= dhdsdio_membytes(bus
, FALSE
, addr
, (uint8
*)sh
, sizeof(sdpcm_shared_t
))) < 0)
3358 sh
->flags
= ltoh32(sh
->flags
);
3359 sh
->trap_addr
= ltoh32(sh
->trap_addr
);
3360 sh
->assert_exp_addr
= ltoh32(sh
->assert_exp_addr
);
3361 sh
->assert_file_addr
= ltoh32(sh
->assert_file_addr
);
3362 sh
->assert_line
= ltoh32(sh
->assert_line
);
3363 sh
->console_addr
= ltoh32(sh
->console_addr
);
3364 sh
->msgtrace_addr
= ltoh32(sh
->msgtrace_addr
);
3366 if ((sh
->flags
& SDPCM_SHARED_VERSION_MASK
) == 3 && SDPCM_SHARED_VERSION
== 1)
3369 if ((sh
->flags
& SDPCM_SHARED_VERSION_MASK
) != SDPCM_SHARED_VERSION
) {
3370 DHD_ERROR(("%s: sdpcm_shared version %d in dhd "
3371 "is different than sdpcm_shared version %d in dongle\n",
3372 __FUNCTION__
, SDPCM_SHARED_VERSION
,
3373 sh
->flags
& SDPCM_SHARED_VERSION_MASK
));
3380 #define CONSOLE_LINE_MAX 192
3384 dhdsdio_readconsole(dhd_bus_t
*bus
)
3386 dhd_console_t
*c
= &bus
->console
;
3387 uint8 line
[CONSOLE_LINE_MAX
], ch
;
3388 uint32 n
, idx
, addr
;
3391 /* Don't do anything until FWREADY updates console address */
3392 if (bus
->console_addr
== 0)
3398 /* Read console log struct */
3399 addr
= bus
->console_addr
+ OFFSETOF(hnd_cons_t
, log
);
3400 if ((rv
= dhdsdio_membytes(bus
, FALSE
, addr
, (uint8
*)&c
->log
, sizeof(c
->log
))) < 0)
3403 /* Allocate console buffer (one time only) */
3404 if (c
->buf
== NULL
) {
3405 c
->bufsize
= ltoh32(c
->log
.buf_size
);
3406 if ((c
->buf
= MALLOC(bus
->dhd
->osh
, c
->bufsize
)) == NULL
)
3410 idx
= ltoh32(c
->log
.idx
);
3412 /* Protect against corrupt value */
3413 if (idx
> c
->bufsize
)
3416 /* Skip reading the console buffer if the index pointer has not moved */
3420 /* Read the console buffer */
3421 addr
= ltoh32(c
->log
.buf
);
3422 if ((rv
= dhdsdio_membytes(bus
, FALSE
, addr
, c
->buf
, c
->bufsize
)) < 0)
3425 while (c
->last
!= idx
) {
3426 for (n
= 0; n
< CONSOLE_LINE_MAX
- 2; n
++) {
3427 if (c
->last
== idx
) {
3428 /* This would output a partial line. Instead, back up
3429 * the buffer pointer and output this line next time around.
3434 c
->last
= c
->bufsize
- n
;
3437 ch
= c
->buf
[c
->last
];
3438 c
->last
= (c
->last
+ 1) % c
->bufsize
;
3445 if (line
[n
- 1] == '\r')
3448 printf("CONSOLE: %s\n", line
);
3449 #ifdef LOG_INTO_TCPDUMP
3450 dhd_sendup_log(bus
->dhd
, line
, n
);
3451 #endif /* LOG_INTO_TCPDUMP */
3458 #endif /* DHD_DEBUG */
3461 dhdsdio_checkdied(dhd_bus_t
*bus
, char *data
, uint size
)
3465 char *mbuffer
= NULL
;
3466 char *console_buffer
= NULL
;
3467 uint maxstrlen
= 256;
3469 sdpcm_shared_t l_sdpcm_shared
;
3470 struct bcmstrbuf strbuf
;
3471 uint32 console_ptr
, console_size
, console_index
;
3472 uint8 line
[CONSOLE_LINE_MAX
], ch
;
3476 DHD_TRACE(("%s: Enter\n", __FUNCTION__
));
3478 if (DHD_NOCHECKDIED_ON())
3483 * Called after a rx ctrl timeout. "data" is NULL.
3484 * allocate memory to trace the trap or assert.
3487 mbuffer
= data
= MALLOC(bus
->dhd
->osh
, msize
);
3488 if (mbuffer
== NULL
) {
3489 DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__
, msize
));
3490 bcmerror
= BCME_NOMEM
;
3495 if ((str
= MALLOC(bus
->dhd
->osh
, maxstrlen
)) == NULL
) {
3496 DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__
, maxstrlen
));
3497 bcmerror
= BCME_NOMEM
;
3501 if ((bcmerror
= dhdsdio_readshared(bus
, &l_sdpcm_shared
)) < 0)
3504 bcm_binit(&strbuf
, data
, size
);
3506 bcm_bprintf(&strbuf
, "msgtrace address : 0x%08X\nconsole address : 0x%08X\n",
3507 l_sdpcm_shared
.msgtrace_addr
, l_sdpcm_shared
.console_addr
);
3509 if ((l_sdpcm_shared
.flags
& SDPCM_SHARED_ASSERT_BUILT
) == 0) {
3510 /* NOTE: Misspelled assert is intentional - DO NOT FIX.
3511 * (Avoids conflict with real asserts for programmatic parsing of output.)
3513 bcm_bprintf(&strbuf
, "Assrt not built in dongle\n");
3516 if ((l_sdpcm_shared
.flags
& (SDPCM_SHARED_ASSERT
|SDPCM_SHARED_TRAP
)) == 0) {
3517 /* NOTE: Misspelled assert is intentional - DO NOT FIX.
3518 * (Avoids conflict with real asserts for programmatic parsing of output.)
3520 bcm_bprintf(&strbuf
, "No trap%s in dongle",
3521 (l_sdpcm_shared
.flags
& SDPCM_SHARED_ASSERT_BUILT
)
3524 if (l_sdpcm_shared
.flags
& SDPCM_SHARED_ASSERT
) {
3525 /* Download assert */
3526 bcm_bprintf(&strbuf
, "Dongle assert");
3527 if (l_sdpcm_shared
.assert_exp_addr
!= 0) {
3529 if ((bcmerror
= dhdsdio_membytes(bus
, FALSE
,
3530 l_sdpcm_shared
.assert_exp_addr
,
3531 (uint8
*)str
, maxstrlen
)) < 0)
3534 str
[maxstrlen
- 1] = '\0';
3535 bcm_bprintf(&strbuf
, " expr \"%s\"", str
);
3538 if (l_sdpcm_shared
.assert_file_addr
!= 0) {
3540 if ((bcmerror
= dhdsdio_membytes(bus
, FALSE
,
3541 l_sdpcm_shared
.assert_file_addr
,
3542 (uint8
*)str
, maxstrlen
)) < 0)
3545 str
[maxstrlen
- 1] = '\0';
3546 bcm_bprintf(&strbuf
, " file \"%s\"", str
);
3549 bcm_bprintf(&strbuf
, " line %d ", l_sdpcm_shared
.assert_line
);
3552 if (l_sdpcm_shared
.flags
& SDPCM_SHARED_TRAP
) {
3553 trap_t
*tr
= &bus
->dhd
->last_trap_info
;
3554 bus
->dhd
->dongle_trap_occured
= TRUE
;
3555 if ((bcmerror
= dhdsdio_membytes(bus
, FALSE
,
3556 l_sdpcm_shared
.trap_addr
,
3557 (uint8
*)tr
, sizeof(trap_t
))) < 0)
3560 bus
->dongle_trap_addr
= ltoh32(l_sdpcm_shared
.trap_addr
);
3562 dhd_bus_dump_trap_info(bus
, &strbuf
);
3564 addr
= l_sdpcm_shared
.console_addr
+ OFFSETOF(hnd_cons_t
, log
);
3565 if ((rv
= dhdsdio_membytes(bus
, FALSE
, addr
,
3566 (uint8
*)&console_ptr
, sizeof(console_ptr
))) < 0)
3569 addr
= l_sdpcm_shared
.console_addr
+ OFFSETOF(hnd_cons_t
, log
.buf_size
);
3570 if ((rv
= dhdsdio_membytes(bus
, FALSE
, addr
,
3571 (uint8
*)&console_size
, sizeof(console_size
))) < 0)
3574 addr
= l_sdpcm_shared
.console_addr
+ OFFSETOF(hnd_cons_t
, log
.idx
);
3575 if ((rv
= dhdsdio_membytes(bus
, FALSE
, addr
,
3576 (uint8
*)&console_index
, sizeof(console_index
))) < 0)
3579 console_ptr
= ltoh32(console_ptr
);
3580 console_size
= ltoh32(console_size
);
3581 console_index
= ltoh32(console_index
);
3583 if (console_size
> CONSOLE_BUFFER_MAX
||
3584 !(console_buffer
= MALLOC(bus
->dhd
->osh
, console_size
)))
3587 if ((rv
= dhdsdio_membytes(bus
, FALSE
, console_ptr
,
3588 (uint8
*)console_buffer
, console_size
)) < 0)
3591 for (i
= 0, n
= 0; i
< console_size
; i
+= n
+ 1) {
3592 for (n
= 0; n
< CONSOLE_LINE_MAX
- 2; n
++) {
3593 ch
= console_buffer
[(console_index
+ i
+ n
) % console_size
];
3600 if (line
[n
- 1] == '\r')
3603 /* Don't use DHD_ERROR macro since we print
3604 * a lot of information quickly. The macro
3605 * will truncate a lot of the printfs
3608 if (dhd_msg_level
& DHD_ERROR_VAL
)
3609 printf("CONSOLE: %s\n", line
);
3616 if (l_sdpcm_shared
.flags
& (SDPCM_SHARED_ASSERT
| SDPCM_SHARED_TRAP
)) {
3617 DHD_ERROR(("%s: %s\n", __FUNCTION__
, strbuf
.origbuf
));
3620 #if defined(DHD_FW_COREDUMP)
3621 if (bus
->dhd
->memdump_enabled
&& (l_sdpcm_shared
.flags
& SDPCM_SHARED_TRAP
)) {
3622 /* Mem dump to a file on device */
3623 bus
->dhd
->memdump_type
= DUMP_TYPE_DONGLE_TRAP
;
3624 dhd_os_sdunlock(bus
->dhd
);
3625 dhdsdio_mem_dump(bus
);
3626 dhd_os_sdlock(bus
->dhd
);
3628 #endif /* #if defined(DHD_FW_COREDUMP) */
3632 MFREE(bus
->dhd
->osh
, mbuffer
, msize
);
3634 MFREE(bus
->dhd
->osh
, str
, maxstrlen
);
3636 MFREE(bus
->dhd
->osh
, console_buffer
, console_size
);
3641 #if defined(DHD_FW_COREDUMP)
3643 dhd_bus_mem_dump(dhd_pub_t
*dhdp
)
3645 dhd_bus_t
*bus
= dhdp
->bus
;
3646 if (dhdp
->busstate
== DHD_BUS_SUSPEND
) {
3647 DHD_ERROR(("%s: Bus is suspend so skip\n", __FUNCTION__
));
3650 return dhdsdio_mem_dump(bus
);
3654 dhdsdio_mem_dump(dhd_bus_t
*bus
)
3657 int size
; /* Full mem size */
3658 uint32 start
= bus
->dongle_ram_base
; /* Start address */
3659 uint read_size
= 0; /* Read size of each iteration */
3660 uint8
*buf
= NULL
, *databuf
= NULL
;
3662 /* Get full mem size */
3663 size
= bus
->ramsize
;
3664 buf
= dhd_get_fwdump_buf(bus
->dhd
, size
);
3666 DHD_ERROR(("%s: Out of memory (%d bytes)\n", __FUNCTION__
, size
));
3670 dhd_os_sdlock(bus
->dhd
);
3672 dhdsdio_clkctl(bus
, CLK_AVAIL
, FALSE
);
3674 /* Read mem content */
3675 DHD_ERROR(("Dump dongle memory\n"));
3679 read_size
= MIN(MEMBLOCK
, size
);
3680 if ((ret
= dhdsdio_membytes(bus
, FALSE
, start
, databuf
, read_size
)))
3682 DHD_ERROR(("%s: Error membytes %d\n", __FUNCTION__
, ret
));
3686 /* Decrement size and increment start address */
3689 databuf
+= read_size
;
3692 if ((bus
->idletime
== DHD_IDLE_IMMEDIATE
) && !bus
->dpc_sched
&&
3693 NO_OTHER_ACTIVE_BUS_USER(bus
)) {
3694 bus
->activity
= FALSE
;
3695 dhdsdio_clkctl(bus
, CLK_NONE
, TRUE
);
3698 dhd_os_sdunlock(bus
->dhd
);
3700 /* schedule a work queue to perform actual memdump. dhd_mem_dump() performs the job */
3702 /* buf, actually soc_ram free handled in dhd_{free,clear} */
3703 dhd_schedule_memdump(bus
->dhd
, buf
, bus
->ramsize
);
3708 #endif /* DHD_FW_COREDUMP */
3711 dhd_socram_dump(dhd_bus_t
* bus
)
3713 #if defined(DHD_FW_COREDUMP)
3714 return (dhdsdio_mem_dump(bus
));
3721 dhdsdio_downloadvars(dhd_bus_t
*bus
, void *arg
, int len
)
3723 int bcmerror
= BCME_OK
;
3725 DHD_TRACE(("%s: Enter\n", __FUNCTION__
));
3729 (DHD_ULP_DISABLED
== dhd_ulp_get_ulp_state(bus
->dhd
)) &&
3730 #endif /* DHD_ULP */
3732 bcmerror
= BCME_NOTDOWN
;
3736 bcmerror
= BCME_BUFTOOSHORT
;
3740 /* Free the old ones and replace with passed variables */
3742 MFREE(bus
->dhd
->osh
, bus
->vars
, bus
->varsz
);
3744 bus
->vars
= MALLOC(bus
->dhd
->osh
, len
);
3745 bus
->varsz
= bus
->vars
? len
: 0;
3746 if (bus
->vars
== NULL
) {
3747 bcmerror
= BCME_NOMEM
;
3751 /* Copy the passed variables, which should include the terminating double-null */
3752 bcopy(arg
, bus
->vars
, bus
->varsz
);
3759 dhd_serialconsole(dhd_bus_t
*bus
, bool set
, bool enable
, int *bcmerror
)
3762 uint32 addr
, data
, uart_enab
= 0;
3764 addr
= SI_ENUM_BASE(bus
->sih
) + OFFSETOF(chipcregs_t
, chipcontrol_addr
);
3765 data
= SI_ENUM_BASE(bus
->sih
) + OFFSETOF(chipcregs_t
, chipcontrol_data
);
3768 bcmsdh_reg_write(bus
->sdh
, addr
, 4, 1);
3769 if (bcmsdh_regfail(bus
->sdh
)) {
3770 *bcmerror
= BCME_SDIO_ERROR
;
3773 int_val
= bcmsdh_reg_read(bus
->sdh
, data
, 4);
3774 if (bcmsdh_regfail(bus
->sdh
)) {
3775 *bcmerror
= BCME_SDIO_ERROR
;
3780 return (int_val
& uart_enab
);
3782 int_val
|= uart_enab
;
3784 int_val
&= ~uart_enab
;
3785 bcmsdh_reg_write(bus
->sdh
, data
, 4, int_val
);
3786 if (bcmsdh_regfail(bus
->sdh
)) {
3787 *bcmerror
= BCME_SDIO_ERROR
;
3791 return (int_val
& uart_enab
);
3796 dhdsdio_doiovar(dhd_bus_t
*bus
, const bcm_iovar_t
*vi
, uint32 actionid
, const char *name
,
3797 void *params
, int plen
, void *arg
, int len
, int val_size
)
3803 DHD_TRACE(("%s: Enter, action %d name %s params %p plen %d arg %p len %d val_size %d\n",
3804 __FUNCTION__
, actionid
, name
, params
, plen
, arg
, len
, val_size
));
3806 if ((bcmerror
= bcm_iovar_lencheck(vi
, arg
, len
, IOV_ISSET(actionid
))) != 0)
3809 if (plen
>= (int)sizeof(int_val
))
3810 bcopy(params
, &int_val
, sizeof(int_val
));
3812 bool_val
= (int_val
!= 0) ? TRUE
: FALSE
;
3814 /* Some ioctls use the bus */
3815 dhd_os_sdlock(bus
->dhd
);
3817 /* Check if dongle is in reset. If so, only allow DEVRESET iovars */
3818 if (bus
->dhd
->dongle_reset
&& !(actionid
== IOV_SVAL(IOV_DEVRESET
) ||
3819 actionid
== IOV_GVAL(IOV_DEVRESET
))) {
3820 bcmerror
= BCME_NOTREADY
;
3825 * Special handling for keepSdioOn: New SDIO Wake-up Mechanism
3827 if ((vi
->varid
== IOV_KSO
) && (IOV_ISSET(actionid
))) {
3828 dhdsdio_clk_kso_iovar(bus
, bool_val
);
3830 } else if ((vi
->varid
== IOV_DEVSLEEP
) && (IOV_ISSET(actionid
))) {
3832 dhdsdio_clk_devsleep_iovar(bus
, bool_val
);
3833 if (!SLPAUTO_ENAB(bus
) && (bool_val
== FALSE
) && (bus
->ipend
)) {
3834 DHD_ERROR(("INT pending in devsleep 1, dpc_sched: %d\n",
3836 if (!bus
->dpc_sched
) {
3837 bus
->dpc_sched
= TRUE
;
3838 dhd_sched_dpc(bus
->dhd
);
3845 /* Handle sleep stuff before any clock mucking */
3846 if (vi
->varid
== IOV_SLEEP
) {
3847 if (IOV_ISSET(actionid
)) {
3848 bcmerror
= dhdsdio_bussleep(bus
, bool_val
);
3850 int_val
= (int32
)bus
->sleeping
;
3851 bcopy(&int_val
, arg
, val_size
);
3856 /* Request clock to allow SDIO accesses */
3857 if (!bus
->dhd
->dongle_reset
) {
3859 dhdsdio_clkctl(bus
, CLK_AVAIL
, FALSE
);
3863 case IOV_GVAL(IOV_INTR
):
3864 int_val
= (int32
)bus
->intr
;
3865 bcopy(&int_val
, arg
, val_size
);
3868 case IOV_SVAL(IOV_INTR
):
3869 bus
->intr
= bool_val
;
3870 bus
->intdis
= FALSE
;
3873 DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__
));
3874 bcmsdh_intr_enable(bus
->sdh
);
3876 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__
));
3877 bcmsdh_intr_disable(bus
->sdh
);
3882 case IOV_GVAL(IOV_POLLRATE
):
3883 int_val
= (int32
)bus
->pollrate
;
3884 bcopy(&int_val
, arg
, val_size
);
3887 case IOV_SVAL(IOV_POLLRATE
):
3888 bus
->pollrate
= (uint
)int_val
;
3889 bus
->poll
= (bus
->pollrate
!= 0);
3892 case IOV_GVAL(IOV_IDLETIME
):
3893 int_val
= bus
->idletime
;
3894 bcopy(&int_val
, arg
, val_size
);
3897 case IOV_SVAL(IOV_IDLETIME
):
3898 if ((int_val
< 0) && (int_val
!= DHD_IDLE_IMMEDIATE
)) {
3899 bcmerror
= BCME_BADARG
;
3901 bus
->idletime
= int_val
;
3905 case IOV_GVAL(IOV_IDLECLOCK
):
3906 int_val
= (int32
)bus
->idleclock
;
3907 bcopy(&int_val
, arg
, val_size
);
3910 case IOV_SVAL(IOV_IDLECLOCK
):
3911 bus
->idleclock
= int_val
;
3914 case IOV_GVAL(IOV_SD1IDLE
):
3915 int_val
= (int32
)sd1idle
;
3916 bcopy(&int_val
, arg
, val_size
);
3919 case IOV_SVAL(IOV_SD1IDLE
):
3923 case IOV_GVAL(IOV_RAMSIZE
):
3924 int_val
= (int32
)bus
->ramsize
;
3925 bcopy(&int_val
, arg
, val_size
);
3928 case IOV_GVAL(IOV_RAMSTART
):
3929 int_val
= (int32
)bus
->dongle_ram_base
;
3930 bcopy(&int_val
, arg
, val_size
);
3933 case IOV_GVAL(IOV_SDIOD_DRIVE
):
3934 int_val
= (int32
)dhd_sdiod_drive_strength
;
3935 bcopy(&int_val
, arg
, val_size
);
3938 case IOV_SVAL(IOV_SDIOD_DRIVE
):
3939 dhd_sdiod_drive_strength
= int_val
;
3940 si_sdiod_drive_strength_init(bus
->sih
, bus
->dhd
->osh
, dhd_sdiod_drive_strength
);
3943 case IOV_SVAL(IOV_SET_DOWNLOAD_STATE
):
3944 bcmerror
= dhdsdio_download_state(bus
, bool_val
);
3947 case IOV_SVAL(IOV_SOCRAM_STATE
):
3948 bcmerror
= dhdsdio_download_state(bus
, bool_val
);
3951 case IOV_SVAL(IOV_VARS
):
3952 bcmerror
= dhdsdio_downloadvars(bus
, arg
, len
);
3955 case IOV_GVAL(IOV_READAHEAD
):
3956 int_val
= (int32
)dhd_readahead
;
3957 bcopy(&int_val
, arg
, val_size
);
3960 case IOV_SVAL(IOV_READAHEAD
):
3961 if (bool_val
&& !dhd_readahead
)
3963 dhd_readahead
= bool_val
;
3966 case IOV_GVAL(IOV_SDRXCHAIN
):
3967 int_val
= (int32
)bus
->use_rxchain
;
3968 bcopy(&int_val
, arg
, val_size
);
3971 case IOV_SVAL(IOV_SDRXCHAIN
):
3972 if (bool_val
&& !bus
->sd_rxchain
)
3973 bcmerror
= BCME_UNSUPPORTED
;
3975 bus
->use_rxchain
= bool_val
;
3978 case IOV_GVAL(IOV_ALIGNCTL
):
3979 int_val
= (int32
)dhd_alignctl
;
3980 bcopy(&int_val
, arg
, val_size
);
3983 case IOV_SVAL(IOV_ALIGNCTL
):
3984 dhd_alignctl
= bool_val
;
3988 case IOV_GVAL(IOV_SDALIGN
):
3989 int_val
= DHD_SDALIGN
;
3990 bcopy(&int_val
, arg
, val_size
);
3994 case IOV_GVAL(IOV_VARS
):
3995 if (bus
->varsz
< (uint
)len
)
3996 bcopy(bus
->vars
, arg
, bus
->varsz
);
3998 bcmerror
= BCME_BUFTOOSHORT
;
4000 #endif /* DHD_DEBUG */
4003 case IOV_GVAL(IOV_SDREG
):
4009 sd_ptr
= (sdreg_t
*)params
;
4011 addr
= ((uintptr
)bus
->regs
+ sd_ptr
->offset
);
4012 size
= sd_ptr
->func
;
4013 int_val
= (int32
)bcmsdh_reg_read(bus
->sdh
, addr
, size
);
4014 if (bcmsdh_regfail(bus
->sdh
))
4015 bcmerror
= BCME_SDIO_ERROR
;
4016 bcopy(&int_val
, arg
, sizeof(int32
));
4020 case IOV_SVAL(IOV_SDREG
):
4026 sd_ptr
= (sdreg_t
*)params
;
4028 addr
= ((uintptr
)bus
->regs
+ sd_ptr
->offset
);
4029 size
= sd_ptr
->func
;
4030 bcmsdh_reg_write(bus
->sdh
, addr
, size
, sd_ptr
->value
);
4031 if (bcmsdh_regfail(bus
->sdh
))
4032 bcmerror
= BCME_SDIO_ERROR
;
4036 /* Same as above, but offset is not backplane (not SDIO core) */
4037 case IOV_GVAL(IOV_SBREG
):
4042 bcopy(params
, &sdreg
, sizeof(sdreg
));
4044 addr
= SI_ENUM_BASE(bus
->sih
) + sdreg
.offset
;
4046 int_val
= (int32
)bcmsdh_reg_read(bus
->sdh
, addr
, size
);
4047 if (bcmsdh_regfail(bus
->sdh
))
4048 bcmerror
= BCME_SDIO_ERROR
;
4049 bcopy(&int_val
, arg
, sizeof(int32
));
4053 case IOV_SVAL(IOV_SBREG
):
4058 bcopy(params
, &sdreg
, sizeof(sdreg
));
4060 addr
= SI_ENUM_BASE(bus
->sih
) + sdreg
.offset
;
4062 bcmsdh_reg_write(bus
->sdh
, addr
, size
, sdreg
.value
);
4063 if (bcmsdh_regfail(bus
->sdh
))
4064 bcmerror
= BCME_SDIO_ERROR
;
4068 case IOV_GVAL(IOV_SDCIS
):
4072 bcmstrcat(arg
, "\nFunc 0\n");
4073 bcmsdh_cis_read(bus
->sdh
, 0x10, (uint8
*)arg
+ strlen(arg
), SBSDIO_CIS_SIZE_LIMIT
);
4074 bcmstrcat(arg
, "\nFunc 1\n");
4075 bcmsdh_cis_read(bus
->sdh
, 0x11, (uint8
*)arg
+ strlen(arg
), SBSDIO_CIS_SIZE_LIMIT
);
4076 bcmstrcat(arg
, "\nFunc 2\n");
4077 bcmsdh_cis_read(bus
->sdh
, 0x12, (uint8
*)arg
+ strlen(arg
), SBSDIO_CIS_SIZE_LIMIT
);
4081 case IOV_GVAL(IOV_FORCEEVEN
):
4082 int_val
= (int32
)forcealign
;
4083 bcopy(&int_val
, arg
, val_size
);
4086 case IOV_SVAL(IOV_FORCEEVEN
):
4087 forcealign
= bool_val
;
4090 case IOV_GVAL(IOV_TXBOUND
):
4091 int_val
= (int32
)dhd_txbound
;
4092 bcopy(&int_val
, arg
, val_size
);
4095 case IOV_SVAL(IOV_TXBOUND
):
4096 dhd_txbound
= (uint
)int_val
;
4099 case IOV_GVAL(IOV_RXBOUND
):
4100 int_val
= (int32
)dhd_rxbound
;
4101 bcopy(&int_val
, arg
, val_size
);
4104 case IOV_SVAL(IOV_RXBOUND
):
4105 dhd_rxbound
= (uint
)int_val
;
4108 case IOV_GVAL(IOV_TXMINMAX
):
4109 int_val
= (int32
)dhd_txminmax
;
4110 bcopy(&int_val
, arg
, val_size
);
4113 case IOV_SVAL(IOV_TXMINMAX
):
4114 dhd_txminmax
= (uint
)int_val
;
4117 case IOV_GVAL(IOV_SERIALCONS
):
4118 int_val
= dhd_serialconsole(bus
, FALSE
, 0, &bcmerror
);
4122 bcopy(&int_val
, arg
, val_size
);
4125 case IOV_SVAL(IOV_SERIALCONS
):
4126 dhd_serialconsole(bus
, TRUE
, bool_val
, &bcmerror
);
4129 #endif /* DHD_DEBUG */
4132 case IOV_GVAL(IOV_EXTLOOP
):
4133 int_val
= (int32
)bus
->ext_loop
;
4134 bcopy(&int_val
, arg
, val_size
);
4137 case IOV_SVAL(IOV_EXTLOOP
):
4138 bus
->ext_loop
= bool_val
;
4141 case IOV_GVAL(IOV_PKTGEN
):
4142 bcmerror
= dhdsdio_pktgen_get(bus
, arg
);
4145 case IOV_SVAL(IOV_PKTGEN
):
4146 bcmerror
= dhdsdio_pktgen_set(bus
, arg
);
4150 #if defined(USE_SDIOFIFO_IOVAR)
4151 case IOV_GVAL(IOV_WATERMARK
):
4152 int_val
= (int32
)watermark
;
4153 bcopy(&int_val
, arg
, val_size
);
4156 case IOV_SVAL(IOV_WATERMARK
):
4157 watermark
= (uint
)int_val
;
4158 watermark
= (watermark
> SBSDIO_WATERMARK_MASK
) ? SBSDIO_WATERMARK_MASK
: watermark
;
4159 DHD_ERROR(("Setting watermark as 0x%x.\n", watermark
));
4160 bcmsdh_cfg_write(bus
->sdh
, SDIO_FUNC_1
, SBSDIO_WATERMARK
, (uint8
)watermark
, NULL
);
4163 case IOV_GVAL(IOV_MESBUSYCTRL
):
4164 int_val
= (int32
)mesbusyctrl
;
4165 bcopy(&int_val
, arg
, val_size
);
4168 case IOV_SVAL(IOV_MESBUSYCTRL
):
4169 mesbusyctrl
= (uint
)int_val
;
4170 mesbusyctrl
= (mesbusyctrl
> SBSDIO_MESBUSYCTRL_MASK
)
4171 ? SBSDIO_MESBUSYCTRL_MASK
: mesbusyctrl
;
4172 DHD_ERROR(("Setting mesbusyctrl as 0x%x.\n", mesbusyctrl
));
4173 bcmsdh_cfg_write(bus
->sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_MESBUSYCTRL
,
4174 ((uint8
)mesbusyctrl
| 0x80), NULL
);
4178 case IOV_GVAL(IOV_DONGLEISOLATION
):
4179 int_val
= bus
->dhd
->dongle_isolation
;
4180 bcopy(&int_val
, arg
, val_size
);
4183 case IOV_SVAL(IOV_DONGLEISOLATION
):
4184 bus
->dhd
->dongle_isolation
= bool_val
;
4187 case IOV_SVAL(IOV_DEVRESET
):
4188 DHD_TRACE(("%s: Called set IOV_DEVRESET=%d dongle_reset=%d busstate=%d\n",
4189 __FUNCTION__
, bool_val
, bus
->dhd
->dongle_reset
,
4190 bus
->dhd
->busstate
));
4192 ASSERT(bus
->dhd
->osh
);
4193 /* ASSERT(bus->cl_devid); */
4195 /* must release sdlock, since devreset also acquires it */
4196 dhd_os_sdunlock(bus
->dhd
);
4197 dhd_bus_devreset(bus
->dhd
, (uint8
)bool_val
);
4198 dhd_os_sdlock(bus
->dhd
);
4201 * softap firmware is updated through module parameter or android private command
4204 case IOV_GVAL(IOV_DEVRESET
):
4205 DHD_TRACE(("%s: Called get IOV_DEVRESET\n", __FUNCTION__
));
4207 /* Get its status */
4208 int_val
= (bool) bus
->dhd
->dongle_reset
;
4209 bcopy(&int_val
, arg
, val_size
);
4213 case IOV_GVAL(IOV_KSO
):
4214 int_val
= dhdsdio_sleepcsr_get(bus
);
4215 bcopy(&int_val
, arg
, val_size
);
4218 case IOV_GVAL(IOV_DEVCAP
):
4219 int_val
= dhdsdio_devcap_get(bus
);
4220 bcopy(&int_val
, arg
, val_size
);
4223 case IOV_SVAL(IOV_DEVCAP
):
4224 dhdsdio_devcap_set(bus
, (uint8
) int_val
);
4226 case IOV_GVAL(IOV_TXGLOMSIZE
):
4227 int_val
= (int32
)bus
->txglomsize
;
4228 bcopy(&int_val
, arg
, val_size
);
4231 case IOV_SVAL(IOV_TXGLOMSIZE
):
4232 if (int_val
> SDPCM_MAXGLOM_SIZE
) {
4233 bcmerror
= BCME_ERROR
;
4235 bus
->txglomsize
= (uint
)int_val
;
4238 case IOV_SVAL(IOV_HANGREPORT
):
4239 bus
->dhd
->hang_report
= bool_val
;
4240 DHD_ERROR(("%s: Set hang_report as %d\n", __FUNCTION__
, bus
->dhd
->hang_report
));
4243 case IOV_GVAL(IOV_HANGREPORT
):
4244 int_val
= (int32
)bus
->dhd
->hang_report
;
4245 bcopy(&int_val
, arg
, val_size
);
4248 case IOV_GVAL(IOV_TXINRX_THRES
):
4249 int_val
= bus
->txinrx_thres
;
4250 bcopy(&int_val
, arg
, val_size
);
4252 case IOV_SVAL(IOV_TXINRX_THRES
):
4254 bcmerror
= BCME_BADARG
;
4256 bus
->txinrx_thres
= int_val
;
4260 case IOV_GVAL(IOV_SDIO_SUSPEND
):
4261 int_val
= (bus
->dhd
->busstate
== DHD_BUS_SUSPEND
) ? 1 : 0;
4262 bcopy(&int_val
, arg
, val_size
);
4265 case IOV_SVAL(IOV_SDIO_SUSPEND
):
4266 if (bool_val
) { /* Suspend */
4267 dhdsdio_suspend(bus
);
4270 dhdsdio_resume(bus
);
4274 #if defined(DEBUGGER) || defined(DHD_DSCOPE)
4275 case IOV_SVAL(IOV_GDB_SERVER
):
4276 if (bool_val
== TRUE
) {
4277 debugger_init((void *) bus
, &bus_ops
, int_val
, SI_ENUM_BASE(bus
->sih
));
4282 #endif /* DEBUGGER || DHD_DSCOPE */
4285 bcmerror
= BCME_UNSUPPORTED
;
4290 if ((bus
->idletime
== DHD_IDLE_IMMEDIATE
) && !bus
->dpc_sched
&&
4291 NO_OTHER_ACTIVE_BUS_USER(bus
)) {
4292 bus
->activity
= FALSE
;
4293 dhdsdio_bussleep(bus
, TRUE
);
4294 dhdsdio_clkctl(bus
, CLK_NONE
, FALSE
);
4297 dhd_os_sdunlock(bus
->dhd
);
4303 dhdsdio_write_vars(dhd_bus_t
*bus
)
4306 uint32 varsize
, phys_size
;
4311 uint8
*nvram_ularray
;
4312 #endif /* DHD_DEBUG */
4314 /* Even if there are no vars are to be written, we still need to set the ramsize. */
4315 varsize
= bus
->varsz
? ROUNDUP(bus
->varsz
, 4) : 0;
4316 varaddr
= (bus
->ramsize
- 4) - varsize
;
4318 varaddr
+= bus
->dongle_ram_base
;
4321 if ((bus
->sih
->buscoretype
== SDIOD_CORE_ID
) && (bus
->sdpcmrev
== 7)) {
4322 if (((varaddr
& 0x3C) == 0x3C) && (varsize
> 4)) {
4323 DHD_ERROR(("PR85623WAR in place\n"));
4329 vbuffer
= (uint8
*)MALLOC(bus
->dhd
->osh
, varsize
);
4333 bzero(vbuffer
, varsize
);
4334 bcopy(bus
->vars
, vbuffer
, bus
->varsz
);
4336 /* Write the vars list */
4337 bcmerror
= dhdsdio_membytes(bus
, TRUE
, varaddr
, vbuffer
, varsize
);
4339 DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
4340 __FUNCTION__
, bcmerror
, varsize
, varaddr
));
4345 /* Verify NVRAM bytes */
4346 DHD_INFO(("Compare NVRAM dl & ul; varsize=%d\n", varsize
));
4347 nvram_ularray
= (uint8
*)MALLOC(bus
->dhd
->osh
, varsize
);
4348 if (!nvram_ularray
) {
4349 MFREE(bus
->dhd
->osh
, vbuffer
, varsize
);
4353 /* Upload image to verify downloaded contents. */
4354 memset(nvram_ularray
, 0xaa, varsize
);
4356 /* Read the vars list to temp buffer for comparison */
4357 bcmerror
= dhdsdio_membytes(bus
, FALSE
, varaddr
, nvram_ularray
, varsize
);
4359 DHD_ERROR(("%s: error %d on reading %d nvram bytes at 0x%08x\n",
4360 __FUNCTION__
, bcmerror
, varsize
, varaddr
));
4362 /* Compare the org NVRAM with the one read from RAM */
4363 if (memcmp(vbuffer
, nvram_ularray
, varsize
)) {
4364 DHD_ERROR(("%s: Downloaded NVRAM image is corrupted.\n", __FUNCTION__
));
4366 DHD_ERROR(("%s: Download, Upload and compare of NVRAM succeeded.\n",
4369 MFREE(bus
->dhd
->osh
, nvram_ularray
, varsize
);
4370 #endif /* DHD_DEBUG */
4372 MFREE(bus
->dhd
->osh
, vbuffer
, varsize
);
4375 phys_size
= REMAP_ENAB(bus
) ? bus
->ramsize
: bus
->orig_ramsize
;
4377 phys_size
+= bus
->dongle_ram_base
;
4379 /* adjust to the user specified RAM */
4380 DHD_INFO(("Physical memory size: %d, usable memory size: %d\n",
4381 phys_size
, bus
->ramsize
));
4382 DHD_INFO(("Vars are at %d, orig varsize is %d\n",
4384 varsize
= ((phys_size
- 4) - varaddr
);
4387 * Determine the length token:
4388 * Varsize, converted to words, in lower 16-bits, checksum in upper 16-bits.
4394 #endif /* DHD_DEBUG */
4396 varsizew
= varsize
/ 4;
4397 varsizew
= (~varsizew
<< 16) | (varsizew
& 0x0000FFFF);
4398 varsizew
= htol32(varsizew
);
4401 DHD_INFO(("New varsize is %d, length token=0x%08x\n", varsize
, varsizew
));
4403 /* Write the length token to the last word */
4404 bcmerror
= dhdsdio_membytes(bus
, TRUE
, (phys_size
- 4),
4405 (uint8
*)&varsizew
, 4);
4411 dhdsdio_download_state(dhd_bus_t
*bus
, bool enter
)
4419 /* To enter download state, disable ARM and reset SOCRAM.
4420 * To exit download state, simply reset ARM (default is RAM boot).
4423 bus
->alp_only
= TRUE
;
4425 if (!(si_setcore(bus
->sih
, ARM7S_CORE_ID
, 0)) &&
4426 !(si_setcore(bus
->sih
, ARMCM3_CORE_ID
, 0))) {
4427 if (si_setcore(bus
->sih
, ARMCR4_CORE_ID
, 0)) {
4430 DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__
));
4431 bcmerror
= BCME_ERROR
;
4437 si_core_disable(bus
->sih
, 0);
4438 if (bcmsdh_regfail(bus
->sdh
)) {
4439 bcmerror
= BCME_SDIO_ERROR
;
4443 if (!(si_setcore(bus
->sih
, SOCRAM_CORE_ID
, 0))) {
4444 DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__
));
4445 bcmerror
= BCME_ERROR
;
4449 si_core_reset(bus
->sih
, 0, 0);
4450 if (bcmsdh_regfail(bus
->sdh
)) {
4451 DHD_ERROR(("%s: Failure trying reset SOCRAM core?\n",
4453 bcmerror
= BCME_SDIO_ERROR
;
4457 /* Disable remap for download */
4458 if (REMAP_ENAB(bus
) && si_socdevram_remap_isenb(bus
->sih
))
4459 dhdsdio_devram_remap(bus
, FALSE
);
4461 if (CHIPID(bus
->sih
->chip
) == BCM43430_CHIP_ID
||
4462 CHIPID(bus
->sih
->chip
) == BCM43018_CHIP_ID
) {
4463 /* Disabling Remap for SRAM_3 */
4464 si_socram_set_bankpda(bus
->sih
, 0x3, 0x0);
4467 /* Clear the top bit of memory */
4470 if (dhdsdio_membytes(bus
, TRUE
, bus
->ramsize
- 4,
4471 (uint8
*)&zeros
, 4) < 0) {
4472 bcmerror
= BCME_SDIO_ERROR
;
4480 * Read RAM base address [0x18_0000]
4481 * [next] Download firmware
4482 * [done at else] Populate the reset vector
4483 * [done at else] Remove ARM halt
4485 /* Halt ARM & remove reset */
4486 si_core_reset(bus
->sih
, SICF_CPUHALT
, SICF_CPUHALT
);
4489 if (!si_setcore(bus
->sih
, ARMCR4_CORE_ID
, 0)) {
4490 if (!(si_setcore(bus
->sih
, SOCRAM_CORE_ID
, 0))) {
4491 DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__
));
4492 bcmerror
= BCME_ERROR
;
4496 if (!si_iscoreup(bus
->sih
)) {
4497 DHD_ERROR(("%s: SOCRAM core is down after reset?\n", __FUNCTION__
));
4498 bcmerror
= BCME_ERROR
;
4502 if ((bcmerror
= dhdsdio_write_vars(bus
))) {
4503 DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__
));
4507 /* Enable remap before ARM reset but after vars.
4508 * No backplane access in remap mode
4510 if (REMAP_ENAB(bus
) && !si_socdevram_remap_isenb(bus
->sih
))
4511 dhdsdio_devram_remap(bus
, TRUE
);
4513 if (!si_setcore(bus
->sih
, CC_CORE_ID
, 0)) {
4514 DHD_ERROR(("%s: Can't set to Chip Common core?\n", __FUNCTION__
));
4515 bcmerror
= BCME_ERROR
;
4519 if (!si_setcore(bus
->sih
, PCMCIA_CORE_ID
, 0) &&
4520 !si_setcore(bus
->sih
, SDIOD_CORE_ID
, 0)) {
4521 DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__
));
4522 bcmerror
= BCME_ERROR
;
4526 W_SDREG(0xFFFFFFFF, &bus
->regs
->intstatus
, retries
);
4528 if (!(si_setcore(bus
->sih
, ARM7S_CORE_ID
, 0)) &&
4529 !(si_setcore(bus
->sih
, ARMCM3_CORE_ID
, 0))) {
4530 DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__
));
4531 bcmerror
= BCME_ERROR
;
4535 /* cr4 has no socram, but tcm's */
4537 if ((bcmerror
= dhdsdio_write_vars(bus
))) {
4538 DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__
));
4542 if (!si_setcore(bus
->sih
, CC_CORE_ID
, 0)) {
4543 DHD_ERROR(("%s: Can't set to Chip Common core?\n", __FUNCTION__
));
4544 bcmerror
= BCME_ERROR
;
4548 if (!si_setcore(bus
->sih
, PCMCIA_CORE_ID
, 0) &&
4549 !si_setcore(bus
->sih
, SDIOD_CORE_ID
, 0)) {
4550 DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__
));
4551 bcmerror
= BCME_ERROR
;
4555 W_SDREG(0xFFFFFFFF, &bus
->regs
->intstatus
, retries
);
4557 /* switch back to arm core again */
4558 if (!(si_setcore(bus
->sih
, ARMCR4_CORE_ID
, 0))) {
4559 DHD_ERROR(("%s: Failed to find ARM CR4 core!\n", __FUNCTION__
));
4560 bcmerror
= BCME_ERROR
;
4563 /* write address 0 with reset instruction */
4564 bcmerror
= dhdsdio_membytes(bus
, TRUE
, 0,
4565 (uint8
*)&bus
->resetinstr
, sizeof(bus
->resetinstr
));
4567 if (bcmerror
== BCME_OK
) {
4571 bcmerror
= dhdsdio_membytes(bus
, FALSE
, 0,
4572 (uint8
*)&tmp
, sizeof(tmp
));
4574 if (bcmerror
== BCME_OK
&& tmp
!= bus
->resetinstr
) {
4575 DHD_ERROR(("%s: Failed to write 0x%08x to addr 0\n",
4576 __FUNCTION__
, bus
->resetinstr
));
4577 DHD_ERROR(("%s: contents of addr 0 is 0x%08x\n",
4578 __FUNCTION__
, tmp
));
4579 bcmerror
= BCME_SDIO_ERROR
;
4584 /* now remove reset and halt and continue to run CR4 */
4587 si_core_reset(bus
->sih
, 0, 0);
4588 if (bcmsdh_regfail(bus
->sdh
)) {
4589 DHD_ERROR(("%s: Failure trying to reset ARM core?\n", __FUNCTION__
));
4590 bcmerror
= BCME_SDIO_ERROR
;
4594 /* Allow HT Clock now that the ARM is running. */
4595 bus
->alp_only
= FALSE
;
4597 bus
->dhd
->busstate
= DHD_BUS_LOAD
;
4601 /* Always return to SDIOD core */
4602 if (!si_setcore(bus
->sih
, PCMCIA_CORE_ID
, 0))
4603 si_setcore(bus
->sih
, SDIOD_CORE_ID
, 0);
4609 dhd_bus_iovar_op(dhd_pub_t
*dhdp
, const char *name
,
4610 void *params
, int plen
, void *arg
, int len
, bool set
)
4612 dhd_bus_t
*bus
= dhdp
->bus
;
4613 const bcm_iovar_t
*vi
= NULL
;
4618 DHD_TRACE(("%s: Enter\n", __FUNCTION__
));
4623 /* Get MUST have return space */
4624 ASSERT(set
|| (arg
&& len
));
4626 /* Set does NOT take qualifiers */
4627 ASSERT(!set
|| (!params
&& !plen
));
4629 /* Look up var locally; if not found pass to host driver */
4630 if ((vi
= bcm_iovar_lookup(dhdsdio_iovars
, name
)) == NULL
) {
4631 dhd_os_sdlock(bus
->dhd
);
4635 /* Turn on clock in case SD command needs backplane */
4636 dhdsdio_clkctl(bus
, CLK_AVAIL
, FALSE
);
4638 bcmerror
= bcmsdh_iovar_op(bus
->sdh
, name
, params
, plen
, arg
, len
, set
);
4640 /* Check for bus configuration changes of interest */
4642 /* If it was divisor change, read the new one */
4643 if (set
&& strcmp(name
, "sd_divisor") == 0) {
4644 if (bcmsdh_iovar_op(bus
->sdh
, "sd_divisor", NULL
, 0,
4645 &bus
->sd_divisor
, sizeof(int32
), FALSE
) != BCME_OK
) {
4646 bus
->sd_divisor
= -1;
4647 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__
, name
));
4649 DHD_INFO(("%s: noted %s update, value now %d\n",
4650 __FUNCTION__
, name
, bus
->sd_divisor
));
4653 /* If it was a mode change, read the new one */
4654 if (set
&& strcmp(name
, "sd_mode") == 0) {
4655 if (bcmsdh_iovar_op(bus
->sdh
, "sd_mode", NULL
, 0,
4656 &bus
->sd_mode
, sizeof(int32
), FALSE
) != BCME_OK
) {
4658 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__
, name
));
4660 DHD_INFO(("%s: noted %s update, value now %d\n",
4661 __FUNCTION__
, name
, bus
->sd_mode
));
4664 /* Similar check for blocksize change */
4665 if (set
&& strcmp(name
, "sd_blocksize") == 0) {
4667 if (bcmsdh_iovar_op(bus
->sdh
, "sd_blocksize", &fnum
, sizeof(int32
),
4668 &bus
->blocksize
, sizeof(int32
), FALSE
) != BCME_OK
) {
4670 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__
, "sd_blocksize"));
4672 DHD_INFO(("%s: noted %s update, value now %d\n",
4673 __FUNCTION__
, "sd_blocksize", bus
->blocksize
));
4675 dhdsdio_tune_fifoparam(bus
);
4678 bus
->roundup
= MIN(max_roundup
, bus
->blocksize
);
4680 if ((bus
->idletime
== DHD_IDLE_IMMEDIATE
) && !bus
->dpc_sched
&&
4681 NO_OTHER_ACTIVE_BUS_USER(bus
)) {
4682 bus
->activity
= FALSE
;
4683 dhdsdio_bussleep(bus
, TRUE
);
4684 dhdsdio_clkctl(bus
, CLK_NONE
, FALSE
);
4687 dhd_os_sdunlock(bus
->dhd
);
4691 DHD_CTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__
,
4692 name
, (set
? "set" : "get"), len
, plen
));
4694 /* set up 'params' pointer in case this is a set command so that
4695 * the convenience int and bool code can be common to set and get
4697 if (params
== NULL
) {
4702 if (vi
->type
== IOVT_VOID
)
4704 else if (vi
->type
== IOVT_BUFFER
)
4707 /* all other types are integer sized */
4708 val_size
= sizeof(int);
4710 actionid
= set
? IOV_SVAL(vi
->varid
) : IOV_GVAL(vi
->varid
);
4711 bcmerror
= dhdsdio_doiovar(bus
, vi
, actionid
, name
, params
, plen
, arg
, len
, val_size
);
4718 dhd_bus_stop(struct dhd_bus
*bus
, bool enforce_mutex
)
4721 uint32 local_hostintmask
;
4725 bool wlfc_enabled
= FALSE
;
4726 unsigned long flags
;
4731 osh
= bus
->dhd
->osh
;
4732 DHD_TRACE(("%s: Enter\n", __FUNCTION__
));
4734 bcmsdh_waitlockfree(bus
->sdh
);
4737 dhd_os_sdlock(bus
->dhd
);
4739 if ((bus
->dhd
->busstate
== DHD_BUS_DOWN
) || bus
->dhd
->hang_was_sent
) {
4740 /* if Firmware already hangs disbale any interrupt */
4741 bus
->dhd
->busstate
= DHD_BUS_DOWN
;
4742 bus
->hostintmask
= 0;
4743 bcmsdh_intr_disable(bus
->sdh
);
4748 if (KSO_ENAB(bus
)) {
4750 /* Enable clock for device interrupts */
4751 dhdsdio_clkctl(bus
, CLK_AVAIL
, FALSE
);
4753 /* Disable and clear interrupts at the chip level also */
4754 W_SDREG(0, &bus
->regs
->hostintmask
, retries
);
4755 local_hostintmask
= bus
->hostintmask
;
4756 bus
->hostintmask
= 0;
4758 /* Change our idea of bus state */
4759 DHD_LINUX_GENERAL_LOCK(bus
->dhd
, flags
);
4760 bus
->dhd
->busstate
= DHD_BUS_DOWN
;
4761 DHD_LINUX_GENERAL_UNLOCK(bus
->dhd
, flags
);
4763 /* Force clocks on backplane to be sure F2 interrupt propagates */
4764 saveclk
= bcmsdh_cfg_read(bus
->sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_CHIPCLKCSR
, &err
);
4766 bcmsdh_cfg_write(bus
->sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_CHIPCLKCSR
,
4767 (saveclk
| SBSDIO_FORCE_HT
), &err
);
4770 DHD_ERROR(("%s: Failed to force clock for F2: err %d\n",
4771 __FUNCTION__
, err
));
4774 /* Turn off the bus (F2), free any pending packets */
4775 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__
));
4776 bcmsdh_intr_disable(bus
->sdh
);
4778 bcmsdh_cfg_write(bus
->sdh
, SDIO_FUNC_0
, SDIOD_CCCR_IOEN
, SDIO_FUNC_ENABLE_1
, NULL
);
4779 #endif /* !BCMSPI */
4781 /* Clear any pending interrupts now that F2 is disabled */
4782 W_SDREG(local_hostintmask
, &bus
->regs
->intstatus
, retries
);
4785 /* Turn off the backplane clock (only) */
4786 dhdsdio_clkctl(bus
, CLK_SDONLY
, FALSE
);
4789 #ifdef PROP_TXSTATUS
4790 wlfc_enabled
= (dhd_wlfc_cleanup_txq(bus
->dhd
, NULL
, 0) != WLFC_UNSUPPORTED
);
4792 if (!wlfc_enabled
) {
4793 #ifdef DHDTCPACK_SUPPRESS
4794 /* Clean tcp_ack_info_tbl in order to prevent access to flushed pkt,
4795 * when there is a newly coming packet from network stack.
4797 dhd_tcpack_info_tbl_clean(bus
->dhd
);
4798 #endif /* DHDTCPACK_SUPPRESS */
4799 dhd_os_sdlock_txq(bus
->dhd
);
4800 /* Clear the data packet queues */
4801 pktq_flush(osh
, &bus
->txq
, TRUE
);
4802 dhd_os_sdunlock_txq(bus
->dhd
);
4805 /* Clear any held glomming stuff */
4807 PKTFREE(osh
, bus
->glomd
, FALSE
);
4810 PKTFREE(osh
, bus
->glom
, FALSE
);
4812 bus
->glom
= bus
->glomd
= NULL
;
4814 /* Clear rx control and wake any waiters */
4816 dhd_os_ioctl_resp_wake(bus
->dhd
);
4818 /* Reset some F2 state stuff */
4819 bus
->rxskip
= FALSE
;
4820 bus
->tx_seq
= bus
->rx_seq
= 0;
4825 dhd_os_sdunlock(bus
->dhd
);
4828 #if defined(BCMSDIOH_TXGLOM) && defined(BCMSDIOH_STD)
4829 extern uint sd_txglom
;
4832 dhd_txglom_enable(dhd_pub_t
*dhdp
, bool enable
)
4834 /* can't enable host txglom by default, some platforms have no
4835 * (or crappy) ADMA support and txglom will cause kernel assertions (e.g.
4838 dhd_bus_t
*bus
= dhdp
->bus
;
4839 #ifdef BCMSDIOH_TXGLOM
4843 DHD_TRACE(("%s: Enter\n", __FUNCTION__
));
4848 #endif /* BCMSDIOH_STD */
4852 ret
= dhd_iovar(dhdp
, 0, "bus:rxglom", (char *)&rxglom
, sizeof(rxglom
), NULL
, 0,
4855 bus
->txglom_enable
= TRUE
;
4859 #endif /* BCMSDIOH_STD */
4860 bus
->txglom_enable
= FALSE
;
4863 #endif /* BCMSDIOH_TXGLOM */
4864 bus
->txglom_enable
= FALSE
;
4868 dhd_bus_init(dhd_pub_t
*dhdp
, bool enforce_mutex
)
4870 dhd_bus_t
*bus
= dhdp
->bus
;
4873 uint8 ready
, enable
;
4876 uint32 dstatus
= 0; /* gSPI device-status bits */
4881 DHD_TRACE(("%s: Enter\n", __FUNCTION__
));
4888 dhd_os_sdlock(bus
->dhd
);
4890 /* Make sure backplane clock is on, needed to generate F2 interrupt */
4891 dhdsdio_clkctl(bus
, CLK_AVAIL
, FALSE
);
4892 if (bus
->clkstate
!= CLK_AVAIL
) {
4893 DHD_ERROR(("%s: clock state is wrong. state = %d\n", __FUNCTION__
, bus
->clkstate
));
4899 /* fake "ready" for spi, wake-wlan would have already enabled F1 and F2 */
4900 ready
= (SDIO_FUNC_ENABLE_1
| SDIO_FUNC_ENABLE_2
);
4903 /* Give the dongle some time to do its thing and set IOR2 */
4904 dhd_timeout_start(&tmo
, WAIT_F2RXFIFORDY
* WAIT_F2RXFIFORDY_DELAY
* 1000);
4905 while (!enable
&& !dhd_timeout_expired(&tmo
)) {
4906 dstatus
= bcmsdh_cfg_read_word(bus
->sdh
, SDIO_FUNC_0
, SPID_STATUS_REG
, NULL
);
4907 if (dstatus
& STATUS_F2_RX_READY
)
4912 DHD_ERROR(("Took %u usec before dongle is ready\n", tmo
.elapsed
));
4915 DHD_ERROR(("dstatus when timed out on f2-fifo not ready = 0x%x\n", dstatus
));
4916 DHD_ERROR(("Waited %u usec, dongle is not ready\n", tmo
.elapsed
));
4922 /* Force clocks on backplane to be sure F2 interrupt propagates */
4923 saveclk
= bcmsdh_cfg_read(bus
->sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_CHIPCLKCSR
, &err
);
4926 if (bus
->sih
->chip
== BCM43012_CHIP_ID
) {
4927 bcmsdh_cfg_write(bus
->sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_CHIPCLKCSR
,
4928 (saveclk
| SBSDIO_HT_AVAIL_REQ
), &err
);
4930 bcmsdh_cfg_write(bus
->sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_CHIPCLKCSR
,
4931 (saveclk
| SBSDIO_FORCE_HT
), &err
);
4936 DHD_ERROR(("%s: Failed to force clock for F2: err %d\n", __FUNCTION__
, err
));
4941 /* Enable function 2 (frame transfers) */
4942 W_SDREG((SDPCM_PROT_VERSION
<< SMB_DATA_VERSION_SHIFT
),
4943 &bus
->regs
->tosbmailboxdata
, retries
);
4944 enable
= (SDIO_FUNC_ENABLE_1
| SDIO_FUNC_ENABLE_2
);
4946 bcmsdh_cfg_write(bus
->sdh
, SDIO_FUNC_0
, SDIOD_CCCR_IOEN
, enable
, NULL
);
4948 /* Give the dongle some time to do its thing and set IOR2 */
4949 dhd_timeout_start(&tmo
, DHD_WAIT_F2RDY
* 1000);
4952 while (ready
!= enable
&& !dhd_timeout_expired(&tmo
))
4953 ready
= bcmsdh_cfg_read(bus
->sdh
, SDIO_FUNC_0
, SDIOD_CCCR_IORDY
, NULL
);
4955 #endif /* !BCMSPI */
4957 DHD_ERROR(("%s: enable 0x%02x, ready 0x%02x (waited %uus)\n",
4958 __FUNCTION__
, enable
, ready
, tmo
.elapsed
));
4960 /* If F2 successfully enabled, set core and enable interrupts */
4961 if (ready
== enable
) {
4962 /* Make sure we're talking to the core. */
4964 bus
->regs
= si_setcore(bus
->sih
, CC_CORE_ID
, 0);
4965 ASSERT(bus
->regs
!= NULL
);
4967 if (!(bus
->regs
= si_setcore(bus
->sih
, PCMCIA_CORE_ID
, 0)))
4968 bus
->regs
= si_setcore(bus
->sih
, SDIOD_CORE_ID
, 0);
4969 ASSERT(bus
->regs
!= NULL
);
4971 /* Set up the interrupt mask and enable interrupts */
4972 bus
->hostintmask
= HOSTINTMASK
;
4973 /* corerev 4 could use the newer interrupt logic to detect the frames */
4975 if ((bus
->sih
->buscoretype
== SDIOD_CORE_ID
) && (bus
->sdpcmrev
== 4) &&
4976 (bus
->rxint_mode
!= SDIO_DEVICE_HMB_RXINT
)) {
4977 bus
->hostintmask
&= ~I_HMB_FRAME_IND
;
4978 bus
->hostintmask
|= I_XMTDATA_AVAIL
;
4981 W_SDREG(bus
->hostintmask
, &bus
->regs
->hostintmask
, retries
);
4983 if (bus
->sih
->buscorerev
< 15) {
4984 bcmsdh_cfg_write(bus
->sdh
, SDIO_FUNC_1
, SBSDIO_WATERMARK
,
4985 (uint8
)watermark
, &err
);
4988 /* Set bus state according to enable result */
4989 dhdp
->busstate
= DHD_BUS_DATA
;
4991 /* Need to set fn2 block size to match fn1 block size.
4992 * Requests to fn2 go thru fn1. *
4993 * faltwig has this code contitioned with #if !BCMSPI_ANDROID.
4994 * It would be cleaner to use the ->sdh->block_sz[fno] instead of
4995 * 64, but this layer has no access to sdh types.
4998 /* bcmsdh_intr_unmask(bus->sdh); */
5000 bus
->intdis
= FALSE
;
5002 DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__
));
5003 #ifndef BCMSPI_ANDROID
5004 bcmsdh_intr_enable(bus
->sdh
);
5005 #endif /* !BCMSPI_ANDROID */
5007 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__
));
5008 bcmsdh_intr_disable(bus
->sdh
);
5016 /* Disable F2 again */
5017 enable
= SDIO_FUNC_ENABLE_1
;
5018 bcmsdh_cfg_write(bus
->sdh
, SDIO_FUNC_0
, SDIOD_CCCR_IOEN
, enable
, NULL
);
5021 if (dhdsdio_sr_cap(bus
)) {
5022 dhdsdio_sr_init(bus
);
5023 /* Masking the chip active interrupt permanantly */
5024 bus
->hostintmask
&= ~I_CHIPACTIVE
;
5025 W_SDREG(bus
->hostintmask
, &bus
->regs
->hostintmask
, retries
);
5026 DHD_INFO(("%s: disable I_CHIPACTIVE in hostintmask[0x%08x]\n",
5027 __FUNCTION__
, bus
->hostintmask
));
5029 bcmsdh_cfg_write(bus
->sdh
, SDIO_FUNC_1
,
5030 SBSDIO_FUNC1_CHIPCLKCSR
, saveclk
, &err
);
5032 #endif /* !BCMSPI */
5034 /* If we didn't come up, turn off backplane clock */
5035 if (dhdp
->busstate
!= DHD_BUS_DATA
)
5036 dhdsdio_clkctl(bus
, CLK_NONE
, FALSE
);
5040 dhd_os_sdunlock(bus
->dhd
);
5046 dhdsdio_rxfail(dhd_bus_t
*bus
, bool abort
, bool rtx
)
5048 bcmsdh_info_t
*sdh
= bus
->sdh
;
5049 sdpcmd_regs_t
*regs
= bus
->regs
;
5055 DHD_ERROR(("%s: %sterminate frame%s\n", __FUNCTION__
,
5056 (abort
? "abort command, " : ""), (rtx
? ", send NAK" : "")));
5058 if (!KSO_ENAB(bus
)) {
5059 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__
));
5064 bcmsdh_abort(sdh
, SDIO_FUNC_2
);
5067 bcmsdh_cfg_write(sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_FRAMECTRL
, SFC_RF_TERM
, &err
);
5069 DHD_ERROR(("%s: SBSDIO_FUNC1_FRAMECTRL cmd err\n", __FUNCTION__
));
5074 /* Wait until the packet has been flushed (device/FIFO stable) */
5075 for (lastrbc
= retries
= 0xffff; retries
> 0; retries
--) {
5076 hi
= bcmsdh_cfg_read(sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_RFRAMEBCHI
, NULL
);
5077 lo
= bcmsdh_cfg_read(sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_RFRAMEBCLO
, &err
);
5079 DHD_ERROR(("%s: SBSDIO_FUNC1_RFAMEBCLO cmd err\n", __FUNCTION__
));
5083 bus
->f1regdata
+= 2;
5085 if ((hi
== 0) && (lo
== 0))
5088 if ((hi
> (lastrbc
>> 8)) && (lo
> (lastrbc
& 0x00ff))) {
5089 DHD_ERROR(("%s: count growing: last 0x%04x now 0x%04x\n",
5090 __FUNCTION__
, lastrbc
, ((hi
<< 8) + lo
)));
5092 lastrbc
= (hi
<< 8) + lo
;
5096 DHD_ERROR(("%s: count never zeroed: last 0x%04x\n", __FUNCTION__
, lastrbc
));
5098 DHD_INFO(("%s: flush took %d iterations\n", __FUNCTION__
, (0xffff - retries
)));
5103 W_SDREG(SMB_NAK
, ®s
->tosbmailbox
, retries
);
5105 if (retries
<= retry_limit
) {
5110 /* Clear partial in any case */
5114 /* If we can't reach the device, signal failure */
5115 if (err
|| bcmsdh_regfail(sdh
))
5116 bus
->dhd
->busstate
= DHD_BUS_DOWN
;
5120 dhdsdio_read_control(dhd_bus_t
*bus
, uint8
*hdr
, uint len
, uint doff
)
5122 bcmsdh_info_t
*sdh
= bus
->sdh
;
5127 DHD_TRACE(("%s: Enter\n", __FUNCTION__
));
5129 /* Control data already received in aligned rxctl */
5130 if ((bus
->bus
== SPI_BUS
) && (!bus
->usebufpool
))
5134 /* Set rxctl for frame (w/optional alignment) */
5135 bus
->rxctl
= bus
->rxbuf
;
5137 bus
->rxctl
+= firstread
;
5138 if ((pad
= ((uintptr
)bus
->rxctl
% DHD_SDALIGN
)))
5139 bus
->rxctl
+= (DHD_SDALIGN
- pad
);
5140 bus
->rxctl
-= firstread
;
5142 ASSERT(bus
->rxctl
>= bus
->rxbuf
);
5144 /* Copy the already-read portion over */
5145 bcopy(hdr
, bus
->rxctl
, firstread
);
5146 if (len
<= firstread
)
5149 /* Copy the full data pkt in gSPI case and process ioctl. */
5150 if (bus
->bus
== SPI_BUS
) {
5151 bcopy(hdr
, bus
->rxctl
, len
);
5155 /* Raise rdlen to next SDIO block to avoid tail command */
5156 rdlen
= len
- firstread
;
5157 if (bus
->roundup
&& bus
->blocksize
&& (rdlen
> bus
->blocksize
)) {
5158 pad
= bus
->blocksize
- (rdlen
% bus
->blocksize
);
5159 if ((pad
<= bus
->roundup
) && (pad
< bus
->blocksize
) &&
5160 ((len
+ pad
) < bus
->dhd
->maxctl
))
5162 } else if (rdlen
% DHD_SDALIGN
) {
5163 rdlen
+= DHD_SDALIGN
- (rdlen
% DHD_SDALIGN
);
5166 /* Satisfy length-alignment requirements */
5167 if (forcealign
&& (rdlen
& (ALIGNMENT
- 1)))
5168 rdlen
= ROUNDUP(rdlen
, ALIGNMENT
);
5170 /* Drop if the read is too big or it exceeds our maximum */
5171 if ((rdlen
+ firstread
) > bus
->dhd
->maxctl
) {
5172 DHD_ERROR(("%s: %d-byte control read exceeds %d-byte buffer\n",
5173 __FUNCTION__
, rdlen
, bus
->dhd
->maxctl
));
5174 bus
->dhd
->rx_errors
++;
5175 dhdsdio_rxfail(bus
, FALSE
, FALSE
);
5179 if ((len
- doff
) > bus
->dhd
->maxctl
) {
5180 DHD_ERROR(("%s: %d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n",
5181 __FUNCTION__
, len
, (len
- doff
), bus
->dhd
->maxctl
));
5182 bus
->dhd
->rx_errors
++; bus
->rx_toolong
++;
5183 dhdsdio_rxfail(bus
, FALSE
, FALSE
);
5187 /* Read remainder of frame body into the rxctl buffer */
5188 sdret
= dhd_bcmsdh_recv_buf(bus
, bcmsdh_cur_sbwad(sdh
), SDIO_FUNC_2
, F2SYNC
,
5189 (bus
->rxctl
+ firstread
), rdlen
, NULL
, NULL
, NULL
);
5191 ASSERT(sdret
!= BCME_PENDING
);
5193 /* Control frame failures need retransmission */
5195 DHD_ERROR(("%s: read %d control bytes failed: %d\n", __FUNCTION__
, rdlen
, sdret
));
5196 bus
->rxc_errors
++; /* dhd.rx_ctlerrs is higher level */
5197 dhdsdio_rxfail(bus
, TRUE
, TRUE
);
5204 if (DHD_BYTES_ON() && DHD_CTL_ON()) {
5205 prhex("RxCtrl", bus
->rxctl
, len
);
5209 /* Point to valid data and indicate its length */
5211 bus
->rxlen
= len
- doff
;
5214 /* Awake any waiters */
5215 dhd_os_ioctl_resp_wake(bus
->dhd
);
5218 dhd_process_pkt_reorder_info(dhd_pub_t
*dhd
, uchar
*reorder_info_buf
, uint reorder_info_len
,
5219 void **pkt
, uint32
*pkt_count
);
5222 dhdsdio_rxglom(dhd_bus_t
*bus
, uint8 rxseq
)
5224 uint16 dlen
, totlen
;
5225 uint8
*dptr
, num
= 0;
5227 uint16 sublen
, check
;
5228 void *pfirst
, *plast
, *pnext
;
5229 void * list_tail
[DHD_MAX_IFS
] = { NULL
};
5230 void * list_head
[DHD_MAX_IFS
] = { NULL
};
5232 osl_t
*osh
= bus
->dhd
->osh
;
5235 uint8 chan
, seq
, doff
, sfdoff
;
5237 uchar reorder_info_buf
[WLHOST_REORDERDATA_TOTLEN
];
5238 uint reorder_info_len
;
5241 bool usechain
= bus
->use_rxchain
;
5243 /* If packets, issue read(s) and send up packet chain */
5244 /* Return sequence numbers consumed? */
5246 DHD_TRACE(("dhdsdio_rxglom: start: glomd %p glom %p\n", bus
->glomd
, bus
->glom
));
5248 /* If there's a descriptor, generate the packet chain */
5250 dhd_os_sdlock_rxq(bus
->dhd
);
5252 pfirst
= plast
= pnext
= NULL
;
5253 dlen
= (uint16
)PKTLEN(osh
, bus
->glomd
);
5254 dptr
= PKTDATA(osh
, bus
->glomd
);
5255 if (!dlen
|| (dlen
& 1)) {
5256 DHD_ERROR(("%s: bad glomd len (%d), ignore descriptor\n",
5257 __FUNCTION__
, dlen
));
5261 for (totlen
= num
= 0; dlen
; num
++) {
5262 /* Get (and move past) next length */
5263 sublen
= ltoh16_ua(dptr
);
5264 dlen
-= sizeof(uint16
);
5265 dptr
+= sizeof(uint16
);
5266 if ((sublen
< SDPCM_HDRLEN
) ||
5267 ((num
== 0) && (sublen
< (2 * SDPCM_HDRLEN
)))) {
5268 DHD_ERROR(("%s: descriptor len %d bad: %d\n",
5269 __FUNCTION__
, num
, sublen
));
5273 if (sublen
% DHD_SDALIGN
) {
5274 DHD_ERROR(("%s: sublen %d not a multiple of %d\n",
5275 __FUNCTION__
, sublen
, DHD_SDALIGN
));
5280 /* For last frame, adjust read len so total is a block multiple */
5282 sublen
+= (ROUNDUP(totlen
, bus
->blocksize
) - totlen
);
5283 totlen
= ROUNDUP(totlen
, bus
->blocksize
);
5286 /* Allocate/chain packet for next subframe */
5287 if ((pnext
= PKTGET(osh
, sublen
+ DHD_SDALIGN
, FALSE
)) == NULL
) {
5288 DHD_ERROR(("%s: PKTGET failed, num %d len %d\n",
5289 __FUNCTION__
, num
, sublen
));
5292 ASSERT(!PKTLINK(pnext
));
5295 pfirst
= plast
= pnext
;
5298 PKTSETNEXT(osh
, plast
, pnext
);
5302 /* Adhere to start alignment requirements */
5303 PKTALIGN(osh
, pnext
, sublen
, DHD_SDALIGN
);
5306 /* If all allocations succeeded, save packet chain in bus structure */
5308 DHD_GLOM(("%s: allocated %d-byte packet chain for %d subframes\n",
5309 __FUNCTION__
, totlen
, num
));
5310 if (DHD_GLOM_ON() && bus
->nextlen
) {
5311 if (totlen
!= bus
->nextlen
) {
5312 DHD_GLOM(("%s: glomdesc mismatch: nextlen %d glomdesc %d "
5313 "rxseq %d\n", __FUNCTION__
, bus
->nextlen
,
5318 pfirst
= pnext
= NULL
;
5321 PKTFREE(osh
, pfirst
, FALSE
);
5326 /* Done with descriptor packet */
5327 PKTFREE(osh
, bus
->glomd
, FALSE
);
5331 dhd_os_sdunlock_rxq(bus
->dhd
);
5334 /* Ok -- either we just generated a packet chain, or had one from before */
5336 if (DHD_GLOM_ON()) {
5337 DHD_GLOM(("%s: attempt superframe read, packet chain:\n", __FUNCTION__
));
5338 for (pnext
= bus
->glom
; pnext
; pnext
= PKTNEXT(osh
, pnext
)) {
5339 DHD_GLOM((" %p: %p len 0x%04x (%d)\n",
5340 pnext
, (uint8
*)PKTDATA(osh
, pnext
),
5341 PKTLEN(osh
, pnext
), PKTLEN(osh
, pnext
)));
5346 dlen
= (uint16
)pkttotlen(osh
, pfirst
);
5348 /* Do an SDIO read for the superframe. Configurable iovar to
5349 * read directly into the chained packet, or allocate a large
5350 * packet and and copy into the chain.
5353 errcode
= dhd_bcmsdh_recv_buf(bus
,
5354 bcmsdh_cur_sbwad(bus
->sdh
), SDIO_FUNC_2
,
5355 F2SYNC
, (uint8
*)PKTDATA(osh
, pfirst
),
5356 dlen
, pfirst
, NULL
, NULL
);
5357 } else if (bus
->dataptr
) {
5358 errcode
= dhd_bcmsdh_recv_buf(bus
,
5359 bcmsdh_cur_sbwad(bus
->sdh
), SDIO_FUNC_2
,
5360 F2SYNC
, bus
->dataptr
,
5361 dlen
, NULL
, NULL
, NULL
);
5362 sublen
= (uint16
)pktfrombuf(osh
, pfirst
, 0, dlen
, bus
->dataptr
);
5363 if (sublen
!= dlen
) {
5364 DHD_ERROR(("%s: FAILED TO COPY, dlen %d sublen %d\n",
5365 __FUNCTION__
, dlen
, sublen
));
5369 BCM_REFERENCE(pnext
);
5371 DHD_ERROR(("COULDN'T ALLOC %d-BYTE GLOM, FORCE FAILURE\n", dlen
));
5375 ASSERT(errcode
!= BCME_PENDING
);
5377 /* On failure, kill the superframe, allow a couple retries */
5379 DHD_ERROR(("%s: glom read of %d bytes failed: %d\n",
5380 __FUNCTION__
, dlen
, errcode
));
5381 bus
->dhd
->rx_errors
++;
5383 if (bus
->glomerr
++ < 3) {
5384 dhdsdio_rxfail(bus
, TRUE
, TRUE
);
5387 dhdsdio_rxfail(bus
, TRUE
, FALSE
);
5388 dhd_os_sdlock_rxq(bus
->dhd
);
5389 PKTFREE(osh
, bus
->glom
, FALSE
);
5390 dhd_os_sdunlock_rxq(bus
->dhd
);
5398 if (DHD_GLOM_ON()) {
5399 prhex("SUPERFRAME", PKTDATA(osh
, pfirst
),
5400 MIN(PKTLEN(osh
, pfirst
), 48));
5404 /* Validate the superframe header */
5405 dptr
= (uint8
*)PKTDATA(osh
, pfirst
);
5406 sublen
= ltoh16_ua(dptr
);
5407 check
= ltoh16_ua(dptr
+ sizeof(uint16
));
5409 chan
= SDPCM_PACKET_CHANNEL(&dptr
[SDPCM_FRAMETAG_LEN
]);
5410 seq
= SDPCM_PACKET_SEQUENCE(&dptr
[SDPCM_FRAMETAG_LEN
]);
5411 bus
->nextlen
= dptr
[SDPCM_FRAMETAG_LEN
+ SDPCM_NEXTLEN_OFFSET
];
5412 if ((bus
->nextlen
<< 4) > MAX_RX_DATASZ
) {
5413 DHD_INFO(("%s: got frame w/nextlen too large (%d) seq %d\n",
5414 __FUNCTION__
, bus
->nextlen
, seq
));
5417 doff
= SDPCM_DOFFSET_VALUE(&dptr
[SDPCM_FRAMETAG_LEN
]);
5418 txmax
= SDPCM_WINDOW_VALUE(&dptr
[SDPCM_FRAMETAG_LEN
]);
5421 if ((uint16
)~(sublen
^check
)) {
5422 DHD_ERROR(("%s (superframe): HW hdr error: len/check 0x%04x/0x%04x\n",
5423 __FUNCTION__
, sublen
, check
));
5425 } else if (ROUNDUP(sublen
, bus
->blocksize
) != dlen
) {
5426 DHD_ERROR(("%s (superframe): len 0x%04x, rounded 0x%04x, expect 0x%04x\n",
5427 __FUNCTION__
, sublen
, ROUNDUP(sublen
, bus
->blocksize
), dlen
));
5429 } else if (SDPCM_PACKET_CHANNEL(&dptr
[SDPCM_FRAMETAG_LEN
]) != SDPCM_GLOM_CHANNEL
) {
5430 DHD_ERROR(("%s (superframe): bad channel %d\n", __FUNCTION__
,
5431 SDPCM_PACKET_CHANNEL(&dptr
[SDPCM_FRAMETAG_LEN
])));
5433 } else if (SDPCM_GLOMDESC(&dptr
[SDPCM_FRAMETAG_LEN
])) {
5434 DHD_ERROR(("%s (superframe): got second descriptor?\n", __FUNCTION__
));
5436 } else if ((doff
< SDPCM_HDRLEN
) ||
5437 (doff
> (PKTLEN(osh
, pfirst
) - SDPCM_HDRLEN
))) {
5438 DHD_ERROR(("%s (superframe): Bad data offset %d: HW %d pkt %d min %d\n",
5439 __FUNCTION__
, doff
, sublen
, PKTLEN(osh
, pfirst
),
5444 /* Check sequence number of superframe SW header */
5446 DHD_INFO(("%s: (superframe) rx_seq %d, expected %d\n",
5447 __FUNCTION__
, seq
, rxseq
));
5452 /* Check window for sanity */
5453 if ((uint8
)(txmax
- bus
->tx_seq
) > 0x70) {
5454 DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
5455 __FUNCTION__
, txmax
, bus
->tx_seq
));
5456 txmax
= bus
->tx_max
;
5458 bus
->tx_max
= txmax
;
5460 /* Remove superframe header, remember offset */
5461 PKTPULL(osh
, pfirst
, doff
);
5464 /* Validate all the subframe headers */
5465 for (num
= 0, pnext
= pfirst
; pnext
&& !errcode
;
5466 num
++, pnext
= PKTNEXT(osh
, pnext
)) {
5467 dptr
= (uint8
*)PKTDATA(osh
, pnext
);
5468 dlen
= (uint16
)PKTLEN(osh
, pnext
);
5469 sublen
= ltoh16_ua(dptr
);
5470 check
= ltoh16_ua(dptr
+ sizeof(uint16
));
5471 chan
= SDPCM_PACKET_CHANNEL(&dptr
[SDPCM_FRAMETAG_LEN
]);
5472 doff
= SDPCM_DOFFSET_VALUE(&dptr
[SDPCM_FRAMETAG_LEN
]);
5474 if (DHD_GLOM_ON()) {
5475 prhex("subframe", dptr
, 32);
5479 if ((uint16
)~(sublen
^check
)) {
5480 DHD_ERROR(("%s (subframe %d): HW hdr error: "
5481 "len/check 0x%04x/0x%04x\n",
5482 __FUNCTION__
, num
, sublen
, check
));
5484 } else if ((sublen
> dlen
) || (sublen
< SDPCM_HDRLEN
)) {
5485 DHD_ERROR(("%s (subframe %d): length mismatch: "
5486 "len 0x%04x, expect 0x%04x\n",
5487 __FUNCTION__
, num
, sublen
, dlen
));
5489 } else if ((chan
!= SDPCM_DATA_CHANNEL
) &&
5490 (chan
!= SDPCM_EVENT_CHANNEL
)) {
5491 DHD_ERROR(("%s (subframe %d): bad channel %d\n",
5492 __FUNCTION__
, num
, chan
));
5494 } else if ((doff
< SDPCM_HDRLEN
) || (doff
> sublen
)) {
5495 DHD_ERROR(("%s (subframe %d): Bad data offset %d: HW %d min %d\n",
5496 __FUNCTION__
, num
, doff
, sublen
, SDPCM_HDRLEN
));
5502 /* Terminate frame on error, request a couple retries */
5503 if (bus
->glomerr
++ < 3) {
5504 /* Restore superframe header space */
5505 PKTPUSH(osh
, pfirst
, sfdoff
);
5506 dhdsdio_rxfail(bus
, TRUE
, TRUE
);
5509 dhdsdio_rxfail(bus
, TRUE
, FALSE
);
5510 dhd_os_sdlock_rxq(bus
->dhd
);
5511 PKTFREE(osh
, bus
->glom
, FALSE
);
5512 dhd_os_sdunlock_rxq(bus
->dhd
);
5520 /* Basic SD framing looks ok - process each packet (header) */
5524 dhd_os_sdlock_rxq(bus
->dhd
);
5525 for (num
= 0; pfirst
; rxseq
++, pfirst
= pnext
) {
5526 pnext
= PKTNEXT(osh
, pfirst
);
5527 PKTSETNEXT(osh
, pfirst
, NULL
);
5529 dptr
= (uint8
*)PKTDATA(osh
, pfirst
);
5530 sublen
= ltoh16_ua(dptr
);
5531 chan
= SDPCM_PACKET_CHANNEL(&dptr
[SDPCM_FRAMETAG_LEN
]);
5532 seq
= SDPCM_PACKET_SEQUENCE(&dptr
[SDPCM_FRAMETAG_LEN
]);
5533 doff
= SDPCM_DOFFSET_VALUE(&dptr
[SDPCM_FRAMETAG_LEN
]);
5535 DHD_GLOM(("%s: Get subframe %d, %p(%p/%d), sublen %d chan %d seq %d\n",
5536 __FUNCTION__
, num
, pfirst
, PKTDATA(osh
, pfirst
),
5537 PKTLEN(osh
, pfirst
), sublen
, chan
, seq
));
5539 ASSERT((chan
== SDPCM_DATA_CHANNEL
) || (chan
== SDPCM_EVENT_CHANNEL
));
5542 DHD_GLOM(("%s: rx_seq %d, expected %d\n",
5543 __FUNCTION__
, seq
, rxseq
));
5549 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
5550 prhex("Rx Subframe Data", dptr
, dlen
);
5554 PKTSETLEN(osh
, pfirst
, sublen
);
5555 PKTPULL(osh
, pfirst
, doff
);
5557 reorder_info_len
= sizeof(reorder_info_buf
);
5559 if (PKTLEN(osh
, pfirst
) == 0) {
5560 PKTFREE(bus
->dhd
->osh
, pfirst
, FALSE
);
5562 } else if (dhd_prot_hdrpull(bus
->dhd
, &ifidx
, pfirst
, reorder_info_buf
,
5563 &reorder_info_len
) != 0) {
5564 DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__
));
5565 bus
->dhd
->rx_errors
++;
5566 PKTFREE(osh
, pfirst
, FALSE
);
5569 if (reorder_info_len
) {
5570 uint32 free_buf_count
;
5574 /* Reordering info from the firmware */
5575 dhd_process_pkt_reorder_info(bus
->dhd
, reorder_info_buf
,
5576 reorder_info_len
, &ppfirst
, &free_buf_count
);
5578 if (free_buf_count
== 0) {
5583 /* go to the end of the chain and attach the pnext there */
5585 while (PKTNEXT(osh
, temp
) != NULL
) {
5586 temp
= PKTNEXT(osh
, temp
);
5589 if (list_tail
[ifidx
] == NULL
)
5590 list_head
[ifidx
] = ppfirst
;
5592 PKTSETNEXT(osh
, list_tail
[ifidx
], ppfirst
);
5593 list_tail
[ifidx
] = pfirst
;
5596 num
+= (uint8
)free_buf_count
;
5598 /* this packet will go up, link back into chain and count it */
5600 if (list_tail
[ifidx
] == NULL
) {
5601 list_head
[ifidx
] = list_tail
[ifidx
] = pfirst
;
5603 PKTSETNEXT(osh
, list_tail
[ifidx
], pfirst
);
5604 list_tail
[ifidx
] = pfirst
;
5609 if (DHD_GLOM_ON()) {
5610 DHD_GLOM(("%s subframe %d to stack, %p(%p/%d) nxt/lnk %p/%p\n",
5611 __FUNCTION__
, num
, pfirst
,
5612 PKTDATA(osh
, pfirst
), PKTLEN(osh
, pfirst
),
5613 PKTNEXT(osh
, pfirst
), PKTLINK(pfirst
)));
5614 prhex("", (uint8
*)PKTDATA(osh
, pfirst
),
5615 MIN(PKTLEN(osh
, pfirst
), 32));
5617 #endif /* DHD_DEBUG */
5619 dhd_os_sdunlock_rxq(bus
->dhd
);
5621 for (idx
= 0; idx
< DHD_MAX_IFS
; idx
++) {
5622 if (list_head
[idx
]) {
5625 temp
= list_head
[idx
];
5627 temp
= PKTNEXT(osh
, temp
);
5631 dhd_os_sdunlock(bus
->dhd
);
5632 dhd_rx_frame(bus
->dhd
, idx
, list_head
[idx
], cnt
, 0);
5633 dhd_os_sdlock(bus
->dhd
);
5637 bus
->rxglomframes
++;
5638 bus
->rxglompkts
+= num
;
5643 /* Return TRUE if there may be more frames to read */
5645 dhdsdio_readframes(dhd_bus_t
*bus
, uint maxframes
, bool *finished
)
5647 osl_t
*osh
= bus
->dhd
->osh
;
5648 bcmsdh_info_t
*sdh
= bus
->sdh
;
5650 uint16 len
, check
; /* Extracted hardware header fields */
5651 uint8 chan
, seq
, doff
; /* Extracted software header fields */
5652 uint8 fcbits
; /* Extracted fcbits from software header */
5655 void *pkt
; /* Packet for event or data frames */
5656 uint16 pad
; /* Number of pad bytes to read */
5657 uint16 rdlen
; /* Total number of bytes to read */
5658 uint8 rxseq
; /* Next sequence number to expect */
5659 uint rxleft
= 0; /* Remaining number of frames allowed */
5660 int sdret
; /* Return code from bcmsdh calls */
5661 uint8 txmax
; /* Maximum tx sequence offered */
5663 uint32 dstatus
= 0; /* gSPI device status bits of */
5665 bool len_consistent
; /* Result of comparing readahead len and len from hw-hdr */
5668 uint rxcount
= 0; /* Total frames read */
5669 uchar reorder_info_buf
[WLHOST_REORDERDATA_TOTLEN
];
5670 uint reorder_info_len
;
5673 #if defined(DHD_DEBUG) || defined(SDTEST)
5674 bool sdtest
= FALSE
; /* To limit message spew from test mode */
5677 DHD_TRACE(("%s: Enter\n", __FUNCTION__
));
5678 bus
->readframes
= TRUE
;
5680 if (!KSO_ENAB(bus
)) {
5681 DHD_ERROR(("%s: KSO off\n", __FUNCTION__
));
5682 bus
->readframes
= FALSE
;
5689 /* Allow pktgen to override maxframes */
5690 if (bus
->pktgen_count
&& (bus
->pktgen_mode
== DHD_PKTGEN_RECV
)) {
5691 maxframes
= bus
->pktgen_count
;
5696 /* Not finished unless we encounter no more frames indication */
5700 /* Get pktlen from gSPI device F0 reg. */
5701 if (bus
->bus
== SPI_BUS
) {
5702 /* Peek in dstatus bits and find out size to do rx-read. */
5703 dstatus
= bcmsdh_get_dstatus(bus
->sdh
);
5705 DHD_ERROR(("%s:ZERO spi dstatus, a case observed in PR61352 hit !!!\n",
5708 DHD_TRACE(("Device status from regread = 0x%x\n", dstatus
));
5709 DHD_TRACE(("Device status from bit-reconstruction = 0x%x\n",
5710 bcmsdh_get_dstatus((void *)bus
->sdh
)));
5712 if ((dstatus
& STATUS_F2_PKT_AVAILABLE
) && (((dstatus
& STATUS_UNDERFLOW
)) == 0)) {
5713 bus
->nextlen
= ((dstatus
& STATUS_F2_PKT_LEN_MASK
) >>
5714 STATUS_F2_PKT_LEN_SHIFT
);
5715 /* '0' size with pkt-available interrupt is eqvt to 2048 bytes */
5716 bus
->nextlen
= (bus
->nextlen
== 0) ? SPI_MAX_PKT_LEN
: bus
->nextlen
;
5718 bus
->nextlen
= bus
->nextlen
<< 2;
5719 DHD_TRACE(("Entering %s: length to be read from gSPI = %d\n",
5720 __FUNCTION__
, bus
->nextlen
));
5722 if (dstatus
& STATUS_F2_PKT_AVAILABLE
)
5723 DHD_ERROR(("Underflow during %s.\n", __FUNCTION__
));
5725 DHD_ERROR(("False pkt-available intr.\n"));
5727 return (maxframes
- rxleft
);
5732 for (rxseq
= bus
->rx_seq
, rxleft
= maxframes
;
5733 !bus
->rxskip
&& rxleft
&& bus
->dhd
->busstate
!= DHD_BUS_DOWN
;
5734 rxseq
++, rxleft
--) {
5735 #ifdef DHDTCPACK_SUP_DBG
5736 if (bus
->dhd
->tcpack_sup_mode
!= TCPACK_SUP_DELAYTX
) {
5737 if (bus
->dotxinrx
== FALSE
)
5738 DHD_ERROR(("%s %d: dotxinrx FALSE with tcpack_sub_mode %d\n",
5739 __FUNCTION__
, __LINE__
, bus
->dhd
->tcpack_sup_mode
));
5741 #ifdef DEBUG_COUNTER
5742 else if (pktq_mlen(&bus
->txq
, ~bus
->flowcontrol
) > 0) {
5743 tack_tbl
.cnt
[bus
->dotxinrx
? 6 : 7]++;
5745 #endif /* DEBUG_COUNTER */
5746 #endif /* DHDTCPACK_SUP_DBG */
5747 /* tx more to improve rx performance */
5748 if (TXCTLOK(bus
) && bus
->ctrl_frame_stat
&& (bus
->clkstate
== CLK_AVAIL
)) {
5749 dhdsdio_sendpendctl(bus
);
5750 } else if (bus
->dotxinrx
&& (bus
->clkstate
== CLK_AVAIL
) &&
5751 !bus
->fcstate
&& DATAOK(bus
) &&
5752 (pktq_mlen(&bus
->txq
, ~bus
->flowcontrol
) > bus
->txinrx_thres
)) {
5753 dhdsdio_sendfromq(bus
, dhd_txbound
);
5754 #ifdef DHDTCPACK_SUPPRESS
5755 /* In TCPACK_SUP_DELAYTX mode, do txinrx only if
5756 * 1. Any DATA packet to TX
5757 * 2. TCPACK to TCPDATA PSH packets.
5760 bus
->dotxinrx
= (bus
->dhd
->tcpack_sup_mode
== TCPACK_SUP_DELAYTX
) ?
5765 /* Handle glomming separately */
5766 if (bus
->glom
|| bus
->glomd
) {
5768 DHD_GLOM(("%s: calling rxglom: glomd %p, glom %p\n",
5769 __FUNCTION__
, bus
->glomd
, bus
->glom
));
5770 cnt
= dhdsdio_rxglom(bus
, rxseq
);
5771 DHD_GLOM(("%s: rxglom returned %d\n", __FUNCTION__
, cnt
));
5773 rxleft
= (rxleft
> cnt
) ? (rxleft
- cnt
) : 1;
5777 /* Try doing single read if we can */
5778 if (dhd_readahead
&& bus
->nextlen
) {
5779 uint16 nextlen
= bus
->nextlen
;
5782 if (bus
->bus
== SPI_BUS
) {
5783 rdlen
= len
= nextlen
;
5785 rdlen
= len
= nextlen
<< 4;
5787 /* Pad read to blocksize for efficiency */
5788 if (bus
->roundup
&& bus
->blocksize
&& (rdlen
> bus
->blocksize
)) {
5789 pad
= bus
->blocksize
- (rdlen
% bus
->blocksize
);
5790 if ((pad
<= bus
->roundup
) && (pad
< bus
->blocksize
) &&
5791 ((rdlen
+ pad
+ firstread
) < MAX_RX_DATASZ
))
5793 } else if (rdlen
% DHD_SDALIGN
) {
5794 rdlen
+= DHD_SDALIGN
- (rdlen
% DHD_SDALIGN
);
5798 /* We use bus->rxctl buffer in WinXP for initial control pkt receives.
5799 * Later we use buffer-poll for data as well as control packets.
5800 * This is required because dhd receives full frame in gSPI unlike SDIO.
5801 * After the frame is received we have to distinguish whether it is data
5802 * or non-data frame.
5804 /* Allocate a packet buffer */
5805 dhd_os_sdlock_rxq(bus
->dhd
);
5806 if (!(pkt
= PKTGET(osh
, rdlen
+ DHD_SDALIGN
, FALSE
))) {
5807 if (bus
->bus
== SPI_BUS
) {
5808 bus
->usebufpool
= FALSE
;
5809 bus
->rxctl
= bus
->rxbuf
;
5811 bus
->rxctl
+= firstread
;
5812 if ((pad
= ((uintptr
)bus
->rxctl
% DHD_SDALIGN
)))
5813 bus
->rxctl
+= (DHD_SDALIGN
- pad
);
5814 bus
->rxctl
-= firstread
;
5816 ASSERT(bus
->rxctl
>= bus
->rxbuf
);
5818 /* Read the entire frame */
5819 sdret
= dhd_bcmsdh_recv_buf(bus
,
5820 bcmsdh_cur_sbwad(sdh
),
5822 F2SYNC
, rxbuf
, rdlen
,
5825 ASSERT(sdret
!= BCME_PENDING
);
5828 if (bcmsdh_get_dstatus((void *)bus
->sdh
) &
5832 DHD_ERROR(("%s: read %d control bytes failed "
5833 "due to spi underflow\n",
5834 __FUNCTION__
, rdlen
));
5835 /* dhd.rx_ctlerrs is higher level */
5837 dhd_os_sdunlock_rxq(bus
->dhd
);
5842 /* Control frame failures need retransmission */
5844 DHD_ERROR(("%s: read %d control bytes failed: %d\n",
5845 __FUNCTION__
, rdlen
, sdret
));
5846 /* dhd.rx_ctlerrs is higher level */
5848 dhd_os_sdunlock_rxq(bus
->dhd
);
5849 dhdsdio_rxfail(bus
, TRUE
,
5850 (bus
->bus
== SPI_BUS
) ? FALSE
: TRUE
);
5854 /* Give up on data, request rtx of events */
5855 DHD_ERROR(("%s (nextlen): PKTGET failed: len %d rdlen %d "
5856 "expected rxseq %d\n",
5857 __FUNCTION__
, len
, rdlen
, rxseq
));
5858 /* Just go try again w/normal header read */
5859 dhd_os_sdunlock_rxq(bus
->dhd
);
5863 if (bus
->bus
== SPI_BUS
)
5864 bus
->usebufpool
= TRUE
;
5866 ASSERT(!PKTLINK(pkt
));
5867 PKTALIGN(osh
, pkt
, rdlen
, DHD_SDALIGN
);
5868 rxbuf
= (uint8
*)PKTDATA(osh
, pkt
);
5869 /* Read the entire frame */
5870 sdret
= dhd_bcmsdh_recv_buf(bus
, bcmsdh_cur_sbwad(sdh
),
5872 F2SYNC
, rxbuf
, rdlen
,
5875 ASSERT(sdret
!= BCME_PENDING
);
5877 if (bcmsdh_get_dstatus((void *)bus
->sdh
) & STATUS_UNDERFLOW
) {
5880 DHD_ERROR(("%s (nextlen): read %d bytes failed due "
5881 "to spi underflow\n",
5882 __FUNCTION__
, rdlen
));
5883 PKTFREE(bus
->dhd
->osh
, pkt
, FALSE
);
5884 bus
->dhd
->rx_errors
++;
5885 dhd_os_sdunlock_rxq(bus
->dhd
);
5891 DHD_ERROR(("%s (nextlen): read %d bytes failed: %d\n",
5892 __FUNCTION__
, rdlen
, sdret
));
5893 PKTFREE(bus
->dhd
->osh
, pkt
, FALSE
);
5894 bus
->dhd
->rx_errors
++;
5895 dhd_os_sdunlock_rxq(bus
->dhd
);
5896 /* Force retry w/normal header read. Don't attempt NAK for
5899 dhdsdio_rxfail(bus
, TRUE
,
5900 (bus
->bus
== SPI_BUS
) ? FALSE
: TRUE
);
5904 dhd_os_sdunlock_rxq(bus
->dhd
);
5906 /* Now check the header */
5907 bcopy(rxbuf
, bus
->rxhdr
, SDPCM_HDRLEN
);
5909 /* Extract hardware header fields */
5910 len
= ltoh16_ua(bus
->rxhdr
);
5911 check
= ltoh16_ua(bus
->rxhdr
+ sizeof(uint16
));
5913 /* All zeros means readahead info was bad */
5915 DHD_INFO(("%s (nextlen): read zeros in HW header???\n",
5917 dhd_os_sdlock_rxq(bus
->dhd
);
5919 dhd_os_sdunlock_rxq(bus
->dhd
);
5920 GSPI_PR55150_BAILOUT
;
5924 /* Validate check bytes */
5925 if ((uint16
)~(len
^check
)) {
5926 DHD_ERROR(("%s (nextlen): HW hdr error: nextlen/len/check"
5927 " 0x%04x/0x%04x/0x%04x\n", __FUNCTION__
, nextlen
,
5929 dhd_os_sdlock_rxq(bus
->dhd
);
5931 dhd_os_sdunlock_rxq(bus
->dhd
);
5933 dhdsdio_rxfail(bus
, FALSE
, FALSE
);
5934 GSPI_PR55150_BAILOUT
;
5938 /* Validate frame length */
5939 if (len
< SDPCM_HDRLEN
) {
5940 DHD_ERROR(("%s (nextlen): HW hdr length invalid: %d\n",
5941 __FUNCTION__
, len
));
5942 dhd_os_sdlock_rxq(bus
->dhd
);
5944 dhd_os_sdunlock_rxq(bus
->dhd
);
5945 GSPI_PR55150_BAILOUT
;
5949 /* Check for consistency with readahead info */
5951 if (bus
->bus
== SPI_BUS
) {
5952 if (bus
->dwordmode
) {
5954 spilen
= ROUNDUP(len
, 4);
5955 len_consistent
= (nextlen
!= spilen
);
5957 len_consistent
= (nextlen
!= len
);
5960 len_consistent
= (nextlen
!= (ROUNDUP(len
, 16) >> 4));
5961 if (len_consistent
) {
5962 /* Mismatch, force retry w/normal header (may be >4K) */
5963 DHD_ERROR(("%s (nextlen): mismatch, nextlen %d len %d rnd %d; "
5964 "expected rxseq %d\n",
5965 __FUNCTION__
, nextlen
, len
, ROUNDUP(len
, 16), rxseq
));
5966 dhd_os_sdlock_rxq(bus
->dhd
);
5968 dhd_os_sdunlock_rxq(bus
->dhd
);
5969 dhdsdio_rxfail(bus
, TRUE
, (bus
->bus
== SPI_BUS
) ? FALSE
: TRUE
);
5970 GSPI_PR55150_BAILOUT
;
5974 /* Extract software header fields */
5975 chan
= SDPCM_PACKET_CHANNEL(&bus
->rxhdr
[SDPCM_FRAMETAG_LEN
]);
5976 seq
= SDPCM_PACKET_SEQUENCE(&bus
->rxhdr
[SDPCM_FRAMETAG_LEN
]);
5977 doff
= SDPCM_DOFFSET_VALUE(&bus
->rxhdr
[SDPCM_FRAMETAG_LEN
]);
5978 txmax
= SDPCM_WINDOW_VALUE(&bus
->rxhdr
[SDPCM_FRAMETAG_LEN
]);
5981 /* Save the readahead length if there is one */
5982 if (bus
->bus
== SPI_BUS
) {
5983 /* Use reconstructed dstatus bits and find out readahead size */
5984 dstatus
= bcmsdh_get_dstatus((void *)bus
->sdh
);
5985 DHD_INFO(("Device status from bit-reconstruction = 0x%x\n",
5986 bcmsdh_get_dstatus((void *)bus
->sdh
)));
5987 if (dstatus
& STATUS_F2_PKT_AVAILABLE
) {
5988 bus
->nextlen
= ((dstatus
& STATUS_F2_PKT_LEN_MASK
) >>
5989 STATUS_F2_PKT_LEN_SHIFT
);
5990 bus
->nextlen
= (bus
->nextlen
== 0) ?
5991 SPI_MAX_PKT_LEN
: bus
->nextlen
;
5993 bus
->nextlen
= bus
->nextlen
<< 2;
5994 DHD_INFO(("readahead len from gSPI = %d \n",
5996 bus
->dhd
->rx_readahead_cnt
++;
6004 bus
->rxhdr
[SDPCM_FRAMETAG_LEN
+ SDPCM_NEXTLEN_OFFSET
];
6005 if ((bus
->nextlen
<< 4) > MAX_RX_DATASZ
) {
6006 DHD_INFO(("%s (nextlen): got frame w/nextlen too large"
6007 " (%d), seq %d\n", __FUNCTION__
, bus
->nextlen
,
6012 bus
->dhd
->rx_readahead_cnt
++;
6016 /* Handle Flow Control */
6017 fcbits
= SDPCM_FCMASK_VALUE(&bus
->rxhdr
[SDPCM_FRAMETAG_LEN
]);
6020 if (~bus
->flowcontrol
& fcbits
) {
6024 if (bus
->flowcontrol
& ~fcbits
) {
6031 bus
->flowcontrol
= fcbits
;
6034 /* Check and update sequence number */
6036 DHD_INFO(("%s (nextlen): rx_seq %d, expected %d\n",
6037 __FUNCTION__
, seq
, rxseq
));
6042 /* Check window for sanity */
6043 if ((uint8
)(txmax
- bus
->tx_seq
) > 0x70) {
6045 if ((bus
->bus
== SPI_BUS
) && !(dstatus
& STATUS_F2_RX_READY
)) {
6046 DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
6047 __FUNCTION__
, txmax
, bus
->tx_seq
));
6048 txmax
= bus
->tx_seq
+ 2;
6051 DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
6052 __FUNCTION__
, txmax
, bus
->tx_seq
));
6053 txmax
= bus
->tx_max
;
6058 bus
->tx_max
= txmax
;
6061 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
6062 prhex("Rx Data", rxbuf
, len
);
6063 } else if (DHD_HDRS_ON()) {
6064 prhex("RxHdr", bus
->rxhdr
, SDPCM_HDRLEN
);
6068 if (chan
== SDPCM_CONTROL_CHANNEL
) {
6069 if (bus
->bus
== SPI_BUS
) {
6070 dhdsdio_read_control(bus
, rxbuf
, len
, doff
);
6071 if (bus
->usebufpool
) {
6072 dhd_os_sdlock_rxq(bus
->dhd
);
6073 PKTFREE(bus
->dhd
->osh
, pkt
, FALSE
);
6074 dhd_os_sdunlock_rxq(bus
->dhd
);
6078 DHD_ERROR(("%s (nextlen): readahead on control"
6079 " packet %d?\n", __FUNCTION__
, seq
));
6080 /* Force retry w/normal header read */
6082 dhdsdio_rxfail(bus
, FALSE
, TRUE
);
6083 dhd_os_sdlock_rxq(bus
->dhd
);
6085 dhd_os_sdunlock_rxq(bus
->dhd
);
6090 if ((bus
->bus
== SPI_BUS
) && !bus
->usebufpool
) {
6091 DHD_ERROR(("Received %d bytes on %d channel. Running out of "
6092 "rx pktbuf's or not yet malloced.\n", len
, chan
));
6096 /* Validate data offset */
6097 if ((doff
< SDPCM_HDRLEN
) || (doff
> len
)) {
6098 DHD_ERROR(("%s (nextlen): bad data offset %d: HW len %d min %d\n",
6099 __FUNCTION__
, doff
, len
, SDPCM_HDRLEN
));
6100 dhd_os_sdlock_rxq(bus
->dhd
);
6102 dhd_os_sdunlock_rxq(bus
->dhd
);
6104 dhdsdio_rxfail(bus
, FALSE
, FALSE
);
6108 /* All done with this one -- now deliver the packet */
6111 /* gSPI frames should not be handled in fractions */
6112 if (bus
->bus
== SPI_BUS
) {
6116 /* Read frame header (hardware and software) */
6117 sdret
= dhd_bcmsdh_recv_buf(bus
, bcmsdh_cur_sbwad(sdh
), SDIO_FUNC_2
, F2SYNC
,
6118 bus
->rxhdr
, firstread
, NULL
, NULL
, NULL
);
6120 ASSERT(sdret
!= BCME_PENDING
);
6123 DHD_ERROR(("%s: RXHEADER FAILED: %d\n", __FUNCTION__
, sdret
));
6125 dhdsdio_rxfail(bus
, TRUE
, TRUE
);
6130 if (DHD_BYTES_ON() || DHD_HDRS_ON()) {
6131 prhex("RxHdr", bus
->rxhdr
, SDPCM_HDRLEN
);
6135 /* Extract hardware header fields */
6136 len
= ltoh16_ua(bus
->rxhdr
);
6137 check
= ltoh16_ua(bus
->rxhdr
+ sizeof(uint16
));
6139 /* All zeros means no more frames */
6145 /* Validate check bytes */
6146 if ((uint16
)~(len
^check
)) {
6147 DHD_ERROR(("%s: HW hdr error: len/check 0x%04x/0x%04x\n",
6148 __FUNCTION__
, len
, check
));
6150 dhdsdio_rxfail(bus
, FALSE
, FALSE
);
6154 /* Validate frame length */
6155 if (len
< SDPCM_HDRLEN
) {
6156 DHD_ERROR(("%s: HW hdr length invalid: %d\n", __FUNCTION__
, len
));
6160 /* Extract software header fields */
6161 chan
= SDPCM_PACKET_CHANNEL(&bus
->rxhdr
[SDPCM_FRAMETAG_LEN
]);
6162 seq
= SDPCM_PACKET_SEQUENCE(&bus
->rxhdr
[SDPCM_FRAMETAG_LEN
]);
6163 doff
= SDPCM_DOFFSET_VALUE(&bus
->rxhdr
[SDPCM_FRAMETAG_LEN
]);
6164 txmax
= SDPCM_WINDOW_VALUE(&bus
->rxhdr
[SDPCM_FRAMETAG_LEN
]);
6166 /* Validate data offset */
6167 if ((doff
< SDPCM_HDRLEN
) || (doff
> len
)) {
6168 DHD_ERROR(("%s: Bad data offset %d: HW len %d, min %d seq %d\n",
6169 __FUNCTION__
, doff
, len
, SDPCM_HDRLEN
, seq
));
6172 dhdsdio_rxfail(bus
, FALSE
, FALSE
);
6176 /* Save the readahead length if there is one */
6177 bus
->nextlen
= bus
->rxhdr
[SDPCM_FRAMETAG_LEN
+ SDPCM_NEXTLEN_OFFSET
];
6178 if ((bus
->nextlen
<< 4) > MAX_RX_DATASZ
) {
6179 DHD_INFO(("%s (nextlen): got frame w/nextlen too large (%d), seq %d\n",
6180 __FUNCTION__
, bus
->nextlen
, seq
));
6184 /* Handle Flow Control */
6185 fcbits
= SDPCM_FCMASK_VALUE(&bus
->rxhdr
[SDPCM_FRAMETAG_LEN
]);
6188 if (~bus
->flowcontrol
& fcbits
) {
6192 if (bus
->flowcontrol
& ~fcbits
) {
6199 bus
->flowcontrol
= fcbits
;
6202 /* Check and update sequence number */
6204 DHD_INFO(("%s: rx_seq %d, expected %d\n", __FUNCTION__
, seq
, rxseq
));
6209 /* Check window for sanity */
6210 if ((uint8
)(txmax
- bus
->tx_seq
) > 0x70) {
6211 DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
6212 __FUNCTION__
, txmax
, bus
->tx_seq
));
6213 txmax
= bus
->tx_max
;
6215 bus
->tx_max
= txmax
;
6217 /* Call a separate function for control frames */
6218 if (chan
== SDPCM_CONTROL_CHANNEL
) {
6219 dhdsdio_read_control(bus
, bus
->rxhdr
, len
, doff
);
6223 ASSERT((chan
== SDPCM_DATA_CHANNEL
) || (chan
== SDPCM_EVENT_CHANNEL
) ||
6224 (chan
== SDPCM_TEST_CHANNEL
) || (chan
== SDPCM_GLOM_CHANNEL
));
6226 /* Length to read */
6227 rdlen
= (len
> firstread
) ? (len
- firstread
) : 0;
6229 /* May pad read to blocksize for efficiency */
6230 if (bus
->roundup
&& bus
->blocksize
&& (rdlen
> bus
->blocksize
)) {
6231 pad
= bus
->blocksize
- (rdlen
% bus
->blocksize
);
6232 if ((pad
<= bus
->roundup
) && (pad
< bus
->blocksize
) &&
6233 ((rdlen
+ pad
+ firstread
) < MAX_RX_DATASZ
))
6235 } else if (rdlen
% DHD_SDALIGN
) {
6236 rdlen
+= DHD_SDALIGN
- (rdlen
% DHD_SDALIGN
);
6239 /* Satisfy length-alignment requirements */
6240 if (forcealign
&& (rdlen
& (ALIGNMENT
- 1)))
6241 rdlen
= ROUNDUP(rdlen
, ALIGNMENT
);
6243 if ((rdlen
+ firstread
) > MAX_RX_DATASZ
) {
6244 /* Too long -- skip this frame */
6245 DHD_ERROR(("%s: too long: len %d rdlen %d\n", __FUNCTION__
, len
, rdlen
));
6246 bus
->dhd
->rx_errors
++; bus
->rx_toolong
++;
6247 dhdsdio_rxfail(bus
, FALSE
, FALSE
);
6251 dhd_os_sdlock_rxq(bus
->dhd
);
6252 if (!(pkt
= PKTGET(osh
, (rdlen
+ firstread
+ DHD_SDALIGN
), FALSE
))) {
6253 /* Give up on data, request rtx of events */
6254 DHD_ERROR(("%s: PKTGET failed: rdlen %d chan %d\n",
6255 __FUNCTION__
, rdlen
, chan
));
6256 bus
->dhd
->rx_dropped
++;
6257 dhd_os_sdunlock_rxq(bus
->dhd
);
6258 dhdsdio_rxfail(bus
, FALSE
, RETRYCHAN(chan
));
6261 dhd_os_sdunlock_rxq(bus
->dhd
);
6263 ASSERT(!PKTLINK(pkt
));
6265 /* Leave room for what we already read, and align remainder */
6266 ASSERT(firstread
< (PKTLEN(osh
, pkt
)));
6267 PKTPULL(osh
, pkt
, firstread
);
6268 PKTALIGN(osh
, pkt
, rdlen
, DHD_SDALIGN
);
6270 /* Read the remaining frame data */
6271 sdret
= dhd_bcmsdh_recv_buf(bus
, bcmsdh_cur_sbwad(sdh
), SDIO_FUNC_2
, F2SYNC
,
6272 ((uint8
*)PKTDATA(osh
, pkt
)), rdlen
, pkt
, NULL
, NULL
);
6274 ASSERT(sdret
!= BCME_PENDING
);
6277 DHD_ERROR(("%s: read %d %s bytes failed: %d\n", __FUNCTION__
, rdlen
,
6278 ((chan
== SDPCM_EVENT_CHANNEL
) ? "event" :
6279 ((chan
== SDPCM_DATA_CHANNEL
) ? "data" : "test")), sdret
));
6280 dhd_os_sdlock_rxq(bus
->dhd
);
6281 PKTFREE(bus
->dhd
->osh
, pkt
, FALSE
);
6282 dhd_os_sdunlock_rxq(bus
->dhd
);
6283 bus
->dhd
->rx_errors
++;
6284 dhdsdio_rxfail(bus
, TRUE
, RETRYCHAN(chan
));
6288 /* Copy the already-read portion */
6289 PKTPUSH(osh
, pkt
, firstread
);
6290 bcopy(bus
->rxhdr
, PKTDATA(osh
, pkt
), firstread
);
6293 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
6294 prhex("Rx Data", PKTDATA(osh
, pkt
), len
);
6299 /* Save superframe descriptor and allocate packet frame */
6300 if (chan
== SDPCM_GLOM_CHANNEL
) {
6301 if (SDPCM_GLOMDESC(&bus
->rxhdr
[SDPCM_FRAMETAG_LEN
])) {
6302 DHD_GLOM(("%s: got glom descriptor, %d bytes:\n",
6303 __FUNCTION__
, len
));
6305 if (DHD_GLOM_ON()) {
6306 prhex("Glom Data", PKTDATA(osh
, pkt
), len
);
6309 PKTSETLEN(osh
, pkt
, len
);
6310 ASSERT(doff
== SDPCM_HDRLEN
);
6311 PKTPULL(osh
, pkt
, SDPCM_HDRLEN
);
6314 DHD_ERROR(("%s: glom superframe w/o descriptor!\n", __FUNCTION__
));
6315 dhdsdio_rxfail(bus
, FALSE
, FALSE
);
6320 /* Fill in packet len and prio, deliver upward */
6321 PKTSETLEN(osh
, pkt
, len
);
6322 PKTPULL(osh
, pkt
, doff
);
6325 /* Test channel packets are processed separately */
6326 if (chan
== SDPCM_TEST_CHANNEL
) {
6327 dhdsdio_testrcv(bus
, pkt
, seq
);
6332 if (PKTLEN(osh
, pkt
) == 0) {
6333 dhd_os_sdlock_rxq(bus
->dhd
);
6334 PKTFREE(bus
->dhd
->osh
, pkt
, FALSE
);
6335 dhd_os_sdunlock_rxq(bus
->dhd
);
6337 } else if (dhd_prot_hdrpull(bus
->dhd
, &ifidx
, pkt
, reorder_info_buf
,
6338 &reorder_info_len
) != 0) {
6339 DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__
));
6340 dhd_os_sdlock_rxq(bus
->dhd
);
6341 PKTFREE(bus
->dhd
->osh
, pkt
, FALSE
);
6342 dhd_os_sdunlock_rxq(bus
->dhd
);
6343 bus
->dhd
->rx_errors
++;
6347 if (reorder_info_len
) {
6348 /* Reordering info from the firmware */
6349 dhd_process_pkt_reorder_info(bus
->dhd
, reorder_info_buf
, reorder_info_len
,
6357 /* Unlock during rx call */
6358 dhd_os_sdunlock(bus
->dhd
);
6359 dhd_rx_frame(bus
->dhd
, ifidx
, pkt
, pkt_count
, chan
);
6360 dhd_os_sdlock(bus
->dhd
);
6362 rxcount
= maxframes
- rxleft
;
6364 /* Message if we hit the limit */
6365 if (!rxleft
&& !sdtest
)
6366 DHD_DATA(("%s: hit rx limit of %d frames\n", __FUNCTION__
, maxframes
));
6368 #endif /* DHD_DEBUG */
6369 DHD_DATA(("%s: processed %d frames\n", __FUNCTION__
, rxcount
));
6370 /* Back off rxseq if awaiting rtx, update rx_seq */
6373 bus
->rx_seq
= rxseq
;
6375 if (bus
->reqbussleep
)
6377 dhdsdio_bussleep(bus
, TRUE
);
6378 bus
->reqbussleep
= FALSE
;
6380 bus
->readframes
= FALSE
;
6386 dhdsdio_hostmail(dhd_bus_t
*bus
, uint32
*hmbd
)
6388 sdpcmd_regs_t
*regs
= bus
->regs
;
6389 uint32 intstatus
= 0;
6394 DHD_TRACE(("%s: Enter\n", __FUNCTION__
));
6396 /* Read mailbox data and ack that we did so */
6397 R_SDREG(hmb_data
, ®s
->tohostmailboxdata
, retries
);
6398 if (retries
<= retry_limit
)
6399 W_SDREG(SMB_INT_ACK
, ®s
->tosbmailbox
, retries
);
6400 bus
->f1regdata
+= 2;
6402 /* Dongle recomposed rx frames, accept them again */
6403 if (hmb_data
& HMB_DATA_NAKHANDLED
) {
6404 DHD_INFO(("Dongle reports NAK handled, expect rtx of %d\n", bus
->rx_seq
));
6406 DHD_ERROR(("%s: unexpected NAKHANDLED!\n", __FUNCTION__
));
6408 bus
->rxskip
= FALSE
;
6409 intstatus
|= FRAME_AVAIL_MASK(bus
);
6413 * DEVREADY does not occur with gSPI.
6415 if (hmb_data
& (HMB_DATA_DEVREADY
| HMB_DATA_FWREADY
)) {
6416 bus
->sdpcm_ver
= (hmb_data
& HMB_DATA_VERSION_MASK
) >> HMB_DATA_VERSION_SHIFT
;
6417 if (bus
->sdpcm_ver
!= SDPCM_PROT_VERSION
)
6418 DHD_ERROR(("Version mismatch, dongle reports %d, expecting %d\n",
6419 bus
->sdpcm_ver
, SDPCM_PROT_VERSION
));
6421 DHD_INFO(("Dongle ready, protocol version %d\n", bus
->sdpcm_ver
));
6423 /* make sure for the SDIO_DEVICE_RXDATAINT_MODE_1 corecontrol is proper */
6424 if ((bus
->sih
->buscoretype
== SDIOD_CORE_ID
) && (bus
->sdpcmrev
>= 4) &&
6425 (bus
->rxint_mode
== SDIO_DEVICE_RXDATAINT_MODE_1
)) {
6428 val
= R_REG(bus
->dhd
->osh
, &bus
->regs
->corecontrol
);
6429 val
&= ~CC_XMTDATAAVAIL_MODE
;
6430 val
|= CC_XMTDATAAVAIL_CTRL
;
6431 W_REG(bus
->dhd
->osh
, &bus
->regs
->corecontrol
, val
);
6433 val
= R_REG(bus
->dhd
->osh
, &bus
->regs
->corecontrol
);
6438 /* Retrieve console state address now that firmware should have updated it */
6440 sdpcm_shared_t shared
;
6441 if (dhdsdio_readshared(bus
, &shared
) == 0)
6442 bus
->console_addr
= shared
.console_addr
;
6444 #endif /* DHD_DEBUG */
6448 * Flow Control has been moved into the RX headers and this out of band
6449 * method isn't used any more. Leave this here for possibly remaining backward
6450 * compatible with older dongles
6452 if (hmb_data
& HMB_DATA_FC
) {
6453 fcbits
= (hmb_data
& HMB_DATA_FCDATA_MASK
) >> HMB_DATA_FCDATA_SHIFT
;
6455 if (fcbits
& ~bus
->flowcontrol
)
6457 if (bus
->flowcontrol
& ~fcbits
)
6461 bus
->flowcontrol
= fcbits
;
6464 /* At least print a message if FW halted */
6465 if (hmb_data
& HMB_DATA_FWHALT
) {
6466 DHD_ERROR(("INTERNAL ERROR: FIRMWARE HALTED : set BUS DOWN\n"));
6467 dhdsdio_checkdied(bus
, NULL
, 0);
6468 bus
->dhd
->busstate
= DHD_BUS_DOWN
;
6471 /* Shouldn't be any others */
6472 if (hmb_data
& ~(HMB_DATA_DEVREADY
|
6474 HMB_DATA_NAKHANDLED
|
6477 HMB_DATA_FCDATA_MASK
|
6478 HMB_DATA_VERSION_MASK
)) {
6479 DHD_ERROR(("Unknown mailbox data content: 0x%02x\n", hmb_data
));
6490 dhdsdio_dpc(dhd_bus_t
*bus
)
6492 bcmsdh_info_t
*sdh
= bus
->sdh
;
6493 sdpcmd_regs_t
*regs
= bus
->regs
;
6494 uint32 intstatus
, newstatus
= 0;
6496 uint rxlimit
= dhd_rxbound
; /* Rx frames to read before resched */
6497 uint txlimit
= dhd_txbound
; /* Tx frames to send before resched */
6498 uint framecnt
= 0; /* Temporary counter of tx/rx frames */
6499 bool rxdone
= TRUE
; /* Flag for no more read data */
6500 bool resched
= FALSE
; /* Flag indicating resched wanted */
6501 unsigned long flags
;
6502 #ifdef DEBUG_DPC_THREAD_WATCHDOG
6503 bool is_resched_by_readframe
= FALSE
;
6504 #endif /* DEBUG_DPC_THREAD_WATCHDOG */
6505 DHD_TRACE(("%s: Enter\n", __FUNCTION__
));
6507 dhd_os_sdlock(bus
->dhd
);
6508 DHD_LINUX_GENERAL_LOCK(bus
->dhd
, flags
);
6509 if (bus
->dhd
->busstate
== DHD_BUS_DOWN
) {
6510 DHD_ERROR(("%s: Bus down, ret\n", __FUNCTION__
));
6512 DHD_LINUX_GENERAL_UNLOCK(bus
->dhd
, flags
);
6513 dhd_os_sdunlock(bus
->dhd
);
6517 DHD_BUS_BUSY_SET_IN_DPC(bus
->dhd
);
6518 DHD_LINUX_GENERAL_UNLOCK(bus
->dhd
, flags
);
6520 /* Start with leftover status bits */
6521 intstatus
= bus
->intstatus
;
6523 if (!SLPAUTO_ENAB(bus
) && !KSO_ENAB(bus
)) {
6524 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__
));
6528 /* If waiting for HTAVAIL, check status */
6529 if (!SLPAUTO_ENAB(bus
) && (bus
->clkstate
== CLK_PENDING
)) {
6531 uint8 clkctl
, devctl
= 0;
6534 /* Check for inconsistent device control */
6535 devctl
= bcmsdh_cfg_read(sdh
, SDIO_FUNC_1
, SBSDIO_DEVICE_CTL
, &err
);
6537 DHD_ERROR(("%s: error reading DEVCTL: %d\n", __FUNCTION__
, err
));
6538 bus
->dhd
->busstate
= DHD_BUS_DOWN
;
6540 ASSERT(devctl
& SBSDIO_DEVCTL_CA_INT_ONLY
);
6542 #endif /* DHD_DEBUG */
6544 /* Read CSR, if clock on switch to AVAIL, else ignore */
6545 clkctl
= bcmsdh_cfg_read(sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_CHIPCLKCSR
, &err
);
6547 DHD_ERROR(("%s: error reading CSR: %d\n", __FUNCTION__
, err
));
6548 bus
->dhd
->busstate
= DHD_BUS_DOWN
;
6551 DHD_INFO(("DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n", devctl
, clkctl
));
6553 if (SBSDIO_HTAV(clkctl
)) {
6554 devctl
= bcmsdh_cfg_read(sdh
, SDIO_FUNC_1
, SBSDIO_DEVICE_CTL
, &err
);
6556 DHD_ERROR(("%s: error reading DEVCTL: %d\n",
6557 __FUNCTION__
, err
));
6558 bus
->dhd
->busstate
= DHD_BUS_DOWN
;
6560 devctl
&= ~SBSDIO_DEVCTL_CA_INT_ONLY
;
6561 bcmsdh_cfg_write(sdh
, SDIO_FUNC_1
, SBSDIO_DEVICE_CTL
, devctl
, &err
);
6563 DHD_ERROR(("%s: error writing DEVCTL: %d\n",
6564 __FUNCTION__
, err
));
6565 bus
->dhd
->busstate
= DHD_BUS_DOWN
;
6567 bus
->clkstate
= CLK_AVAIL
;
6575 /* Make sure backplane clock is on */
6576 dhdsdio_clkctl(bus
, CLK_AVAIL
, TRUE
);
6577 if (bus
->clkstate
!= CLK_AVAIL
)
6580 /* Pending interrupt indicates new device status */
6583 #if defined(BT_OVER_SDIO)
6584 bcmsdh_btsdio_process_f3_intr();
6585 #endif /* defined (BT_OVER_SDIO) */
6587 R_SDREG(newstatus
, ®s
->intstatus
, retries
);
6589 if (bcmsdh_regfail(bus
->sdh
))
6591 newstatus
&= bus
->hostintmask
;
6592 bus
->fcstate
= !!(newstatus
& I_HMB_FC_STATE
);
6596 if ((bus
->rxint_mode
== SDIO_DEVICE_RXDATAINT_MODE_0
) &&
6597 (newstatus
== I_XMTDATA_AVAIL
)) {
6600 W_SDREG(newstatus
, ®s
->intstatus
, retries
);
6604 /* Merge new bits with previous */
6605 intstatus
|= newstatus
;
6608 /* Handle flow-control change: read new state in case our ack
6609 * crossed another change interrupt. If change still set, assume
6610 * FC ON for safety, let next loop through do the debounce.
6612 if (intstatus
& I_HMB_FC_CHANGE
) {
6613 intstatus
&= ~I_HMB_FC_CHANGE
;
6614 W_SDREG(I_HMB_FC_CHANGE
, ®s
->intstatus
, retries
);
6615 R_SDREG(newstatus
, ®s
->intstatus
, retries
);
6616 bus
->f1regdata
+= 2;
6617 bus
->fcstate
= !!(newstatus
& (I_HMB_FC_STATE
| I_HMB_FC_CHANGE
));
6618 intstatus
|= (newstatus
& bus
->hostintmask
);
6621 /* Handle host mailbox indication */
6622 if (intstatus
& I_HMB_HOST_INT
) {
6625 intstatus
&= ~I_HMB_HOST_INT
;
6626 intstatus
|= dhdsdio_hostmail(bus
, &hmbdata
);
6629 /* ULP prototyping. Redowload fw on oob interupt */
6631 /* all the writes after this point CAN use cached sbwad value */
6632 bcmsdh_force_sbwad_calc(bus
->sdh
, FALSE
);
6634 if (dhd_ulp_pre_redownload_check(bus
->dhd
, bus
->sdh
, hmbdata
)) {
6635 if (dhd_bus_ulp_reinit_fw(bus
) < 0) {
6636 DHD_ERROR(("%s:%d FW redownload failed\n",
6637 __FUNCTION__
, __LINE__
));
6645 #ifdef DHD_UCODE_DOWNLOAD
6647 #endif /* DHD_UCODE_DOWNLOAD */
6649 /* Just being here means nothing more to do for chipactive */
6650 if (intstatus
& I_CHIPACTIVE
) {
6651 /* ASSERT(bus->clkstate == CLK_AVAIL); */
6652 intstatus
&= ~I_CHIPACTIVE
;
6655 /* Handle host mailbox indication */
6656 if (intstatus
& I_HMB_HOST_INT
) {
6657 intstatus
&= ~I_HMB_HOST_INT
;
6658 intstatus
|= dhdsdio_hostmail(bus
, NULL
);
6661 /* Generally don't ask for these, can get CRC errors... */
6662 if (intstatus
& I_WR_OOSYNC
) {
6663 DHD_ERROR(("Dongle reports WR_OOSYNC\n"));
6664 intstatus
&= ~I_WR_OOSYNC
;
6667 if (intstatus
& I_RD_OOSYNC
) {
6668 DHD_ERROR(("Dongle reports RD_OOSYNC\n"));
6669 intstatus
&= ~I_RD_OOSYNC
;
6672 if (intstatus
& I_SBINT
) {
6673 DHD_ERROR(("Dongle reports SBINT\n"));
6674 intstatus
&= ~I_SBINT
;
6677 /* Would be active due to wake-wlan in gSPI */
6678 if (intstatus
& I_CHIPACTIVE
) {
6679 DHD_INFO(("Dongle reports CHIPACTIVE\n"));
6680 intstatus
&= ~I_CHIPACTIVE
;
6683 if (intstatus
& I_HMB_FC_STATE
) {
6684 DHD_INFO(("Dongle reports HMB_FC_STATE\n"));
6685 intstatus
&= ~I_HMB_FC_STATE
;
6688 /* Ignore frame indications if rxskip is set */
6690 intstatus
&= ~FRAME_AVAIL_MASK(bus
);
6693 /* On frame indication, read available frames */
6694 if (PKT_AVAILABLE(bus
, intstatus
)) {
6696 framecnt
= dhdsdio_readframes(bus
, rxlimit
, &rxdone
);
6697 if (rxdone
|| bus
->rxskip
)
6698 intstatus
&= ~FRAME_AVAIL_MASK(bus
);
6699 rxlimit
-= MIN(framecnt
, rxlimit
);
6702 /* Keep still-pending events for next scheduling */
6703 bus
->intstatus
= intstatus
;
6706 /* Re-enable interrupts to detect new device events (mailbox, rx frame)
6707 * or clock availability. (Allows tx loop to check ipend if desired.)
6708 * (Unless register access seems hosed, as we may not be able to ACK...)
6710 if (bus
->intr
&& bus
->intdis
&& !bcmsdh_regfail(sdh
)) {
6711 DHD_INTR(("%s: enable SDIO interrupts, rxdone %d framecnt %d\n",
6712 __FUNCTION__
, rxdone
, framecnt
));
6713 bus
->intdis
= FALSE
;
6714 #if defined(OOB_INTR_ONLY)
6715 bcmsdh_oob_intr_set(bus
->sdh
, TRUE
);
6716 #endif /* defined(OOB_INTR_ONLY) */
6717 bcmsdh_intr_enable(sdh
);
6718 #ifdef BCMSPI_ANDROID
6719 if (*dhd_spi_lockcount
== 0)
6720 bcmsdh_oob_intr_set(bus
->sdh
, TRUE
);
6721 #endif /* BCMSPI_ANDROID */
6724 #if defined(OOB_INTR_ONLY) && !defined(HW_OOB)
6725 /* In case of SW-OOB(using edge trigger),
6726 * Check interrupt status in the dongle again after enable irq on the host.
6727 * and rechedule dpc if interrupt is pended in the dongle.
6728 * There is a chance to miss OOB interrupt while irq is disabled on the host.
6729 * No need to do this with HW-OOB(level trigger)
6731 R_SDREG(newstatus
, ®s
->intstatus
, retries
);
6732 if (bcmsdh_regfail(bus
->sdh
))
6734 if (newstatus
& bus
->hostintmask
) {
6738 #endif /* defined(OOB_INTR_ONLY) && !defined(HW_OOB) */
6740 #ifdef PROP_TXSTATUS
6741 dhd_wlfc_commit_packets(bus
->dhd
, (f_commitpkt_t
)dhd_bus_txdata
, (void *)bus
, NULL
, FALSE
);
6744 if (TXCTLOK(bus
) && bus
->ctrl_frame_stat
&& (bus
->clkstate
== CLK_AVAIL
))
6745 dhdsdio_sendpendctl(bus
);
6747 /* Send queued frames (limit 1 if rx may still be pending) */
6748 else if ((bus
->clkstate
== CLK_AVAIL
) && !bus
->fcstate
&&
6749 pktq_mlen(&bus
->txq
, ~bus
->flowcontrol
) && txlimit
&& DATAOK(bus
)) {
6752 if (dhd_ulp_f2_ready(bus
->dhd
, bus
->sdh
)) {
6753 #endif /* DHD_ULP */
6754 framecnt
= rxdone
? txlimit
: MIN(txlimit
, dhd_txminmax
);
6755 framecnt
= dhdsdio_sendfromq(bus
, framecnt
);
6756 txlimit
-= framecnt
;
6759 /* In other transient states like DHD_ULP_, after the states are
6760 * DHD_ULP_F2ENAB_CLEARING and DHD_ULP_F2ENAB_SETTING,
6761 * dpc is scheduled after steady-state and dhdsdio_sendfromq() will
6765 #endif /* DHD_ULP */
6767 /* Resched the DPC if ctrl cmd is pending on bus credit */
6768 if (bus
->ctrl_frame_stat
)
6771 /* Resched if events or tx frames are pending, else await next interrupt */
6772 /* On failed register access, all bets are off: no resched or interrupts */
6773 if ((bus
->dhd
->busstate
== DHD_BUS_DOWN
) || bcmsdh_regfail(sdh
)) {
6774 if ((bus
->sih
&& bus
->sih
->buscorerev
>= 12) && !(dhdsdio_sleepcsr_get(bus
) &
6775 SBSDIO_FUNC1_SLEEPCSR_KSO_MASK
)) {
6776 /* Bus failed because of KSO */
6777 DHD_ERROR(("%s: Bus failed due to KSO\n", __FUNCTION__
));
6780 DHD_ERROR(("%s: failed backplane access over SDIO, halting operation\n",
6782 bus
->dhd
->busstate
= DHD_BUS_DOWN
;
6785 } else if (bus
->clkstate
== CLK_PENDING
) {
6786 /* Awaiting I_CHIPACTIVE; don't resched */
6787 } else if (bus
->intstatus
|| bus
->ipend
||
6788 (!bus
->fcstate
&& pktq_mlen(&bus
->txq
, ~bus
->flowcontrol
) && DATAOK(bus
)) ||
6789 PKT_AVAILABLE(bus
, bus
->intstatus
)) { /* Read multiple frames */
6793 bus
->dpc_sched
= resched
;
6795 /* If we're done for now, turn off clock request. */
6796 if ((bus
->idletime
== DHD_IDLE_IMMEDIATE
) && (bus
->clkstate
!= CLK_PENDING
) &&
6797 NO_OTHER_ACTIVE_BUS_USER(bus
)) {
6798 bus
->activity
= FALSE
;
6799 dhdsdio_bussleep(bus
, TRUE
);
6800 dhdsdio_clkctl(bus
, CLK_NONE
, FALSE
);
6805 if (!resched
&& dhd_dpcpoll
) {
6806 if (dhdsdio_readframes(bus
, dhd_rxbound
, &rxdone
) != 0) {
6808 #ifdef DEBUG_DPC_THREAD_WATCHDOG
6809 is_resched_by_readframe
= TRUE
;
6810 #endif /* DEBUG_DPC_THREAD_WATCHDOG */
6814 dhd_os_sdunlock(bus
->dhd
);
6815 #ifdef DEBUG_DPC_THREAD_WATCHDOG
6816 if (bus
->dhd
->dhd_bug_on
) {
6817 DHD_INFO(("%s: resched = %d ctrl_frame_stat = %d intstatus 0x%08x"
6818 " ipend = %d pktq_mlen = %d is_resched_by_readframe = %d \n",
6819 __FUNCTION__
, resched
, bus
->ctrl_frame_stat
,
6820 bus
->intstatus
, bus
->ipend
,
6821 pktq_mlen(&bus
->txq
, ~bus
->flowcontrol
), is_resched_by_readframe
));
6823 bus
->dhd
->dhd_bug_on
= FALSE
;
6825 #endif /* DEBUG_DPC_THREAD_WATCHDOG */
6827 DHD_LINUX_GENERAL_LOCK(bus
->dhd
, flags
);
6828 DHD_BUS_BUSY_CLEAR_IN_DPC(bus
->dhd
);
6829 dhd_os_busbusy_wake(bus
->dhd
);
6830 DHD_LINUX_GENERAL_UNLOCK(bus
->dhd
, flags
);
6836 dhd_bus_dpc(struct dhd_bus
*bus
)
6840 /* Call the DPC directly. */
6841 DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__
));
6842 resched
= dhdsdio_dpc(bus
);
6848 dhdsdio_isr(void *arg
)
6850 dhd_bus_t
*bus
= (dhd_bus_t
*)arg
;
6853 DHD_TRACE(("%s: Enter\n", __FUNCTION__
));
6856 DHD_ERROR(("%s : bus is null pointer , exit \n", __FUNCTION__
));
6861 if (bus
->dhd
->busstate
== DHD_BUS_DOWN
) {
6862 DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__
));
6866 DHD_TRACE(("%s: Enter\n", __FUNCTION__
));
6868 /* Count the interrupt call */
6872 /* Shouldn't get this interrupt if we're sleeping? */
6873 if (!SLPAUTO_ENAB(bus
)) {
6874 if (bus
->sleeping
) {
6875 DHD_ERROR(("INTERRUPT WHILE SLEEPING??\n"));
6877 } else if (!KSO_ENAB(bus
)) {
6878 DHD_ERROR(("ISR in devsleep 1\n"));
6882 /* Disable additional interrupts (is this needed now)? */
6884 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__
));
6886 DHD_ERROR(("dhdsdio_isr() w/o interrupt configured!\n"));
6889 #ifdef BCMSPI_ANDROID
6890 bcmsdh_oob_intr_set(bus
->sdh
, FALSE
);
6891 #endif /* BCMSPI_ANDROID */
6892 bcmsdh_intr_disable(sdh
);
6895 #if defined(SDIO_ISR_THREAD)
6896 DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__
));
6897 DHD_OS_WAKE_LOCK(bus
->dhd
);
6899 DHD_OS_WAKE_UNLOCK(bus
->dhd
);
6901 bus
->dpc_sched
= TRUE
;
6902 dhd_sched_dpc(bus
->dhd
);
6903 #endif /* defined(SDIO_ISR_THREAD) */
6909 dhdsdio_pktgen_init(dhd_bus_t
*bus
)
6911 /* Default to specified length, or full range */
6912 if (dhd_pktgen_len
) {
6913 bus
->pktgen_maxlen
= MIN(dhd_pktgen_len
, MAX_PKTGEN_LEN
);
6914 bus
->pktgen_minlen
= bus
->pktgen_maxlen
;
6916 bus
->pktgen_maxlen
= MAX_PKTGEN_LEN
;
6917 bus
->pktgen_minlen
= 0;
6919 bus
->pktgen_len
= (uint16
)bus
->pktgen_minlen
;
6921 /* Default to per-watchdog burst with 10s print time */
6922 bus
->pktgen_freq
= 1;
6923 bus
->pktgen_print
= dhd_watchdog_ms
? (10000 / dhd_watchdog_ms
) : 0;
6924 bus
->pktgen_count
= (dhd_pktgen
* dhd_watchdog_ms
+ 999) / 1000;
6926 /* Default to echo mode */
6927 bus
->pktgen_mode
= DHD_PKTGEN_ECHO
;
6928 bus
->pktgen_stop
= 1;
6932 dhdsdio_pktgen(dhd_bus_t
*bus
)
6938 osl_t
*osh
= bus
->dhd
->osh
;
6944 /* Display current count if appropriate */
6945 if (bus
->pktgen_print
&& (++bus
->pktgen_ptick
>= bus
->pktgen_print
)) {
6946 bus
->pktgen_ptick
= 0;
6947 printf("%s: send attempts %d, rcvd %d, errors %d\n",
6948 __FUNCTION__
, bus
->pktgen_sent
, bus
->pktgen_rcvd
, bus
->pktgen_fail
);
6950 /* Print throughput stats only for constant length packet runs */
6951 if (bus
->pktgen_minlen
== bus
->pktgen_maxlen
) {
6952 time_lapse
= jiffies
- bus
->pktgen_prev_time
;
6953 bus
->pktgen_prev_time
= jiffies
;
6954 sent_pkts
= bus
->pktgen_sent
- bus
->pktgen_prev_sent
;
6955 bus
->pktgen_prev_sent
= bus
->pktgen_sent
;
6956 rcvd_pkts
= bus
->pktgen_rcvd
- bus
->pktgen_prev_rcvd
;
6957 bus
->pktgen_prev_rcvd
= bus
->pktgen_rcvd
;
6959 printf("%s: Tx Throughput %d kbps, Rx Throughput %d kbps\n",
6961 (sent_pkts
* bus
->pktgen_len
/ jiffies_to_msecs(time_lapse
)) * 8,
6962 (rcvd_pkts
* bus
->pktgen_len
/ jiffies_to_msecs(time_lapse
)) * 8);
6966 /* For recv mode, just make sure dongle has started sending */
6967 if (bus
->pktgen_mode
== DHD_PKTGEN_RECV
) {
6968 if (bus
->pktgen_rcv_state
== PKTGEN_RCV_IDLE
) {
6969 bus
->pktgen_rcv_state
= PKTGEN_RCV_ONGOING
;
6970 dhdsdio_sdtest_set(bus
, bus
->pktgen_total
);
6975 /* Otherwise, generate or request the specified number of packets */
6976 for (pktcount
= 0; pktcount
< bus
->pktgen_count
; pktcount
++) {
6977 /* Stop if total has been reached */
6978 if (bus
->pktgen_total
&& (bus
->pktgen_sent
>= bus
->pktgen_total
)) {
6979 bus
->pktgen_count
= 0;
6983 /* Allocate an appropriate-sized packet */
6984 if (bus
->pktgen_mode
== DHD_PKTGEN_RXBURST
) {
6985 len
= SDPCM_TEST_PKT_CNT_FLD_LEN
;
6987 len
= bus
->pktgen_len
;
6989 if (!(pkt
= PKTGET(osh
, (len
+ SDPCM_HDRLEN
+ SDPCM_TEST_HDRLEN
+ DHD_SDALIGN
),
6991 DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__
));
6994 PKTALIGN(osh
, pkt
, (len
+ SDPCM_HDRLEN
+ SDPCM_TEST_HDRLEN
), DHD_SDALIGN
);
6995 data
= (uint8
*)PKTDATA(osh
, pkt
) + SDPCM_HDRLEN
;
6997 /* Write test header cmd and extra based on mode */
6998 switch (bus
->pktgen_mode
) {
6999 case DHD_PKTGEN_ECHO
:
7000 *data
++ = SDPCM_TEST_ECHOREQ
;
7001 *data
++ = (uint8
)bus
->pktgen_sent
;
7004 case DHD_PKTGEN_SEND
:
7005 *data
++ = SDPCM_TEST_DISCARD
;
7006 *data
++ = (uint8
)bus
->pktgen_sent
;
7009 case DHD_PKTGEN_RXBURST
:
7010 *data
++ = SDPCM_TEST_BURST
;
7011 *data
++ = (uint8
)bus
->pktgen_count
; /* Just for backward compatability */
7015 DHD_ERROR(("Unrecognized pktgen mode %d\n", bus
->pktgen_mode
));
7016 PKTFREE(osh
, pkt
, TRUE
);
7017 bus
->pktgen_count
= 0;
7021 /* Write test header length field */
7022 *data
++ = (bus
->pktgen_len
>> 0);
7023 *data
++ = (bus
->pktgen_len
>> 8);
7025 /* Write frame count in a 4 byte field adjucent to SDPCM test header for
7028 if (bus
->pktgen_mode
== DHD_PKTGEN_RXBURST
) {
7029 *data
++ = (uint8
)(bus
->pktgen_count
>> 0);
7030 *data
++ = (uint8
)(bus
->pktgen_count
>> 8);
7031 *data
++ = (uint8
)(bus
->pktgen_count
>> 16);
7032 *data
++ = (uint8
)(bus
->pktgen_count
>> 24);
7035 /* Then fill in the remainder -- N/A for burst */
7036 for (fillbyte
= 0; fillbyte
< len
; fillbyte
++)
7037 *data
++ = SDPCM_TEST_FILL(fillbyte
, (uint8
)bus
->pktgen_sent
);
7041 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
7042 data
= (uint8
*)PKTDATA(osh
, pkt
) + SDPCM_HDRLEN
;
7043 prhex("dhdsdio_pktgen: Tx Data", data
, PKTLEN(osh
, pkt
) - SDPCM_HDRLEN
);
7048 if (dhdsdio_txpkt(bus
, SDPCM_TEST_CHANNEL
, &pkt
, 1, TRUE
) != BCME_OK
) {
7050 if (bus
->pktgen_stop
&& bus
->pktgen_stop
== bus
->pktgen_fail
)
7051 bus
->pktgen_count
= 0;
7055 /* Bump length if not fixed, wrap at max */
7056 if (++bus
->pktgen_len
> bus
->pktgen_maxlen
)
7057 bus
->pktgen_len
= (uint16
)bus
->pktgen_minlen
;
7059 /* Special case for burst mode: just send one request! */
7060 if (bus
->pktgen_mode
== DHD_PKTGEN_RXBURST
)
7066 dhdsdio_sdtest_set(dhd_bus_t
*bus
, uint count
)
7070 osl_t
*osh
= bus
->dhd
->osh
;
7072 /* Allocate the packet */
7073 if (!(pkt
= PKTGET(osh
, SDPCM_HDRLEN
+ SDPCM_TEST_HDRLEN
+
7074 SDPCM_TEST_PKT_CNT_FLD_LEN
+ DHD_SDALIGN
, TRUE
))) {
7075 DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__
));
7078 PKTALIGN(osh
, pkt
, (SDPCM_HDRLEN
+ SDPCM_TEST_HDRLEN
+
7079 SDPCM_TEST_PKT_CNT_FLD_LEN
), DHD_SDALIGN
);
7080 data
= (uint8
*)PKTDATA(osh
, pkt
) + SDPCM_HDRLEN
;
7082 /* Fill in the test header */
7083 *data
++ = SDPCM_TEST_SEND
;
7084 *data
++ = (count
> 0)?TRUE
:FALSE
;
7085 *data
++ = (bus
->pktgen_maxlen
>> 0);
7086 *data
++ = (bus
->pktgen_maxlen
>> 8);
7087 *data
++ = (uint8
)(count
>> 0);
7088 *data
++ = (uint8
)(count
>> 8);
7089 *data
++ = (uint8
)(count
>> 16);
7090 *data
++ = (uint8
)(count
>> 24);
7093 if (dhdsdio_txpkt(bus
, SDPCM_TEST_CHANNEL
, &pkt
, 1, TRUE
) != BCME_OK
)
7098 dhdsdio_testrcv(dhd_bus_t
*bus
, void *pkt
, uint seq
)
7100 osl_t
*osh
= bus
->dhd
->osh
;
7109 /* Check for min length */
7110 if ((pktlen
= PKTLEN(osh
, pkt
)) < SDPCM_TEST_HDRLEN
) {
7111 DHD_ERROR(("dhdsdio_restrcv: toss runt frame, pktlen %d\n", pktlen
));
7112 PKTFREE(osh
, pkt
, FALSE
);
7116 /* Extract header fields */
7117 data
= PKTDATA(osh
, pkt
);
7120 len
= *data
++; len
+= *data
++ << 8;
7121 DHD_TRACE(("%s:cmd:%d, xtra:%d,len:%d\n", __FUNCTION__
, cmd
, extra
, len
));
7122 /* Check length for relevant commands */
7123 if (cmd
== SDPCM_TEST_DISCARD
|| cmd
== SDPCM_TEST_ECHOREQ
|| cmd
== SDPCM_TEST_ECHORSP
) {
7124 if (pktlen
!= len
+ SDPCM_TEST_HDRLEN
) {
7125 DHD_ERROR(("dhdsdio_testrcv: frame length mismatch, pktlen %d seq %d"
7126 " cmd %d extra %d len %d\n", pktlen
, seq
, cmd
, extra
, len
));
7127 PKTFREE(osh
, pkt
, FALSE
);
7132 /* Process as per command */
7134 case SDPCM_TEST_ECHOREQ
:
7135 /* Rx->Tx turnaround ok (even on NDIS w/current implementation) */
7136 *(uint8
*)(PKTDATA(osh
, pkt
)) = SDPCM_TEST_ECHORSP
;
7137 if (dhdsdio_txpkt(bus
, SDPCM_TEST_CHANNEL
, &pkt
, 1, TRUE
) == BCME_OK
) {
7141 PKTFREE(osh
, pkt
, FALSE
);
7146 case SDPCM_TEST_ECHORSP
:
7147 if (bus
->ext_loop
) {
7148 PKTFREE(osh
, pkt
, FALSE
);
7153 for (offset
= 0; offset
< len
; offset
++, data
++) {
7154 if (*data
!= SDPCM_TEST_FILL(offset
, extra
)) {
7155 DHD_ERROR(("dhdsdio_testrcv: echo data mismatch: "
7156 "offset %d (len %d) expect 0x%02x rcvd 0x%02x\n",
7157 offset
, len
, SDPCM_TEST_FILL(offset
, extra
), *data
));
7161 PKTFREE(osh
, pkt
, FALSE
);
7165 case SDPCM_TEST_DISCARD
:
7169 uint8 testval
= extra
;
7170 for (i
= 0; i
< len
; i
++) {
7171 if (*prn
!= testval
) {
7172 DHD_ERROR(("DIErr@Pkt#:%d,Ix:%d, expected:0x%x, got:0x%x\n",
7173 i
, bus
->pktgen_rcvd_rcvsession
, testval
, *prn
));
7178 PKTFREE(osh
, pkt
, FALSE
);
7182 case SDPCM_TEST_BURST
:
7183 case SDPCM_TEST_SEND
:
7185 DHD_INFO(("dhdsdio_testrcv: unsupported or unknown command, pktlen %d seq %d"
7186 " cmd %d extra %d len %d\n", pktlen
, seq
, cmd
, extra
, len
));
7187 PKTFREE(osh
, pkt
, FALSE
);
7191 /* For recv mode, stop at limit (and tell dongle to stop sending) */
7192 if (bus
->pktgen_mode
== DHD_PKTGEN_RECV
) {
7193 if (bus
->pktgen_rcv_state
!= PKTGEN_RCV_IDLE
) {
7194 bus
->pktgen_rcvd_rcvsession
++;
7196 if (bus
->pktgen_total
&&
7197 (bus
->pktgen_rcvd_rcvsession
>= bus
->pktgen_total
)) {
7198 bus
->pktgen_count
= 0;
7199 DHD_ERROR(("Pktgen:rcv test complete!\n"));
7200 bus
->pktgen_rcv_state
= PKTGEN_RCV_IDLE
;
7201 dhdsdio_sdtest_set(bus
, FALSE
);
7202 bus
->pktgen_rcvd_rcvsession
= 0;
7209 int dhd_bus_oob_intr_register(dhd_pub_t
*dhdp
)
7213 #if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
7214 err
= bcmsdh_oob_intr_register(dhdp
->bus
->sdh
, dhdsdio_isr
, dhdp
->bus
);
7219 void dhd_bus_oob_intr_unregister(dhd_pub_t
*dhdp
)
7221 #if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
7222 bcmsdh_oob_intr_unregister(dhdp
->bus
->sdh
);
7226 void dhd_bus_oob_intr_set(dhd_pub_t
*dhdp
, bool enable
)
7228 #if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
7229 bcmsdh_oob_intr_set(dhdp
->bus
->sdh
, enable
);
7233 void dhd_bus_dev_pm_stay_awake(dhd_pub_t
*dhdpub
)
7235 bcmsdh_dev_pm_stay_awake(dhdpub
->bus
->sdh
);
7238 void dhd_bus_dev_pm_relax(dhd_pub_t
*dhdpub
)
7240 bcmsdh_dev_relax(dhdpub
->bus
->sdh
);
7243 bool dhd_bus_dev_pm_enabled(dhd_pub_t
*dhdpub
)
7245 bool enabled
= FALSE
;
7247 enabled
= bcmsdh_dev_pm_enabled(dhdpub
->bus
->sdh
);
7252 dhd_bus_watchdog(dhd_pub_t
*dhdp
)
7255 unsigned long flags
;
7257 DHD_TIMER(("%s: Enter\n", __FUNCTION__
));
7261 if (bus
->dhd
->dongle_reset
)
7264 if (bus
->dhd
->hang_was_sent
) {
7265 dhd_os_wd_timer(bus
->dhd
, 0);
7269 /* Ignore the timer if simulating bus down */
7270 if (!SLPAUTO_ENAB(bus
) && bus
->sleeping
)
7273 DHD_LINUX_GENERAL_LOCK(dhdp
, flags
);
7274 if (DHD_BUS_CHECK_DOWN_OR_DOWN_IN_PROGRESS(dhdp
) ||
7275 DHD_BUS_CHECK_SUSPEND_OR_SUSPEND_IN_PROGRESS(dhdp
)) {
7276 DHD_LINUX_GENERAL_UNLOCK(dhdp
, flags
);
7279 DHD_BUS_BUSY_SET_IN_WD(dhdp
);
7280 DHD_LINUX_GENERAL_UNLOCK(dhdp
, flags
);
7282 dhd_os_sdlock(bus
->dhd
);
7284 /* Poll period: check device if appropriate. */
7285 if (!SLPAUTO_ENAB(bus
) && (bus
->poll
&& (++bus
->polltick
>= bus
->pollrate
))) {
7286 uint32 intstatus
= 0;
7288 /* Reset poll tick */
7291 /* Check device if no interrupts */
7292 if (!bus
->intr
|| (bus
->intrcount
== bus
->lastintrs
)) {
7295 if (!bus
->dpc_sched
) {
7297 devpend
= bcmsdh_cfg_read(bus
->sdh
, SDIO_FUNC_0
,
7298 SDIOD_CCCR_INTPEND
, NULL
);
7299 intstatus
= devpend
& (INTR_STATUS_FUNC1
| INTR_STATUS_FUNC2
);
7302 if (!bus
->dpc_sched
) {
7304 devpend
= bcmsdh_cfg_read_word(bus
->sdh
, SDIO_FUNC_0
,
7305 SPID_STATUS_REG
, NULL
);
7306 intstatus
= devpend
& STATUS_F2_PKT_AVAILABLE
;
7308 #endif /* !BCMSPI */
7310 /* If there is something, make like the ISR and schedule the DPC */
7315 bcmsdh_intr_disable(bus
->sdh
);
7317 bus
->dpc_sched
= TRUE
;
7318 dhd_sched_dpc(bus
->dhd
);
7322 /* Update interrupt tracking */
7323 bus
->lastintrs
= bus
->intrcount
;
7327 /* Poll for console output periodically */
7328 if (dhdp
->busstate
== DHD_BUS_DATA
&& dhdp
->dhd_console_ms
!= 0) {
7329 bus
->console
.count
+= dhd_watchdog_ms
;
7330 if (bus
->console
.count
>= dhdp
->dhd_console_ms
) {
7331 bus
->console
.count
-= dhdp
->dhd_console_ms
;
7332 /* Make sure backplane clock is on */
7333 if (SLPAUTO_ENAB(bus
))
7334 dhdsdio_bussleep(bus
, FALSE
);
7336 dhdsdio_clkctl(bus
, CLK_AVAIL
, FALSE
);
7337 if (dhdsdio_readconsole(bus
) < 0)
7338 dhdp
->dhd_console_ms
= 0; /* On error, stop trying */
7341 #endif /* DHD_DEBUG */
7344 /* Generate packets if configured */
7345 if (bus
->pktgen_count
&& (++bus
->pktgen_tick
>= bus
->pktgen_freq
)) {
7346 /* Make sure backplane clock is on */
7347 if (SLPAUTO_ENAB(bus
))
7348 dhdsdio_bussleep(bus
, FALSE
);
7350 dhdsdio_clkctl(bus
, CLK_AVAIL
, FALSE
);
7351 bus
->pktgen_tick
= 0;
7352 dhdsdio_pktgen(bus
);
7356 /* On idle timeout clear activity flag and/or turn off clock */
7357 #ifdef DHD_USE_IDLECOUNT
7359 bus
->activity
= FALSE
;
7364 * If the condition to switch off the clock is reached And if
7365 * BT is inactive (in case of BT_OVER_SDIO build) turn off clk.
7367 * Consider the following case, DHD is configured with
7368 * 1) idletime == DHD_IDLE_IMMEDIATE
7369 * 2) BT is the last user of the clock
7370 * We cannot disable the clock from __dhdsdio_clk_disable
7371 * since WLAN might be using it. If WLAN is active then
7372 * from the respective function/context after doing the job
7373 * the clk is turned off.
7374 * But if WLAN is actually inactive then the watchdog should
7375 * disable the clock. So the condition check below should be
7376 * bus->idletime != 0 instead of idletime == 0
7378 if ((bus
->idletime
!= 0) && (bus
->idlecount
>= bus
->idletime
) &&
7379 NO_OTHER_ACTIVE_BUS_USER(bus
)) {
7380 DHD_TIMER(("%s: DHD Idle state!!\n", __FUNCTION__
));
7381 if (SLPAUTO_ENAB(bus
)) {
7382 if (dhdsdio_bussleep(bus
, TRUE
) != BCME_BUSY
)
7383 dhd_os_wd_timer(bus
->dhd
, 0);
7385 dhdsdio_clkctl(bus
, CLK_NONE
, FALSE
);
7391 if ((bus
->idletime
!= 0) && (bus
->clkstate
== CLK_AVAIL
) &&
7392 NO_OTHER_ACTIVE_BUS_USER(bus
)) {
7393 if (++bus
->idlecount
>= bus
->idletime
) {
7395 if (bus
->activity
) {
7396 bus
->activity
= FALSE
;
7397 if (SLPAUTO_ENAB(bus
)) {
7398 if (!bus
->readframes
)
7399 dhdsdio_bussleep(bus
, TRUE
);
7401 bus
->reqbussleep
= TRUE
;
7403 dhdsdio_clkctl(bus
, CLK_NONE
, FALSE
);
7408 #endif /* DHD_USE_IDLECOUNT */
7410 dhd_os_sdunlock(bus
->dhd
);
7412 DHD_LINUX_GENERAL_LOCK(dhdp
, flags
);
7413 DHD_BUS_BUSY_CLEAR_IN_WD(dhdp
);
7414 dhd_os_busbusy_wake(dhdp
);
7415 DHD_LINUX_GENERAL_UNLOCK(dhdp
, flags
);
7421 dhd_bus_console_in(dhd_pub_t
*dhdp
, uchar
*msg
, uint msglen
)
7423 dhd_bus_t
*bus
= dhdp
->bus
;
7428 /* Address could be zero if CONSOLE := 0 in dongle Makefile */
7429 if (bus
->console_addr
== 0)
7430 return BCME_UNSUPPORTED
;
7432 /* Exclusive bus access */
7433 dhd_os_sdlock(bus
->dhd
);
7435 /* Don't allow input if dongle is in reset */
7436 if (bus
->dhd
->dongle_reset
) {
7437 dhd_os_sdunlock(bus
->dhd
);
7438 return BCME_NOTREADY
;
7441 /* Request clock to allow SDIO accesses */
7443 /* No pend allowed since txpkt is called later, ht clk has to be on */
7444 dhdsdio_clkctl(bus
, CLK_AVAIL
, FALSE
);
7446 /* Zero cbuf_index */
7447 addr
= bus
->console_addr
+ OFFSETOF(hnd_cons_t
, cbuf_idx
);
7449 if ((rv
= dhdsdio_membytes(bus
, TRUE
, addr
, (uint8
*)&val
, sizeof(val
))) < 0)
7452 /* Write message into cbuf */
7453 addr
= bus
->console_addr
+ OFFSETOF(hnd_cons_t
, cbuf
);
7454 if ((rv
= dhdsdio_membytes(bus
, TRUE
, addr
, (uint8
*)msg
, msglen
)) < 0)
7457 /* Write length into vcons_in */
7458 addr
= bus
->console_addr
+ OFFSETOF(hnd_cons_t
, vcons_in
);
7459 val
= htol32(msglen
);
7460 if ((rv
= dhdsdio_membytes(bus
, TRUE
, addr
, (uint8
*)&val
, sizeof(val
))) < 0)
7463 /* Bump dongle by sending an empty packet on the event channel.
7464 * sdpcm_sendup (RX) checks for virtual console input.
7466 if ((pkt
= PKTGET(bus
->dhd
->osh
, 4 + SDPCM_RESERVE
, TRUE
)) != NULL
)
7467 rv
= dhdsdio_txpkt(bus
, SDPCM_EVENT_CHANNEL
, &pkt
, 1, TRUE
);
7470 if ((bus
->idletime
== DHD_IDLE_IMMEDIATE
) && !bus
->dpc_sched
&&
7471 NO_OTHER_ACTIVE_BUS_USER(bus
)) {
7472 bus
->activity
= FALSE
;
7473 dhdsdio_bussleep(bus
, TRUE
);
7474 dhdsdio_clkctl(bus
, CLK_NONE
, FALSE
);
7477 dhd_os_sdunlock(bus
->dhd
);
7482 #if defined(DHD_DEBUG) && !defined(BCMSDIOLITE)
7484 dhd_dump_cis(uint fn
, uint8
*cis
)
7486 uint byte
, tag
, tdata
;
7487 DHD_INFO(("Function %d CIS:\n", fn
));
7489 for (tdata
= byte
= 0; byte
< SBSDIO_CIS_SIZE_LIMIT
; byte
++) {
7490 if ((byte
% 16) == 0)
7492 DHD_INFO(("%02x ", cis
[byte
]));
7493 if ((byte
% 16) == 15)
7501 else if ((byte
+ 1) < SBSDIO_CIS_SIZE_LIMIT
)
7502 tdata
= cis
[byte
+ 1] + 1;
7507 if ((byte
% 16) != 15)
7510 #endif /* DHD_DEBUG */
7513 dhdsdio_chipmatch(uint16 chipid
)
7515 if (chipid
== BCM4335_CHIP_ID
)
7517 if (chipid
== BCM4339_CHIP_ID
)
7519 if (BCM4345_CHIP(chipid
))
7521 if (chipid
== BCM4350_CHIP_ID
)
7523 if (chipid
== BCM4354_CHIP_ID
)
7525 if (chipid
== BCM4358_CHIP_ID
)
7527 if (chipid
== BCM43430_CHIP_ID
)
7529 if (chipid
== BCM43018_CHIP_ID
)
7531 if (BCM4349_CHIP(chipid
))
7533 if (chipid
== BCM4364_CHIP_ID
)
7536 if (chipid
== BCM43012_CHIP_ID
)
7539 if (chipid
== BCM43014_CHIP_ID
)
7546 dhdsdio_probe(uint16 venid
, uint16 devid
, uint16 bus_no
, uint16 slot
,
7547 uint16 func
, uint bustype
, void *regsva
, osl_t
* osh
, void *sdh
)
7552 #if defined(MULTIPLE_SUPPLICANT)
7553 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
7554 if (mutex_is_locked(&_dhd_sdio_mutex_lock_
) == 0) {
7555 DHD_ERROR(("%s : no mutex held. set lock\n", __FUNCTION__
));
7557 DHD_ERROR(("%s : mutex is locked!. wait for unlocking\n", __FUNCTION__
));
7559 mutex_lock(&_dhd_sdio_mutex_lock_
);
7560 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
7563 /* Init global variables at run-time, not as part of the declaration.
7564 * This is required to support init/de-init of the driver. Initialization
7565 * of globals as part of the declaration results in non-deterministic
7566 * behavior since the value of the globals may be different on the
7567 * first time that the driver is initialized vs subsequent initializations.
7569 dhd_txbound
= DHD_TXBOUND
;
7570 dhd_rxbound
= DHD_RXBOUND
;
7572 dhd_alignctl
= FALSE
;
7574 dhd_alignctl
= TRUE
;
7577 dhd_readahead
= TRUE
;
7580 #ifdef DISABLE_FLOW_CONTROL
7582 #endif /* DISABLE_FLOW_CONTROL */
7583 dhd_dongle_ramsize
= 0;
7584 dhd_txminmax
= DHD_TXMINMAX
;
7590 #endif /* !BCMSPI */
7592 DHD_TRACE(("%s: Enter\n", __FUNCTION__
));
7593 DHD_INFO(("%s: venid 0x%04x devid 0x%04x\n", __FUNCTION__
, venid
, devid
));
7595 /* We make assumptions about address window mappings */
7596 ASSERT((uintptr
)regsva
== si_enum_base(devid
));
7598 /* BCMSDH passes venid and devid based on CIS parsing -- but low-power start
7599 * means early parse could fail, so here we should get either an ID
7600 * we recognize OR (-1) indicating we must request power first.
7602 /* Check the Vendor ID */
7605 case VENDOR_BROADCOM
:
7608 DHD_ERROR(("%s: unknown vendor: 0x%04x\n",
7609 __FUNCTION__
, venid
));
7613 /* Check the Device ID and make sure it's one that we support */
7616 DHD_INFO(("%s: allow device id 0, will check chip internals\n",
7621 DHD_ERROR(("%s: skipping 0x%04x/0x%04x, not a dongle\n",
7622 __FUNCTION__
, venid
, devid
));
7627 DHD_ERROR(("%s: osh is NULL!\n", __FUNCTION__
));
7631 /* Allocate private bus interface state */
7632 if (!(bus
= MALLOC(osh
, sizeof(dhd_bus_t
)))) {
7633 DHD_ERROR(("%s: MALLOC of dhd_bus_t failed\n", __FUNCTION__
));
7636 bzero(bus
, sizeof(dhd_bus_t
));
7638 bus
->cl_devid
= (uint16
)devid
;
7640 bus
->bus_num
= bus_no
;
7641 bus
->slot_num
= slot
;
7642 bus
->tx_seq
= SDPCM_SEQUENCE_WRAP
- 1;
7643 bus
->usebufpool
= FALSE
; /* Use bufpool if allocated, else use locally malloced rxbuf */
7645 bus
->bt_use_count
= 0;
7648 #if defined(SUPPORT_P2P_GO_PS)
7649 init_waitqueue_head(&bus
->bus_sleep
);
7650 #endif /* LINUX && SUPPORT_P2P_GO_PS */
7652 /* attempt to attach to the dongle */
7653 if (!(dhdsdio_probe_attach(bus
, osh
, sdh
, regsva
, devid
))) {
7654 DHD_ERROR(("%s: dhdsdio_probe_attach failed\n", __FUNCTION__
));
7658 /* Attach to the dhd/OS/network interface */
7659 if (!(bus
->dhd
= dhd_attach(osh
, bus
, SDPCM_RESERVE
))) {
7660 DHD_ERROR(("%s: dhd_attach failed\n", __FUNCTION__
));
7664 /* Allocate buffers */
7665 if (!(dhdsdio_probe_malloc(bus
, osh
, sdh
))) {
7666 DHD_ERROR(("%s: dhdsdio_probe_malloc failed\n", __FUNCTION__
));
7670 if (!(dhdsdio_probe_init(bus
, osh
, sdh
))) {
7671 DHD_ERROR(("%s: dhdsdio_probe_init failed\n", __FUNCTION__
));
7676 /* Register interrupt callback, but mask it (not operational yet). */
7677 DHD_INTR(("%s: disable SDIO interrupts (not interested yet)\n", __FUNCTION__
));
7678 bcmsdh_intr_disable(sdh
);
7679 if ((ret
= bcmsdh_intr_reg(sdh
, dhdsdio_isr
, bus
)) != 0) {
7680 DHD_ERROR(("%s: FAILED: bcmsdh_intr_reg returned %d\n",
7681 __FUNCTION__
, ret
));
7684 DHD_INTR(("%s: registered SDIO interrupt function ok\n", __FUNCTION__
));
7686 DHD_INFO(("%s: SDIO interrupt function is NOT registered due to polling mode\n",
7690 DHD_INFO(("%s: completed!!\n", __FUNCTION__
));
7692 /* if firmware path present try to download and bring up bus */
7693 bus
->dhd
->hang_report
= TRUE
;
7694 if (dhd_download_fw_on_driverload
) {
7695 if ((ret
= dhd_bus_start(bus
->dhd
)) != 0) {
7696 DHD_ERROR(("%s: dhd_bus_start failed\n", __FUNCTION__
));
7701 /* Set random MAC address during boot time */
7702 get_random_bytes(&bus
->dhd
->mac
.octet
[3], 3);
7703 /* Adding BRCM OUI */
7704 bus
->dhd
->mac
.octet
[0] = 0;
7705 bus
->dhd
->mac
.octet
[1] = 0x90;
7706 bus
->dhd
->mac
.octet
[2] = 0x4C;
7708 #if defined(BT_OVER_SDIO)
7709 /* At this point Regulators are turned on and iconditionaly sdio bus is started
7710 * based upon dhd_download_fw_on_driverload check, so
7711 * increase the bus user count, this count will only be disabled inside
7712 * dhd_register_if() function if flag dhd_download_fw_on_driverload is set to false,
7713 * i.e FW download during insmod is not needed, otherwise it will not be decremented
7714 * so that WALN will always hold the bus untill rmmod is done.
7716 dhdsdio_bus_usr_cnt_inc(bus
->dhd
);
7717 #endif /* BT_OVER_SDIO */
7719 /* Ok, have the per-port tell the stack we're open for business */
7720 if (dhd_attach_net(bus
->dhd
, TRUE
) != 0)
7722 DHD_ERROR(("%s: Net attach failed!!\n", __FUNCTION__
));
7726 #ifdef BCMHOST_XTAL_PU_TIME_MOD
7727 bcmsdh_reg_write(bus
->sdh
, 0x18000620, 2, 11);
7728 bcmsdh_reg_write(bus
->sdh
, 0x18000628, 4, 0x00F80001);
7729 #endif /* BCMHOST_XTAL_PU_TIME_MOD */
7731 #if defined(MULTIPLE_SUPPLICANT)
7732 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
7733 mutex_unlock(&_dhd_sdio_mutex_lock_
);
7734 DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__
));
7735 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
7741 dhdsdio_release(bus
, osh
);
7744 #if defined(MULTIPLE_SUPPLICANT)
7745 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
7746 mutex_unlock(&_dhd_sdio_mutex_lock_
);
7747 DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__
));
7748 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
7755 dhdsdio_probe_attach(struct dhd_bus
*bus
, osl_t
*osh
, void *sdh
, void *regsva
,
7760 #endif /* !BCMSPI */
7762 uint8
*cis
[SDIOD_MAX_IOFUNCS
];
7766 BCM_REFERENCE(value
);
7767 bus
->alp_only
= TRUE
;
7770 /* Return the window to backplane enumeration space for core access */
7771 if (dhdsdio_set_siaddr_window(bus
, si_enum_base(devid
))) {
7772 DHD_ERROR(("%s: FAILED to return to SI_ENUM_BASE\n", __FUNCTION__
));
7775 #if defined(DHD_DEBUG) && !defined(CUSTOMER_HW4_DEBUG)
7776 DHD_ERROR(("F1 signature read @0x18000000=0x%4x\n",
7777 bcmsdh_reg_read(bus
->sdh
, si_enum_base(devid
), 4)));
7778 #endif /* DHD_DEBUG && !CUSTOMER_HW4_DEBUG */
7780 #ifndef BCMSPI /* wake-wlan in gSPI will bring up the htavail/alpavail clocks. */
7782 /* Force PLL off until si_attach() programs PLL control regs */
7784 bcmsdh_cfg_write(sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_CHIPCLKCSR
, DHD_INIT_CLKCTL1
, &err
);
7786 clkctl
= bcmsdh_cfg_read(sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_CHIPCLKCSR
, &err
);
7788 if (err
|| ((clkctl
& ~SBSDIO_AVBITS
) != DHD_INIT_CLKCTL1
)) {
7789 DHD_ERROR(("dhdsdio_probe: ChipClkCSR access: err %d wrote 0x%02x read 0x%02x\n",
7790 err
, DHD_INIT_CLKCTL1
, clkctl
));
7794 #endif /* !BCMSPI */
7796 numfn
= bcmsdh_query_iofnum(sdh
);
7797 ASSERT(numfn
<= SDIOD_MAX_IOFUNCS
);
7799 /* Make sure ALP is available before trying to read CIS */
7800 SPINWAIT(((clkctl
= bcmsdh_cfg_read(sdh
, SDIO_FUNC_1
,
7801 SBSDIO_FUNC1_CHIPCLKCSR
, NULL
)),
7802 !SBSDIO_ALPAV(clkctl
)), PMU_MAX_TRANSITION_DLY
);
7804 /* Now request ALP be put on the bus */
7805 bcmsdh_cfg_write(sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_CHIPCLKCSR
,
7806 DHD_INIT_CLKCTL2
, &err
);
7809 numfn
= 0; /* internally func is hardcoded to 1 as gSPI has cis on F1 only */
7810 #endif /* !BCMSPI */
7812 for (fn
= 0; fn
<= numfn
; fn
++) {
7813 if (!(cis
[fn
] = MALLOC(osh
, SBSDIO_CIS_SIZE_LIMIT
))) {
7814 DHD_INFO(("dhdsdio_probe: fn %d cis malloc failed\n", fn
));
7817 bzero(cis
[fn
], SBSDIO_CIS_SIZE_LIMIT
);
7819 if ((err
= bcmsdh_cis_read(sdh
, fn
, cis
[fn
],
7820 SBSDIO_CIS_SIZE_LIMIT
))) {
7821 DHD_INFO(("dhdsdio_probe: fn %d cis read err %d\n", fn
, err
));
7822 MFREE(osh
, cis
[fn
], SBSDIO_CIS_SIZE_LIMIT
);
7826 /* Reading the F1, F2 and F3 max blocksize values from CIS
7827 * and writing into the F1, F2 and F3 block size registers.
7828 * There is no max block size register value available for F0 in CIS register.
7829 * So, setting default value for F0 block size as 32 (which was set earlier
7830 * in iovar). IOVAR takes only one arguement.
7831 * So, we are passing the function number alongwith the value (fn<<16)
7834 value
= F0_BLOCK_SIZE
;
7836 value
= (cis
[fn
][25]<<8) | cis
[fn
][24] | (fn
<<16);
7837 if (bcmsdh_iovar_op(sdh
, "sd_blocksize", NULL
, 0, &value
,
7838 sizeof(value
), TRUE
) != BCME_OK
) {
7840 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__
,
7844 if (DHD_INFO_ON()) {
7845 dhd_dump_cis(fn
, cis
[fn
]);
7847 #endif /* DHD_DEBUG */
7851 MFREE(osh
, cis
[fn
], SBSDIO_CIS_SIZE_LIMIT
);
7856 #endif /* DHD_DEBUG */
7859 DHD_ERROR(("dhdsdio_probe: failure reading or parsing CIS\n"));
7862 /* si_attach() will provide an SI handle and scan the backplane */
7863 if (!(bus
->sih
= si_attach((uint
)devid
, osh
, regsva
, DHD_BUS
, sdh
,
7864 &bus
->vars
, &bus
->varsz
))) {
7865 DHD_ERROR(("%s: si_attach failed!\n", __FUNCTION__
));
7870 DHD_ERROR(("F1 signature OK, socitype:0x%x chip:0x%4x rev:0x%x pkg:0x%x\n",
7871 bus
->sih
->socitype
, bus
->sih
->chip
, bus
->sih
->chiprev
, bus
->sih
->chippkg
));
7872 #endif /* DHD_DEBUG */
7874 bcmsdh_chipinfo(sdh
, bus
->sih
->chip
, bus
->sih
->chiprev
);
7876 if (!dhdsdio_chipmatch((uint16
)bus
->sih
->chip
)) {
7877 DHD_ERROR(("%s: unsupported chip: 0x%04x\n",
7878 __FUNCTION__
, bus
->sih
->chip
));
7882 if (bus
->sih
->buscorerev
>= 12)
7883 dhdsdio_clk_kso_init(bus
);
7887 si_sdiod_drive_strength_init(bus
->sih
, osh
, dhd_sdiod_drive_strength
);
7889 /* Get info on the ARM and SOCRAM cores... */
7890 if (!DHD_NOPMU(bus
)) {
7891 if ((si_setcore(bus
->sih
, ARM7S_CORE_ID
, 0)) ||
7892 (si_setcore(bus
->sih
, ARMCM3_CORE_ID
, 0)) ||
7893 (si_setcore(bus
->sih
, ARMCR4_CORE_ID
, 0))) {
7894 bus
->armrev
= si_corerev(bus
->sih
);
7896 DHD_ERROR(("%s: failed to find ARM core!\n", __FUNCTION__
));
7900 if (!si_setcore(bus
->sih
, ARMCR4_CORE_ID
, 0)) {
7901 if (!(bus
->orig_ramsize
= si_socram_size(bus
->sih
))) {
7902 DHD_ERROR(("%s: failed to find SOCRAM memory!\n", __FUNCTION__
));
7906 /* cr4 has a different way to find the RAM size from TCM's */
7907 if (!(bus
->orig_ramsize
= si_tcm_size(bus
->sih
))) {
7908 DHD_ERROR(("%s: failed to find CR4-TCM memory!\n", __FUNCTION__
));
7911 /* also populate base address */
7912 switch ((uint16
)bus
->sih
->chip
) {
7913 case BCM4335_CHIP_ID
:
7914 case BCM4339_CHIP_ID
:
7915 bus
->dongle_ram_base
= CR4_4335_RAM_BASE
;
7917 case BCM4350_CHIP_ID
:
7918 case BCM4354_CHIP_ID
:
7919 case BCM4358_CHIP_ID
:
7920 bus
->dongle_ram_base
= CR4_4350_RAM_BASE
;
7922 case BCM4360_CHIP_ID
:
7923 bus
->dongle_ram_base
= CR4_4360_RAM_BASE
;
7926 bus
->dongle_ram_base
= (bus
->sih
->chiprev
< 6) /* from 4345C0 */
7927 ? CR4_4345_LT_C0_RAM_BASE
: CR4_4345_GE_C0_RAM_BASE
;
7929 case BCM4349_CHIP_GRPID
:
7930 /* RAM based changed from 4349c0(revid=9) onwards */
7931 bus
->dongle_ram_base
= ((bus
->sih
->chiprev
< 9) ?
7932 CR4_4349_RAM_BASE
: CR4_4349_RAM_BASE_FROM_REV_9
);
7934 case BCM4364_CHIP_ID
:
7935 bus
->dongle_ram_base
= CR4_4364_RAM_BASE
;
7938 bus
->dongle_ram_base
= 0;
7939 DHD_ERROR(("%s: WARNING: Using default ram base at 0x%x\n",
7940 __FUNCTION__
, bus
->dongle_ram_base
));
7943 bus
->ramsize
= bus
->orig_ramsize
;
7944 if (dhd_dongle_ramsize
)
7945 dhd_dongle_setramsize(bus
, dhd_dongle_ramsize
);
7947 DHD_ERROR(("DHD: dongle ram size is set to %d(orig %d) at 0x%x\n",
7948 bus
->ramsize
, bus
->orig_ramsize
, bus
->dongle_ram_base
));
7950 bus
->srmemsize
= si_socram_srmem_size(bus
->sih
);
7953 /* ...but normally deal with the SDPCMDEV core */
7955 if (!(bus
->regs
= si_setcore(bus
->sih
, CC_CORE_ID
, 0))) {
7956 DHD_ERROR(("%s: failed to find Chip Common core!\n", __FUNCTION__
));
7960 if (!(bus
->regs
= si_setcore(bus
->sih
, PCMCIA_CORE_ID
, 0)) &&
7961 !(bus
->regs
= si_setcore(bus
->sih
, SDIOD_CORE_ID
, 0))) {
7962 DHD_ERROR(("%s: failed to find SDIODEV core!\n", __FUNCTION__
));
7966 bus
->sdpcmrev
= si_corerev(bus
->sih
);
7968 /* Set core control so an SDIO reset does a backplane reset */
7969 OR_REG(osh
, &bus
->regs
->corecontrol
, CC_BPRESEN
);
7971 bus
->rxint_mode
= SDIO_DEVICE_HMB_RXINT
;
7973 if ((bus
->sih
->buscoretype
== SDIOD_CORE_ID
) && (bus
->sdpcmrev
>= 4) &&
7974 (bus
->rxint_mode
== SDIO_DEVICE_RXDATAINT_MODE_1
))
7978 val
= R_REG(osh
, &bus
->regs
->corecontrol
);
7979 val
&= ~CC_XMTDATAAVAIL_MODE
;
7980 val
|= CC_XMTDATAAVAIL_CTRL
;
7981 W_REG(osh
, &bus
->regs
->corecontrol
, val
);
7985 pktq_init(&bus
->txq
, (PRIOMASK
+ 1), QLEN
);
7987 /* Locate an appropriately-aligned portion of hdrbuf */
7988 bus
->rxhdr
= (uint8
*)ROUNDUP((uintptr
)&bus
->hdrbuf
[0], DHD_SDALIGN
);
7990 /* Set the poll and/or interrupt flags */
7991 bus
->intr
= (bool)dhd_intr
;
7992 if ((bus
->poll
= (bool)dhd_poll
))
7995 /* Setting default Glom size */
7996 bus
->txglomsize
= SDPCM_DEFGLOM_SIZE
;
8001 if (bus
->sih
!= NULL
) {
8002 si_detach(bus
->sih
);
8009 dhdsdio_probe_malloc(dhd_bus_t
*bus
, osl_t
*osh
, void *sdh
)
8011 DHD_TRACE(("%s: Enter\n", __FUNCTION__
));
8013 if (bus
->dhd
->maxctl
) {
8014 bus
->rxblen
= ROUNDUP((bus
->dhd
->maxctl
+SDPCM_HDRLEN
), ALIGNMENT
) + DHD_SDALIGN
;
8015 if (!(bus
->rxbuf
= DHD_OS_PREALLOC(bus
->dhd
, DHD_PREALLOC_RXBUF
, bus
->rxblen
))) {
8016 DHD_ERROR(("%s: MALLOC of %d-byte rxbuf failed\n",
8017 __FUNCTION__
, bus
->rxblen
));
8021 /* Allocate buffer to receive glomed packet */
8022 if (!(bus
->databuf
= DHD_OS_PREALLOC(bus
->dhd
, DHD_PREALLOC_DATABUF
, MAX_DATA_BUF
))) {
8023 DHD_ERROR(("%s: MALLOC of %d-byte databuf failed\n",
8024 __FUNCTION__
, MAX_DATA_BUF
));
8025 /* release rxbuf which was already located as above */
8027 DHD_OS_PREFREE(bus
->dhd
, bus
->rxbuf
, bus
->rxblen
);
8031 /* Align the buffer */
8032 if ((uintptr
)bus
->databuf
% DHD_SDALIGN
)
8033 bus
->dataptr
= bus
->databuf
+ (DHD_SDALIGN
- ((uintptr
)bus
->databuf
% DHD_SDALIGN
));
8035 bus
->dataptr
= bus
->databuf
;
8044 dhdsdio_probe_init(dhd_bus_t
*bus
, osl_t
*osh
, void *sdh
)
8048 DHD_TRACE(("%s: Enter\n", __FUNCTION__
));
8050 bus
->_srenab
= FALSE
;
8053 dhdsdio_pktgen_init(bus
);
8057 /* Disable F2 to clear any intermediate frame state on the dongle */
8058 bcmsdh_cfg_write(sdh
, SDIO_FUNC_0
, SDIOD_CCCR_IOEN
, SDIO_FUNC_ENABLE_1
, NULL
);
8059 #endif /* !BCMSPI */
8061 bus
->dhd
->busstate
= DHD_BUS_DOWN
;
8062 bus
->sleeping
= FALSE
;
8063 bus
->rxflow
= FALSE
;
8064 bus
->prev_rxlim_hit
= 0;
8067 /* Done with backplane-dependent accesses, can drop clock... */
8068 bcmsdh_cfg_write(sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_CHIPCLKCSR
, 0, NULL
);
8069 #endif /* !BCMSPI */
8071 /* ...and initialize clock/power states */
8072 bus
->clkstate
= CLK_SDONLY
;
8073 bus
->idletime
= (int32
)dhd_idletime
;
8074 bus
->idleclock
= DHD_IDLE_ACTIVE
;
8076 /* Query the SD clock speed */
8077 if (bcmsdh_iovar_op(sdh
, "sd_divisor", NULL
, 0,
8078 &bus
->sd_divisor
, sizeof(int32
), FALSE
) != BCME_OK
) {
8079 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__
, "sd_divisor"));
8080 bus
->sd_divisor
= -1;
8082 DHD_INFO(("%s: Initial value for %s is %d\n",
8083 __FUNCTION__
, "sd_divisor", bus
->sd_divisor
));
8086 /* Query the SD bus mode */
8087 if (bcmsdh_iovar_op(sdh
, "sd_mode", NULL
, 0,
8088 &bus
->sd_mode
, sizeof(int32
), FALSE
) != BCME_OK
) {
8089 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__
, "sd_mode"));
8092 DHD_INFO(("%s: Initial value for %s is %d\n",
8093 __FUNCTION__
, "sd_mode", bus
->sd_mode
));
8096 /* Query the F2 block size, set roundup accordingly */
8098 if (bcmsdh_iovar_op(sdh
, "sd_blocksize", &fnum
, sizeof(int32
),
8099 &bus
->blocksize
, sizeof(int32
), FALSE
) != BCME_OK
) {
8101 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__
, "sd_blocksize"));
8103 DHD_INFO(("%s: Initial value for %s is %d\n",
8104 __FUNCTION__
, "sd_blocksize", bus
->blocksize
));
8106 dhdsdio_tune_fifoparam(bus
);
8108 bus
->roundup
= MIN(max_roundup
, bus
->blocksize
);
8110 #ifdef DHDENABLE_TAILPAD
8112 PKTFREE(osh
, bus
->pad_pkt
, FALSE
);
8113 bus
->pad_pkt
= PKTGET(osh
, SDIO_MAX_BLOCK_SIZE
, FALSE
);
8114 if (bus
->pad_pkt
== NULL
)
8115 DHD_ERROR(("failed to allocate padding packet\n"));
8117 int alignment_offset
= 0;
8118 uintptr pktprt
= (uintptr
)PKTDATA(osh
, bus
->pad_pkt
);
8119 if (!(pktprt
&1) && (pktprt
= (pktprt
% DHD_SDALIGN
)))
8120 PKTPUSH(osh
, bus
->pad_pkt
, alignment_offset
);
8121 PKTSETNEXT(osh
, bus
->pad_pkt
, NULL
);
8123 #endif /* DHDENABLE_TAILPAD */
8125 /* Query if bus module supports packet chaining, default to use if supported */
8126 if (bcmsdh_iovar_op(sdh
, "sd_rxchain", NULL
, 0,
8127 &bus
->sd_rxchain
, sizeof(int32
), FALSE
) != BCME_OK
) {
8128 bus
->sd_rxchain
= FALSE
;
8130 DHD_INFO(("%s: bus module (through bcmsdh API) %s chaining\n",
8131 __FUNCTION__
, (bus
->sd_rxchain
? "supports" : "does not support")));
8133 bus
->use_rxchain
= (bool)bus
->sd_rxchain
;
8134 bus
->txinrx_thres
= CUSTOM_TXINRX_THRES
;
8135 /* TX first in dhdsdio_readframes() */
8136 bus
->dotxinrx
= TRUE
;
8142 dhd_bus_download_firmware(struct dhd_bus
*bus
, osl_t
*osh
,
8143 char *pfw_path
, char *pnv_path
)
8147 bus
->fw_path
= pfw_path
;
8148 bus
->nv_path
= pnv_path
;
8150 ret
= dhdsdio_download_firmware(bus
, osh
, bus
->sdh
);
8156 dhdsdio_download_firmware(struct dhd_bus
*bus
, osl_t
*osh
, void *sdh
)
8160 #if defined(SUPPORT_MULTIPLE_REVISION)
8161 if (concate_revision(bus
, bus
->fw_path
, bus
->nv_path
) != 0) {
8162 DHD_ERROR(("%s: fail to concatnate revison \n",
8166 #endif /* SUPPORT_MULTIPLE_REVISION */
8168 #if defined(DHD_BLOB_EXISTENCE_CHECK)
8169 dhd_set_blob_support(bus
->dhd
, bus
->fw_path
);
8170 #endif /* DHD_BLOB_EXISTENCE_CHECK */
8172 DHD_TRACE_HW4(("%s: firmware path=%s, nvram path=%s\n",
8173 __FUNCTION__
, bus
->fw_path
, bus
->nv_path
));
8174 DHD_OS_WAKE_LOCK(bus
->dhd
);
8176 /* Download the firmware */
8177 dhdsdio_clkctl(bus
, CLK_AVAIL
, FALSE
);
8179 ret
= _dhdsdio_download_firmware(bus
);
8181 dhdsdio_clkctl(bus
, CLK_SDONLY
, FALSE
);
8183 DHD_OS_WAKE_UNLOCK(bus
->dhd
);
8187 /* Detach and free everything */
8189 dhdsdio_release(dhd_bus_t
*bus
, osl_t
*osh
)
8191 bool dongle_isolation
= FALSE
;
8192 DHD_TRACE(("%s: Enter\n", __FUNCTION__
));
8198 #if defined(DEBUGGER) || defined(DHD_DSCOPE)
8200 #endif /* DEBUGGER || DHD_DSCOPE */
8201 dongle_isolation
= bus
->dhd
->dongle_isolation
;
8202 dhd_detach(bus
->dhd
);
8205 /* De-register interrupt handler */
8206 bcmsdh_intr_disable(bus
->sdh
);
8207 bcmsdh_intr_dereg(bus
->sdh
);
8210 dhdsdio_release_dongle(bus
, osh
, dongle_isolation
, TRUE
);
8215 dhdsdio_release_malloc(bus
, osh
);
8218 if (bus
->console
.buf
!= NULL
)
8219 MFREE(osh
, bus
->console
.buf
, bus
->console
.bufsize
);
8222 #ifdef DHDENABLE_TAILPAD
8224 PKTFREE(osh
, bus
->pad_pkt
, FALSE
);
8225 #endif /* DHDENABLE_TAILPAD */
8227 MFREE(osh
, bus
, sizeof(dhd_bus_t
));
8230 DHD_TRACE(("%s: Disconnected\n", __FUNCTION__
));
8234 dhdsdio_release_malloc(dhd_bus_t
*bus
, osl_t
*osh
)
8236 DHD_TRACE(("%s: Enter\n", __FUNCTION__
));
8238 if (bus
->dhd
&& bus
->dhd
->dongle_reset
)
8242 #ifndef CONFIG_DHD_USE_STATIC_BUF
8243 MFREE(osh
, bus
->rxbuf
, bus
->rxblen
);
8245 bus
->rxctl
= bus
->rxbuf
= NULL
;
8250 #ifndef CONFIG_DHD_USE_STATIC_BUF
8251 MFREE(osh
, bus
->databuf
, MAX_DATA_BUF
);
8253 bus
->databuf
= NULL
;
8256 if (bus
->vars
&& bus
->varsz
) {
8257 MFREE(osh
, bus
->vars
, bus
->varsz
);
8264 dhdsdio_release_dongle(dhd_bus_t
*bus
, osl_t
*osh
, bool dongle_isolation
, bool reset_flag
)
8266 DHD_TRACE(("%s: Enter bus->dhd %p bus->dhd->dongle_reset %d \n", __FUNCTION__
,
8267 bus
->dhd
, bus
->dhd
->dongle_reset
));
8269 if ((bus
->dhd
&& bus
->dhd
->dongle_reset
) && reset_flag
)
8273 /* In Win10, system will be BSOD if using "sysprep" to do OS image */
8274 /* Skip this will not cause the BSOD. */
8275 #if !defined(BCMLXSDMMC)
8277 dhdsdio_clkctl(bus
, CLK_AVAIL
, FALSE
);
8279 if (KSO_ENAB(bus
) && (dongle_isolation
== FALSE
))
8280 si_watchdog(bus
->sih
, 4);
8281 #endif /* !defined(BCMLXSDMMC) */
8283 dhdsdio_clkctl(bus
, CLK_NONE
, FALSE
);
8285 si_detach(bus
->sih
);
8287 if (bus
->vars
&& bus
->varsz
)
8288 MFREE(osh
, bus
->vars
, bus
->varsz
);
8292 DHD_TRACE(("%s: Disconnected\n", __FUNCTION__
));
8296 dhdsdio_disconnect(void *ptr
)
8298 dhd_bus_t
*bus
= (dhd_bus_t
*)ptr
;
8300 DHD_TRACE(("%s: Enter\n", __FUNCTION__
));
8302 #if defined(MULTIPLE_SUPPLICANT)
8303 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
8304 if (mutex_is_locked(&_dhd_sdio_mutex_lock_
) == 0) {
8305 DHD_ERROR(("%s : no mutex held. set lock\n", __FUNCTION__
));
8307 DHD_ERROR(("%s : mutex is locked!. wait for unlocking\n", __FUNCTION__
));
8309 mutex_lock(&_dhd_sdio_mutex_lock_
);
8310 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
8315 /* Advertise bus cleanup during rmmod */
8316 dhdsdio_advertise_bus_cleanup(bus
->dhd
);
8317 dhdsdio_release(bus
, bus
->dhd
->osh
);
8320 #if defined(MULTIPLE_SUPPLICANT)
8321 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
8322 mutex_unlock(&_dhd_sdio_mutex_lock_
);
8323 DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__
));
8324 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
8327 DHD_TRACE(("%s: Disconnected\n", __FUNCTION__
));
8331 dhdsdio_suspend(void *context
)
8334 #ifdef SUPPORT_P2P_GO_PS
8336 #endif /* SUPPORT_P2P_GO_PS */
8338 dhd_bus_t
*bus
= (dhd_bus_t
*)context
;
8339 unsigned long flags
;
8341 DHD_ERROR(("%s Enter\n", __FUNCTION__
));
8342 if (bus
->dhd
== NULL
) {
8343 DHD_ERROR(("bus not inited\n"));
8346 if (bus
->dhd
->prot
== NULL
) {
8347 DHD_ERROR(("prot is not inited\n"));
8351 if (bus
->dhd
->up
== FALSE
) {
8355 DHD_LINUX_GENERAL_LOCK(bus
->dhd
, flags
);
8356 if (bus
->dhd
->busstate
!= DHD_BUS_DATA
&& bus
->dhd
->busstate
!= DHD_BUS_SUSPEND
) {
8357 DHD_ERROR(("not in a readystate to LPBK is not inited\n"));
8358 DHD_LINUX_GENERAL_UNLOCK(bus
->dhd
, flags
);
8361 DHD_LINUX_GENERAL_UNLOCK(bus
->dhd
, flags
);
8362 if (bus
->dhd
->dongle_reset
) {
8363 DHD_ERROR(("Dongle is in reset state.\n"));
8367 DHD_LINUX_GENERAL_LOCK(bus
->dhd
, flags
);
8368 bus
->dhd
->busstate
= DHD_BUS_SUSPEND
;
8369 if (DHD_BUS_BUSY_CHECK_IN_TX(bus
->dhd
)) {
8370 DHD_ERROR(("Tx Request is not ended\n"));
8371 bus
->dhd
->busstate
= DHD_BUS_DATA
;
8372 DHD_LINUX_GENERAL_UNLOCK(bus
->dhd
, flags
);
8375 DHD_BUS_BUSY_SET_SUSPEND_IN_PROGRESS(bus
->dhd
);
8376 DHD_LINUX_GENERAL_UNLOCK(bus
->dhd
, flags
);
8378 #ifdef SUPPORT_P2P_GO_PS
8379 if (bus
->idletime
> 0) {
8380 wait_time
= msecs_to_jiffies(bus
->idletime
* dhd_watchdog_ms
);
8382 #endif /* SUPPORT_P2P_GO_PS */
8383 ret
= dhd_os_check_wakelock(bus
->dhd
);
8384 #ifdef SUPPORT_P2P_GO_PS
8385 if ((!ret
) && (bus
->dhd
->up
) && (bus
->dhd
->op_mode
!= DHD_FLAG_HOSTAP_MODE
)) {
8386 if (wait_event_timeout(bus
->bus_sleep
, bus
->sleeping
, wait_time
) == 0) {
8387 if (!bus
->sleeping
) {
8392 #endif /* SUPPORT_P2P_GO_PS */
8394 DHD_LINUX_GENERAL_LOCK(bus
->dhd
, flags
);
8396 bus
->dhd
->busstate
= DHD_BUS_DATA
;
8398 DHD_BUS_BUSY_CLEAR_SUSPEND_IN_PROGRESS(bus
->dhd
);
8399 dhd_os_busbusy_wake(bus
->dhd
);
8400 DHD_LINUX_GENERAL_UNLOCK(bus
->dhd
, flags
);
8405 dhdsdio_resume(void *context
)
8407 dhd_bus_t
*bus
= (dhd_bus_t
*)context
;
8410 DHD_ERROR(("%s Enter\n", __FUNCTION__
));
8412 if (bus
->dhd
->up
== FALSE
) {
8416 DHD_LINUX_GENERAL_LOCK(bus
->dhd
, flags
);
8417 DHD_BUS_BUSY_SET_RESUME_IN_PROGRESS(bus
->dhd
);
8418 DHD_LINUX_GENERAL_UNLOCK(bus
->dhd
, flags
);
8420 #if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
8421 if (dhd_os_check_if_up(bus
->dhd
))
8422 bcmsdh_oob_intr_set(bus
->sdh
, TRUE
);
8423 #endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */
8425 DHD_LINUX_GENERAL_LOCK(bus
->dhd
, flags
);
8426 DHD_BUS_BUSY_CLEAR_RESUME_IN_PROGRESS(bus
->dhd
);
8427 bus
->dhd
->busstate
= DHD_BUS_DATA
;
8428 dhd_os_busbusy_wake(bus
->dhd
);
8429 DHD_LINUX_GENERAL_UNLOCK(bus
->dhd
, flags
);
8434 /* Register/Unregister functions are called by the main DHD entry
8435 * point (e.g. module insertion) to link with the bus driver, in
8436 * order to look for or await the device.
8439 static bcmsdh_driver_t dhd_sdio
= {
8447 dhd_bus_register(void)
8449 DHD_TRACE(("%s: Enter\n", __FUNCTION__
));
8451 return bcmsdh_register(&dhd_sdio
);
8455 dhd_bus_unregister(void)
8457 DHD_TRACE(("%s: Enter\n", __FUNCTION__
));
8459 bcmsdh_unregister();
8462 #if defined(BCMLXSDMMC)
8463 /* Register a dummy SDIO client driver in order to be notified of new SDIO device */
8464 int dhd_bus_reg_sdio_notify(void* semaphore
)
8466 return bcmsdh_reg_sdio_notify(semaphore
);
8469 void dhd_bus_unreg_sdio_notify(void)
8471 bcmsdh_unreg_sdio_notify();
8473 #endif /* defined(BCMLXSDMMC) */
8476 dhdsdio_download_code_file(struct dhd_bus
*bus
, char *pfw_path
)
8482 uint8
*memblock
= NULL
, *memptr
;
8483 uint memblock_size
= MEMBLOCK
;
8484 #ifdef DHD_DEBUG_DOWNLOADTIME
8485 unsigned long initial_jiffies
= 0;
8486 uint firmware_sz
= 0;
8489 DHD_INFO(("%s: download firmware %s\n", __FUNCTION__
, pfw_path
));
8491 image
= dhd_os_open_image1(bus
->dhd
, pfw_path
);
8492 if (image
== NULL
) {
8493 DHD_ERROR(("%s: Failed to open fw file !\n", __FUNCTION__
));
8497 /* Update the dongle image download block size depending on the F1 block size */
8498 if (sd_f1_blocksize
== 512)
8499 memblock_size
= MAX_MEMBLOCK
;
8500 memptr
= memblock
= MALLOC(bus
->dhd
->osh
, memblock_size
+ DHD_SDALIGN
);
8501 if (memblock
== NULL
) {
8502 DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__
,
8506 if ((uint32
)(uintptr
)memblock
% DHD_SDALIGN
)
8507 memptr
+= (DHD_SDALIGN
- ((uint32
)(uintptr
)memblock
% DHD_SDALIGN
));
8509 #ifdef DHD_DEBUG_DOWNLOADTIME
8510 initial_jiffies
= jiffies
;
8513 /* Download image */
8514 while ((len
= dhd_os_get_image_block((char*)memptr
, memblock_size
, image
))) {
8516 DHD_ERROR(("%s: dhd_os_get_image_block failed (%d)\n", __FUNCTION__
, len
));
8517 bcmerror
= BCME_ERROR
;
8521 if (si_setcore(bus
->sih
, ARMCR4_CORE_ID
, 0)) {
8522 /* if address is 0, store the reset instruction to be written in 0 */
8525 bus
->resetinstr
= *(((uint32
*)memptr
));
8526 /* Add start of RAM address to the address given by user */
8527 offset
+= bus
->dongle_ram_base
;
8531 bcmerror
= dhdsdio_membytes(bus
, TRUE
, offset
, memptr
, len
);
8533 DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
8534 __FUNCTION__
, bcmerror
, memblock_size
, offset
));
8538 offset
+= memblock_size
;
8539 #ifdef DHD_DEBUG_DOWNLOADTIME
8544 #ifdef DHD_DEBUG_DOWNLOADTIME
8545 DHD_ERROR(("Firmware download time for %u bytes: %u ms\n",
8546 firmware_sz
, jiffies_to_msecs(jiffies
- initial_jiffies
)));
8551 MFREE(bus
->dhd
->osh
, memblock
, memblock_size
+ DHD_SDALIGN
);
8554 dhd_os_close_image1(bus
->dhd
, image
);
8559 #ifdef DHD_UCODE_DOWNLOAD
8560 /* Currently supported only for the chips in which ucode RAM is AXI addressable */
8562 dhdsdio_ucode_base(struct dhd_bus
*bus
)
8564 uint32 ucode_base
= 0;
8566 switch ((uint16
)bus
->sih
->chip
) {
8567 case BCM43012_CHIP_ID
:
8568 ucode_base
= 0xE8020000;
8571 DHD_ERROR(("%s: Unsupported!\n", __func__
));
8579 dhdsdio_download_ucode_file(struct dhd_bus
*bus
, char *ucode_path
)
8586 uint8
*memblock
= NULL
, *memptr
;
8587 uint memblock_size
= MEMBLOCK
;
8588 #ifdef DHD_DEBUG_DOWNLOADTIME
8589 unsigned long initial_jiffies
= 0;
8590 uint firmware_sz
= 0;
8593 DHD_INFO(("%s: download firmware %s\n", __FUNCTION__
, ucode_path
));
8595 ucode_base
= dhdsdio_ucode_base(bus
);
8597 image
= dhd_os_open_image1(bus
->dhd
, ucode_path
);
8601 /* Update the dongle image download block size depending on the F1 block size */
8602 if (sd_f1_blocksize
== 512)
8603 memblock_size
= MAX_MEMBLOCK
;
8605 memptr
= memblock
= MALLOC(bus
->dhd
->osh
, memblock_size
+ DHD_SDALIGN
);
8606 if (memblock
== NULL
) {
8607 DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__
,
8611 if ((uint32
)(uintptr
)memblock
% DHD_SDALIGN
)
8612 memptr
+= (DHD_SDALIGN
- ((uint32
)(uintptr
)memblock
% DHD_SDALIGN
));
8614 #ifdef DHD_DEBUG_DOWNLOADTIME
8615 initial_jiffies
= jiffies
;
8618 /* Download image */
8619 while ((len
= dhd_os_get_image_block((char*)memptr
, memblock_size
, image
))) {
8621 DHD_ERROR(("%s: dhd_os_get_image_block failed (%d)\n", __FUNCTION__
, len
));
8622 bcmerror
= BCME_ERROR
;
8626 bcmerror
= dhdsdio_membytes(bus
, TRUE
, (ucode_base
+ offset
), memptr
, len
);
8628 DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
8629 __FUNCTION__
, bcmerror
, memblock_size
, offset
));
8633 offset
+= memblock_size
;
8634 #ifdef DHD_DEBUG_DOWNLOADTIME
8639 #ifdef DHD_DEBUG_DOWNLOADTIME
8640 DHD_ERROR(("ucode download time for %u bytes: %u ms\n",
8641 firmware_sz
, jiffies_to_msecs(jiffies
- initial_jiffies
)));
8646 MFREE(bus
->dhd
->osh
, memblock
, memblock_size
+ DHD_SDALIGN
);
8649 dhd_os_close_image1(bus
->dhd
, image
);
8652 } /* dhdsdio_download_ucode_file */
8655 dhd_bus_ucode_download(struct dhd_bus
*bus
)
8657 uint32 shaddr
= 0, shdata
= 0;
8659 shaddr
= bus
->dongle_ram_base
+ bus
->ramsize
- 4;
8660 dhdsdio_membytes(bus
, FALSE
, shaddr
, (uint8
*)&shdata
, 4);
8662 DHD_TRACE(("%s: shdata:[0x%08x :0x%08x]\n", __func__
, shaddr
, shdata
));
8664 if (shdata
== UCODE_DOWNLOAD_REQUEST
)
8666 DHD_ERROR(("%s: Received ucode download request!\n", __func__
));
8668 /* Download the ucode */
8669 if (!dhd_get_ucode_path(bus
->dhd
)) {
8670 DHD_ERROR(("%s: bus->uc_path not set!\n", __func__
));
8673 dhdsdio_download_ucode_file(bus
, dhd_get_ucode_path(bus
->dhd
));
8675 DHD_ERROR(("%s: Ucode downloaded successfully!\n", __func__
));
8677 shdata
= UCODE_DOWNLOAD_COMPLETE
;
8678 dhdsdio_membytes(bus
, TRUE
, shaddr
, (uint8
*)&shdata
, 4);
8682 #endif /* DHD_UCODE_DOWNLOAD */
8685 dhdsdio_download_nvram(struct dhd_bus
*bus
)
8689 void * image
= NULL
;
8690 char * memblock
= NULL
;
8693 bool nvram_file_exists
;
8695 pnv_path
= bus
->nv_path
;
8697 nvram_file_exists
= ((pnv_path
!= NULL
) && (pnv_path
[0] != '\0'));
8699 /* For Get nvram from UEFI */
8700 if (nvram_file_exists
)
8701 image
= dhd_os_open_image1(bus
->dhd
, pnv_path
);
8703 memblock
= MALLOC(bus
->dhd
->osh
, MAX_NVRAMBUF_SIZE
);
8704 if (memblock
== NULL
) {
8705 DHD_ERROR(("%s: Failed to allocate memory %d bytes\n",
8706 __FUNCTION__
, MAX_NVRAMBUF_SIZE
));
8710 /* For Get nvram from image or UEFI (when image == NULL ) */
8711 len
= dhd_os_get_image_block(memblock
, MAX_NVRAMBUF_SIZE
, image
);
8713 if (len
> 0 && len
< MAX_NVRAMBUF_SIZE
) {
8714 bufp
= (char *)memblock
;
8716 len
= process_nvram_vars(bufp
, len
);
8718 len
+= 4 - (len
% 4);
8723 bcmerror
= dhdsdio_downloadvars(bus
, memblock
, len
+ 1);
8725 DHD_ERROR(("%s: error downloading vars: %d\n",
8726 __FUNCTION__
, bcmerror
));
8729 DHD_ERROR(("%s: error reading nvram file: %d\n",
8730 __FUNCTION__
, len
));
8731 bcmerror
= BCME_SDIO_ERROR
;
8736 MFREE(bus
->dhd
->osh
, memblock
, MAX_NVRAMBUF_SIZE
);
8739 dhd_os_close_image1(bus
->dhd
, image
);
8745 _dhdsdio_download_firmware(struct dhd_bus
*bus
)
8749 bool embed
= FALSE
; /* download embedded firmware */
8750 bool dlok
= FALSE
; /* download firmware succeeded */
8752 /* Out immediately if no image to download */
8753 if ((bus
->fw_path
== NULL
) || (bus
->fw_path
[0] == '\0')) {
8757 /* Keep arm in reset */
8758 if (dhdsdio_download_state(bus
, TRUE
)) {
8759 DHD_ERROR(("%s: error placing ARM core in reset\n", __FUNCTION__
));
8763 /* External image takes precedence if specified */
8764 if ((bus
->fw_path
!= NULL
) && (bus
->fw_path
[0] != '\0')) {
8765 if (dhdsdio_download_code_file(bus
, bus
->fw_path
)) {
8766 DHD_ERROR(("%s: dongle image file download failed\n", __FUNCTION__
));
8774 BCM_REFERENCE(embed
);
8776 DHD_ERROR(("%s: dongle image download failed\n", __FUNCTION__
));
8780 /* External nvram takes precedence if specified */
8781 if (dhdsdio_download_nvram(bus
)) {
8782 DHD_ERROR(("%s: dongle nvram file download failed\n", __FUNCTION__
));
8786 /* Take arm out of reset */
8787 if (dhdsdio_download_state(bus
, FALSE
)) {
8788 DHD_ERROR(("%s: error getting out of ARM core reset\n", __FUNCTION__
));
8799 dhd_bcmsdh_recv_buf(dhd_bus_t
*bus
, uint32 addr
, uint fn
, uint flags
, uint8
*buf
, uint nbytes
,
8800 void *pkt
, bcmsdh_cmplt_fn_t complete_fn
, void *handle
)
8804 if (!KSO_ENAB(bus
)) {
8805 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__
));
8806 return BCME_NODEVICE
;
8809 status
= bcmsdh_recv_buf(bus
->sdh
, addr
, fn
, flags
, buf
, nbytes
, pkt
, complete_fn
, handle
);
8815 dhd_bcmsdh_send_buf(dhd_bus_t
*bus
, uint32 addr
, uint fn
, uint flags
, uint8
*buf
, uint nbytes
,
8816 void *pkt
, bcmsdh_cmplt_fn_t complete_fn
, void *handle
, int max_retry
)
8823 if (!KSO_ENAB(bus
)) {
8824 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__
));
8825 return BCME_NODEVICE
;
8830 ret
= bcmsdh_send_buf(bus
->sdh
, addr
, fn
, flags
, buf
, nbytes
,
8831 pkt
, complete_fn
, handle
);
8834 ASSERT(ret
!= BCME_PENDING
);
8836 if (ret
== BCME_NODEVICE
) {
8837 DHD_ERROR(("%s: Device asleep already\n", __FUNCTION__
));
8838 } else if (ret
< 0) {
8839 /* On failure, abort the command and terminate the frame */
8840 DHD_ERROR(("%s: sdio error %d, abort command and terminate frame.\n",
8841 __FUNCTION__
, ret
));
8844 bus
->dhd
->tx_errors
++;
8845 bcmsdh_abort(sdh
, SDIO_FUNC_2
);
8846 bcmsdh_cfg_write(sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_FRAMECTRL
,
8848 for (i
= 0; i
< READ_FRM_CNT_RETRIES
; i
++) {
8850 hi
= bcmsdh_cfg_read(sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_WFRAMEBCHI
,
8852 lo
= bcmsdh_cfg_read(sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_WFRAMEBCLO
,
8854 bus
->f1regdata
+= 2;
8855 if ((hi
== 0) && (lo
== 0))
8859 } while ((ret
< 0) && retrydata
&& ++retries
< max_retry
);
8865 dhd_bus_is_ioready(struct dhd_bus
*bus
)
8870 ASSERT(bus
->sih
!= NULL
);
8871 enable
= (SDIO_FUNC_ENABLE_1
| SDIO_FUNC_ENABLE_2
);
8873 return (enable
== bcmsdh_cfg_read(sdh
, SDIO_FUNC_0
, SDIOD_CCCR_IORDY
, NULL
));
8877 dhd_bus_chip(struct dhd_bus
*bus
)
8879 ASSERT(bus
->sih
!= NULL
);
8880 return bus
->sih
->chip
;
8884 dhd_bus_chiprev(struct dhd_bus
*bus
)
8887 ASSERT(bus
->sih
!= NULL
);
8888 return bus
->sih
->chiprev
;
8892 dhd_bus_pub(struct dhd_bus
*bus
)
8898 dhd_bus_sih(struct dhd_bus
*bus
)
8900 return (void *)bus
->sih
;
8904 dhd_bus_txq(struct dhd_bus
*bus
)
8910 dhd_bus_hdrlen(struct dhd_bus
*bus
)
8912 return (bus
->txglom_enable
) ? SDPCM_HDRLEN_TXGLOM
: SDPCM_HDRLEN
;
8916 dhd_bus_set_dotxinrx(struct dhd_bus
*bus
, bool val
)
8918 bus
->dotxinrx
= val
;
8922 * dhdsdio_advertise_bus_cleanup advertises that clean up is under progress
8923 * to other bus user contexts like Tx, Rx, IOVAR, WD etc and it waits for other contexts
8924 * to gracefully exit. All the bus usage contexts before marking busstate as busy, will check for
8925 * whether the busstate is DHD_BUS_DOWN or DHD_BUS_DOWN_IN_PROGRESS, if so
8926 * they will exit from there itself without marking dhd_bus_busy_state as BUSY.
8929 dhdsdio_advertise_bus_cleanup(dhd_pub_t
*dhdp
)
8931 unsigned long flags
;
8934 DHD_LINUX_GENERAL_LOCK(dhdp
, flags
);
8935 dhdp
->busstate
= DHD_BUS_DOWN_IN_PROGRESS
;
8936 DHD_LINUX_GENERAL_UNLOCK(dhdp
, flags
);
8938 timeleft
= dhd_os_busbusy_wait_negation(dhdp
, &dhdp
->dhd_bus_busy_state
);
8939 if ((timeleft
== 0) || (timeleft
== 1)) {
8940 DHD_ERROR(("%s : Timeout due to dhd_bus_busy_state=0x%x\n",
8941 __FUNCTION__
, dhdp
->dhd_bus_busy_state
));
8949 dhd_bus_devreset(dhd_pub_t
*dhdp
, uint8 flag
)
8953 unsigned long flags
;
8958 if (!bus
->dhd
->dongle_reset
) {
8959 DHD_ERROR(("%s: == Power OFF ==\n", __FUNCTION__
));
8960 dhdsdio_advertise_bus_cleanup(bus
->dhd
);
8961 dhd_os_sdlock(dhdp
);
8962 dhd_os_wd_timer(dhdp
, 0);
8963 #if !defined(IGNORE_ETH0_DOWN)
8964 /* Force flow control as protection when stop come before ifconfig_down */
8965 dhd_txflowcontrol(bus
->dhd
, ALL_INTERFACES
, ON
);
8966 #endif /* !defined(IGNORE_ETH0_DOWN) */
8967 /* Expect app to have torn down any connection before calling */
8968 /* Stop the bus, disable F2 */
8969 dhd_bus_stop(bus
, FALSE
);
8970 #if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
8971 /* Clean up any pending IRQ */
8972 dhd_enable_oob_intr(bus
, FALSE
);
8973 bcmsdh_oob_intr_set(bus
->sdh
, FALSE
);
8974 bcmsdh_oob_intr_unregister(bus
->sdh
);
8975 #endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */
8977 /* Clean tx/rx buffer pointers, detach from the dongle */
8978 dhdsdio_release_dongle(bus
, bus
->dhd
->osh
, TRUE
, TRUE
);
8980 bus
->dhd
->dongle_reset
= TRUE
;
8981 bus
->dhd
->up
= FALSE
;
8982 dhd_txglom_enable(dhdp
, FALSE
);
8983 dhd_os_sdunlock(dhdp
);
8985 DHD_LINUX_GENERAL_LOCK(bus
->dhd
, flags
);
8986 bus
->dhd
->busstate
= DHD_BUS_DOWN
;
8987 DHD_LINUX_GENERAL_UNLOCK(bus
->dhd
, flags
);
8989 DHD_TRACE(("%s: WLAN OFF DONE\n", __FUNCTION__
));
8990 /* App can now remove power from device */
8992 bcmerror
= BCME_SDIO_ERROR
;
8994 /* App must have restored power to device before calling */
8996 DHD_ERROR(("\n\n%s: == Power ON ==\n", __FUNCTION__
));
8998 if (bus
->dhd
->dongle_reset
) {
9000 dhd_os_sdlock(dhdp
);
9001 /* Reset SD client -- required if devreset is called
9002 * via 'dhd devreset' iovar
9004 bcmsdh_reset(bus
->sdh
);
9005 /* Attempt to re-attach & download */
9006 if (dhdsdio_probe_attach(bus
, bus
->dhd
->osh
, bus
->sdh
,
9007 (uint32
*)(uintptr
)si_enum_base(bus
->cl_devid
),
9010 DHD_LINUX_GENERAL_LOCK(bus
->dhd
, flags
);
9011 bus
->dhd
->busstate
= DHD_BUS_DOWN
;
9012 DHD_LINUX_GENERAL_UNLOCK(bus
->dhd
, flags
);
9014 /* Attempt to download binary to the dongle */
9015 if (dhdsdio_probe_init(bus
, bus
->dhd
->osh
, bus
->sdh
) &&
9016 dhdsdio_download_firmware(bus
, bus
->dhd
->osh
, bus
->sdh
) >= 0) {
9018 /* Re-init bus, enable F2 transfer */
9019 bcmerror
= dhd_bus_init((dhd_pub_t
*) bus
->dhd
, FALSE
);
9020 if (bcmerror
== BCME_OK
) {
9021 #if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
9022 dhd_enable_oob_intr(bus
, TRUE
);
9023 bcmsdh_oob_intr_register(bus
->sdh
,
9025 bcmsdh_oob_intr_set(bus
->sdh
, TRUE
);
9026 #endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */
9028 bus
->dhd
->dongle_reset
= FALSE
;
9029 bus
->dhd
->up
= TRUE
;
9031 #if !defined(IGNORE_ETH0_DOWN)
9032 /* Restore flow control */
9033 dhd_txflowcontrol(bus
->dhd
, ALL_INTERFACES
, OFF
);
9035 dhd_os_wd_timer(dhdp
, dhd_watchdog_ms
);
9037 DHD_TRACE(("%s: WLAN ON DONE\n", __FUNCTION__
));
9039 dhd_bus_stop(bus
, FALSE
);
9040 dhdsdio_release_dongle(bus
, bus
->dhd
->osh
,
9044 DHD_ERROR(("%s Failed to download binary to the dongle\n",
9046 if (bus
->sih
!= NULL
) {
9047 si_detach(bus
->sih
);
9050 bcmerror
= BCME_SDIO_ERROR
;
9053 bcmerror
= BCME_SDIO_ERROR
;
9055 dhd_os_sdunlock(dhdp
);
9057 DHD_INFO(("%s called when dongle is not in reset\n",
9059 DHD_INFO(("Will call dhd_bus_start instead\n"));
9060 dhd_bus_resume(dhdp
, 1);
9061 if ((bcmerror
= dhd_bus_start(dhdp
)) != 0)
9062 DHD_ERROR(("%s: dhd_bus_start fail with %d\n",
9063 __FUNCTION__
, bcmerror
));
9069 int dhd_bus_suspend(dhd_pub_t
*dhdpub
)
9071 return bcmsdh_stop(dhdpub
->bus
->sdh
);
9074 int dhd_bus_resume(dhd_pub_t
*dhdpub
, int stage
)
9076 return bcmsdh_start(dhdpub
->bus
->sdh
, stage
);
9079 /* Get Chip ID version */
9080 uint
dhd_bus_chip_id(dhd_pub_t
*dhdp
)
9082 dhd_bus_t
*bus
= dhdp
->bus
;
9084 return bus
->sih
->chip
;
9087 /* Get Chip Rev ID version */
9088 uint
dhd_bus_chiprev_id(dhd_pub_t
*dhdp
)
9090 dhd_bus_t
*bus
= dhdp
->bus
;
9092 return bus
->sih
->chiprev
;
9095 /* Get Chip Pkg ID version */
9096 uint
dhd_bus_chippkg_id(dhd_pub_t
*dhdp
)
9098 dhd_bus_t
*bus
= dhdp
->bus
;
9100 return bus
->sih
->chippkg
;
9103 int dhd_bus_get_ids(struct dhd_bus
*bus
, uint32
*bus_type
, uint32
*bus_num
, uint32
*slot_num
)
9105 *bus_type
= bus
->bus
;
9106 *bus_num
= bus
->bus_num
;
9107 *slot_num
= bus
->slot_num
;
9112 dhd_bus_membytes(dhd_pub_t
*dhdp
, bool set
, uint32 address
, uint8
*data
, uint size
)
9117 return dhdsdio_membytes(bus
, set
, address
, data
, size
);
9120 #if defined(SUPPORT_MULTIPLE_REVISION)
9122 concate_revision_bcm4335(dhd_bus_t
*bus
, char *fw_path
, char *nv_path
)
9126 #if defined(SUPPORT_MULTIPLE_CHIPS)
9127 char chipver_tag
[10] = "_4335";
9129 char chipver_tag
[4] = {0, };
9130 #endif /* defined(SUPPORT_MULTIPLE_CHIPS) */
9132 DHD_TRACE(("%s: BCM4335 Multiple Revision Check\n", __FUNCTION__
));
9133 if (bus
->sih
->chip
!= BCM4335_CHIP_ID
) {
9134 DHD_ERROR(("%s:Chip is not BCM4335\n", __FUNCTION__
));
9137 chipver
= bus
->sih
->chiprev
;
9138 DHD_ERROR(("CHIP VER = [0x%x]\n", chipver
));
9139 if (chipver
== 0x0) {
9140 DHD_ERROR(("----- CHIP bcm4335_A0 -----\n"));
9141 strcat(chipver_tag
, "_a0");
9142 } else if (chipver
== 0x1) {
9143 DHD_ERROR(("----- CHIP bcm4335_B0 -----\n"));
9144 #if defined(SUPPORT_MULTIPLE_CHIPS)
9145 strcat(chipver_tag
, "_b0");
9146 #endif /* defined(SUPPORT_MULTIPLE_CHIPS) */
9149 strcat(fw_path
, chipver_tag
);
9150 strcat(nv_path
, chipver_tag
);
9155 concate_revision_bcm4339(dhd_bus_t
*bus
, char *fw_path
, char *nv_path
)
9159 #if defined(SUPPORT_MULTIPLE_CHIPS)
9160 char chipver_tag
[10] = "_4339";
9162 char chipver_tag
[4] = {0, };
9163 #endif /* defined(SUPPORT_MULTIPLE_CHIPS) */
9165 DHD_TRACE(("%s: BCM4339 Multiple Revision Check\n", __FUNCTION__
));
9166 if (bus
->sih
->chip
!= BCM4339_CHIP_ID
) {
9167 DHD_ERROR(("%s:Chip is not BCM4339\n", __FUNCTION__
));
9170 chipver
= bus
->sih
->chiprev
;
9171 DHD_ERROR(("CHIP VER = [0x%x]\n", chipver
));
9172 if (chipver
== 0x1) {
9173 DHD_ERROR(("----- CHIP bcm4339_A0 -----\n"));
9174 strcat(chipver_tag
, "_a0");
9176 DHD_ERROR(("----- CHIP bcm4339 unknown revision %d -----\n",
9180 strcat(fw_path
, chipver_tag
);
9181 strcat(nv_path
, chipver_tag
);
9185 static int concate_revision_bcm4350(dhd_bus_t
*bus
, char *fw_path
, char *nv_path
)
9188 #if defined(SUPPORT_MULTIPLE_CHIPS)
9189 char chipver_tag
[10] = {0, };
9191 char chipver_tag
[4] = {0, };
9192 #endif /* defined(SUPPORT_MULTIPLE_CHIPS) */
9193 chip_ver
= bus
->sih
->chiprev
;
9195 #if defined(SUPPORT_MULTIPLE_CHIPS)
9197 strcat(chipver_tag
, "_4354");
9199 strcat(chipver_tag
, "_4350");
9202 if (chip_ver
== 3) {
9203 DHD_ERROR(("----- CHIP 4354 A0 -----\n"));
9204 strcat(chipver_tag
, "_a0");
9206 DHD_ERROR(("----- Unknown chip version, ver=%x -----\n", chip_ver
));
9209 strcat(fw_path
, chipver_tag
);
9210 strcat(nv_path
, chipver_tag
);
9214 static int concate_revision_bcm4354(dhd_bus_t
*bus
, char *fw_path
, char *nv_path
)
9217 #if defined(SUPPORT_MULTIPLE_CHIPS)
9218 char chipver_tag
[10] = "_4354";
9220 #if !defined(CUSTOMER_HW4)
9221 char chipver_tag
[4] = {0, };
9222 #endif /* !CUSTOMER_HW4 */
9223 #endif /* SUPPORT_MULTIPLE_CHIPS */
9225 chip_ver
= bus
->sih
->chiprev
;
9226 #if !defined(SUPPORT_MULTIPLE_CHIPS) && defined(CUSTOMER_HW4)
9227 DHD_INFO(("----- CHIP 4354, ver=%x -----\n", chip_ver
));
9229 if (chip_ver
== 1) {
9230 DHD_ERROR(("----- CHIP 4354 A1 -----\n"));
9231 strcat(chipver_tag
, "_a1");
9233 DHD_ERROR(("----- Unknown chip version, ver=%x -----\n", chip_ver
));
9236 strcat(fw_path
, chipver_tag
);
9237 strcat(nv_path
, chipver_tag
);
9238 #endif /* !SUPPORT_MULTIPLE_CHIPS && CUSTOMER_HW4 */
9243 #ifdef SUPPORT_MULTIPLE_CHIP_4345X
9245 concate_revision_bcm4345x(dhd_bus_t
*bus
,
9246 char *fw_path
, char *nv_path
)
9249 char chipver_tag
[10] = "_43454";
9251 chip_id
= bus
->sih
->chip
;
9253 if (chip_id
== BCM43454_CHIP_ID
) {
9254 DHD_ERROR(("----- CHIP 43454 -----\n"));
9255 strcat(fw_path
, chipver_tag
);
9256 strcat(nv_path
, chipver_tag
);
9257 } else if (chip_id
== BCM4345_CHIP_ID
) {
9258 DHD_ERROR(("----- CHIP 43455 -----\n"));
9260 DHD_ERROR(("----- Unknown chip , id r=%x -----\n", chip_id
));
9265 #else /* SUPPORT_MULTIPLE_CHIP_4345X */
9267 concate_revision_bcm43454(dhd_bus_t
*bus
, char *fw_path
, char *nv_path
)
9269 char chipver_tag
[10] = {0, };
9270 #ifdef SUPPORT_MULTIPLE_BOARD_REV_FROM_DT
9271 int base_system_rev_for_nv
= 0;
9272 #endif /* SUPPORT_MULTIPLE_BOARD_REV_FROM_DT */
9274 DHD_TRACE(("%s: BCM43454 Multiple Revision Check\n", __FUNCTION__
));
9275 if (bus
->sih
->chip
!= BCM43454_CHIP_ID
) {
9276 DHD_ERROR(("%s:Chip is not BCM43454!\n", __FUNCTION__
));
9279 #ifdef SUPPORT_MULTIPLE_BOARD_REV_FROM_DT
9280 base_system_rev_for_nv
= dhd_get_system_rev();
9281 if (base_system_rev_for_nv
> 0) {
9282 DHD_ERROR(("----- Board Rev [%d] -----\n", base_system_rev_for_nv
));
9283 sprintf(chipver_tag
, "_r%02d", base_system_rev_for_nv
);
9285 #endif /* SUPPORT_MULTIPLE_BOARD_REV_FROM_DT */
9286 #ifdef SUPPORT_MULTIPLE_BOARD_REV_FROM_HW
9287 DHD_ERROR(("----- Rev [%d] Fot MULTIPLE Board. -----\n", system_hw_rev
));
9288 if ((system_hw_rev
>= 8) && (system_hw_rev
<= 11)) {
9289 DHD_ERROR(("This HW is Rev 08 ~ 11. this is For FD-HW\n"));
9290 strcat(chipver_tag
, "_FD");
9292 #endif /* SUPPORT_MULTIPLE_BOARD_REV_FROM_HW */
9294 strcat(nv_path
, chipver_tag
);
9299 concate_revision_bcm43455(dhd_bus_t
*bus
, char *fw_path
, char *nv_path
)
9301 char chipver_tag
[10] = {0, };
9302 uint32 chip_rev
= 0;
9303 #ifdef SUPPORT_MULTIPLE_BOARD_REV_FROM_DT
9304 int base_system_rev_for_nv
= 0;
9305 #endif /* SUPPORT_MULTIPLE_BOARD_REV_FROM_DT */
9307 DHD_TRACE(("%s: BCM43455 Multiple Revision Check\n", __FUNCTION__
));
9308 if (bus
->sih
->chip
!= BCM4345_CHIP_ID
) {
9309 DHD_ERROR(("%s:Chip is not BCM43455!\n", __FUNCTION__
));
9313 chip_rev
= bus
->sih
->chiprev
;
9314 if (chip_rev
== 0x9) {
9315 DHD_ERROR(("----- CHIP 43456 -----\n"));
9316 strcat(fw_path
, "_c5");
9317 strcat(nv_path
, "_c5");
9319 DHD_ERROR(("----- CHIP 43455 -----\n"));
9321 #ifdef SUPPORT_MULTIPLE_BOARD_REV_FROM_DT
9322 base_system_rev_for_nv
= dhd_get_system_rev();
9323 if (base_system_rev_for_nv
> 0) {
9324 DHD_ERROR(("----- Board Rev [%d]-----\n", base_system_rev_for_nv
));
9325 sprintf(chipver_tag
, "_r%02d", base_system_rev_for_nv
);
9327 #endif /* SUPPORT_MULTIPLE_BOARD_REV_FROM_DT */
9328 strcat(nv_path
, chipver_tag
);
9331 #endif /* SUPPORT_MULTIPLE_CHIP_4345X */
9334 concate_revision(dhd_bus_t
*bus
, char *fw_path
, char *nv_path
)
9338 if (!bus
|| !bus
->sih
) {
9339 DHD_ERROR(("%s:Bus is Invalid\n", __FUNCTION__
));
9343 switch (bus
->sih
->chip
) {
9344 case BCM4335_CHIP_ID
:
9345 res
= concate_revision_bcm4335(bus
, fw_path
, nv_path
);
9347 case BCM4339_CHIP_ID
:
9348 res
= concate_revision_bcm4339(bus
, fw_path
, nv_path
);
9350 case BCM4350_CHIP_ID
:
9351 res
= concate_revision_bcm4350(bus
, fw_path
, nv_path
);
9353 case BCM4354_CHIP_ID
:
9354 res
= concate_revision_bcm4354(bus
, fw_path
, nv_path
);
9356 #ifdef SUPPORT_MULTIPLE_CHIP_4345X
9357 case BCM43454_CHIP_ID
:
9358 case BCM4345_CHIP_ID
:
9359 res
= concate_revision_bcm4345x(bus
, fw_path
, nv_path
);
9361 #else /* SUPPORT_MULTIPLE_CHIP_4345X */
9362 case BCM43454_CHIP_ID
:
9363 res
= concate_revision_bcm43454(bus
, fw_path
, nv_path
);
9365 case BCM4345_CHIP_ID
:
9366 res
= concate_revision_bcm43455(bus
, fw_path
, nv_path
);
9368 #endif /* SUPPORT_MULTIPLE_CHIP_4345X */
9371 DHD_ERROR(("REVISION SPECIFIC feature is not required\n"));
9379 #endif /* SUPPORT_MULTIPLE_REVISION */
9382 dhd_bus_update_fw_nv_path(struct dhd_bus
*bus
, char *pfw_path
, char *pnv_path
)
9384 bus
->fw_path
= pfw_path
;
9385 bus
->nv_path
= pnv_path
;
9389 dhd_enableOOB(dhd_pub_t
*dhd
, bool sleep
)
9391 dhd_bus_t
*bus
= dhd
->bus
;
9392 sdpcmd_regs_t
*regs
= bus
->regs
;
9396 dhdsdio_clkctl(bus
, CLK_AVAIL
, FALSE
);
9397 /* Tell device to start using OOB wakeup */
9398 W_SDREG(SMB_USE_OOB
, ®s
->tosbmailbox
, retries
);
9399 if (retries
> retry_limit
) {
9400 DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
9403 /* Turn off our contribution to the HT clock request */
9404 dhdsdio_clkctl(bus
, CLK_SDONLY
, FALSE
);
9406 /* Make sure the controller has the bus up */
9407 dhdsdio_clkctl(bus
, CLK_AVAIL
, FALSE
);
9409 /* Send misc interrupt to indicate OOB not needed */
9410 W_SDREG(0, ®s
->tosbmailboxdata
, retries
);
9411 if (retries
<= retry_limit
)
9412 W_SDREG(SMB_DEV_INT
, ®s
->tosbmailbox
, retries
);
9414 if (retries
> retry_limit
)
9415 DHD_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n"));
9417 /* Make sure we have SD bus access */
9418 dhdsdio_clkctl(bus
, CLK_SDONLY
, FALSE
);
9424 dhd_bus_pktq_flush(dhd_pub_t
*dhdp
)
9426 dhd_bus_t
*bus
= dhdp
->bus
;
9427 bool wlfc_enabled
= FALSE
;
9429 #ifdef PROP_TXSTATUS
9430 wlfc_enabled
= (dhd_wlfc_cleanup_txq(dhdp
, NULL
, 0) != WLFC_UNSUPPORTED
);
9432 if (!wlfc_enabled
) {
9433 #ifdef DHDTCPACK_SUPPRESS
9434 /* Clean tcp_ack_info_tbl in order to prevent access to flushed pkt,
9435 * when there is a newly coming packet from network stack.
9437 dhd_tcpack_info_tbl_clean(bus
->dhd
);
9438 #endif /* DHDTCPACK_SUPPRESS */
9439 /* Clear the data packet queues */
9440 pktq_flush(dhdp
->osh
, &bus
->txq
, TRUE
);
9446 dhd_sr_config(dhd_pub_t
*dhd
, bool on
)
9448 dhd_bus_t
*bus
= dhd
->bus
;
9453 return dhdsdio_clk_devsleep_iovar(bus
, on
);
9457 dhd_get_chipid(dhd_pub_t
*dhd
)
9459 dhd_bus_t
*bus
= dhd
->bus
;
9461 if (bus
&& bus
->sih
)
9462 return (uint16
)bus
->sih
->chip
;
9466 #endif /* BCMSDIO */
9470 dhd_sdio_reg_read(struct dhd_bus
*bus
, ulong addr
)
9474 dhd_os_sdlock(bus
->dhd
);
9478 dhdsdio_clkctl(bus
, CLK_AVAIL
, FALSE
);
9480 rval
= bcmsdh_reg_read(bus
->sdh
, addr
, 4);
9482 dhd_os_sdunlock(bus
->dhd
);
9488 dhd_sdio_reg_write(struct dhd_bus
*bus
, ulong addr
, uint32 val
)
9490 dhd_os_sdlock(bus
->dhd
);
9494 dhdsdio_clkctl(bus
, CLK_AVAIL
, FALSE
);
9496 bcmsdh_reg_write(bus
->sdh
, addr
, 4, val
);
9498 dhd_os_sdunlock(bus
->dhd
);
9501 #endif /* DEBUGGER */
9503 #if defined(BT_OVER_SDIO)
9504 uint8
dhd_bus_cfg_read(void *h
, uint fun_num
, uint32 addr
, int *err
)
9507 dhd_pub_t
*dhdp
= (dhd_pub_t
*)h
;
9508 dhd_bus_t
*bus
= (dhd_bus_t
*)dhdp
->bus
;
9510 dhd_os_sdlock(bus
->dhd
);
9512 intrd
= bcmsdh_cfg_read(bus
->sdh
, fun_num
, addr
, err
);
9514 dhd_os_sdunlock(bus
->dhd
);
9517 } EXPORT_SYMBOL(dhd_bus_cfg_read
);
9519 void dhd_bus_cfg_write(void *h
, uint fun_num
, uint32 addr
, uint8 val
, int *err
)
9521 dhd_pub_t
*dhdp
= (dhd_pub_t
*)h
;
9522 dhd_bus_t
*bus
= (dhd_bus_t
*)dhdp
->bus
;
9524 dhd_os_sdlock(bus
->dhd
);
9526 bcmsdh_cfg_write(bus
->sdh
, fun_num
, addr
, val
, err
);
9528 dhd_os_sdunlock(bus
->dhd
);
9530 } EXPORT_SYMBOL(dhd_bus_cfg_write
);
9533 extract_hex_field(char * line
, uint16 start_pos
, uint16 num_chars
, uint16
* value
)
9537 strncpy(field
, line
+ start_pos
, num_chars
);
9538 field
[num_chars
] = '\0';
9540 return (sscanf (field
, "%hX", value
) == 1);
9544 read_more_btbytes(struct dhd_bus
*bus
, void * file
, char *line
, int * addr_mode
, uint16
* hi_addr
,
9545 uint32
* dest_addr
, uint8
*data_bytes
, uint32
* num_bytes
)
9548 uint16 num_data_bytes
, addr
, data_pos
, type
, w
, i
;
9549 uint32 abs_base_addr32
= 0;
9554 str_len
= dhd_os_gets_image(bus
->dhd
, line
, BTFW_MAX_STR_LEN
, file
);
9556 DHD_TRACE(("%s: Len :0x%x %s\n", __FUNCTION__
, str_len
, line
));
9560 } else if (str_len
> 9) {
9561 extract_hex_field(line
, 1, 2, &num_data_bytes
);
9562 extract_hex_field(line
, 3, 4, &addr
);
9563 extract_hex_field(line
, 7, 2, &type
);
9566 for (i
= 0; i
< num_data_bytes
; i
++) {
9567 extract_hex_field(line
, data_pos
, 2, &w
);
9568 data_bytes
[i
] = (uint8
)(w
& 0x00FF);
9572 if (type
== BTFW_HEX_LINE_TYPE_EXTENDED_ADDRESS
) {
9573 *hi_addr
= (data_bytes
[0] << 8) | data_bytes
[1];
9574 *addr_mode
= BTFW_ADDR_MODE_EXTENDED
;
9575 } else if (type
== BTFW_HEX_LINE_TYPE_EXTENDED_SEGMENT_ADDRESS
) {
9576 *hi_addr
= (data_bytes
[0] << 8) | data_bytes
[1];
9577 *addr_mode
= BTFW_ADDR_MODE_SEGMENT
;
9578 } else if (type
== BTFW_HEX_LINE_TYPE_ABSOLUTE_32BIT_ADDRESS
) {
9579 abs_base_addr32
= (data_bytes
[0] << 24) | (data_bytes
[1] << 16) |
9580 (data_bytes
[2] << 8) | data_bytes
[3];
9581 *addr_mode
= BTFW_ADDR_MODE_LINEAR32
;
9582 } else if (type
== BTFW_HEX_LINE_TYPE_DATA
) {
9584 if (*addr_mode
== BTFW_ADDR_MODE_EXTENDED
)
9585 *dest_addr
+= (*hi_addr
<< 16);
9586 else if (*addr_mode
== BTFW_ADDR_MODE_SEGMENT
)
9587 *dest_addr
+= (*hi_addr
<< 4);
9588 else if (*addr_mode
== BTFW_ADDR_MODE_LINEAR32
)
9589 *dest_addr
+= abs_base_addr32
;
9590 *num_bytes
= num_data_bytes
;
9594 return (*num_bytes
> 0);
9598 _dhdsdio_download_btfw(struct dhd_bus
*bus
)
9602 uint8
*mem_blk
= NULL
, *mem_ptr
= NULL
, *data_ptr
= NULL
;
9604 uint32 offset_addr
= 0, offset_len
= 0, bytes_to_write
= 0;
9607 uint32 dest_addr
= 0, num_bytes
;
9608 uint16 hiAddress
= 0;
9609 uint32 start_addr
, start_data
, end_addr
, end_data
, i
, index
, pad
,
9612 int addr_mode
= BTFW_ADDR_MODE_EXTENDED
;
9614 /* Out immediately if no image to download */
9615 if ((bus
->btfw_path
== NULL
) || (bus
->btfw_path
[0] == '\0')) {
9619 image
= dhd_os_open_image1(bus
->dhd
, bus
->btfw_path
);
9623 mem_ptr
= mem_blk
= MALLOC(bus
->dhd
->osh
, BTFW_DOWNLOAD_BLK_SIZE
+ DHD_SDALIGN
);
9624 if (mem_blk
== NULL
) {
9625 DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__
,
9626 BTFW_DOWNLOAD_BLK_SIZE
+ DHD_SDALIGN
));
9629 if ((uint32
)(uintptr
)mem_blk
% DHD_SDALIGN
)
9630 mem_ptr
+= (DHD_SDALIGN
- ((uint32
)(uintptr
)mem_blk
% DHD_SDALIGN
));
9632 data_ptr
= MALLOC(bus
->dhd
->osh
, BTFW_DOWNLOAD_BLK_SIZE
- 8);
9633 if (data_ptr
== NULL
) {
9634 DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__
,
9635 BTFW_DOWNLOAD_BLK_SIZE
- 8));
9638 /* Write to BT register to hold WLAN wake high during BT FW download */
9639 bt2wlan_pwrup_adr
= BTMEM_OFFSET
+ BT2WLAN_PWRUP_ADDR
;
9640 bcmsdh_reg_write(bus
->sdh
, bt2wlan_pwrup_adr
, 4, BT2WLAN_PWRUP_WAKE
);
9642 * Wait for at least 2msec for the clock to be ready/Available.
9646 line
= MALLOC(bus
->dhd
->osh
, BTFW_MAX_STR_LEN
);
9648 DHD_ERROR(("%s: Failed to allocate memory %d bytes\n",
9649 __FUNCTION__
, BTFW_MAX_STR_LEN
));
9652 memset(line
, 0, BTFW_MAX_STR_LEN
);
9654 while (read_more_btbytes (bus
, image
, line
, &addr_mode
, &hiAddress
, &dest_addr
,
9655 data_ptr
, &num_bytes
)) {
9657 DHD_TRACE(("read %d bytes at address %08X\n", num_bytes
, dest_addr
));
9659 start_addr
= BTMEM_OFFSET
+ dest_addr
;
9662 /* Make sure the start address is 4 byte aligned to avoid alignment issues
9663 * with SD host controllers
9665 if (!ISALIGNED(start_addr
, 4)) {
9666 pad
= start_addr
% 4;
9667 start_addr
= ROUNDDN(start_addr
, 4);
9668 start_data
= bcmsdh_reg_read(bus
->sdh
, start_addr
, 4);
9669 for (i
= 0; i
< pad
; i
++, index
++) {
9670 mem_ptr
[index
] = (uint8
)((uint8
*)&start_data
)[i
];
9673 bcopy(data_ptr
, &(mem_ptr
[index
]), num_bytes
);
9676 /* Make sure the length is multiple of 4bytes to avoid alignment issues
9677 * with SD host controllers
9679 end_addr
= start_addr
+ index
;
9680 if (!ISALIGNED(end_addr
, 4)) {
9681 end_addr
= ROUNDDN(end_addr
, 4);
9682 end_data
= bcmsdh_reg_read(bus
->sdh
, end_addr
, 4);
9683 for (i
= (index
% 4); i
< 4; i
++, index
++) {
9684 mem_ptr
[index
] = (uint8
)((uint8
*)&end_data
)[i
];
9688 offset_addr
= start_addr
& 0xFFF;
9689 offset_len
= offset_addr
+ index
;
9690 if (offset_len
<= 0x1000) {
9691 bcm_error
= dhdsdio_membytes(bus
, TRUE
, start_addr
, mem_ptr
, index
);
9693 DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
9694 __FUNCTION__
, bcm_error
, num_bytes
, start_addr
));
9699 bytes_to_write
= 0x1000 - offset_addr
;
9700 bcm_error
= dhdsdio_membytes(bus
, TRUE
, start_addr
, mem_ptr
,
9703 DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
9704 __FUNCTION__
, bcm_error
, num_bytes
, start_addr
));
9710 bcm_error
= dhdsdio_membytes(bus
, TRUE
, (start_addr
+ bytes_to_write
),
9711 (mem_ptr
+ bytes_to_write
), (index
- bytes_to_write
));
9713 DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
9714 __FUNCTION__
, bcm_error
, num_bytes
, start_addr
));
9718 memset(line
, 0, BTFW_MAX_STR_LEN
);
9724 MFREE(bus
->dhd
->osh
, mem_blk
, BTFW_DOWNLOAD_BLK_SIZE
+ DHD_SDALIGN
);
9727 MFREE(bus
->dhd
->osh
, data_ptr
, BTFW_DOWNLOAD_BLK_SIZE
- 8);
9730 MFREE(bus
->dhd
->osh
, line
, BTFW_MAX_STR_LEN
);
9733 dhd_os_close_image1(bus
->dhd
, image
);
9739 dhdsdio_download_btfw(struct dhd_bus
*bus
, osl_t
*osh
, void *sdh
)
9743 DHD_TRACE(("%s: btfw path=%s\n",
9744 __FUNCTION__
, bus
->btfw_path
));
9745 DHD_OS_WAKE_LOCK(bus
->dhd
);
9746 dhd_os_sdlock(bus
->dhd
);
9748 /* Download the firmware */
9749 ret
= _dhdsdio_download_btfw(bus
);
9751 dhd_os_sdunlock(bus
->dhd
);
9752 DHD_OS_WAKE_UNLOCK(bus
->dhd
);
9758 dhd_bus_download_btfw(struct dhd_bus
*bus
, osl_t
*osh
,
9763 bus
->btfw_path
= pbtfw_path
;
9765 ret
= dhdsdio_download_btfw(bus
, osh
, bus
->sdh
);
9769 #endif /* defined (BT_OVER_SDIO) */
9772 dhd_bus_dump_trap_info(dhd_bus_t
*bus
, struct bcmstrbuf
*strbuf
)
9774 trap_t
*tr
= &bus
->dhd
->last_trap_info
;
9777 "Dongle trap type 0x%x @ epc 0x%x, cpsr 0x%x, spsr 0x%x, sp 0x%x,"
9778 "lp 0x%x, rpc 0x%x Trap offset 0x%x, "
9779 "r0 0x%x, r1 0x%x, r2 0x%x, r3 0x%x, "
9780 "r4 0x%x, r5 0x%x, r6 0x%x, r7 0x%x\n\n",
9781 ltoh32(tr
->type
), ltoh32(tr
->epc
), ltoh32(tr
->cpsr
), ltoh32(tr
->spsr
),
9782 ltoh32(tr
->r13
), ltoh32(tr
->r14
), ltoh32(tr
->pc
),
9783 ltoh32(bus
->dongle_trap_addr
),
9784 ltoh32(tr
->r0
), ltoh32(tr
->r1
), ltoh32(tr
->r2
), ltoh32(tr
->r3
),
9785 ltoh32(tr
->r4
), ltoh32(tr
->r5
), ltoh32(tr
->r6
), ltoh32(tr
->r7
));
9790 dhd_bcmsdh_send_buffer(void *bus
, uint8
*frame
, uint16 len
)
9794 ret
= dhd_bcmsdh_send_buf(bus
, bcmsdh_cur_sbwad(((dhd_bus_t
*)bus
)->sdh
),
9795 SDIO_FUNC_2
, F2SYNC
, frame
, len
, NULL
, NULL
, NULL
, TXRETRIES
);
9798 ((dhd_bus_t
*)bus
)->tx_seq
= (((dhd_bus_t
*)bus
)->tx_seq
+ 1) % SDPCM_SEQUENCE_WRAP
;
9803 /* Function to set the min res mask depending on the chip ID used */
9805 dhd_bus_set_default_min_res_mask(struct dhd_bus
*bus
)
9807 if ((bus
== NULL
) || (bus
->sih
== NULL
)) {
9808 DHD_ERROR(("%s(): Invalid Arguments \r\n", __FUNCTION__
));
9812 switch (bus
->sih
->chip
) {
9813 case BCM4339_CHIP_ID
:
9814 bcmsdh_reg_write(bus
->sdh
, SI_ENUM_BASE(bus
->sih
) + 0x618, 4, 0x3fcaf377);
9815 if (bcmsdh_regfail(bus
->sdh
)) {
9816 DHD_ERROR(("%s:%d Setting min_res_mask failed\n", __FUNCTION__
, __LINE__
));
9821 case BCM43012_CHIP_ID
:
9822 bcmsdh_reg_write(bus
->sdh
,
9823 si_get_pmu_reg_addr(bus
->sih
, OFFSETOF(pmuregs_t
, min_res_mask
)),
9824 4, DEFAULT_43012_MIN_RES_MASK
);
9825 if (bcmsdh_regfail(bus
->sdh
)) {
9826 DHD_ERROR(("%s:%d Setting min_res_mask failed\n", __FUNCTION__
, __LINE__
));
9832 DHD_ERROR(("%s: Unhandled chip id\n", __FUNCTION__
));
9839 /* Function to reset PMU registers */
9841 dhd_bus_pmu_reg_reset(dhd_pub_t
*dhdp
)
9843 struct dhd_bus
*bus
= dhdp
->bus
;
9844 bcmsdh_reg_write(bus
->sdh
, si_get_pmu_reg_addr(bus
->sih
,
9845 OFFSETOF(pmuregs_t
, swscratch
)), 4, 0x0);
9846 if (bcmsdh_regfail(bus
->sdh
)) {
9847 DHD_ERROR(("%s:%d Setting min_res_mask failed\n", __FUNCTION__
, __LINE__
));
9853 /* Function to disable console messages on entering ULP mode */
9855 dhd_bus_ulp_disable_console(dhd_pub_t
*dhdp
)
9858 DHD_ERROR(("Flushing and disabling console messages\n"));
9860 /* Save the console print interval */
9861 dhd_ulp_save_console_interval(dhdp
);
9863 /* Flush the console buffer before disabling */
9864 dhdsdio_readconsole(dhdp
->bus
);
9865 dhdp
->dhd_console_ms
= 0;
9866 #endif /* DHD_DEBUG */
9869 /* Function for redownloading firmaware */
9871 dhd_bus_ulp_reinit_fw(dhd_bus_t
*bus
)
9875 /* After firmware redownload tx/rx seq are reset accordingly these values are
9876 reset on DHD side tx_max is initially set to 4, which later is updated by FW
9878 bus
->tx_seq
= bus
->rx_seq
= 0;
9881 if (dhd_bus_download_firmware(bus
, bus
->dhd
->osh
,
9882 bus
->fw_path
, bus
->nv_path
) >= 0) {
9884 /* Re-init bus, enable F2 transfer */
9885 bcmerror
= dhd_bus_init((dhd_pub_t
*) bus
->dhd
, FALSE
);
9886 if (bcmerror
== BCME_OK
) {
9887 bus
->dhd
->up
= TRUE
;
9888 dhd_os_wd_timer(bus
->dhd
, dhd_watchdog_ms
);
9890 dhd_ulp_set_ulp_state(bus
->dhd
, DHD_ULP_READY
);
9891 #if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
9892 dhd_enable_oob_intr(bus
, TRUE
);
9893 bcmsdh_oob_intr_set(bus
->sdh
, TRUE
);
9894 #endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */
9896 /* Re-enable the console messages on FW redownload to default value */
9897 dhd_ulp_restore_console_interval(bus
->dhd
);
9898 #endif /* DHD_DEBUG */
9900 DHD_ERROR(("bus init failed\n"));
9901 dhd_bus_stop(bus
, FALSE
);
9902 dhdsdio_release_dongle(bus
, bus
->dhd
->osh
,
9906 bcmerror
= BCME_SDIO_ERROR
;
9910 #endif /* DHD_ULP */
9913 dhd_bus_readwrite_bp_addr(dhd_pub_t
*dhdp
, uint addr
, uint size
, uint
* data
, bool read
)
9916 struct dhd_bus
*bus
= dhdp
->bus
;
9919 *data
= (int32
)bcmsdh_reg_read(bus
->sdh
, addr
, size
);
9921 bcmsdh_reg_write(bus
->sdh
, addr
, size
, *data
);
9924 if (bcmsdh_regfail(bus
->sdh
))
9925 bcmerror
= BCME_SDIO_ERROR
;
9930 int dhd_get_idletime(dhd_pub_t
*dhd
)
9932 return dhd
->bus
->idletime
;
9935 #ifdef DHD_WAKE_STATUS
9937 dhd_bus_get_wakecount(dhd_pub_t
*dhd
)
9939 return &dhd
->bus
->wake_counts
;
9942 dhd_bus_get_bus_wake(dhd_pub_t
*dhd
)
9944 return bcmsdh_set_get_wake(dhd
->bus
->sdh
, 0);
9946 #endif /* DHD_WAKE_STATUS */