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