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