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