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