source: G950FXXS5DSI1
[GitHub/exynos8895/android_kernel_samsung_universal8895.git] / drivers / net / wireless / bcmdhd4361 / dhd_sdio.c
CommitLineData
1cac41cb
MB
1/*
2 * DHD Bus Module for SDIO
3 *
4 * Copyright (C) 1999-2019, Broadcom.
5 *
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:
11 *
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.
19 *
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.
23 *
24 *
25 * <<Broadcom-WL-IPTag/Open:>>
26 *
5a068558 27 * $Id: dhd_sdio.c 814373 2019-04-11 02:01:55Z $
1cac41cb
MB
28 */
29
30#include <typedefs.h>
31#include <osl.h>
32#include <bcmsdh.h>
33
34#include <bcmdefs.h>
35#include <bcmutils.h>
36#include <bcmendian.h>
37#include <bcmdevs.h>
38
39#include <siutils.h>
40#include <hndpmu.h>
41#include <hndsoc.h>
42#include <bcmsdpcm.h>
43#include <hnd_armtrap.h>
44#include <hnd_cons.h>
45#include <sbchipc.h>
46#include <sbhnddma.h>
47
48#include <sdio.h>
49#ifdef BCMSPI
50#include <spid.h>
51#endif /* BCMSPI */
52#include <sbsdio.h>
53#include <sbsdpcmdev.h>
54#include <bcmsdpcm.h>
55#include <bcmsdbus.h>
56
57#include <ethernet.h>
58#include <802.1d.h>
59#include <802.11.h>
60
61#include <dngl_stats.h>
62#include <dhd.h>
63#include <dhd_bus.h>
64#include <dhd_proto.h>
65#include <dhd_dbg.h>
66#include <dhdioctl.h>
67#include <sdiovar.h>
68
69#ifdef PROP_TXSTATUS
70#include <dhd_wlfc.h>
71#endif // endif
72#ifdef DHDTCPACK_SUPPRESS
73#include <dhd_ip.h>
74#endif /* DHDTCPACK_SUPPRESS */
75
76#ifdef BT_OVER_SDIO
77#include <dhd_bt_interface.h>
78#endif /* BT_OVER_SDIO */
79
80#if defined(DEBUGGER) || defined(DHD_DSCOPE)
81#include <debugger.h>
82#endif /* DEBUGGER || DHD_DSCOPE */
83
84bool dhd_mp_halting(dhd_pub_t *dhdp);
85extern void bcmsdh_waitfor_iodrain(void *sdh);
86extern void bcmsdh_reject_ioreqs(void *sdh, bool reject);
87extern bool bcmsdh_fatal_error(void *sdh);
88static int dhdsdio_suspend(void *context);
89static int dhdsdio_resume(void *context);
90
91#ifndef DHDSDIO_MEM_DUMP_FNAME
92#define DHDSDIO_MEM_DUMP_FNAME "mem_dump"
93#endif // endif
94
95#define QLEN (1024) /* bulk rx and tx queue lengths */
96#define FCHI (QLEN - 10)
97#define FCLOW (FCHI / 2)
98#define PRIOMASK 7
99
100#define F0_BLOCK_SIZE 32
101#define TXRETRIES 2 /* # of retries for tx frames */
102#define READ_FRM_CNT_RETRIES 3
103#ifndef DHD_RXBOUND
104#define DHD_RXBOUND 50 /* Default for max rx frames in one scheduling */
105#endif // endif
106
107#ifndef DHD_TXBOUND
108#define DHD_TXBOUND 20 /* Default for max tx frames in one scheduling */
109#endif // endif
110
111#define DHD_TXMINMAX 1 /* Max tx frames if rx still pending */
112
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 */
115
116#define MAX_DATA_BUF (64 * 1024) /* Must be large enough to hold biggest possible glom */
117
118#ifndef DHD_FIRSTREAD
119#define DHD_FIRSTREAD 32
120#endif // endif
121#if !ISPOWEROF2(DHD_FIRSTREAD)
122#error DHD_FIRSTREAD is not a power of 2!
123#endif // endif
124
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
129
130#ifdef SDTEST
131#define SDPCM_RESERVE (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN)
132#else
133#define SDPCM_RESERVE (SDPCM_HDRLEN + DHD_SDALIGN)
134#endif // endif
135
136/* Space for header read, limit for data packets */
137#ifndef MAX_HDR_READ
138#define MAX_HDR_READ 32
139#endif // endif
140#if !ISPOWEROF2(MAX_HDR_READ)
141#error MAX_HDR_READ is not a power of 2!
142#endif // endif
143
144#define MAX_RX_DATASZ 2048
145
146/* Maximum milliseconds to wait for F2 to come up */
147#define DHD_WAIT_F2RDY 3000
148
149/* Maximum usec to wait for HTAVAIL to come up */
150#define DHD_WAIT_HTAVAIL 10000
151
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).
156 */
157#if (PMU_MAX_TRANSITION_DLY <= 1000000)
158#undef PMU_MAX_TRANSITION_DLY
159#define PMU_MAX_TRANSITION_DLY 1000000
160#endif // endif
161
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
166#endif // endif
167
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)
171
172/* Flags for SDH calls */
173#define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED)
174
175/* Packet free applicable unconditionally for sdio and sdspi. Conditional if
176 * bufpool was present for gspi bus.
177 */
178#define PKTFREE2() if ((bus->bus != SPI_BUS) || bus->usebufpool) \
179 PKTFREE(bus->dhd->osh, pkt, FALSE);
180DHD_SPINWAIT_SLEEP_INIT(sdioh_spinwait_sleep);
181
182#if defined(MULTIPLE_SUPPLICANT)
183#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
184DEFINE_MUTEX(_dhd_sdio_mutex_lock_);
185#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
186#endif // endif
187
188#ifdef SUPPORT_MULTIPLE_BOARD_REV_FROM_HW
189extern unsigned int system_hw_rev;
190#endif /* SUPPORT_MULTIPLE_BOARD_REV_FROM_HW */
191
192/* Device console log buffer state */
193#define CONSOLE_LINE_MAX 192
194#define CONSOLE_BUFFER_MAX 2024
195typedef 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 */
202} dhd_console_t;
203
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))
209
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)
215
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
224
225#define CC_PMUCC3 (0x3)
226
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 */
232
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 */
238
239#define BTFW_MAX_STR_LEN 600
240#define BTFW_DOWNLOAD_BLK_SIZE (BTFW_MAX_STR_LEN/2 + 8)
241
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
246
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
252
253#endif /* defined (BT_OVER_SDIO) */
254
5a068558
MB
255#define SBSDIO_CIS_TINY_SIZE_LIMIT 26
256
1cac41cb
MB
257/* Private data for SDIO bus interaction */
258typedef struct dhd_bus {
259 dhd_pub_t *dhd;
260
261 bcmsdh_info_t *sdh; /* Handle for BCMSDH calls */
262 si_t *sih; /* Handle for SI calls */
263 char *vars; /* Variables (from CIS and/or other) */
264 uint varsz; /* Size of variables buffer */
265 uint32 sbaddr; /* Current SB window pointer (-1, invalid) */
266
267 sdpcmd_regs_t *regs; /* Registers for SDIO core */
268 uint sdpcmrev; /* SDIO core revision */
269 uint armrev; /* CPU core revision */
270 uint ramrev; /* SOCRAM core revision */
271 uint32 ramsize; /* Size of RAM in SOCRAM (bytes) */
272 uint32 orig_ramsize; /* Size of RAM in SOCRAM (bytes) */
273 uint32 srmemsize; /* Size of SRMEM */
274
275 uint32 bus; /* gSPI or SDIO bus */
276 uint32 bus_num; /* bus number */
277 uint32 slot_num; /* slot ID */
278 uint32 hostintmask; /* Copy of Host Interrupt Mask */
279 uint32 intstatus; /* Intstatus bits (events) pending */
280 bool dpc_sched; /* Indicates DPC schedule (intrpt rcvd) */
281 bool fcstate; /* State of dongle flow-control */
282
283 uint16 cl_devid; /* cached devid for dhdsdio_probe_attach() */
284 char *fw_path; /* module_param: path to firmware image */
285 char *nv_path; /* module_param: path to nvram vars file */
286
287 uint blocksize; /* Block size of SDIO transfers */
288 uint roundup; /* Max roundup limit */
289
290 struct pktq txq; /* Queue length used for flow-control */
291 uint8 flowcontrol; /* per prio flow control bitmask */
292 uint8 tx_seq; /* Transmit sequence number (next) */
293 uint8 tx_max; /* Maximum transmit sequence allowed */
294
295 uint8 hdrbuf[MAX_HDR_READ + DHD_SDALIGN];
296 uint8 *rxhdr; /* Header of current rx frame (in hdrbuf) */
297 uint16 nextlen; /* Next Read Len from last header */
298 uint8 rx_seq; /* Receive sequence number (expected) */
299 bool rxskip; /* Skip receive (awaiting NAK ACK) */
300
301 void *glomd; /* Packet containing glomming descriptor */
302 void *glom; /* Packet chain for glommed superframe */
303 uint glomerr; /* Glom packet read errors */
304
305 uint8 *rxbuf; /* Buffer for receiving control packets */
306 uint rxblen; /* Allocated length of rxbuf */
307 uint8 *rxctl; /* Aligned pointer into rxbuf */
308 uint8 *databuf; /* Buffer for receiving big glom packet */
309 uint8 *dataptr; /* Aligned pointer into databuf */
310 uint rxlen; /* Length of valid data in buffer */
311
312 uint8 sdpcm_ver; /* Bus protocol reported by dongle */
313
314 bool intr; /* Use interrupts */
315 bool poll; /* Use polling */
316 bool ipend; /* Device interrupt is pending */
317 bool intdis; /* Interrupts disabled by isr */
318 uint intrcount; /* Count of device interrupt callbacks */
319 uint lastintrs; /* Count as of last watchdog timer */
320 uint spurious; /* Count of spurious interrupts */
321 uint pollrate; /* Ticks between device polls */
322 uint polltick; /* Tick counter */
323 uint pollcnt; /* Count of active polls */
324
325 dhd_console_t console; /* Console output polling support */
326 uint console_addr; /* Console address from shared struct */
327
328 uint regfails; /* Count of R_REG/W_REG failures */
329
330 uint clkstate; /* State of sd and backplane clock(s) */
331 bool activity; /* Activity flag for clock down */
332 int32 idletime; /* Control for activity timeout */
333 int32 idlecount; /* Activity timeout counter */
334 int32 idleclock; /* How to set bus driver when idle */
335 int32 sd_divisor; /* Speed control to bus driver */
336 int32 sd_mode; /* Mode control to bus driver */
337 int32 sd_rxchain; /* If bcmsdh api accepts PKT chains */
338 bool use_rxchain; /* If dhd should use PKT chains */
339 bool sleeping; /* Is SDIO bus sleeping? */
340#if defined(SUPPORT_P2P_GO_PS)
341 wait_queue_head_t bus_sleep;
342#endif /* LINUX && SUPPORT_P2P_GO_PS */
343 uint rxflow_mode; /* Rx flow control mode */
344 bool rxflow; /* Is rx flow control on */
345 uint prev_rxlim_hit; /* Is prev rx limit exceeded (per dpc schedule) */
346 bool alp_only; /* Don't use HT clock (ALP only) */
347 /* Field to decide if rx of control frames happen in rxbuf or lb-pool */
348 bool usebufpool;
349 int32 txinrx_thres; /* num of in-queued pkts */
350 int32 dotxinrx; /* tx first in dhdsdio_readframes */
351#ifdef SDTEST
352 /* external loopback */
353 bool ext_loop;
354 uint8 loopid;
355
356 /* pktgen configuration */
357 uint pktgen_freq; /* Ticks between bursts */
358 uint pktgen_count; /* Packets to send each burst */
359 uint pktgen_print; /* Bursts between count displays */
360 uint pktgen_total; /* Stop after this many */
361 uint pktgen_minlen; /* Minimum packet data len */
362 uint pktgen_maxlen; /* Maximum packet data len */
363 uint pktgen_mode; /* Configured mode: tx, rx, or echo */
364 uint pktgen_stop; /* Number of tx failures causing stop */
365
366 /* active pktgen fields */
367 uint pktgen_tick; /* Tick counter for bursts */
368 uint pktgen_ptick; /* Burst counter for printing */
369 uint pktgen_sent; /* Number of test packets generated */
370 uint pktgen_rcvd; /* Number of test packets received */
371 uint pktgen_prev_time; /* Time at which previous stats where printed */
372 uint pktgen_prev_sent; /* Number of test packets generated when
373 * previous stats were printed
374 */
375 uint pktgen_prev_rcvd; /* Number of test packets received when
376 * previous stats were printed
377 */
378 uint pktgen_fail; /* Number of failed send attempts */
379 uint16 pktgen_len; /* Length of next packet to send */
380#define PKTGEN_RCV_IDLE (0)
381#define PKTGEN_RCV_ONGOING (1)
382 uint16 pktgen_rcv_state; /* receive state */
383 uint pktgen_rcvd_rcvsession; /* test pkts rcvd per rcv session. */
384#endif /* SDTEST */
385
386 /* Some additional counters */
387 uint tx_sderrs; /* Count of tx attempts with sd errors */
388 uint fcqueued; /* Tx packets that got queued */
389 uint rxrtx; /* Count of rtx requests (NAK to dongle) */
390 uint rx_toolong; /* Receive frames too long to receive */
391 uint rxc_errors; /* SDIO errors when reading control frames */
392 uint rx_hdrfail; /* SDIO errors on header reads */
393 uint rx_badhdr; /* Bad received headers (roosync?) */
394 uint rx_badseq; /* Mismatched rx sequence number */
395 uint fc_rcvd; /* Number of flow-control events received */
396 uint fc_xoff; /* Number which turned on flow-control */
397 uint fc_xon; /* Number which turned off flow-control */
398 uint rxglomfail; /* Failed deglom attempts */
399 uint rxglomframes; /* Number of glom frames (superframes) */
400 uint rxglompkts; /* Number of packets from glom frames */
401 uint f2rxhdrs; /* Number of header reads */
402 uint f2rxdata; /* Number of frame data reads */
403 uint f2txdata; /* Number of f2 frame writes */
404 uint f1regdata; /* Number of f1 register accesses */
405 wake_counts_t wake_counts; /* Wake up counter */
406#ifdef BCMSPI
407 bool dwordmode;
408#endif /* BCMSPI */
409#ifdef DHDENABLE_TAILPAD
410 uint tx_tailpad_chain; /* Number of tail padding by chaining pad_pkt */
411 uint tx_tailpad_pktget; /* Number of tail padding by new PKTGET */
412#endif /* DHDENABLE_TAILPAD */
413 uint8 *ctrl_frame_buf;
414 uint32 ctrl_frame_len;
415 bool ctrl_frame_stat;
416#ifndef BCMSPI
417 uint32 rxint_mode; /* rx interrupt mode */
418#endif /* BCMSPI */
419 bool remap; /* Contiguous 1MB RAM: 512K socram + 512K devram
420 * Available with socram rev 16
421 * Remap region not DMA-able
422 */
423 bool kso;
424 bool _slpauto;
425 bool _oobwakeup;
426 bool _srenab;
427 bool readframes;
428 bool reqbussleep;
429 uint32 resetinstr;
430 uint32 dongle_ram_base;
431
432 void *glom_pkt_arr[SDPCM_MAXGLOM_SIZE]; /* Array of pkts for glomming */
433 uint32 txglom_cnt; /* Number of pkts in the glom array */
434 uint32 txglom_total_len; /* Total length of pkts in glom array */
435 bool txglom_enable; /* Flag to indicate whether tx glom is enabled/disabled */
436 uint32 txglomsize; /* Glom size limitation */
437#ifdef DHDENABLE_TAILPAD
438 void *pad_pkt;
439#endif /* DHDENABLE_TAILPAD */
440 uint32 dongle_trap_addr; /* device trap addr location in device memory */
441#if defined(BT_OVER_SDIO)
442 char *btfw_path; /* module_param: path to BT firmware image */
443 uint32 bt_use_count; /* Counter that tracks whether BT is using the bus */
444#endif /* defined (BT_OVER_SDIO) */
445} dhd_bus_t;
446
447/*
448 * Whenever DHD_IDLE_IMMEDIATE condition is handled, we have to now check if
449 * BT is active too. Instead of adding #ifdef code in all the places, we thought
450 * of adding one macro check as part of the if condition that checks for DHD_IDLE_IMMEDIATE
451 * In case of non BT over SDIO builds, this macro will always return TRUE. In case
452 * of the builds where BT_OVER_SDIO is enabled, it will expand to a condition check
453 * that checks if bt_use_count is zero. So this macro will return equate to 1 if
454 * bt_use_count is 0, indicating that there are no active users and if bt_use_count
455 * is non zero it would return 0 there by preventing the caller from executing the
456 * sleep calls.
457 */
458#ifdef BT_OVER_SDIO
459#define NO_OTHER_ACTIVE_BUS_USER(bus) (bus->bt_use_count == 0)
460#else
461#define NO_OTHER_ACTIVE_BUS_USER(bus) (1)
462#endif /* BT_OVER_SDIO */
463
464/* clkstate */
465#define CLK_NONE 0
466#define CLK_SDONLY 1
467#define CLK_PENDING 2 /* Not used yet */
468#define CLK_AVAIL 3
469
470#define DHD_NOPMU(dhd) (FALSE)
471
472#if defined(BCMSDIOH_STD)
473#define BLK_64_MAXTXGLOM 20
474#endif /* BCMSDIOH_STD */
475
476#ifdef DHD_DEBUG
477static int qcount[NUMPRIO];
478static int tx_packets[NUMPRIO];
479#endif /* DHD_DEBUG */
480
481/* Deferred transmit */
482const uint dhd_deferred_tx = 1;
483
484extern uint dhd_watchdog_ms;
485extern uint sd_f1_blocksize;
486
487#ifdef BCMSPI_ANDROID
488extern uint *dhd_spi_lockcount;
489#endif /* BCMSPI_ANDROID */
490
491extern void dhd_os_wd_timer(void *bus, uint wdtick);
492int dhd_enableOOB(dhd_pub_t *dhd, bool sleep);
493
494#ifdef DHD_PM_CONTROL_FROM_FILE
495extern bool g_pm_control;
496#endif /* DHD_PM_CONTROL_FROM_FILE */
497
498/* Tx/Rx bounds */
499uint dhd_txbound;
500uint dhd_rxbound;
501uint dhd_txminmax = DHD_TXMINMAX;
502
503/* override the RAM size if possible */
504#define DONGLE_MIN_RAMSIZE (128 *1024)
505int dhd_dongle_ramsize;
506
507uint dhd_doflow = TRUE;
508uint dhd_dpcpoll = FALSE;
509
510module_param(dhd_doflow, uint, 0644);
511module_param(dhd_dpcpoll, uint, 0644);
512
513static bool dhd_alignctl;
514
515static bool sd1idle;
516
517static bool retrydata;
518#define RETRYCHAN(chan) (((chan) == SDPCM_EVENT_CHANNEL) || retrydata)
519
520#ifdef BCMSPI
521/* At a watermark around 8 the spid hits underflow error. */
522static uint watermark = 32;
523static uint mesbusyctrl = 0;
524#else
525static uint watermark = 8;
526static uint mesbusyctrl = 0;
527#endif /* BCMSPI */
528static const uint firstread = DHD_FIRSTREAD;
529
530/* Retry count for register access failures */
531static const uint retry_limit = 2;
532
533/* Force even SD lengths (some host controllers mess up on odd bytes) */
534static bool forcealign;
535
536#if defined(DEBUGGER)
537static uint32 dhd_sdio_reg_read(struct dhd_bus *bus, ulong addr);
538static void dhd_sdio_reg_write(struct dhd_bus *bus, ulong addr, uint32 val);
539
540/** the debugger layer will call back into this (bus) layer to read/write dongle memory */
541static struct dhd_dbg_bus_ops_s bus_ops = {
542 .read_u16 = NULL,
543 .read_u32 = dhd_sdio_reg_read,
544 .write_u32 = dhd_sdio_reg_write,
545};
546#endif /* DEBUGGER */
547
548#define ALIGNMENT 4
549
550#if defined(OOB_INTR_ONLY) && defined(HW_OOB)
551extern void bcmsdh_enable_hw_oob_intr(void *sdh, bool enable);
552#endif // endif
553
554#if defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD)
555#error OOB_INTR_ONLY is NOT working with SDIO_ISR_THREAD
556#endif /* defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD) */
557#define PKTALIGN(osh, p, len, align) \
558 do { \
559 uintptr datalign; \
560 datalign = (uintptr)PKTDATA((osh), (p)); \
561 datalign = ROUNDUP(datalign, (align)) - datalign; \
562 ASSERT(datalign < (align)); \
563 ASSERT(PKTLEN((osh), (p)) >= ((len) + datalign)); \
564 if (datalign) \
565 PKTPULL((osh), (p), (uint)datalign); \
566 PKTSETLEN((osh), (p), (len)); \
567 } while (0)
568
569/* Limit on rounding up frames */
570static const uint max_roundup = 512;
571
572/* Try doing readahead */
573static bool dhd_readahead;
574
575/* To check if there's window offered */
576#define DATAOK(bus) \
577 (((uint8)(bus->tx_max - bus->tx_seq) > 1) && \
578 (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0))
579
580/* To check if there's window offered for ctrl frame */
581#define TXCTLOK(bus) \
582 (((uint8)(bus->tx_max - bus->tx_seq) != 0) && \
583 (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0))
584
585/* Number of pkts available in dongle for data RX */
586#define DATABUFCNT(bus) \
587 ((uint8)(bus->tx_max - bus->tx_seq) - 1)
588
589/* Macros to get register read/write status */
590/* NOTE: these assume a local dhdsdio_bus_t *bus! */
591#define R_SDREG(regvar, regaddr, retryvar) \
592do { \
593 retryvar = 0; \
594 do { \
595 regvar = R_REG(bus->dhd->osh, regaddr); \
596 } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \
597 if (retryvar) { \
598 bus->regfails += (retryvar-1); \
599 if (retryvar > retry_limit) { \
600 DHD_ERROR(("%s: FAILED" #regvar "READ, LINE %d\n", \
601 __FUNCTION__, __LINE__)); \
602 regvar = 0; \
603 } \
604 } \
605} while (0)
606
607#define W_SDREG(regval, regaddr, retryvar) \
608do { \
609 retryvar = 0; \
610 do { \
611 W_REG(bus->dhd->osh, regaddr, regval); \
612 } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \
613 if (retryvar) { \
614 bus->regfails += (retryvar-1); \
615 if (retryvar > retry_limit) \
616 DHD_ERROR(("%s: FAILED REGISTER WRITE, LINE %d\n", \
617 __FUNCTION__, __LINE__)); \
618 } \
619} while (0)
620
621#define BUS_WAKE(bus) \
622 do { \
623 bus->idlecount = 0; \
624 if ((bus)->sleeping) \
625 dhdsdio_bussleep((bus), FALSE); \
626 } while (0);
627
628/*
629 * pktavail interrupts from dongle to host can be managed in 3 different ways
630 * whenever there is a packet available in dongle to transmit to host.
631 *
632 * Mode 0: Dongle writes the software host mailbox and host is interrupted.
633 * Mode 1: (sdiod core rev >= 4)
634 * Device sets a new bit in the intstatus whenever there is a packet
635 * available in fifo. Host can't clear this specific status bit until all the
636 * packets are read from the FIFO. No need to ack dongle intstatus.
637 * Mode 2: (sdiod core rev >= 4)
638 * Device sets a bit in the intstatus, and host acks this by writing
639 * one to this bit. Dongle won't generate anymore packet interrupts
640 * until host reads all the packets from the dongle and reads a zero to
641 * figure that there are no more packets. No need to disable host ints.
642 * Need to ack the intstatus.
643 */
644
645#define SDIO_DEVICE_HMB_RXINT 0 /* default old way */
646#define SDIO_DEVICE_RXDATAINT_MODE_0 1 /* from sdiod rev 4 */
647#define SDIO_DEVICE_RXDATAINT_MODE_1 2 /* from sdiod rev 4 */
648
649#ifdef BCMSPI
650
651#define FRAME_AVAIL_MASK(bus) I_HMB_FRAME_IND
652
653#define DHD_BUS SPI_BUS
654
655/* check packet-available-interrupt in piggybacked dstatus */
656#define PKT_AVAILABLE(bus, intstatus) (bcmsdh_get_dstatus(bus->sdh) & STATUS_F2_PKT_AVAILABLE)
657
658#define HOSTINTMASK (I_HMB_FC_CHANGE | I_HMB_HOST_INT)
659
660#define GSPI_PR55150_BAILOUT \
661do { \
662 uint32 dstatussw = bcmsdh_get_dstatus((void *)bus->sdh); \
663 uint32 dstatushw = bcmsdh_cfg_read_word(bus->sdh, SDIO_FUNC_0, SPID_STATUS_REG, NULL); \
664 uint32 intstatuserr = 0; \
665 uint retries = 0; \
666 \
667 R_SDREG(intstatuserr, &bus->regs->intstatus, retries); \
668 printf("dstatussw = 0x%x, dstatushw = 0x%x, intstatus = 0x%x\n", \
669 dstatussw, dstatushw, intstatuserr); \
670 \
671 bus->nextlen = 0; \
672 *finished = TRUE; \
673} while (0)
674
675#else /* BCMSDIO */
676
677#define FRAME_AVAIL_MASK(bus) \
678 ((bus->rxint_mode == SDIO_DEVICE_HMB_RXINT) ? I_HMB_FRAME_IND : I_XMTDATA_AVAIL)
679
680#define DHD_BUS SDIO_BUS
681
682#define PKT_AVAILABLE(bus, intstatus) ((intstatus) & (FRAME_AVAIL_MASK(bus)))
683
684#define HOSTINTMASK (I_HMB_SW_MASK | I_CHIPACTIVE)
685
686#define GSPI_PR55150_BAILOUT
687
688#endif /* BCMSPI */
689
690#ifdef SDTEST
691static void dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq);
692static void dhdsdio_sdtest_set(dhd_bus_t *bus, uint count);
693#endif // endif
694
695static int dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size);
696#ifdef DHD_DEBUG
697static int dhd_serialconsole(dhd_bus_t *bus, bool get, bool enable, int *bcmerror);
698#endif /* DHD_DEBUG */
699
700#if defined(DHD_FW_COREDUMP)
701static int dhdsdio_mem_dump(dhd_bus_t *bus);
702#endif /* DHD_FW_COREDUMP */
703static int dhdsdio_devcap_set(dhd_bus_t *bus, uint8 cap);
704static int dhdsdio_download_state(dhd_bus_t *bus, bool enter);
705
706static void dhdsdio_release(dhd_bus_t *bus, osl_t *osh);
707static void dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh);
708static void dhdsdio_disconnect(void *ptr);
709static bool dhdsdio_chipmatch(uint16 chipid);
710static bool dhdsdio_probe_attach(dhd_bus_t *bus, osl_t *osh, void *sdh,
711 void * regsva, uint16 devid);
712static bool dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh);
713static bool dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh);
714static void dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation,
715 bool reset_flag);
716
717static void dhd_dongle_setramsize(struct dhd_bus *bus, int mem_size);
718static int dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags,
719 uint8 *buf, uint nbytes,
720 void *pkt, bcmsdh_cmplt_fn_t complete, void *handle);
721static int dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags,
722 uint8 *buf, uint nbytes,
723 void *pkt, bcmsdh_cmplt_fn_t complete, void *handle, int max_retry);
724static int dhdsdio_txpkt(dhd_bus_t *bus, uint chan, void** pkts, int num_pkt, bool free_pkt);
725static int dhdsdio_txpkt_preprocess(dhd_bus_t *bus, void *pkt, int chan, int txseq,
726 int prev_chain_total_len, bool last_chained_pkt,
727 int *pad_pkt_len, void **new_pkt);
728static int dhdsdio_txpkt_postprocess(dhd_bus_t *bus, void *pkt);
729
730static int dhdsdio_download_firmware(dhd_bus_t *bus, osl_t *osh, void *sdh);
731static int _dhdsdio_download_firmware(dhd_bus_t *bus);
732
733#ifdef DHD_UCODE_DOWNLOAD
734static int dhdsdio_download_ucode_file(struct dhd_bus *bus, char *ucode_path);
735#endif /* DHD_UCODE_DOWNLOAD */
736static int dhdsdio_download_code_file(dhd_bus_t *bus, char *image_path);
737static int dhdsdio_download_nvram(dhd_bus_t *bus);
738static int dhdsdio_bussleep(dhd_bus_t *bus, bool sleep);
739static int dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok);
740static uint8 dhdsdio_sleepcsr_get(dhd_bus_t *bus);
741static bool dhdsdio_dpc(dhd_bus_t *bus);
742static int dhd_bcmsdh_send_buffer(void *bus, uint8 *frame, uint16 len);
743static int dhdsdio_set_sdmode(dhd_bus_t *bus, int32 sd_mode);
744static int dhdsdio_sdclk(dhd_bus_t *bus, bool on);
745static void dhdsdio_advertise_bus_cleanup(dhd_pub_t *dhdp);
746
747#if defined(BT_OVER_SDIO)
748static int extract_hex_field(char * line, uint16 start_pos, uint16 num_chars, uint16 * value);
749static int read_more_btbytes(struct dhd_bus *bus, void * file, char *line, int * addr_mode,
750 uint16 * hi_addr, uint32 * dest_addr, uint8 *data_bytes, uint32 * num_bytes);
751static int dhdsdio_download_btfw(struct dhd_bus *bus, osl_t *osh, void *sdh);
752static int _dhdsdio_download_btfw(struct dhd_bus *bus);
753#endif /* defined (BT_OVER_SDIO) */
754
755#ifdef DHD_ULP
756#include <dhd_ulp.h>
757static int dhd_bus_ulp_reinit_fw(dhd_bus_t *bus);
758#endif /* DHD_ULP */
759
760static void
761dhdsdio_tune_fifoparam(struct dhd_bus *bus)
762{
763 int err;
764 uint8 devctl, wm, mes;
765
766 if (bus->sih->buscorerev >= 15) {
767 /* See .ppt in PR for these recommended values */
768 if (bus->blocksize == 512) {
769 wm = OVERFLOW_BLKSZ512_WM;
770 mes = OVERFLOW_BLKSZ512_MES;
771 } else {
772 mes = bus->blocksize/4;
773 wm = bus->blocksize/4;
774 }
775
776 watermark = wm;
777 mesbusyctrl = mes;
778 } else {
779 DHD_INFO(("skip fifotune: SdioRev(%d) is lower than minimal requested ver\n",
780 bus->sih->buscorerev));
781 return;
782 }
783
784 /* Update watermark */
785 if (wm > 0) {
786 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, wm, &err);
787
788 devctl = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
789 devctl |= SBSDIO_DEVCTL_F2WM_ENAB;
790 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
791 }
792
793 /* Update MES */
794 if (mes > 0) {
795 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL,
796 (mes | SBSDIO_MESBUSYCTRL_ENAB), &err);
797 }
798
799 DHD_INFO(("Apply overflow WAR: 0x%02x 0x%02x 0x%02x\n",
800 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err),
801 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, &err),
802 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL, &err)));
803}
804
805static void
806dhd_dongle_setramsize(struct dhd_bus *bus, int mem_size)
807{
808 int32 min_size = DONGLE_MIN_RAMSIZE;
809 /* Restrict the ramsize to user specified limit */
810 DHD_ERROR(("user: Restrict the dongle ram size to %d, min accepted %d\n",
811 dhd_dongle_ramsize, min_size));
812 if ((dhd_dongle_ramsize > min_size) &&
813 (dhd_dongle_ramsize < (int32)bus->orig_ramsize))
814 bus->ramsize = dhd_dongle_ramsize;
815}
816
817static int
818dhdsdio_set_siaddr_window(dhd_bus_t *bus, uint32 address)
819{
820 int err = 0;
821 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW,
822 (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err);
823 if (!err)
824 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID,
825 (address >> 16) & SBSDIO_SBADDRMID_MASK, &err);
826 if (!err)
827 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH,
828 (address >> 24) & SBSDIO_SBADDRHIGH_MASK, &err);
829 return err;
830}
831
832#ifdef BCMSPI
833static void
834dhdsdio_wkwlan(dhd_bus_t *bus, bool on)
835{
836 int err;
837 uint32 regdata;
838 bcmsdh_info_t *sdh = bus->sdh;
839
840 if (bus->sih->buscoretype == SDIOD_CORE_ID) {
841 /* wake up wlan function :WAKE_UP goes as ht_avail_request and alp_avail_request */
842 regdata = bcmsdh_cfg_read_word(sdh, SDIO_FUNC_0, SPID_CONFIG, NULL);
843 DHD_INFO(("F0 REG0 rd = 0x%x\n", regdata));
844
845 if (on == TRUE)
846 regdata |= WAKE_UP;
847 else
848 regdata &= ~WAKE_UP;
849
850 bcmsdh_cfg_write_word(sdh, SDIO_FUNC_0, SPID_CONFIG, regdata, &err);
851 }
852}
853#endif /* BCMSPI */
854
855#ifdef USE_OOB_GPIO1
856static int
857dhdsdio_oobwakeup_init(dhd_bus_t *bus)
858{
859 uint32 val, addr, data;
860
861 bcmsdh_gpioouten(bus->sdh, GPIO_DEV_WAKEUP);
862
863 addr = SI_ENUM_BASE(bus->sih) + OFFSETOF(chipcregs_t, chipcontrol_addr);
864 data = SI_ENUM_BASE(bus->sih) + OFFSETOF(chipcregs_t, chipcontrol_data);
865
866 /* Set device for gpio1 wakeup */
867 bcmsdh_reg_write(bus->sdh, addr, 4, 2);
868 val = bcmsdh_reg_read(bus->sdh, data, 4);
869 val |= CC_CHIPCTRL2_GPIO1_WAKEUP;
870 bcmsdh_reg_write(bus->sdh, data, 4, val);
871
872 bus->_oobwakeup = TRUE;
873
874 return 0;
875}
876#endif /* USE_OOB_GPIO1 */
877
878#ifndef BCMSPI
879/*
880 * Query if FW is in SR mode
881 */
882static bool
883dhdsdio_sr_cap(dhd_bus_t *bus)
884{
885 bool cap = FALSE;
886 uint32 core_capext, addr, data;
887
888 if (bus->sih->chip == BCM43430_CHIP_ID ||
889 bus->sih->chip == BCM43018_CHIP_ID) {
890 /* check if fw initialized sr engine */
891 addr = SI_ENUM_BASE(bus->sih) + OFFSETOF(chipcregs_t, sr_control1);
892 if (bcmsdh_reg_read(bus->sdh, addr, 4) != 0)
893 cap = TRUE;
894
895 return cap;
896 }
897 if (
898 0) {
899 core_capext = FALSE;
900 } else if ((bus->sih->chip == BCM4335_CHIP_ID) ||
901 (bus->sih->chip == BCM4339_CHIP_ID) ||
902 BCM4345_CHIP(bus->sih->chip) ||
903 (bus->sih->chip == BCM4354_CHIP_ID) ||
904 (bus->sih->chip == BCM4358_CHIP_ID) ||
905 (BCM4349_CHIP(bus->sih->chip)) ||
906 (bus->sih->chip == BCM4350_CHIP_ID) ||
907 (bus->sih->chip == BCM43012_CHIP_ID) ||
908 (bus->sih->chip == BCM43014_CHIP_ID)) {
909 core_capext = TRUE;
910 } else {
911 core_capext = bcmsdh_reg_read(bus->sdh,
912 si_get_pmu_reg_addr(bus->sih, OFFSETOF(chipcregs_t, core_cap_ext)),
913 4);
914
915 core_capext = (core_capext & CORE_CAPEXT_SR_SUPPORTED_MASK);
916 }
917 if (!(core_capext))
918 return FALSE;
919
920 if ((bus->sih->chip == BCM4335_CHIP_ID) ||
921 (bus->sih->chip == BCM4339_CHIP_ID) ||
922 BCM4345_CHIP(bus->sih->chip) ||
923 (bus->sih->chip == BCM4354_CHIP_ID) ||
924 (bus->sih->chip == BCM4358_CHIP_ID) ||
925 (bus->sih->chip == BCM4350_CHIP_ID)) {
926 uint32 enabval = 0;
927 addr = SI_ENUM_BASE(bus->sih) + OFFSETOF(chipcregs_t, chipcontrol_addr);
928 data = SI_ENUM_BASE(bus->sih) + OFFSETOF(chipcregs_t, chipcontrol_data);
929 bcmsdh_reg_write(bus->sdh, addr, 4, CC_PMUCC3);
930 enabval = bcmsdh_reg_read(bus->sdh, data, 4);
931
932 if ((bus->sih->chip == BCM4350_CHIP_ID) ||
933 BCM4345_CHIP(bus->sih->chip) ||
934 (bus->sih->chip == BCM4354_CHIP_ID) ||
935 (bus->sih->chip == BCM4358_CHIP_ID))
936 enabval &= CC_CHIPCTRL3_SR_ENG_ENABLE;
937
938 if (enabval)
939 cap = TRUE;
940 } else {
941 data = bcmsdh_reg_read(bus->sdh,
942 si_get_pmu_reg_addr(bus->sih, OFFSETOF(chipcregs_t, retention_ctl)),
943 4);
944 if ((data & (RCTL_MACPHY_DISABLE_MASK | RCTL_LOGIC_DISABLE_MASK)) == 0)
945 cap = TRUE;
946 }
947
948 return cap;
949}
950
951static int
952dhdsdio_sr_init(dhd_bus_t *bus)
953{
954 uint8 val;
955 int err = 0;
956
957 if (bus->sih->chip == BCM43012_CHIP_ID) {
958 val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, NULL);
959 val |= 1 << SBSDIO_FUNC1_WCTRL_ALPWAIT_SHIFT;
960 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL,
961 1 << SBSDIO_FUNC1_WCTRL_ALPWAIT_SHIFT, &err);
962 val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, NULL);
963 } else {
964 val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, NULL);
965 val |= 1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT;
966 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL,
967 1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT, &err);
968 val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, NULL);
969 }
970
971#ifdef USE_CMD14
972 /* Add CMD14 Support */
973 dhdsdio_devcap_set(bus,
974 (SDIOD_CCCR_BRCM_CARDCAP_CMD14_SUPPORT | SDIOD_CCCR_BRCM_CARDCAP_CMD14_EXT));
975#endif /* USE_CMD14 */
976
977 if (CHIPID(bus->sih->chip) == BCM43430_CHIP_ID ||
978 CHIPID(bus->sih->chip) == BCM43018_CHIP_ID ||
979 CHIPID(bus->sih->chip) == BCM4339_CHIP_ID ||
980 CHIPID(bus->sih->chip) == BCM43012_CHIP_ID ||
981 CHIPID(bus->sih->chip) == BCM43014_CHIP_ID)
982 dhdsdio_devcap_set(bus, SDIOD_CCCR_BRCM_CARDCAP_CMD_NODEC);
983
984 if (bus->sih->chip == BCM43012_CHIP_ID) {
985 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1,
986 SBSDIO_FUNC1_CHIPCLKCSR, SBSDIO_HT_AVAIL_REQ, &err);
987 } else {
988 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1,
989 SBSDIO_FUNC1_CHIPCLKCSR, SBSDIO_FORCE_HT, &err);
990 }
991 bus->_slpauto = dhd_slpauto ? TRUE : FALSE;
992
993 bus->_srenab = TRUE;
994
995 return 0;
996}
997#endif /* BCMSPI */
998
999/*
1000 * FIX: Be sure KSO bit is enabled
1001 * Currently, it's defaulting to 0 which should be 1.
1002 */
1003static int
1004dhdsdio_clk_kso_init(dhd_bus_t *bus)
1005{
1006 uint8 val;
1007 int err = 0;
1008
1009 /* set flag */
1010 bus->kso = TRUE;
1011
1012 /*
1013 * Enable KeepSdioOn (KSO) bit for normal operation
1014 * Default is 0 (4334A0) so set it. Fixed in B0.
1015 */
1016 val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, NULL);
1017 if (!(val & SBSDIO_FUNC1_SLEEPCSR_KSO_MASK)) {
1018 val |= (SBSDIO_FUNC1_SLEEPCSR_KSO_EN << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT);
1019 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, val, &err);
1020 if (err)
1021 DHD_ERROR(("%s: SBSDIO_FUNC1_SLEEPCSR err: 0x%x\n", __FUNCTION__, err));
1022 }
1023
1024 return 0;
1025}
1026
1027#define KSO_DBG(x)
1028#define KSO_WAIT_US 50
1029#define KSO_WAIT_MS 1
1030#define KSO_SLEEP_RETRY_COUNT 20
1031#define KSO_WAKE_RETRY_COUNT 100
1032#define ERROR_BCME_NODEVICE_MAX 1
1033
1034#define DEFAULT_MAX_KSO_ATTEMPTS (PMU_MAX_TRANSITION_DLY/KSO_WAIT_US)
1035#ifndef CUSTOM_MAX_KSO_ATTEMPTS
1036#define CUSTOM_MAX_KSO_ATTEMPTS DEFAULT_MAX_KSO_ATTEMPTS
1037#endif // endif
1038
1039static int
1040dhdsdio_clk_kso_enab(dhd_bus_t *bus, bool on)
1041{
1042 uint8 wr_val = 0, rd_val, cmp_val, bmask;
1043 int err = 0;
1044 int try_cnt = 0;
1045
1046 KSO_DBG(("%s> op:%s\n", __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR")));
1047
1048 wr_val |= (on << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT);
1049
1050 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, wr_val, &err);
1051
1052 /* In case of 43012 chip, the chip could go down immediately after KSO bit is cleared.
1053 * So the further reads of KSO register could fail. Thereby just bailing out immediately
1054 * after clearing KSO bit, to avoid polling of KSO bit.
1055 */
1056 if ((!on) && (bus->sih->chip == BCM43012_CHIP_ID)) {
1057 return err;
1058 }
1059
1060 if (on) {
1061 cmp_val = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK | SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK;
1062 bmask = cmp_val;
1063
1064 OSL_SLEEP(3);
1065
1066 } else {
1067 /* Put device to sleep, turn off KSO */
1068 cmp_val = 0;
1069 bmask = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK;
1070 }
1071
1072 do {
1073 rd_val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, &err);
1074 if (((rd_val & bmask) == cmp_val) && !err)
1075 break;
1076
1077 KSO_DBG(("%s> KSO wr/rd retry:%d, ERR:%x \n", __FUNCTION__, try_cnt, err));
1078
1079 if (((try_cnt + 1) % KSO_SLEEP_RETRY_COUNT) == 0) {
1080 OSL_SLEEP(KSO_WAIT_MS);
1081 } else
1082 OSL_DELAY(KSO_WAIT_US);
1083
1084 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, wr_val, &err);
1085 } while (try_cnt++ < CUSTOM_MAX_KSO_ATTEMPTS);
1086
1087 if (try_cnt > 2)
1088 KSO_DBG(("%s> op:%s, try_cnt:%d, rd_val:%x, ERR:%x \n",
1089 __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"), try_cnt, rd_val, err));
1090
1091 if (try_cnt > CUSTOM_MAX_KSO_ATTEMPTS) {
1092 DHD_ERROR(("%s> op:%s, ERROR: try_cnt:%d, rd_val:%x, ERR:%x \n",
1093 __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"), try_cnt, rd_val, err));
1094 }
1095
1096 return err;
1097}
1098
1099static int
1100dhdsdio_clk_kso_iovar(dhd_bus_t *bus, bool on)
1101{
1102 int err = 0;
1103
1104 if (on == FALSE) {
1105
1106 BUS_WAKE(bus);
1107 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
1108
1109 DHD_ERROR(("%s: KSO disable clk: 0x%x\n", __FUNCTION__,
1110 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
1111 SBSDIO_FUNC1_CHIPCLKCSR, &err)));
1112 dhdsdio_clk_kso_enab(bus, FALSE);
1113 } else {
1114 DHD_ERROR(("%s: KSO enable\n", __FUNCTION__));
1115
1116 /* Make sure we have SD bus access */
1117 if (bus->clkstate == CLK_NONE) {
1118 DHD_ERROR(("%s: Request SD clk\n", __FUNCTION__));
1119 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
1120 }
1121
1122 dhdsdio_clk_kso_enab(bus, TRUE);
1123
1124 DHD_ERROR(("%s: sleepcsr: 0x%x\n", __FUNCTION__,
1125 dhdsdio_sleepcsr_get(bus)));
1126 }
1127
1128 bus->kso = on;
1129 BCM_REFERENCE(err);
1130
1131 return 0;
1132}
1133
1134static uint8
1135dhdsdio_sleepcsr_get(dhd_bus_t *bus)
1136{
1137 int err = 0;
1138 uint8 val = 0;
1139
1140 val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, &err);
1141 if (err)
1142 DHD_TRACE(("Failed to read SLEEPCSR: %d\n", err));
1143
1144 return val;
1145}
1146
1147uint8
1148dhdsdio_devcap_get(dhd_bus_t *bus)
1149{
1150 return bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_BRCM_CARDCAP, NULL);
1151}
1152
1153static int
1154dhdsdio_devcap_set(dhd_bus_t *bus, uint8 cap)
1155{
1156 int err = 0;
1157
1158 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_BRCM_CARDCAP, cap, &err);
1159 if (err)
1160 DHD_ERROR(("%s: devcap set err: 0x%x\n", __FUNCTION__, err));
1161
1162 return 0;
1163}
1164
1165static int
1166dhdsdio_clk_devsleep_iovar(dhd_bus_t *bus, bool on)
1167{
1168 int err = 0, retry;
1169 uint8 val;
1170
1171 retry = 0;
1172 if (on == TRUE) {
1173 /* Enter Sleep */
1174
1175 /* Be sure we request clk before going to sleep
1176 * so we can wake-up with clk request already set
1177 * else device can go back to sleep immediately
1178 */
1179 if (!SLPAUTO_ENAB(bus))
1180 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
1181 else {
1182 val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
1183 if ((val & SBSDIO_CSR_MASK) == 0) {
1184 DHD_ERROR(("%s: No clock before enter sleep:0x%x\n",
1185 __FUNCTION__, val));
1186
1187 /* Reset clock request */
1188 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
1189 SBSDIO_ALP_AVAIL_REQ, &err);
1190 DHD_ERROR(("%s: clock before sleep:0x%x\n", __FUNCTION__,
1191 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
1192 SBSDIO_FUNC1_CHIPCLKCSR, &err)));
1193 }
1194 }
1195
1196 DHD_TRACE(("%s: clk before sleep: 0x%x\n", __FUNCTION__,
1197 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
1198 SBSDIO_FUNC1_CHIPCLKCSR, &err)));
1199#ifdef USE_CMD14
1200 err = bcmsdh_sleep(bus->sdh, TRUE);
1201#else
1202 if ((SLPAUTO_ENAB(bus)) && (bus->idleclock == DHD_IDLE_STOP)) {
1203 if (sd1idle) {
1204 /* Change to SD1 mode */
1205 dhdsdio_set_sdmode(bus, 1);
1206 }
1207 }
1208
1209 err = dhdsdio_clk_kso_enab(bus, FALSE);
1210 if (OOB_WAKEUP_ENAB(bus))
1211 {
1212 err = bcmsdh_gpioout(bus->sdh, GPIO_DEV_WAKEUP, FALSE); /* GPIO_1 is off */
1213 }
1214#endif /* USE_CMD14 */
1215
1216 if ((SLPAUTO_ENAB(bus)) && (bus->idleclock != DHD_IDLE_ACTIVE)) {
1217 DHD_TRACE(("%s: Turnoff SD clk\n", __FUNCTION__));
1218 /* Now remove the SD clock */
1219 err = dhdsdio_sdclk(bus, FALSE);
1220 }
1221 } else {
1222 /* Exit Sleep */
1223 /* Make sure we have SD bus access */
1224 if (bus->clkstate == CLK_NONE) {
1225 DHD_TRACE(("%s: Request SD clk\n", __FUNCTION__));
1226 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
1227 }
1228#ifdef USE_CMD14
1229 err = bcmsdh_sleep(bus->sdh, FALSE);
1230 if (SLPAUTO_ENAB(bus) && (err != 0)) {
1231 OSL_DELAY(10000);
1232 DHD_TRACE(("%s: Resync device sleep\n", __FUNCTION__));
1233
1234 /* Toggle sleep to resync with host and device */
1235 err = bcmsdh_sleep(bus->sdh, TRUE);
1236 OSL_DELAY(10000);
1237 err = bcmsdh_sleep(bus->sdh, FALSE);
1238
1239 if (err) {
1240 OSL_DELAY(10000);
1241 DHD_ERROR(("%s: CMD14 exit failed again!\n", __FUNCTION__));
1242
1243 /* Toggle sleep to resync with host and device */
1244 err = bcmsdh_sleep(bus->sdh, TRUE);
1245 OSL_DELAY(10000);
1246 err = bcmsdh_sleep(bus->sdh, FALSE);
1247 if (err) {
1248 DHD_ERROR(("%s: CMD14 exit failed twice!\n", __FUNCTION__));
1249 DHD_ERROR(("%s: FATAL: Device non-response!\n",
1250 __FUNCTION__));
1251 err = 0;
1252 }
1253 }
1254 }
1255#else
1256 if (OOB_WAKEUP_ENAB(bus))
1257 {
1258 err = bcmsdh_gpioout(bus->sdh, GPIO_DEV_WAKEUP, TRUE); /* GPIO_1 is on */
1259 }
1260 do {
1261 err = dhdsdio_clk_kso_enab(bus, TRUE);
1262 if (err)
1263 OSL_SLEEP(10);
1264 } while ((err != 0) && (++retry < 3));
1265
1266 if (err != 0) {
1267 DHD_ERROR(("ERROR: kso set failed retry: %d\n", retry));
1268#ifndef BT_OVER_SDIO
1269 err = 0; /* continue anyway */
1270#endif /* BT_OVER_SDIO */
1271 }
1272
1273 if ((SLPAUTO_ENAB(bus)) && (bus->idleclock == DHD_IDLE_STOP)) {
1274 dhdsdio_set_sdmode(bus, bus->sd_mode);
1275 }
1276#endif /* !USE_CMD14 */
1277
1278 if (err == 0) {
1279 uint8 csr;
1280
1281 /* Wait for device ready during transition to wake-up */
1282 SPINWAIT_SLEEP(sdioh_spinwait_sleep,
1283 (((csr = dhdsdio_sleepcsr_get(bus)) &
1284 SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK) !=
1285 (SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK)), (20000));
1286
1287 DHD_TRACE(("%s: ExitSleep sleepcsr: 0x%x\n", __FUNCTION__, csr));
1288
1289 if (!(csr & SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK)) {
1290 DHD_ERROR(("%s:ERROR: ExitSleep device NOT Ready! 0x%x\n",
1291 __FUNCTION__, csr));
1292 err = BCME_NODEVICE;
1293 }
1294
1295 SPINWAIT_SLEEP(sdioh_spinwait_sleep,
1296 (((csr = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
1297 SBSDIO_FUNC1_CHIPCLKCSR, &err)) & SBSDIO_HT_AVAIL) !=
1298 (SBSDIO_HT_AVAIL)), (DHD_WAIT_HTAVAIL));
1299
1300 DHD_TRACE(("%s: SBSDIO_FUNC1_CHIPCLKCSR : 0x%x\n", __FUNCTION__, csr));
1301 if (!err && ((csr & SBSDIO_HT_AVAIL) != SBSDIO_HT_AVAIL)) {
1302 DHD_ERROR(("%s:ERROR: device NOT Ready! 0x%x\n",
1303 __FUNCTION__, csr));
1304 err = BCME_NODEVICE;
1305 }
1306 }
1307 }
1308
1309 /* Update if successful */
1310 if (err == 0)
1311 bus->kso = on ? FALSE : TRUE;
1312 else {
1313 DHD_ERROR(("%s: Sleep request failed: kso:%d on:%d err:%d\n",
1314 __FUNCTION__, bus->kso, on, err));
1315 if (!on && retry > 2)
1316 bus->kso = FALSE;
1317 }
1318
1319 return err;
1320}
1321
1322/* Turn backplane clock on or off */
1323static int
1324dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok)
1325{
1326#define HT_AVAIL_ERROR_MAX 10
1327 static int ht_avail_error = 0;
1328 int err;
1329 uint8 clkctl, clkreq, devctl;
1330 bcmsdh_info_t *sdh;
1331
1332 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1333
1334 clkctl = 0;
1335 sdh = bus->sdh;
1336
1337 if (!KSO_ENAB(bus))
1338 return BCME_OK;
1339
1340 if (SLPAUTO_ENAB(bus)) {
1341 bus->clkstate = (on ? CLK_AVAIL : CLK_SDONLY);
1342 return BCME_OK;
1343 }
1344
1345 if (on) {
1346 /* Request HT Avail */
1347 clkreq = bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ;
1348
1349#ifdef BCMSPI
1350 dhdsdio_wkwlan(bus, TRUE);
1351#endif /* BCMSPI */
1352
1353 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
1354 if (err) {
1355 ht_avail_error++;
1356 if (ht_avail_error < HT_AVAIL_ERROR_MAX) {
1357 DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err));
1358 }
1359
1360#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
1361 else if (ht_avail_error == HT_AVAIL_ERROR_MAX) {
1362 bus->dhd->hang_reason = HANG_REASON_HT_AVAIL_ERROR;
1363 dhd_os_send_hang_message(bus->dhd);
1364 }
1365#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) */
1366 return BCME_ERROR;
1367 } else {
1368 ht_avail_error = 0;
1369 }
1370
1371 /* Check current status */
1372 clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
1373 if (err) {
1374 DHD_ERROR(("%s: HT Avail read error: %d\n", __FUNCTION__, err));
1375 return BCME_ERROR;
1376 }
1377
1378#if !defined(OOB_INTR_ONLY)
1379 /* Go to pending and await interrupt if appropriate */
1380 if (!SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) {
1381 /* Allow only clock-available interrupt */
1382 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
1383 if (err) {
1384 DHD_ERROR(("%s: Devctl access error setting CA: %d\n",
1385 __FUNCTION__, err));
1386 return BCME_ERROR;
1387 }
1388
1389 devctl |= SBSDIO_DEVCTL_CA_INT_ONLY;
1390 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
1391 DHD_INFO(("CLKCTL: set PENDING\n"));
1392 bus->clkstate = CLK_PENDING;
1393 return BCME_OK;
1394 } else
1395#endif /* !defined (OOB_INTR_ONLY) */
1396 {
1397 if (bus->clkstate == CLK_PENDING) {
1398 /* Cancel CA-only interrupt filter */
1399 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
1400 devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
1401 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
1402 }
1403 }
1404#ifndef BCMSDIOLITE
1405 /* Otherwise, wait here (polling) for HT Avail */
1406 if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
1407 SPINWAIT_SLEEP(sdioh_spinwait_sleep,
1408 ((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
1409 SBSDIO_FUNC1_CHIPCLKCSR, &err)),
1410 !SBSDIO_CLKAV(clkctl, bus->alp_only)), PMU_MAX_TRANSITION_DLY);
1411 }
1412 if (err) {
1413 DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err));
1414 return BCME_ERROR;
1415 }
1416 if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
1417 DHD_ERROR(("%s: HT Avail timeout (%d): clkctl 0x%02x\n",
1418 __FUNCTION__, PMU_MAX_TRANSITION_DLY, clkctl));
1419 return BCME_ERROR;
1420 }
1421#endif /* BCMSDIOLITE */
1422 /* Mark clock available */
1423 bus->clkstate = CLK_AVAIL;
1424 DHD_INFO(("CLKCTL: turned ON\n"));
1425
1426#if defined(DHD_DEBUG)
1427 if (bus->alp_only == TRUE) {
1428#if !defined(BCMLXSDMMC)
1429 if (!SBSDIO_ALPONLY(clkctl)) {
1430 DHD_ERROR(("%s: HT Clock, when ALP Only\n", __FUNCTION__));
1431 }
1432#endif /* !defined(BCMLXSDMMC) */
1433 } else {
1434 if (SBSDIO_ALPONLY(clkctl)) {
1435 DHD_ERROR(("%s: HT Clock should be on.\n", __FUNCTION__));
1436 }
1437 }
1438#endif /* defined (DHD_DEBUG) */
1439
1440 bus->activity = TRUE;
1441#ifdef DHD_USE_IDLECOUNT
1442 bus->idlecount = 0;
1443#endif /* DHD_USE_IDLECOUNT */
1444 } else {
1445 clkreq = 0;
1446
1447 if (bus->clkstate == CLK_PENDING) {
1448 /* Cancel CA-only interrupt filter */
1449 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
1450 devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
1451 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
1452 }
1453
1454 bus->clkstate = CLK_SDONLY;
1455 if (!SR_ENAB(bus)) {
1456 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
1457 DHD_INFO(("CLKCTL: turned OFF\n"));
1458 if (err) {
1459 DHD_ERROR(("%s: Failed access turning clock off: %d\n",
1460 __FUNCTION__, err));
1461 return BCME_ERROR;
1462 }
1463 }
1464#ifdef BCMSPI
1465 dhdsdio_wkwlan(bus, FALSE);
1466#endif /* BCMSPI */
1467 }
1468 return BCME_OK;
1469}
1470
1471/* Change SD1/SD4 bus mode */
1472static int
1473dhdsdio_set_sdmode(dhd_bus_t *bus, int32 sd_mode)
1474{
1475 int err;
1476
1477 err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
1478 &sd_mode, sizeof(sd_mode), TRUE);
1479 if (err) {
1480 DHD_ERROR(("%s: error changing sd_mode: %d\n",
1481 __FUNCTION__, err));
1482 return BCME_ERROR;
1483 }
1484 return BCME_OK;
1485}
1486
1487/* Change idle/active SD state */
1488static int
1489dhdsdio_sdclk(dhd_bus_t *bus, bool on)
1490{
1491#ifndef BCMSPI
1492 int err;
1493 int32 iovalue;
1494
1495 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1496
1497 if (on) {
1498 if (bus->idleclock == DHD_IDLE_STOP) {
1499 /* Turn on clock and restore mode */
1500 iovalue = 1;
1501 err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0,
1502 &iovalue, sizeof(iovalue), TRUE);
1503 if (err) {
1504 DHD_ERROR(("%s: error enabling sd_clock: %d\n",
1505 __FUNCTION__, err));
1506 return BCME_ERROR;
1507 }
1508
1509 } else if (bus->idleclock != DHD_IDLE_ACTIVE) {
1510 /* Restore clock speed */
1511 iovalue = bus->sd_divisor;
1512 err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
1513 &iovalue, sizeof(iovalue), TRUE);
1514 if (err) {
1515 DHD_ERROR(("%s: error restoring sd_divisor: %d\n",
1516 __FUNCTION__, err));
1517 return BCME_ERROR;
1518 }
1519 }
1520 bus->clkstate = CLK_SDONLY;
1521 } else {
1522 /* Stop or slow the SD clock itself */
1523 if ((bus->sd_divisor == -1) || (bus->sd_mode == -1)) {
1524 DHD_TRACE(("%s: can't idle clock, divisor %d mode %d\n",
1525 __FUNCTION__, bus->sd_divisor, bus->sd_mode));
1526 return BCME_ERROR;
1527 }
1528 if (bus->idleclock == DHD_IDLE_STOP) {
1529 iovalue = 0;
1530 err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0,
1531 &iovalue, sizeof(iovalue), TRUE);
1532 if (err) {
1533 DHD_ERROR(("%s: error disabling sd_clock: %d\n",
1534 __FUNCTION__, err));
1535 return BCME_ERROR;
1536 }
1537 } else if (bus->idleclock != DHD_IDLE_ACTIVE) {
1538 /* Set divisor to idle value */
1539 iovalue = bus->idleclock;
1540 err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
1541 &iovalue, sizeof(iovalue), TRUE);
1542 if (err) {
1543 DHD_ERROR(("%s: error changing sd_divisor: %d\n",
1544 __FUNCTION__, err));
1545 return BCME_ERROR;
1546 }
1547 }
1548 bus->clkstate = CLK_NONE;
1549 }
1550#endif /* BCMSPI */
1551
1552 return BCME_OK;
1553}
1554
1555/* Transition SD and backplane clock readiness */
1556static int
1557dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok)
1558{
1559 int ret = BCME_OK;
1560#ifdef DHD_DEBUG
1561 uint oldstate = bus->clkstate;
1562#endif /* DHD_DEBUG */
1563
1564 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1565
1566 /* Early exit if we're already there */
1567 if (bus->clkstate == target) {
1568 if (target == CLK_AVAIL) {
1569 dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
1570 bus->activity = TRUE;
1571#ifdef DHD_USE_IDLECOUNT
1572 bus->idlecount = 0;
1573#endif /* DHD_USE_IDLECOUNT */
1574 }
1575 return ret;
1576 }
1577
1578 switch (target) {
1579 case CLK_AVAIL:
1580 /* Make sure SD clock is available */
1581 if (bus->clkstate == CLK_NONE)
1582 dhdsdio_sdclk(bus, TRUE);
1583 /* Now request HT Avail on the backplane */
1584 ret = dhdsdio_htclk(bus, TRUE, pendok);
1585 if (ret == BCME_OK) {
1586 dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
1587 bus->activity = TRUE;
1588#ifdef DHD_USE_IDLECOUNT
1589 bus->idlecount = 0;
1590#endif /* DHD_USE_IDLECOUNT */
1591 }
1592 break;
1593
1594 case CLK_SDONLY:
1595
1596#ifdef BT_OVER_SDIO
1597 /*
1598 * If the request is to switch off Back plane clock,
1599 * confirm that BT is inactive before doing so.
1600 * If this call had come from Non Watchdog context any way
1601 * the Watchdog would switch off the clock again when
1602 * nothing is to be done & Bt has finished using the bus.
1603 */
1604 if (bus->bt_use_count != 0) {
1605 DHD_INFO(("%s(): Req CLK_SDONLY, BT is active %d not switching off \r\n",
1606 __FUNCTION__, bus->bt_use_count));
1607 ret = BCME_OK;
1608 dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
1609 break;
1610 }
1611
1612 DHD_INFO(("%s(): Request CLK_NONE BT is NOT active switching off \r\n",
1613 __FUNCTION__));
1614#endif /* BT_OVER_SDIO */
1615
1616 /* Remove HT request, or bring up SD clock */
1617 if (bus->clkstate == CLK_NONE)
1618 ret = dhdsdio_sdclk(bus, TRUE);
1619 else if (bus->clkstate == CLK_AVAIL)
1620 ret = dhdsdio_htclk(bus, FALSE, FALSE);
1621 else
1622 DHD_ERROR(("dhdsdio_clkctl: request for %d -> %d\n",
1623 bus->clkstate, target));
1624 if (ret == BCME_OK) {
1625 dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
1626 }
1627 break;
1628
1629 case CLK_NONE:
1630
1631#ifdef BT_OVER_SDIO
1632 /*
1633 * If the request is to switch off Back plane clock,
1634 * confirm that BT is inactive before doing so.
1635 * If this call had come from Non Watchdog context any way
1636 * the Watchdog would switch off the clock again when
1637 * nothing is to be done & Bt has finished using the bus.
1638 */
1639 if (bus->bt_use_count != 0) {
1640 DHD_INFO(("%s(): Request CLK_NONE BT is active %d not switching off \r\n",
1641 __FUNCTION__, bus->bt_use_count));
1642 ret = BCME_OK;
1643 break;
1644 }
1645
1646 DHD_INFO(("%s(): Request CLK_NONE BT is NOT active switching off \r\n",
1647 __FUNCTION__));
1648#endif /* BT_OVER_SDIO */
1649
1650 /* Make sure to remove HT request */
1651 if (bus->clkstate == CLK_AVAIL)
1652 ret = dhdsdio_htclk(bus, FALSE, FALSE);
1653 /* Now remove the SD clock */
1654 ret = dhdsdio_sdclk(bus, FALSE);
1655#ifdef DHD_DEBUG
1656 if (bus->dhd->dhd_console_ms == 0)
1657#endif /* DHD_DEBUG */
1658 if (bus->poll == 0)
1659 dhd_os_wd_timer(bus->dhd, 0);
1660 break;
1661 }
1662#ifdef DHD_DEBUG
1663 DHD_INFO(("dhdsdio_clkctl: %d -> %d\n", oldstate, bus->clkstate));
1664#endif /* DHD_DEBUG */
1665
1666 return ret;
1667}
1668
1669static int
1670dhdsdio_bussleep(dhd_bus_t *bus, bool sleep)
1671{
1672 int err = 0;
1673 bcmsdh_info_t *sdh = bus->sdh;
1674 sdpcmd_regs_t *regs = bus->regs;
1675 uint retries = 0;
1676
1677 DHD_INFO(("dhdsdio_bussleep: request %s (currently %s)\n",
1678 (sleep ? "SLEEP" : "WAKE"),
1679 (bus->sleeping ? "SLEEP" : "WAKE")));
1680
1681 if (bus->dhd->hang_was_sent)
1682 return BCME_ERROR;
1683
1684 /* Done if we're already in the requested state */
1685 if (sleep == bus->sleeping)
1686 return BCME_OK;
1687
1688 /* Going to sleep: set the alarm and turn off the lights... */
1689 if (sleep) {
1690 /* Don't sleep if something is pending */
1691#ifdef DHD_USE_IDLECOUNT
1692 if (bus->dpc_sched || bus->rxskip || pktq_n_pkts_tot(&bus->txq) ||
1693 bus->readframes || bus->ctrl_frame_stat)
1694#else
1695 if (bus->dpc_sched || bus->rxskip || pktq_n_pkts_tot(&bus->txq))
1696#endif /* DHD_USE_IDLECOUNT */
1697 return BCME_BUSY;
1698
1699#ifdef BT_OVER_SDIO
1700 /*
1701 * The following is the assumption based on which the hook is placed.
1702 * From WLAN driver, either from the active contexts OR from the Watchdog contexts
1703 * we will be attempting to Go to Sleep. AT that moment if we see that BT is still
1704 * actively using the bus, we will return BCME_BUSY from here, but the bus->sleeping
1705 * state would not have changed. So the caller can then schedule the Watchdog again
1706 * which will come and attempt to sleep at a later point.
1707 *
1708 * In case if BT is the only one and is the last user, we don't switch off the clock
1709 * immediately, we allow the WLAN to decide when to sleep i.e from the watchdog.
1710 * Now if the watchdog becomes active and attempts to switch off the clock and if
1711 * another WLAN context is active they are any way serialized with sdlock.
1712 */
1713 if (bus->bt_use_count != 0) {
1714 DHD_INFO(("%s(): Cannot sleep BT is active \r\n", __FUNCTION__));
1715 return BCME_BUSY;
1716 }
1717#endif /* !BT_OVER_SDIO */
1718
1719 if (!SLPAUTO_ENAB(bus)) {
1720 /* Disable SDIO interrupts (no longer interested) */
1721 bcmsdh_intr_disable(bus->sdh);
1722
1723 /* Make sure the controller has the bus up */
1724 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
1725
1726 /* Tell device to start using OOB wakeup */
1727 W_SDREG(SMB_USE_OOB, &regs->tosbmailbox, retries);
1728 if (retries > retry_limit)
1729 DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
1730
1731 /* Turn off our contribution to the HT clock request */
1732 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
1733
1734 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
1735 SBSDIO_FORCE_HW_CLKREQ_OFF, NULL);
1736
1737 /* Isolate the bus */
1738 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL,
1739 SBSDIO_DEVCTL_PADS_ISO, NULL);
1740 } else {
1741 /* Leave interrupts enabled since device can exit sleep and
1742 * interrupt host
1743 */
1744 err = dhdsdio_clk_devsleep_iovar(bus, TRUE /* sleep */);
1745 }
1746
1747 /* Change state */
1748 bus->sleeping = TRUE;
1749#if defined(SUPPORT_P2P_GO_PS)
1750 wake_up(&bus->bus_sleep);
1751#endif /* LINUX && SUPPORT_P2P_GO_PS */
1752 } else {
1753 /* Waking up: bus power up is ok, set local state */
1754
1755 if (!SLPAUTO_ENAB(bus)) {
1756 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0, &err);
1757
1758 /* Force pad isolation off if possible (in case power never toggled) */
1759 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, 0, NULL);
1760
1761 /* Make sure the controller has the bus up */
1762 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
1763
1764 /* Send misc interrupt to indicate OOB not needed */
1765 W_SDREG(0, &regs->tosbmailboxdata, retries);
1766 if (retries <= retry_limit)
1767 W_SDREG(SMB_DEV_INT, &regs->tosbmailbox, retries);
1768
1769 if (retries > retry_limit)
1770 DHD_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n"));
1771
1772 /* Make sure we have SD bus access */
1773 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
1774
1775 /* Enable interrupts again */
1776 if (bus->intr && (bus->dhd->busstate == DHD_BUS_DATA)) {
1777 bus->intdis = FALSE;
1778 bcmsdh_intr_enable(bus->sdh);
1779 }
1780 } else {
1781 err = dhdsdio_clk_devsleep_iovar(bus, FALSE /* wake */);
1782#ifdef BT_OVER_SDIO
1783 if (err < 0) {
1784 struct net_device *net = NULL;
1785 dhd_pub_t *dhd = bus->dhd;
1786 net = dhd_idx2net(dhd, 0);
1787 if (net != NULL) {
1788 DHD_ERROR(("<< WIFI HANG by KSO Enabled failure\n"));
1789 dhd_os_sdunlock(dhd);
1790 net_os_send_hang_message(net);
1791 dhd_os_sdlock(dhd);
1792 } else {
1793 DHD_ERROR(("<< WIFI HANG Fail because net is NULL\n"));
1794 }
1795 }
1796#endif /* BT_OVER_SDIO */
1797 }
1798
1799 if (err == 0) {
1800 /* Change state */
1801 bus->sleeping = FALSE;
1802 }
1803 }
1804
1805 return err;
1806}
1807
1808#ifdef BT_OVER_SDIO
1809/*
1810 * Call this function to Get the Clock running.
1811 * Assumes that the caller holds the sdlock.
1812 * bus - Pointer to the dhd_bus handle
1813 * can_wait - TRUE if the caller can wait until the clock becomes ready
1814 * FALSE if the caller cannot wait
1815 */
1816int __dhdsdio_clk_enable(struct dhd_bus *bus, bus_owner_t owner, int can_wait)
1817{
1818 int ret = BCME_ERROR;
1819
1820 BCM_REFERENCE(owner);
1821
1822 bus->bt_use_count++;
1823
1824 /*
1825 * We can call BUS_WAKE, clkctl multiple times, both of the items
1826 * have states and if its already ON, no new configuration is done
1827 */
1828
1829 /* Wake up the Dongle FW from SR */
1830 BUS_WAKE(bus);
1831
1832 /*
1833 * Make sure back plane ht clk is on
1834 * CLK_AVAIL - Turn On both SD & HT clock
1835 */
1836 ret = dhdsdio_clkctl(bus, CLK_AVAIL, can_wait);
1837
1838 DHD_INFO(("%s():bt_use_count %d \r\n", __FUNCTION__,
1839 bus->bt_use_count));
1840 return ret;
1841}
1842
1843/*
1844 * Call this function to relinquish the Clock.
1845 * Assumes that the caller holds the sdlock.
1846 * bus - Pointer to the dhd_bus handle
1847 * can_wait - TRUE if the caller can wait until the clock becomes ready
1848 * FALSE if the caller cannot wait
1849 */
1850int __dhdsdio_clk_disable(struct dhd_bus *bus, bus_owner_t owner, int can_wait)
1851{
1852 int ret = BCME_ERROR;
1853
1854 BCM_REFERENCE(owner);
1855 BCM_REFERENCE(can_wait);
1856
1857 if (bus->bt_use_count == 0) {
1858 DHD_ERROR(("%s(): Clocks are already turned off \r\n",
1859 __FUNCTION__));
1860 return ret;
1861 }
1862
1863 bus->bt_use_count--;
1864
1865 /*
1866 * When the SDIO Bus is shared between BT & WLAN, we turn Off the clock
1867 * once the last user has relinqushed the same. But there are two schemes
1868 * in that too. We consider WLAN as the bus master (even if its not
1869 * active). Even when the WLAN is OFF the DHD Watchdog is active.
1870 * So this Bus Watchdog is the context whill put the Bus to sleep.
1871 * Refer dhd_bus_watchdog function
1872 */
1873
1874 ret = BCME_OK;
1875 DHD_INFO(("%s():bt_use_count %d \r\n", __FUNCTION__,
1876 bus->bt_use_count));
1877 return ret;
1878}
1879
1880void dhdsdio_reset_bt_use_count(struct dhd_bus *bus)
1881{
1882 /* reset bt use count */
1883 bus->bt_use_count = 0;
1884}
1885#endif /* BT_OVER_SDIO */
1886
1887#ifdef USE_DYNAMIC_F2_BLKSIZE
1888int dhdsdio_func_blocksize(dhd_pub_t *dhd, int function_num, int block_size)
1889{
1890 int func_blk_size = function_num;
1891 int bcmerr = 0;
1892 int result;
1893
1894 bcmerr = dhd_bus_iovar_op(dhd, "sd_blocksize", &func_blk_size,
1895 sizeof(int), &result, sizeof(int), IOV_GET);
1896
1897 if (bcmerr != BCME_OK) {
1898 DHD_ERROR(("%s: Get F%d Block size error\n", __FUNCTION__, function_num));
1899 return BCME_ERROR;
1900 }
1901
1902 if (result != block_size) {
1903 DHD_TRACE_HW4(("%s: F%d Block size set from %d to %d\n",
1904 __FUNCTION__, function_num, result, block_size));
1905 func_blk_size = function_num << 16 | block_size;
1906 bcmerr = dhd_bus_iovar_op(dhd, "sd_blocksize", NULL,
1907 0, &func_blk_size, sizeof(int32), IOV_SET);
1908 if (bcmerr != BCME_OK) {
1909 DHD_ERROR(("%s: Set F2 Block size error\n", __FUNCTION__));
1910 return BCME_ERROR;
1911 }
1912 }
1913
1914 return BCME_OK;
1915}
1916#endif /* USE_DYNAMIC_F2_BLKSIZE */
1917
1918#if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
1919void
1920dhd_enable_oob_intr(struct dhd_bus *bus, bool enable)
1921{
1922#if defined(BCMSPI_ANDROID)
1923 bcmsdh_intr_enable(bus->sdh);
1924#elif defined(HW_OOB)
1925 bcmsdh_enable_hw_oob_intr(bus->sdh, enable);
1926#else
1927 sdpcmd_regs_t *regs = bus->regs;
1928 uint retries = 0;
1929
1930 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
1931 if (enable == TRUE) {
1932
1933 /* Tell device to start using OOB wakeup */
1934 W_SDREG(SMB_USE_OOB, &regs->tosbmailbox, retries);
1935 if (retries > retry_limit)
1936 DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
1937
1938 } else {
1939 /* Send misc interrupt to indicate OOB not needed */
1940 W_SDREG(0, &regs->tosbmailboxdata, retries);
1941 if (retries <= retry_limit)
1942 W_SDREG(SMB_DEV_INT, &regs->tosbmailbox, retries);
1943 }
1944
1945 /* Turn off our contribution to the HT clock request */
1946 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
1947#endif /* !defined(HW_OOB) */
1948}
1949#endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */
1950
1951int
1952dhd_bus_txdata(struct dhd_bus *bus, void *pkt)
1953{
1954 int ret = BCME_ERROR;
1955 osl_t *osh;
1956 uint datalen, prec;
1957#if defined(DHD_TX_DUMP)
1958 uint8 *dump_data;
1959#endif /* DHD_TX_DUMP */
1960
1961 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1962
1963 osh = bus->dhd->osh;
1964 datalen = PKTLEN(osh, pkt);
1965
1966#ifdef SDTEST
1967 /* Push the test header if doing loopback */
1968 if (bus->ext_loop) {
1969 uint8* data;
1970 PKTPUSH(osh, pkt, SDPCM_TEST_HDRLEN);
1971 data = PKTDATA(osh, pkt);
1972 *data++ = SDPCM_TEST_ECHOREQ;
1973 *data++ = (uint8)bus->loopid++;
1974 *data++ = (datalen >> 0);
1975 *data++ = (datalen >> 8);
1976 datalen += SDPCM_TEST_HDRLEN;
1977 }
1978#else /* SDTEST */
1979 BCM_REFERENCE(datalen);
1980#endif /* SDTEST */
1981
1982#ifdef DHD_ULP
1983 dhd_ulp_set_path(bus->dhd, DHD_ULP_TX_DATA);
1984#endif /* DHD_ULP */
1985
1986#if defined(DHD_TX_DUMP) && defined(DHD_TX_FULL_DUMP)
1987 dump_data = PKTDATA(osh, pkt);
1988 dump_data += 4; /* skip 4 bytes header */
1989 {
1990 int i;
1991 DHD_ERROR(("TX DUMP\n"));
1992
1993 for (i = 0; i < (datalen - 4); i++) {
1994 DHD_ERROR(("%02X ", dump_data[i]));
1995 if ((i & 15) == 15)
1996 printk("\n");
1997 }
1998 DHD_ERROR(("\n"));
1999 }
2000#endif /* DHD_TX_DUMP && DHD_TX_FULL_DUMP */
2001
2002 prec = PRIO2PREC((PKTPRIO(pkt) & PRIOMASK));
2003
2004 /* Check for existing queue, current flow-control, pending event, or pending clock */
2005 if (dhd_deferred_tx || bus->fcstate || pktq_n_pkts_tot(&bus->txq) || bus->dpc_sched ||
2006 (!DATAOK(bus)) || (bus->flowcontrol & NBITVAL(prec)) ||
2007 (bus->clkstate != CLK_AVAIL)) {
2008 bool deq_ret;
2009 int pkq_len;
2010
2011 DHD_TRACE(("%s: deferring pktq len %d\n", __FUNCTION__,
2012 pktq_n_pkts_tot(&bus->txq)));
2013 bus->fcqueued++;
2014
2015 /* Priority based enq */
2016 dhd_os_sdlock_txq(bus->dhd);
2017 deq_ret = dhd_prec_enq(bus->dhd, &bus->txq, pkt, prec);
2018 dhd_os_sdunlock_txq(bus->dhd);
2019
2020 if (!deq_ret) {
2021#ifdef PROP_TXSTATUS
2022 if (DHD_PKTTAG_WLFCPKT(PKTTAG(pkt)) == 0)
2023#endif /* PROP_TXSTATUS */
2024 {
2025#ifdef DHDTCPACK_SUPPRESS
2026 if (dhd_tcpack_check_xmit(bus->dhd, pkt) == BCME_ERROR) {
2027 DHD_ERROR(("%s %d: tcpack_suppress ERROR!!! Stop using\n",
2028 __FUNCTION__, __LINE__));
2029 dhd_tcpack_suppress_set(bus->dhd, TCPACK_SUP_OFF);
2030 }
2031#endif /* DHDTCPACK_SUPPRESS */
2032 dhd_txcomplete(bus->dhd, pkt, FALSE);
2033 PKTFREE(osh, pkt, TRUE);
2034 }
2035 ret = BCME_NORESOURCE;
2036 } else
2037 ret = BCME_OK;
2038
2039 dhd_os_sdlock_txq(bus->dhd);
2040 pkq_len = pktq_n_pkts_tot(&bus->txq);
2041 dhd_os_sdunlock_txq(bus->dhd);
2042 if (pkq_len >= FCHI) {
2043 bool wlfc_enabled = FALSE;
2044#ifdef PROP_TXSTATUS
2045 wlfc_enabled = (dhd_wlfc_flowcontrol(bus->dhd, ON, FALSE) !=
2046 WLFC_UNSUPPORTED);
2047#endif // endif
2048 if (!wlfc_enabled && dhd_doflow) {
2049 dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON);
2050 }
2051 }
2052
2053#ifdef DHD_DEBUG
2054 dhd_os_sdlock_txq(bus->dhd);
2055 if (pktqprec_n_pkts(&bus->txq, prec) > qcount[prec])
2056 qcount[prec] = pktqprec_n_pkts(&bus->txq, prec);
2057 dhd_os_sdunlock_txq(bus->dhd);
2058#endif // endif
2059
2060 /* Schedule DPC if needed to send queued packet(s) */
2061 if (dhd_deferred_tx && !bus->dpc_sched) {
2062 bus->dpc_sched = TRUE;
2063 dhd_sched_dpc(bus->dhd);
2064 }
2065 } else {
2066 int chan = SDPCM_DATA_CHANNEL;
2067
2068#ifdef SDTEST
2069 chan = (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL);
2070#endif // endif
2071 /* Lock: we're about to use shared data/code (and SDIO) */
2072 dhd_os_sdlock(bus->dhd);
2073
2074 /* Otherwise, send it now */
2075 BUS_WAKE(bus);
2076 /* Make sure back plane ht clk is on, no pending allowed */
2077 dhdsdio_clkctl(bus, CLK_AVAIL, TRUE);
2078
2079 ret = dhdsdio_txpkt(bus, chan, &pkt, 1, TRUE);
2080
2081 if (ret != BCME_OK)
2082 bus->dhd->tx_errors++;
2083 else
2084 bus->dhd->dstats.tx_bytes += datalen;
2085
2086 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched &&
2087 NO_OTHER_ACTIVE_BUS_USER(bus)) {
2088 bus->activity = FALSE;
2089 dhdsdio_bussleep(bus, TRUE);
2090 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
2091 }
2092
2093 dhd_os_sdunlock(bus->dhd);
2094 }
2095
2096 return ret;
2097}
2098
2099/* align packet data pointer and packet length to n-byte boundary, process packet headers,
2100 * a new packet may be allocated if there is not enough head and/or tail from for padding.
2101 * the caller is responsible for updating the glom size in the head packet (when glom is
2102 * used)
2103 *
2104 * pad_pkt_len: returns the length of extra padding needed from the padding packet, this parameter
2105 * is taken in tx glom mode only
2106 *
2107 * new_pkt: out, pointer of the new packet allocated due to insufficient head room for alignment
2108 * padding, NULL if not needed, the caller is responsible for freeing the new packet
2109 *
2110 * return: positive value - length of the packet, including head and tail padding
2111 * negative value - errors
2112 */
2113static int dhdsdio_txpkt_preprocess(dhd_bus_t *bus, void *pkt, int chan, int txseq,
2114 int prev_chain_total_len, bool last_chained_pkt,
2115 int *pad_pkt_len, void **new_pkt)
2116{
2117 osl_t *osh;
2118 uint8 *frame;
2119 int pkt_len;
2120 int modulo;
2121 int head_padding;
2122 int tail_padding = 0;
2123 uint32 swheader;
2124 uint32 swhdr_offset;
2125 bool alloc_new_pkt = FALSE;
2126 uint8 sdpcm_hdrlen = bus->txglom_enable ? SDPCM_HDRLEN_TXGLOM : SDPCM_HDRLEN;
2127
2128 *new_pkt = NULL;
2129 osh = bus->dhd->osh;
2130
2131#ifdef DHDTCPACK_SUPPRESS
2132 if (dhd_tcpack_check_xmit(bus->dhd, pkt) == BCME_ERROR) {
2133 DHD_ERROR(("%s %d: tcpack_suppress ERROR!!! Stop using it\n",
2134 __FUNCTION__, __LINE__));
2135 dhd_tcpack_suppress_set(bus->dhd, TCPACK_SUP_OFF);
2136 }
2137#endif /* DHDTCPACK_SUPPRESS */
2138
2139 /* Add space for the SDPCM hardware/software headers */
2140 PKTPUSH(osh, pkt, sdpcm_hdrlen);
2141 ASSERT(ISALIGNED((uintptr)PKTDATA(osh, pkt), 2));
2142
2143 frame = (uint8*)PKTDATA(osh, pkt);
2144 pkt_len = (uint16)PKTLEN(osh, pkt);
2145
2146#ifdef DHD_DEBUG
2147 if (PKTPRIO(pkt) < ARRAYSIZE(tx_packets))
2148 tx_packets[PKTPRIO(pkt)]++;
2149#endif /* DHD_DEBUG */
2150
2151 /* align the data pointer, allocate a new packet if there is not enough space (new
2152 * packet data pointer will be aligned thus no padding will be needed)
2153 */
2154 head_padding = (uintptr)frame % DHD_SDALIGN;
2155 if (PKTHEADROOM(osh, pkt) < head_padding) {
2156 head_padding = 0;
2157 alloc_new_pkt = TRUE;
2158 } else {
2159 uint cur_chain_total_len;
2160 int chain_tail_padding = 0;
2161
2162 /* All packets need to be aligned by DHD_SDALIGN */
2163 modulo = (pkt_len + head_padding) % DHD_SDALIGN;
2164 tail_padding = modulo > 0 ? (DHD_SDALIGN - modulo) : 0;
2165
2166 /* Total pkt chain length needs to be aligned by block size,
2167 * unless it is a single pkt chain with total length less than one block size,
2168 * which we prefer sending by byte mode.
2169 *
2170 * Do the chain alignment here if
2171 * 1. This is the last pkt of the chain of multiple pkts or a single pkt.
2172 * 2-1. This chain is of multiple pkts, or
2173 * 2-2. This is a single pkt whose size is longer than one block size.
2174 */
2175 cur_chain_total_len = prev_chain_total_len +
2176 (head_padding + pkt_len + tail_padding);
2177 if (last_chained_pkt && bus->blocksize != 0 &&
2178 (cur_chain_total_len > (int)bus->blocksize || prev_chain_total_len > 0)) {
2179 modulo = cur_chain_total_len % bus->blocksize;
2180 chain_tail_padding = modulo > 0 ? (bus->blocksize - modulo) : 0;
2181 }
2182
2183#ifdef DHDENABLE_TAILPAD
2184 if (PKTTAILROOM(osh, pkt) < tail_padding) {
2185 /* We don't have tail room to align by DHD_SDALIGN */
2186 alloc_new_pkt = TRUE;
2187 bus->tx_tailpad_pktget++;
2188 } else if (PKTTAILROOM(osh, pkt) < tail_padding + chain_tail_padding) {
2189 /* We have tail room for tail_padding of this pkt itself, but not for
2190 * total pkt chain alignment by block size.
2191 * Use the padding packet to avoid memory copy if applicable,
2192 * otherwise, just allocate a new pkt.
2193 */
2194 if (bus->pad_pkt) {
2195 *pad_pkt_len = chain_tail_padding;
2196 bus->tx_tailpad_chain++;
2197 } else {
2198 alloc_new_pkt = TRUE;
2199 bus->tx_tailpad_pktget++;
2200 }
2201 } else
2202 /* This last pkt's tailroom is sufficient to hold both tail_padding
2203 * of the pkt itself and chain_tail_padding of total pkt chain
2204 */
2205#endif /* DHDENABLE_TAILPAD */
2206 tail_padding += chain_tail_padding;
2207 }
2208
2209 DHD_INFO(("%s sdhdr len + orig_pkt_len %d h_pad %d t_pad %d pad_pkt_len %d\n",
2210 __FUNCTION__, pkt_len, head_padding, tail_padding, *pad_pkt_len));
2211
2212 if (alloc_new_pkt) {
2213 void *tmp_pkt;
2214 int newpkt_size;
2215 int cur_total_len;
2216
2217 ASSERT(*pad_pkt_len == 0);
2218
2219 DHD_INFO(("%s allocating new packet for padding\n", __FUNCTION__));
2220
2221 /* head pointer is aligned now, no padding needed */
2222 head_padding = 0;
2223
2224 /* update the tail padding as it depends on the head padding, since a new packet is
2225 * allocated, the head padding is non longer needed and packet length is chagned
2226 */
2227
2228 cur_total_len = prev_chain_total_len + pkt_len;
2229 if (last_chained_pkt && bus->blocksize != 0 &&
2230 (cur_total_len > (int)bus->blocksize || prev_chain_total_len > 0)) {
2231 modulo = cur_total_len % bus->blocksize;
2232 tail_padding = modulo > 0 ? (bus->blocksize - modulo) : 0;
2233 } else {
2234 modulo = pkt_len % DHD_SDALIGN;
2235 tail_padding = modulo > 0 ? (DHD_SDALIGN - modulo) : 0;
2236 }
2237
2238 newpkt_size = PKTLEN(osh, pkt) + bus->blocksize + DHD_SDALIGN;
2239 bus->dhd->tx_realloc++;
2240 tmp_pkt = PKTGET(osh, newpkt_size, TRUE);
2241 if (tmp_pkt == NULL) {
2242 DHD_ERROR(("failed to alloc new %d byte packet\n", newpkt_size));
2243 return BCME_NOMEM;
2244 }
2245 PKTALIGN(osh, tmp_pkt, PKTLEN(osh, pkt), DHD_SDALIGN);
2246 bcopy(PKTDATA(osh, pkt), PKTDATA(osh, tmp_pkt), PKTLEN(osh, pkt));
2247 *new_pkt = tmp_pkt;
2248 pkt = tmp_pkt;
2249 }
2250
2251 if (head_padding)
2252 PKTPUSH(osh, pkt, head_padding);
2253
2254 frame = (uint8*)PKTDATA(osh, pkt);
2255 bzero(frame, head_padding + sdpcm_hdrlen);
2256 pkt_len = (uint16)PKTLEN(osh, pkt);
2257
2258 /* the header has the followming format
2259 * 4-byte HW frame tag: length, ~length (for glom this is the total length)
2260 *
2261 * 8-byte HW extesion flags (glom mode only) as the following:
2262 * 2-byte packet length, excluding HW tag and padding
2263 * 2-byte frame channel and frame flags (e.g. next frame following)
2264 * 2-byte header length
2265 * 2-byte tail padding size
2266 *
2267 * 8-byte SW frame tags as the following
2268 * 4-byte flags: host tx seq, channel, data offset
2269 * 4-byte flags: TBD
2270 */
2271
2272 swhdr_offset = SDPCM_FRAMETAG_LEN;
2273
2274 /* hardware frame tag:
2275 *
2276 * in tx-glom mode, dongle only checks the hardware frame tag in the first
2277 * packet and sees it as the total lenght of the glom (including tail padding),
2278 * for each packet in the glom, the packet length needs to be updated, (see
2279 * below PKTSETLEN)
2280 *
2281 * in non tx-glom mode, PKTLEN still need to include tail padding as to be
2282 * referred to in sdioh_request_buffer(). The tail length will be excluded in
2283 * dhdsdio_txpkt_postprocess().
2284 */
2285 *(uint16*)frame = (uint16)htol16(pkt_len);
2286 *(((uint16*)frame) + 1) = (uint16)htol16(~pkt_len);
2287 pkt_len += tail_padding;
2288
2289 /* hardware extesion flags */
2290 if (bus->txglom_enable) {
2291 uint32 hwheader1;
2292 uint32 hwheader2;
2293
2294 swhdr_offset += SDPCM_HWEXT_LEN;
2295 hwheader1 = (pkt_len - SDPCM_FRAMETAG_LEN - tail_padding) |
2296 (last_chained_pkt << 24);
2297 hwheader2 = (tail_padding) << 16;
2298 htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN);
2299 htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4);
2300 }
2301 PKTSETLEN((osh), (pkt), (pkt_len));
2302
2303 /* software frame tags */
2304 swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK)
2305 | (txseq % SDPCM_SEQUENCE_WRAP) |
2306 (((head_padding + sdpcm_hdrlen) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
2307 htol32_ua_store(swheader, frame + swhdr_offset);
2308 htol32_ua_store(0, frame + swhdr_offset + sizeof(swheader));
2309
2310 return pkt_len;
2311}
2312
2313static int dhdsdio_txpkt_postprocess(dhd_bus_t *bus, void *pkt)
2314{
2315 osl_t *osh;
2316 uint8 *frame;
2317 int data_offset;
2318 int tail_padding;
2319 int swhdr_offset = SDPCM_FRAMETAG_LEN + (bus->txglom_enable ? SDPCM_HWEXT_LEN : 0);
2320
2321 (void)osh;
2322 osh = bus->dhd->osh;
2323
2324 /* restore pkt buffer pointer, but keeps the header pushed by dhd_prot_hdrpush */
2325 frame = (uint8*)PKTDATA(osh, pkt);
2326
2327 DHD_INFO(("%s PKTLEN before postprocess %d",
2328 __FUNCTION__, PKTLEN(osh, pkt)));
2329
2330 /* PKTLEN still includes tail_padding, so exclude it.
2331 * We shall have head_padding + original pkt_len for PKTLEN afterwards.
2332 */
2333 if (bus->txglom_enable) {
2334 /* txglom pkts have tail_padding length in HW ext header */
2335 tail_padding = ltoh32_ua(frame + SDPCM_FRAMETAG_LEN + 4) >> 16;
2336 PKTSETLEN(osh, pkt, PKTLEN(osh, pkt) - tail_padding);
2337 DHD_INFO((" txglom pkt: tail_padding %d PKTLEN %d\n",
2338 tail_padding, PKTLEN(osh, pkt)));
2339 } else {
2340 /* non-txglom pkts have head_padding + original pkt length in HW frame tag.
2341 * We cannot refer to this field for txglom pkts as the first pkt of the chain will
2342 * have the field for the total length of the chain.
2343 */
2344 PKTSETLEN(osh, pkt, *(uint16*)frame);
2345 DHD_INFO((" non-txglom pkt: HW frame tag len %d after PKTLEN %d\n",
2346 *(uint16*)frame, PKTLEN(osh, pkt)));
2347 }
2348
2349 data_offset = ltoh32_ua(frame + swhdr_offset);
2350 data_offset = (data_offset & SDPCM_DOFFSET_MASK) >> SDPCM_DOFFSET_SHIFT;
2351 /* Get rid of sdpcm header + head_padding */
2352 PKTPULL(osh, pkt, data_offset);
2353
2354 DHD_INFO(("%s data_offset %d, PKTLEN %d\n",
2355 __FUNCTION__, data_offset, PKTLEN(osh, pkt)));
2356
2357 return BCME_OK;
2358}
2359
2360static int dhdsdio_txpkt(dhd_bus_t *bus, uint chan, void** pkts, int num_pkt, bool free_pkt)
2361{
2362 int i;
2363 int ret = 0;
2364 osl_t *osh;
2365 bcmsdh_info_t *sdh;
2366 void *pkt = NULL;
2367 void *pkt_chain;
2368 int total_len = 0;
2369 void *head_pkt = NULL;
2370 void *prev_pkt = NULL;
2371 int pad_pkt_len = 0;
2372 int new_pkt_num = 0;
2373 void *new_pkts[MAX_TX_PKTCHAIN_CNT];
2374 bool wlfc_enabled = FALSE;
2375
2376 if (bus->dhd->dongle_reset)
2377 return BCME_NOTREADY;
2378
2379 if (num_pkt <= 0)
2380 return BCME_BADARG;
2381
2382 sdh = bus->sdh;
2383 osh = bus->dhd->osh;
2384 /* init new_pkts[0] to make some compiler happy, not necessary as we check new_pkt_num */
2385 new_pkts[0] = NULL;
2386
2387 for (i = 0; i < num_pkt; i++) {
2388 int pkt_len;
2389 bool last_pkt;
2390 void *new_pkt = NULL;
2391
2392 pkt = pkts[i];
2393 ASSERT(pkt);
2394 last_pkt = (i == num_pkt - 1);
2395 pkt_len = dhdsdio_txpkt_preprocess(bus, pkt, chan, bus->tx_seq + i,
2396 total_len, last_pkt, &pad_pkt_len, &new_pkt);
2397 if (pkt_len <= 0)
2398 goto done;
2399 if (new_pkt) {
2400 pkt = new_pkt;
2401 new_pkts[new_pkt_num++] = new_pkt;
2402 }
2403 total_len += pkt_len;
2404
2405 PKTSETNEXT(osh, pkt, NULL);
2406 /* insert the packet into the list */
2407 head_pkt ? PKTSETNEXT(osh, prev_pkt, pkt) : (head_pkt = pkt);
2408 prev_pkt = pkt;
2409
2410 }
2411
2412 /* Update the HW frame tag (total length) in the first pkt of the glom */
2413 if (bus->txglom_enable) {
2414 uint8 *frame;
2415
2416 total_len += pad_pkt_len;
2417 frame = (uint8*)PKTDATA(osh, head_pkt);
2418 *(uint16*)frame = (uint16)htol16(total_len);
2419 *(((uint16*)frame) + 1) = (uint16)htol16(~total_len);
2420
2421 }
2422
2423#ifdef DHDENABLE_TAILPAD
2424 /* if a padding packet if needed, insert it to the end of the link list */
2425 if (pad_pkt_len) {
2426 PKTSETLEN(osh, bus->pad_pkt, pad_pkt_len);
2427 PKTSETNEXT(osh, pkt, bus->pad_pkt);
2428 }
2429#endif /* DHDENABLE_TAILPAD */
2430
2431 /* dhd_bcmsdh_send_buf ignores the buffer pointer if he packet
2432 * parameter is not NULL, for non packet chian we pass NULL pkt pointer
2433 * so it will take the aligned length and buffer pointer.
2434 */
2435 pkt_chain = PKTNEXT(osh, head_pkt) ? head_pkt : NULL;
2436 ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
2437 PKTDATA(osh, head_pkt), total_len, pkt_chain, NULL, NULL, TXRETRIES);
2438 if (ret == BCME_OK)
2439 bus->tx_seq = (bus->tx_seq + num_pkt) % SDPCM_SEQUENCE_WRAP;
2440
2441 /* if a padding packet was needed, remove it from the link list as it not a data pkt */
2442 if (pad_pkt_len && pkt)
2443 PKTSETNEXT(osh, pkt, NULL);
2444
2445done:
2446 pkt = head_pkt;
2447 while (pkt) {
2448 void *pkt_next = PKTNEXT(osh, pkt);
2449 PKTSETNEXT(osh, pkt, NULL);
2450 dhdsdio_txpkt_postprocess(bus, pkt);
2451 pkt = pkt_next;
2452 }
2453
2454 /* new packets might be allocated due to insufficient room for padding, but we
2455 * still have to indicate the original packets to upper layer
2456 */
2457 for (i = 0; i < num_pkt; i++) {
2458 pkt = pkts[i];
2459 wlfc_enabled = FALSE;
2460#ifdef PROP_TXSTATUS
2461 if (DHD_PKTTAG_WLFCPKT(PKTTAG(pkt))) {
2462 wlfc_enabled = (dhd_wlfc_txcomplete(bus->dhd, pkt, ret == 0) !=
2463 WLFC_UNSUPPORTED);
2464 }
2465#endif /* PROP_TXSTATUS */
2466 if (!wlfc_enabled) {
2467 PKTSETNEXT(osh, pkt, NULL);
2468 dhd_txcomplete(bus->dhd, pkt, ret != 0);
2469 if (free_pkt)
2470 PKTFREE(osh, pkt, TRUE);
2471 }
2472 }
2473
2474 for (i = 0; i < new_pkt_num; i++)
2475 PKTFREE(osh, new_pkts[i], TRUE);
2476
2477 return ret;
2478}
2479
2480static uint
2481dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes)
2482{
2483 uint cnt = 0;
2484 uint8 tx_prec_map;
2485 uint16 txpktqlen = 0;
2486 uint32 intstatus = 0;
2487 uint retries = 0;
2488 osl_t *osh;
2489 uint datalen = 0;
2490 dhd_pub_t *dhd = bus->dhd;
2491 sdpcmd_regs_t *regs = bus->regs;
2492#ifdef DHD_LOSSLESS_ROAMING
2493 uint8 *pktdata;
2494 struct ether_header *eh;
2495#endif /* DHD_LOSSLESS_ROAMING */
2496
2497 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2498
2499 if (!KSO_ENAB(bus)) {
2500 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
2501 return BCME_NODEVICE;
2502 }
2503
2504 osh = dhd->osh;
2505 tx_prec_map = ~bus->flowcontrol;
2506#ifdef DHD_LOSSLESS_ROAMING
2507 tx_prec_map &= dhd->dequeue_prec_map;
2508#endif /* DHD_LOSSLESS_ROAMING */
2509 for (cnt = 0; (cnt < maxframes) && DATAOK(bus);) {
2510 int i;
2511 int num_pkt = 1;
2512 void *pkts[MAX_TX_PKTCHAIN_CNT];
2513 int prec_out;
2514
2515 dhd_os_sdlock_txq(bus->dhd);
2516 if (bus->txglom_enable) {
2517 uint32 glomlimit = (uint32)bus->txglomsize;
2518#if defined(BCMSDIOH_STD)
2519 if (bus->blocksize == 64) {
2520 glomlimit = MIN((uint32)bus->txglomsize, BLK_64_MAXTXGLOM);
2521 }
2522#endif /* BCMSDIOH_STD */
2523 num_pkt = MIN((uint32)DATABUFCNT(bus), glomlimit);
2524 num_pkt = MIN(num_pkt, ARRAYSIZE(pkts));
2525 }
2526 num_pkt = MIN(num_pkt, pktq_mlen(&bus->txq, tx_prec_map));
2527 for (i = 0; i < num_pkt; i++) {
2528 pkts[i] = pktq_mdeq(&bus->txq, tx_prec_map, &prec_out);
2529 if (!pkts[i]) {
2530 DHD_ERROR(("%s: pktq_mlen non-zero when no pkt\n",
2531 __FUNCTION__));
2532 ASSERT(0);
2533 break;
2534 }
2535#ifdef DHD_LOSSLESS_ROAMING
2536 pktdata = (uint8 *)PKTDATA(osh, pkts[i]);
2537#ifdef BDC
2538 /* Skip BDC header */
2539 pktdata += BDC_HEADER_LEN + ((struct bdc_header *)pktdata)->dataOffset;
2540#endif // endif
2541 eh = (struct ether_header *)pktdata;
2542 if (eh->ether_type == hton16(ETHER_TYPE_802_1X)) {
2543 uint8 prio = (uint8)PKTPRIO(pkts[i]);
2544
2545 /* Restore to original priority for 802.1X packet */
2546 if (prio == PRIO_8021D_NC) {
2547 PKTSETPRIO(pkts[i], dhd->prio_8021x);
2548 }
2549 }
2550#endif /* DHD_LOSSLESS_ROAMING */
2551 PKTORPHAN(pkts[i]);
2552 datalen += PKTLEN(osh, pkts[i]);
2553 }
2554 dhd_os_sdunlock_txq(bus->dhd);
2555
2556 if (i == 0)
2557 break;
2558 if (dhdsdio_txpkt(bus, SDPCM_DATA_CHANNEL, pkts, i, TRUE) != BCME_OK)
2559 dhd->tx_errors++;
2560 else
2561 dhd->dstats.tx_bytes += datalen;
2562 cnt += i;
2563
2564 /* In poll mode, need to check for other events */
2565 if (!bus->intr && cnt)
2566 {
2567 /* Check device status, signal pending interrupt */
2568 R_SDREG(intstatus, &regs->intstatus, retries);
2569 bus->f2txdata++;
2570 if (bcmsdh_regfail(bus->sdh))
2571 break;
2572 if (intstatus & bus->hostintmask)
2573 bus->ipend = TRUE;
2574 }
2575
2576 }
2577
2578 dhd_os_sdlock_txq(bus->dhd);
2579 txpktqlen = pktq_n_pkts_tot(&bus->txq);
2580 dhd_os_sdunlock_txq(bus->dhd);
2581
2582 /* Do flow-control if needed */
2583 if (dhd->up && (dhd->busstate == DHD_BUS_DATA) && (txpktqlen < FCLOW)) {
2584 bool wlfc_enabled = FALSE;
2585#ifdef PROP_TXSTATUS
2586 wlfc_enabled = (dhd_wlfc_flowcontrol(dhd, OFF, TRUE) != WLFC_UNSUPPORTED);
2587#endif // endif
2588 if (!wlfc_enabled && dhd_doflow && dhd->txoff) {
2589 dhd_txflowcontrol(dhd, ALL_INTERFACES, OFF);
2590 }
2591 }
2592
2593 return cnt;
2594}
2595
2596static void
2597dhdsdio_sendpendctl(dhd_bus_t *bus)
2598{
2599 bcmsdh_info_t *sdh = bus->sdh;
2600 int ret;
2601 uint8* frame_seq = bus->ctrl_frame_buf + SDPCM_FRAMETAG_LEN;
2602
2603 if (bus->txglom_enable)
2604 frame_seq += SDPCM_HWEXT_LEN;
2605
2606 if (*frame_seq != bus->tx_seq) {
2607 DHD_INFO(("%s IOCTL frame seq lag detected!"
2608 " frm_seq:%d != bus->tx_seq:%d, corrected\n",
2609 __FUNCTION__, *frame_seq, bus->tx_seq));
2610 *frame_seq = bus->tx_seq;
2611 }
2612
2613 ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
2614 (uint8 *)bus->ctrl_frame_buf, (uint32)bus->ctrl_frame_len,
2615 NULL, NULL, NULL, 1);
2616 if (ret == BCME_OK)
2617 bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
2618
2619 bus->ctrl_frame_stat = FALSE;
2620 dhd_wait_event_wakeup(bus->dhd);
2621}
2622
2623int
2624dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen)
2625{
2626 static int err_nodevice = 0;
2627 uint8 *frame;
2628 uint16 len;
2629 uint32 swheader;
2630 uint8 doff = 0;
2631 int ret = -1;
2632 uint8 sdpcm_hdrlen = bus->txglom_enable ? SDPCM_HDRLEN_TXGLOM : SDPCM_HDRLEN;
2633
2634 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2635
2636 if (bus->dhd->dongle_reset)
2637 return -EIO;
2638
2639 /* Back the pointer to make a room for bus header */
2640 frame = msg - sdpcm_hdrlen;
2641 len = (msglen += sdpcm_hdrlen);
2642
2643 /* Add alignment padding (optional for ctl frames) */
2644 if (dhd_alignctl) {
2645 if ((doff = ((uintptr)frame % DHD_SDALIGN))) {
2646 frame -= doff;
2647 len += doff;
2648 msglen += doff;
2649 bzero(frame, doff + sdpcm_hdrlen);
2650 }
2651 ASSERT(doff < DHD_SDALIGN);
2652 }
2653 doff += sdpcm_hdrlen;
2654
2655#ifndef BCMSPI
2656 /* Round send length to next SDIO block */
2657 if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
2658 uint16 pad = bus->blocksize - (len % bus->blocksize);
2659 if ((pad <= bus->roundup) && (pad < bus->blocksize))
2660 len += pad;
2661 } else if (len % DHD_SDALIGN) {
2662 len += DHD_SDALIGN - (len % DHD_SDALIGN);
2663 }
2664#endif /* BCMSPI */
2665
2666 /* Satisfy length-alignment requirements */
2667 if (forcealign && (len & (ALIGNMENT - 1)))
2668 len = ROUNDUP(len, ALIGNMENT);
2669
2670 ASSERT(ISALIGNED((uintptr)frame, 2));
2671
2672 /* Need to lock here to protect txseq and SDIO tx calls */
2673 dhd_os_sdlock(bus->dhd);
2674
2675 BUS_WAKE(bus);
2676
2677 /* Make sure backplane clock is on */
2678 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
2679
2680 /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
2681 *(uint16*)frame = htol16((uint16)msglen);
2682 *(((uint16*)frame) + 1) = htol16(~msglen);
2683
2684 if (bus->txglom_enable) {
2685 uint32 hwheader1, hwheader2;
2686 /* Software tag: channel, sequence number, data offset */
2687 swheader = ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK)
2688 | bus->tx_seq
2689 | ((doff << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
2690 htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN);
2691 htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN
2692 + SDPCM_HWEXT_LEN + sizeof(swheader));
2693
2694 hwheader1 = (msglen - SDPCM_FRAMETAG_LEN) | (1 << 24);
2695 hwheader2 = (len - (msglen)) << 16;
2696 htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN);
2697 htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4);
2698
2699 *(uint16*)frame = htol16(len);
2700 *(((uint16*)frame) + 1) = htol16(~(len));
2701 } else {
2702 /* Software tag: channel, sequence number, data offset */
2703 swheader = ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK)
2704 | bus->tx_seq | ((doff << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
2705 htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN);
2706 htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
2707 }
2708
2709#ifdef DHD_ULP
2710 dhd_ulp_set_path(bus->dhd, DHD_ULP_TX_CTRL);
2711
2712 if (!TXCTLOK(bus) || !dhd_ulp_f2_ready(bus->dhd, bus->sdh))
2713#else
2714 if (!TXCTLOK(bus))
2715#endif // endif
2716 {
2717 DHD_INFO(("%s: No bus credit bus->tx_max %d, bus->tx_seq %d\n",
2718 __FUNCTION__, bus->tx_max, bus->tx_seq));
2719 bus->ctrl_frame_stat = TRUE;
2720 /* Send from dpc */
2721 bus->ctrl_frame_buf = frame;
2722 bus->ctrl_frame_len = len;
2723
2724 if (!bus->dpc_sched) {
2725 bus->dpc_sched = TRUE;
2726 dhd_sched_dpc(bus->dhd);
2727 }
2728 if (bus->ctrl_frame_stat) {
2729 dhd_wait_for_event(bus->dhd, &bus->ctrl_frame_stat);
2730 }
2731
2732 if (bus->ctrl_frame_stat == FALSE) {
2733 DHD_INFO(("%s: ctrl_frame_stat == FALSE\n", __FUNCTION__));
2734 ret = 0;
2735 } else {
2736 bus->dhd->txcnt_timeout++;
2737 if (!bus->dhd->hang_was_sent) {
2738#ifdef CUSTOMER_HW4_DEBUG
2739 uint32 status, retry = 0;
2740 R_SDREG(status, &bus->regs->intstatus, retry);
2741 DHD_TRACE_HW4(("%s: txcnt_timeout, INT status=0x%08X\n",
2742 __FUNCTION__, status));
2743 DHD_TRACE_HW4(("%s : tx_max : %d, tx_seq : %d, clkstate : %d \n",
2744 __FUNCTION__, bus->tx_max, bus->tx_seq, bus->clkstate));
2745#endif /* CUSTOMER_HW4_DEBUG */
2746 DHD_ERROR(("%s: ctrl_frame_stat == TRUE txcnt_timeout=%d\n",
2747 __FUNCTION__, bus->dhd->txcnt_timeout));
2748 }
2749#ifdef DHD_FW_COREDUMP
2750 /* Collect socram dump */
2751 if ((bus->dhd->memdump_enabled) &&
2752 (bus->dhd->txcnt_timeout >= MAX_CNTL_TX_TIMEOUT)) {
2753 /* collect core dump */
2754 bus->dhd->memdump_type = DUMP_TYPE_RESUMED_ON_TIMEOUT_TX;
2755 dhd_os_sdunlock(bus->dhd);
2756 dhd_bus_mem_dump(bus->dhd);
2757 dhd_os_sdlock(bus->dhd);
2758 }
2759#endif /* DHD_FW_COREDUMP */
2760 ret = -1;
2761 bus->ctrl_frame_stat = FALSE;
2762 goto done;
2763 }
2764 }
2765
2766 bus->dhd->txcnt_timeout = 0;
2767 bus->ctrl_frame_stat = TRUE;
2768
2769 if (ret == -1) {
2770#ifdef DHD_DEBUG
2771 if (DHD_BYTES_ON() && DHD_CTL_ON()) {
2772 prhex("Tx Frame", frame, len);
2773 } else if (DHD_HDRS_ON()) {
2774 prhex("TxHdr", frame, MIN(len, 16));
2775 }
2776#endif // endif
2777 ret = dhd_bcmsdh_send_buffer(bus, frame, len);
2778 }
2779 bus->ctrl_frame_stat = FALSE;
2780#ifdef DHD_ULP
2781 dhd_ulp_enable_cached_sbwad(bus->dhd, bus->sdh);
2782#endif /* DHD_ULP */
2783
2784done:
2785 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched &&
2786 NO_OTHER_ACTIVE_BUS_USER(bus)) {
2787 bus->activity = FALSE;
2788 dhdsdio_bussleep(bus, TRUE);
2789 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
2790 }
2791
2792 dhd_os_sdunlock(bus->dhd);
2793
2794 if (ret)
2795 bus->dhd->tx_ctlerrs++;
2796 else
2797 bus->dhd->tx_ctlpkts++;
2798
2799 if (bus->dhd->txcnt_timeout >= MAX_CNTL_TX_TIMEOUT) {
2800#ifdef DHD_PM_CONTROL_FROM_FILE
2801 if (g_pm_control == TRUE) {
2802 return -BCME_ERROR;
2803 } else {
2804 return -ETIMEDOUT;
2805 }
2806#else
2807 return -ETIMEDOUT;
2808#endif /* DHD_PM_CONTROL_FROM_FILE */
2809 }
2810 if (ret == BCME_NODEVICE)
2811 err_nodevice++;
2812 else
2813 err_nodevice = 0;
2814
2815 return ret ? err_nodevice >= ERROR_BCME_NODEVICE_MAX ? -ETIMEDOUT : -EIO : 0;
2816}
2817
2818int
2819dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen)
2820{
2821 int timeleft;
2822 uint rxlen = 0;
2823
2824 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2825
2826 if (bus->dhd->dongle_reset)
2827 return -EIO;
2828
2829 /* Wait until control frame is available */
2830 timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->rxlen);
2831
2832 dhd_os_sdlock(bus->dhd);
2833 rxlen = bus->rxlen;
2834 bcopy(bus->rxctl, msg, MIN(msglen, rxlen));
2835 bus->rxlen = 0;
2836 dhd_os_sdunlock(bus->dhd);
2837
2838 if (rxlen) {
2839 DHD_CTL(("%s: resumed on rxctl frame, got %d expected %d\n",
2840 __FUNCTION__, rxlen, msglen));
2841 } else {
2842 if (timeleft == 0) {
2843#ifdef DHD_DEBUG
2844 uint32 status, retry = 0;
2845 R_SDREG(status, &bus->regs->intstatus, retry);
2846 DHD_ERROR(("%s: resumed on timeout, INT status=0x%08X\n",
2847 __FUNCTION__, status));
2848#else
2849 DHD_ERROR(("%s: resumed on timeout\n", __FUNCTION__));
2850#endif /* DHD_DEBUG */
2851 if (!bus->dhd->dongle_trap_occured) {
2852#ifdef DHD_FW_COREDUMP
2853 bus->dhd->memdump_type = DUMP_TYPE_RESUMED_ON_TIMEOUT;
2854#endif /* DHD_FW_COREDUMP */
2855 dhd_os_sdlock(bus->dhd);
2856 dhdsdio_checkdied(bus, NULL, 0);
2857 dhd_os_sdunlock(bus->dhd);
2858 }
2859 } else {
2860 DHD_CTL(("%s: resumed for unknown reason?\n", __FUNCTION__));
2861 if (!bus->dhd->dongle_trap_occured) {
2862#ifdef DHD_FW_COREDUMP
2863 bus->dhd->memdump_type = DUMP_TYPE_RESUMED_UNKNOWN;
2864#endif /* DHD_FW_COREDUMP */
2865 dhd_os_sdlock(bus->dhd);
2866 dhdsdio_checkdied(bus, NULL, 0);
2867 dhd_os_sdunlock(bus->dhd);
2868 }
2869 }
2870#ifdef DHD_FW_COREDUMP
2871 /* Dump the ram image */
2872 if (bus->dhd->memdump_enabled && !bus->dhd->dongle_trap_occured)
2873 dhdsdio_mem_dump(bus);
2874#endif /* DHD_FW_COREDUMP */
2875 }
2876 if (timeleft == 0) {
2877 if (rxlen == 0)
2878 bus->dhd->rxcnt_timeout++;
2879 DHD_ERROR(("%s: rxcnt_timeout=%d, rxlen=%d\n", __FUNCTION__,
2880 bus->dhd->rxcnt_timeout, rxlen));
2881#ifdef DHD_FW_COREDUMP
2882 /* collect socram dump */
2883 if (bus->dhd->memdump_enabled) {
2884 bus->dhd->memdump_type = DUMP_TYPE_RESUMED_ON_TIMEOUT_RX;
2885 dhd_bus_mem_dump(bus->dhd);
2886 }
2887#endif /* DHD_FW_COREDUMP */
2888 } else {
2889 bus->dhd->rxcnt_timeout = 0;
2890 }
2891
2892 if (rxlen)
2893 bus->dhd->rx_ctlpkts++;
2894 else
2895 bus->dhd->rx_ctlerrs++;
2896
2897 if (bus->dhd->rxcnt_timeout >= MAX_CNTL_RX_TIMEOUT) {
2898#ifdef DHD_PM_CONTROL_FROM_FILE
2899 if (g_pm_control == TRUE) {
2900 return -BCME_ERROR;
2901 } else {
2902 return -ETIMEDOUT;
2903 }
2904#else
2905 return -ETIMEDOUT;
2906#endif /* DHD_PM_CONTROL_FROM_FILE */
2907 }
2908 if (bus->dhd->dongle_trap_occured)
2909 return -EREMOTEIO;
2910
2911 return rxlen ? (int)rxlen : -EIO;
2912}
2913
2914/* IOVar table */
2915enum {
2916 IOV_INTR = 1,
2917 IOV_POLLRATE,
2918 IOV_SDREG,
2919 IOV_SBREG,
2920 IOV_SDCIS,
2921 IOV_RAMSIZE,
2922 IOV_RAMSTART,
2923#ifdef DHD_DEBUG
2924 IOV_CHECKDIED,
2925 IOV_SERIALCONS,
2926#endif /* DHD_DEBUG */
2927 IOV_SET_DOWNLOAD_STATE,
2928 IOV_SOCRAM_STATE,
2929 IOV_FORCEEVEN,
2930 IOV_SDIOD_DRIVE,
2931 IOV_READAHEAD,
2932 IOV_SDRXCHAIN,
2933 IOV_ALIGNCTL,
2934 IOV_SDALIGN,
2935 IOV_DEVRESET,
2936 IOV_CPU,
2937#if defined(USE_SDIOFIFO_IOVAR)
2938 IOV_WATERMARK,
2939 IOV_MESBUSYCTRL,
2940#endif /* USE_SDIOFIFO_IOVAR */
2941#ifdef SDTEST
2942 IOV_PKTGEN,
2943 IOV_EXTLOOP,
2944#endif /* SDTEST */
2945 IOV_SPROM,
2946 IOV_TXBOUND,
2947 IOV_RXBOUND,
2948 IOV_TXMINMAX,
2949 IOV_IDLETIME,
2950 IOV_IDLECLOCK,
2951 IOV_SD1IDLE,
2952 IOV_SLEEP,
2953 IOV_DONGLEISOLATION,
2954 IOV_KSO,
2955 IOV_DEVSLEEP,
2956 IOV_DEVCAP,
2957 IOV_VARS,
2958#ifdef SOFTAP
2959 IOV_FWPATH,
2960#endif // endif
2961 IOV_TXGLOMSIZE,
2962 IOV_TXGLOMMODE,
2963 IOV_HANGREPORT,
2964 IOV_TXINRX_THRES,
2965 IOV_SDIO_SUSPEND
2966#if defined(DEBUGGER) || defined(DHD_DSCOPE)
2967 IOV_GDB_SERVER, /**< starts gdb server on given interface */
2968#endif /* DEBUGGER || DHD_DSCOPE */
2969};
2970
2971const bcm_iovar_t dhdsdio_iovars[] = {
2972 {"intr", IOV_INTR, 0, 0, IOVT_BOOL, 0 },
2973 {"sleep", IOV_SLEEP, 0, 0, IOVT_BOOL, 0 },
2974 {"pollrate", IOV_POLLRATE, 0, 0, IOVT_UINT32, 0 },
2975 {"idletime", IOV_IDLETIME, 0, 0, IOVT_INT32, 0 },
2976 {"idleclock", IOV_IDLECLOCK, 0, 0, IOVT_INT32, 0 },
2977 {"sd1idle", IOV_SD1IDLE, 0, 0, IOVT_BOOL, 0 },
2978 {"ramsize", IOV_RAMSIZE, 0, 0, IOVT_UINT32, 0 },
2979 {"ramstart", IOV_RAMSTART, 0, 0, IOVT_UINT32, 0 },
2980 {"dwnldstate", IOV_SET_DOWNLOAD_STATE, 0, 0, IOVT_BOOL, 0 },
2981 {"socram_state", IOV_SOCRAM_STATE, 0, 0, IOVT_BOOL, 0 },
2982 {"vars", IOV_VARS, 0, 0, IOVT_BUFFER, 0 },
2983 {"sdiod_drive", IOV_SDIOD_DRIVE, 0, 0, IOVT_UINT32, 0 },
2984 {"readahead", IOV_READAHEAD, 0, 0, IOVT_BOOL, 0 },
2985 {"sdrxchain", IOV_SDRXCHAIN, 0, 0, IOVT_BOOL, 0 },
2986 {"alignctl", IOV_ALIGNCTL, 0, 0, IOVT_BOOL, 0 },
2987 {"sdalign", IOV_SDALIGN, 0, 0, IOVT_BOOL, 0 },
2988 {"devreset", IOV_DEVRESET, 0, 0, IOVT_BOOL, 0 },
2989#ifdef DHD_DEBUG
2990 {"sdreg", IOV_SDREG, 0, 0, IOVT_BUFFER, sizeof(sdreg_t) },
2991 {"sbreg", IOV_SBREG, 0, 0, IOVT_BUFFER, sizeof(sdreg_t) },
2992 {"sd_cis", IOV_SDCIS, 0, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN },
2993 {"forcealign", IOV_FORCEEVEN, 0, 0, IOVT_BOOL, 0 },
2994 {"txbound", IOV_TXBOUND, 0, 0, IOVT_UINT32, 0 },
2995 {"rxbound", IOV_RXBOUND, 0, 0, IOVT_UINT32, 0 },
2996 {"txminmax", IOV_TXMINMAX, 0, 0, IOVT_UINT32, 0 },
2997 {"cpu", IOV_CPU, 0, 0, IOVT_BOOL, 0 },
2998#ifdef DHD_DEBUG
2999 {"checkdied", IOV_CHECKDIED, 0, 0, IOVT_BUFFER, 0 },
3000 {"serial", IOV_SERIALCONS, 0, 0, IOVT_UINT32, 0 },
3001#endif /* DHD_DEBUG */
3002#endif /* DHD_DEBUG */
3003#ifdef SDTEST
3004 {"extloop", IOV_EXTLOOP, 0, 0, IOVT_BOOL, 0 },
3005 {"pktgen", IOV_PKTGEN, 0, 0, IOVT_BUFFER, sizeof(dhd_pktgen_t) },
3006#endif /* SDTEST */
3007#if defined(USE_SDIOFIFO_IOVAR)
3008 {"watermark", IOV_WATERMARK, 0, 0, IOVT_UINT32, 0 },
3009 {"mesbusyctrl", IOV_MESBUSYCTRL, 0, 0, IOVT_UINT32, 0 },
3010#endif /* USE_SDIOFIFO_IOVAR */
3011 {"devcap", IOV_DEVCAP, 0, 0, IOVT_UINT32, 0 },
3012 {"dngl_isolation", IOV_DONGLEISOLATION, 0, 0, IOVT_UINT32, 0 },
3013 {"kso", IOV_KSO, 0, 0, IOVT_UINT32, 0 },
3014 {"devsleep", IOV_DEVSLEEP, 0, 0, IOVT_UINT32, 0 },
3015#ifdef SOFTAP
3016 {"fwpath", IOV_FWPATH, 0, 0, IOVT_BUFFER, 0 },
3017#endif // endif
3018 {"txglomsize", IOV_TXGLOMSIZE, 0, 0, IOVT_UINT32, 0 },
3019 {"fw_hang_report", IOV_HANGREPORT, 0, 0, IOVT_BOOL, 0 },
3020 {"txinrx_thres", IOV_TXINRX_THRES, 0, 0, IOVT_INT32, 0 },
3021 {"sdio_suspend", IOV_SDIO_SUSPEND, 0, 0, IOVT_UINT32, 0 },
3022#if defined(DEBUGGER) || defined(DHD_DSCOPE)
3023 {"gdb_server", IOV_GDB_SERVER, 0, 0, IOVT_UINT32, 0 },
3024#endif /* DEBUGGER || DHD_DSCOPE */
3025 {NULL, 0, 0, 0, 0, 0 }
3026};
3027
3028static void
3029dhd_dump_pct(struct bcmstrbuf *strbuf, char *desc, uint num, uint div)
3030{
3031 uint q1, q2;
3032
3033 if (!div) {
3034 bcm_bprintf(strbuf, "%s N/A", desc);
3035 } else {
3036 q1 = num / div;
3037 q2 = (100 * (num - (q1 * div))) / div;
3038 bcm_bprintf(strbuf, "%s %d.%02d", desc, q1, q2);
3039 }
3040}
3041
3042void
3043dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf)
3044{
3045 dhd_bus_t *bus = dhdp->bus;
3046#if defined(DHD_WAKE_STATUS) && defined(DHD_WAKE_EVENT_STATUS)
3047 int i;
3048#endif // endif
3049
3050 bcm_bprintf(strbuf, "Bus SDIO structure:\n");
3051 bcm_bprintf(strbuf, "hostintmask 0x%08x intstatus 0x%08x sdpcm_ver %d\n",
3052 bus->hostintmask, bus->intstatus, bus->sdpcm_ver);
3053 bcm_bprintf(strbuf, "fcstate %d qlen %u tx_seq %d, max %d, rxskip %d rxlen %u rx_seq %d\n",
3054 bus->fcstate, pktq_n_pkts_tot(&bus->txq), bus->tx_seq, bus->tx_max, bus->rxskip,
3055 bus->rxlen, bus->rx_seq);
3056 bcm_bprintf(strbuf, "intr %d intrcount %u lastintrs %u spurious %u\n",
3057 bus->intr, bus->intrcount, bus->lastintrs, bus->spurious);
3058
3059#ifdef DHD_WAKE_STATUS
3060 bcm_bprintf(strbuf, "wake %u rxwake %u readctrlwake %u\n",
3061 bcmsdh_get_total_wake(bus->sdh), bus->wake_counts.rxwake,
3062 bus->wake_counts.rcwake);
3063#ifdef DHD_WAKE_RX_STATUS
3064 bcm_bprintf(strbuf, " unicast %u multicast %u broadcast %u arp %u\n",
3065 bus->wake_counts.rx_ucast, bus->wake_counts.rx_mcast,
3066 bus->wake_counts.rx_bcast, bus->wake_counts.rx_arp);
3067 bcm_bprintf(strbuf, " multi4 %u multi6 %u icmp6 %u multiother %u\n",
3068 bus->wake_counts.rx_multi_ipv4, bus->wake_counts.rx_multi_ipv6,
3069 bus->wake_counts.rx_icmpv6, bus->wake_counts.rx_multi_other);
3070 bcm_bprintf(strbuf, " icmp6_ra %u, icmp6_na %u, icmp6_ns %u\n",
3071 bus->wake_counts.rx_icmpv6_ra, bus->wake_counts.rx_icmpv6_na,
3072 bus->wake_counts.rx_icmpv6_ns);
3073#endif /* DHD_WAKE_RX_STATUS */
3074#ifdef DHD_WAKE_EVENT_STATUS
3075 for (i = 0; i < WLC_E_LAST; i++)
3076 if (bus->wake_counts.rc_event[i] != 0)
3077 bcm_bprintf(strbuf, " %s = %u\n", bcmevent_get_name(i),
3078 bus->wake_counts.rc_event[i]);
3079 bcm_bprintf(strbuf, "\n");
3080#endif /* DHD_WAKE_EVENT_STATUS */
3081#endif /* DHD_WAKE_STATUS */
3082
3083 bcm_bprintf(strbuf, "pollrate %u pollcnt %u regfails %u\n",
3084 bus->pollrate, bus->pollcnt, bus->regfails);
3085
3086 bcm_bprintf(strbuf, "\nAdditional counters:\n");
3087#ifdef DHDENABLE_TAILPAD
3088 bcm_bprintf(strbuf, "tx_tailpad_chain %u tx_tailpad_pktget %u\n",
3089 bus->tx_tailpad_chain, bus->tx_tailpad_pktget);
3090#endif /* DHDENABLE_TAILPAD */
3091 bcm_bprintf(strbuf, "tx_sderrs %u fcqueued %u rxrtx %u rx_toolong %u rxc_errors %u\n",
3092 bus->tx_sderrs, bus->fcqueued, bus->rxrtx, bus->rx_toolong,
3093 bus->rxc_errors);
3094 bcm_bprintf(strbuf, "rx_hdrfail %u badhdr %u badseq %u\n",
3095 bus->rx_hdrfail, bus->rx_badhdr, bus->rx_badseq);
3096 bcm_bprintf(strbuf, "fc_rcvd %u, fc_xoff %u, fc_xon %u\n",
3097 bus->fc_rcvd, bus->fc_xoff, bus->fc_xon);
3098 bcm_bprintf(strbuf, "rxglomfail %u, rxglomframes %u, rxglompkts %u\n",
3099 bus->rxglomfail, bus->rxglomframes, bus->rxglompkts);
3100 bcm_bprintf(strbuf, "f2rx (hdrs/data) %u (%u/%u), f2tx %u f1regs %u\n",
3101 (bus->f2rxhdrs + bus->f2rxdata), bus->f2rxhdrs, bus->f2rxdata,
3102 bus->f2txdata, bus->f1regdata);
3103 {
3104 dhd_dump_pct(strbuf, "\nRx: pkts/f2rd", bus->dhd->rx_packets,
3105 (bus->f2rxhdrs + bus->f2rxdata));
3106 dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->rx_packets, bus->f1regdata);
3107 dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->rx_packets,
3108 (bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata));
3109 dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->rx_packets, bus->intrcount);
3110 bcm_bprintf(strbuf, "\n");
3111
3112 dhd_dump_pct(strbuf, "Rx: glom pct", (100 * bus->rxglompkts),
3113 bus->dhd->rx_packets);
3114 dhd_dump_pct(strbuf, ", pkts/glom", bus->rxglompkts, bus->rxglomframes);
3115 bcm_bprintf(strbuf, "\n");
3116
3117 dhd_dump_pct(strbuf, "Tx: pkts/f2wr", bus->dhd->tx_packets, bus->f2txdata);
3118 dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->tx_packets, bus->f1regdata);
3119 dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->tx_packets,
3120 (bus->f2txdata + bus->f1regdata));
3121 dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->tx_packets, bus->intrcount);
3122 bcm_bprintf(strbuf, "\n");
3123
3124 dhd_dump_pct(strbuf, "Total: pkts/f2rw",
3125 (bus->dhd->tx_packets + bus->dhd->rx_packets),
3126 (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata));
3127 dhd_dump_pct(strbuf, ", pkts/f1sd",
3128 (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->f1regdata);
3129 dhd_dump_pct(strbuf, ", pkts/sd",
3130 (bus->dhd->tx_packets + bus->dhd->rx_packets),
3131 (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata));
3132 dhd_dump_pct(strbuf, ", pkts/int",
3133 (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->intrcount);
3134 bcm_bprintf(strbuf, "\n\n");
3135 }
3136
3137#ifdef SDTEST
3138 if (bus->pktgen_count) {
3139 bcm_bprintf(strbuf, "pktgen config and count:\n");
3140 bcm_bprintf(strbuf, "freq %u count %u print %u total %u min %u len %u\n",
3141 bus->pktgen_freq, bus->pktgen_count, bus->pktgen_print,
3142 bus->pktgen_total, bus->pktgen_minlen, bus->pktgen_maxlen);
3143 bcm_bprintf(strbuf, "send attempts %u rcvd %u fail %u\n",
3144 bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail);
3145 }
3146#endif /* SDTEST */
3147#ifdef DHD_DEBUG
3148 bcm_bprintf(strbuf, "dpc_sched %d host interrupt%spending\n",
3149 bus->dpc_sched, (bcmsdh_intr_pending(bus->sdh) ? " " : " not "));
3150 bcm_bprintf(strbuf, "blocksize %u roundup %u\n", bus->blocksize, bus->roundup);
3151#endif /* DHD_DEBUG */
3152 bcm_bprintf(strbuf, "clkstate %d activity %d idletime %d idlecount %d sleeping %d\n",
3153 bus->clkstate, bus->activity, bus->idletime, bus->idlecount, bus->sleeping);
3154}
3155
3156void
3157dhd_bus_clearcounts(dhd_pub_t *dhdp)
3158{
3159 dhd_bus_t *bus = (dhd_bus_t *)dhdp->bus;
3160
3161 bus->intrcount = bus->lastintrs = bus->spurious = bus->regfails = 0;
3162 bus->rxrtx = bus->rx_toolong = bus->rxc_errors = 0;
3163 bus->rx_hdrfail = bus->rx_badhdr = bus->rx_badseq = 0;
3164#ifdef DHDENABLE_TAILPAD
3165 bus->tx_tailpad_chain = bus->tx_tailpad_pktget = 0;
3166#endif /* DHDENABLE_TAILPAD */
3167 bus->tx_sderrs = bus->fc_rcvd = bus->fc_xoff = bus->fc_xon = 0;
3168 bus->rxglomfail = bus->rxglomframes = bus->rxglompkts = 0;
3169 bus->f2rxhdrs = bus->f2rxdata = bus->f2txdata = bus->f1regdata = 0;
3170}
3171
3172#ifdef SDTEST
3173static int
3174dhdsdio_pktgen_get(dhd_bus_t *bus, uint8 *arg)
3175{
3176 dhd_pktgen_t pktgen;
3177
3178 pktgen.version = DHD_PKTGEN_VERSION;
3179 pktgen.freq = bus->pktgen_freq;
3180 pktgen.count = bus->pktgen_count;
3181 pktgen.print = bus->pktgen_print;
3182 pktgen.total = bus->pktgen_total;
3183 pktgen.minlen = bus->pktgen_minlen;
3184 pktgen.maxlen = bus->pktgen_maxlen;
3185 pktgen.numsent = bus->pktgen_sent;
3186 pktgen.numrcvd = bus->pktgen_rcvd;
3187 pktgen.numfail = bus->pktgen_fail;
3188 pktgen.mode = bus->pktgen_mode;
3189 pktgen.stop = bus->pktgen_stop;
3190
3191 bcopy(&pktgen, arg, sizeof(pktgen));
3192
3193 return 0;
3194}
3195
3196static int
3197dhdsdio_pktgen_set(dhd_bus_t *bus, uint8 *arg)
3198{
3199 dhd_pktgen_t pktgen;
3200 uint oldcnt, oldmode;
3201
3202 bcopy(arg, &pktgen, sizeof(pktgen));
3203 if (pktgen.version != DHD_PKTGEN_VERSION)
3204 return BCME_BADARG;
3205
3206 oldcnt = bus->pktgen_count;
3207 oldmode = bus->pktgen_mode;
3208
3209 bus->pktgen_freq = pktgen.freq;
3210 bus->pktgen_count = pktgen.count;
3211 bus->pktgen_print = pktgen.print;
3212 bus->pktgen_total = pktgen.total;
3213 bus->pktgen_minlen = pktgen.minlen;
3214 bus->pktgen_maxlen = pktgen.maxlen;
3215 bus->pktgen_mode = pktgen.mode;
3216 bus->pktgen_stop = pktgen.stop;
3217
3218 bus->pktgen_tick = bus->pktgen_ptick = 0;
3219 bus->pktgen_prev_time = jiffies;
3220 bus->pktgen_len = MAX(bus->pktgen_len, bus->pktgen_minlen);
3221 bus->pktgen_len = MIN(bus->pktgen_len, bus->pktgen_maxlen);
3222
3223 /* Clear counts for a new pktgen (mode change, or was stopped) */
3224 if (bus->pktgen_count && (!oldcnt || oldmode != bus->pktgen_mode)) {
3225 bus->pktgen_sent = bus->pktgen_prev_sent = bus->pktgen_rcvd = 0;
3226 bus->pktgen_prev_rcvd = bus->pktgen_fail = 0;
3227 }
3228
3229 return 0;
3230}
3231#endif /* SDTEST */
3232
3233static void
3234dhdsdio_devram_remap(dhd_bus_t *bus, bool val)
3235{
3236 uint8 enable, protect, remap;
3237
3238 si_socdevram(bus->sih, FALSE, &enable, &protect, &remap);
3239 remap = val ? TRUE : FALSE;
3240 si_socdevram(bus->sih, TRUE, &enable, &protect, &remap);
3241}
3242
3243static int
3244dhdsdio_membytes(dhd_bus_t *bus, bool write, uint32 address, uint8 *data, uint size)
3245{
3246 int bcmerror = 0;
3247 uint32 sdaddr;
3248 uint dsize;
3249
3250 /* In remap mode, adjust address beyond socram and redirect
3251 * to devram at SOCDEVRAM_BP_ADDR since remap address > orig_ramsize
3252 * is not backplane accessible
3253 */
3254 if (REMAP_ENAB(bus) && REMAP_ISADDR(bus, address)) {
3255 address -= bus->orig_ramsize;
3256 address += SOCDEVRAM_BP_ADDR;
3257 }
3258
3259 /* Determine initial transfer parameters */
3260 sdaddr = address & SBSDIO_SB_OFT_ADDR_MASK;
3261 if ((sdaddr + size) & SBSDIO_SBWINDOW_MASK)
3262 dsize = (SBSDIO_SB_OFT_ADDR_LIMIT - sdaddr);
3263 else
3264 dsize = size;
3265
3266 /* Set the backplane window to include the start address */
3267 if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) {
3268 DHD_ERROR(("%s: window change failed\n", __FUNCTION__));
3269 goto xfer_done;
3270 }
3271
3272 /* Do the transfer(s) */
3273 while (size) {
3274 DHD_INFO(("%s: %s %d bytes at offset 0x%08x in window 0x%08x\n",
3275 __FUNCTION__, (write ? "write" : "read"), dsize, sdaddr,
3276 (address & SBSDIO_SBWINDOW_MASK)));
3277 if ((bcmerror = bcmsdh_rwdata(bus->sdh, write, sdaddr, data, dsize))) {
3278 DHD_ERROR(("%s: membytes transfer failed\n", __FUNCTION__));
3279 break;
3280 }
3281
3282 /* Adjust for next transfer (if any) */
3283 if ((size -= dsize)) {
3284 data += dsize;
3285 address += dsize;
3286 if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) {
3287 DHD_ERROR(("%s: window change failed\n", __FUNCTION__));
3288 break;
3289 }
3290 sdaddr = 0;
3291 dsize = MIN(SBSDIO_SB_OFT_ADDR_LIMIT, size);
3292 }
3293
3294 }
3295
3296xfer_done:
3297 /* Return the window to backplane enumeration space for core access */
3298 if (dhdsdio_set_siaddr_window(bus, bcmsdh_cur_sbwad(bus->sdh))) {
3299 DHD_ERROR(("%s: FAILED to set window back to 0x%x\n", __FUNCTION__,
3300 bcmsdh_cur_sbwad(bus->sdh)));
3301 }
3302
3303 return bcmerror;
3304}
3305
3306static int
3307dhdsdio_readshared(dhd_bus_t *bus, sdpcm_shared_t *sh)
3308{
3309 uint32 addr;
3310 int rv, i;
3311 uint32 shaddr = 0;
3312
3313 if (bus->sih == NULL) {
3314 if (bus->dhd && bus->dhd->dongle_reset) {
3315 DHD_ERROR(("%s: Dongle is in reset state\n", __FUNCTION__));
3316 return BCME_NOTREADY;
3317 } else {
3318 ASSERT(bus->dhd);
3319 ASSERT(bus->sih);
3320 DHD_ERROR(("%s: The address of sih is invalid\n", __FUNCTION__));
3321 return BCME_ERROR;
3322 }
3323 }
3324 if ((CHIPID(bus->sih->chip) == BCM43430_CHIP_ID ||
3325 CHIPID(bus->sih->chip) == BCM43018_CHIP_ID) && !dhdsdio_sr_cap(bus))
3326 bus->srmemsize = 0;
3327
3328 shaddr = bus->dongle_ram_base + bus->ramsize - 4;
3329 i = 0;
3330 do {
3331 /* Read last word in memory to determine address of sdpcm_shared structure */
3332 if ((rv = dhdsdio_membytes(bus, FALSE, shaddr, (uint8 *)&addr, 4)) < 0)
3333 return rv;
3334
3335 addr = ltoh32(addr);
3336
3337 DHD_INFO(("sdpcm_shared address 0x%08X\n", addr));
3338
3339 /*
3340 * Check if addr is valid.
3341 * NVRAM length at the end of memory should have been overwritten.
3342 */
3343 if (addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff)) {
3344 if ((bus->srmemsize > 0) && (i++ == 0)) {
3345 shaddr -= bus->srmemsize;
3346 } else {
3347 DHD_ERROR(("%s: address (0x%08x) of sdpcm_shared invalid\n",
3348 __FUNCTION__, addr));
3349 return BCME_ERROR;
3350 }
3351 } else
3352 break;
3353 } while (i < 2);
3354
3355 /* Read hndrte_shared structure */
3356 if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)sh, sizeof(sdpcm_shared_t))) < 0)
3357 return rv;
3358
3359 /* Endianness */
3360 sh->flags = ltoh32(sh->flags);
3361 sh->trap_addr = ltoh32(sh->trap_addr);
3362 sh->assert_exp_addr = ltoh32(sh->assert_exp_addr);
3363 sh->assert_file_addr = ltoh32(sh->assert_file_addr);
3364 sh->assert_line = ltoh32(sh->assert_line);
3365 sh->console_addr = ltoh32(sh->console_addr);
3366 sh->msgtrace_addr = ltoh32(sh->msgtrace_addr);
3367
3368 if ((sh->flags & SDPCM_SHARED_VERSION_MASK) == 3 && SDPCM_SHARED_VERSION == 1)
3369 return BCME_OK;
3370
3371 if ((sh->flags & SDPCM_SHARED_VERSION_MASK) != SDPCM_SHARED_VERSION) {
3372 DHD_ERROR(("%s: sdpcm_shared version %d in dhd "
3373 "is different than sdpcm_shared version %d in dongle\n",
3374 __FUNCTION__, SDPCM_SHARED_VERSION,
3375 sh->flags & SDPCM_SHARED_VERSION_MASK));
3376 return BCME_ERROR;
3377 }
3378
3379 return BCME_OK;
3380}
3381
3382#define CONSOLE_LINE_MAX 192
3383
3384#ifdef DHD_DEBUG
3385static int
3386dhdsdio_readconsole(dhd_bus_t *bus)
3387{
3388 dhd_console_t *c = &bus->console;
3389 uint8 line[CONSOLE_LINE_MAX], ch;
3390 uint32 n, idx, addr;
3391 int rv;
3392
3393 /* Don't do anything until FWREADY updates console address */
3394 if (bus->console_addr == 0)
3395 return 0;
3396
3397 if (!KSO_ENAB(bus))
3398 return 0;
3399
3400 /* Read console log struct */
3401 addr = bus->console_addr + OFFSETOF(hnd_cons_t, log);
3402 if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)&c->log, sizeof(c->log))) < 0)
3403 return rv;
3404
3405 /* Allocate console buffer (one time only) */
3406 if (c->buf == NULL) {
3407 c->bufsize = ltoh32(c->log.buf_size);
3408 if ((c->buf = MALLOC(bus->dhd->osh, c->bufsize)) == NULL)
3409 return BCME_NOMEM;
3410 }
3411
3412 idx = ltoh32(c->log.idx);
3413
3414 /* Protect against corrupt value */
3415 if (idx > c->bufsize)
3416 return BCME_ERROR;
3417
3418 /* Skip reading the console buffer if the index pointer has not moved */
3419 if (idx == c->last)
3420 return BCME_OK;
3421
3422 /* Read the console buffer */
3423 addr = ltoh32(c->log.buf);
3424 if ((rv = dhdsdio_membytes(bus, FALSE, addr, c->buf, c->bufsize)) < 0)
3425 return rv;
3426
3427 while (c->last != idx) {
3428 for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) {
3429 if (c->last == idx) {
3430 /* This would output a partial line. Instead, back up
3431 * the buffer pointer and output this line next time around.
3432 */
3433 if (c->last >= n)
3434 c->last -= n;
3435 else
3436 c->last = c->bufsize - n;
3437 goto break2;
3438 }
3439 ch = c->buf[c->last];
3440 c->last = (c->last + 1) % c->bufsize;
3441 if (ch == '\n')
3442 break;
3443 line[n] = ch;
3444 }
3445
3446 if (n > 0) {
3447 if (line[n - 1] == '\r')
3448 n--;
3449 line[n] = 0;
3450 printf("CONSOLE: %s\n", line);
3451#ifdef LOG_INTO_TCPDUMP
3452 dhd_sendup_log(bus->dhd, line, n);
3453#endif /* LOG_INTO_TCPDUMP */
3454 }
3455 }
3456break2:
3457
3458 return BCME_OK;
3459}
3460#endif /* DHD_DEBUG */
3461
3462static int
3463dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size)
3464{
3465 int bcmerror = 0;
3466 uint msize = 512;
3467 char *mbuffer = NULL;
3468 char *console_buffer = NULL;
3469 uint maxstrlen = 256;
3470 char *str = NULL;
3471 sdpcm_shared_t l_sdpcm_shared;
3472 struct bcmstrbuf strbuf;
3473 uint32 console_ptr, console_size, console_index;
3474 uint8 line[CONSOLE_LINE_MAX], ch;
3475 uint32 n, i, addr;
3476 int rv;
3477
3478 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3479
3480 if (DHD_NOCHECKDIED_ON())
3481 return 0;
3482
3483 if (data == NULL) {
3484 /*
3485 * Called after a rx ctrl timeout. "data" is NULL.
3486 * allocate memory to trace the trap or assert.
3487 */
3488 size = msize;
3489 mbuffer = data = MALLOC(bus->dhd->osh, msize);
3490 if (mbuffer == NULL) {
3491 DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, msize));
3492 bcmerror = BCME_NOMEM;
3493 goto done;
3494 }
3495 }
3496
3497 if ((str = MALLOC(bus->dhd->osh, maxstrlen)) == NULL) {
3498 DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, maxstrlen));
3499 bcmerror = BCME_NOMEM;
3500 goto done;
3501 }
3502
3503 if ((bcmerror = dhdsdio_readshared(bus, &l_sdpcm_shared)) < 0)
3504 goto done;
3505
3506 bcm_binit(&strbuf, data, size);
3507
3508 bcm_bprintf(&strbuf, "msgtrace address : 0x%08X\nconsole address : 0x%08X\n",
3509 l_sdpcm_shared.msgtrace_addr, l_sdpcm_shared.console_addr);
3510
3511 if ((l_sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT) == 0) {
3512 /* NOTE: Misspelled assert is intentional - DO NOT FIX.
3513 * (Avoids conflict with real asserts for programmatic parsing of output.)
3514 */
3515 bcm_bprintf(&strbuf, "Assrt not built in dongle\n");
3516 }
3517
3518 if ((l_sdpcm_shared.flags & (SDPCM_SHARED_ASSERT|SDPCM_SHARED_TRAP)) == 0) {
3519 /* NOTE: Misspelled assert is intentional - DO NOT FIX.
3520 * (Avoids conflict with real asserts for programmatic parsing of output.)
3521 */
3522 bcm_bprintf(&strbuf, "No trap%s in dongle",
3523 (l_sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT)
3524 ?"/assrt" :"");
3525 } else {
3526 if (l_sdpcm_shared.flags & SDPCM_SHARED_ASSERT) {
3527 /* Download assert */
3528 bcm_bprintf(&strbuf, "Dongle assert");
3529 if (l_sdpcm_shared.assert_exp_addr != 0) {
3530 str[0] = '\0';
3531 if ((bcmerror = dhdsdio_membytes(bus, FALSE,
3532 l_sdpcm_shared.assert_exp_addr,
3533 (uint8 *)str, maxstrlen)) < 0)
3534 goto done;
3535
3536 str[maxstrlen - 1] = '\0';
3537 bcm_bprintf(&strbuf, " expr \"%s\"", str);
3538 }
3539
3540 if (l_sdpcm_shared.assert_file_addr != 0) {
3541 str[0] = '\0';
3542 if ((bcmerror = dhdsdio_membytes(bus, FALSE,
3543 l_sdpcm_shared.assert_file_addr,
3544 (uint8 *)str, maxstrlen)) < 0)
3545 goto done;
3546
3547 str[maxstrlen - 1] = '\0';
3548 bcm_bprintf(&strbuf, " file \"%s\"", str);
3549 }
3550
3551 bcm_bprintf(&strbuf, " line %d ", l_sdpcm_shared.assert_line);
3552 }
3553
3554 if (l_sdpcm_shared.flags & SDPCM_SHARED_TRAP) {
3555 trap_t *tr = &bus->dhd->last_trap_info;
3556 bus->dhd->dongle_trap_occured = TRUE;
3557 if ((bcmerror = dhdsdio_membytes(bus, FALSE,
3558 l_sdpcm_shared.trap_addr,
3559 (uint8*)tr, sizeof(trap_t))) < 0)
3560 goto done;
3561
3562 bus->dongle_trap_addr = ltoh32(l_sdpcm_shared.trap_addr);
3563
3564 dhd_bus_dump_trap_info(bus, &strbuf);
3565
3566 addr = l_sdpcm_shared.console_addr + OFFSETOF(hnd_cons_t, log);
3567 if ((rv = dhdsdio_membytes(bus, FALSE, addr,
3568 (uint8 *)&console_ptr, sizeof(console_ptr))) < 0)
3569 goto printbuf;
3570
3571 addr = l_sdpcm_shared.console_addr + OFFSETOF(hnd_cons_t, log.buf_size);
3572 if ((rv = dhdsdio_membytes(bus, FALSE, addr,
3573 (uint8 *)&console_size, sizeof(console_size))) < 0)
3574 goto printbuf;
3575
3576 addr = l_sdpcm_shared.console_addr + OFFSETOF(hnd_cons_t, log.idx);
3577 if ((rv = dhdsdio_membytes(bus, FALSE, addr,
3578 (uint8 *)&console_index, sizeof(console_index))) < 0)
3579 goto printbuf;
3580
3581 console_ptr = ltoh32(console_ptr);
3582 console_size = ltoh32(console_size);
3583 console_index = ltoh32(console_index);
3584
3585 if (console_size > CONSOLE_BUFFER_MAX ||
3586 !(console_buffer = MALLOC(bus->dhd->osh, console_size)))
3587 goto printbuf;
3588
3589 if ((rv = dhdsdio_membytes(bus, FALSE, console_ptr,
3590 (uint8 *)console_buffer, console_size)) < 0)
3591 goto printbuf;
3592
3593 for (i = 0, n = 0; i < console_size; i += n + 1) {
3594 for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) {
3595 ch = console_buffer[(console_index + i + n) % console_size];
3596 if (ch == '\n')
3597 break;
3598 line[n] = ch;
3599 }
3600
3601 if (n > 0) {
3602 if (line[n - 1] == '\r')
3603 n--;
3604 line[n] = 0;
3605 /* Don't use DHD_ERROR macro since we print
3606 * a lot of information quickly. The macro
3607 * will truncate a lot of the printfs
3608 */
3609
3610 if (dhd_msg_level & DHD_ERROR_VAL)
3611 printf("CONSOLE: %s\n", line);
3612 }
3613 }
3614 }
3615 }
3616
3617printbuf:
3618 if (l_sdpcm_shared.flags & (SDPCM_SHARED_ASSERT | SDPCM_SHARED_TRAP)) {
3619 DHD_ERROR(("%s: %s\n", __FUNCTION__, strbuf.origbuf));
3620 }
3621
3622#if defined(DHD_FW_COREDUMP)
3623 if (bus->dhd->memdump_enabled && (l_sdpcm_shared.flags & SDPCM_SHARED_TRAP)) {
3624 /* Mem dump to a file on device */
3625 bus->dhd->memdump_type = DUMP_TYPE_DONGLE_TRAP;
3626 dhd_os_sdunlock(bus->dhd);
3627 dhdsdio_mem_dump(bus);
3628 dhd_os_sdlock(bus->dhd);
3629 }
3630#endif /* #if defined(DHD_FW_COREDUMP) */
3631
3632done:
3633 if (mbuffer)
3634 MFREE(bus->dhd->osh, mbuffer, msize);
3635 if (str)
3636 MFREE(bus->dhd->osh, str, maxstrlen);
3637 if (console_buffer)
3638 MFREE(bus->dhd->osh, console_buffer, console_size);
3639
3640 return bcmerror;
3641}
3642
3643#if defined(DHD_FW_COREDUMP)
3644int
3645dhd_bus_mem_dump(dhd_pub_t *dhdp)
3646{
3647 dhd_bus_t *bus = dhdp->bus;
3648 if (dhdp->busstate == DHD_BUS_SUSPEND) {
3649 DHD_ERROR(("%s: Bus is suspend so skip\n", __FUNCTION__));
3650 return 0;
3651 }
3652 return dhdsdio_mem_dump(bus);
3653}
3654
3655static int
3656dhdsdio_mem_dump(dhd_bus_t *bus)
3657{
3658 int ret = 0;
3659 int size; /* Full mem size */
3660 uint32 start = bus->dongle_ram_base; /* Start address */
3661 uint read_size = 0; /* Read size of each iteration */
3662 uint8 *buf = NULL, *databuf = NULL;
3663
3664 /* Get full mem size */
3665 size = bus->ramsize;
3666 buf = dhd_get_fwdump_buf(bus->dhd, size);
3667 if (!buf) {
3668 DHD_ERROR(("%s: Out of memory (%d bytes)\n", __FUNCTION__, size));
3669 return -1;
3670 }
3671
3672 dhd_os_sdlock(bus->dhd);
3673 BUS_WAKE(bus);
3674 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
3675
3676 /* Read mem content */
3677 DHD_ERROR(("Dump dongle memory\n"));
3678 databuf = buf;
3679 while (size)
3680 {
3681 read_size = MIN(MEMBLOCK, size);
3682 if ((ret = dhdsdio_membytes(bus, FALSE, start, databuf, read_size)))
3683 {
3684 DHD_ERROR(("%s: Error membytes %d\n", __FUNCTION__, ret));
3685 ret = BCME_ERROR;
3686 break;
3687 }
3688 /* Decrement size and increment start address */
3689 size -= read_size;
3690 start += read_size;
3691 databuf += read_size;
3692 }
3693
3694 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched &&
3695 NO_OTHER_ACTIVE_BUS_USER(bus)) {
3696 bus->activity = FALSE;
3697 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
3698 }
3699
3700 dhd_os_sdunlock(bus->dhd);
3701
3702 /* schedule a work queue to perform actual memdump. dhd_mem_dump() performs the job */
3703 if (!ret) {
3704 /* buf, actually soc_ram free handled in dhd_{free,clear} */
3705 dhd_schedule_memdump(bus->dhd, buf, bus->ramsize);
3706 }
3707
3708 return ret;
3709}
3710#endif /* DHD_FW_COREDUMP */
3711
3712int
3713dhd_socram_dump(dhd_bus_t * bus)
3714{
3715#if defined(DHD_FW_COREDUMP)
3716 return (dhdsdio_mem_dump(bus));
3717#else
3718 return -1;
3719#endif // endif
3720}
3721
3722int
3723dhdsdio_downloadvars(dhd_bus_t *bus, void *arg, int len)
3724{
3725 int bcmerror = BCME_OK;
3726
3727 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3728
3729 if (bus->dhd->up &&
3730#ifdef DHD_ULP
3731 (DHD_ULP_DISABLED == dhd_ulp_get_ulp_state(bus->dhd)) &&
3732#endif /* DHD_ULP */
3733 1) {
3734 bcmerror = BCME_NOTDOWN;
3735 goto err;
3736 }
3737 if (!len) {
3738 bcmerror = BCME_BUFTOOSHORT;
3739 goto err;
3740 }
3741
3742 /* Free the old ones and replace with passed variables */
3743 if (bus->vars)
3744 MFREE(bus->dhd->osh, bus->vars, bus->varsz);
3745
3746 bus->vars = MALLOC(bus->dhd->osh, len);
3747 bus->varsz = bus->vars ? len : 0;
3748 if (bus->vars == NULL) {
3749 bcmerror = BCME_NOMEM;
3750 goto err;
3751 }
3752
3753 /* Copy the passed variables, which should include the terminating double-null */
3754 bcopy(arg, bus->vars, bus->varsz);
3755err:
3756 return bcmerror;
3757}
3758
3759#ifdef DHD_DEBUG
3760static int
3761dhd_serialconsole(dhd_bus_t *bus, bool set, bool enable, int *bcmerror)
3762{
3763 int int_val;
3764 uint32 addr, data, uart_enab = 0;
3765
3766 addr = SI_ENUM_BASE(bus->sih) + OFFSETOF(chipcregs_t, chipcontrol_addr);
3767 data = SI_ENUM_BASE(bus->sih) + OFFSETOF(chipcregs_t, chipcontrol_data);
3768 *bcmerror = 0;
3769
3770 bcmsdh_reg_write(bus->sdh, addr, 4, 1);
3771 if (bcmsdh_regfail(bus->sdh)) {
3772 *bcmerror = BCME_SDIO_ERROR;
3773 return -1;
3774 }
3775 int_val = bcmsdh_reg_read(bus->sdh, data, 4);
3776 if (bcmsdh_regfail(bus->sdh)) {
3777 *bcmerror = BCME_SDIO_ERROR;
3778 return -1;
3779 }
3780
3781 if (!set)
3782 return (int_val & uart_enab);
3783 if (enable)
3784 int_val |= uart_enab;
3785 else
3786 int_val &= ~uart_enab;
3787 bcmsdh_reg_write(bus->sdh, data, 4, int_val);
3788 if (bcmsdh_regfail(bus->sdh)) {
3789 *bcmerror = BCME_SDIO_ERROR;
3790 return -1;
3791 }
3792
3793 return (int_val & uart_enab);
3794}
3795#endif // endif
3796
3797static int
3798dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const char *name,
3799 void *params, int plen, void *arg, int len, int val_size)
3800{
3801 int bcmerror = 0;
3802 int32 int_val = 0;
3803 bool bool_val = 0;
3804
3805 DHD_TRACE(("%s: Enter, action %d name %s params %p plen %d arg %p len %d val_size %d\n",
3806 __FUNCTION__, actionid, name, params, plen, arg, len, val_size));
3807
3808 if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0)
3809 goto exit;
3810
3811 if (plen >= (int)sizeof(int_val))
3812 bcopy(params, &int_val, sizeof(int_val));
3813
3814 bool_val = (int_val != 0) ? TRUE : FALSE;
3815
3816 /* Some ioctls use the bus */
3817 dhd_os_sdlock(bus->dhd);
3818
3819 /* Check if dongle is in reset. If so, only allow DEVRESET iovars */
3820 if (bus->dhd->dongle_reset && !(actionid == IOV_SVAL(IOV_DEVRESET) ||
3821 actionid == IOV_GVAL(IOV_DEVRESET))) {
3822 bcmerror = BCME_NOTREADY;
3823 goto exit;
3824 }
3825
3826 /*
3827 * Special handling for keepSdioOn: New SDIO Wake-up Mechanism
3828 */
3829 if ((vi->varid == IOV_KSO) && (IOV_ISSET(actionid))) {
3830 dhdsdio_clk_kso_iovar(bus, bool_val);
3831 goto exit;
3832 } else if ((vi->varid == IOV_DEVSLEEP) && (IOV_ISSET(actionid))) {
3833 {
3834 dhdsdio_clk_devsleep_iovar(bus, bool_val);
3835 if (!SLPAUTO_ENAB(bus) && (bool_val == FALSE) && (bus->ipend)) {
3836 DHD_ERROR(("INT pending in devsleep 1, dpc_sched: %d\n",
3837 bus->dpc_sched));
3838 if (!bus->dpc_sched) {
3839 bus->dpc_sched = TRUE;
3840 dhd_sched_dpc(bus->dhd);
3841 }
3842 }
3843 }
3844 goto exit;
3845 }
3846
3847 /* Handle sleep stuff before any clock mucking */
3848 if (vi->varid == IOV_SLEEP) {
3849 if (IOV_ISSET(actionid)) {
3850 bcmerror = dhdsdio_bussleep(bus, bool_val);
3851 } else {
3852 int_val = (int32)bus->sleeping;
3853 bcopy(&int_val, arg, val_size);
3854 }
3855 goto exit;
3856 }
3857
3858 /* Request clock to allow SDIO accesses */
3859 if (!bus->dhd->dongle_reset) {
3860 BUS_WAKE(bus);
3861 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
3862 }
3863
3864 switch (actionid) {
3865 case IOV_GVAL(IOV_INTR):
3866 int_val = (int32)bus->intr;
3867 bcopy(&int_val, arg, val_size);
3868 break;
3869
3870 case IOV_SVAL(IOV_INTR):
3871 bus->intr = bool_val;
3872 bus->intdis = FALSE;
3873 if (bus->dhd->up) {
3874 if (bus->intr) {
3875 DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__));
3876 bcmsdh_intr_enable(bus->sdh);
3877 } else {
3878 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
3879 bcmsdh_intr_disable(bus->sdh);
3880 }
3881 }
3882 break;
3883
3884 case IOV_GVAL(IOV_POLLRATE):
3885 int_val = (int32)bus->pollrate;
3886 bcopy(&int_val, arg, val_size);
3887 break;
3888
3889 case IOV_SVAL(IOV_POLLRATE):
3890 bus->pollrate = (uint)int_val;
3891 bus->poll = (bus->pollrate != 0);
3892 break;
3893
3894 case IOV_GVAL(IOV_IDLETIME):
3895 int_val = bus->idletime;
3896 bcopy(&int_val, arg, val_size);
3897 break;
3898
3899 case IOV_SVAL(IOV_IDLETIME):
3900 if ((int_val < 0) && (int_val != DHD_IDLE_IMMEDIATE)) {
3901 bcmerror = BCME_BADARG;
3902 } else {
3903 bus->idletime = int_val;
3904 }
3905 break;
3906
3907 case IOV_GVAL(IOV_IDLECLOCK):
3908 int_val = (int32)bus->idleclock;
3909 bcopy(&int_val, arg, val_size);
3910 break;
3911
3912 case IOV_SVAL(IOV_IDLECLOCK):
3913 bus->idleclock = int_val;
3914 break;
3915
3916 case IOV_GVAL(IOV_SD1IDLE):
3917 int_val = (int32)sd1idle;
3918 bcopy(&int_val, arg, val_size);
3919 break;
3920
3921 case IOV_SVAL(IOV_SD1IDLE):
3922 sd1idle = bool_val;
3923 break;
3924
3925 case IOV_GVAL(IOV_RAMSIZE):
3926 int_val = (int32)bus->ramsize;
3927 bcopy(&int_val, arg, val_size);
3928 break;
3929
3930 case IOV_GVAL(IOV_RAMSTART):
3931 int_val = (int32)bus->dongle_ram_base;
3932 bcopy(&int_val, arg, val_size);
3933 break;
3934
3935 case IOV_GVAL(IOV_SDIOD_DRIVE):
3936 int_val = (int32)dhd_sdiod_drive_strength;
3937 bcopy(&int_val, arg, val_size);
3938 break;
3939
3940 case IOV_SVAL(IOV_SDIOD_DRIVE):
3941 dhd_sdiod_drive_strength = int_val;
3942 si_sdiod_drive_strength_init(bus->sih, bus->dhd->osh, dhd_sdiod_drive_strength);
3943 break;
3944
3945 case IOV_SVAL(IOV_SET_DOWNLOAD_STATE):
3946 bcmerror = dhdsdio_download_state(bus, bool_val);
3947 break;
3948
3949 case IOV_SVAL(IOV_SOCRAM_STATE):
3950 bcmerror = dhdsdio_download_state(bus, bool_val);
3951 break;
3952
3953 case IOV_SVAL(IOV_VARS):
3954 bcmerror = dhdsdio_downloadvars(bus, arg, len);
3955 break;
3956
3957 case IOV_GVAL(IOV_READAHEAD):
3958 int_val = (int32)dhd_readahead;
3959 bcopy(&int_val, arg, val_size);
3960 break;
3961
3962 case IOV_SVAL(IOV_READAHEAD):
3963 if (bool_val && !dhd_readahead)
3964 bus->nextlen = 0;
3965 dhd_readahead = bool_val;
3966 break;
3967
3968 case IOV_GVAL(IOV_SDRXCHAIN):
3969 int_val = (int32)bus->use_rxchain;
3970 bcopy(&int_val, arg, val_size);
3971 break;
3972
3973 case IOV_SVAL(IOV_SDRXCHAIN):
3974 if (bool_val && !bus->sd_rxchain)
3975 bcmerror = BCME_UNSUPPORTED;
3976 else
3977 bus->use_rxchain = bool_val;
3978 break;
3979#ifndef BCMSPI
3980 case IOV_GVAL(IOV_ALIGNCTL):
3981 int_val = (int32)dhd_alignctl;
3982 bcopy(&int_val, arg, val_size);
3983 break;
3984
3985 case IOV_SVAL(IOV_ALIGNCTL):
3986 dhd_alignctl = bool_val;
3987 break;
3988#endif /* BCMSPI */
3989
3990 case IOV_GVAL(IOV_SDALIGN):
3991 int_val = DHD_SDALIGN;
3992 bcopy(&int_val, arg, val_size);
3993 break;
3994
3995#ifdef DHD_DEBUG
3996 case IOV_GVAL(IOV_VARS):
3997 if (bus->varsz < (uint)len)
3998 bcopy(bus->vars, arg, bus->varsz);
3999 else
4000 bcmerror = BCME_BUFTOOSHORT;
4001 break;
4002#endif /* DHD_DEBUG */
4003
4004#ifdef DHD_DEBUG
4005 case IOV_GVAL(IOV_SDREG):
4006 {
4007 sdreg_t *sd_ptr;
4008 uintptr addr;
4009 uint size;
4010
4011 sd_ptr = (sdreg_t *)params;
4012
4013 addr = ((uintptr)bus->regs + sd_ptr->offset);
4014 size = sd_ptr->func;
4015 int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size);
4016 if (bcmsdh_regfail(bus->sdh))
4017 bcmerror = BCME_SDIO_ERROR;
4018 bcopy(&int_val, arg, sizeof(int32));
4019 break;
4020 }
4021
4022 case IOV_SVAL(IOV_SDREG):
4023 {
4024 sdreg_t *sd_ptr;
4025 uintptr addr;
4026 uint size;
4027
4028 sd_ptr = (sdreg_t *)params;
4029
4030 addr = ((uintptr)bus->regs + sd_ptr->offset);
4031 size = sd_ptr->func;
4032 bcmsdh_reg_write(bus->sdh, addr, size, sd_ptr->value);
4033 if (bcmsdh_regfail(bus->sdh))
4034 bcmerror = BCME_SDIO_ERROR;
4035 break;
4036 }
4037
4038 /* Same as above, but offset is not backplane (not SDIO core) */
4039 case IOV_GVAL(IOV_SBREG):
4040 {
4041 sdreg_t sdreg;
4042 uint32 addr, size;
4043
4044 bcopy(params, &sdreg, sizeof(sdreg));
4045
4046 addr = SI_ENUM_BASE(bus->sih) + sdreg.offset;
4047 size = sdreg.func;
4048 int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size);
4049 if (bcmsdh_regfail(bus->sdh))
4050 bcmerror = BCME_SDIO_ERROR;
4051 bcopy(&int_val, arg, sizeof(int32));
4052 break;
4053 }
4054
4055 case IOV_SVAL(IOV_SBREG):
4056 {
4057 sdreg_t sdreg;
4058 uint32 addr, size;
4059
4060 bcopy(params, &sdreg, sizeof(sdreg));
4061
4062 addr = SI_ENUM_BASE(bus->sih) + sdreg.offset;
4063 size = sdreg.func;
4064 bcmsdh_reg_write(bus->sdh, addr, size, sdreg.value);
4065 if (bcmsdh_regfail(bus->sdh))
4066 bcmerror = BCME_SDIO_ERROR;
4067 break;
4068 }
4069
4070 case IOV_GVAL(IOV_SDCIS):
4071 {
4072 *(char *)arg = 0;
4073
4074 bcmstrcat(arg, "\nFunc 0\n");
4075 bcmsdh_cis_read(bus->sdh, 0x10, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
4076 bcmstrcat(arg, "\nFunc 1\n");
4077 bcmsdh_cis_read(bus->sdh, 0x11, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
4078 bcmstrcat(arg, "\nFunc 2\n");
4079 bcmsdh_cis_read(bus->sdh, 0x12, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
4080 break;
4081 }
4082
4083 case IOV_GVAL(IOV_FORCEEVEN):
4084 int_val = (int32)forcealign;
4085 bcopy(&int_val, arg, val_size);
4086 break;
4087
4088 case IOV_SVAL(IOV_FORCEEVEN):
4089 forcealign = bool_val;
4090 break;
4091
4092 case IOV_GVAL(IOV_TXBOUND):
4093 int_val = (int32)dhd_txbound;
4094 bcopy(&int_val, arg, val_size);
4095 break;
4096
4097 case IOV_SVAL(IOV_TXBOUND):
4098 dhd_txbound = (uint)int_val;
4099 break;
4100
4101 case IOV_GVAL(IOV_RXBOUND):
4102 int_val = (int32)dhd_rxbound;
4103 bcopy(&int_val, arg, val_size);
4104 break;
4105
4106 case IOV_SVAL(IOV_RXBOUND):
4107 dhd_rxbound = (uint)int_val;
4108 break;
4109
4110 case IOV_GVAL(IOV_TXMINMAX):
4111 int_val = (int32)dhd_txminmax;
4112 bcopy(&int_val, arg, val_size);
4113 break;
4114
4115 case IOV_SVAL(IOV_TXMINMAX):
4116 dhd_txminmax = (uint)int_val;
4117 break;
4118
4119 case IOV_GVAL(IOV_SERIALCONS):
4120 int_val = dhd_serialconsole(bus, FALSE, 0, &bcmerror);
4121 if (bcmerror != 0)
4122 break;
4123
4124 bcopy(&int_val, arg, val_size);
4125 break;
4126
4127 case IOV_SVAL(IOV_SERIALCONS):
4128 dhd_serialconsole(bus, TRUE, bool_val, &bcmerror);
4129 break;
4130
4131#endif /* DHD_DEBUG */
4132
4133#ifdef SDTEST
4134 case IOV_GVAL(IOV_EXTLOOP):
4135 int_val = (int32)bus->ext_loop;
4136 bcopy(&int_val, arg, val_size);
4137 break;
4138
4139 case IOV_SVAL(IOV_EXTLOOP):
4140 bus->ext_loop = bool_val;
4141 break;
4142
4143 case IOV_GVAL(IOV_PKTGEN):
4144 bcmerror = dhdsdio_pktgen_get(bus, arg);
4145 break;
4146
4147 case IOV_SVAL(IOV_PKTGEN):
4148 bcmerror = dhdsdio_pktgen_set(bus, arg);
4149 break;
4150#endif /* SDTEST */
4151
4152#if defined(USE_SDIOFIFO_IOVAR)
4153 case IOV_GVAL(IOV_WATERMARK):
4154 int_val = (int32)watermark;
4155 bcopy(&int_val, arg, val_size);
4156 break;
4157
4158 case IOV_SVAL(IOV_WATERMARK):
4159 watermark = (uint)int_val;
4160 watermark = (watermark > SBSDIO_WATERMARK_MASK) ? SBSDIO_WATERMARK_MASK : watermark;
4161 DHD_ERROR(("Setting watermark as 0x%x.\n", watermark));
4162 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, (uint8)watermark, NULL);
4163 break;
4164
4165 case IOV_GVAL(IOV_MESBUSYCTRL):
4166 int_val = (int32)mesbusyctrl;
4167 bcopy(&int_val, arg, val_size);
4168 break;
4169
4170 case IOV_SVAL(IOV_MESBUSYCTRL):
4171 mesbusyctrl = (uint)int_val;
4172 mesbusyctrl = (mesbusyctrl > SBSDIO_MESBUSYCTRL_MASK)
4173 ? SBSDIO_MESBUSYCTRL_MASK : mesbusyctrl;
4174 DHD_ERROR(("Setting mesbusyctrl as 0x%x.\n", mesbusyctrl));
4175 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL,
4176 ((uint8)mesbusyctrl | 0x80), NULL);
4177 break;
4178#endif // endif
4179
4180 case IOV_GVAL(IOV_DONGLEISOLATION):
4181 int_val = bus->dhd->dongle_isolation;
4182 bcopy(&int_val, arg, val_size);
4183 break;
4184
4185 case IOV_SVAL(IOV_DONGLEISOLATION):
4186 bus->dhd->dongle_isolation = bool_val;
4187 break;
4188
4189 case IOV_SVAL(IOV_DEVRESET):
4190 DHD_TRACE(("%s: Called set IOV_DEVRESET=%d dongle_reset=%d busstate=%d\n",
4191 __FUNCTION__, bool_val, bus->dhd->dongle_reset,
4192 bus->dhd->busstate));
4193
4194 ASSERT(bus->dhd->osh);
4195 /* ASSERT(bus->cl_devid); */
4196
4197 /* must release sdlock, since devreset also acquires it */
4198 dhd_os_sdunlock(bus->dhd);
4199 dhd_bus_devreset(bus->dhd, (uint8)bool_val);
4200 dhd_os_sdlock(bus->dhd);
4201 break;
4202 /*
4203 * softap firmware is updated through module parameter or android private command
4204 */
4205
4206 case IOV_GVAL(IOV_DEVRESET):
4207 DHD_TRACE(("%s: Called get IOV_DEVRESET\n", __FUNCTION__));
4208
4209 /* Get its status */
4210 int_val = (bool) bus->dhd->dongle_reset;
4211 bcopy(&int_val, arg, val_size);
4212
4213 break;
4214
4215 case IOV_GVAL(IOV_KSO):
4216 int_val = dhdsdio_sleepcsr_get(bus);
4217 bcopy(&int_val, arg, val_size);
4218 break;
4219
4220 case IOV_GVAL(IOV_DEVCAP):
4221 int_val = dhdsdio_devcap_get(bus);
4222 bcopy(&int_val, arg, val_size);
4223 break;
4224
4225 case IOV_SVAL(IOV_DEVCAP):
4226 dhdsdio_devcap_set(bus, (uint8) int_val);
4227 break;
4228 case IOV_GVAL(IOV_TXGLOMSIZE):
4229 int_val = (int32)bus->txglomsize;
4230 bcopy(&int_val, arg, val_size);
4231 break;
4232
4233 case IOV_SVAL(IOV_TXGLOMSIZE):
4234 if (int_val > SDPCM_MAXGLOM_SIZE) {
4235 bcmerror = BCME_ERROR;
4236 } else {
4237 bus->txglomsize = (uint)int_val;
4238 }
4239 break;
4240 case IOV_SVAL(IOV_HANGREPORT):
4241 bus->dhd->hang_report = bool_val;
4242 DHD_ERROR(("%s: Set hang_report as %d\n", __FUNCTION__, bus->dhd->hang_report));
4243 break;
4244
4245 case IOV_GVAL(IOV_HANGREPORT):
4246 int_val = (int32)bus->dhd->hang_report;
4247 bcopy(&int_val, arg, val_size);
4248 break;
4249
4250 case IOV_GVAL(IOV_TXINRX_THRES):
4251 int_val = bus->txinrx_thres;
4252 bcopy(&int_val, arg, val_size);
4253 break;
4254 case IOV_SVAL(IOV_TXINRX_THRES):
4255 if (int_val < 0) {
4256 bcmerror = BCME_BADARG;
4257 } else {
4258 bus->txinrx_thres = int_val;
4259 }
4260 break;
4261
4262 case IOV_GVAL(IOV_SDIO_SUSPEND):
4263 int_val = (bus->dhd->busstate == DHD_BUS_SUSPEND) ? 1 : 0;
4264 bcopy(&int_val, arg, val_size);
4265 break;
4266
4267 case IOV_SVAL(IOV_SDIO_SUSPEND):
4268 if (bool_val) { /* Suspend */
4269 dhdsdio_suspend(bus);
4270 }
4271 else { /* Resume */
4272 dhdsdio_resume(bus);
4273 }
4274 break;
4275
4276#if defined(DEBUGGER) || defined(DHD_DSCOPE)
4277 case IOV_SVAL(IOV_GDB_SERVER):
4278 if (bool_val == TRUE) {
4279 debugger_init((void *) bus, &bus_ops, int_val, SI_ENUM_BASE(bus->sih));
4280 } else {
4281 debugger_close();
4282 }
4283 break;
4284#endif /* DEBUGGER || DHD_DSCOPE */
4285
4286 default:
4287 bcmerror = BCME_UNSUPPORTED;
4288 break;
4289 }
4290
4291exit:
4292 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched &&
4293 NO_OTHER_ACTIVE_BUS_USER(bus)) {
4294 bus->activity = FALSE;
4295 dhdsdio_bussleep(bus, TRUE);
4296 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
4297 }
4298
4299 dhd_os_sdunlock(bus->dhd);
4300
4301 return bcmerror;
4302}
4303
4304static int
4305dhdsdio_write_vars(dhd_bus_t *bus)
4306{
4307 int bcmerror = 0;
4308 uint32 varsize, phys_size;
4309 uint32 varaddr;
4310 uint8 *vbuffer;
4311 uint32 varsizew;
4312#ifdef DHD_DEBUG
4313 uint8 *nvram_ularray;
4314#endif /* DHD_DEBUG */
4315
4316 /* Even if there are no vars are to be written, we still need to set the ramsize. */
4317 varsize = bus->varsz ? ROUNDUP(bus->varsz, 4) : 0;
4318 varaddr = (bus->ramsize - 4) - varsize;
4319
4320 varaddr += bus->dongle_ram_base;
4321
4322 if (bus->vars) {
4323 if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 7)) {
4324 if (((varaddr & 0x3C) == 0x3C) && (varsize > 4)) {
4325 DHD_ERROR(("PR85623WAR in place\n"));
4326 varsize += 4;
4327 varaddr -= 4;
4328 }
4329 }
4330
4331 vbuffer = (uint8 *)MALLOC(bus->dhd->osh, varsize);
4332 if (!vbuffer)
4333 return BCME_NOMEM;
4334
4335 bzero(vbuffer, varsize);
4336 bcopy(bus->vars, vbuffer, bus->varsz);
4337
4338 /* Write the vars list */
4339 bcmerror = dhdsdio_membytes(bus, TRUE, varaddr, vbuffer, varsize);
4340 if (bcmerror) {
4341 DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
4342 __FUNCTION__, bcmerror, varsize, varaddr));
4343 return bcmerror;
4344 }
4345
4346#ifdef DHD_DEBUG
4347 /* Verify NVRAM bytes */
4348 DHD_INFO(("Compare NVRAM dl & ul; varsize=%d\n", varsize));
4349 nvram_ularray = (uint8*)MALLOC(bus->dhd->osh, varsize);
4350 if (!nvram_ularray) {
4351 MFREE(bus->dhd->osh, vbuffer, varsize);
4352 return BCME_NOMEM;
4353 }
4354
4355 /* Upload image to verify downloaded contents. */
4356 memset(nvram_ularray, 0xaa, varsize);
4357
4358 /* Read the vars list to temp buffer for comparison */
4359 bcmerror = dhdsdio_membytes(bus, FALSE, varaddr, nvram_ularray, varsize);
4360 if (bcmerror) {
4361 DHD_ERROR(("%s: error %d on reading %d nvram bytes at 0x%08x\n",
4362 __FUNCTION__, bcmerror, varsize, varaddr));
4363 }
4364 /* Compare the org NVRAM with the one read from RAM */
4365 if (memcmp(vbuffer, nvram_ularray, varsize)) {
4366 DHD_ERROR(("%s: Downloaded NVRAM image is corrupted.\n", __FUNCTION__));
4367 } else
4368 DHD_ERROR(("%s: Download, Upload and compare of NVRAM succeeded.\n",
4369 __FUNCTION__));
4370
4371 MFREE(bus->dhd->osh, nvram_ularray, varsize);
4372#endif /* DHD_DEBUG */
4373
4374 MFREE(bus->dhd->osh, vbuffer, varsize);
4375 }
4376
4377 phys_size = REMAP_ENAB(bus) ? bus->ramsize : bus->orig_ramsize;
4378
4379 phys_size += bus->dongle_ram_base;
4380
4381 /* adjust to the user specified RAM */
4382 DHD_INFO(("Physical memory size: %d, usable memory size: %d\n",
4383 phys_size, bus->ramsize));
4384 DHD_INFO(("Vars are at %d, orig varsize is %d\n",
4385 varaddr, varsize));
4386 varsize = ((phys_size - 4) - varaddr);
4387
4388 /*
4389 * Determine the length token:
4390 * Varsize, converted to words, in lower 16-bits, checksum in upper 16-bits.
4391 */
4392#ifdef DHD_DEBUG
4393 if (bcmerror) {
4394 varsizew = 0;
4395 } else
4396#endif /* DHD_DEBUG */
4397 {
4398 varsizew = varsize / 4;
4399 varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF);
4400 varsizew = htol32(varsizew);
4401 }
4402
4403 DHD_INFO(("New varsize is %d, length token=0x%08x\n", varsize, varsizew));
4404
4405 /* Write the length token to the last word */
4406 bcmerror = dhdsdio_membytes(bus, TRUE, (phys_size - 4),
4407 (uint8*)&varsizew, 4);
4408
4409 return bcmerror;
4410}
4411
4412static int
4413dhdsdio_download_state(dhd_bus_t *bus, bool enter)
4414{
4415 uint retries;
4416 int bcmerror = 0;
4417 int foundcr4 = 0;
4418
4419 if (!bus->sih)
4420 return BCME_ERROR;
4421 /* To enter download state, disable ARM and reset SOCRAM.
4422 * To exit download state, simply reset ARM (default is RAM boot).
4423 */
4424 if (enter) {
4425 bus->alp_only = TRUE;
4426
4427 if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) &&
4428 !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) {
4429 if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
4430 foundcr4 = 1;
4431 } else {
4432 DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__));
4433 bcmerror = BCME_ERROR;
4434 goto fail;
4435 }
4436 }
4437
4438 if (!foundcr4) {
4439 si_core_disable(bus->sih, 0);
4440 if (bcmsdh_regfail(bus->sdh)) {
4441 bcmerror = BCME_SDIO_ERROR;
4442 goto fail;
4443 }
4444
4445 if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) {
4446 DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__));
4447 bcmerror = BCME_ERROR;
4448 goto fail;
4449 }
4450
4451 si_core_reset(bus->sih, 0, 0);
4452 if (bcmsdh_regfail(bus->sdh)) {
4453 DHD_ERROR(("%s: Failure trying reset SOCRAM core?\n",
4454 __FUNCTION__));
4455 bcmerror = BCME_SDIO_ERROR;
4456 goto fail;
4457 }
4458
4459 /* Disable remap for download */
4460 if (REMAP_ENAB(bus) && si_socdevram_remap_isenb(bus->sih))
4461 dhdsdio_devram_remap(bus, FALSE);
4462
4463 if (CHIPID(bus->sih->chip) == BCM43430_CHIP_ID ||
4464 CHIPID(bus->sih->chip) == BCM43018_CHIP_ID) {
4465 /* Disabling Remap for SRAM_3 */
4466 si_socram_set_bankpda(bus->sih, 0x3, 0x0);
4467 }
4468
4469 /* Clear the top bit of memory */
4470 if (bus->ramsize) {
4471 uint32 zeros = 0;
4472 if (dhdsdio_membytes(bus, TRUE, bus->ramsize - 4,
4473 (uint8*)&zeros, 4) < 0) {
4474 bcmerror = BCME_SDIO_ERROR;
4475 goto fail;
4476 }
4477 }
4478 } else {
4479 /* For CR4,
4480 * Halt ARM
4481 * Remove ARM reset
4482 * Read RAM base address [0x18_0000]
4483 * [next] Download firmware
4484 * [done at else] Populate the reset vector
4485 * [done at else] Remove ARM halt
4486 */
4487 /* Halt ARM & remove reset */
4488 si_core_reset(bus->sih, SICF_CPUHALT, SICF_CPUHALT);
4489 }
4490 } else {
4491 if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
4492 if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) {
4493 DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__));
4494 bcmerror = BCME_ERROR;
4495 goto fail;
4496 }
4497
4498 if (!si_iscoreup(bus->sih)) {
4499 DHD_ERROR(("%s: SOCRAM core is down after reset?\n", __FUNCTION__));
4500 bcmerror = BCME_ERROR;
4501 goto fail;
4502 }
4503
4504 if ((bcmerror = dhdsdio_write_vars(bus))) {
4505 DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__));
4506 goto fail;
4507 }
4508
4509 /* Enable remap before ARM reset but after vars.
4510 * No backplane access in remap mode
4511 */
4512 if (REMAP_ENAB(bus) && !si_socdevram_remap_isenb(bus->sih))
4513 dhdsdio_devram_remap(bus, TRUE);
4514#ifdef BCMSDIOLITE
4515 if (!si_setcore(bus->sih, CC_CORE_ID, 0)) {
4516 DHD_ERROR(("%s: Can't set to Chip Common core?\n", __FUNCTION__));
4517 bcmerror = BCME_ERROR;
4518 goto fail;
4519 }
4520#else
4521 if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) &&
4522 !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) {
4523 DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__));
4524 bcmerror = BCME_ERROR;
4525 goto fail;
4526 }
4527#endif // endif
4528 W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries);
4529
4530 if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) &&
4531 !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) {
4532 DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__));
4533 bcmerror = BCME_ERROR;
4534 goto fail;
4535 }
4536 } else {
4537 /* cr4 has no socram, but tcm's */
4538 /* write vars */
4539 if ((bcmerror = dhdsdio_write_vars(bus))) {
4540 DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__));
4541 goto fail;
4542 }
4543#ifdef BCMSDIOLITE
4544 if (!si_setcore(bus->sih, CC_CORE_ID, 0)) {
4545 DHD_ERROR(("%s: Can't set to Chip Common core?\n", __FUNCTION__));
4546 bcmerror = BCME_ERROR;
4547 goto fail;
4548 }
4549#else
4550 if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) &&
4551 !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) {
4552 DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__));
4553 bcmerror = BCME_ERROR;
4554 goto fail;
4555 }
4556#endif // endif
4557 W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries);
4558
4559 /* switch back to arm core again */
4560 if (!(si_setcore(bus->sih, ARMCR4_CORE_ID, 0))) {
4561 DHD_ERROR(("%s: Failed to find ARM CR4 core!\n", __FUNCTION__));
4562 bcmerror = BCME_ERROR;
4563 goto fail;
4564 }
4565 /* write address 0 with reset instruction */
4566 bcmerror = dhdsdio_membytes(bus, TRUE, 0,
4567 (uint8 *)&bus->resetinstr, sizeof(bus->resetinstr));
4568
4569 if (bcmerror == BCME_OK) {
4570 uint32 tmp;
4571
4572 /* verify write */
4573 bcmerror = dhdsdio_membytes(bus, FALSE, 0,
4574 (uint8 *)&tmp, sizeof(tmp));
4575
4576 if (bcmerror == BCME_OK && tmp != bus->resetinstr) {
4577 DHD_ERROR(("%s: Failed to write 0x%08x to addr 0\n",
4578 __FUNCTION__, bus->resetinstr));
4579 DHD_ERROR(("%s: contents of addr 0 is 0x%08x\n",
4580 __FUNCTION__, tmp));
4581 bcmerror = BCME_SDIO_ERROR;
4582 goto fail;
4583 }
4584 }
4585
4586 /* now remove reset and halt and continue to run CR4 */
4587 }
4588
4589 si_core_reset(bus->sih, 0, 0);
4590 if (bcmsdh_regfail(bus->sdh)) {
4591 DHD_ERROR(("%s: Failure trying to reset ARM core?\n", __FUNCTION__));
4592 bcmerror = BCME_SDIO_ERROR;
4593 goto fail;
4594 }
4595
4596 /* Allow HT Clock now that the ARM is running. */
4597 bus->alp_only = FALSE;
4598
4599 bus->dhd->busstate = DHD_BUS_LOAD;
4600 }
4601
4602fail:
4603 /* Always return to SDIOD core */
4604 if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0))
4605 si_setcore(bus->sih, SDIOD_CORE_ID, 0);
4606
4607 return bcmerror;
4608}
4609
4610int
4611dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name,
4612 void *params, int plen, void *arg, int len, bool set)
4613{
4614 dhd_bus_t *bus = dhdp->bus;
4615 const bcm_iovar_t *vi = NULL;
4616 int bcmerror = 0;
4617 int val_size;
4618 uint32 actionid;
4619
4620 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4621
4622 ASSERT(name);
4623 ASSERT(len >= 0);
4624
4625 /* Get MUST have return space */
4626 ASSERT(set || (arg && len));
4627
4628 /* Set does NOT take qualifiers */
4629 ASSERT(!set || (!params && !plen));
4630
4631 /* Look up var locally; if not found pass to host driver */
4632 if ((vi = bcm_iovar_lookup(dhdsdio_iovars, name)) == NULL) {
4633 dhd_os_sdlock(bus->dhd);
4634
4635 BUS_WAKE(bus);
4636
4637 /* Turn on clock in case SD command needs backplane */
4638 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
4639
4640 bcmerror = bcmsdh_iovar_op(bus->sdh, name, params, plen, arg, len, set);
4641
4642 /* Check for bus configuration changes of interest */
4643
4644 /* If it was divisor change, read the new one */
4645 if (set && strcmp(name, "sd_divisor") == 0) {
4646 if (bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
4647 &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) {
4648 bus->sd_divisor = -1;
4649 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, name));
4650 } else {
4651 DHD_INFO(("%s: noted %s update, value now %d\n",
4652 __FUNCTION__, name, bus->sd_divisor));
4653 }
4654 }
4655 /* If it was a mode change, read the new one */
4656 if (set && strcmp(name, "sd_mode") == 0) {
4657 if (bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
4658 &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) {
4659 bus->sd_mode = -1;
4660 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, name));
4661 } else {
4662 DHD_INFO(("%s: noted %s update, value now %d\n",
4663 __FUNCTION__, name, bus->sd_mode));
4664 }
4665 }
4666 /* Similar check for blocksize change */
4667 if (set && strcmp(name, "sd_blocksize") == 0) {
4668 int32 fnum = 2;
4669 if (bcmsdh_iovar_op(bus->sdh, "sd_blocksize", &fnum, sizeof(int32),
4670 &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) {
4671 bus->blocksize = 0;
4672 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize"));
4673 } else {
4674 DHD_INFO(("%s: noted %s update, value now %d\n",
4675 __FUNCTION__, "sd_blocksize", bus->blocksize));
4676
4677 dhdsdio_tune_fifoparam(bus);
4678 }
4679 }
4680 bus->roundup = MIN(max_roundup, bus->blocksize);
4681
4682 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched &&
4683 NO_OTHER_ACTIVE_BUS_USER(bus)) {
4684 bus->activity = FALSE;
4685 dhdsdio_bussleep(bus, TRUE);
4686 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
4687 }
4688
4689 dhd_os_sdunlock(bus->dhd);
4690 goto exit;
4691 }
4692
4693 DHD_CTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__,
4694 name, (set ? "set" : "get"), len, plen));
4695
4696 /* set up 'params' pointer in case this is a set command so that
4697 * the convenience int and bool code can be common to set and get
4698 */
4699 if (params == NULL) {
4700 params = arg;
4701 plen = len;
4702 }
4703
4704 if (vi->type == IOVT_VOID)
4705 val_size = 0;
4706 else if (vi->type == IOVT_BUFFER)
4707 val_size = len;
4708 else
4709 /* all other types are integer sized */
4710 val_size = sizeof(int);
4711
4712 actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
4713 bcmerror = dhdsdio_doiovar(bus, vi, actionid, name, params, plen, arg, len, val_size);
4714
4715exit:
4716 return bcmerror;
4717}
4718
4719void
4720dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex)
4721{
4722 osl_t *osh;
4723 uint32 local_hostintmask;
4724 uint8 saveclk;
4725 uint retries;
4726 int err;
4727 bool wlfc_enabled = FALSE;
4728 unsigned long flags;
4729
4730 if (!bus->dhd)
4731 return;
4732
4733 osh = bus->dhd->osh;
4734 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4735
4736 bcmsdh_waitlockfree(bus->sdh);
4737
4738 if (enforce_mutex)
4739 dhd_os_sdlock(bus->dhd);
4740
4741 if ((bus->dhd->busstate == DHD_BUS_DOWN) || bus->dhd->hang_was_sent) {
4742 /* if Firmware already hangs disbale any interrupt */
4743 bus->dhd->busstate = DHD_BUS_DOWN;
4744 bus->hostintmask = 0;
4745 bcmsdh_intr_disable(bus->sdh);
4746 } else {
4747
4748 BUS_WAKE(bus);
4749
4750 if (KSO_ENAB(bus)) {
4751
4752 /* Enable clock for device interrupts */
4753 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
4754
4755 /* Disable and clear interrupts at the chip level also */
4756 W_SDREG(0, &bus->regs->hostintmask, retries);
4757 local_hostintmask = bus->hostintmask;
4758 bus->hostintmask = 0;
4759
4760 /* Change our idea of bus state */
4761 DHD_LINUX_GENERAL_LOCK(bus->dhd, flags);
4762 bus->dhd->busstate = DHD_BUS_DOWN;
4763 DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
4764
4765 /* Force clocks on backplane to be sure F2 interrupt propagates */
4766 saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
4767 if (!err) {
4768 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
4769 (saveclk | SBSDIO_FORCE_HT), &err);
4770 }
4771 if (err) {
4772 DHD_ERROR(("%s: Failed to force clock for F2: err %d\n",
4773 __FUNCTION__, err));
4774 }
4775
4776 /* Turn off the bus (F2), free any pending packets */
4777 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
4778 bcmsdh_intr_disable(bus->sdh);
4779#ifndef BCMSPI
4780 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL);
4781#endif /* !BCMSPI */
4782
4783 /* Clear any pending interrupts now that F2 is disabled */
4784 W_SDREG(local_hostintmask, &bus->regs->intstatus, retries);
4785 }
4786
4787 /* Turn off the backplane clock (only) */
4788 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
4789 }
4790
4791#ifdef PROP_TXSTATUS
4792 wlfc_enabled = (dhd_wlfc_cleanup_txq(bus->dhd, NULL, 0) != WLFC_UNSUPPORTED);
4793#endif // endif
4794 if (!wlfc_enabled) {
4795#ifdef DHDTCPACK_SUPPRESS
4796 /* Clean tcp_ack_info_tbl in order to prevent access to flushed pkt,
4797 * when there is a newly coming packet from network stack.
4798 */
4799 dhd_tcpack_info_tbl_clean(bus->dhd);
4800#endif /* DHDTCPACK_SUPPRESS */
4801 dhd_os_sdlock_txq(bus->dhd);
4802 /* Clear the data packet queues */
4803 pktq_flush(osh, &bus->txq, TRUE);
4804 dhd_os_sdunlock_txq(bus->dhd);
4805 }
4806
4807 /* Clear any held glomming stuff */
4808 if (bus->glomd)
4809 PKTFREE(osh, bus->glomd, FALSE);
4810
4811 if (bus->glom)
4812 PKTFREE(osh, bus->glom, FALSE);
4813
4814 bus->glom = bus->glomd = NULL;
4815
4816 /* Clear rx control and wake any waiters */
4817 bus->rxlen = 0;
4818 dhd_os_ioctl_resp_wake(bus->dhd);
4819
4820 /* Reset some F2 state stuff */
4821 bus->rxskip = FALSE;
4822 bus->tx_seq = bus->rx_seq = 0;
4823
4824 bus->tx_max = 4;
4825
4826 if (enforce_mutex)
4827 dhd_os_sdunlock(bus->dhd);
4828}
4829
4830#if defined(BCMSDIOH_TXGLOM) && defined(BCMSDIOH_STD)
4831extern uint sd_txglom;
4832#endif // endif
4833void
4834dhd_txglom_enable(dhd_pub_t *dhdp, bool enable)
4835{
4836 /* can't enable host txglom by default, some platforms have no
4837 * (or crappy) ADMA support and txglom will cause kernel assertions (e.g.
4838 * panda board)
4839 */
4840 dhd_bus_t *bus = dhdp->bus;
4841#ifdef BCMSDIOH_TXGLOM
4842 uint32 rxglom;
4843 int32 ret;
4844
4845 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4846
4847#ifdef BCMSDIOH_STD
4848 if (enable)
4849 enable = sd_txglom;
4850#endif /* BCMSDIOH_STD */
4851
4852 if (enable) {
4853 rxglom = 1;
4854 ret = dhd_iovar(dhdp, 0, "bus:rxglom", (char *)&rxglom, sizeof(rxglom), NULL, 0,
4855 TRUE);
4856 if (ret >= 0)
4857 bus->txglom_enable = TRUE;
4858 else {
4859#ifdef BCMSDIOH_STD
4860 sd_txglom = 0;
4861#endif /* BCMSDIOH_STD */
4862 bus->txglom_enable = FALSE;
4863 }
4864 } else
4865#endif /* BCMSDIOH_TXGLOM */
4866 bus->txglom_enable = FALSE;
4867}
4868
4869int
4870dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex)
4871{
4872 dhd_bus_t *bus = dhdp->bus;
4873 dhd_timeout_t tmo;
4874 uint retries = 0;
4875 uint8 ready, enable;
4876 int err, ret = 0;
4877#ifdef BCMSPI
4878 uint32 dstatus = 0; /* gSPI device-status bits */
4879#else /* BCMSPI */
4880 uint8 saveclk;
4881#endif /* BCMSPI */
4882
4883 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4884
4885 ASSERT(bus->dhd);
4886 if (!bus->dhd)
4887 return 0;
4888
4889 if (enforce_mutex)
4890 dhd_os_sdlock(bus->dhd);
4891
4892 /* Make sure backplane clock is on, needed to generate F2 interrupt */
4893 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
4894 if (bus->clkstate != CLK_AVAIL) {
4895 DHD_ERROR(("%s: clock state is wrong. state = %d\n", __FUNCTION__, bus->clkstate));
4896 ret = -1;
4897 goto exit;
4898 }
4899
4900#ifdef BCMSPI
4901 /* fake "ready" for spi, wake-wlan would have already enabled F1 and F2 */
4902 ready = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2);
4903 enable = 0;
4904
4905 /* Give the dongle some time to do its thing and set IOR2 */
4906 dhd_timeout_start(&tmo, WAIT_F2RXFIFORDY * WAIT_F2RXFIFORDY_DELAY * 1000);
4907 while (!enable && !dhd_timeout_expired(&tmo)) {
4908 dstatus = bcmsdh_cfg_read_word(bus->sdh, SDIO_FUNC_0, SPID_STATUS_REG, NULL);
4909 if (dstatus & STATUS_F2_RX_READY)
4910 enable = TRUE;
4911 }
4912
4913 if (enable) {
4914 DHD_ERROR(("Took %u usec before dongle is ready\n", tmo.elapsed));
4915 enable = ready;
4916 } else {
4917 DHD_ERROR(("dstatus when timed out on f2-fifo not ready = 0x%x\n", dstatus));
4918 DHD_ERROR(("Waited %u usec, dongle is not ready\n", tmo.elapsed));
4919 ret = -1;
4920 goto exit;
4921 }
4922
4923#else /* !BCMSPI */
4924 /* Force clocks on backplane to be sure F2 interrupt propagates */
4925 saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
4926
4927 if (!err) {
4928 if (bus->sih->chip == BCM43012_CHIP_ID) {
4929 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
4930 (saveclk | SBSDIO_HT_AVAIL_REQ), &err);
4931 } else {
4932 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
4933 (saveclk | SBSDIO_FORCE_HT), &err);
4934 }
4935 }
4936
4937 if (err) {
4938 DHD_ERROR(("%s: Failed to force clock for F2: err %d\n", __FUNCTION__, err));
4939 ret = -1;
4940 goto exit;
4941 }
4942
4943 /* Enable function 2 (frame transfers) */
4944 W_SDREG((SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT),
4945 &bus->regs->tosbmailboxdata, retries);
4946 enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2);
4947
4948 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL);
4949
4950 /* Give the dongle some time to do its thing and set IOR2 */
4951 dhd_timeout_start(&tmo, DHD_WAIT_F2RDY * 1000);
4952
4953 ready = 0;
4954 while (ready != enable && !dhd_timeout_expired(&tmo))
4955 ready = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IORDY, NULL);
4956
4957#endif /* !BCMSPI */
4958
4959 DHD_ERROR(("%s: enable 0x%02x, ready 0x%02x (waited %uus)\n",
4960 __FUNCTION__, enable, ready, tmo.elapsed));
4961
4962 /* If F2 successfully enabled, set core and enable interrupts */
4963 if (ready == enable) {
4964 /* Make sure we're talking to the core. */
4965#ifdef BCMSDIOLITE
4966 bus->regs = si_setcore(bus->sih, CC_CORE_ID, 0);
4967 ASSERT(bus->regs != NULL);
4968#else
4969 if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0)))
4970 bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0);
4971 ASSERT(bus->regs != NULL);
4972#endif // endif
4973 /* Set up the interrupt mask and enable interrupts */
4974 bus->hostintmask = HOSTINTMASK;
4975 /* corerev 4 could use the newer interrupt logic to detect the frames */
4976#ifndef BCMSPI
4977 if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 4) &&
4978 (bus->rxint_mode != SDIO_DEVICE_HMB_RXINT)) {
4979 bus->hostintmask &= ~I_HMB_FRAME_IND;
4980 bus->hostintmask |= I_XMTDATA_AVAIL;
4981 }
4982#endif /* BCMSPI */
4983 W_SDREG(bus->hostintmask, &bus->regs->hostintmask, retries);
4984
4985 if (bus->sih->buscorerev < 15) {
4986 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK,
4987 (uint8)watermark, &err);
4988 }
4989
4990 /* Set bus state according to enable result */
4991 dhdp->busstate = DHD_BUS_DATA;
4992
4993 /* Need to set fn2 block size to match fn1 block size.
4994 * Requests to fn2 go thru fn1. *
4995 * faltwig has this code contitioned with #if !BCMSPI_ANDROID.
4996 * It would be cleaner to use the ->sdh->block_sz[fno] instead of
4997 * 64, but this layer has no access to sdh types.
4998 */
4999
5000 /* bcmsdh_intr_unmask(bus->sdh); */
5001
5002 bus->intdis = FALSE;
5003 if (bus->intr) {
5004 DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__));
5005#ifndef BCMSPI_ANDROID
5006 bcmsdh_intr_enable(bus->sdh);
5007#endif /* !BCMSPI_ANDROID */
5008 } else {
5009 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
5010 bcmsdh_intr_disable(bus->sdh);
5011 }
5012
5013 }
5014
5015#ifndef BCMSPI
5016
5017 else {
5018 /* Disable F2 again */
5019 enable = SDIO_FUNC_ENABLE_1;
5020 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL);
5021 }
5022
5023 if (dhdsdio_sr_cap(bus)) {
5024 dhdsdio_sr_init(bus);
5025 /* Masking the chip active interrupt permanantly */
5026 bus->hostintmask &= ~I_CHIPACTIVE;
5027 W_SDREG(bus->hostintmask, &bus->regs->hostintmask, retries);
5028 DHD_INFO(("%s: disable I_CHIPACTIVE in hostintmask[0x%08x]\n",
5029 __FUNCTION__, bus->hostintmask));
5030 } else {
5031 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1,
5032 SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err);
5033 }
5034#endif /* !BCMSPI */
5035
5036 /* If we didn't come up, turn off backplane clock */
5037 if (dhdp->busstate != DHD_BUS_DATA)
5038 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
5039
5040exit:
5041 if (enforce_mutex)
5042 dhd_os_sdunlock(bus->dhd);
5043
5044 return ret;
5045}
5046
5047static void
5048dhdsdio_rxfail(dhd_bus_t *bus, bool abort, bool rtx)
5049{
5050 bcmsdh_info_t *sdh = bus->sdh;
5051 sdpcmd_regs_t *regs = bus->regs;
5052 uint retries = 0;
5053 uint16 lastrbc;
5054 uint8 hi, lo;
5055 int err;
5056
5057 DHD_ERROR(("%s: %sterminate frame%s\n", __FUNCTION__,
5058 (abort ? "abort command, " : ""), (rtx ? ", send NAK" : "")));
5059
5060 if (!KSO_ENAB(bus)) {
5061 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
5062 return;
5063 }
5064
5065 if (abort) {
5066 bcmsdh_abort(sdh, SDIO_FUNC_2);
5067 }
5068
5069 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, SFC_RF_TERM, &err);
5070 if (err) {
5071 DHD_ERROR(("%s: SBSDIO_FUNC1_FRAMECTRL cmd err\n", __FUNCTION__));
5072 goto fail;
5073 }
5074 bus->f1regdata++;
5075
5076 /* Wait until the packet has been flushed (device/FIFO stable) */
5077 for (lastrbc = retries = 0xffff; retries > 0; retries--) {
5078 hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCHI, NULL);
5079 lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCLO, &err);
5080 if (err) {
5081 DHD_ERROR(("%s: SBSDIO_FUNC1_RFAMEBCLO cmd err\n", __FUNCTION__));
5082 goto fail;
5083 }
5084
5085 bus->f1regdata += 2;
5086
5087 if ((hi == 0) && (lo == 0))
5088 break;
5089
5090 if ((hi > (lastrbc >> 8)) && (lo > (lastrbc & 0x00ff))) {
5091 DHD_ERROR(("%s: count growing: last 0x%04x now 0x%04x\n",
5092 __FUNCTION__, lastrbc, ((hi << 8) + lo)));
5093 }
5094 lastrbc = (hi << 8) + lo;
5095 }
5096
5097 if (!retries) {
5098 DHD_ERROR(("%s: count never zeroed: last 0x%04x\n", __FUNCTION__, lastrbc));
5099 } else {
5100 DHD_INFO(("%s: flush took %d iterations\n", __FUNCTION__, (0xffff - retries)));
5101 }
5102
5103 if (rtx) {
5104 bus->rxrtx++;
5105 W_SDREG(SMB_NAK, &regs->tosbmailbox, retries);
5106 bus->f1regdata++;
5107 if (retries <= retry_limit) {
5108 bus->rxskip = TRUE;
5109 }
5110 }
5111
5112 /* Clear partial in any case */
5113 bus->nextlen = 0;
5114
5115fail:
5116 /* If we can't reach the device, signal failure */
5117 if (err || bcmsdh_regfail(sdh))
5118 bus->dhd->busstate = DHD_BUS_DOWN;
5119}
5120
5121static void
5122dhdsdio_read_control(dhd_bus_t *bus, uint8 *hdr, uint len, uint doff)
5123{
5124 bcmsdh_info_t *sdh = bus->sdh;
5125 uint rdlen, pad;
5126
5127 int sdret;
5128
5129 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5130
5131 /* Control data already received in aligned rxctl */
5132 if ((bus->bus == SPI_BUS) && (!bus->usebufpool))
5133 goto gotpkt;
5134
5135 ASSERT(bus->rxbuf);
5136 /* Set rxctl for frame (w/optional alignment) */
5137 bus->rxctl = bus->rxbuf;
5138 if (dhd_alignctl) {
5139 bus->rxctl += firstread;
5140 if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN)))
5141 bus->rxctl += (DHD_SDALIGN - pad);
5142 bus->rxctl -= firstread;
5143 }
5144 ASSERT(bus->rxctl >= bus->rxbuf);
5145
5146 /* Copy the already-read portion over */
5147 bcopy(hdr, bus->rxctl, firstread);
5148 if (len <= firstread)
5149 goto gotpkt;
5150
5151 /* Copy the full data pkt in gSPI case and process ioctl. */
5152 if (bus->bus == SPI_BUS) {
5153 bcopy(hdr, bus->rxctl, len);
5154 goto gotpkt;
5155 }
5156
5157 /* Raise rdlen to next SDIO block to avoid tail command */
5158 rdlen = len - firstread;
5159 if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
5160 pad = bus->blocksize - (rdlen % bus->blocksize);
5161 if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
5162 ((len + pad) < bus->dhd->maxctl))
5163 rdlen += pad;
5164 } else if (rdlen % DHD_SDALIGN) {
5165 rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
5166 }
5167
5168 /* Satisfy length-alignment requirements */
5169 if (forcealign && (rdlen & (ALIGNMENT - 1)))
5170 rdlen = ROUNDUP(rdlen, ALIGNMENT);
5171
5172 /* Drop if the read is too big or it exceeds our maximum */
5173 if ((rdlen + firstread) > bus->dhd->maxctl) {
5174 DHD_ERROR(("%s: %d-byte control read exceeds %d-byte buffer\n",
5175 __FUNCTION__, rdlen, bus->dhd->maxctl));
5176 bus->dhd->rx_errors++;
5177 dhdsdio_rxfail(bus, FALSE, FALSE);
5178 goto done;
5179 }
5180
5181 if ((len - doff) > bus->dhd->maxctl) {
5182 DHD_ERROR(("%s: %d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n",
5183 __FUNCTION__, len, (len - doff), bus->dhd->maxctl));
5184 bus->dhd->rx_errors++; bus->rx_toolong++;
5185 dhdsdio_rxfail(bus, FALSE, FALSE);
5186 goto done;
5187 }
5188
5189 /* Read remainder of frame body into the rxctl buffer */
5190 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
5191 (bus->rxctl + firstread), rdlen, NULL, NULL, NULL);
5192 bus->f2rxdata++;
5193 ASSERT(sdret != BCME_PENDING);
5194
5195 /* Control frame failures need retransmission */
5196 if (sdret < 0) {
5197 DHD_ERROR(("%s: read %d control bytes failed: %d\n", __FUNCTION__, rdlen, sdret));
5198 bus->rxc_errors++; /* dhd.rx_ctlerrs is higher level */
5199 dhdsdio_rxfail(bus, TRUE, TRUE);
5200 goto done;
5201 }
5202
5203gotpkt:
5204
5205#ifdef DHD_DEBUG
5206 if (DHD_BYTES_ON() && DHD_CTL_ON()) {
5207 prhex("RxCtrl", bus->rxctl, len);
5208 }
5209#endif // endif
5210
5211 /* Point to valid data and indicate its length */
5212 bus->rxctl += doff;
5213 bus->rxlen = len - doff;
5214
5215done:
5216 /* Awake any waiters */
5217 dhd_os_ioctl_resp_wake(bus->dhd);
5218}
5219int
5220dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf, uint reorder_info_len,
5221 void **pkt, uint32 *pkt_count);
5222
5223static uint8
5224dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq)
5225{
5226 uint16 dlen, totlen;
5227 uint8 *dptr, num = 0;
5228
5229 uint16 sublen, check;
5230 void *pfirst, *plast, *pnext;
5231 void * list_tail[DHD_MAX_IFS] = { NULL };
5232 void * list_head[DHD_MAX_IFS] = { NULL };
5233 uint8 idx;
5234 osl_t *osh = bus->dhd->osh;
5235
5236 int errcode;
5237 uint8 chan, seq, doff, sfdoff;
5238 uint8 txmax;
5239 uchar reorder_info_buf[WLHOST_REORDERDATA_TOTLEN];
5240 uint reorder_info_len;
5241
5242 int ifidx = 0;
5243 bool usechain = bus->use_rxchain;
5244
5245 /* If packets, issue read(s) and send up packet chain */
5246 /* Return sequence numbers consumed? */
5247
5248 DHD_TRACE(("dhdsdio_rxglom: start: glomd %p glom %p\n", bus->glomd, bus->glom));
5249
5250 /* If there's a descriptor, generate the packet chain */
5251 if (bus->glomd) {
5252 dhd_os_sdlock_rxq(bus->dhd);
5253
5254 pfirst = plast = pnext = NULL;
5255 dlen = (uint16)PKTLEN(osh, bus->glomd);
5256 dptr = PKTDATA(osh, bus->glomd);
5257 if (!dlen || (dlen & 1)) {
5258 DHD_ERROR(("%s: bad glomd len (%d), ignore descriptor\n",
5259 __FUNCTION__, dlen));
5260 dlen = 0;
5261 }
5262
5263 for (totlen = num = 0; dlen; num++) {
5264 /* Get (and move past) next length */
5265 sublen = ltoh16_ua(dptr);
5266 dlen -= sizeof(uint16);
5267 dptr += sizeof(uint16);
5268 if ((sublen < SDPCM_HDRLEN) ||
5269 ((num == 0) && (sublen < (2 * SDPCM_HDRLEN)))) {
5270 DHD_ERROR(("%s: descriptor len %d bad: %d\n",
5271 __FUNCTION__, num, sublen));
5272 pnext = NULL;
5273 break;
5274 }
5275 if (sublen % DHD_SDALIGN) {
5276 DHD_ERROR(("%s: sublen %d not a multiple of %d\n",
5277 __FUNCTION__, sublen, DHD_SDALIGN));
5278 usechain = FALSE;
5279 }
5280 totlen += sublen;
5281
5282 /* For last frame, adjust read len so total is a block multiple */
5283 if (!dlen) {
5284 sublen += (ROUNDUP(totlen, bus->blocksize) - totlen);
5285 totlen = ROUNDUP(totlen, bus->blocksize);
5286 }
5287
5288 /* Allocate/chain packet for next subframe */
5289 if ((pnext = PKTGET(osh, sublen + DHD_SDALIGN, FALSE)) == NULL) {
5290 DHD_ERROR(("%s: PKTGET failed, num %d len %d\n",
5291 __FUNCTION__, num, sublen));
5292 break;
5293 }
5294 ASSERT(!PKTLINK(pnext));
5295 if (!pfirst) {
5296 ASSERT(!plast);
5297 pfirst = plast = pnext;
5298 } else {
5299 ASSERT(plast);
5300 PKTSETNEXT(osh, plast, pnext);
5301 plast = pnext;
5302 }
5303
5304 /* Adhere to start alignment requirements */
5305 PKTALIGN(osh, pnext, sublen, DHD_SDALIGN);
5306 }
5307
5308 /* If all allocations succeeded, save packet chain in bus structure */
5309 if (pnext) {
5310 DHD_GLOM(("%s: allocated %d-byte packet chain for %d subframes\n",
5311 __FUNCTION__, totlen, num));
5312 if (DHD_GLOM_ON() && bus->nextlen) {
5313 if (totlen != bus->nextlen) {
5314 DHD_GLOM(("%s: glomdesc mismatch: nextlen %d glomdesc %d "
5315 "rxseq %d\n", __FUNCTION__, bus->nextlen,
5316 totlen, rxseq));
5317 }
5318 }
5319 bus->glom = pfirst;
5320 pfirst = pnext = NULL;
5321 } else {
5322 if (pfirst)
5323 PKTFREE(osh, pfirst, FALSE);
5324 bus->glom = NULL;
5325 num = 0;
5326 }
5327
5328 /* Done with descriptor packet */
5329 PKTFREE(osh, bus->glomd, FALSE);
5330 bus->glomd = NULL;
5331 bus->nextlen = 0;
5332
5333 dhd_os_sdunlock_rxq(bus->dhd);
5334 }
5335
5336 /* Ok -- either we just generated a packet chain, or had one from before */
5337 if (bus->glom) {
5338 if (DHD_GLOM_ON()) {
5339 DHD_GLOM(("%s: attempt superframe read, packet chain:\n", __FUNCTION__));
5340 for (pnext = bus->glom; pnext; pnext = PKTNEXT(osh, pnext)) {
5341 DHD_GLOM((" %p: %p len 0x%04x (%d)\n",
5342 pnext, (uint8*)PKTDATA(osh, pnext),
5343 PKTLEN(osh, pnext), PKTLEN(osh, pnext)));
5344 }
5345 }
5346
5347 pfirst = bus->glom;
5348 dlen = (uint16)pkttotlen(osh, pfirst);
5349
5350 /* Do an SDIO read for the superframe. Configurable iovar to
5351 * read directly into the chained packet, or allocate a large
5352 * packet and and copy into the chain.
5353 */
5354 if (usechain) {
5355 errcode = dhd_bcmsdh_recv_buf(bus,
5356 bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2,
5357 F2SYNC, (uint8*)PKTDATA(osh, pfirst),
5358 dlen, pfirst, NULL, NULL);
5359 } else if (bus->dataptr) {
5360 errcode = dhd_bcmsdh_recv_buf(bus,
5361 bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2,
5362 F2SYNC, bus->dataptr,
5363 dlen, NULL, NULL, NULL);
5364 sublen = (uint16)pktfrombuf(osh, pfirst, 0, dlen, bus->dataptr);
5365 if (sublen != dlen) {
5366 DHD_ERROR(("%s: FAILED TO COPY, dlen %d sublen %d\n",
5367 __FUNCTION__, dlen, sublen));
5368 errcode = -1;
5369 }
5370 pnext = NULL;
5371 BCM_REFERENCE(pnext);
5372 } else {
5373 DHD_ERROR(("COULDN'T ALLOC %d-BYTE GLOM, FORCE FAILURE\n", dlen));
5374 errcode = -1;
5375 }
5376 bus->f2rxdata++;
5377 ASSERT(errcode != BCME_PENDING);
5378
5379 /* On failure, kill the superframe, allow a couple retries */
5380 if (errcode < 0) {
5381 DHD_ERROR(("%s: glom read of %d bytes failed: %d\n",
5382 __FUNCTION__, dlen, errcode));
5383 bus->dhd->rx_errors++;
5384
5385 if (bus->glomerr++ < 3) {
5386 dhdsdio_rxfail(bus, TRUE, TRUE);
5387 } else {
5388 bus->glomerr = 0;
5389 dhdsdio_rxfail(bus, TRUE, FALSE);
5390 dhd_os_sdlock_rxq(bus->dhd);
5391 PKTFREE(osh, bus->glom, FALSE);
5392 dhd_os_sdunlock_rxq(bus->dhd);
5393 bus->rxglomfail++;
5394 bus->glom = NULL;
5395 }
5396 return 0;
5397 }
5398
5399#ifdef DHD_DEBUG
5400 if (DHD_GLOM_ON()) {
5401 prhex("SUPERFRAME", PKTDATA(osh, pfirst),
5402 MIN(PKTLEN(osh, pfirst), 48));
5403 }
5404#endif // endif
5405
5406 /* Validate the superframe header */
5407 dptr = (uint8 *)PKTDATA(osh, pfirst);
5408 sublen = ltoh16_ua(dptr);
5409 check = ltoh16_ua(dptr + sizeof(uint16));
5410
5411 chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
5412 seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
5413 bus->nextlen = dptr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
5414 if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
5415 DHD_INFO(("%s: got frame w/nextlen too large (%d) seq %d\n",
5416 __FUNCTION__, bus->nextlen, seq));
5417 bus->nextlen = 0;
5418 }
5419 doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
5420 txmax = SDPCM_WINDOW_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
5421
5422 errcode = 0;
5423 if ((uint16)~(sublen^check)) {
5424 DHD_ERROR(("%s (superframe): HW hdr error: len/check 0x%04x/0x%04x\n",
5425 __FUNCTION__, sublen, check));
5426 errcode = -1;
5427 } else if (ROUNDUP(sublen, bus->blocksize) != dlen) {
5428 DHD_ERROR(("%s (superframe): len 0x%04x, rounded 0x%04x, expect 0x%04x\n",
5429 __FUNCTION__, sublen, ROUNDUP(sublen, bus->blocksize), dlen));
5430 errcode = -1;
5431 } else if (SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]) != SDPCM_GLOM_CHANNEL) {
5432 DHD_ERROR(("%s (superframe): bad channel %d\n", __FUNCTION__,
5433 SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN])));
5434 errcode = -1;
5435 } else if (SDPCM_GLOMDESC(&dptr[SDPCM_FRAMETAG_LEN])) {
5436 DHD_ERROR(("%s (superframe): got second descriptor?\n", __FUNCTION__));
5437 errcode = -1;
5438 } else if ((doff < SDPCM_HDRLEN) ||
5439 (doff > (PKTLEN(osh, pfirst) - SDPCM_HDRLEN))) {
5440 DHD_ERROR(("%s (superframe): Bad data offset %d: HW %d pkt %d min %d\n",
5441 __FUNCTION__, doff, sublen, PKTLEN(osh, pfirst),
5442 SDPCM_HDRLEN));
5443 errcode = -1;
5444 }
5445
5446 /* Check sequence number of superframe SW header */
5447 if (rxseq != seq) {
5448 DHD_INFO(("%s: (superframe) rx_seq %d, expected %d\n",
5449 __FUNCTION__, seq, rxseq));
5450 bus->rx_badseq++;
5451 rxseq = seq;
5452 }
5453
5454 /* Check window for sanity */
5455 if ((uint8)(txmax - bus->tx_seq) > 0x70) {
5456 DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
5457 __FUNCTION__, txmax, bus->tx_seq));
5458 txmax = bus->tx_max;
5459 }
5460 bus->tx_max = txmax;
5461
5462 /* Remove superframe header, remember offset */
5463 PKTPULL(osh, pfirst, doff);
5464 sfdoff = doff;
5465
5466 /* Validate all the subframe headers */
5467 for (num = 0, pnext = pfirst; pnext && !errcode;
5468 num++, pnext = PKTNEXT(osh, pnext)) {
5469 dptr = (uint8 *)PKTDATA(osh, pnext);
5470 dlen = (uint16)PKTLEN(osh, pnext);
5471 sublen = ltoh16_ua(dptr);
5472 check = ltoh16_ua(dptr + sizeof(uint16));
5473 chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
5474 doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
5475#ifdef DHD_DEBUG
5476 if (DHD_GLOM_ON()) {
5477 prhex("subframe", dptr, 32);
5478 }
5479#endif // endif
5480
5481 if ((uint16)~(sublen^check)) {
5482 DHD_ERROR(("%s (subframe %d): HW hdr error: "
5483 "len/check 0x%04x/0x%04x\n",
5484 __FUNCTION__, num, sublen, check));
5485 errcode = -1;
5486 } else if ((sublen > dlen) || (sublen < SDPCM_HDRLEN)) {
5487 DHD_ERROR(("%s (subframe %d): length mismatch: "
5488 "len 0x%04x, expect 0x%04x\n",
5489 __FUNCTION__, num, sublen, dlen));
5490 errcode = -1;
5491 } else if ((chan != SDPCM_DATA_CHANNEL) &&
5492 (chan != SDPCM_EVENT_CHANNEL)) {
5493 DHD_ERROR(("%s (subframe %d): bad channel %d\n",
5494 __FUNCTION__, num, chan));
5495 errcode = -1;
5496 } else if ((doff < SDPCM_HDRLEN) || (doff > sublen)) {
5497 DHD_ERROR(("%s (subframe %d): Bad data offset %d: HW %d min %d\n",
5498 __FUNCTION__, num, doff, sublen, SDPCM_HDRLEN));
5499 errcode = -1;
5500 }
5501 }
5502
5503 if (errcode) {
5504 /* Terminate frame on error, request a couple retries */
5505 if (bus->glomerr++ < 3) {
5506 /* Restore superframe header space */
5507 PKTPUSH(osh, pfirst, sfdoff);
5508 dhdsdio_rxfail(bus, TRUE, TRUE);
5509 } else {
5510 bus->glomerr = 0;
5511 dhdsdio_rxfail(bus, TRUE, FALSE);
5512 dhd_os_sdlock_rxq(bus->dhd);
5513 PKTFREE(osh, bus->glom, FALSE);
5514 dhd_os_sdunlock_rxq(bus->dhd);
5515 bus->rxglomfail++;
5516 bus->glom = NULL;
5517 }
5518 bus->nextlen = 0;
5519 return 0;
5520 }
5521
5522 /* Basic SD framing looks ok - process each packet (header) */
5523 bus->glom = NULL;
5524 plast = NULL;
5525
5526 dhd_os_sdlock_rxq(bus->dhd);
5527 for (num = 0; pfirst; rxseq++, pfirst = pnext) {
5528 pnext = PKTNEXT(osh, pfirst);
5529 PKTSETNEXT(osh, pfirst, NULL);
5530
5531 dptr = (uint8 *)PKTDATA(osh, pfirst);
5532 sublen = ltoh16_ua(dptr);
5533 chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
5534 seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
5535 doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
5536
5537 DHD_GLOM(("%s: Get subframe %d, %p(%p/%d), sublen %d chan %d seq %d\n",
5538 __FUNCTION__, num, pfirst, PKTDATA(osh, pfirst),
5539 PKTLEN(osh, pfirst), sublen, chan, seq));
5540
5541 ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL));
5542
5543 if (rxseq != seq) {
5544 DHD_GLOM(("%s: rx_seq %d, expected %d\n",
5545 __FUNCTION__, seq, rxseq));
5546 bus->rx_badseq++;
5547 rxseq = seq;
5548 }
5549
5550#ifdef DHD_DEBUG
5551 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
5552 prhex("Rx Subframe Data", dptr, dlen);
5553 }
5554#endif // endif
5555
5556 PKTSETLEN(osh, pfirst, sublen);
5557 PKTPULL(osh, pfirst, doff);
5558
5559 reorder_info_len = sizeof(reorder_info_buf);
5560
5561 if (PKTLEN(osh, pfirst) == 0) {
5562 PKTFREE(bus->dhd->osh, pfirst, FALSE);
5563 continue;
5564 } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pfirst, reorder_info_buf,
5565 &reorder_info_len) != 0) {
5566 DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__));
5567 bus->dhd->rx_errors++;
5568 PKTFREE(osh, pfirst, FALSE);
5569 continue;
5570 }
5571 if (reorder_info_len) {
5572 uint32 free_buf_count;
5573 void *ppfirst;
5574
5575 ppfirst = pfirst;
5576 /* Reordering info from the firmware */
5577 dhd_process_pkt_reorder_info(bus->dhd, reorder_info_buf,
5578 reorder_info_len, &ppfirst, &free_buf_count);
5579
5580 if (free_buf_count == 0) {
5581 continue;
5582 } else {
5583 void *temp;
5584
5585 /* go to the end of the chain and attach the pnext there */
5586 temp = ppfirst;
5587 while (PKTNEXT(osh, temp) != NULL) {
5588 temp = PKTNEXT(osh, temp);
5589 }
5590 pfirst = temp;
5591 if (list_tail[ifidx] == NULL)
5592 list_head[ifidx] = ppfirst;
5593 else
5594 PKTSETNEXT(osh, list_tail[ifidx], ppfirst);
5595 list_tail[ifidx] = pfirst;
5596 }
5597
5598 num += (uint8)free_buf_count;
5599 } else {
5600 /* this packet will go up, link back into chain and count it */
5601
5602 if (list_tail[ifidx] == NULL) {
5603 list_head[ifidx] = list_tail[ifidx] = pfirst;
5604 } else {
5605 PKTSETNEXT(osh, list_tail[ifidx], pfirst);
5606 list_tail[ifidx] = pfirst;
5607 }
5608 num++;
5609 }
5610#ifdef DHD_DEBUG
5611 if (DHD_GLOM_ON()) {
5612 DHD_GLOM(("%s subframe %d to stack, %p(%p/%d) nxt/lnk %p/%p\n",
5613 __FUNCTION__, num, pfirst,
5614 PKTDATA(osh, pfirst), PKTLEN(osh, pfirst),
5615 PKTNEXT(osh, pfirst), PKTLINK(pfirst)));
5616 prhex("", (uint8 *)PKTDATA(osh, pfirst),
5617 MIN(PKTLEN(osh, pfirst), 32));
5618 }
5619#endif /* DHD_DEBUG */
5620 }
5621 dhd_os_sdunlock_rxq(bus->dhd);
5622
5623 for (idx = 0; idx < DHD_MAX_IFS; idx++) {
5624 if (list_head[idx]) {
5625 void *temp;
5626 uint8 cnt = 0;
5627 temp = list_head[idx];
5628 do {
5629 temp = PKTNEXT(osh, temp);
5630 cnt++;
5631 } while (temp);
5632 if (cnt) {
5633 dhd_os_sdunlock(bus->dhd);
5634 dhd_rx_frame(bus->dhd, idx, list_head[idx], cnt, 0);
5635 dhd_os_sdlock(bus->dhd);
5636 }
5637 }
5638 }
5639 bus->rxglomframes++;
5640 bus->rxglompkts += num;
5641 }
5642 return num;
5643}
5644
5645/* Return TRUE if there may be more frames to read */
5646static uint
5647dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished)
5648{
5649 osl_t *osh = bus->dhd->osh;
5650 bcmsdh_info_t *sdh = bus->sdh;
5651
5652 uint16 len, check; /* Extracted hardware header fields */
5653 uint8 chan, seq, doff; /* Extracted software header fields */
5654 uint8 fcbits; /* Extracted fcbits from software header */
5655 uint8 delta;
5656
5657 void *pkt; /* Packet for event or data frames */
5658 uint16 pad; /* Number of pad bytes to read */
5659 uint16 rdlen; /* Total number of bytes to read */
5660 uint8 rxseq; /* Next sequence number to expect */
5661 uint rxleft = 0; /* Remaining number of frames allowed */
5662 int sdret; /* Return code from bcmsdh calls */
5663 uint8 txmax; /* Maximum tx sequence offered */
5664#ifdef BCMSPI
5665 uint32 dstatus = 0; /* gSPI device status bits of */
5666#endif /* BCMSPI */
5667 bool len_consistent; /* Result of comparing readahead len and len from hw-hdr */
5668 uint8 *rxbuf;
5669 int ifidx = 0;
5670 uint rxcount = 0; /* Total frames read */
5671 uchar reorder_info_buf[WLHOST_REORDERDATA_TOTLEN];
5672 uint reorder_info_len;
5673 uint pkt_count;
5674
5675#if defined(DHD_DEBUG) || defined(SDTEST)
5676 bool sdtest = FALSE; /* To limit message spew from test mode */
5677#endif // endif
5678
5679 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5680 bus->readframes = TRUE;
5681
5682 if (!KSO_ENAB(bus)) {
5683 DHD_ERROR(("%s: KSO off\n", __FUNCTION__));
5684 bus->readframes = FALSE;
5685 return 0;
5686 }
5687
5688 ASSERT(maxframes);
5689
5690#ifdef SDTEST
5691 /* Allow pktgen to override maxframes */
5692 if (bus->pktgen_count && (bus->pktgen_mode == DHD_PKTGEN_RECV)) {
5693 maxframes = bus->pktgen_count;
5694 sdtest = TRUE;
5695 }
5696#endif // endif
5697
5698 /* Not finished unless we encounter no more frames indication */
5699 *finished = FALSE;
5700
5701#ifdef BCMSPI
5702 /* Get pktlen from gSPI device F0 reg. */
5703 if (bus->bus == SPI_BUS) {
5704 /* Peek in dstatus bits and find out size to do rx-read. */
5705 dstatus = bcmsdh_get_dstatus(bus->sdh);
5706 if (dstatus == 0)
5707 DHD_ERROR(("%s:ZERO spi dstatus, a case observed in PR61352 hit !!!\n",
5708 __FUNCTION__));
5709
5710 DHD_TRACE(("Device status from regread = 0x%x\n", dstatus));
5711 DHD_TRACE(("Device status from bit-reconstruction = 0x%x\n",
5712 bcmsdh_get_dstatus((void *)bus->sdh)));
5713
5714 if ((dstatus & STATUS_F2_PKT_AVAILABLE) && (((dstatus & STATUS_UNDERFLOW)) == 0)) {
5715 bus->nextlen = ((dstatus & STATUS_F2_PKT_LEN_MASK) >>
5716 STATUS_F2_PKT_LEN_SHIFT);
5717 /* '0' size with pkt-available interrupt is eqvt to 2048 bytes */
5718 bus->nextlen = (bus->nextlen == 0) ? SPI_MAX_PKT_LEN : bus->nextlen;
5719 if (bus->dwordmode)
5720 bus->nextlen = bus->nextlen << 2;
5721 DHD_TRACE(("Entering %s: length to be read from gSPI = %d\n",
5722 __FUNCTION__, bus->nextlen));
5723 } else {
5724 if (dstatus & STATUS_F2_PKT_AVAILABLE)
5725 DHD_ERROR(("Underflow during %s.\n", __FUNCTION__));
5726 else
5727 DHD_ERROR(("False pkt-available intr.\n"));
5728 *finished = TRUE;
5729 return (maxframes - rxleft);
5730 }
5731 }
5732#endif /* BCMSPI */
5733
5734 for (rxseq = bus->rx_seq, rxleft = maxframes;
5735 !bus->rxskip && rxleft && bus->dhd->busstate != DHD_BUS_DOWN;
5736 rxseq++, rxleft--) {
5737#ifdef DHDTCPACK_SUP_DBG
5738 if (bus->dhd->tcpack_sup_mode != TCPACK_SUP_DELAYTX) {
5739 if (bus->dotxinrx == FALSE)
5740 DHD_ERROR(("%s %d: dotxinrx FALSE with tcpack_sub_mode %d\n",
5741 __FUNCTION__, __LINE__, bus->dhd->tcpack_sup_mode));
5742 }
5743#ifdef DEBUG_COUNTER
5744 else if (pktq_mlen(&bus->txq, ~bus->flowcontrol) > 0) {
5745 tack_tbl.cnt[bus->dotxinrx ? 6 : 7]++;
5746 }
5747#endif /* DEBUG_COUNTER */
5748#endif /* DHDTCPACK_SUP_DBG */
5749 /* tx more to improve rx performance */
5750 if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL)) {
5751 dhdsdio_sendpendctl(bus);
5752 } else if (bus->dotxinrx && (bus->clkstate == CLK_AVAIL) &&
5753 !bus->fcstate && DATAOK(bus) &&
5754 (pktq_mlen(&bus->txq, ~bus->flowcontrol) > bus->txinrx_thres)) {
5755 dhdsdio_sendfromq(bus, dhd_txbound);
5756#ifdef DHDTCPACK_SUPPRESS
5757 /* In TCPACK_SUP_DELAYTX mode, do txinrx only if
5758 * 1. Any DATA packet to TX
5759 * 2. TCPACK to TCPDATA PSH packets.
5760 * in bus txq.
5761 */
5762 bus->dotxinrx = (bus->dhd->tcpack_sup_mode == TCPACK_SUP_DELAYTX) ?
5763 FALSE : TRUE;
5764#endif // endif
5765 }
5766
5767 /* Handle glomming separately */
5768 if (bus->glom || bus->glomd) {
5769 uint8 cnt;
5770 DHD_GLOM(("%s: calling rxglom: glomd %p, glom %p\n",
5771 __FUNCTION__, bus->glomd, bus->glom));
5772 cnt = dhdsdio_rxglom(bus, rxseq);
5773 DHD_GLOM(("%s: rxglom returned %d\n", __FUNCTION__, cnt));
5774 rxseq += cnt - 1;
5775 rxleft = (rxleft > cnt) ? (rxleft - cnt) : 1;
5776 continue;
5777 }
5778
5779 /* Try doing single read if we can */
5780 if (dhd_readahead && bus->nextlen) {
5781 uint16 nextlen = bus->nextlen;
5782 bus->nextlen = 0;
5783
5784 if (bus->bus == SPI_BUS) {
5785 rdlen = len = nextlen;
5786 } else {
5787 rdlen = len = nextlen << 4;
5788
5789 /* Pad read to blocksize for efficiency */
5790 if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
5791 pad = bus->blocksize - (rdlen % bus->blocksize);
5792 if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
5793 ((rdlen + pad + firstread) < MAX_RX_DATASZ))
5794 rdlen += pad;
5795 } else if (rdlen % DHD_SDALIGN) {
5796 rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
5797 }
5798 }
5799
5800 /* We use bus->rxctl buffer in WinXP for initial control pkt receives.
5801 * Later we use buffer-poll for data as well as control packets.
5802 * This is required because dhd receives full frame in gSPI unlike SDIO.
5803 * After the frame is received we have to distinguish whether it is data
5804 * or non-data frame.
5805 */
5806 /* Allocate a packet buffer */
5807 dhd_os_sdlock_rxq(bus->dhd);
5808 if (!(pkt = PKTGET(osh, rdlen + DHD_SDALIGN, FALSE))) {
5809 if (bus->bus == SPI_BUS) {
5810 bus->usebufpool = FALSE;
5811 bus->rxctl = bus->rxbuf;
5812 if (dhd_alignctl) {
5813 bus->rxctl += firstread;
5814 if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN)))
5815 bus->rxctl += (DHD_SDALIGN - pad);
5816 bus->rxctl -= firstread;
5817 }
5818 ASSERT(bus->rxctl >= bus->rxbuf);
5819 rxbuf = bus->rxctl;
5820 /* Read the entire frame */
5821 sdret = dhd_bcmsdh_recv_buf(bus,
5822 bcmsdh_cur_sbwad(sdh),
5823 SDIO_FUNC_2,
5824 F2SYNC, rxbuf, rdlen,
5825 NULL, NULL, NULL);
5826 bus->f2rxdata++;
5827 ASSERT(sdret != BCME_PENDING);
5828
5829#ifdef BCMSPI
5830 if (bcmsdh_get_dstatus((void *)bus->sdh) &
5831 STATUS_UNDERFLOW) {
5832 bus->nextlen = 0;
5833 *finished = TRUE;
5834 DHD_ERROR(("%s: read %d control bytes failed "
5835 "due to spi underflow\n",
5836 __FUNCTION__, rdlen));
5837 /* dhd.rx_ctlerrs is higher level */
5838 bus->rxc_errors++;
5839 dhd_os_sdunlock_rxq(bus->dhd);
5840 continue;
5841 }
5842#endif /* BCMSPI */
5843
5844 /* Control frame failures need retransmission */
5845 if (sdret < 0) {
5846 DHD_ERROR(("%s: read %d control bytes failed: %d\n",
5847 __FUNCTION__, rdlen, sdret));
5848 /* dhd.rx_ctlerrs is higher level */
5849 bus->rxc_errors++;
5850 dhd_os_sdunlock_rxq(bus->dhd);
5851 dhdsdio_rxfail(bus, TRUE,
5852 (bus->bus == SPI_BUS) ? FALSE : TRUE);
5853 continue;
5854 }
5855 } else {
5856 /* Give up on data, request rtx of events */
5857 DHD_ERROR(("%s (nextlen): PKTGET failed: len %d rdlen %d "
5858 "expected rxseq %d\n",
5859 __FUNCTION__, len, rdlen, rxseq));
5860 /* Just go try again w/normal header read */
5861 dhd_os_sdunlock_rxq(bus->dhd);
5862 continue;
5863 }
5864 } else {
5865 if (bus->bus == SPI_BUS)
5866 bus->usebufpool = TRUE;
5867
5868 ASSERT(!PKTLINK(pkt));
5869 PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN);
5870 rxbuf = (uint8 *)PKTDATA(osh, pkt);
5871 /* Read the entire frame */
5872 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh),
5873 SDIO_FUNC_2,
5874 F2SYNC, rxbuf, rdlen,
5875 pkt, NULL, NULL);
5876 bus->f2rxdata++;
5877 ASSERT(sdret != BCME_PENDING);
5878#ifdef BCMSPI
5879 if (bcmsdh_get_dstatus((void *)bus->sdh) & STATUS_UNDERFLOW) {
5880 bus->nextlen = 0;
5881 *finished = TRUE;
5882 DHD_ERROR(("%s (nextlen): read %d bytes failed due "
5883 "to spi underflow\n",
5884 __FUNCTION__, rdlen));
5885 PKTFREE(bus->dhd->osh, pkt, FALSE);
5886 bus->dhd->rx_errors++;
5887 dhd_os_sdunlock_rxq(bus->dhd);
5888 continue;
5889 }
5890#endif /* BCMSPI */
5891
5892 if (sdret < 0) {
5893 DHD_ERROR(("%s (nextlen): read %d bytes failed: %d\n",
5894 __FUNCTION__, rdlen, sdret));
5895 PKTFREE(bus->dhd->osh, pkt, FALSE);
5896 bus->dhd->rx_errors++;
5897 dhd_os_sdunlock_rxq(bus->dhd);
5898 /* Force retry w/normal header read. Don't attempt NAK for
5899 * gSPI
5900 */
5901 dhdsdio_rxfail(bus, TRUE,
5902 (bus->bus == SPI_BUS) ? FALSE : TRUE);
5903 continue;
5904 }
5905 }
5906 dhd_os_sdunlock_rxq(bus->dhd);
5907
5908 /* Now check the header */
5909 bcopy(rxbuf, bus->rxhdr, SDPCM_HDRLEN);
5910
5911 /* Extract hardware header fields */
5912 len = ltoh16_ua(bus->rxhdr);
5913 check = ltoh16_ua(bus->rxhdr + sizeof(uint16));
5914
5915 /* All zeros means readahead info was bad */
5916 if (!(len|check)) {
5917 DHD_INFO(("%s (nextlen): read zeros in HW header???\n",
5918 __FUNCTION__));
5919 dhd_os_sdlock_rxq(bus->dhd);
5920 PKTFREE2();
5921 dhd_os_sdunlock_rxq(bus->dhd);
5922 GSPI_PR55150_BAILOUT;
5923 continue;
5924 }
5925
5926 /* Validate check bytes */
5927 if ((uint16)~(len^check)) {
5928 DHD_ERROR(("%s (nextlen): HW hdr error: nextlen/len/check"
5929 " 0x%04x/0x%04x/0x%04x\n", __FUNCTION__, nextlen,
5930 len, check));
5931 dhd_os_sdlock_rxq(bus->dhd);
5932 PKTFREE2();
5933 dhd_os_sdunlock_rxq(bus->dhd);
5934 bus->rx_badhdr++;
5935 dhdsdio_rxfail(bus, FALSE, FALSE);
5936 GSPI_PR55150_BAILOUT;
5937 continue;
5938 }
5939
5940 /* Validate frame length */
5941 if (len < SDPCM_HDRLEN) {
5942 DHD_ERROR(("%s (nextlen): HW hdr length invalid: %d\n",
5943 __FUNCTION__, len));
5944 dhd_os_sdlock_rxq(bus->dhd);
5945 PKTFREE2();
5946 dhd_os_sdunlock_rxq(bus->dhd);
5947 GSPI_PR55150_BAILOUT;
5948 continue;
5949 }
5950
5951 /* Check for consistency with readahead info */
5952#ifdef BCMSPI
5953 if (bus->bus == SPI_BUS) {
5954 if (bus->dwordmode) {
5955 uint16 spilen;
5956 spilen = ROUNDUP(len, 4);
5957 len_consistent = (nextlen != spilen);
5958 } else
5959 len_consistent = (nextlen != len);
5960 } else
5961#endif /* BCMSPI */
5962 len_consistent = (nextlen != (ROUNDUP(len, 16) >> 4));
5963 if (len_consistent) {
5964 /* Mismatch, force retry w/normal header (may be >4K) */
5965 DHD_ERROR(("%s (nextlen): mismatch, nextlen %d len %d rnd %d; "
5966 "expected rxseq %d\n",
5967 __FUNCTION__, nextlen, len, ROUNDUP(len, 16), rxseq));
5968 dhd_os_sdlock_rxq(bus->dhd);
5969 PKTFREE2();
5970 dhd_os_sdunlock_rxq(bus->dhd);
5971 dhdsdio_rxfail(bus, TRUE, (bus->bus == SPI_BUS) ? FALSE : TRUE);
5972 GSPI_PR55150_BAILOUT;
5973 continue;
5974 }
5975
5976 /* Extract software header fields */
5977 chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5978 seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5979 doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5980 txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5981
5982#ifdef BCMSPI
5983 /* Save the readahead length if there is one */
5984 if (bus->bus == SPI_BUS) {
5985 /* Use reconstructed dstatus bits and find out readahead size */
5986 dstatus = bcmsdh_get_dstatus((void *)bus->sdh);
5987 DHD_INFO(("Device status from bit-reconstruction = 0x%x\n",
5988 bcmsdh_get_dstatus((void *)bus->sdh)));
5989 if (dstatus & STATUS_F2_PKT_AVAILABLE) {
5990 bus->nextlen = ((dstatus & STATUS_F2_PKT_LEN_MASK) >>
5991 STATUS_F2_PKT_LEN_SHIFT);
5992 bus->nextlen = (bus->nextlen == 0) ?
5993 SPI_MAX_PKT_LEN : bus->nextlen;
5994 if (bus->dwordmode)
5995 bus->nextlen = bus->nextlen << 2;
5996 DHD_INFO(("readahead len from gSPI = %d \n",
5997 bus->nextlen));
5998 bus->dhd->rx_readahead_cnt ++;
5999 } else {
6000 bus->nextlen = 0;
6001 *finished = TRUE;
6002 }
6003 } else {
6004#endif /* BCMSPI */
6005 bus->nextlen =
6006 bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
6007 if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
6008 DHD_INFO(("%s (nextlen): got frame w/nextlen too large"
6009 " (%d), seq %d\n", __FUNCTION__, bus->nextlen,
6010 seq));
6011 bus->nextlen = 0;
6012 }
6013
6014 bus->dhd->rx_readahead_cnt ++;
6015#ifdef BCMSPI
6016 }
6017#endif /* BCMSPI */
6018 /* Handle Flow Control */
6019 fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
6020
6021 delta = 0;
6022 if (~bus->flowcontrol & fcbits) {
6023 bus->fc_xoff++;
6024 delta = 1;
6025 }
6026 if (bus->flowcontrol & ~fcbits) {
6027 bus->fc_xon++;
6028 delta = 1;
6029 }
6030
6031 if (delta) {
6032 bus->fc_rcvd++;
6033 bus->flowcontrol = fcbits;
6034 }
6035
6036 /* Check and update sequence number */
6037 if (rxseq != seq) {
6038 DHD_INFO(("%s (nextlen): rx_seq %d, expected %d\n",
6039 __FUNCTION__, seq, rxseq));
6040 bus->rx_badseq++;
6041 rxseq = seq;
6042 }
6043
6044 /* Check window for sanity */
6045 if ((uint8)(txmax - bus->tx_seq) > 0x70) {
6046#ifdef BCMSPI
6047 if ((bus->bus == SPI_BUS) && !(dstatus & STATUS_F2_RX_READY)) {
6048 DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
6049 __FUNCTION__, txmax, bus->tx_seq));
6050 txmax = bus->tx_seq + 2;
6051 } else {
6052#endif /* BCMSPI */
6053 DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
6054 __FUNCTION__, txmax, bus->tx_seq));
6055 txmax = bus->tx_max;
6056#ifdef BCMSPI
6057 }
6058#endif /* BCMSPI */
6059 }
6060 bus->tx_max = txmax;
6061
6062#ifdef DHD_DEBUG
6063 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
6064 prhex("Rx Data", rxbuf, len);
6065 } else if (DHD_HDRS_ON()) {
6066 prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN);
6067 }
6068#endif // endif
6069
6070 if (chan == SDPCM_CONTROL_CHANNEL) {
6071 if (bus->bus == SPI_BUS) {
6072 dhdsdio_read_control(bus, rxbuf, len, doff);
6073 if (bus->usebufpool) {
6074 dhd_os_sdlock_rxq(bus->dhd);
6075 PKTFREE(bus->dhd->osh, pkt, FALSE);
6076 dhd_os_sdunlock_rxq(bus->dhd);
6077 }
6078 continue;
6079 } else {
6080 DHD_ERROR(("%s (nextlen): readahead on control"
6081 " packet %d?\n", __FUNCTION__, seq));
6082 /* Force retry w/normal header read */
6083 bus->nextlen = 0;
6084 dhdsdio_rxfail(bus, FALSE, TRUE);
6085 dhd_os_sdlock_rxq(bus->dhd);
6086 PKTFREE2();
6087 dhd_os_sdunlock_rxq(bus->dhd);
6088 continue;
6089 }
6090 }
6091
6092 if ((bus->bus == SPI_BUS) && !bus->usebufpool) {
6093 DHD_ERROR(("Received %d bytes on %d channel. Running out of "
6094 "rx pktbuf's or not yet malloced.\n", len, chan));
6095 continue;
6096 }
6097
6098 /* Validate data offset */
6099 if ((doff < SDPCM_HDRLEN) || (doff > len)) {
6100 DHD_ERROR(("%s (nextlen): bad data offset %d: HW len %d min %d\n",
6101 __FUNCTION__, doff, len, SDPCM_HDRLEN));
6102 dhd_os_sdlock_rxq(bus->dhd);
6103 PKTFREE2();
6104 dhd_os_sdunlock_rxq(bus->dhd);
6105 ASSERT(0);
6106 dhdsdio_rxfail(bus, FALSE, FALSE);
6107 continue;
6108 }
6109
6110 /* All done with this one -- now deliver the packet */
6111 goto deliver;
6112 }
6113 /* gSPI frames should not be handled in fractions */
6114 if (bus->bus == SPI_BUS) {
6115 break;
6116 }
6117
6118 /* Read frame header (hardware and software) */
6119 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
6120 bus->rxhdr, firstread, NULL, NULL, NULL);
6121 bus->f2rxhdrs++;
6122 ASSERT(sdret != BCME_PENDING);
6123
6124 if (sdret < 0) {
6125 DHD_ERROR(("%s: RXHEADER FAILED: %d\n", __FUNCTION__, sdret));
6126 bus->rx_hdrfail++;
6127 dhdsdio_rxfail(bus, TRUE, TRUE);
6128 continue;
6129 }
6130
6131#ifdef DHD_DEBUG
6132 if (DHD_BYTES_ON() || DHD_HDRS_ON()) {
6133 prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN);
6134 }
6135#endif // endif
6136
6137 /* Extract hardware header fields */
6138 len = ltoh16_ua(bus->rxhdr);
6139 check = ltoh16_ua(bus->rxhdr + sizeof(uint16));
6140
6141 /* All zeros means no more frames */
6142 if (!(len|check)) {
6143 *finished = TRUE;
6144 break;
6145 }
6146
6147 /* Validate check bytes */
6148 if ((uint16)~(len^check)) {
6149 DHD_ERROR(("%s: HW hdr error: len/check 0x%04x/0x%04x\n",
6150 __FUNCTION__, len, check));
6151 bus->rx_badhdr++;
6152 dhdsdio_rxfail(bus, FALSE, FALSE);
6153 continue;
6154 }
6155
6156 /* Validate frame length */
6157 if (len < SDPCM_HDRLEN) {
6158 DHD_ERROR(("%s: HW hdr length invalid: %d\n", __FUNCTION__, len));
6159 continue;
6160 }
6161
6162 /* Extract software header fields */
6163 chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
6164 seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
6165 doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
6166 txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
6167
6168 /* Validate data offset */
6169 if ((doff < SDPCM_HDRLEN) || (doff > len)) {
6170 DHD_ERROR(("%s: Bad data offset %d: HW len %d, min %d seq %d\n",
6171 __FUNCTION__, doff, len, SDPCM_HDRLEN, seq));
6172 bus->rx_badhdr++;
6173 ASSERT(0);
6174 dhdsdio_rxfail(bus, FALSE, FALSE);
6175 continue;
6176 }
6177
6178 /* Save the readahead length if there is one */
6179 bus->nextlen = bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
6180 if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
6181 DHD_INFO(("%s (nextlen): got frame w/nextlen too large (%d), seq %d\n",
6182 __FUNCTION__, bus->nextlen, seq));
6183 bus->nextlen = 0;
6184 }
6185
6186 /* Handle Flow Control */
6187 fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
6188
6189 delta = 0;
6190 if (~bus->flowcontrol & fcbits) {
6191 bus->fc_xoff++;
6192 delta = 1;
6193 }
6194 if (bus->flowcontrol & ~fcbits) {
6195 bus->fc_xon++;
6196 delta = 1;
6197 }
6198
6199 if (delta) {
6200 bus->fc_rcvd++;
6201 bus->flowcontrol = fcbits;
6202 }
6203
6204 /* Check and update sequence number */
6205 if (rxseq != seq) {
6206 DHD_INFO(("%s: rx_seq %d, expected %d\n", __FUNCTION__, seq, rxseq));
6207 bus->rx_badseq++;
6208 rxseq = seq;
6209 }
6210
6211 /* Check window for sanity */
6212 if ((uint8)(txmax - bus->tx_seq) > 0x70) {
6213 DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
6214 __FUNCTION__, txmax, bus->tx_seq));
6215 txmax = bus->tx_max;
6216 }
6217 bus->tx_max = txmax;
6218
6219 /* Call a separate function for control frames */
6220 if (chan == SDPCM_CONTROL_CHANNEL) {
6221 dhdsdio_read_control(bus, bus->rxhdr, len, doff);
6222 continue;
6223 }
6224
6225 ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL) ||
6226 (chan == SDPCM_TEST_CHANNEL) || (chan == SDPCM_GLOM_CHANNEL));
6227
6228 /* Length to read */
6229 rdlen = (len > firstread) ? (len - firstread) : 0;
6230
6231 /* May pad read to blocksize for efficiency */
6232 if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
6233 pad = bus->blocksize - (rdlen % bus->blocksize);
6234 if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
6235 ((rdlen + pad + firstread) < MAX_RX_DATASZ))
6236 rdlen += pad;
6237 } else if (rdlen % DHD_SDALIGN) {
6238 rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
6239 }
6240
6241 /* Satisfy length-alignment requirements */
6242 if (forcealign && (rdlen & (ALIGNMENT - 1)))
6243 rdlen = ROUNDUP(rdlen, ALIGNMENT);
6244
6245 if ((rdlen + firstread) > MAX_RX_DATASZ) {
6246 /* Too long -- skip this frame */
6247 DHD_ERROR(("%s: too long: len %d rdlen %d\n", __FUNCTION__, len, rdlen));
6248 bus->dhd->rx_errors++; bus->rx_toolong++;
6249 dhdsdio_rxfail(bus, FALSE, FALSE);
6250 continue;
6251 }
6252
6253 dhd_os_sdlock_rxq(bus->dhd);
6254 if (!(pkt = PKTGET(osh, (rdlen + firstread + DHD_SDALIGN), FALSE))) {
6255 /* Give up on data, request rtx of events */
6256 DHD_ERROR(("%s: PKTGET failed: rdlen %d chan %d\n",
6257 __FUNCTION__, rdlen, chan));
6258 bus->dhd->rx_dropped++;
6259 dhd_os_sdunlock_rxq(bus->dhd);
6260 dhdsdio_rxfail(bus, FALSE, RETRYCHAN(chan));
6261 continue;
6262 }
6263 dhd_os_sdunlock_rxq(bus->dhd);
6264
6265 ASSERT(!PKTLINK(pkt));
6266
6267 /* Leave room for what we already read, and align remainder */
6268 ASSERT(firstread < (PKTLEN(osh, pkt)));
6269 PKTPULL(osh, pkt, firstread);
6270 PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN);
6271
6272 /* Read the remaining frame data */
6273 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
6274 ((uint8 *)PKTDATA(osh, pkt)), rdlen, pkt, NULL, NULL);
6275 bus->f2rxdata++;
6276 ASSERT(sdret != BCME_PENDING);
6277
6278 if (sdret < 0) {
6279 DHD_ERROR(("%s: read %d %s bytes failed: %d\n", __FUNCTION__, rdlen,
6280 ((chan == SDPCM_EVENT_CHANNEL) ? "event" :
6281 ((chan == SDPCM_DATA_CHANNEL) ? "data" : "test")), sdret));
6282 dhd_os_sdlock_rxq(bus->dhd);
6283 PKTFREE(bus->dhd->osh, pkt, FALSE);
6284 dhd_os_sdunlock_rxq(bus->dhd);
6285 bus->dhd->rx_errors++;
6286 dhdsdio_rxfail(bus, TRUE, RETRYCHAN(chan));
6287 continue;
6288 }
6289
6290 /* Copy the already-read portion */
6291 PKTPUSH(osh, pkt, firstread);
6292 bcopy(bus->rxhdr, PKTDATA(osh, pkt), firstread);
6293
6294#ifdef DHD_DEBUG
6295 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
6296 prhex("Rx Data", PKTDATA(osh, pkt), len);
6297 }
6298#endif // endif
6299
6300deliver:
6301 /* Save superframe descriptor and allocate packet frame */
6302 if (chan == SDPCM_GLOM_CHANNEL) {
6303 if (SDPCM_GLOMDESC(&bus->rxhdr[SDPCM_FRAMETAG_LEN])) {
6304 DHD_GLOM(("%s: got glom descriptor, %d bytes:\n",
6305 __FUNCTION__, len));
6306#ifdef DHD_DEBUG
6307 if (DHD_GLOM_ON()) {
6308 prhex("Glom Data", PKTDATA(osh, pkt), len);
6309 }
6310#endif // endif
6311 PKTSETLEN(osh, pkt, len);
6312 ASSERT(doff == SDPCM_HDRLEN);
6313 PKTPULL(osh, pkt, SDPCM_HDRLEN);
6314 bus->glomd = pkt;
6315 } else {
6316 DHD_ERROR(("%s: glom superframe w/o descriptor!\n", __FUNCTION__));
6317 dhdsdio_rxfail(bus, FALSE, FALSE);
6318 }
6319 continue;
6320 }
6321
6322 /* Fill in packet len and prio, deliver upward */
6323 PKTSETLEN(osh, pkt, len);
6324 PKTPULL(osh, pkt, doff);
6325
6326#ifdef SDTEST
6327 /* Test channel packets are processed separately */
6328 if (chan == SDPCM_TEST_CHANNEL) {
6329 dhdsdio_testrcv(bus, pkt, seq);
6330 continue;
6331 }
6332#endif /* SDTEST */
6333
6334 if (PKTLEN(osh, pkt) == 0) {
6335 dhd_os_sdlock_rxq(bus->dhd);
6336 PKTFREE(bus->dhd->osh, pkt, FALSE);
6337 dhd_os_sdunlock_rxq(bus->dhd);
6338 continue;
6339 } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pkt, reorder_info_buf,
6340 &reorder_info_len) != 0) {
6341 DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__));
6342 dhd_os_sdlock_rxq(bus->dhd);
6343 PKTFREE(bus->dhd->osh, pkt, FALSE);
6344 dhd_os_sdunlock_rxq(bus->dhd);
6345 bus->dhd->rx_errors++;
6346 continue;
6347 }
6348
6349 if (reorder_info_len) {
6350 /* Reordering info from the firmware */
6351 dhd_process_pkt_reorder_info(bus->dhd, reorder_info_buf, reorder_info_len,
6352 &pkt, &pkt_count);
6353 if (pkt_count == 0)
6354 continue;
6355 } else {
6356 pkt_count = 1;
6357 }
6358
6359 /* Unlock during rx call */
6360 dhd_os_sdunlock(bus->dhd);
6361 dhd_rx_frame(bus->dhd, ifidx, pkt, pkt_count, chan);
6362 dhd_os_sdlock(bus->dhd);
6363 }
6364 rxcount = maxframes - rxleft;
6365#ifdef DHD_DEBUG
6366 /* Message if we hit the limit */
6367 if (!rxleft && !sdtest)
6368 DHD_DATA(("%s: hit rx limit of %d frames\n", __FUNCTION__, maxframes));
6369 else
6370#endif /* DHD_DEBUG */
6371 DHD_DATA(("%s: processed %d frames\n", __FUNCTION__, rxcount));
6372 /* Back off rxseq if awaiting rtx, update rx_seq */
6373 if (bus->rxskip)
6374 rxseq--;
6375 bus->rx_seq = rxseq;
6376
6377 if (bus->reqbussleep)
6378 {
6379 dhdsdio_bussleep(bus, TRUE);
6380 bus->reqbussleep = FALSE;
6381 }
6382 bus->readframes = FALSE;
6383
6384 return rxcount;
6385}
6386
6387static uint32
6388dhdsdio_hostmail(dhd_bus_t *bus, uint32 *hmbd)
6389{
6390 sdpcmd_regs_t *regs = bus->regs;
6391 uint32 intstatus = 0;
6392 uint32 hmb_data;
6393 uint8 fcbits;
6394 uint retries = 0;
6395
6396 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
6397
6398 /* Read mailbox data and ack that we did so */
6399 R_SDREG(hmb_data, &regs->tohostmailboxdata, retries);
6400 if (retries <= retry_limit)
6401 W_SDREG(SMB_INT_ACK, &regs->tosbmailbox, retries);
6402 bus->f1regdata += 2;
6403
6404 /* Dongle recomposed rx frames, accept them again */
6405 if (hmb_data & HMB_DATA_NAKHANDLED) {
6406 DHD_INFO(("Dongle reports NAK handled, expect rtx of %d\n", bus->rx_seq));
6407 if (!bus->rxskip) {
6408 DHD_ERROR(("%s: unexpected NAKHANDLED!\n", __FUNCTION__));
6409 }
6410 bus->rxskip = FALSE;
6411 intstatus |= FRAME_AVAIL_MASK(bus);
6412 }
6413
6414 /*
6415 * DEVREADY does not occur with gSPI.
6416 */
6417 if (hmb_data & (HMB_DATA_DEVREADY | HMB_DATA_FWREADY)) {
6418 bus->sdpcm_ver = (hmb_data & HMB_DATA_VERSION_MASK) >> HMB_DATA_VERSION_SHIFT;
6419 if (bus->sdpcm_ver != SDPCM_PROT_VERSION)
6420 DHD_ERROR(("Version mismatch, dongle reports %d, expecting %d\n",
6421 bus->sdpcm_ver, SDPCM_PROT_VERSION));
6422 else
6423 DHD_INFO(("Dongle ready, protocol version %d\n", bus->sdpcm_ver));
6424#ifndef BCMSPI
6425 /* make sure for the SDIO_DEVICE_RXDATAINT_MODE_1 corecontrol is proper */
6426 if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev >= 4) &&
6427 (bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_1)) {
6428 uint32 val;
6429
6430 val = R_REG(bus->dhd->osh, &bus->regs->corecontrol);
6431 val &= ~CC_XMTDATAAVAIL_MODE;
6432 val |= CC_XMTDATAAVAIL_CTRL;
6433 W_REG(bus->dhd->osh, &bus->regs->corecontrol, val);
6434
6435 val = R_REG(bus->dhd->osh, &bus->regs->corecontrol);
6436 }
6437#endif /* BCMSPI */
6438
6439#ifdef DHD_DEBUG
6440 /* Retrieve console state address now that firmware should have updated it */
6441 {
6442 sdpcm_shared_t shared;
6443 if (dhdsdio_readshared(bus, &shared) == 0)
6444 bus->console_addr = shared.console_addr;
6445 }
6446#endif /* DHD_DEBUG */
6447 }
6448
6449 /*
6450 * Flow Control has been moved into the RX headers and this out of band
6451 * method isn't used any more. Leave this here for possibly remaining backward
6452 * compatible with older dongles
6453 */
6454 if (hmb_data & HMB_DATA_FC) {
6455 fcbits = (hmb_data & HMB_DATA_FCDATA_MASK) >> HMB_DATA_FCDATA_SHIFT;
6456
6457 if (fcbits & ~bus->flowcontrol)
6458 bus->fc_xoff++;
6459 if (bus->flowcontrol & ~fcbits)
6460 bus->fc_xon++;
6461
6462 bus->fc_rcvd++;
6463 bus->flowcontrol = fcbits;
6464 }
6465
6466 /* At least print a message if FW halted */
6467 if (hmb_data & HMB_DATA_FWHALT) {
6468 DHD_ERROR(("INTERNAL ERROR: FIRMWARE HALTED : set BUS DOWN\n"));
6469 dhdsdio_checkdied(bus, NULL, 0);
6470 bus->dhd->busstate = DHD_BUS_DOWN;
6471 }
6472
6473 /* Shouldn't be any others */
6474 if (hmb_data & ~(HMB_DATA_DEVREADY |
6475 HMB_DATA_FWHALT |
6476 HMB_DATA_NAKHANDLED |
6477 HMB_DATA_FC |
6478 HMB_DATA_FWREADY |
6479 HMB_DATA_FCDATA_MASK |
6480 HMB_DATA_VERSION_MASK)) {
6481 DHD_ERROR(("Unknown mailbox data content: 0x%02x\n", hmb_data));
6482 }
6483
6484 if (hmbd) {
6485 *hmbd = hmb_data;
6486 }
6487
6488 return intstatus;
6489}
6490
6491static bool
6492dhdsdio_dpc(dhd_bus_t *bus)
6493{
6494 bcmsdh_info_t *sdh = bus->sdh;
6495 sdpcmd_regs_t *regs = bus->regs;
6496 uint32 intstatus, newstatus = 0;
6497 uint retries = 0;
6498 uint rxlimit = dhd_rxbound; /* Rx frames to read before resched */
6499 uint txlimit = dhd_txbound; /* Tx frames to send before resched */
6500 uint framecnt = 0; /* Temporary counter of tx/rx frames */
6501 bool rxdone = TRUE; /* Flag for no more read data */
6502 bool resched = FALSE; /* Flag indicating resched wanted */
6503 unsigned long flags;
6504#ifdef DEBUG_DPC_THREAD_WATCHDOG
6505 bool is_resched_by_readframe = FALSE;
6506#endif /* DEBUG_DPC_THREAD_WATCHDOG */
6507 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
6508
6509 dhd_os_sdlock(bus->dhd);
6510 DHD_LINUX_GENERAL_LOCK(bus->dhd, flags);
6511 if (bus->dhd->busstate == DHD_BUS_DOWN) {
6512 DHD_ERROR(("%s: Bus down, ret\n", __FUNCTION__));
6513 bus->intstatus = 0;
6514 DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
6515 dhd_os_sdunlock(bus->dhd);
6516 return 0;
6517 }
6518
6519 DHD_BUS_BUSY_SET_IN_DPC(bus->dhd);
6520 DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
6521
6522 /* Start with leftover status bits */
6523 intstatus = bus->intstatus;
6524
6525 if (!SLPAUTO_ENAB(bus) && !KSO_ENAB(bus)) {
6526 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
6527 goto exit;
6528 }
6529
6530 /* If waiting for HTAVAIL, check status */
6531 if (!SLPAUTO_ENAB(bus) && (bus->clkstate == CLK_PENDING)) {
6532 int err;
6533 uint8 clkctl, devctl = 0;
6534
6535#ifdef DHD_DEBUG
6536 /* Check for inconsistent device control */
6537 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
6538 if (err) {
6539 DHD_ERROR(("%s: error reading DEVCTL: %d\n", __FUNCTION__, err));
6540 bus->dhd->busstate = DHD_BUS_DOWN;
6541 } else {
6542 ASSERT(devctl & SBSDIO_DEVCTL_CA_INT_ONLY);
6543 }
6544#endif /* DHD_DEBUG */
6545
6546 /* Read CSR, if clock on switch to AVAIL, else ignore */
6547 clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
6548 if (err) {
6549 DHD_ERROR(("%s: error reading CSR: %d\n", __FUNCTION__, err));
6550 bus->dhd->busstate = DHD_BUS_DOWN;
6551 }
6552
6553 DHD_INFO(("DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n", devctl, clkctl));
6554
6555 if (SBSDIO_HTAV(clkctl)) {
6556 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
6557 if (err) {
6558 DHD_ERROR(("%s: error reading DEVCTL: %d\n",
6559 __FUNCTION__, err));
6560 bus->dhd->busstate = DHD_BUS_DOWN;
6561 }
6562 devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
6563 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
6564 if (err) {
6565 DHD_ERROR(("%s: error writing DEVCTL: %d\n",
6566 __FUNCTION__, err));
6567 bus->dhd->busstate = DHD_BUS_DOWN;
6568 }
6569 bus->clkstate = CLK_AVAIL;
6570 } else {
6571 goto clkwait;
6572 }
6573 }
6574
6575 BUS_WAKE(bus);
6576
6577 /* Make sure backplane clock is on */
6578 dhdsdio_clkctl(bus, CLK_AVAIL, TRUE);
6579 if (bus->clkstate != CLK_AVAIL)
6580 goto clkwait;
6581
6582 /* Pending interrupt indicates new device status */
6583 if (bus->ipend) {
6584 bus->ipend = FALSE;
6585#if defined(BT_OVER_SDIO)
6586 bcmsdh_btsdio_process_f3_intr();
6587#endif /* defined (BT_OVER_SDIO) */
6588
6589 R_SDREG(newstatus, &regs->intstatus, retries);
6590 bus->f1regdata++;
6591 if (bcmsdh_regfail(bus->sdh))
6592 newstatus = 0;
6593 newstatus &= bus->hostintmask;
6594 bus->fcstate = !!(newstatus & I_HMB_FC_STATE);
6595 if (newstatus) {
6596 bus->f1regdata++;
6597#ifndef BCMSPI
6598 if ((bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_0) &&
6599 (newstatus == I_XMTDATA_AVAIL)) {
6600 } else
6601#endif /* BCMSPI */
6602 W_SDREG(newstatus, &regs->intstatus, retries);
6603 }
6604 }
6605
6606 /* Merge new bits with previous */
6607 intstatus |= newstatus;
6608 bus->intstatus = 0;
6609
6610 /* Handle flow-control change: read new state in case our ack
6611 * crossed another change interrupt. If change still set, assume
6612 * FC ON for safety, let next loop through do the debounce.
6613 */
6614 if (intstatus & I_HMB_FC_CHANGE) {
6615 intstatus &= ~I_HMB_FC_CHANGE;
6616 W_SDREG(I_HMB_FC_CHANGE, &regs->intstatus, retries);
6617 R_SDREG(newstatus, &regs->intstatus, retries);
6618 bus->f1regdata += 2;
6619 bus->fcstate = !!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE));
6620 intstatus |= (newstatus & bus->hostintmask);
6621 }
6622
6623 /* Handle host mailbox indication */
6624 if (intstatus & I_HMB_HOST_INT) {
6625 uint32 hmbdata = 0;
6626
6627 intstatus &= ~I_HMB_HOST_INT;
6628 intstatus |= dhdsdio_hostmail(bus, &hmbdata);
6629
6630#ifdef DHD_ULP
6631 /* ULP prototyping. Redowload fw on oob interupt */
6632
6633 /* all the writes after this point CAN use cached sbwad value */
6634 bcmsdh_force_sbwad_calc(bus->sdh, FALSE);
6635
6636 if (dhd_ulp_pre_redownload_check(bus->dhd, bus->sdh, hmbdata)) {
6637 if (dhd_bus_ulp_reinit_fw(bus) < 0) {
6638 DHD_ERROR(("%s:%d FW redownload failed\n",
6639 __FUNCTION__, __LINE__));
6640 goto exit;
6641 }
6642 }
6643#endif // endif
6644
6645 }
6646
6647#ifdef DHD_UCODE_DOWNLOAD
6648exit_ucode:
6649#endif /* DHD_UCODE_DOWNLOAD */
6650
6651 /* Just being here means nothing more to do for chipactive */
6652 if (intstatus & I_CHIPACTIVE) {
6653 /* ASSERT(bus->clkstate == CLK_AVAIL); */
6654 intstatus &= ~I_CHIPACTIVE;
6655 }
6656
6657 /* Handle host mailbox indication */
6658 if (intstatus & I_HMB_HOST_INT) {
6659 intstatus &= ~I_HMB_HOST_INT;
6660 intstatus |= dhdsdio_hostmail(bus, NULL);
6661 }
6662
6663 /* Generally don't ask for these, can get CRC errors... */
6664 if (intstatus & I_WR_OOSYNC) {
6665 DHD_ERROR(("Dongle reports WR_OOSYNC\n"));
6666 intstatus &= ~I_WR_OOSYNC;
6667 }
6668
6669 if (intstatus & I_RD_OOSYNC) {
6670 DHD_ERROR(("Dongle reports RD_OOSYNC\n"));
6671 intstatus &= ~I_RD_OOSYNC;
6672 }
6673
6674 if (intstatus & I_SBINT) {
6675 DHD_ERROR(("Dongle reports SBINT\n"));
6676 intstatus &= ~I_SBINT;
6677 }
6678
6679 /* Would be active due to wake-wlan in gSPI */
6680 if (intstatus & I_CHIPACTIVE) {
6681 DHD_INFO(("Dongle reports CHIPACTIVE\n"));
6682 intstatus &= ~I_CHIPACTIVE;
6683 }
6684
6685 if (intstatus & I_HMB_FC_STATE) {
6686 DHD_INFO(("Dongle reports HMB_FC_STATE\n"));
6687 intstatus &= ~I_HMB_FC_STATE;
6688 }
6689
6690 /* Ignore frame indications if rxskip is set */
6691 if (bus->rxskip) {
6692 intstatus &= ~FRAME_AVAIL_MASK(bus);
6693 }
6694
6695 /* On frame indication, read available frames */
6696 if (PKT_AVAILABLE(bus, intstatus)) {
6697
6698 framecnt = dhdsdio_readframes(bus, rxlimit, &rxdone);
6699 if (rxdone || bus->rxskip)
6700 intstatus &= ~FRAME_AVAIL_MASK(bus);
6701 rxlimit -= MIN(framecnt, rxlimit);
6702 }
6703
6704 /* Keep still-pending events for next scheduling */
6705 bus->intstatus = intstatus;
6706
6707clkwait:
6708 /* Re-enable interrupts to detect new device events (mailbox, rx frame)
6709 * or clock availability. (Allows tx loop to check ipend if desired.)
6710 * (Unless register access seems hosed, as we may not be able to ACK...)
6711 */
6712 if (bus->intr && bus->intdis && !bcmsdh_regfail(sdh)) {
6713 DHD_INTR(("%s: enable SDIO interrupts, rxdone %d framecnt %d\n",
6714 __FUNCTION__, rxdone, framecnt));
6715 bus->intdis = FALSE;
6716#if defined(OOB_INTR_ONLY)
6717 bcmsdh_oob_intr_set(bus->sdh, TRUE);
6718#endif /* defined(OOB_INTR_ONLY) */
6719 bcmsdh_intr_enable(sdh);
6720#ifdef BCMSPI_ANDROID
6721 if (*dhd_spi_lockcount == 0)
6722 bcmsdh_oob_intr_set(bus->sdh, TRUE);
6723#endif /* BCMSPI_ANDROID */
6724 }
6725
6726#if defined(OOB_INTR_ONLY) && !defined(HW_OOB)
6727 /* In case of SW-OOB(using edge trigger),
6728 * Check interrupt status in the dongle again after enable irq on the host.
6729 * and rechedule dpc if interrupt is pended in the dongle.
6730 * There is a chance to miss OOB interrupt while irq is disabled on the host.
6731 * No need to do this with HW-OOB(level trigger)
6732 */
6733 R_SDREG(newstatus, &regs->intstatus, retries);
6734 if (bcmsdh_regfail(bus->sdh))
6735 newstatus = 0;
6736 if (newstatus & bus->hostintmask) {
6737 bus->ipend = TRUE;
6738 resched = TRUE;
6739 }
6740#endif /* defined(OOB_INTR_ONLY) && !defined(HW_OOB) */
6741
6742#ifdef PROP_TXSTATUS
6743 dhd_wlfc_commit_packets(bus->dhd, (f_commitpkt_t)dhd_bus_txdata, (void *)bus, NULL, FALSE);
6744#endif // endif
6745
6746 if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL))
6747 dhdsdio_sendpendctl(bus);
6748
6749 /* Send queued frames (limit 1 if rx may still be pending) */
6750 else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate &&
6751 pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit && DATAOK(bus)) {
6752
6753#ifdef DHD_ULP
6754 if (dhd_ulp_f2_ready(bus->dhd, bus->sdh)) {
6755#endif /* DHD_ULP */
6756 framecnt = rxdone ? txlimit : MIN(txlimit, dhd_txminmax);
6757 framecnt = dhdsdio_sendfromq(bus, framecnt);
6758 txlimit -= framecnt;
6759#ifdef DHD_ULP
6760 } else {
6761 /* In other transient states like DHD_ULP_, after the states are
6762 * DHD_ULP_F2ENAB_CLEARING and DHD_ULP_F2ENAB_SETTING,
6763 * dpc is scheduled after steady-state and dhdsdio_sendfromq() will
6764 * execute again
6765 */
6766 }
6767#endif /* DHD_ULP */
6768 }
6769 /* Resched the DPC if ctrl cmd is pending on bus credit */
6770 if (bus->ctrl_frame_stat)
6771 resched = TRUE;
6772
6773 /* Resched if events or tx frames are pending, else await next interrupt */
6774 /* On failed register access, all bets are off: no resched or interrupts */
6775 if ((bus->dhd->busstate == DHD_BUS_DOWN) || bcmsdh_regfail(sdh)) {
6776 if ((bus->sih && bus->sih->buscorerev >= 12) && !(dhdsdio_sleepcsr_get(bus) &
6777 SBSDIO_FUNC1_SLEEPCSR_KSO_MASK)) {
6778 /* Bus failed because of KSO */
6779 DHD_ERROR(("%s: Bus failed due to KSO\n", __FUNCTION__));
6780 bus->kso = FALSE;
6781 } else {
6782 DHD_ERROR(("%s: failed backplane access over SDIO, halting operation\n",
6783 __FUNCTION__));
6784 bus->dhd->busstate = DHD_BUS_DOWN;
6785 bus->intstatus = 0;
6786 }
6787 } else if (bus->clkstate == CLK_PENDING) {
6788 /* Awaiting I_CHIPACTIVE; don't resched */
6789 } else if (bus->intstatus || bus->ipend ||
6790 (!bus->fcstate && pktq_mlen(&bus->txq, ~bus->flowcontrol) && DATAOK(bus)) ||
6791 PKT_AVAILABLE(bus, bus->intstatus)) { /* Read multiple frames */
6792 resched = TRUE;
6793 }
6794
6795 bus->dpc_sched = resched;
6796
6797 /* If we're done for now, turn off clock request. */
6798 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && (bus->clkstate != CLK_PENDING) &&
6799 NO_OTHER_ACTIVE_BUS_USER(bus)) {
6800 bus->activity = FALSE;
6801 dhdsdio_bussleep(bus, TRUE);
6802 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
6803 }
6804
6805exit:
6806
6807 if (!resched && dhd_dpcpoll) {
6808 if (dhdsdio_readframes(bus, dhd_rxbound, &rxdone) != 0) {
6809 resched = TRUE;
6810#ifdef DEBUG_DPC_THREAD_WATCHDOG
6811 is_resched_by_readframe = TRUE;
6812#endif /* DEBUG_DPC_THREAD_WATCHDOG */
6813 }
6814 }
6815
6816 dhd_os_sdunlock(bus->dhd);
6817#ifdef DEBUG_DPC_THREAD_WATCHDOG
6818 if (bus->dhd->dhd_bug_on) {
6819 DHD_INFO(("%s: resched = %d ctrl_frame_stat = %d intstatus 0x%08x"
6820 " ipend = %d pktq_mlen = %d is_resched_by_readframe = %d \n",
6821 __FUNCTION__, resched, bus->ctrl_frame_stat,
6822 bus->intstatus, bus->ipend,
6823 pktq_mlen(&bus->txq, ~bus->flowcontrol), is_resched_by_readframe));
6824
6825 bus->dhd->dhd_bug_on = FALSE;
6826 }
6827#endif /* DEBUG_DPC_THREAD_WATCHDOG */
6828
6829 DHD_LINUX_GENERAL_LOCK(bus->dhd, flags);
6830 DHD_BUS_BUSY_CLEAR_IN_DPC(bus->dhd);
6831 dhd_os_busbusy_wake(bus->dhd);
6832 DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
6833
6834 return resched;
6835}
6836
6837bool
6838dhd_bus_dpc(struct dhd_bus *bus)
6839{
6840 bool resched;
6841
6842 /* Call the DPC directly. */
6843 DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__));
6844 resched = dhdsdio_dpc(bus);
6845
6846 return resched;
6847}
6848
6849void
6850dhdsdio_isr(void *arg)
6851{
6852 dhd_bus_t *bus = (dhd_bus_t*)arg;
6853 bcmsdh_info_t *sdh;
6854
6855 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
6856
6857 if (!bus) {
6858 DHD_ERROR(("%s : bus is null pointer , exit \n", __FUNCTION__));
6859 return;
6860 }
6861 sdh = bus->sdh;
6862
6863 if (bus->dhd->busstate == DHD_BUS_DOWN) {
6864 DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__));
6865 return;
6866 }
6867
6868 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
6869
6870 /* Count the interrupt call */
6871 bus->intrcount++;
6872 bus->ipend = TRUE;
6873
6874 /* Shouldn't get this interrupt if we're sleeping? */
6875 if (!SLPAUTO_ENAB(bus)) {
6876 if (bus->sleeping) {
6877 DHD_ERROR(("INTERRUPT WHILE SLEEPING??\n"));
6878 return;
6879 } else if (!KSO_ENAB(bus)) {
6880 DHD_ERROR(("ISR in devsleep 1\n"));
6881 }
6882 }
6883
6884 /* Disable additional interrupts (is this needed now)? */
6885 if (bus->intr) {
6886 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
6887 } else {
6888 DHD_ERROR(("dhdsdio_isr() w/o interrupt configured!\n"));
6889 }
6890
6891#ifdef BCMSPI_ANDROID
6892 bcmsdh_oob_intr_set(bus->sdh, FALSE);
6893#endif /* BCMSPI_ANDROID */
6894 bcmsdh_intr_disable(sdh);
6895 bus->intdis = TRUE;
6896
6897#if defined(SDIO_ISR_THREAD)
6898 DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__));
6899 DHD_OS_WAKE_LOCK(bus->dhd);
6900 dhdsdio_dpc(bus);
6901 DHD_OS_WAKE_UNLOCK(bus->dhd);
6902#else
6903 bus->dpc_sched = TRUE;
6904 dhd_sched_dpc(bus->dhd);
6905#endif /* defined(SDIO_ISR_THREAD) */
6906
6907}
6908
6909#ifdef SDTEST
6910static void
6911dhdsdio_pktgen_init(dhd_bus_t *bus)
6912{
6913 /* Default to specified length, or full range */
6914 if (dhd_pktgen_len) {
6915 bus->pktgen_maxlen = MIN(dhd_pktgen_len, MAX_PKTGEN_LEN);
6916 bus->pktgen_minlen = bus->pktgen_maxlen;
6917 } else {
6918 bus->pktgen_maxlen = MAX_PKTGEN_LEN;
6919 bus->pktgen_minlen = 0;
6920 }
6921 bus->pktgen_len = (uint16)bus->pktgen_minlen;
6922
6923 /* Default to per-watchdog burst with 10s print time */
6924 bus->pktgen_freq = 1;
6925 bus->pktgen_print = dhd_watchdog_ms ? (10000 / dhd_watchdog_ms) : 0;
6926 bus->pktgen_count = (dhd_pktgen * dhd_watchdog_ms + 999) / 1000;
6927
6928 /* Default to echo mode */
6929 bus->pktgen_mode = DHD_PKTGEN_ECHO;
6930 bus->pktgen_stop = 1;
6931}
6932
6933static void
6934dhdsdio_pktgen(dhd_bus_t *bus)
6935{
6936 void *pkt;
6937 uint8 *data;
6938 uint pktcount;
6939 uint fillbyte;
6940 osl_t *osh = bus->dhd->osh;
6941 uint16 len;
6942 ulong time_lapse;
6943 uint sent_pkts;
6944 uint rcvd_pkts;
6945
6946 /* Display current count if appropriate */
6947 if (bus->pktgen_print && (++bus->pktgen_ptick >= bus->pktgen_print)) {
6948 bus->pktgen_ptick = 0;
6949 printf("%s: send attempts %d, rcvd %d, errors %d\n",
6950 __FUNCTION__, bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail);
6951
6952 /* Print throughput stats only for constant length packet runs */
6953 if (bus->pktgen_minlen == bus->pktgen_maxlen) {
6954 time_lapse = jiffies - bus->pktgen_prev_time;
6955 bus->pktgen_prev_time = jiffies;
6956 sent_pkts = bus->pktgen_sent - bus->pktgen_prev_sent;
6957 bus->pktgen_prev_sent = bus->pktgen_sent;
6958 rcvd_pkts = bus->pktgen_rcvd - bus->pktgen_prev_rcvd;
6959 bus->pktgen_prev_rcvd = bus->pktgen_rcvd;
6960
6961 printf("%s: Tx Throughput %d kbps, Rx Throughput %d kbps\n",
6962 __FUNCTION__,
6963 (sent_pkts * bus->pktgen_len / jiffies_to_msecs(time_lapse)) * 8,
6964 (rcvd_pkts * bus->pktgen_len / jiffies_to_msecs(time_lapse)) * 8);
6965 }
6966 }
6967
6968 /* For recv mode, just make sure dongle has started sending */
6969 if (bus->pktgen_mode == DHD_PKTGEN_RECV) {
6970 if (bus->pktgen_rcv_state == PKTGEN_RCV_IDLE) {
6971 bus->pktgen_rcv_state = PKTGEN_RCV_ONGOING;
6972 dhdsdio_sdtest_set(bus, bus->pktgen_total);
6973 }
6974 return;
6975 }
6976
6977 /* Otherwise, generate or request the specified number of packets */
6978 for (pktcount = 0; pktcount < bus->pktgen_count; pktcount++) {
6979 /* Stop if total has been reached */
6980 if (bus->pktgen_total && (bus->pktgen_sent >= bus->pktgen_total)) {
6981 bus->pktgen_count = 0;
6982 break;
6983 }
6984
6985 /* Allocate an appropriate-sized packet */
6986 if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) {
6987 len = SDPCM_TEST_PKT_CNT_FLD_LEN;
6988 } else {
6989 len = bus->pktgen_len;
6990 }
6991 if (!(pkt = PKTGET(osh, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN),
6992 TRUE))) {;
6993 DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__));
6994 break;
6995 }
6996 PKTALIGN(osh, pkt, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN), DHD_SDALIGN);
6997 data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
6998
6999 /* Write test header cmd and extra based on mode */
7000 switch (bus->pktgen_mode) {
7001 case DHD_PKTGEN_ECHO:
7002 *data++ = SDPCM_TEST_ECHOREQ;
7003 *data++ = (uint8)bus->pktgen_sent;
7004 break;
7005
7006 case DHD_PKTGEN_SEND:
7007 *data++ = SDPCM_TEST_DISCARD;
7008 *data++ = (uint8)bus->pktgen_sent;
7009 break;
7010
7011 case DHD_PKTGEN_RXBURST:
7012 *data++ = SDPCM_TEST_BURST;
7013 *data++ = (uint8)bus->pktgen_count; /* Just for backward compatability */
7014 break;
7015
7016 default:
7017 DHD_ERROR(("Unrecognized pktgen mode %d\n", bus->pktgen_mode));
7018 PKTFREE(osh, pkt, TRUE);
7019 bus->pktgen_count = 0;
7020 return;
7021 }
7022
7023 /* Write test header length field */
7024 *data++ = (bus->pktgen_len >> 0);
7025 *data++ = (bus->pktgen_len >> 8);
7026
7027 /* Write frame count in a 4 byte field adjucent to SDPCM test header for
7028 * burst mode
7029 */
7030 if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) {
7031 *data++ = (uint8)(bus->pktgen_count >> 0);
7032 *data++ = (uint8)(bus->pktgen_count >> 8);
7033 *data++ = (uint8)(bus->pktgen_count >> 16);
7034 *data++ = (uint8)(bus->pktgen_count >> 24);
7035 } else {
7036
7037 /* Then fill in the remainder -- N/A for burst */
7038 for (fillbyte = 0; fillbyte < len; fillbyte++)
7039 *data++ = SDPCM_TEST_FILL(fillbyte, (uint8)bus->pktgen_sent);
7040 }
7041
7042#ifdef DHD_DEBUG
7043 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
7044 data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
7045 prhex("dhdsdio_pktgen: Tx Data", data, PKTLEN(osh, pkt) - SDPCM_HDRLEN);
7046 }
7047#endif // endif
7048
7049 /* Send it */
7050 if (dhdsdio_txpkt(bus, SDPCM_TEST_CHANNEL, &pkt, 1, TRUE) != BCME_OK) {
7051 bus->pktgen_fail++;
7052 if (bus->pktgen_stop && bus->pktgen_stop == bus->pktgen_fail)
7053 bus->pktgen_count = 0;
7054 }
7055 bus->pktgen_sent++;
7056
7057 /* Bump length if not fixed, wrap at max */
7058 if (++bus->pktgen_len > bus->pktgen_maxlen)
7059 bus->pktgen_len = (uint16)bus->pktgen_minlen;
7060
7061 /* Special case for burst mode: just send one request! */
7062 if (bus->pktgen_mode == DHD_PKTGEN_RXBURST)
7063 break;
7064 }
7065}
7066
7067static void
7068dhdsdio_sdtest_set(dhd_bus_t *bus, uint count)
7069{
7070 void *pkt;
7071 uint8 *data;
7072 osl_t *osh = bus->dhd->osh;
7073
7074 /* Allocate the packet */
7075 if (!(pkt = PKTGET(osh, SDPCM_HDRLEN + SDPCM_TEST_HDRLEN +
7076 SDPCM_TEST_PKT_CNT_FLD_LEN + DHD_SDALIGN, TRUE))) {
7077 DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__));
7078 return;
7079 }
7080 PKTALIGN(osh, pkt, (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN +
7081 SDPCM_TEST_PKT_CNT_FLD_LEN), DHD_SDALIGN);
7082 data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
7083
7084 /* Fill in the test header */
7085 *data++ = SDPCM_TEST_SEND;
7086 *data++ = (count > 0)?TRUE:FALSE;
7087 *data++ = (bus->pktgen_maxlen >> 0);
7088 *data++ = (bus->pktgen_maxlen >> 8);
7089 *data++ = (uint8)(count >> 0);
7090 *data++ = (uint8)(count >> 8);
7091 *data++ = (uint8)(count >> 16);
7092 *data++ = (uint8)(count >> 24);
7093
7094 /* Send it */
7095 if (dhdsdio_txpkt(bus, SDPCM_TEST_CHANNEL, &pkt, 1, TRUE) != BCME_OK)
7096 bus->pktgen_fail++;
7097}
7098
7099static void
7100dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq)
7101{
7102 osl_t *osh = bus->dhd->osh;
7103 uint8 *data;
7104 uint pktlen;
7105
7106 uint8 cmd;
7107 uint8 extra;
7108 uint16 len;
7109 uint16 offset;
7110
7111 /* Check for min length */
7112 if ((pktlen = PKTLEN(osh, pkt)) < SDPCM_TEST_HDRLEN) {
7113 DHD_ERROR(("dhdsdio_restrcv: toss runt frame, pktlen %d\n", pktlen));
7114 PKTFREE(osh, pkt, FALSE);
7115 return;
7116 }
7117
7118 /* Extract header fields */
7119 data = PKTDATA(osh, pkt);
7120 cmd = *data++;
7121 extra = *data++;
7122 len = *data++; len += *data++ << 8;
7123 DHD_TRACE(("%s:cmd:%d, xtra:%d,len:%d\n", __FUNCTION__, cmd, extra, len));
7124 /* Check length for relevant commands */
7125 if (cmd == SDPCM_TEST_DISCARD || cmd == SDPCM_TEST_ECHOREQ || cmd == SDPCM_TEST_ECHORSP) {
7126 if (pktlen != len + SDPCM_TEST_HDRLEN) {
7127 DHD_ERROR(("dhdsdio_testrcv: frame length mismatch, pktlen %d seq %d"
7128 " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len));
7129 PKTFREE(osh, pkt, FALSE);
7130 return;
7131 }
7132 }
7133
7134 /* Process as per command */
7135 switch (cmd) {
7136 case SDPCM_TEST_ECHOREQ:
7137 /* Rx->Tx turnaround ok (even on NDIS w/current implementation) */
7138 *(uint8 *)(PKTDATA(osh, pkt)) = SDPCM_TEST_ECHORSP;
7139 if (dhdsdio_txpkt(bus, SDPCM_TEST_CHANNEL, &pkt, 1, TRUE) == BCME_OK) {
7140 bus->pktgen_sent++;
7141 } else {
7142 bus->pktgen_fail++;
7143 PKTFREE(osh, pkt, FALSE);
7144 }
7145 bus->pktgen_rcvd++;
7146 break;
7147
7148 case SDPCM_TEST_ECHORSP:
7149 if (bus->ext_loop) {
7150 PKTFREE(osh, pkt, FALSE);
7151 bus->pktgen_rcvd++;
7152 break;
7153 }
7154
7155 for (offset = 0; offset < len; offset++, data++) {
7156 if (*data != SDPCM_TEST_FILL(offset, extra)) {
7157 DHD_ERROR(("dhdsdio_testrcv: echo data mismatch: "
7158 "offset %d (len %d) expect 0x%02x rcvd 0x%02x\n",
7159 offset, len, SDPCM_TEST_FILL(offset, extra), *data));
7160 break;
7161 }
7162 }
7163 PKTFREE(osh, pkt, FALSE);
7164 bus->pktgen_rcvd++;
7165 break;
7166
7167 case SDPCM_TEST_DISCARD:
7168 {
7169 int i = 0;
7170 uint8 *prn = data;
7171 uint8 testval = extra;
7172 for (i = 0; i < len; i++) {
7173 if (*prn != testval) {
7174 DHD_ERROR(("DIErr@Pkt#:%d,Ix:%d, expected:0x%x, got:0x%x\n",
7175 i, bus->pktgen_rcvd_rcvsession, testval, *prn));
7176 prn++; testval++;
7177 }
7178 }
7179 }
7180 PKTFREE(osh, pkt, FALSE);
7181 bus->pktgen_rcvd++;
7182 break;
7183
7184 case SDPCM_TEST_BURST:
7185 case SDPCM_TEST_SEND:
7186 default:
7187 DHD_INFO(("dhdsdio_testrcv: unsupported or unknown command, pktlen %d seq %d"
7188 " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len));
7189 PKTFREE(osh, pkt, FALSE);
7190 break;
7191 }
7192
7193 /* For recv mode, stop at limit (and tell dongle to stop sending) */
7194 if (bus->pktgen_mode == DHD_PKTGEN_RECV) {
7195 if (bus->pktgen_rcv_state != PKTGEN_RCV_IDLE) {
7196 bus->pktgen_rcvd_rcvsession++;
7197
7198 if (bus->pktgen_total &&
7199 (bus->pktgen_rcvd_rcvsession >= bus->pktgen_total)) {
7200 bus->pktgen_count = 0;
7201 DHD_ERROR(("Pktgen:rcv test complete!\n"));
7202 bus->pktgen_rcv_state = PKTGEN_RCV_IDLE;
7203 dhdsdio_sdtest_set(bus, FALSE);
7204 bus->pktgen_rcvd_rcvsession = 0;
7205 }
7206 }
7207 }
7208}
7209#endif /* SDTEST */
7210
7211int dhd_bus_oob_intr_register(dhd_pub_t *dhdp)
7212{
7213 int err = 0;
7214
7215#if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
7216 err = bcmsdh_oob_intr_register(dhdp->bus->sdh, dhdsdio_isr, dhdp->bus);
7217#endif // endif
7218 return err;
7219}
7220
7221void dhd_bus_oob_intr_unregister(dhd_pub_t *dhdp)
7222{
7223#if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
7224 bcmsdh_oob_intr_unregister(dhdp->bus->sdh);
7225#endif // endif
7226}
7227
7228void dhd_bus_oob_intr_set(dhd_pub_t *dhdp, bool enable)
7229{
7230#if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
7231 bcmsdh_oob_intr_set(dhdp->bus->sdh, enable);
7232#endif // endif
7233}
7234
7235void dhd_bus_dev_pm_stay_awake(dhd_pub_t *dhdpub)
7236{
7237 bcmsdh_dev_pm_stay_awake(dhdpub->bus->sdh);
7238}
7239
7240void dhd_bus_dev_pm_relax(dhd_pub_t *dhdpub)
7241{
7242 bcmsdh_dev_relax(dhdpub->bus->sdh);
7243}
7244
7245bool dhd_bus_dev_pm_enabled(dhd_pub_t *dhdpub)
7246{
7247 bool enabled = FALSE;
7248
7249 enabled = bcmsdh_dev_pm_enabled(dhdpub->bus->sdh);
7250 return enabled;
7251}
7252
7253extern bool
7254dhd_bus_watchdog(dhd_pub_t *dhdp)
7255{
7256 dhd_bus_t *bus;
7257 unsigned long flags;
7258
7259 DHD_TIMER(("%s: Enter\n", __FUNCTION__));
7260
7261 bus = dhdp->bus;
7262
7263 if (bus->dhd->dongle_reset)
7264 return FALSE;
7265
7266 if (bus->dhd->hang_was_sent) {
7267 dhd_os_wd_timer(bus->dhd, 0);
7268 return FALSE;
7269 }
7270
7271 /* Ignore the timer if simulating bus down */
7272 if (!SLPAUTO_ENAB(bus) && bus->sleeping)
7273 return FALSE;
7274
7275 DHD_LINUX_GENERAL_LOCK(dhdp, flags);
7276 if (DHD_BUS_CHECK_DOWN_OR_DOWN_IN_PROGRESS(dhdp) ||
7277 DHD_BUS_CHECK_SUSPEND_OR_SUSPEND_IN_PROGRESS(dhdp)) {
7278 DHD_LINUX_GENERAL_UNLOCK(dhdp, flags);
7279 return FALSE;
7280 }
7281 DHD_BUS_BUSY_SET_IN_WD(dhdp);
7282 DHD_LINUX_GENERAL_UNLOCK(dhdp, flags);
7283
7284 dhd_os_sdlock(bus->dhd);
7285
7286 /* Poll period: check device if appropriate. */
7287 if (!SLPAUTO_ENAB(bus) && (bus->poll && (++bus->polltick >= bus->pollrate))) {
7288 uint32 intstatus = 0;
7289
7290 /* Reset poll tick */
7291 bus->polltick = 0;
7292
7293 /* Check device if no interrupts */
7294 if (!bus->intr || (bus->intrcount == bus->lastintrs)) {
7295
7296#ifndef BCMSPI
7297 if (!bus->dpc_sched) {
7298 uint8 devpend;
7299 devpend = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0,
7300 SDIOD_CCCR_INTPEND, NULL);
7301 intstatus = devpend & (INTR_STATUS_FUNC1 | INTR_STATUS_FUNC2);
7302 }
7303#else
7304 if (!bus->dpc_sched) {
7305 uint32 devpend;
7306 devpend = bcmsdh_cfg_read_word(bus->sdh, SDIO_FUNC_0,
7307 SPID_STATUS_REG, NULL);
7308 intstatus = devpend & STATUS_F2_PKT_AVAILABLE;
7309 }
7310#endif /* !BCMSPI */
7311
7312 /* If there is something, make like the ISR and schedule the DPC */
7313 if (intstatus) {
7314 bus->pollcnt++;
7315 bus->ipend = TRUE;
7316 if (bus->intr) {
7317 bcmsdh_intr_disable(bus->sdh);
7318 }
7319 bus->dpc_sched = TRUE;
7320 dhd_sched_dpc(bus->dhd);
7321 }
7322 }
7323
7324 /* Update interrupt tracking */
7325 bus->lastintrs = bus->intrcount;
7326 }
7327
7328#ifdef DHD_DEBUG
7329 /* Poll for console output periodically */
7330 if (dhdp->busstate == DHD_BUS_DATA && dhdp->dhd_console_ms != 0) {
7331 bus->console.count += dhd_watchdog_ms;
7332 if (bus->console.count >= dhdp->dhd_console_ms) {
7333 bus->console.count -= dhdp->dhd_console_ms;
7334 /* Make sure backplane clock is on */
7335 if (SLPAUTO_ENAB(bus))
7336 dhdsdio_bussleep(bus, FALSE);
7337 else
7338 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
7339 if (dhdsdio_readconsole(bus) < 0)
7340 dhdp->dhd_console_ms = 0; /* On error, stop trying */
7341 }
7342 }
7343#endif /* DHD_DEBUG */
7344
7345#ifdef SDTEST
7346 /* Generate packets if configured */
7347 if (bus->pktgen_count && (++bus->pktgen_tick >= bus->pktgen_freq)) {
7348 /* Make sure backplane clock is on */
7349 if (SLPAUTO_ENAB(bus))
7350 dhdsdio_bussleep(bus, FALSE);
7351 else
7352 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
7353 bus->pktgen_tick = 0;
7354 dhdsdio_pktgen(bus);
7355 }
7356#endif // endif
7357
7358 /* On idle timeout clear activity flag and/or turn off clock */
7359#ifdef DHD_USE_IDLECOUNT
7360 if (bus->activity)
7361 bus->activity = FALSE;
7362 else {
7363 bus->idlecount++;
7364
7365 /*
7366 * If the condition to switch off the clock is reached And if
7367 * BT is inactive (in case of BT_OVER_SDIO build) turn off clk.
7368 *
7369 * Consider the following case, DHD is configured with
7370 * 1) idletime == DHD_IDLE_IMMEDIATE
7371 * 2) BT is the last user of the clock
7372 * We cannot disable the clock from __dhdsdio_clk_disable
7373 * since WLAN might be using it. If WLAN is active then
7374 * from the respective function/context after doing the job
7375 * the clk is turned off.
7376 * But if WLAN is actually inactive then the watchdog should
7377 * disable the clock. So the condition check below should be
7378 * bus->idletime != 0 instead of idletime == 0
7379 */
7380 if ((bus->idletime != 0) && (bus->idlecount >= bus->idletime) &&
7381 NO_OTHER_ACTIVE_BUS_USER(bus)) {
7382 DHD_TIMER(("%s: DHD Idle state!!\n", __FUNCTION__));
7383 if (SLPAUTO_ENAB(bus)) {
7384 if (dhdsdio_bussleep(bus, TRUE) != BCME_BUSY)
7385 dhd_os_wd_timer(bus->dhd, 0);
7386 } else
7387 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
7388
7389 bus->idlecount = 0;
7390 }
7391 }
7392#else
7393 if ((bus->idletime != 0) && (bus->clkstate == CLK_AVAIL) &&
7394 NO_OTHER_ACTIVE_BUS_USER(bus)) {
7395 if (++bus->idlecount >= bus->idletime) {
7396 bus->idlecount = 0;
7397 if (bus->activity) {
7398 bus->activity = FALSE;
7399 if (SLPAUTO_ENAB(bus)) {
7400 if (!bus->readframes)
7401 dhdsdio_bussleep(bus, TRUE);
7402 else
7403 bus->reqbussleep = TRUE;
7404 } else {
7405 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
7406 }
7407 }
7408 }
7409 }
7410#endif /* DHD_USE_IDLECOUNT */
7411
7412 dhd_os_sdunlock(bus->dhd);
7413
7414 DHD_LINUX_GENERAL_LOCK(dhdp, flags);
7415 DHD_BUS_BUSY_CLEAR_IN_WD(dhdp);
7416 dhd_os_busbusy_wake(dhdp);
7417 DHD_LINUX_GENERAL_UNLOCK(dhdp, flags);
7418
7419 return bus->ipend;
7420}
7421
7422extern int
7423dhd_bus_console_in(dhd_pub_t *dhdp, uchar *msg, uint msglen)
7424{
7425 dhd_bus_t *bus = dhdp->bus;
7426 uint32 addr, val;
7427 int rv;
7428 void *pkt;
7429
7430 /* Address could be zero if CONSOLE := 0 in dongle Makefile */
7431 if (bus->console_addr == 0)
7432 return BCME_UNSUPPORTED;
7433
7434 /* Exclusive bus access */
7435 dhd_os_sdlock(bus->dhd);
7436
7437 /* Don't allow input if dongle is in reset */
7438 if (bus->dhd->dongle_reset) {
7439 dhd_os_sdunlock(bus->dhd);
7440 return BCME_NOTREADY;
7441 }
7442
7443 /* Request clock to allow SDIO accesses */
7444 BUS_WAKE(bus);
7445 /* No pend allowed since txpkt is called later, ht clk has to be on */
7446 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
7447
7448 /* Zero cbuf_index */
7449 addr = bus->console_addr + OFFSETOF(hnd_cons_t, cbuf_idx);
7450 val = htol32(0);
7451 if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0)
7452 goto done;
7453
7454 /* Write message into cbuf */
7455 addr = bus->console_addr + OFFSETOF(hnd_cons_t, cbuf);
7456 if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)msg, msglen)) < 0)
7457 goto done;
7458
7459 /* Write length into vcons_in */
7460 addr = bus->console_addr + OFFSETOF(hnd_cons_t, vcons_in);
7461 val = htol32(msglen);
7462 if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0)
7463 goto done;
7464
7465 /* Bump dongle by sending an empty packet on the event channel.
7466 * sdpcm_sendup (RX) checks for virtual console input.
7467 */
7468 if ((pkt = PKTGET(bus->dhd->osh, 4 + SDPCM_RESERVE, TRUE)) != NULL)
7469 rv = dhdsdio_txpkt(bus, SDPCM_EVENT_CHANNEL, &pkt, 1, TRUE);
7470
7471done:
7472 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched &&
7473 NO_OTHER_ACTIVE_BUS_USER(bus)) {
7474 bus->activity = FALSE;
7475 dhdsdio_bussleep(bus, TRUE);
7476 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
7477 }
7478
7479 dhd_os_sdunlock(bus->dhd);
7480
7481 return rv;
7482}
7483
7484#if defined(DHD_DEBUG) && !defined(BCMSDIOLITE)
7485static void
7486dhd_dump_cis(uint fn, uint8 *cis)
7487{
7488 uint byte, tag, tdata;
7489 DHD_INFO(("Function %d CIS:\n", fn));
7490
7491 for (tdata = byte = 0; byte < SBSDIO_CIS_SIZE_LIMIT; byte++) {
7492 if ((byte % 16) == 0)
7493 DHD_INFO((" "));
7494 DHD_INFO(("%02x ", cis[byte]));
7495 if ((byte % 16) == 15)
7496 DHD_INFO(("\n"));
7497 if (!tdata--) {
7498 tag = cis[byte];
7499 if (tag == 0xff)
7500 break;
7501 else if (!tag)
7502 tdata = 0;
7503 else if ((byte + 1) < SBSDIO_CIS_SIZE_LIMIT)
7504 tdata = cis[byte + 1] + 1;
7505 else
7506 DHD_INFO(("]"));
7507 }
7508 }
7509 if ((byte % 16) != 15)
7510 DHD_INFO(("\n"));
7511}
7512#endif /* DHD_DEBUG */
7513
7514static bool
7515dhdsdio_chipmatch(uint16 chipid)
7516{
7517 if (chipid == BCM4335_CHIP_ID)
7518 return TRUE;
7519 if (chipid == BCM4339_CHIP_ID)
7520 return TRUE;
7521 if (BCM4345_CHIP(chipid))
7522 return TRUE;
7523 if (chipid == BCM4350_CHIP_ID)
7524 return TRUE;
7525 if (chipid == BCM4354_CHIP_ID)
7526 return TRUE;
7527 if (chipid == BCM4358_CHIP_ID)
7528 return TRUE;
7529 if (chipid == BCM43430_CHIP_ID)
7530 return TRUE;
7531 if (chipid == BCM43018_CHIP_ID)
7532 return TRUE;
7533 if (BCM4349_CHIP(chipid))
7534 return TRUE;
7535 if (chipid == BCM4364_CHIP_ID)
7536 return TRUE;
7537
7538 if (chipid == BCM43012_CHIP_ID)
7539 return TRUE;
7540
7541 if (chipid == BCM43014_CHIP_ID)
7542 return TRUE;
7543
7544 return FALSE;
7545}
7546
7547static void *
7548dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot,
7549 uint16 func, uint bustype, void *regsva, osl_t * osh, void *sdh)
7550{
7551 int ret;
7552 dhd_bus_t *bus;
7553
7554#if defined(MULTIPLE_SUPPLICANT)
7555#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
7556 if (mutex_is_locked(&_dhd_sdio_mutex_lock_) == 0) {
7557 DHD_ERROR(("%s : no mutex held. set lock\n", __FUNCTION__));
7558 } else {
7559 DHD_ERROR(("%s : mutex is locked!. wait for unlocking\n", __FUNCTION__));
7560 }
7561 mutex_lock(&_dhd_sdio_mutex_lock_);
7562#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
7563#endif // endif
7564
7565 /* Init global variables at run-time, not as part of the declaration.
7566 * This is required to support init/de-init of the driver. Initialization
7567 * of globals as part of the declaration results in non-deterministic
7568 * behavior since the value of the globals may be different on the
7569 * first time that the driver is initialized vs subsequent initializations.
7570 */
7571 dhd_txbound = DHD_TXBOUND;
7572 dhd_rxbound = DHD_RXBOUND;
7573#ifdef BCMSPI
7574 dhd_alignctl = FALSE;
7575#else
7576 dhd_alignctl = TRUE;
7577#endif /* BCMSPI */
7578 sd1idle = TRUE;
7579 dhd_readahead = TRUE;
7580 retrydata = FALSE;
7581
7582#ifdef DISABLE_FLOW_CONTROL
7583 dhd_doflow = FALSE;
7584#endif /* DISABLE_FLOW_CONTROL */
7585 dhd_dongle_ramsize = 0;
7586 dhd_txminmax = DHD_TXMINMAX;
7587
7588#ifdef BCMSPI
7589 forcealign = FALSE;
7590#else
7591 forcealign = TRUE;
7592#endif /* !BCMSPI */
7593
7594 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7595 DHD_INFO(("%s: venid 0x%04x devid 0x%04x\n", __FUNCTION__, venid, devid));
7596
7597 /* We make assumptions about address window mappings */
7598 ASSERT((uintptr)regsva == si_enum_base(devid));
7599
7600 /* BCMSDH passes venid and devid based on CIS parsing -- but low-power start
7601 * means early parse could fail, so here we should get either an ID
7602 * we recognize OR (-1) indicating we must request power first.
7603 */
7604 /* Check the Vendor ID */
7605 switch (venid) {
7606 case 0x0000:
7607 case VENDOR_BROADCOM:
7608 break;
7609 default:
7610 DHD_ERROR(("%s: unknown vendor: 0x%04x\n",
7611 __FUNCTION__, venid));
7612 goto forcereturn;
7613 }
7614
7615 /* Check the Device ID and make sure it's one that we support */
7616 switch (devid) {
7617 case 0:
7618 DHD_INFO(("%s: allow device id 0, will check chip internals\n",
7619 __FUNCTION__));
7620 break;
7621
7622 default:
7623 DHD_ERROR(("%s: skipping 0x%04x/0x%04x, not a dongle\n",
7624 __FUNCTION__, venid, devid));
7625 goto forcereturn;
7626 }
7627
7628 if (osh == NULL) {
7629 DHD_ERROR(("%s: osh is NULL!\n", __FUNCTION__));
7630 goto forcereturn;
7631 }
7632
7633 /* Allocate private bus interface state */
7634 if (!(bus = MALLOC(osh, sizeof(dhd_bus_t)))) {
7635 DHD_ERROR(("%s: MALLOC of dhd_bus_t failed\n", __FUNCTION__));
7636 goto fail;
7637 }
7638 bzero(bus, sizeof(dhd_bus_t));
7639 bus->sdh = sdh;
7640 bus->cl_devid = (uint16)devid;
7641 bus->bus = DHD_BUS;
7642 bus->bus_num = bus_no;
7643 bus->slot_num = slot;
7644 bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1;
7645 bus->usebufpool = FALSE; /* Use bufpool if allocated, else use locally malloced rxbuf */
7646#ifdef BT_OVER_SDIO
7647 bus->bt_use_count = 0;
7648#endif // endif
7649
7650#if defined(SUPPORT_P2P_GO_PS)
7651 init_waitqueue_head(&bus->bus_sleep);
7652#endif /* LINUX && SUPPORT_P2P_GO_PS */
7653
7654 /* attempt to attach to the dongle */
7655 if (!(dhdsdio_probe_attach(bus, osh, sdh, regsva, devid))) {
7656 DHD_ERROR(("%s: dhdsdio_probe_attach failed\n", __FUNCTION__));
7657 goto fail;
7658 }
7659
7660 /* Attach to the dhd/OS/network interface */
7661 if (!(bus->dhd = dhd_attach(osh, bus, SDPCM_RESERVE))) {
7662 DHD_ERROR(("%s: dhd_attach failed\n", __FUNCTION__));
7663 goto fail;
7664 }
7665
7666 /* Allocate buffers */
7667 if (!(dhdsdio_probe_malloc(bus, osh, sdh))) {
7668 DHD_ERROR(("%s: dhdsdio_probe_malloc failed\n", __FUNCTION__));
7669 goto fail;
7670 }
7671
7672 if (!(dhdsdio_probe_init(bus, osh, sdh))) {
7673 DHD_ERROR(("%s: dhdsdio_probe_init failed\n", __FUNCTION__));
7674 goto fail;
7675 }
7676
7677 if (bus->intr) {
7678 /* Register interrupt callback, but mask it (not operational yet). */
7679 DHD_INTR(("%s: disable SDIO interrupts (not interested yet)\n", __FUNCTION__));
7680 bcmsdh_intr_disable(sdh);
7681 if ((ret = bcmsdh_intr_reg(sdh, dhdsdio_isr, bus)) != 0) {
7682 DHD_ERROR(("%s: FAILED: bcmsdh_intr_reg returned %d\n",
7683 __FUNCTION__, ret));
7684 goto fail;
7685 }
7686 DHD_INTR(("%s: registered SDIO interrupt function ok\n", __FUNCTION__));
7687 } else {
7688 DHD_INFO(("%s: SDIO interrupt function is NOT registered due to polling mode\n",
7689 __FUNCTION__));
7690 }
7691
7692 DHD_INFO(("%s: completed!!\n", __FUNCTION__));
7693
7694 /* if firmware path present try to download and bring up bus */
7695 bus->dhd->hang_report = TRUE;
7696 if (dhd_download_fw_on_driverload) {
7697 if ((ret = dhd_bus_start(bus->dhd)) != 0) {
7698 DHD_ERROR(("%s: dhd_bus_start failed\n", __FUNCTION__));
7699 goto fail;
7700 }
7701 }
7702 else {
7703 /* Set random MAC address during boot time */
7704 get_random_bytes(&bus->dhd->mac.octet[3], 3);
7705 /* Adding BRCM OUI */
7706 bus->dhd->mac.octet[0] = 0;
7707 bus->dhd->mac.octet[1] = 0x90;
7708 bus->dhd->mac.octet[2] = 0x4C;
7709 }
7710#if defined(BT_OVER_SDIO)
7711 /* At this point Regulators are turned on and iconditionaly sdio bus is started
7712 * based upon dhd_download_fw_on_driverload check, so
7713 * increase the bus user count, this count will only be disabled inside
7714 * dhd_register_if() function if flag dhd_download_fw_on_driverload is set to false,
7715 * i.e FW download during insmod is not needed, otherwise it will not be decremented
7716 * so that WALN will always hold the bus untill rmmod is done.
7717 */
7718 dhdsdio_bus_usr_cnt_inc(bus->dhd);
7719#endif /* BT_OVER_SDIO */
7720
7721 /* Ok, have the per-port tell the stack we're open for business */
7722 if (dhd_attach_net(bus->dhd, TRUE) != 0)
7723 {
7724 DHD_ERROR(("%s: Net attach failed!!\n", __FUNCTION__));
7725 goto fail;
7726 }
7727
7728#ifdef BCMHOST_XTAL_PU_TIME_MOD
7729 bcmsdh_reg_write(bus->sdh, 0x18000620, 2, 11);
7730 bcmsdh_reg_write(bus->sdh, 0x18000628, 4, 0x00F80001);
7731#endif /* BCMHOST_XTAL_PU_TIME_MOD */
7732
7733#if defined(MULTIPLE_SUPPLICANT)
7734#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
7735 mutex_unlock(&_dhd_sdio_mutex_lock_);
7736 DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__));
7737#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
7738#endif // endif
7739
7740 return bus;
7741
7742fail:
7743 dhdsdio_release(bus, osh);
7744
7745forcereturn:
7746#if defined(MULTIPLE_SUPPLICANT)
7747#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
7748 mutex_unlock(&_dhd_sdio_mutex_lock_);
7749 DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__));
7750#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
7751#endif // endif
7752
7753 return NULL;
7754}
7755
7756static bool
7757dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva,
7758 uint16 devid)
7759{
7760#ifndef BCMSPI
7761 uint8 clkctl = 0;
7762#endif /* !BCMSPI */
7763 uint fn, numfn;
5a068558 7764 uint8 *cis = NULL;
1cac41cb
MB
7765 int32 value;
7766 int err = 0;
7767
7768 BCM_REFERENCE(value);
7769 bus->alp_only = TRUE;
7770 bus->sih = NULL;
7771
7772 /* Return the window to backplane enumeration space for core access */
7773 if (dhdsdio_set_siaddr_window(bus, si_enum_base(devid))) {
7774 DHD_ERROR(("%s: FAILED to return to SI_ENUM_BASE\n", __FUNCTION__));
7775 }
7776
7777#if defined(DHD_DEBUG) && !defined(CUSTOMER_HW4_DEBUG)
7778 DHD_ERROR(("F1 signature read @0x18000000=0x%4x\n",
7779 bcmsdh_reg_read(bus->sdh, si_enum_base(devid), 4)));
7780#endif /* DHD_DEBUG && !CUSTOMER_HW4_DEBUG */
7781
7782#ifndef BCMSPI /* wake-wlan in gSPI will bring up the htavail/alpavail clocks. */
7783
7784 /* Force PLL off until si_attach() programs PLL control regs */
7785
7786 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, DHD_INIT_CLKCTL1, &err);
7787 if (!err)
7788 clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
7789
7790 if (err || ((clkctl & ~SBSDIO_AVBITS) != DHD_INIT_CLKCTL1)) {
7791 DHD_ERROR(("dhdsdio_probe: ChipClkCSR access: err %d wrote 0x%02x read 0x%02x\n",
7792 err, DHD_INIT_CLKCTL1, clkctl));
7793 goto fail;
7794 }
7795
7796#endif /* !BCMSPI */
7797#ifndef BCMSPI
7798 numfn = bcmsdh_query_iofnum(sdh);
7799 ASSERT(numfn <= SDIOD_MAX_IOFUNCS);
7800
7801 /* Make sure ALP is available before trying to read CIS */
7802 SPINWAIT(((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
7803 SBSDIO_FUNC1_CHIPCLKCSR, NULL)),
7804 !SBSDIO_ALPAV(clkctl)), PMU_MAX_TRANSITION_DLY);
7805
7806 /* Now request ALP be put on the bus */
7807 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
7808 DHD_INIT_CLKCTL2, &err);
7809 OSL_DELAY(65);
7810#else
7811 numfn = 0; /* internally func is hardcoded to 1 as gSPI has cis on F1 only */
7812#endif /* !BCMSPI */
7813#ifndef BCMSDIOLITE
5a068558
MB
7814 if (!(cis = MALLOC(osh, SBSDIO_CIS_SIZE_LIMIT))) {
7815 DHD_INFO(("dhdsdio_probe: cis malloc failed\n"));
7816 goto fail;
7817 }
7818 bzero(cis, SBSDIO_CIS_SIZE_LIMIT);
7819
1cac41cb 7820 for (fn = 0; fn <= numfn; fn++) {
5a068558
MB
7821 if (DHD_INFO_ON()) {
7822 if ((err = bcmsdh_cis_read(sdh, fn, cis,
7823 SBSDIO_CIS_SIZE_LIMIT))) {
7824 DHD_INFO(("dhdsdio_probe: fn %d cis read err %d\n",
7825 fn, err));
7826 break;
7827 }
7828#ifdef DHD_DEBUG
7829 dhd_dump_cis(fn, cis);
7830#endif /* DHD_DEBUG */
1cac41cb 7831 }
5a068558
MB
7832 else
7833 {
7834 if (fn > 0) {
7835 if ((err = bcmsdh_cis_read(sdh, fn, cis,
7836 SBSDIO_CIS_TINY_SIZE_LIMIT))) {
7837 DHD_INFO(("dhdsdio_probe: fn %d cis read err %d\n",
7838 fn, err));
7839 break;
7840 }
7841 }
1cac41cb
MB
7842 }
7843
5a068558
MB
7844 /* Reading the F1, F2 and F3 max blocksize values from CIS
7845 * and writing into the F1, F2 and F3 block size registers.
7846 * There is no max block size register value available for F0 in CIS
7847 * register.
7848 * So, setting default value for F0 block size as 32 (which was set earlier
7849 * in iovar). IOVAR takes only one arguement.
7850 * So, we are passing the function number alongwith the value (fn<<16)
7851 */
1cac41cb
MB
7852 if (!fn)
7853 value = F0_BLOCK_SIZE;
7854 else
5a068558 7855 value = (cis[25]<<8) | cis[24] | (fn<<16);
1cac41cb 7856 if (bcmsdh_iovar_op(sdh, "sd_blocksize", NULL, 0, &value,
5a068558 7857 sizeof(value), TRUE) != BCME_OK) {
1cac41cb
MB
7858 bus->blocksize = 0;
7859 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__,
7860 "sd_blocksize"));
7861 }
1cac41cb 7862 }
5a068558 7863 MFREE(osh, cis, SBSDIO_CIS_SIZE_LIMIT);
1cac41cb
MB
7864#else
7865 BCM_REFERENCE(cis);
7866 BCM_REFERENCE(fn);
7867#endif /* DHD_DEBUG */
7868
7869 if (err) {
7870 DHD_ERROR(("dhdsdio_probe: failure reading or parsing CIS\n"));
7871 goto fail;
7872 }
7873 /* si_attach() will provide an SI handle and scan the backplane */
7874 if (!(bus->sih = si_attach((uint)devid, osh, regsva, DHD_BUS, sdh,
7875 &bus->vars, &bus->varsz))) {
7876 DHD_ERROR(("%s: si_attach failed!\n", __FUNCTION__));
7877 goto fail;
7878 }
7879
7880#ifdef DHD_DEBUG
7881 DHD_ERROR(("F1 signature OK, socitype:0x%x chip:0x%4x rev:0x%x pkg:0x%x\n",
7882 bus->sih->socitype, bus->sih->chip, bus->sih->chiprev, bus->sih->chippkg));
7883#endif /* DHD_DEBUG */
7884
7885 bcmsdh_chipinfo(sdh, bus->sih->chip, bus->sih->chiprev);
7886
7887 if (!dhdsdio_chipmatch((uint16)bus->sih->chip)) {
7888 DHD_ERROR(("%s: unsupported chip: 0x%04x\n",
7889 __FUNCTION__, bus->sih->chip));
7890 goto fail;
7891 }
7892
7893 if (bus->sih->buscorerev >= 12)
7894 dhdsdio_clk_kso_init(bus);
7895 else
7896 bus->kso = TRUE;
7897
7898 si_sdiod_drive_strength_init(bus->sih, osh, dhd_sdiod_drive_strength);
7899
7900 /* Get info on the ARM and SOCRAM cores... */
7901 if (!DHD_NOPMU(bus)) {
7902 if ((si_setcore(bus->sih, ARM7S_CORE_ID, 0)) ||
7903 (si_setcore(bus->sih, ARMCM3_CORE_ID, 0)) ||
7904 (si_setcore(bus->sih, ARMCR4_CORE_ID, 0))) {
7905 bus->armrev = si_corerev(bus->sih);
7906 } else {
7907 DHD_ERROR(("%s: failed to find ARM core!\n", __FUNCTION__));
7908 goto fail;
7909 }
7910
7911 if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
7912 if (!(bus->orig_ramsize = si_socram_size(bus->sih))) {
7913 DHD_ERROR(("%s: failed to find SOCRAM memory!\n", __FUNCTION__));
7914 goto fail;
7915 }
7916 } else {
7917 /* cr4 has a different way to find the RAM size from TCM's */
7918 if (!(bus->orig_ramsize = si_tcm_size(bus->sih))) {
7919 DHD_ERROR(("%s: failed to find CR4-TCM memory!\n", __FUNCTION__));
7920 goto fail;
7921 }
7922 /* also populate base address */
7923 switch ((uint16)bus->sih->chip) {
7924 case BCM4335_CHIP_ID:
7925 case BCM4339_CHIP_ID:
7926 bus->dongle_ram_base = CR4_4335_RAM_BASE;
7927 break;
7928 case BCM4350_CHIP_ID:
7929 case BCM4354_CHIP_ID:
7930 case BCM4358_CHIP_ID:
7931 bus->dongle_ram_base = CR4_4350_RAM_BASE;
7932 break;
7933 case BCM4360_CHIP_ID:
7934 bus->dongle_ram_base = CR4_4360_RAM_BASE;
7935 break;
7936 CASE_BCM4345_CHIP:
7937 bus->dongle_ram_base = (bus->sih->chiprev < 6) /* from 4345C0 */
7938 ? CR4_4345_LT_C0_RAM_BASE : CR4_4345_GE_C0_RAM_BASE;
7939 break;
7940 case BCM4349_CHIP_GRPID:
7941 /* RAM based changed from 4349c0(revid=9) onwards */
7942 bus->dongle_ram_base = ((bus->sih->chiprev < 9) ?
7943 CR4_4349_RAM_BASE: CR4_4349_RAM_BASE_FROM_REV_9);
7944 break;
7945 case BCM4364_CHIP_ID:
7946 bus->dongle_ram_base = CR4_4364_RAM_BASE;
7947 break;
7948 default:
7949 bus->dongle_ram_base = 0;
7950 DHD_ERROR(("%s: WARNING: Using default ram base at 0x%x\n",
7951 __FUNCTION__, bus->dongle_ram_base));
7952 }
7953 }
7954 bus->ramsize = bus->orig_ramsize;
7955 if (dhd_dongle_ramsize)
7956 dhd_dongle_setramsize(bus, dhd_dongle_ramsize);
7957
7958 DHD_ERROR(("DHD: dongle ram size is set to %d(orig %d) at 0x%x\n",
7959 bus->ramsize, bus->orig_ramsize, bus->dongle_ram_base));
7960
7961 bus->srmemsize = si_socram_srmem_size(bus->sih);
7962 }
7963
7964 /* ...but normally deal with the SDPCMDEV core */
7965#ifdef BCMSDIOLITE
7966 if (!(bus->regs = si_setcore(bus->sih, CC_CORE_ID, 0))) {
7967 DHD_ERROR(("%s: failed to find Chip Common core!\n", __FUNCTION__));
7968 goto fail;
7969 }
7970#else
7971 if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0)) &&
7972 !(bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0))) {
7973 DHD_ERROR(("%s: failed to find SDIODEV core!\n", __FUNCTION__));
7974 goto fail;
7975 }
7976#endif // endif
7977 bus->sdpcmrev = si_corerev(bus->sih);
7978
7979 /* Set core control so an SDIO reset does a backplane reset */
7980 OR_REG(osh, &bus->regs->corecontrol, CC_BPRESEN);
7981#ifndef BCMSPI
7982 bus->rxint_mode = SDIO_DEVICE_HMB_RXINT;
7983
7984 if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev >= 4) &&
7985 (bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_1))
7986 {
7987 uint32 val;
7988
7989 val = R_REG(osh, &bus->regs->corecontrol);
7990 val &= ~CC_XMTDATAAVAIL_MODE;
7991 val |= CC_XMTDATAAVAIL_CTRL;
7992 W_REG(osh, &bus->regs->corecontrol, val);
7993 }
7994#endif /* BCMSPI */
7995
7996 pktq_init(&bus->txq, (PRIOMASK + 1), QLEN);
7997
7998 /* Locate an appropriately-aligned portion of hdrbuf */
7999 bus->rxhdr = (uint8 *)ROUNDUP((uintptr)&bus->hdrbuf[0], DHD_SDALIGN);
8000
8001 /* Set the poll and/or interrupt flags */
8002 bus->intr = (bool)dhd_intr;
8003 if ((bus->poll = (bool)dhd_poll))
8004 bus->pollrate = 1;
8005
8006 /* Setting default Glom size */
8007 bus->txglomsize = SDPCM_DEFGLOM_SIZE;
8008
8009 return TRUE;
8010
8011fail:
8012 if (bus->sih != NULL) {
8013 si_detach(bus->sih);
8014 bus->sih = NULL;
8015 }
8016 return FALSE;
8017}
8018
8019static bool
8020dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh)
8021{
8022 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
8023
8024 if (bus->dhd->maxctl) {
8025 bus->rxblen = ROUNDUP((bus->dhd->maxctl+SDPCM_HDRLEN), ALIGNMENT) + DHD_SDALIGN;
8026 if (!(bus->rxbuf = DHD_OS_PREALLOC(bus->dhd, DHD_PREALLOC_RXBUF, bus->rxblen))) {
8027 DHD_ERROR(("%s: MALLOC of %d-byte rxbuf failed\n",
8028 __FUNCTION__, bus->rxblen));
8029 goto fail;
8030 }
8031 }
8032 /* Allocate buffer to receive glomed packet */
8033 if (!(bus->databuf = DHD_OS_PREALLOC(bus->dhd, DHD_PREALLOC_DATABUF, MAX_DATA_BUF))) {
8034 DHD_ERROR(("%s: MALLOC of %d-byte databuf failed\n",
8035 __FUNCTION__, MAX_DATA_BUF));
8036 /* release rxbuf which was already located as above */
8037 if (!bus->rxblen)
8038 DHD_OS_PREFREE(bus->dhd, bus->rxbuf, bus->rxblen);
8039 goto fail;
8040 }
8041
8042 /* Align the buffer */
8043 if ((uintptr)bus->databuf % DHD_SDALIGN)
8044 bus->dataptr = bus->databuf + (DHD_SDALIGN - ((uintptr)bus->databuf % DHD_SDALIGN));
8045 else
8046 bus->dataptr = bus->databuf;
8047
8048 return TRUE;
8049
8050fail:
8051 return FALSE;
8052}
8053
8054static bool
8055dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh)
8056{
8057 int32 fnum;
8058
8059 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
8060
8061 bus->_srenab = FALSE;
8062
8063#ifdef SDTEST
8064 dhdsdio_pktgen_init(bus);
8065#endif /* SDTEST */
8066
8067#ifndef BCMSPI
8068 /* Disable F2 to clear any intermediate frame state on the dongle */
8069 bcmsdh_cfg_write(sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL);
8070#endif /* !BCMSPI */
8071
8072 bus->dhd->busstate = DHD_BUS_DOWN;
8073 bus->sleeping = FALSE;
8074 bus->rxflow = FALSE;
8075 bus->prev_rxlim_hit = 0;
8076
8077#ifndef BCMSPI
8078 /* Done with backplane-dependent accesses, can drop clock... */
8079 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
8080#endif /* !BCMSPI */
8081
8082 /* ...and initialize clock/power states */
8083 bus->clkstate = CLK_SDONLY;
8084 bus->idletime = (int32)dhd_idletime;
8085 bus->idleclock = DHD_IDLE_ACTIVE;
8086
8087 /* Query the SD clock speed */
8088 if (bcmsdh_iovar_op(sdh, "sd_divisor", NULL, 0,
8089 &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) {
8090 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_divisor"));
8091 bus->sd_divisor = -1;
8092 } else {
8093 DHD_INFO(("%s: Initial value for %s is %d\n",
8094 __FUNCTION__, "sd_divisor", bus->sd_divisor));
8095 }
8096
8097 /* Query the SD bus mode */
8098 if (bcmsdh_iovar_op(sdh, "sd_mode", NULL, 0,
8099 &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) {
8100 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_mode"));
8101 bus->sd_mode = -1;
8102 } else {
8103 DHD_INFO(("%s: Initial value for %s is %d\n",
8104 __FUNCTION__, "sd_mode", bus->sd_mode));
8105 }
8106
8107 /* Query the F2 block size, set roundup accordingly */
8108 fnum = 2;
8109 if (bcmsdh_iovar_op(sdh, "sd_blocksize", &fnum, sizeof(int32),
8110 &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) {
8111 bus->blocksize = 0;
8112 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize"));
8113 } else {
8114 DHD_INFO(("%s: Initial value for %s is %d\n",
8115 __FUNCTION__, "sd_blocksize", bus->blocksize));
8116
8117 dhdsdio_tune_fifoparam(bus);
8118 }
8119 bus->roundup = MIN(max_roundup, bus->blocksize);
8120
8121#ifdef DHDENABLE_TAILPAD
8122 if (bus->pad_pkt)
8123 PKTFREE(osh, bus->pad_pkt, FALSE);
8124 bus->pad_pkt = PKTGET(osh, SDIO_MAX_BLOCK_SIZE, FALSE);
8125 if (bus->pad_pkt == NULL)
8126 DHD_ERROR(("failed to allocate padding packet\n"));
8127 else {
8128 int alignment_offset = 0;
8129 uintptr pktprt = (uintptr)PKTDATA(osh, bus->pad_pkt);
8130 if (!(pktprt&1) && (pktprt = (pktprt % DHD_SDALIGN)))
8131 PKTPUSH(osh, bus->pad_pkt, alignment_offset);
8132 PKTSETNEXT(osh, bus->pad_pkt, NULL);
8133 }
8134#endif /* DHDENABLE_TAILPAD */
8135
8136 /* Query if bus module supports packet chaining, default to use if supported */
8137 if (bcmsdh_iovar_op(sdh, "sd_rxchain", NULL, 0,
8138 &bus->sd_rxchain, sizeof(int32), FALSE) != BCME_OK) {
8139 bus->sd_rxchain = FALSE;
8140 } else {
8141 DHD_INFO(("%s: bus module (through bcmsdh API) %s chaining\n",
8142 __FUNCTION__, (bus->sd_rxchain ? "supports" : "does not support")));
8143 }
8144 bus->use_rxchain = (bool)bus->sd_rxchain;
8145 bus->txinrx_thres = CUSTOM_TXINRX_THRES;
8146 /* TX first in dhdsdio_readframes() */
8147 bus->dotxinrx = TRUE;
8148
8149 return TRUE;
8150}
8151
8152int
8153dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh,
8154 char *pfw_path, char *pnv_path)
8155{
8156 int ret;
8157
8158 bus->fw_path = pfw_path;
8159 bus->nv_path = pnv_path;
8160
8161 ret = dhdsdio_download_firmware(bus, osh, bus->sdh);
8162
8163 return ret;
8164}
8165
8166static int
8167dhdsdio_download_firmware(struct dhd_bus *bus, osl_t *osh, void *sdh)
8168{
8169 int ret;
8170
8171#if defined(SUPPORT_MULTIPLE_REVISION)
8172 if (concate_revision(bus, bus->fw_path, bus->nv_path) != 0) {
8173 DHD_ERROR(("%s: fail to concatnate revison \n",
8174 __FUNCTION__));
8175 return BCME_BADARG;
8176 }
8177#endif /* SUPPORT_MULTIPLE_REVISION */
8178
8179#if defined(DHD_BLOB_EXISTENCE_CHECK)
8180 dhd_set_blob_support(bus->dhd, bus->fw_path);
8181#endif /* DHD_BLOB_EXISTENCE_CHECK */
8182
8183 DHD_TRACE_HW4(("%s: firmware path=%s, nvram path=%s\n",
8184 __FUNCTION__, bus->fw_path, bus->nv_path));
8185 DHD_OS_WAKE_LOCK(bus->dhd);
8186
8187 /* Download the firmware */
8188 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
8189
8190 ret = _dhdsdio_download_firmware(bus);
8191
8192 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
8193
8194 DHD_OS_WAKE_UNLOCK(bus->dhd);
8195 return ret;
8196}
8197
8198/* Detach and free everything */
8199static void
8200dhdsdio_release(dhd_bus_t *bus, osl_t *osh)
8201{
8202 bool dongle_isolation = FALSE;
8203 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
8204
8205 if (bus) {
8206 ASSERT(osh);
8207
8208 if (bus->dhd) {
8209#if defined(DEBUGGER) || defined(DHD_DSCOPE)
8210 debugger_close();
8211#endif /* DEBUGGER || DHD_DSCOPE */
8212 dongle_isolation = bus->dhd->dongle_isolation;
8213 dhd_detach(bus->dhd);
8214 }
8215
8216 /* De-register interrupt handler */
8217 bcmsdh_intr_disable(bus->sdh);
8218 bcmsdh_intr_dereg(bus->sdh);
8219
8220 if (bus->dhd) {
8221 dhdsdio_release_dongle(bus, osh, dongle_isolation, TRUE);
8222 dhd_free(bus->dhd);
8223 bus->dhd = NULL;
8224 }
8225
8226 dhdsdio_release_malloc(bus, osh);
8227
8228#ifdef DHD_DEBUG
8229 if (bus->console.buf != NULL)
8230 MFREE(osh, bus->console.buf, bus->console.bufsize);
8231#endif // endif
8232
8233#ifdef DHDENABLE_TAILPAD
8234 if (bus->pad_pkt)
8235 PKTFREE(osh, bus->pad_pkt, FALSE);
8236#endif /* DHDENABLE_TAILPAD */
8237
8238 MFREE(osh, bus, sizeof(dhd_bus_t));
8239 }
8240
8241 DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
8242}
8243
8244static void
8245dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh)
8246{
8247 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
8248
8249 if (bus->dhd && bus->dhd->dongle_reset)
8250 return;
8251
8252 if (bus->rxbuf) {
8253#ifndef CONFIG_DHD_USE_STATIC_BUF
8254 MFREE(osh, bus->rxbuf, bus->rxblen);
8255#endif // endif
8256 bus->rxctl = bus->rxbuf = NULL;
8257 bus->rxlen = 0;
8258 }
8259
8260 if (bus->databuf) {
8261#ifndef CONFIG_DHD_USE_STATIC_BUF
8262 MFREE(osh, bus->databuf, MAX_DATA_BUF);
8263#endif // endif
8264 bus->databuf = NULL;
8265 }
8266
8267 if (bus->vars && bus->varsz) {
8268 MFREE(osh, bus->vars, bus->varsz);
8269 bus->vars = NULL;
8270 }
8271
8272}
8273
8274static void
8275dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation, bool reset_flag)
8276{
8277 DHD_TRACE(("%s: Enter bus->dhd %p bus->dhd->dongle_reset %d \n", __FUNCTION__,
8278 bus->dhd, bus->dhd->dongle_reset));
8279
8280 if ((bus->dhd && bus->dhd->dongle_reset) && reset_flag)
8281 return;
8282
8283 if (bus->sih) {
8284 /* In Win10, system will be BSOD if using "sysprep" to do OS image */
8285 /* Skip this will not cause the BSOD. */
8286#if !defined(BCMLXSDMMC)
8287 if (bus->dhd) {
8288 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
8289 }
8290 if (KSO_ENAB(bus) && (dongle_isolation == FALSE))
8291 si_watchdog(bus->sih, 4);
8292#endif /* !defined(BCMLXSDMMC) */
8293 if (bus->dhd) {
8294 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
8295 }
8296 si_detach(bus->sih);
8297 bus->sih = NULL;
8298 if (bus->vars && bus->varsz)
8299 MFREE(osh, bus->vars, bus->varsz);
8300 bus->vars = NULL;
8301 }
8302
8303 DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
8304}
8305
8306static void
8307dhdsdio_disconnect(void *ptr)
8308{
8309 dhd_bus_t *bus = (dhd_bus_t *)ptr;
8310
8311 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
8312
8313#if defined(MULTIPLE_SUPPLICANT)
8314#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
8315 if (mutex_is_locked(&_dhd_sdio_mutex_lock_) == 0) {
8316 DHD_ERROR(("%s : no mutex held. set lock\n", __FUNCTION__));
8317 } else {
8318 DHD_ERROR(("%s : mutex is locked!. wait for unlocking\n", __FUNCTION__));
8319 }
8320 mutex_lock(&_dhd_sdio_mutex_lock_);
8321#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
8322#endif // endif
8323
8324 if (bus) {
8325 ASSERT(bus->dhd);
8326 /* Advertise bus cleanup during rmmod */
8327 dhdsdio_advertise_bus_cleanup(bus->dhd);
8328 dhdsdio_release(bus, bus->dhd->osh);
8329 }
8330
8331#if defined(MULTIPLE_SUPPLICANT)
8332#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
8333 mutex_unlock(&_dhd_sdio_mutex_lock_);
8334 DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__));
8335#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
8336#endif /* LINUX */
8337
8338 DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
8339}
8340
8341static int
8342dhdsdio_suspend(void *context)
8343{
8344 int ret = 0;
8345#ifdef SUPPORT_P2P_GO_PS
8346 int wait_time = 0;
8347#endif /* SUPPORT_P2P_GO_PS */
8348
8349 dhd_bus_t *bus = (dhd_bus_t*)context;
8350 unsigned long flags;
8351
8352 DHD_ERROR(("%s Enter\n", __FUNCTION__));
8353 if (bus->dhd == NULL) {
8354 DHD_ERROR(("bus not inited\n"));
8355 return BCME_ERROR;
8356 }
8357 if (bus->dhd->prot == NULL) {
8358 DHD_ERROR(("prot is not inited\n"));
8359 return BCME_ERROR;
8360 }
8361
8362 if (bus->dhd->up == FALSE) {
8363 return BCME_OK;
8364 }
8365
8366 DHD_LINUX_GENERAL_LOCK(bus->dhd, flags);
8367 if (bus->dhd->busstate != DHD_BUS_DATA && bus->dhd->busstate != DHD_BUS_SUSPEND) {
8368 DHD_ERROR(("not in a readystate to LPBK is not inited\n"));
8369 DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
8370 return BCME_ERROR;
8371 }
8372 DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
8373 if (bus->dhd->dongle_reset) {
8374 DHD_ERROR(("Dongle is in reset state.\n"));
8375 return -EIO;
8376 }
8377
8378 DHD_LINUX_GENERAL_LOCK(bus->dhd, flags);
5a068558
MB
8379 /* stop all interface network queue. */
8380 dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON);
1cac41cb
MB
8381 bus->dhd->busstate = DHD_BUS_SUSPEND;
8382 if (DHD_BUS_BUSY_CHECK_IN_TX(bus->dhd)) {
8383 DHD_ERROR(("Tx Request is not ended\n"));
8384 bus->dhd->busstate = DHD_BUS_DATA;
5a068558
MB
8385 /* resume all interface network queue. */
8386 dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF);
1cac41cb
MB
8387 DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
8388 return -EBUSY;
8389 }
8390 DHD_BUS_BUSY_SET_SUSPEND_IN_PROGRESS(bus->dhd);
8391 DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
8392
8393#ifdef SUPPORT_P2P_GO_PS
8394 if (bus->idletime > 0) {
8395 wait_time = msecs_to_jiffies(bus->idletime * dhd_watchdog_ms);
8396 }
8397#endif /* SUPPORT_P2P_GO_PS */
8398 ret = dhd_os_check_wakelock(bus->dhd);
8399#ifdef SUPPORT_P2P_GO_PS
8400 if ((!ret) && (bus->dhd->up) && (bus->dhd->op_mode != DHD_FLAG_HOSTAP_MODE)) {
8401 if (wait_event_timeout(bus->bus_sleep, bus->sleeping, wait_time) == 0) {
8402 if (!bus->sleeping) {
8403 ret = 1;
8404 }
8405 }
8406 }
8407#endif /* SUPPORT_P2P_GO_PS */
8408
8409 DHD_LINUX_GENERAL_LOCK(bus->dhd, flags);
8410 if (ret) {
8411 bus->dhd->busstate = DHD_BUS_DATA;
5a068558
MB
8412 /* resume all interface network queue. */
8413 dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF);
1cac41cb
MB
8414 }
8415 DHD_BUS_BUSY_CLEAR_SUSPEND_IN_PROGRESS(bus->dhd);
8416 dhd_os_busbusy_wake(bus->dhd);
8417 DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
8418 return ret;
8419}
8420
8421static int
8422dhdsdio_resume(void *context)
8423{
8424 dhd_bus_t *bus = (dhd_bus_t*)context;
8425 ulong flags;
8426
8427 DHD_ERROR(("%s Enter\n", __FUNCTION__));
8428
8429 if (bus->dhd->up == FALSE) {
8430 return BCME_OK;
8431 }
8432
8433 DHD_LINUX_GENERAL_LOCK(bus->dhd, flags);
8434 DHD_BUS_BUSY_SET_RESUME_IN_PROGRESS(bus->dhd);
8435 DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
8436
8437#if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
8438 if (dhd_os_check_if_up(bus->dhd))
8439 bcmsdh_oob_intr_set(bus->sdh, TRUE);
8440#endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */
8441
8442 DHD_LINUX_GENERAL_LOCK(bus->dhd, flags);
8443 DHD_BUS_BUSY_CLEAR_RESUME_IN_PROGRESS(bus->dhd);
8444 bus->dhd->busstate = DHD_BUS_DATA;
8445 dhd_os_busbusy_wake(bus->dhd);
5a068558
MB
8446 /* resume all interface network queue. */
8447 dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF);
1cac41cb
MB
8448 DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
8449
8450 return 0;
8451}
8452
8453/* Register/Unregister functions are called by the main DHD entry
8454 * point (e.g. module insertion) to link with the bus driver, in
8455 * order to look for or await the device.
8456 */
8457
8458static bcmsdh_driver_t dhd_sdio = {
8459 dhdsdio_probe,
8460 dhdsdio_disconnect,
8461 dhdsdio_suspend,
8462 dhdsdio_resume
8463};
8464
8465int
8466dhd_bus_register(void)
8467{
8468 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
8469
8470 return bcmsdh_register(&dhd_sdio);
8471}
8472
8473void
8474dhd_bus_unregister(void)
8475{
8476 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
8477
8478 bcmsdh_unregister();
8479}
8480
8481#if defined(BCMLXSDMMC)
8482/* Register a dummy SDIO client driver in order to be notified of new SDIO device */
8483int dhd_bus_reg_sdio_notify(void* semaphore)
8484{
8485 return bcmsdh_reg_sdio_notify(semaphore);
8486}
8487
8488void dhd_bus_unreg_sdio_notify(void)
8489{
8490 bcmsdh_unreg_sdio_notify();
8491}
8492#endif /* defined(BCMLXSDMMC) */
8493
8494static int
8495dhdsdio_download_code_file(struct dhd_bus *bus, char *pfw_path)
8496{
8497 int bcmerror = -1;
8498 int offset = 0;
8499 int len;
8500 void *image = NULL;
8501 uint8 *memblock = NULL, *memptr;
8502 uint memblock_size = MEMBLOCK;
8503#ifdef DHD_DEBUG_DOWNLOADTIME
8504 unsigned long initial_jiffies = 0;
8505 uint firmware_sz = 0;
8506#endif // endif
8507
8508 DHD_INFO(("%s: download firmware %s\n", __FUNCTION__, pfw_path));
8509
8510 image = dhd_os_open_image1(bus->dhd, pfw_path);
8511 if (image == NULL) {
8512 DHD_ERROR(("%s: Failed to open fw file !\n", __FUNCTION__));
8513 goto err;
8514 }
8515
8516 /* Update the dongle image download block size depending on the F1 block size */
8517 if (sd_f1_blocksize == 512)
8518 memblock_size = MAX_MEMBLOCK;
8519 memptr = memblock = MALLOC(bus->dhd->osh, memblock_size + DHD_SDALIGN);
8520 if (memblock == NULL) {
8521 DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__,
8522 memblock_size));
8523 goto err;
8524 }
8525 if ((uint32)(uintptr)memblock % DHD_SDALIGN)
8526 memptr += (DHD_SDALIGN - ((uint32)(uintptr)memblock % DHD_SDALIGN));
8527
8528#ifdef DHD_DEBUG_DOWNLOADTIME
8529 initial_jiffies = jiffies;
8530#endif // endif
8531
8532 /* Download image */
8533 while ((len = dhd_os_get_image_block((char*)memptr, memblock_size, image))) {
8534 if (len < 0) {
8535 DHD_ERROR(("%s: dhd_os_get_image_block failed (%d)\n", __FUNCTION__, len));
8536 bcmerror = BCME_ERROR;
8537 goto err;
8538 }
8539 /* check if CR4 */
8540 if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
8541 /* if address is 0, store the reset instruction to be written in 0 */
8542
8543 if (offset == 0) {
8544 bus->resetinstr = *(((uint32*)memptr));
8545 /* Add start of RAM address to the address given by user */
8546 offset += bus->dongle_ram_base;
8547 }
8548 }
8549
8550 bcmerror = dhdsdio_membytes(bus, TRUE, offset, memptr, len);
8551 if (bcmerror) {
8552 DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
8553 __FUNCTION__, bcmerror, memblock_size, offset));
8554 goto err;
8555 }
8556
8557 offset += memblock_size;
8558#ifdef DHD_DEBUG_DOWNLOADTIME
8559 firmware_sz += len;
8560#endif // endif
8561 }
8562
8563#ifdef DHD_DEBUG_DOWNLOADTIME
8564 DHD_ERROR(("Firmware download time for %u bytes: %u ms\n",
8565 firmware_sz, jiffies_to_msecs(jiffies - initial_jiffies)));
8566#endif // endif
8567
8568err:
8569 if (memblock)
8570 MFREE(bus->dhd->osh, memblock, memblock_size + DHD_SDALIGN);
8571
8572 if (image)
8573 dhd_os_close_image1(bus->dhd, image);
8574
8575 return bcmerror;
8576}
8577
8578#ifdef DHD_UCODE_DOWNLOAD
8579/* Currently supported only for the chips in which ucode RAM is AXI addressable */
8580static uint32
8581dhdsdio_ucode_base(struct dhd_bus *bus)
8582{
8583 uint32 ucode_base = 0;
8584
8585 switch ((uint16)bus->sih->chip) {
8586 case BCM43012_CHIP_ID:
8587 ucode_base = 0xE8020000;
8588 break;
8589 default:
8590 DHD_ERROR(("%s: Unsupported!\n", __func__));
8591 break;
8592 }
8593
8594 return ucode_base;
8595}
8596
8597static int
8598dhdsdio_download_ucode_file(struct dhd_bus *bus, char *ucode_path)
8599{
8600 int bcmerror = -1;
8601 int offset = 0;
8602 int len;
8603 uint32 ucode_base;
8604 void *image = NULL;
8605 uint8 *memblock = NULL, *memptr;
8606 uint memblock_size = MEMBLOCK;
8607#ifdef DHD_DEBUG_DOWNLOADTIME
8608 unsigned long initial_jiffies = 0;
8609 uint firmware_sz = 0;
8610#endif // endif
8611
8612 DHD_INFO(("%s: download firmware %s\n", __FUNCTION__, ucode_path));
8613
8614 ucode_base = dhdsdio_ucode_base(bus);
8615
8616 image = dhd_os_open_image1(bus->dhd, ucode_path);
8617 if (image == NULL)
8618 goto err;
8619
8620 /* Update the dongle image download block size depending on the F1 block size */
8621 if (sd_f1_blocksize == 512)
8622 memblock_size = MAX_MEMBLOCK;
8623
8624 memptr = memblock = MALLOC(bus->dhd->osh, memblock_size + DHD_SDALIGN);
8625 if (memblock == NULL) {
8626 DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__,
8627 memblock_size));
8628 goto err;
8629 }
8630 if ((uint32)(uintptr)memblock % DHD_SDALIGN)
8631 memptr += (DHD_SDALIGN - ((uint32)(uintptr)memblock % DHD_SDALIGN));
8632
8633#ifdef DHD_DEBUG_DOWNLOADTIME
8634 initial_jiffies = jiffies;
8635#endif // endif
8636
8637 /* Download image */
8638 while ((len = dhd_os_get_image_block((char*)memptr, memblock_size, image))) {
8639 if (len < 0) {
8640 DHD_ERROR(("%s: dhd_os_get_image_block failed (%d)\n", __FUNCTION__, len));
8641 bcmerror = BCME_ERROR;
8642 goto err;
8643 }
8644
8645 bcmerror = dhdsdio_membytes(bus, TRUE, (ucode_base + offset), memptr, len);
8646 if (bcmerror) {
8647 DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
8648 __FUNCTION__, bcmerror, memblock_size, offset));
8649 goto err;
8650 }
8651
8652 offset += memblock_size;
8653#ifdef DHD_DEBUG_DOWNLOADTIME
8654 firmware_sz += len;
8655#endif // endif
8656 }
8657
8658#ifdef DHD_DEBUG_DOWNLOADTIME
8659 DHD_ERROR(("ucode download time for %u bytes: %u ms\n",
8660 firmware_sz, jiffies_to_msecs(jiffies - initial_jiffies)));
8661#endif // endif
8662
8663err:
8664 if (memblock)
8665 MFREE(bus->dhd->osh, memblock, memblock_size + DHD_SDALIGN);
8666
8667 if (image)
8668 dhd_os_close_image1(bus->dhd, image);
8669
8670 return bcmerror;
8671} /* dhdsdio_download_ucode_file */
8672
8673void
8674dhd_bus_ucode_download(struct dhd_bus *bus)
8675{
8676 uint32 shaddr = 0, shdata = 0;
8677
8678 shaddr = bus->dongle_ram_base + bus->ramsize - 4;
8679 dhdsdio_membytes(bus, FALSE, shaddr, (uint8 *)&shdata, 4);
8680
8681 DHD_TRACE(("%s: shdata:[0x%08x :0x%08x]\n", __func__, shaddr, shdata));
8682
8683 if (shdata == UCODE_DOWNLOAD_REQUEST)
8684 {
8685 DHD_ERROR(("%s: Received ucode download request!\n", __func__));
8686
8687 /* Download the ucode */
8688 if (!dhd_get_ucode_path(bus->dhd)) {
8689 DHD_ERROR(("%s: bus->uc_path not set!\n", __func__));
8690 return;
8691 }
8692 dhdsdio_download_ucode_file(bus, dhd_get_ucode_path(bus->dhd));
8693
8694 DHD_ERROR(("%s: Ucode downloaded successfully!\n", __func__));
8695
8696 shdata = UCODE_DOWNLOAD_COMPLETE;
8697 dhdsdio_membytes(bus, TRUE, shaddr, (uint8 *)&shdata, 4);
8698 }
8699}
8700
8701#endif /* DHD_UCODE_DOWNLOAD */
8702
8703static int
8704dhdsdio_download_nvram(struct dhd_bus *bus)
8705{
8706 int bcmerror = -1;
8707 uint len;
8708 void * image = NULL;
8709 char * memblock = NULL;
8710 char *bufp;
8711 char *pnv_path;
8712 bool nvram_file_exists;
8713
8714 pnv_path = bus->nv_path;
8715
8716 nvram_file_exists = ((pnv_path != NULL) && (pnv_path[0] != '\0'));
8717
8718 /* For Get nvram from UEFI */
8719 if (nvram_file_exists)
8720 image = dhd_os_open_image1(bus->dhd, pnv_path);
8721
8722 memblock = MALLOC(bus->dhd->osh, MAX_NVRAMBUF_SIZE);
8723 if (memblock == NULL) {
8724 DHD_ERROR(("%s: Failed to allocate memory %d bytes\n",
8725 __FUNCTION__, MAX_NVRAMBUF_SIZE));
8726 goto err;
8727 }
8728
8729 /* For Get nvram from image or UEFI (when image == NULL ) */
8730 len = dhd_os_get_image_block(memblock, MAX_NVRAMBUF_SIZE, image);
8731
8732 if (len > 0 && len < MAX_NVRAMBUF_SIZE) {
8733 bufp = (char *)memblock;
8734 bufp[len] = 0;
8735 len = process_nvram_vars(bufp, len);
8736 if (len % 4) {
8737 len += 4 - (len % 4);
8738 }
8739 bufp += len;
8740 *bufp++ = 0;
8741 if (len)
8742 bcmerror = dhdsdio_downloadvars(bus, memblock, len + 1);
8743 if (bcmerror) {
8744 DHD_ERROR(("%s: error downloading vars: %d\n",
8745 __FUNCTION__, bcmerror));
8746 }
8747 } else {
8748 DHD_ERROR(("%s: error reading nvram file: %d\n",
8749 __FUNCTION__, len));
8750 bcmerror = BCME_SDIO_ERROR;
8751 }
8752
8753err:
8754 if (memblock)
8755 MFREE(bus->dhd->osh, memblock, MAX_NVRAMBUF_SIZE);
8756
8757 if (image)
8758 dhd_os_close_image1(bus->dhd, image);
8759
8760 return bcmerror;
8761}
8762
8763static int
8764_dhdsdio_download_firmware(struct dhd_bus *bus)
8765{
8766 int bcmerror = -1;
8767
8768 bool embed = FALSE; /* download embedded firmware */
8769 bool dlok = FALSE; /* download firmware succeeded */
8770
8771 /* Out immediately if no image to download */
8772 if ((bus->fw_path == NULL) || (bus->fw_path[0] == '\0')) {
8773 return bcmerror;
8774 }
8775
8776 /* Keep arm in reset */
8777 if (dhdsdio_download_state(bus, TRUE)) {
8778 DHD_ERROR(("%s: error placing ARM core in reset\n", __FUNCTION__));
8779 goto err;
8780 }
8781
8782 /* External image takes precedence if specified */
8783 if ((bus->fw_path != NULL) && (bus->fw_path[0] != '\0')) {
8784 if (dhdsdio_download_code_file(bus, bus->fw_path)) {
8785 DHD_ERROR(("%s: dongle image file download failed\n", __FUNCTION__));
8786 goto err;
8787 } else {
8788 embed = FALSE;
8789 dlok = TRUE;
8790 }
8791 }
8792
8793 BCM_REFERENCE(embed);
8794 if (!dlok) {
8795 DHD_ERROR(("%s: dongle image download failed\n", __FUNCTION__));
8796 goto err;
8797 }
8798
8799 /* External nvram takes precedence if specified */
8800 if (dhdsdio_download_nvram(bus)) {
8801 DHD_ERROR(("%s: dongle nvram file download failed\n", __FUNCTION__));
8802 goto err;
8803 }
8804
8805 /* Take arm out of reset */
8806 if (dhdsdio_download_state(bus, FALSE)) {
8807 DHD_ERROR(("%s: error getting out of ARM core reset\n", __FUNCTION__));
8808 goto err;
8809 }
8810
8811 bcmerror = 0;
8812
8813err:
8814 return bcmerror;
8815}
8816
8817static int
8818dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes,
8819 void *pkt, bcmsdh_cmplt_fn_t complete_fn, void *handle)
8820{
8821 int status;
8822
8823 if (!KSO_ENAB(bus)) {
8824 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
8825 return BCME_NODEVICE;
8826 }
8827
8828 status = bcmsdh_recv_buf(bus->sdh, addr, fn, flags, buf, nbytes, pkt, complete_fn, handle);
8829
8830 return status;
8831}
8832
8833static int
8834dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes,
8835 void *pkt, bcmsdh_cmplt_fn_t complete_fn, void *handle, int max_retry)
8836{
8837 int ret;
8838 int i = 0;
8839 int retries = 0;
8840 bcmsdh_info_t *sdh;
8841
8842 if (!KSO_ENAB(bus)) {
8843 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
8844 return BCME_NODEVICE;
8845 }
8846
8847 sdh = bus->sdh;
8848 do {
8849 ret = bcmsdh_send_buf(bus->sdh, addr, fn, flags, buf, nbytes,
8850 pkt, complete_fn, handle);
8851
8852 bus->f2txdata++;
8853 ASSERT(ret != BCME_PENDING);
8854
8855 if (ret == BCME_NODEVICE) {
8856 DHD_ERROR(("%s: Device asleep already\n", __FUNCTION__));
8857 } else if (ret < 0) {
8858 /* On failure, abort the command and terminate the frame */
8859 DHD_ERROR(("%s: sdio error %d, abort command and terminate frame.\n",
8860 __FUNCTION__, ret));
8861 bus->tx_sderrs++;
8862 bus->f1regdata++;
8863 bus->dhd->tx_errors++;
8864 bcmsdh_abort(sdh, SDIO_FUNC_2);
8865 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
8866 SFC_WF_TERM, NULL);
8867 for (i = 0; i < READ_FRM_CNT_RETRIES; i++) {
8868 uint8 hi, lo;
8869 hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WFRAMEBCHI,
8870 NULL);
8871 lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WFRAMEBCLO,
8872 NULL);
8873 bus->f1regdata += 2;
8874 if ((hi == 0) && (lo == 0))
8875 break;
8876 }
8877 }
8878 } while ((ret < 0) && retrydata && ++retries < max_retry);
8879
8880 return ret;
8881}
8882
8883uint8
8884dhd_bus_is_ioready(struct dhd_bus *bus)
8885{
8886 uint8 enable;
8887 bcmsdh_info_t *sdh;
8888 ASSERT(bus);
8889 ASSERT(bus->sih != NULL);
8890 enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2);
8891 sdh = bus->sdh;
8892 return (enable == bcmsdh_cfg_read(sdh, SDIO_FUNC_0, SDIOD_CCCR_IORDY, NULL));
8893}
8894
8895uint
8896dhd_bus_chip(struct dhd_bus *bus)
8897{
8898 ASSERT(bus->sih != NULL);
8899 return bus->sih->chip;
8900}
8901
8902uint
8903dhd_bus_chiprev(struct dhd_bus *bus)
8904{
8905 ASSERT(bus);
8906 ASSERT(bus->sih != NULL);
8907 return bus->sih->chiprev;
8908}
8909
8910void *
8911dhd_bus_pub(struct dhd_bus *bus)
8912{
8913 return bus->dhd;
8914}
8915
8916void *
8917dhd_bus_sih(struct dhd_bus *bus)
8918{
8919 return (void *)bus->sih;
8920}
8921
8922void *
8923dhd_bus_txq(struct dhd_bus *bus)
8924{
8925 return &bus->txq;
8926}
8927
8928uint
8929dhd_bus_hdrlen(struct dhd_bus *bus)
8930{
8931 return (bus->txglom_enable) ? SDPCM_HDRLEN_TXGLOM : SDPCM_HDRLEN;
8932}
8933
8934void
8935dhd_bus_set_dotxinrx(struct dhd_bus *bus, bool val)
8936{
8937 bus->dotxinrx = val;
8938}
8939
8940/*
8941 * dhdsdio_advertise_bus_cleanup advertises that clean up is under progress
8942 * to other bus user contexts like Tx, Rx, IOVAR, WD etc and it waits for other contexts
8943 * to gracefully exit. All the bus usage contexts before marking busstate as busy, will check for
8944 * whether the busstate is DHD_BUS_DOWN or DHD_BUS_DOWN_IN_PROGRESS, if so
8945 * they will exit from there itself without marking dhd_bus_busy_state as BUSY.
8946 */
8947static void
8948dhdsdio_advertise_bus_cleanup(dhd_pub_t *dhdp)
8949{
8950 unsigned long flags;
8951 int timeleft;
8952
8953 DHD_LINUX_GENERAL_LOCK(dhdp, flags);
8954 dhdp->busstate = DHD_BUS_DOWN_IN_PROGRESS;
8955 DHD_LINUX_GENERAL_UNLOCK(dhdp, flags);
8956
8957 timeleft = dhd_os_busbusy_wait_negation(dhdp, &dhdp->dhd_bus_busy_state);
8958 if ((timeleft == 0) || (timeleft == 1)) {
8959 DHD_ERROR(("%s : Timeout due to dhd_bus_busy_state=0x%x\n",
8960 __FUNCTION__, dhdp->dhd_bus_busy_state));
8961 ASSERT(0);
8962 }
8963
8964 return;
8965}
8966
8967int
8968dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag)
8969{
8970 int bcmerror = 0;
8971 dhd_bus_t *bus;
8972 unsigned long flags;
8973
8974 bus = dhdp->bus;
8975
8976 if (flag == TRUE) {
8977 if (!bus->dhd->dongle_reset) {
8978 DHD_ERROR(("%s: == Power OFF ==\n", __FUNCTION__));
8979 dhdsdio_advertise_bus_cleanup(bus->dhd);
8980 dhd_os_sdlock(dhdp);
8981 dhd_os_wd_timer(dhdp, 0);
8982#if !defined(IGNORE_ETH0_DOWN)
8983 /* Force flow control as protection when stop come before ifconfig_down */
8984 dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON);
8985#endif /* !defined(IGNORE_ETH0_DOWN) */
8986 /* Expect app to have torn down any connection before calling */
8987 /* Stop the bus, disable F2 */
8988 dhd_bus_stop(bus, FALSE);
8989#if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
8990 /* Clean up any pending IRQ */
8991 dhd_enable_oob_intr(bus, FALSE);
8992 bcmsdh_oob_intr_set(bus->sdh, FALSE);
8993 bcmsdh_oob_intr_unregister(bus->sdh);
8994#endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */
8995
8996 /* Clean tx/rx buffer pointers, detach from the dongle */
8997 dhdsdio_release_dongle(bus, bus->dhd->osh, TRUE, TRUE);
8998
8999 bus->dhd->dongle_reset = TRUE;
9000 bus->dhd->up = FALSE;
9001 dhd_txglom_enable(dhdp, FALSE);
9002 dhd_os_sdunlock(dhdp);
9003
9004 DHD_LINUX_GENERAL_LOCK(bus->dhd, flags);
9005 bus->dhd->busstate = DHD_BUS_DOWN;
9006 DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
9007
9008 DHD_TRACE(("%s: WLAN OFF DONE\n", __FUNCTION__));
9009 /* App can now remove power from device */
9010 } else
9011 bcmerror = BCME_SDIO_ERROR;
9012 } else {
9013 /* App must have restored power to device before calling */
9014
9015 DHD_ERROR(("\n\n%s: == Power ON ==\n", __FUNCTION__));
9016
9017 if (bus->dhd->dongle_reset) {
9018 /* Turn on WLAN */
9019 dhd_os_sdlock(dhdp);
9020 /* Reset SD client -- required if devreset is called
9021 * via 'dhd devreset' iovar
9022 */
9023 bcmsdh_reset(bus->sdh);
9024 /* Attempt to re-attach & download */
9025 if (dhdsdio_probe_attach(bus, bus->dhd->osh, bus->sdh,
9026 (uint32 *)(uintptr)si_enum_base(bus->cl_devid),
9027 bus->cl_devid)) {
9028
9029 DHD_LINUX_GENERAL_LOCK(bus->dhd, flags);
9030 bus->dhd->busstate = DHD_BUS_DOWN;
9031 DHD_LINUX_GENERAL_UNLOCK(bus->dhd, flags);
9032
9033 /* Attempt to download binary to the dongle */
9034 if (dhdsdio_probe_init(bus, bus->dhd->osh, bus->sdh) &&
9035 dhdsdio_download_firmware(bus, bus->dhd->osh, bus->sdh) >= 0) {
9036
9037 /* Re-init bus, enable F2 transfer */
9038 bcmerror = dhd_bus_init((dhd_pub_t *) bus->dhd, FALSE);
9039 if (bcmerror == BCME_OK) {
9040#if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
9041 dhd_enable_oob_intr(bus, TRUE);
9042 bcmsdh_oob_intr_register(bus->sdh,
9043 dhdsdio_isr, bus);
9044 bcmsdh_oob_intr_set(bus->sdh, TRUE);
9045#endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */
9046
9047 bus->dhd->dongle_reset = FALSE;
9048 bus->dhd->up = TRUE;
9049
9050#if !defined(IGNORE_ETH0_DOWN)
9051 /* Restore flow control */
9052 dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF);
9053#endif // endif
9054 dhd_os_wd_timer(dhdp, dhd_watchdog_ms);
9055
9056 DHD_TRACE(("%s: WLAN ON DONE\n", __FUNCTION__));
9057 } else {
9058 dhd_bus_stop(bus, FALSE);
9059 dhdsdio_release_dongle(bus, bus->dhd->osh,
9060 TRUE, FALSE);
9061 }
9062 } else {
9063 DHD_ERROR(("%s Failed to download binary to the dongle\n",
9064 __FUNCTION__));
9065 if (bus->sih != NULL) {
9066 si_detach(bus->sih);
9067 bus->sih = NULL;
9068 }
9069 bcmerror = BCME_SDIO_ERROR;
9070 }
9071 } else
9072 bcmerror = BCME_SDIO_ERROR;
9073
9074 dhd_os_sdunlock(dhdp);
9075 } else {
9076 DHD_INFO(("%s called when dongle is not in reset\n",
9077 __FUNCTION__));
9078 DHD_INFO(("Will call dhd_bus_start instead\n"));
9079 dhd_bus_resume(dhdp, 1);
9080 if ((bcmerror = dhd_bus_start(dhdp)) != 0)
9081 DHD_ERROR(("%s: dhd_bus_start fail with %d\n",
9082 __FUNCTION__, bcmerror));
9083 }
9084 }
9085 return bcmerror;
9086}
9087
9088int dhd_bus_suspend(dhd_pub_t *dhdpub)
9089{
9090 return bcmsdh_stop(dhdpub->bus->sdh);
9091}
9092
9093int dhd_bus_resume(dhd_pub_t *dhdpub, int stage)
9094{
9095 return bcmsdh_start(dhdpub->bus->sdh, stage);
9096}
9097
9098/* Get Chip ID version */
9099uint dhd_bus_chip_id(dhd_pub_t *dhdp)
9100{
9101 dhd_bus_t *bus = dhdp->bus;
9102
9103 return bus->sih->chip;
9104}
9105
9106/* Get Chip Rev ID version */
9107uint dhd_bus_chiprev_id(dhd_pub_t *dhdp)
9108{
9109 dhd_bus_t *bus = dhdp->bus;
9110
9111 return bus->sih->chiprev;
9112}
9113
9114/* Get Chip Pkg ID version */
9115uint dhd_bus_chippkg_id(dhd_pub_t *dhdp)
9116{
9117 dhd_bus_t *bus = dhdp->bus;
9118
9119 return bus->sih->chippkg;
9120}
9121
9122int dhd_bus_get_ids(struct dhd_bus *bus, uint32 *bus_type, uint32 *bus_num, uint32 *slot_num)
9123{
9124 *bus_type = bus->bus;
9125 *bus_num = bus->bus_num;
9126 *slot_num = bus->slot_num;
9127 return 0;
9128}
9129
9130int
9131dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint size)
9132{
9133 dhd_bus_t *bus;
9134
9135 bus = dhdp->bus;
9136 return dhdsdio_membytes(bus, set, address, data, size);
9137}
9138
9139#if defined(SUPPORT_MULTIPLE_REVISION)
9140static int
9141concate_revision_bcm4335(dhd_bus_t *bus, char *fw_path, char *nv_path)
9142{
9143
9144 uint chipver;
9145#if defined(SUPPORT_MULTIPLE_CHIPS)
9146 char chipver_tag[10] = "_4335";
9147#else
9148 char chipver_tag[4] = {0, };
9149#endif /* defined(SUPPORT_MULTIPLE_CHIPS) */
9150
9151 DHD_TRACE(("%s: BCM4335 Multiple Revision Check\n", __FUNCTION__));
9152 if (bus->sih->chip != BCM4335_CHIP_ID) {
9153 DHD_ERROR(("%s:Chip is not BCM4335\n", __FUNCTION__));
9154 return -1;
9155 }
9156 chipver = bus->sih->chiprev;
9157 DHD_ERROR(("CHIP VER = [0x%x]\n", chipver));
9158 if (chipver == 0x0) {
9159 DHD_ERROR(("----- CHIP bcm4335_A0 -----\n"));
9160 strcat(chipver_tag, "_a0");
9161 } else if (chipver == 0x1) {
9162 DHD_ERROR(("----- CHIP bcm4335_B0 -----\n"));
9163#if defined(SUPPORT_MULTIPLE_CHIPS)
9164 strcat(chipver_tag, "_b0");
9165#endif /* defined(SUPPORT_MULTIPLE_CHIPS) */
9166 }
9167
9168 strcat(fw_path, chipver_tag);
9169 strcat(nv_path, chipver_tag);
9170 return 0;
9171}
9172
9173static int
9174concate_revision_bcm4339(dhd_bus_t *bus, char *fw_path, char *nv_path)
9175{
9176
9177 uint chipver;
9178#if defined(SUPPORT_MULTIPLE_CHIPS)
9179 char chipver_tag[10] = "_4339";
9180#else
9181 char chipver_tag[4] = {0, };
9182#endif /* defined(SUPPORT_MULTIPLE_CHIPS) */
9183
9184 DHD_TRACE(("%s: BCM4339 Multiple Revision Check\n", __FUNCTION__));
9185 if (bus->sih->chip != BCM4339_CHIP_ID) {
9186 DHD_ERROR(("%s:Chip is not BCM4339\n", __FUNCTION__));
9187 return -1;
9188 }
9189 chipver = bus->sih->chiprev;
9190 DHD_ERROR(("CHIP VER = [0x%x]\n", chipver));
9191 if (chipver == 0x1) {
9192 DHD_ERROR(("----- CHIP bcm4339_A0 -----\n"));
9193 strcat(chipver_tag, "_a0");
9194 } else {
9195 DHD_ERROR(("----- CHIP bcm4339 unknown revision %d -----\n",
9196 chipver));
9197 }
9198
9199 strcat(fw_path, chipver_tag);
9200 strcat(nv_path, chipver_tag);
9201 return 0;
9202}
9203
9204static int concate_revision_bcm4350(dhd_bus_t *bus, char *fw_path, char *nv_path)
9205{
9206 uint32 chip_ver;
9207#if defined(SUPPORT_MULTIPLE_CHIPS)
9208 char chipver_tag[10] = {0, };
9209#else
9210 char chipver_tag[4] = {0, };
9211#endif /* defined(SUPPORT_MULTIPLE_CHIPS) */
9212 chip_ver = bus->sih->chiprev;
9213
9214#if defined(SUPPORT_MULTIPLE_CHIPS)
9215 if (chip_ver == 3)
9216 strcat(chipver_tag, "_4354");
9217 else
9218 strcat(chipver_tag, "_4350");
9219#endif // endif
9220
9221 if (chip_ver == 3) {
9222 DHD_ERROR(("----- CHIP 4354 A0 -----\n"));
9223 strcat(chipver_tag, "_a0");
9224 } else {
9225 DHD_ERROR(("----- Unknown chip version, ver=%x -----\n", chip_ver));
9226 }
9227
9228 strcat(fw_path, chipver_tag);
9229 strcat(nv_path, chipver_tag);
9230 return 0;
9231}
9232
9233static int concate_revision_bcm4354(dhd_bus_t *bus, char *fw_path, char *nv_path)
9234{
9235 uint32 chip_ver;
9236#if defined(SUPPORT_MULTIPLE_CHIPS)
9237 char chipver_tag[10] = "_4354";
9238#else
9239#if !defined(CUSTOMER_HW4)
9240 char chipver_tag[4] = {0, };
9241#endif /* !CUSTOMER_HW4 */
9242#endif /* SUPPORT_MULTIPLE_CHIPS */
9243
9244 chip_ver = bus->sih->chiprev;
9245#if !defined(SUPPORT_MULTIPLE_CHIPS) && defined(CUSTOMER_HW4)
9246 DHD_INFO(("----- CHIP 4354, ver=%x -----\n", chip_ver));
9247#else
9248 if (chip_ver == 1) {
9249 DHD_ERROR(("----- CHIP 4354 A1 -----\n"));
9250 strcat(chipver_tag, "_a1");
9251 } else {
9252 DHD_ERROR(("----- Unknown chip version, ver=%x -----\n", chip_ver));
9253 }
9254
9255 strcat(fw_path, chipver_tag);
9256 strcat(nv_path, chipver_tag);
9257#endif /* !SUPPORT_MULTIPLE_CHIPS && CUSTOMER_HW4 */
9258
9259 return 0;
9260}
9261
9262#ifdef SUPPORT_MULTIPLE_CHIP_4345X
9263static int
9264concate_revision_bcm4345x(dhd_bus_t *bus,
9265 char *fw_path, char *nv_path)
9266{
9267 uint32 chip_id;
9268 char chipver_tag[10] = "_43454";
9269
9270 chip_id = bus->sih->chip;
9271
9272 if (chip_id == BCM43454_CHIP_ID) {
9273 DHD_ERROR(("----- CHIP 43454 -----\n"));
9274 strcat(fw_path, chipver_tag);
9275 strcat(nv_path, chipver_tag);
9276 } else if (chip_id == BCM4345_CHIP_ID) {
9277 DHD_ERROR(("----- CHIP 43455 -----\n"));
9278 } else {
9279 DHD_ERROR(("----- Unknown chip , id r=%x -----\n", chip_id));
9280 }
9281
9282 return 0;
9283}
9284#else /* SUPPORT_MULTIPLE_CHIP_4345X */
9285static int
9286concate_revision_bcm43454(dhd_bus_t *bus, char *fw_path, char *nv_path)
9287{
9288 char chipver_tag[10] = {0, };
9289#ifdef SUPPORT_MULTIPLE_BOARD_REV_FROM_DT
9290 int base_system_rev_for_nv = 0;
9291#endif /* SUPPORT_MULTIPLE_BOARD_REV_FROM_DT */
9292
9293 DHD_TRACE(("%s: BCM43454 Multiple Revision Check\n", __FUNCTION__));
9294 if (bus->sih->chip != BCM43454_CHIP_ID) {
9295 DHD_ERROR(("%s:Chip is not BCM43454!\n", __FUNCTION__));
9296 return -1;
9297 }
9298#ifdef SUPPORT_MULTIPLE_BOARD_REV_FROM_DT
9299 base_system_rev_for_nv = dhd_get_system_rev();
9300 if (base_system_rev_for_nv > 0) {
9301 DHD_ERROR(("----- Board Rev [%d] -----\n", base_system_rev_for_nv));
9302 sprintf(chipver_tag, "_r%02d", base_system_rev_for_nv);
9303 }
9304#endif /* SUPPORT_MULTIPLE_BOARD_REV_FROM_DT */
9305#ifdef SUPPORT_MULTIPLE_BOARD_REV_FROM_HW
9306 DHD_ERROR(("----- Rev [%d] Fot MULTIPLE Board. -----\n", system_hw_rev));
9307 if ((system_hw_rev >= 8) && (system_hw_rev <= 11)) {
9308 DHD_ERROR(("This HW is Rev 08 ~ 11. this is For FD-HW\n"));
9309 strcat(chipver_tag, "_FD");
9310 }
9311#endif /* SUPPORT_MULTIPLE_BOARD_REV_FROM_HW */
9312
9313 strcat(nv_path, chipver_tag);
9314 return 0;
9315}
9316
9317static int
9318concate_revision_bcm43455(dhd_bus_t *bus, char *fw_path, char *nv_path)
9319{
9320 char chipver_tag[10] = {0, };
9321 uint32 chip_rev = 0;
9322#ifdef SUPPORT_MULTIPLE_BOARD_REV_FROM_DT
9323 int base_system_rev_for_nv = 0;
9324#endif /* SUPPORT_MULTIPLE_BOARD_REV_FROM_DT */
9325
9326 DHD_TRACE(("%s: BCM43455 Multiple Revision Check\n", __FUNCTION__));
9327 if (bus->sih->chip != BCM4345_CHIP_ID) {
9328 DHD_ERROR(("%s:Chip is not BCM43455!\n", __FUNCTION__));
9329 return -1;
9330 }
9331
9332 chip_rev = bus->sih->chiprev;
9333 if (chip_rev == 0x9) {
9334 DHD_ERROR(("----- CHIP 43456 -----\n"));
9335 strcat(fw_path, "_c5");
9336 strcat(nv_path, "_c5");
9337 } else {
9338 DHD_ERROR(("----- CHIP 43455 -----\n"));
9339 }
9340#ifdef SUPPORT_MULTIPLE_BOARD_REV_FROM_DT
9341 base_system_rev_for_nv = dhd_get_system_rev();
9342 if (base_system_rev_for_nv > 0) {
9343 DHD_ERROR(("----- Board Rev [%d]-----\n", base_system_rev_for_nv));
9344 sprintf(chipver_tag, "_r%02d", base_system_rev_for_nv);
9345 }
9346#endif /* SUPPORT_MULTIPLE_BOARD_REV_FROM_DT */
9347 strcat(nv_path, chipver_tag);
9348 return 0;
9349}
9350#endif /* SUPPORT_MULTIPLE_CHIP_4345X */
9351
5a068558
MB
9352static int
9353concate_revision_bcm43430(dhd_bus_t *bus, char *fw_path, char *nv_path)
9354{
9355
9356 uint chipver;
9357 char chipver_tag[4] = {0, };
9358
9359 DHD_TRACE(("%s: BCM43430 Multiple Revision Check\n", __FUNCTION__));
9360 if (bus->sih->chip != BCM43430_CHIP_ID) {
9361 DHD_ERROR(("%s:Chip is not BCM43430\n", __FUNCTION__));
9362 return BCME_ERROR;
9363 }
9364 chipver = bus->sih->chiprev;
9365 DHD_ERROR(("CHIP VER = [0x%x]\n", chipver));
9366 if (chipver == 0x0) {
9367 DHD_ERROR(("----- CHIP bcm4343S -----\n"));
9368 strcat(chipver_tag, "_3s");
9369 } else if (chipver == 0x1) {
9370 DHD_ERROR(("----- CHIP bcm43438 -----\n"));
9371 } else if (chipver == 0x2) {
9372 DHD_ERROR(("----- CHIP bcm43436L -----\n"));
9373 strcat(chipver_tag, "_36");
9374 } else {
9375 DHD_ERROR(("----- CHIP bcm43430 unknown revision %d -----\n",
9376 chipver));
9377 }
9378
9379 strcat(fw_path, chipver_tag);
9380 strcat(nv_path, chipver_tag);
9381 return 0;
9382}
9383
1cac41cb
MB
9384int
9385concate_revision(dhd_bus_t *bus, char *fw_path, char *nv_path)
9386{
9387 int res = 0;
9388
9389 if (!bus || !bus->sih) {
9390 DHD_ERROR(("%s:Bus is Invalid\n", __FUNCTION__));
9391 return -1;
9392 }
9393
9394 switch (bus->sih->chip) {
9395 case BCM4335_CHIP_ID:
9396 res = concate_revision_bcm4335(bus, fw_path, nv_path);
9397 break;
9398 case BCM4339_CHIP_ID:
9399 res = concate_revision_bcm4339(bus, fw_path, nv_path);
9400 break;
9401 case BCM4350_CHIP_ID:
9402 res = concate_revision_bcm4350(bus, fw_path, nv_path);
9403 break;
9404 case BCM4354_CHIP_ID:
9405 res = concate_revision_bcm4354(bus, fw_path, nv_path);
9406 break;
9407#ifdef SUPPORT_MULTIPLE_CHIP_4345X
9408 case BCM43454_CHIP_ID:
9409 case BCM4345_CHIP_ID:
9410 res = concate_revision_bcm4345x(bus, fw_path, nv_path);
9411 break;
9412#else /* SUPPORT_MULTIPLE_CHIP_4345X */
9413 case BCM43454_CHIP_ID:
9414 res = concate_revision_bcm43454(bus, fw_path, nv_path);
9415 break;
9416 case BCM4345_CHIP_ID:
9417 res = concate_revision_bcm43455(bus, fw_path, nv_path);
9418 break;
9419#endif /* SUPPORT_MULTIPLE_CHIP_4345X */
5a068558
MB
9420 case BCM43430_CHIP_ID:
9421 res = concate_revision_bcm43430(bus, fw_path, nv_path);
9422 break;
1cac41cb
MB
9423
9424 default:
9425 DHD_ERROR(("REVISION SPECIFIC feature is not required\n"));
9426 return res;
9427 }
9428
9429 if (res == 0) {
9430 }
9431 return res;
9432}
9433#endif /* SUPPORT_MULTIPLE_REVISION */
9434
9435void
9436dhd_bus_update_fw_nv_path(struct dhd_bus *bus, char *pfw_path, char *pnv_path)
9437{
9438 bus->fw_path = pfw_path;
9439 bus->nv_path = pnv_path;
9440}
9441
9442int
9443dhd_enableOOB(dhd_pub_t *dhd, bool sleep)
9444{
9445 dhd_bus_t *bus = dhd->bus;
9446 sdpcmd_regs_t *regs = bus->regs;
9447 uint retries = 0;
9448
9449 if (sleep) {
9450 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
9451 /* Tell device to start using OOB wakeup */
9452 W_SDREG(SMB_USE_OOB, &regs->tosbmailbox, retries);
9453 if (retries > retry_limit) {
9454 DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
9455 return BCME_BUSY;
9456 }
9457 /* Turn off our contribution to the HT clock request */
9458 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
9459 } else {
9460 /* Make sure the controller has the bus up */
9461 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
9462
9463 /* Send misc interrupt to indicate OOB not needed */
9464 W_SDREG(0, &regs->tosbmailboxdata, retries);
9465 if (retries <= retry_limit)
9466 W_SDREG(SMB_DEV_INT, &regs->tosbmailbox, retries);
9467
9468 if (retries > retry_limit)
9469 DHD_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n"));
9470
9471 /* Make sure we have SD bus access */
9472 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
9473 }
9474 return BCME_OK;
9475}
9476
9477void
9478dhd_bus_pktq_flush(dhd_pub_t *dhdp)
9479{
9480 dhd_bus_t *bus = dhdp->bus;
9481 bool wlfc_enabled = FALSE;
9482
9483#ifdef PROP_TXSTATUS
9484 wlfc_enabled = (dhd_wlfc_cleanup_txq(dhdp, NULL, 0) != WLFC_UNSUPPORTED);
9485#endif // endif
9486 if (!wlfc_enabled) {
9487#ifdef DHDTCPACK_SUPPRESS
9488 /* Clean tcp_ack_info_tbl in order to prevent access to flushed pkt,
9489 * when there is a newly coming packet from network stack.
9490 */
9491 dhd_tcpack_info_tbl_clean(bus->dhd);
9492#endif /* DHDTCPACK_SUPPRESS */
9493 /* Clear the data packet queues */
9494 pktq_flush(dhdp->osh, &bus->txq, TRUE);
9495 }
9496}
9497
9498#ifdef BCMSDIO
9499int
9500dhd_sr_config(dhd_pub_t *dhd, bool on)
9501{
9502 dhd_bus_t *bus = dhd->bus;
9503
9504 if (!bus->_srenab)
9505 return -1;
9506
9507 return dhdsdio_clk_devsleep_iovar(bus, on);
9508}
9509
9510uint16
9511dhd_get_chipid(dhd_pub_t *dhd)
9512{
9513 dhd_bus_t *bus = dhd->bus;
9514
9515 if (bus && bus->sih)
9516 return (uint16)bus->sih->chip;
9517 else
9518 return 0;
9519}
9520#endif /* BCMSDIO */
9521
9522#ifdef DEBUGGER
9523static uint32
9524dhd_sdio_reg_read(struct dhd_bus *bus, ulong addr)
9525{
9526 uint32 rval;
9527
9528 dhd_os_sdlock(bus->dhd);
9529
9530 BUS_WAKE(bus);
9531
9532 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
9533
9534 rval = bcmsdh_reg_read(bus->sdh, addr, 4);
9535
9536 dhd_os_sdunlock(bus->dhd);
9537
9538 return rval;
9539}
9540
9541static void
9542dhd_sdio_reg_write(struct dhd_bus *bus, ulong addr, uint32 val)
9543{
9544 dhd_os_sdlock(bus->dhd);
9545
9546 BUS_WAKE(bus);
9547
9548 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
9549
9550 bcmsdh_reg_write(bus->sdh, addr, 4, val);
9551
9552 dhd_os_sdunlock(bus->dhd);
9553}
9554
9555#endif /* DEBUGGER */
9556
9557#if defined(BT_OVER_SDIO)
9558uint8 dhd_bus_cfg_read(void *h, uint fun_num, uint32 addr, int *err)
9559{
9560 uint8 intrd;
9561 dhd_pub_t *dhdp = (dhd_pub_t *)h;
9562 dhd_bus_t *bus = (dhd_bus_t *)dhdp->bus;
9563
9564 dhd_os_sdlock(bus->dhd);
9565
9566 intrd = bcmsdh_cfg_read(bus->sdh, fun_num, addr, err);
9567
9568 dhd_os_sdunlock(bus->dhd);
9569
9570 return intrd;
9571} EXPORT_SYMBOL(dhd_bus_cfg_read);
9572
9573void dhd_bus_cfg_write(void *h, uint fun_num, uint32 addr, uint8 val, int *err)
9574{
9575 dhd_pub_t *dhdp = (dhd_pub_t *)h;
9576 dhd_bus_t *bus = (dhd_bus_t *)dhdp->bus;
9577
9578 dhd_os_sdlock(bus->dhd);
9579
9580 bcmsdh_cfg_write(bus->sdh, fun_num, addr, val, err);
9581
9582 dhd_os_sdunlock(bus->dhd);
9583
9584} EXPORT_SYMBOL(dhd_bus_cfg_write);
9585
9586static int
9587extract_hex_field(char * line, uint16 start_pos, uint16 num_chars, uint16 * value)
9588{
9589 char field [8];
9590
9591 strncpy(field, line + start_pos, num_chars);
9592 field [num_chars] = '\0';
9593
9594 return (sscanf (field, "%hX", value) == 1);
9595}
9596
9597static int
9598read_more_btbytes(struct dhd_bus *bus, void * file, char *line, int * addr_mode, uint16 * hi_addr,
9599 uint32 * dest_addr, uint8 *data_bytes, uint32 * num_bytes)
9600{
9601 int str_len;
9602 uint16 num_data_bytes, addr, data_pos, type, w, i;
9603 uint32 abs_base_addr32 = 0;
9604 *num_bytes = 0;
9605
9606 while (!*num_bytes)
9607 {
9608 str_len = dhd_os_gets_image(bus->dhd, line, BTFW_MAX_STR_LEN, file);
9609
9610 DHD_TRACE(("%s: Len :0x%x %s\n", __FUNCTION__, str_len, line));
9611
9612 if (str_len == 0) {
9613 break;
9614 } else if (str_len > 9) {
9615 extract_hex_field(line, 1, 2, &num_data_bytes);
9616 extract_hex_field(line, 3, 4, &addr);
9617 extract_hex_field(line, 7, 2, &type);
9618
9619 data_pos = 9;
9620 for (i = 0; i < num_data_bytes; i++) {
9621 extract_hex_field(line, data_pos, 2, &w);
9622 data_bytes [i] = (uint8)(w & 0x00FF);
9623 data_pos += 2;
9624 }
9625
9626 if (type == BTFW_HEX_LINE_TYPE_EXTENDED_ADDRESS) {
9627 *hi_addr = (data_bytes [0] << 8) | data_bytes [1];
9628 *addr_mode = BTFW_ADDR_MODE_EXTENDED;
9629 } else if (type == BTFW_HEX_LINE_TYPE_EXTENDED_SEGMENT_ADDRESS) {
9630 *hi_addr = (data_bytes [0] << 8) | data_bytes [1];
9631 *addr_mode = BTFW_ADDR_MODE_SEGMENT;
9632 } else if (type == BTFW_HEX_LINE_TYPE_ABSOLUTE_32BIT_ADDRESS) {
9633 abs_base_addr32 = (data_bytes [0] << 24) | (data_bytes [1] << 16) |
9634 (data_bytes [2] << 8) | data_bytes [3];
9635 *addr_mode = BTFW_ADDR_MODE_LINEAR32;
9636 } else if (type == BTFW_HEX_LINE_TYPE_DATA) {
9637 *dest_addr = addr;
9638 if (*addr_mode == BTFW_ADDR_MODE_EXTENDED)
9639 *dest_addr += (*hi_addr << 16);
9640 else if (*addr_mode == BTFW_ADDR_MODE_SEGMENT)
9641 *dest_addr += (*hi_addr << 4);
9642 else if (*addr_mode == BTFW_ADDR_MODE_LINEAR32)
9643 *dest_addr += abs_base_addr32;
9644 *num_bytes = num_data_bytes;
9645 }
9646 }
9647 }
9648 return (*num_bytes > 0);
9649}
9650
9651static int
9652_dhdsdio_download_btfw(struct dhd_bus *bus)
9653{
9654 int bcm_error = -1;
9655 void *image = NULL;
9656 uint8 *mem_blk = NULL, *mem_ptr = NULL, *data_ptr = NULL;
9657
9658 uint32 offset_addr = 0, offset_len = 0, bytes_to_write = 0;
9659
9660 char *line = NULL;
9661 uint32 dest_addr = 0, num_bytes;
9662 uint16 hiAddress = 0;
9663 uint32 start_addr, start_data, end_addr, end_data, i, index, pad,
9664 bt2wlan_pwrup_adr;
9665
9666 int addr_mode = BTFW_ADDR_MODE_EXTENDED;
9667
9668 /* Out immediately if no image to download */
9669 if ((bus->btfw_path == NULL) || (bus->btfw_path[0] == '\0')) {
9670 return 0;
9671 }
9672
9673 image = dhd_os_open_image1(bus->dhd, bus->btfw_path);
9674 if (image == NULL)
9675 goto err;
9676
9677 mem_ptr = mem_blk = MALLOC(bus->dhd->osh, BTFW_DOWNLOAD_BLK_SIZE + DHD_SDALIGN);
9678 if (mem_blk == NULL) {
9679 DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__,
9680 BTFW_DOWNLOAD_BLK_SIZE + DHD_SDALIGN));
9681 goto err;
9682 }
9683 if ((uint32)(uintptr)mem_blk % DHD_SDALIGN)
9684 mem_ptr += (DHD_SDALIGN - ((uint32)(uintptr)mem_blk % DHD_SDALIGN));
9685
9686 data_ptr = MALLOC(bus->dhd->osh, BTFW_DOWNLOAD_BLK_SIZE - 8);
9687 if (data_ptr == NULL) {
9688 DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__,
9689 BTFW_DOWNLOAD_BLK_SIZE - 8));
9690 goto err;
9691 }
9692 /* Write to BT register to hold WLAN wake high during BT FW download */
9693 bt2wlan_pwrup_adr = BTMEM_OFFSET + BT2WLAN_PWRUP_ADDR;
9694 bcmsdh_reg_write(bus->sdh, bt2wlan_pwrup_adr, 4, BT2WLAN_PWRUP_WAKE);
9695 /*
9696 * Wait for at least 2msec for the clock to be ready/Available.
9697 */
9698 OSL_DELAY(2000);
9699
9700 line = MALLOC(bus->dhd->osh, BTFW_MAX_STR_LEN);
9701 if (line == NULL) {
9702 DHD_ERROR(("%s: Failed to allocate memory %d bytes\n",
9703 __FUNCTION__, BTFW_MAX_STR_LEN));
9704 goto err;
9705 }
9706 memset(line, 0, BTFW_MAX_STR_LEN);
9707
9708 while (read_more_btbytes (bus, image, line, &addr_mode, &hiAddress, &dest_addr,
9709 data_ptr, &num_bytes)) {
9710
9711 DHD_TRACE(("read %d bytes at address %08X\n", num_bytes, dest_addr));
9712
9713 start_addr = BTMEM_OFFSET + dest_addr;
9714 index = 0;
9715
9716 /* Make sure the start address is 4 byte aligned to avoid alignment issues
9717 * with SD host controllers
9718 */
9719 if (!ISALIGNED(start_addr, 4)) {
9720 pad = start_addr % 4;
9721 start_addr = ROUNDDN(start_addr, 4);
9722 start_data = bcmsdh_reg_read(bus->sdh, start_addr, 4);
9723 for (i = 0; i < pad; i++, index++) {
9724 mem_ptr[index] = (uint8)((uint8 *)&start_data)[i];
9725 }
9726 }
9727 bcopy(data_ptr, &(mem_ptr[index]), num_bytes);
9728 index += num_bytes;
9729
9730 /* Make sure the length is multiple of 4bytes to avoid alignment issues
9731 * with SD host controllers
9732 */
9733 end_addr = start_addr + index;
9734 if (!ISALIGNED(end_addr, 4)) {
9735 end_addr = ROUNDDN(end_addr, 4);
9736 end_data = bcmsdh_reg_read(bus->sdh, end_addr, 4);
9737 for (i = (index % 4); i < 4; i++, index++) {
9738 mem_ptr[index] = (uint8)((uint8 *)&end_data)[i];
9739 }
9740 }
9741
9742 offset_addr = start_addr & 0xFFF;
9743 offset_len = offset_addr + index;
9744 if (offset_len <= 0x1000) {
9745 bcm_error = dhdsdio_membytes(bus, TRUE, start_addr, mem_ptr, index);
9746 if (bcm_error) {
9747 DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
9748 __FUNCTION__, bcm_error, num_bytes, start_addr));
9749 goto err;
9750 }
9751 }
9752 else {
9753 bytes_to_write = 0x1000 - offset_addr;
9754 bcm_error = dhdsdio_membytes(bus, TRUE, start_addr, mem_ptr,
9755 bytes_to_write);
9756 if (bcm_error) {
9757 DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
9758 __FUNCTION__, bcm_error, num_bytes, start_addr));
9759 goto err;
9760 }
9761
9762 OSL_DELAY(10000);
9763
9764 bcm_error = dhdsdio_membytes(bus, TRUE, (start_addr + bytes_to_write),
9765 (mem_ptr + bytes_to_write), (index - bytes_to_write));
9766 if (bcm_error) {
9767 DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
9768 __FUNCTION__, bcm_error, num_bytes, start_addr));
9769 goto err;
9770 }
9771 }
9772 memset(line, 0, BTFW_MAX_STR_LEN);
9773 }
9774
9775 bcm_error = 0;
9776err:
9777 if (mem_blk)
9778 MFREE(bus->dhd->osh, mem_blk, BTFW_DOWNLOAD_BLK_SIZE + DHD_SDALIGN);
9779
9780 if (data_ptr)
9781 MFREE(bus->dhd->osh, data_ptr, BTFW_DOWNLOAD_BLK_SIZE - 8);
9782
9783 if (line)
9784 MFREE(bus->dhd->osh, line, BTFW_MAX_STR_LEN);
9785
9786 if (image)
9787 dhd_os_close_image1(bus->dhd, image);
9788
9789 return bcm_error;
9790}
9791
9792static int
9793dhdsdio_download_btfw(struct dhd_bus *bus, osl_t *osh, void *sdh)
9794{
9795 int ret;
9796
9797 DHD_TRACE(("%s: btfw path=%s\n",
9798 __FUNCTION__, bus->btfw_path));
9799 DHD_OS_WAKE_LOCK(bus->dhd);
9800 dhd_os_sdlock(bus->dhd);
9801
9802 /* Download the firmware */
9803 ret = _dhdsdio_download_btfw(bus);
9804
9805 dhd_os_sdunlock(bus->dhd);
9806 DHD_OS_WAKE_UNLOCK(bus->dhd);
9807
9808 return ret;
9809}
9810
9811int
9812dhd_bus_download_btfw(struct dhd_bus *bus, osl_t *osh,
9813 char *pbtfw_path)
9814{
9815 int ret;
9816
9817 bus->btfw_path = pbtfw_path;
9818
9819 ret = dhdsdio_download_btfw(bus, osh, bus->sdh);
9820
9821 return ret;
9822}
9823#endif /* defined (BT_OVER_SDIO) */
9824
9825void
9826dhd_bus_dump_trap_info(dhd_bus_t *bus, struct bcmstrbuf *strbuf)
9827{
9828 trap_t *tr = &bus->dhd->last_trap_info;
9829
9830 bcm_bprintf(strbuf,
9831 "Dongle trap type 0x%x @ epc 0x%x, cpsr 0x%x, spsr 0x%x, sp 0x%x,"
9832 "lp 0x%x, rpc 0x%x Trap offset 0x%x, "
9833 "r0 0x%x, r1 0x%x, r2 0x%x, r3 0x%x, "
9834 "r4 0x%x, r5 0x%x, r6 0x%x, r7 0x%x\n\n",
9835 ltoh32(tr->type), ltoh32(tr->epc), ltoh32(tr->cpsr), ltoh32(tr->spsr),
9836 ltoh32(tr->r13), ltoh32(tr->r14), ltoh32(tr->pc),
9837 ltoh32(bus->dongle_trap_addr),
9838 ltoh32(tr->r0), ltoh32(tr->r1), ltoh32(tr->r2), ltoh32(tr->r3),
9839 ltoh32(tr->r4), ltoh32(tr->r5), ltoh32(tr->r6), ltoh32(tr->r7));
9840
9841}
9842
9843static int
9844dhd_bcmsdh_send_buffer(void *bus, uint8 *frame, uint16 len)
9845{
9846 int ret = -1;
9847
9848 ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(((dhd_bus_t*)bus)->sdh),
9849 SDIO_FUNC_2, F2SYNC, frame, len, NULL, NULL, NULL, TXRETRIES);
9850
9851 if (ret == BCME_OK)
9852 ((dhd_bus_t*)bus)->tx_seq = (((dhd_bus_t*)bus)->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
9853
9854 return ret;
9855}
9856
9857/* Function to set the min res mask depending on the chip ID used */
9858bool
9859dhd_bus_set_default_min_res_mask(struct dhd_bus *bus)
9860{
9861 if ((bus == NULL) || (bus->sih == NULL)) {
9862 DHD_ERROR(("%s(): Invalid Arguments \r\n", __FUNCTION__));
9863 return FALSE;
9864 }
9865
9866 switch (bus->sih->chip) {
9867 case BCM4339_CHIP_ID:
9868 bcmsdh_reg_write(bus->sdh, SI_ENUM_BASE(bus->sih) + 0x618, 4, 0x3fcaf377);
9869 if (bcmsdh_regfail(bus->sdh)) {
9870 DHD_ERROR(("%s:%d Setting min_res_mask failed\n", __FUNCTION__, __LINE__));
9871 return FALSE;
9872 }
9873 break;
9874
9875 case BCM43012_CHIP_ID:
9876 bcmsdh_reg_write(bus->sdh,
9877 si_get_pmu_reg_addr(bus->sih, OFFSETOF(pmuregs_t, min_res_mask)),
9878 4, DEFAULT_43012_MIN_RES_MASK);
9879 if (bcmsdh_regfail(bus->sdh)) {
9880 DHD_ERROR(("%s:%d Setting min_res_mask failed\n", __FUNCTION__, __LINE__));
9881 return FALSE;
9882 }
9883 break;
9884
9885 default:
9886 DHD_ERROR(("%s: Unhandled chip id\n", __FUNCTION__));
9887 return FALSE;
9888 }
9889
9890 return TRUE;
9891}
9892
9893/* Function to reset PMU registers */
9894void
9895dhd_bus_pmu_reg_reset(dhd_pub_t *dhdp)
9896{
9897 struct dhd_bus *bus = dhdp->bus;
9898 bcmsdh_reg_write(bus->sdh, si_get_pmu_reg_addr(bus->sih,
9899 OFFSETOF(pmuregs_t, swscratch)), 4, 0x0);
9900 if (bcmsdh_regfail(bus->sdh)) {
9901 DHD_ERROR(("%s:%d Setting min_res_mask failed\n", __FUNCTION__, __LINE__));
9902 }
9903}
9904
9905#ifdef DHD_ULP
9906
9907/* Function to disable console messages on entering ULP mode */
9908void
9909dhd_bus_ulp_disable_console(dhd_pub_t *dhdp)
9910{
9911#ifdef DHD_DEBUG
9912 DHD_ERROR(("Flushing and disabling console messages\n"));
9913
9914 /* Save the console print interval */
9915 dhd_ulp_save_console_interval(dhdp);
9916
9917 /* Flush the console buffer before disabling */
9918 dhdsdio_readconsole(dhdp->bus);
9919 dhdp->dhd_console_ms = 0;
9920#endif /* DHD_DEBUG */
9921}
9922
9923/* Function for redownloading firmaware */
9924static int
9925dhd_bus_ulp_reinit_fw(dhd_bus_t *bus)
9926{
9927 int bcmerror = 0;
9928
9929 /* After firmware redownload tx/rx seq are reset accordingly these values are
9930 reset on DHD side tx_max is initially set to 4, which later is updated by FW
9931 */
9932 bus->tx_seq = bus->rx_seq = 0;
9933 bus->tx_max = 4;
9934
9935 if (dhd_bus_download_firmware(bus, bus->dhd->osh,
9936 bus->fw_path, bus->nv_path) >= 0) {
9937
9938 /* Re-init bus, enable F2 transfer */
9939 bcmerror = dhd_bus_init((dhd_pub_t *) bus->dhd, FALSE);
9940 if (bcmerror == BCME_OK) {
9941 bus->dhd->up = TRUE;
9942 dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
9943
9944 dhd_ulp_set_ulp_state(bus->dhd, DHD_ULP_READY);
9945#if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
9946 dhd_enable_oob_intr(bus, TRUE);
9947 bcmsdh_oob_intr_set(bus->sdh, TRUE);
9948#endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */
9949#ifdef DHD_DEBUG
9950 /* Re-enable the console messages on FW redownload to default value */
9951 dhd_ulp_restore_console_interval(bus->dhd);
9952#endif /* DHD_DEBUG */
9953 } else {
9954 DHD_ERROR(("bus init failed\n"));
9955 dhd_bus_stop(bus, FALSE);
9956 dhdsdio_release_dongle(bus, bus->dhd->osh,
9957 TRUE, FALSE);
9958 }
9959 } else
9960 bcmerror = BCME_SDIO_ERROR;
9961
9962 return bcmerror;
9963}
9964#endif /* DHD_ULP */
9965
9966int
9967dhd_bus_readwrite_bp_addr(dhd_pub_t *dhdp, uint addr, uint size, uint* data, bool read)
9968{
9969 int bcmerror = 0;
9970 struct dhd_bus *bus = dhdp->bus;
9971
9972 if (read) {
9973 *data = (int32)bcmsdh_reg_read(bus->sdh, addr, size);
9974 } else {
9975 bcmsdh_reg_write(bus->sdh, addr, size, *data);
9976 }
9977
9978 if (bcmsdh_regfail(bus->sdh))
9979 bcmerror = BCME_SDIO_ERROR;
9980
9981 return bcmerror;
9982}
9983
9984int dhd_get_idletime(dhd_pub_t *dhd)
9985{
9986 return dhd->bus->idletime;
9987}
9988
9989#ifdef DHD_WAKE_STATUS
9990wake_counts_t*
9991dhd_bus_get_wakecount(dhd_pub_t *dhd)
9992{
9993 return &dhd->bus->wake_counts;
9994}
9995int
9996dhd_bus_get_bus_wake(dhd_pub_t *dhd)
9997{
9998 return bcmsdh_set_get_wake(dhd->bus->sdh, 0);
9999}
10000#endif /* DHD_WAKE_STATUS */