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