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