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