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