Merge branch 'develop-3.0' of ssh://192.168.1.29/rk/kernel into develop-3.0
[firefly-linux-kernel-4.4.55.git] / drivers / net / wireless / bcm4319 / dhd_sdio.c
1 /*
2  * DHD Bus Module for SDIO
3  *
4  * Copyright (C) 1999-2010, Broadcom Corporation
5  * 
6  *      Unless you and Broadcom execute a separate written software license
7  * agreement governing use of this software, this software is licensed to you
8  * under the terms of the GNU General Public License version 2 (the "GPL"),
9  * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10  * following added to such license:
11  * 
12  *      As a special exception, the copyright holders of this software give you
13  * permission to link this software with independent modules, and to copy and
14  * distribute the resulting executable under terms of your choice, provided that
15  * you also meet, for each linked independent module, the terms and conditions of
16  * the license of that module.  An independent module is a module which is not
17  * derived from this software.  The special exception does not apply to any
18  * modifications of the software.
19  * 
20  *      Notwithstanding the above, under no circumstances may you combine this
21  * software in any way with any other Broadcom software provided under a license
22  * other than the GPL, without Broadcom's express prior written consent.
23  *
24  * $Id: dhd_sdio.c,v 1.157.2.27.2.33.2.126 2010/06/15 23:38:39 Exp $
25  */
26
27 #include <typedefs.h>
28 #include <osl.h>
29 #include <bcmsdh.h>
30
31 #ifdef BCMEMBEDIMAGE
32 #include BCMEMBEDIMAGE
33 #endif /* BCMEMBEDIMAGE */
34
35 #include <bcmdefs.h>
36 #include <bcmutils.h>
37 #include <bcmendian.h>
38 #include <bcmdevs.h>
39
40 #include <siutils.h>
41 #include <hndpmu.h>
42 #include <hndsoc.h>
43 #ifdef DHD_DEBUG
44 #include <hndrte_armtrap.h>
45 #include <hndrte_cons.h>
46 #endif /* DHD_DEBUG */
47 #include <sbchipc.h>
48 #include <sbhnddma.h>
49
50 #include <sdio.h>
51 #include <sbsdio.h>
52 #include <sbsdpcmdev.h>
53 #include <bcmsdpcm.h>
54
55 #include <proto/ethernet.h>
56 #include <proto/802.1d.h>
57 #include <proto/802.11.h>
58
59 #include <dngl_stats.h>
60 #include <dhd.h>
61 #include <dhd_bus.h>
62 #include <dhd_proto.h>
63 #include <dhd_dbg.h>
64 #include <dhdioctl.h>
65 #include <sdiovar.h>
66
67 #ifndef DHDSDIO_MEM_DUMP_FNAME
68 #define DHDSDIO_MEM_DUMP_FNAME         "mem_dump"
69 #endif
70
71 #define QLEN            256     /* bulk rx and tx queue lengths */
72 #define FCHI            (QLEN - 10)
73 #define FCLOW           (FCHI / 2)
74 #define PRIOMASK        7
75
76 #define TXRETRIES       2       /* # of retries for tx frames */
77
78 #if defined(CONFIG_MACH_SANDGATE2G)
79 #define DHD_RXBOUND     250     /* Default for max rx frames in one scheduling */
80 #else
81 #define DHD_RXBOUND     50      /* Default for max rx frames in one scheduling */
82 #endif /* defined(CONFIG_MACH_SANDGATE2G) */
83
84 #define DHD_TXBOUND     20      /* Default for max tx frames in one scheduling */
85
86 #define DHD_TXMINMAX    1       /* Max tx frames if rx still pending */
87
88 #define MEMBLOCK        2048            /* Block size used for downloading of dongle image */
89 #define MAX_DATA_BUF    (32 * 1024)     /* Must be large enough to hold biggest possible glom */
90
91 /* Packet alignment for most efficient SDIO (can change based on platform) */
92 #ifndef DHD_SDALIGN
93 #define DHD_SDALIGN     32
94 #endif
95 #if !ISPOWEROF2(DHD_SDALIGN)
96 #error DHD_SDALIGN is not a power of 2!
97 #endif
98
99 #ifndef DHD_FIRSTREAD
100 #define DHD_FIRSTREAD   32
101 #endif
102 #if !ISPOWEROF2(DHD_FIRSTREAD)
103 #error DHD_FIRSTREAD is not a power of 2!
104 #endif
105
106 /* Total length of frame header for dongle protocol */
107 #define SDPCM_HDRLEN    (SDPCM_FRAMETAG_LEN + SDPCM_SWHEADER_LEN)
108 #ifdef SDTEST
109 #define SDPCM_RESERVE   (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN)
110 #else
111 #define SDPCM_RESERVE   (SDPCM_HDRLEN + DHD_SDALIGN)
112 #endif
113
114 /* Space for header read, limit for data packets */
115 #ifndef MAX_HDR_READ
116 #define MAX_HDR_READ    32
117 #endif
118 #if !ISPOWEROF2(MAX_HDR_READ)
119 #error MAX_HDR_READ is not a power of 2!
120 #endif
121
122 #define MAX_RX_DATASZ   2048
123
124 /* Maximum milliseconds to wait for F2 to come up */
125 #define DHD_WAIT_F2RDY  3000
126
127 /* Bump up limit on waiting for HT to account for first startup;
128  * if the image is doing a CRC calculation before programming the PMU
129  * for HT availability, it could take a couple hundred ms more, so
130  * max out at a half second (500000us).
131  */
132 #if (PMU_MAX_TRANSITION_DLY <= 500000)
133 #undef PMU_MAX_TRANSITION_DLY
134 #define PMU_MAX_TRANSITION_DLY 500000
135 #endif
136
137 /* Value for ChipClockCSR during initial setup */
138 #define DHD_INIT_CLKCTL1        (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ)
139 #define DHD_INIT_CLKCTL2        (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP)
140
141 /* Flags for SDH calls */
142 #define F2SYNC  (SDIO_REQ_4BYTE | SDIO_REQ_FIXED)
143
144 /* Packet free applicable unconditionally for sdio and sdspi.  Conditional if
145  * bufpool was present for gspi bus.
146  */
147 #define PKTFREE2()              if ((bus->bus != SPI_BUS) || bus->usebufpool) \
148                                         PKTFREE(bus->dhd->osh, pkt, FALSE);
149 DHD_SPINWAIT_SLEEP_INIT(sdioh_spinwait_sleep);
150 extern int dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len);
151
152 #ifdef DHD_DEBUG
153 /* Device console log buffer state */
154 typedef struct dhd_console {
155         uint            count;                  /* Poll interval msec counter */
156         uint            log_addr;               /* Log struct address (fixed) */
157         hndrte_log_t    log;                    /* Log struct (host copy) */
158         uint            bufsize;                /* Size of log buffer */
159         uint8           *buf;                   /* Log buffer (host copy) */
160         uint            last;                   /* Last buffer read index */
161 } dhd_console_t;
162 #endif /* DHD_DEBUG */
163
164 /* Private data for SDIO bus interaction */
165 typedef struct dhd_bus {
166         dhd_pub_t       *dhd;
167
168         bcmsdh_info_t   *sdh;                   /* Handle for BCMSDH calls */
169         si_t            *sih;                   /* Handle for SI calls */
170         char            *vars;                  /* Variables (from CIS and/or other) */
171         uint            varsz;                  /* Size of variables buffer */
172         uint32          sbaddr;                 /* Current SB window pointer (-1, invalid) */
173
174         sdpcmd_regs_t   *regs;                  /* Registers for SDIO core */
175         uint            sdpcmrev;               /* SDIO core revision */
176         uint            armrev;                 /* CPU core revision */
177         uint            ramrev;                 /* SOCRAM core revision */
178         uint32          ramsize;                /* Size of RAM in SOCRAM (bytes) */
179         uint32          orig_ramsize;           /* Size of RAM in SOCRAM (bytes) */
180
181         uint32          bus;                    /* gSPI or SDIO bus */
182         uint32          hostintmask;            /* Copy of Host Interrupt Mask */
183         uint32          intstatus;              /* Intstatus bits (events) pending */
184         bool            dpc_sched;              /* Indicates DPC schedule (intrpt rcvd) */
185         bool            fcstate;                /* State of dongle flow-control */
186
187         uint16          cl_devid;               /* cached devid for dhdsdio_probe_attach() */
188         char            *fw_path; /* module_param: path to firmware image */
189         char            *nv_path; /* module_param: path to nvram vars file */
190         const char      *nvram_params;          /* user specified nvram params. */
191
192         uint            blocksize;              /* Block size of SDIO transfers */
193         uint            roundup;                /* Max roundup limit */
194
195         struct pktq     txq;                    /* Queue length used for flow-control */
196         uint8           flowcontrol;            /* per prio flow control bitmask */
197         uint8           tx_seq;                 /* Transmit sequence number (next) */
198         uint8           tx_max;                 /* Maximum transmit sequence allowed */
199
200         uint8           hdrbuf[MAX_HDR_READ + DHD_SDALIGN];
201         uint8           *rxhdr;                 /* Header of current rx frame (in hdrbuf) */
202         uint16          nextlen;                /* Next Read Len from last header */
203         uint8           rx_seq;                 /* Receive sequence number (expected) */
204         bool            rxskip;                 /* Skip receive (awaiting NAK ACK) */
205
206         void            *glomd;                 /* Packet containing glomming descriptor */
207         void            *glom;                  /* Packet chain for glommed superframe */
208         uint            glomerr;                /* Glom packet read errors */
209
210         uint8           *rxbuf;                 /* Buffer for receiving control packets */
211         uint            rxblen;                 /* Allocated length of rxbuf */
212         uint8           *rxctl;                 /* Aligned pointer into rxbuf */
213         uint8           *databuf;               /* Buffer for receiving big glom packet */
214         uint8           *dataptr;               /* Aligned pointer into databuf */
215         uint            rxlen;                  /* Length of valid data in buffer */
216
217         uint8           sdpcm_ver;              /* Bus protocol reported by dongle */
218
219         bool            intr;                   /* Use interrupts */
220         bool            poll;                   /* Use polling */
221         bool            ipend;                  /* Device interrupt is pending */
222         bool            intdis;                 /* Interrupts disabled by isr */
223         uint            intrcount;              /* Count of device interrupt callbacks */
224         uint            lastintrs;              /* Count as of last watchdog timer */
225         uint            spurious;               /* Count of spurious interrupts */
226         uint            pollrate;               /* Ticks between device polls */
227         uint            polltick;               /* Tick counter */
228         uint            pollcnt;                /* Count of active polls */
229
230 #ifdef DHD_DEBUG
231         dhd_console_t   console;                /* Console output polling support */
232         uint            console_addr;           /* Console address from shared struct */
233 #endif /* DHD_DEBUG */
234
235         uint            regfails;               /* Count of R_REG/W_REG failures */
236
237         uint            clkstate;               /* State of sd and backplane clock(s) */
238         bool            activity;               /* Activity flag for clock down */
239         int32           idletime;               /* Control for activity timeout */
240         int32           idlecount;              /* Activity timeout counter */
241         int32           idleclock;              /* How to set bus driver when idle */
242         int32           sd_divisor;             /* Speed control to bus driver */
243         int32           sd_mode;                /* Mode control to bus driver */
244         int32           sd_rxchain;             /* If bcmsdh api accepts PKT chains */
245         bool            use_rxchain;            /* If dhd should use PKT chains */
246         bool            sleeping;               /* Is SDIO bus sleeping? */
247         bool            rxflow_mode;    /* Rx flow control mode */
248         bool            rxflow;                 /* Is rx flow control on */
249         uint            prev_rxlim_hit;         /* Is prev rx limit exceeded (per dpc schedule) */
250         bool            alp_only;               /* Don't use HT clock (ALP only) */
251         /* Field to decide if rx of control frames happen in rxbuf or lb-pool */
252         bool            usebufpool;
253
254 #ifdef SDTEST
255         /* external loopback */
256         bool            ext_loop;
257         uint8           loopid;
258
259         /* pktgen configuration */
260         uint            pktgen_freq;            /* Ticks between bursts */
261         uint            pktgen_count;           /* Packets to send each burst */
262         uint            pktgen_print;           /* Bursts between count displays */
263         uint            pktgen_total;           /* Stop after this many */
264         uint            pktgen_minlen;          /* Minimum packet data len */
265         uint            pktgen_maxlen;          /* Maximum packet data len */
266         uint            pktgen_mode;            /* Configured mode: tx, rx, or echo */
267         uint            pktgen_stop;            /* Number of tx failures causing stop */
268
269         /* active pktgen fields */
270         uint            pktgen_tick;            /* Tick counter for bursts */
271         uint            pktgen_ptick;           /* Burst counter for printing */
272         uint            pktgen_sent;            /* Number of test packets generated */
273         uint            pktgen_rcvd;            /* Number of test packets received */
274         uint            pktgen_fail;            /* Number of failed send attempts */
275         uint16          pktgen_len;             /* Length of next packet to send */
276 #endif /* SDTEST */
277
278         /* Some additional counters */
279         uint            tx_sderrs;              /* Count of tx attempts with sd errors */
280         uint            fcqueued;               /* Tx packets that got queued */
281         uint            rxrtx;                  /* Count of rtx requests (NAK to dongle) */
282         uint            rx_toolong;             /* Receive frames too long to receive */
283         uint            rxc_errors;             /* SDIO errors when reading control frames */
284         uint            rx_hdrfail;             /* SDIO errors on header reads */
285         uint            rx_badhdr;              /* Bad received headers (roosync?) */
286         uint            rx_badseq;              /* Mismatched rx sequence number */
287         uint            fc_rcvd;                /* Number of flow-control events received */
288         uint            fc_xoff;                /* Number which turned on flow-control */
289         uint            fc_xon;                 /* Number which turned off flow-control */
290         uint            rxglomfail;             /* Failed deglom attempts */
291         uint            rxglomframes;           /* Number of glom frames (superframes) */
292         uint            rxglompkts;             /* Number of packets from glom frames */
293         uint            f2rxhdrs;               /* Number of header reads */
294         uint            f2rxdata;               /* Number of frame data reads */
295         uint            f2txdata;               /* Number of f2 frame writes */
296         uint            f1regdata;              /* Number of f1 register accesses */
297
298         uint8           *ctrl_frame_buf;
299         uint32          ctrl_frame_len;
300         bool            ctrl_frame_stat;
301 } dhd_bus_t;
302
303 /* clkstate */
304 #define CLK_NONE        0
305 #define CLK_SDONLY      1
306 #define CLK_PENDING     2       /* Not used yet */
307 #define CLK_AVAIL       3
308
309 #define DHD_NOPMU(dhd)  (FALSE)
310
311 #ifdef DHD_DEBUG
312 static int qcount[NUMPRIO];
313 static int tx_packets[NUMPRIO];
314 #endif /* DHD_DEBUG */
315
316 /* Deferred transmit */
317 const uint dhd_deferred_tx = 1;
318
319 extern uint dhd_watchdog_ms;
320 extern void dhd_os_wd_timer(void *bus, uint wdtick);
321
322 /* Tx/Rx bounds */
323 uint dhd_txbound;
324 uint dhd_rxbound;
325 uint dhd_txminmax;
326
327 /* override the RAM size if possible */
328 #define DONGLE_MIN_MEMSIZE (128 *1024)
329 int dhd_dongle_memsize;
330
331 static bool dhd_doflow;
332 static bool dhd_alignctl;
333
334 static bool sd1idle;
335
336 static bool retrydata;
337 #define RETRYCHAN(chan) (((chan) == SDPCM_EVENT_CHANNEL) || retrydata)
338
339 static const uint watermark = 8;
340 static const uint firstread = DHD_FIRSTREAD;
341
342 #define HDATLEN (firstread - (SDPCM_HDRLEN))
343
344 /* Retry count for register access failures */
345 static const uint retry_limit = 2;
346
347 /* Force even SD lengths (some host controllers mess up on odd bytes) */
348 static bool forcealign;
349
350 #define ALIGNMENT  4
351
352 #if defined(OOB_INTR_ONLY) && defined(HW_OOB)
353 extern void bcmsdh_enable_hw_oob_intr(void *sdh, bool enable);
354 #endif
355
356 #if defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD)
357 #error OOB_INTR_ONLY is NOT working with SDIO_ISR_THREAD
358 #endif /* defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD) */
359 #define PKTALIGN(osh, p, len, align)                                    \
360         do {                                                            \
361                 uint datalign;                                          \
362                 datalign = (uintptr)PKTDATA((osh), (p));                \
363                 datalign = ROUNDUP(datalign, (align)) - datalign;       \
364                 ASSERT(datalign < (align));                             \
365                 ASSERT(PKTLEN((osh), (p)) >= ((len) + datalign));       \
366                 if (datalign)                                           \
367                         PKTPULL((osh), (p), datalign);                  \
368                 PKTSETLEN((osh), (p), (len));                           \
369         } while (0)
370
371 /* Limit on rounding up frames */
372 static const uint max_roundup = 512;
373
374 /* Try doing readahead */
375 static bool dhd_readahead;
376
377
378 /* To check if there's window offered */
379 #define DATAOK(bus) \
380         (((uint8)(bus->tx_max - bus->tx_seq) != 0) && \
381         (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0))
382
383 /* Macros to get register read/write status */
384 /* NOTE: these assume a local dhdsdio_bus_t *bus! */
385 #define R_SDREG(regvar, regaddr, retryvar) \
386 do { \
387         retryvar = 0; \
388         do { \
389                 regvar = R_REG(bus->dhd->osh, regaddr); \
390         } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \
391         if (retryvar) { \
392                 bus->regfails += (retryvar-1); \
393                 if (retryvar > retry_limit) { \
394                         DHD_ERROR(("%s: FAILED" #regvar "READ, LINE %d\n", \
395                                    __FUNCTION__, __LINE__)); \
396                         regvar = 0; \
397                 } \
398         } \
399 } while (0)
400
401 #define W_SDREG(regval, regaddr, retryvar) \
402 do { \
403         retryvar = 0; \
404         do { \
405                 W_REG(bus->dhd->osh, regaddr, regval); \
406         } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \
407         if (retryvar) { \
408                 bus->regfails += (retryvar-1); \
409                 if (retryvar > retry_limit) \
410                         DHD_ERROR(("%s: FAILED REGISTER WRITE, LINE %d\n", \
411                                    __FUNCTION__, __LINE__)); \
412         } \
413 } while (0)
414
415
416 #define DHD_BUS                 SDIO_BUS
417
418 #define PKT_AVAILABLE()         (intstatus & I_HMB_FRAME_IND)
419
420 #define HOSTINTMASK             (I_HMB_SW_MASK | I_CHIPACTIVE)
421
422 #define GSPI_PR55150_BAILOUT
423
424
425 #ifdef SDTEST
426 static void dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq);
427 static void dhdsdio_sdtest_set(dhd_bus_t *bus, bool start);
428 #endif
429
430 #ifdef DHD_DEBUG
431 static int dhdsdio_checkdied(dhd_bus_t *bus, uint8 *data, uint size);
432 static int dhdsdio_mem_dump(dhd_bus_t *bus);
433 #endif /* DHD_DEBUG  */
434 static int dhdsdio_download_state(dhd_bus_t *bus, bool enter);
435
436 static void dhdsdio_release(dhd_bus_t *bus, osl_t *osh);
437 static void dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh);
438 static void dhdsdio_disconnect(void *ptr);
439 static bool dhdsdio_chipmatch(uint16 chipid);
440 static bool dhdsdio_probe_attach(dhd_bus_t *bus, osl_t *osh, void *sdh,
441                                  void * regsva, uint16  devid);
442 static bool dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh);
443 static bool dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh);
444 static void dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh);
445
446 static uint process_nvram_vars(char *varbuf, uint len);
447
448 static void dhd_dongle_setmemsize(struct dhd_bus *bus, int mem_size);
449 static int dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags,
450         uint8 *buf, uint nbytes,
451         void *pkt, bcmsdh_cmplt_fn_t complete, void *handle);
452 static int dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags,
453         uint8 *buf, uint nbytes,
454         void *pkt, bcmsdh_cmplt_fn_t complete, void *handle);
455
456 static bool dhdsdio_download_firmware(struct dhd_bus *bus, osl_t *osh, void *sdh);
457 static int _dhdsdio_download_firmware(struct dhd_bus *bus);
458
459 static int dhdsdio_download_code_file(struct dhd_bus *bus, char *image_path);
460 static int dhdsdio_download_nvram(struct dhd_bus *bus);
461 #ifdef BCMEMBEDIMAGE
462 static int dhdsdio_download_code_array(struct dhd_bus *bus);
463 #endif
464
465
466 static void
467 dhd_dongle_setmemsize(struct dhd_bus *bus, int mem_size)
468 {
469         int32 min_size =  DONGLE_MIN_MEMSIZE;
470         /* Restrict the memsize to user specified limit */
471         DHD_ERROR(("user: Restrict the dongle ram size to %d, min accepted %d\n",
472                 dhd_dongle_memsize, min_size));
473         if ((dhd_dongle_memsize > min_size) &&
474                 (dhd_dongle_memsize < (int32)bus->orig_ramsize))
475                 bus->ramsize = dhd_dongle_memsize;
476 }
477
478 static int
479 dhdsdio_set_siaddr_window(dhd_bus_t *bus, uint32 address)
480 {
481         int err = 0;
482         bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW,
483                          (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err);
484         if (!err)
485                 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID,
486                                  (address >> 16) & SBSDIO_SBADDRMID_MASK, &err);
487         if (!err)
488                 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH,
489                                  (address >> 24) & SBSDIO_SBADDRHIGH_MASK, &err);
490         return err;
491 }
492
493
494 /* Turn backplane clock on or off */
495 static int
496 dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok)
497 {
498         int err;
499         uint8 clkctl, clkreq, devctl;
500         bcmsdh_info_t *sdh;
501
502         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
503
504 #if defined(OOB_INTR_ONLY)
505         pendok = FALSE;
506 #endif
507         clkctl = 0;
508         sdh = bus->sdh;
509
510
511         if (on) {
512                 /* Request HT Avail */
513                 clkreq = bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ;
514
515                 if ((bus->sih->chip == BCM4329_CHIP_ID) && (bus->sih->chiprev == 0))
516                         clkreq |= SBSDIO_FORCE_ALP;
517
518
519
520
521                 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
522                 if (err) {
523                         DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err));
524                         return BCME_ERROR;
525                 }
526
527                 if (pendok &&
528                     ((bus->sih->buscoretype == PCMCIA_CORE_ID) && (bus->sih->buscorerev == 9))) {
529                         uint32 dummy, retries;
530                         R_SDREG(dummy, &bus->regs->clockctlstatus, retries);
531                 }
532
533                 /* Check current status */
534                 clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
535                 if (err) {
536                         DHD_ERROR(("%s: HT Avail read error: %d\n", __FUNCTION__, err));
537                         return BCME_ERROR;
538                 }
539
540                 /* Go to pending and await interrupt if appropriate */
541                 if (!SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) {
542                         /* Allow only clock-available interrupt */
543                         devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
544                         if (err) {
545                                 DHD_ERROR(("%s: Devctl access error setting CA: %d\n",
546                                            __FUNCTION__, err));
547                                 return BCME_ERROR;
548                         }
549
550                         devctl |= SBSDIO_DEVCTL_CA_INT_ONLY;
551                         bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
552                         DHD_INFO(("CLKCTL: set PENDING\n"));
553                         bus->clkstate = CLK_PENDING;
554
555                         return BCME_OK;
556                 } else if (bus->clkstate == CLK_PENDING) {
557                         /* Cancel CA-only interrupt filter */
558                         devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
559                         devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
560                         bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
561                 }
562
563                 /* Otherwise, wait here (polling) for HT Avail */
564                 if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
565                         SPINWAIT_SLEEP(sdioh_spinwait_sleep,
566                                 ((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
567                                                             SBSDIO_FUNC1_CHIPCLKCSR, &err)),
568                                   !SBSDIO_CLKAV(clkctl, bus->alp_only)), PMU_MAX_TRANSITION_DLY);
569                 }
570                 if (err) {
571                         DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err));
572                         return BCME_ERROR;
573                 }
574                 if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
575                         DHD_ERROR(("%s: HT Avail timeout (%d): clkctl 0x%02x\n",
576                                    __FUNCTION__, PMU_MAX_TRANSITION_DLY, clkctl));
577                         return BCME_ERROR;
578                 }
579
580
581                 /* Mark clock available */
582                 bus->clkstate = CLK_AVAIL;
583                 DHD_INFO(("CLKCTL: turned ON\n"));
584
585 #if defined(DHD_DEBUG)
586                 if (bus->alp_only == TRUE) {
587 #if !defined(BCMLXSDMMC)
588                         if (!SBSDIO_ALPONLY(clkctl)) {
589                                 DHD_ERROR(("%s: HT Clock, when ALP Only\n", __FUNCTION__));
590                         }
591 #endif /* !defined(BCMLXSDMMC) */
592                 } else {
593                         if (SBSDIO_ALPONLY(clkctl)) {
594                                 DHD_ERROR(("%s: HT Clock should be on.\n", __FUNCTION__));
595                         }
596                 }
597 #endif /* defined (DHD_DEBUG) */
598
599                 bus->activity = TRUE;
600         } else {
601                 clkreq = 0;
602
603                 if (bus->clkstate == CLK_PENDING) {
604                         /* Cancel CA-only interrupt filter */
605                         devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
606                         devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
607                         bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
608                 }
609
610                 bus->clkstate = CLK_SDONLY;
611                 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
612                 DHD_INFO(("CLKCTL: turned OFF\n"));
613                 if (err) {
614                         DHD_ERROR(("%s: Failed access turning clock off: %d\n",
615                                    __FUNCTION__, err));
616                         return BCME_ERROR;
617                 }
618         }
619         return BCME_OK;
620 }
621
622 /* Change idle/active SD state */
623 static int
624 dhdsdio_sdclk(dhd_bus_t *bus, bool on)
625 {
626         int err;
627         int32 iovalue;
628
629         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
630
631         if (on) {
632                 if (bus->idleclock == DHD_IDLE_STOP) {
633                         /* Turn on clock and restore mode */
634                         iovalue = 1;
635                         err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0,
636                                               &iovalue, sizeof(iovalue), TRUE);
637                         if (err) {
638                                 DHD_ERROR(("%s: error enabling sd_clock: %d\n",
639                                            __FUNCTION__, err));
640                                 return BCME_ERROR;
641                         }
642
643                         iovalue = bus->sd_mode;
644                         err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
645                                               &iovalue, sizeof(iovalue), TRUE);
646                         if (err) {
647                                 DHD_ERROR(("%s: error changing sd_mode: %d\n",
648                                            __FUNCTION__, err));
649                                 return BCME_ERROR;
650                         }
651                 } else if (bus->idleclock != DHD_IDLE_ACTIVE) {
652                         /* Restore clock speed */
653                         iovalue = bus->sd_divisor;
654                         err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
655                                               &iovalue, sizeof(iovalue), TRUE);
656                         if (err) {
657                                 DHD_ERROR(("%s: error restoring sd_divisor: %d\n",
658                                            __FUNCTION__, err));
659                                 return BCME_ERROR;
660                         }
661                 }
662                 bus->clkstate = CLK_SDONLY;
663         } else {
664                 /* Stop or slow the SD clock itself */
665                 if ((bus->sd_divisor == -1) || (bus->sd_mode == -1)) {
666                         DHD_TRACE(("%s: can't idle clock, divisor %d mode %d\n",
667                                    __FUNCTION__, bus->sd_divisor, bus->sd_mode));
668                         return BCME_ERROR;
669                 }
670                 if (bus->idleclock == DHD_IDLE_STOP) {
671                         if (sd1idle) {
672                                 /* Change to SD1 mode and turn off clock */
673                                 iovalue = 1;
674                                 err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
675                                                       &iovalue, sizeof(iovalue), TRUE);
676                                 if (err) {
677                                         DHD_ERROR(("%s: error changing sd_clock: %d\n",
678                                                    __FUNCTION__, err));
679                                         return BCME_ERROR;
680                                 }
681                         }
682
683                         iovalue = 0;
684                         err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0,
685                                               &iovalue, sizeof(iovalue), TRUE);
686                         if (err) {
687                                 DHD_ERROR(("%s: error disabling sd_clock: %d\n",
688                                            __FUNCTION__, err));
689                                 return BCME_ERROR;
690                         }
691                 } else if (bus->idleclock != DHD_IDLE_ACTIVE) {
692                         /* Set divisor to idle value */
693                         iovalue = bus->idleclock;
694                         err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
695                                               &iovalue, sizeof(iovalue), TRUE);
696                         if (err) {
697                                 DHD_ERROR(("%s: error changing sd_divisor: %d\n",
698                                            __FUNCTION__, err));
699                                 return BCME_ERROR;
700                         }
701                 }
702                 bus->clkstate = CLK_NONE;
703         }
704
705         return BCME_OK;
706 }
707
708 /* Transition SD and backplane clock readiness */
709 static int
710 dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok)
711 {
712         int ret = BCME_OK;
713 #ifdef DHD_DEBUG
714         uint oldstate = bus->clkstate;
715 #endif /* DHD_DEBUG */
716
717         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
718
719         /* Early exit if we're already there */
720         if (bus->clkstate == target) {
721                 if (target == CLK_AVAIL) {
722                         dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
723                         bus->activity = TRUE;
724                 }
725                 return BCME_OK;
726         }
727
728         switch (target) {
729         case CLK_AVAIL:
730                 /* Make sure SD clock is available */
731                 if (bus->clkstate == CLK_NONE)
732                         dhdsdio_sdclk(bus, TRUE);
733                 /* Now request HT Avail on the backplane */
734                 ret = dhdsdio_htclk(bus, TRUE, pendok);
735                 if (ret == BCME_OK) {
736                         dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
737                         bus->activity = TRUE;
738                 }
739                 break;
740
741         case CLK_SDONLY:
742                 /* Remove HT request, or bring up SD clock */
743                 if (bus->clkstate == CLK_NONE)
744                         ret = dhdsdio_sdclk(bus, TRUE);
745                 else if (bus->clkstate == CLK_AVAIL)
746                         ret = dhdsdio_htclk(bus, FALSE, FALSE);
747                 else
748                         DHD_ERROR(("dhdsdio_clkctl: request for %d -> %d\n",
749                                    bus->clkstate, target));
750                 if (ret == BCME_OK) {
751                         dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
752                 }
753                 break;
754
755         case CLK_NONE:
756                 /* Make sure to remove HT request */
757                 if (bus->clkstate == CLK_AVAIL)
758                         ret = dhdsdio_htclk(bus, FALSE, FALSE);
759                 /* Now remove the SD clock */
760                 ret = dhdsdio_sdclk(bus, FALSE);
761                 dhd_os_wd_timer(bus->dhd, 0);
762                 break;
763         }
764 #ifdef DHD_DEBUG
765         DHD_INFO(("dhdsdio_clkctl: %d -> %d\n", oldstate, bus->clkstate));
766 #endif /* DHD_DEBUG */
767
768         return ret;
769 }
770
771 int
772 dhdsdio_bussleep(dhd_bus_t *bus, bool sleep)
773 {
774         bcmsdh_info_t *sdh = bus->sdh;
775         sdpcmd_regs_t *regs = bus->regs;
776         uint retries = 0;
777
778         DHD_INFO(("dhdsdio_bussleep: request %s (currently %s)\n",
779                   (sleep ? "SLEEP" : "WAKE"),
780                   (bus->sleeping ? "SLEEP" : "WAKE")));
781
782         /* Done if we're already in the requested state */
783         if (sleep == bus->sleeping)
784                 return BCME_OK;
785
786         /* Going to sleep: set the alarm and turn off the lights... */
787         if (sleep) {
788                 /* Don't sleep if something is pending */
789                 if (bus->dpc_sched || bus->rxskip || pktq_len(&bus->txq))
790                         return BCME_BUSY;
791
792
793                 /* Disable SDIO interrupts (no longer interested) */
794                 bcmsdh_intr_disable(bus->sdh);
795
796                 /* Make sure the controller has the bus up */
797                 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
798
799                 /* Tell device to start using OOB wakeup */
800                 W_SDREG(SMB_USE_OOB, &regs->tosbmailbox, retries);
801                 if (retries > retry_limit)
802                         DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
803
804                 /* Turn off our contribution to the HT clock request */
805                 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
806
807                 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
808                                  SBSDIO_FORCE_HW_CLKREQ_OFF, NULL);
809
810                 /* Isolate the bus */
811                 if (bus->sih->chip != BCM4329_CHIP_ID && bus->sih->chip != BCM4319_CHIP_ID) {
812                                 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL,
813                                         SBSDIO_DEVCTL_PADS_ISO, NULL);
814                 }
815
816                 /* Change state */
817                 bus->sleeping = TRUE;
818
819         } else {
820                 /* Waking up: bus power up is ok, set local state */
821
822                 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
823                                  0, NULL);
824
825                 /* Force pad isolation off if possible (in case power never toggled) */
826                 if ((bus->sih->buscoretype == PCMCIA_CORE_ID) && (bus->sih->buscorerev >= 10))
827                         bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, 0, NULL);
828
829
830                 /* Make sure the controller has the bus up */
831                 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
832
833                 /* Send misc interrupt to indicate OOB not needed */
834                 W_SDREG(0, &regs->tosbmailboxdata, retries);
835                 if (retries <= retry_limit)
836                         W_SDREG(SMB_DEV_INT, &regs->tosbmailbox, retries);
837
838                 if (retries > retry_limit)
839                         DHD_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n"));
840
841                 /* Make sure we have SD bus access */
842                 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
843
844                 /* Change state */
845                 bus->sleeping = FALSE;
846
847                 /* Enable interrupts again */
848                 if (bus->intr && (bus->dhd->busstate == DHD_BUS_DATA)) {
849                         bus->intdis = FALSE;
850                         bcmsdh_intr_enable(bus->sdh);
851                 }
852         }
853
854         return BCME_OK;
855 }
856 #if defined(OOB_INTR_ONLY)
857 void
858 dhd_enable_oob_intr(struct dhd_bus *bus, bool enable)
859 {
860 #if defined(HW_OOB)
861         bcmsdh_enable_hw_oob_intr(bus->sdh, enable);
862 #else
863         sdpcmd_regs_t *regs = bus->regs;
864         uint retries = 0;
865
866         dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
867         if (enable == TRUE) {
868
869                 /* Tell device to start using OOB wakeup */
870                 W_SDREG(SMB_USE_OOB, &regs->tosbmailbox, retries);
871                 if (retries > retry_limit)
872                         DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
873
874         } else {
875                 /* Send misc interrupt to indicate OOB not needed */
876                 W_SDREG(0, &regs->tosbmailboxdata, retries);
877                 if (retries <= retry_limit)
878                         W_SDREG(SMB_DEV_INT, &regs->tosbmailbox, retries);
879         }
880
881         /* Turn off our contribution to the HT clock request */
882         dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
883 #endif /* !defined(HW_OOB) */
884 }
885 #endif /* defined(OOB_INTR_ONLY) */
886
887 #define BUS_WAKE(bus) \
888         do { \
889                 if ((bus)->sleeping) \
890                         dhdsdio_bussleep((bus), FALSE); \
891         } while (0);
892
893
894 /* Writes a HW/SW header into the packet and sends it. */
895 /* Assumes: (a) header space already there, (b) caller holds lock */
896 static int
897 dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt)
898 {
899         int ret;
900         osl_t *osh;
901         uint8 *frame;
902         uint16 len, pad = 0;
903         uint32 swheader;
904         uint retries = 0;
905         bcmsdh_info_t *sdh;
906         void *new;
907         int i;
908
909         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
910
911         sdh = bus->sdh;
912         osh = bus->dhd->osh;
913
914         if (bus->dhd->dongle_reset) {
915                 ret = BCME_NOTREADY;
916                 goto done;
917         }
918
919         frame = (uint8*)PKTDATA(osh, pkt);
920
921         /* Add alignment padding, allocate new packet if needed */
922         if ((pad = ((uintptr)frame % DHD_SDALIGN))) {
923                 if (PKTHEADROOM(osh, pkt) < pad) {
924                         DHD_INFO(("%s: insufficient headroom %d for %d pad\n",
925                                   __FUNCTION__, (int)PKTHEADROOM(osh, pkt), pad));
926                         bus->dhd->tx_realloc++;
927                         new = PKTGET(osh, (PKTLEN(osh, pkt) + DHD_SDALIGN), TRUE);
928                         if (!new) {
929                                 DHD_ERROR(("%s: couldn't allocate new %d-byte packet\n",
930                                            __FUNCTION__, PKTLEN(osh, pkt) + DHD_SDALIGN));
931                                 ret = BCME_NOMEM;
932                                 goto done;
933                         }
934
935                         PKTALIGN(osh, new, PKTLEN(osh, pkt), DHD_SDALIGN);
936                         bcopy(PKTDATA(osh, pkt), PKTDATA(osh, new), PKTLEN(osh, pkt));
937                         if (free_pkt)
938                                 PKTFREE(osh, pkt, TRUE);
939                         /* free the pkt if canned one is not used */
940                         free_pkt = TRUE;
941                         pkt = new;
942                         frame = (uint8*)PKTDATA(osh, pkt);
943                         ASSERT(((uintptr)frame % DHD_SDALIGN) == 0);
944                         pad = 0;
945                 } else {
946                         PKTPUSH(osh, pkt, pad);
947                         frame = (uint8*)PKTDATA(osh, pkt);
948
949                         ASSERT((pad + SDPCM_HDRLEN) <= (int) PKTLEN(osh, pkt));
950                         bzero(frame, pad + SDPCM_HDRLEN);
951                 }
952         }
953         ASSERT(pad < DHD_SDALIGN);
954
955         /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
956         len = (uint16)PKTLEN(osh, pkt);
957         *(uint16*)frame = htol16(len);
958         *(((uint16*)frame) + 1) = htol16(~len);
959
960         /* Software tag: channel, sequence number, data offset */
961         swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) | bus->tx_seq |
962                 (((pad + SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
963         htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN);
964         htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
965
966 #ifdef DHD_DEBUG
967         tx_packets[PKTPRIO(pkt)]++;
968         if (DHD_BYTES_ON() &&
969             (((DHD_CTL_ON() && (chan == SDPCM_CONTROL_CHANNEL)) ||
970               (DHD_DATA_ON() && (chan != SDPCM_CONTROL_CHANNEL))))) {
971                 prhex("Tx Frame", frame, len);
972         } else if (DHD_HDRS_ON()) {
973                 prhex("TxHdr", frame, MIN(len, 16));
974         }
975 #endif
976
977         /* Raise len to next SDIO block to eliminate tail command */
978         if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
979                 uint16 pad = bus->blocksize - (len % bus->blocksize);
980                 if ((pad <= bus->roundup) && (pad < bus->blocksize))
981 #ifdef NOTUSED
982                         if (pad <= PKTTAILROOM(osh, pkt))
983 #endif /* NOTUSED */
984                                 len += pad;
985         } else if (len % DHD_SDALIGN) {
986                 len += DHD_SDALIGN - (len % DHD_SDALIGN);
987         }
988
989         /* Some controllers have trouble with odd bytes -- round to even */
990         if (forcealign && (len & (ALIGNMENT - 1))) {
991 #ifdef NOTUSED
992                 if (PKTTAILROOM(osh, pkt))
993 #endif
994                         len = ROUNDUP(len, ALIGNMENT);
995 #ifdef NOTUSED
996                 else
997                         DHD_ERROR(("%s: sending unrounded %d-byte packet\n", __FUNCTION__, len));
998 #endif
999         }
1000
1001         do {
1002                 ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
1003                                       frame, len, pkt, NULL, NULL);
1004                 bus->f2txdata++;
1005                 ASSERT(ret != BCME_PENDING);
1006
1007                 if (ret < 0) {
1008                         /* On failure, abort the command and terminate the frame */
1009                         DHD_INFO(("%s: sdio error %d, abort command and terminate frame.\n",
1010                                   __FUNCTION__, ret));
1011                         bus->tx_sderrs++;
1012
1013                         bcmsdh_abort(sdh, SDIO_FUNC_2);
1014                         bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
1015                                          SFC_WF_TERM, NULL);
1016                         bus->f1regdata++;
1017
1018                         for (i = 0; i < 3; i++) {
1019                                 uint8 hi, lo;
1020                                 hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
1021                                                      SBSDIO_FUNC1_WFRAMEBCHI, NULL);
1022                                 lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
1023                                                      SBSDIO_FUNC1_WFRAMEBCLO, NULL);
1024                                 bus->f1regdata += 2;
1025                                 if ((hi == 0) && (lo == 0))
1026                                         break;
1027                         }
1028
1029                 }
1030                 if (ret == 0) {
1031                         bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
1032                 }
1033         } while ((ret < 0) && retrydata && retries++ < TXRETRIES);
1034
1035 done:
1036         /* restore pkt buffer pointer before calling tx complete routine */
1037         PKTPULL(osh, pkt, SDPCM_HDRLEN + pad);
1038         dhd_os_sdunlock(bus->dhd);
1039         dhd_txcomplete(bus->dhd, pkt, ret != 0);
1040         dhd_os_sdlock(bus->dhd);
1041
1042         if (free_pkt)
1043                 PKTFREE(osh, pkt, TRUE);
1044
1045         return ret;
1046 }
1047
1048 int
1049 dhd_bus_txdata(struct dhd_bus *bus, void *pkt)
1050 {
1051         int ret = BCME_ERROR;
1052         osl_t *osh;
1053         uint datalen, prec;
1054
1055         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1056
1057         osh = bus->dhd->osh;
1058         datalen = PKTLEN(osh, pkt);
1059
1060 #ifdef SDTEST
1061         /* Push the test header if doing loopback */
1062         if (bus->ext_loop) {
1063                 uint8* data;
1064                 PKTPUSH(osh, pkt, SDPCM_TEST_HDRLEN);
1065                 data = PKTDATA(osh, pkt);
1066                 *data++ = SDPCM_TEST_ECHOREQ;
1067                 *data++ = (uint8)bus->loopid++;
1068                 *data++ = (datalen >> 0);
1069                 *data++ = (datalen >> 8);
1070                 datalen += SDPCM_TEST_HDRLEN;
1071         }
1072 #endif /* SDTEST */
1073
1074         /* Add space for the header */
1075         PKTPUSH(osh, pkt, SDPCM_HDRLEN);
1076         ASSERT(ISALIGNED((uintptr)PKTDATA(osh, pkt), 2));
1077
1078         prec = PRIO2PREC((PKTPRIO(pkt) & PRIOMASK));
1079
1080
1081         /* Check for existing queue, current flow-control, pending event, or pending clock */
1082         if (dhd_deferred_tx || bus->fcstate || pktq_len(&bus->txq) || bus->dpc_sched ||
1083             (!DATAOK(bus)) || (bus->flowcontrol & NBITVAL(prec)) ||
1084             (bus->clkstate != CLK_AVAIL)) {
1085                 DHD_TRACE(("%s: deferring pktq len %d\n", __FUNCTION__,
1086                         pktq_len(&bus->txq)));
1087                 bus->fcqueued++;
1088
1089                 /* Priority based enq */
1090                 dhd_os_sdlock_txq(bus->dhd);
1091                 if (dhd_prec_enq(bus->dhd, &bus->txq, pkt, prec) == FALSE) {
1092                         PKTPULL(osh, pkt, SDPCM_HDRLEN);
1093                         dhd_txcomplete(bus->dhd, pkt, FALSE);
1094                         PKTFREE(osh, pkt, TRUE);
1095                         DHD_ERROR(("%s: out of bus->txq !!!\n", __FUNCTION__));
1096                         ret = BCME_NORESOURCE;
1097                 } else {
1098                         ret = BCME_OK;
1099                 }
1100                 dhd_os_sdunlock_txq(bus->dhd);
1101
1102                 if ((pktq_len(&bus->txq) >= FCHI) && dhd_doflow)
1103                         dhd_txflowcontrol(bus->dhd, 0, ON);
1104
1105 #ifdef DHD_DEBUG
1106                 if (pktq_plen(&bus->txq, prec) > qcount[prec])
1107                         qcount[prec] = pktq_plen(&bus->txq, prec);
1108 #endif
1109                 /* Schedule DPC if needed to send queued packet(s) */
1110                 if (dhd_deferred_tx && !bus->dpc_sched) {
1111                         bus->dpc_sched = TRUE;
1112                         dhd_sched_dpc(bus->dhd);
1113                 }
1114         } else {
1115                 /* Lock: we're about to use shared data/code (and SDIO) */
1116                 dhd_os_sdlock(bus->dhd);
1117
1118                 /* Otherwise, send it now */
1119                 BUS_WAKE(bus);
1120                 /* Make sure back plane ht clk is on, no pending allowed */
1121                 dhdsdio_clkctl(bus, CLK_AVAIL, TRUE);
1122
1123 #ifndef SDTEST
1124                 DHD_TRACE(("%s: calling txpkt\n", __FUNCTION__));
1125                 ret = dhdsdio_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, TRUE);
1126 #else
1127                 ret = dhdsdio_txpkt(bus, pkt,
1128                         (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL), TRUE);
1129 #endif
1130                 if (ret)
1131                         bus->dhd->tx_errors++;
1132                 else
1133                         bus->dhd->dstats.tx_bytes += datalen;
1134
1135                 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
1136                         bus->activity = FALSE;
1137                         dhdsdio_clkctl(bus, CLK_NONE, TRUE);
1138                 }
1139
1140                 dhd_os_sdunlock(bus->dhd);
1141         }
1142
1143
1144         return ret;
1145 }
1146
1147 static uint
1148 dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes)
1149 {
1150         void *pkt;
1151         uint32 intstatus = 0;
1152         uint retries = 0;
1153         int ret = 0, prec_out;
1154         uint cnt = 0;
1155         uint datalen;
1156         uint8 tx_prec_map;
1157
1158         dhd_pub_t *dhd = bus->dhd;
1159         sdpcmd_regs_t *regs = bus->regs;
1160
1161         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1162
1163         tx_prec_map = ~bus->flowcontrol;
1164
1165         /* Send frames until the limit or some other event */
1166         for (cnt = 0; (cnt < maxframes) && DATAOK(bus); cnt++) {
1167                 dhd_os_sdlock_txq(bus->dhd);
1168                 if ((pkt = pktq_mdeq(&bus->txq, tx_prec_map, &prec_out)) == NULL) {
1169                         dhd_os_sdunlock_txq(bus->dhd);
1170                         break;
1171                 }
1172                 dhd_os_sdunlock_txq(bus->dhd);
1173                 datalen = PKTLEN(bus->dhd->osh, pkt) - SDPCM_HDRLEN;
1174
1175 #ifndef SDTEST
1176                 ret = dhdsdio_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, TRUE);
1177 #else
1178                 ret = dhdsdio_txpkt(bus, pkt,
1179                         (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL), TRUE);
1180 #endif
1181                 if (ret)
1182                         bus->dhd->tx_errors++;
1183                 else
1184                         bus->dhd->dstats.tx_bytes += datalen;
1185
1186                 /* In poll mode, need to check for other events */
1187                 if (!bus->intr && cnt)
1188                 {
1189                         /* Check device status, signal pending interrupt */
1190                         R_SDREG(intstatus, &regs->intstatus, retries);
1191                         bus->f2txdata++;
1192                         if (bcmsdh_regfail(bus->sdh))
1193                                 break;
1194                         if (intstatus & bus->hostintmask)
1195                                 bus->ipend = TRUE;
1196                 }
1197         }
1198
1199         /* Deflow-control stack if needed */
1200         if (dhd_doflow && dhd->up && (dhd->busstate == DHD_BUS_DATA) &&
1201             dhd->txoff && (pktq_len(&bus->txq) < FCLOW))
1202                 dhd_txflowcontrol(dhd, 0, OFF);
1203
1204         return cnt;
1205 }
1206
1207 int
1208 dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen)
1209 {
1210         uint8 *frame;
1211         uint16 len;
1212         uint32 swheader;
1213         uint retries = 0;
1214         bcmsdh_info_t *sdh = bus->sdh;
1215         uint8 doff = 0;
1216         int ret = -1;
1217         int i;
1218
1219         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1220
1221         if (bus->dhd->dongle_reset)
1222                 return -EIO;
1223
1224         /* Back the pointer to make a room for bus header */
1225         frame = msg - SDPCM_HDRLEN;
1226         len = (msglen += SDPCM_HDRLEN);
1227
1228         /* Add alignment padding (optional for ctl frames) */
1229         if (dhd_alignctl) {
1230                 if ((doff = ((uintptr)frame % DHD_SDALIGN))) {
1231                         frame -= doff;
1232                         len += doff;
1233                         msglen += doff;
1234                         bzero(frame, doff + SDPCM_HDRLEN);
1235                 }
1236                 ASSERT(doff < DHD_SDALIGN);
1237         }
1238         doff += SDPCM_HDRLEN;
1239
1240         /* Round send length to next SDIO block */
1241         if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
1242                 uint16 pad = bus->blocksize - (len % bus->blocksize);
1243                 if ((pad <= bus->roundup) && (pad < bus->blocksize))
1244                         len += pad;
1245         } else if (len % DHD_SDALIGN) {
1246                 len += DHD_SDALIGN - (len % DHD_SDALIGN);
1247         }
1248
1249         /* Satisfy length-alignment requirements */
1250         if (forcealign && (len & (ALIGNMENT - 1)))
1251                 len = ROUNDUP(len, ALIGNMENT);
1252
1253         ASSERT(ISALIGNED((uintptr)frame, 2));
1254
1255
1256         /* Need to lock here to protect txseq and SDIO tx calls */
1257         dhd_os_sdlock(bus->dhd);
1258
1259         BUS_WAKE(bus);
1260
1261         /* Make sure backplane clock is on */
1262         dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
1263
1264         /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
1265         *(uint16*)frame = htol16((uint16)msglen);
1266         *(((uint16*)frame) + 1) = htol16(~msglen);
1267
1268         /* Software tag: channel, sequence number, data offset */
1269         swheader = ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK)
1270                 | bus->tx_seq | ((doff << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
1271         htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN);
1272         htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
1273
1274         if (!DATAOK(bus)) {
1275                 DHD_INFO(("%s: No bus credit bus->tx_max %d, bus->tx_seq %d\n",
1276                         __FUNCTION__, bus->tx_max, bus->tx_seq));
1277                 bus->ctrl_frame_stat = TRUE;
1278                 /* Send from dpc */
1279                 bus->ctrl_frame_buf = frame;
1280                 bus->ctrl_frame_len = len;
1281
1282                 dhd_wait_for_event(bus->dhd, &bus->ctrl_frame_stat);
1283
1284                 if (bus->ctrl_frame_stat == FALSE) {
1285                         DHD_INFO(("%s: ctrl_frame_stat == FALSE\n", __FUNCTION__));
1286                         ret = 0;
1287                 } else {
1288                         DHD_INFO(("%s: ctrl_frame_stat == TRUE\n", __FUNCTION__));
1289                         ret = -1;
1290                 }
1291         }
1292
1293         if (ret == -1) {
1294 #ifdef DHD_DEBUG
1295                 if (DHD_BYTES_ON() && DHD_CTL_ON()) {
1296                         prhex("Tx Frame", frame, len);
1297                 } else if (DHD_HDRS_ON()) {
1298                         prhex("TxHdr", frame, MIN(len, 16));
1299                 }
1300 #endif
1301
1302                 do {
1303                         bus->ctrl_frame_stat = FALSE;
1304                         ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
1305                                                   frame, len, NULL, NULL, NULL);
1306
1307                         ASSERT(ret != BCME_PENDING);
1308
1309                         if (ret < 0) {
1310                                 /* On failure, abort the command and terminate the frame */
1311                                 DHD_INFO(("%s: sdio error %d, abort command and terminate frame.\n",
1312                                           __FUNCTION__, ret));
1313                                 bus->tx_sderrs++;
1314
1315                                 bcmsdh_abort(sdh, SDIO_FUNC_2);
1316
1317                                 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
1318                                                  SFC_WF_TERM, NULL);
1319                                 bus->f1regdata++;
1320
1321                                 for (i = 0; i < 3; i++) {
1322                                         uint8 hi, lo;
1323                                         hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
1324                                                              SBSDIO_FUNC1_WFRAMEBCHI, NULL);
1325                                         lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
1326                                                              SBSDIO_FUNC1_WFRAMEBCLO, NULL);
1327                                         bus->f1regdata += 2;
1328                                         if ((hi == 0) && (lo == 0))
1329                                                 break;
1330                                 }
1331
1332                         }
1333                         if (ret == 0) {
1334                                 bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
1335                         }
1336                 } while ((ret < 0) && retries++ < TXRETRIES);
1337         }
1338
1339         if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
1340                 bus->activity = FALSE;
1341                 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
1342         }
1343
1344         dhd_os_sdunlock(bus->dhd);
1345
1346         if (ret)
1347                 bus->dhd->tx_ctlerrs++;
1348         else
1349                 bus->dhd->tx_ctlpkts++;
1350
1351         return ret ? -EIO : 0;
1352 }
1353
1354 int
1355 dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen)
1356 {
1357         int timeleft;
1358         uint rxlen = 0;
1359         bool pending;
1360
1361         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1362
1363         if (bus->dhd->dongle_reset)
1364                 return -EIO;
1365
1366         /* Wait until control frame is available */
1367         timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->rxlen, &pending);
1368
1369         dhd_os_sdlock(bus->dhd);
1370         rxlen = bus->rxlen;
1371         bcopy(bus->rxctl, msg, MIN(msglen, rxlen));
1372         bus->rxlen = 0;
1373         dhd_os_sdunlock(bus->dhd);
1374
1375         if (rxlen) {
1376                 DHD_CTL(("%s: resumed on rxctl frame, got %d expected %d\n",
1377                          __FUNCTION__, rxlen, msglen));
1378         } else if (timeleft == 0) {
1379                 DHD_ERROR(("%s: resumed on timeout\n", __FUNCTION__));
1380 #ifdef DHD_DEBUG
1381                 dhd_os_sdlock(bus->dhd);
1382                 dhdsdio_checkdied(bus, NULL, 0);
1383                 dhd_os_sdunlock(bus->dhd);
1384 #endif /* DHD_DEBUG */
1385         } else if (pending == TRUE) {
1386                 DHD_CTL(("%s: cancelled\n", __FUNCTION__));
1387                 return -ERESTARTSYS;
1388         } else {
1389                 DHD_CTL(("%s: resumed for unknown reason?\n", __FUNCTION__));
1390 #ifdef DHD_DEBUG
1391                 dhd_os_sdlock(bus->dhd);
1392                 dhdsdio_checkdied(bus, NULL, 0);
1393                 dhd_os_sdunlock(bus->dhd);
1394 #endif /* DHD_DEBUG */
1395         }
1396
1397         if (rxlen)
1398                 bus->dhd->rx_ctlpkts++;
1399         else
1400                 bus->dhd->rx_ctlerrs++;
1401
1402         return rxlen ? (int)rxlen : -ETIMEDOUT;
1403 }
1404
1405 /* IOVar table */
1406 enum {
1407         IOV_INTR = 1,
1408         IOV_POLLRATE,
1409         IOV_SDREG,
1410         IOV_SBREG,
1411         IOV_SDCIS,
1412         IOV_MEMBYTES,
1413         IOV_MEMSIZE,
1414 #ifdef DHD_DEBUG
1415         IOV_CHECKDIED,
1416 #endif
1417         IOV_DOWNLOAD,
1418         IOV_FORCEEVEN,
1419         IOV_SDIOD_DRIVE,
1420         IOV_READAHEAD,
1421         IOV_SDRXCHAIN,
1422         IOV_ALIGNCTL,
1423         IOV_SDALIGN,
1424         IOV_DEVRESET,
1425         IOV_CPU,
1426 #ifdef SDTEST
1427         IOV_PKTGEN,
1428         IOV_EXTLOOP,
1429 #endif /* SDTEST */
1430         IOV_SPROM,
1431         IOV_TXBOUND,
1432         IOV_RXBOUND,
1433         IOV_TXMINMAX,
1434         IOV_IDLETIME,
1435         IOV_IDLECLOCK,
1436         IOV_SD1IDLE,
1437         IOV_SLEEP,
1438         IOV_VARS
1439 };
1440
1441 const bcm_iovar_t dhdsdio_iovars[] = {
1442         {"intr",        IOV_INTR,       0,      IOVT_BOOL,      0 },
1443         {"sleep",       IOV_SLEEP,      0,      IOVT_BOOL,      0 },
1444         {"pollrate",    IOV_POLLRATE,   0,      IOVT_UINT32,    0 },
1445         {"idletime",    IOV_IDLETIME,   0,      IOVT_INT32,     0 },
1446         {"idleclock",   IOV_IDLECLOCK,  0,      IOVT_INT32,     0 },
1447         {"sd1idle",     IOV_SD1IDLE,    0,      IOVT_BOOL,      0 },
1448         {"membytes",    IOV_MEMBYTES,   0,      IOVT_BUFFER,    2 * sizeof(int) },
1449         {"memsize",     IOV_MEMSIZE,    0,      IOVT_UINT32,    0 },
1450         {"download",    IOV_DOWNLOAD,   0,      IOVT_BOOL,      0 },
1451         {"vars",        IOV_VARS,       0,      IOVT_BUFFER,    0 },
1452         {"sdiod_drive", IOV_SDIOD_DRIVE, 0,     IOVT_UINT32,    0 },
1453         {"readahead",   IOV_READAHEAD,  0,      IOVT_BOOL,      0 },
1454         {"sdrxchain",   IOV_SDRXCHAIN,  0,      IOVT_BOOL,      0 },
1455         {"alignctl",    IOV_ALIGNCTL,   0,      IOVT_BOOL,      0 },
1456         {"sdalign",     IOV_SDALIGN,    0,      IOVT_BOOL,      0 },
1457         {"devreset",    IOV_DEVRESET,   0,      IOVT_BOOL,      0 },
1458 #ifdef DHD_DEBUG
1459         {"sdreg",       IOV_SDREG,      0,      IOVT_BUFFER,    sizeof(sdreg_t) },
1460         {"sbreg",       IOV_SBREG,      0,      IOVT_BUFFER,    sizeof(sdreg_t) },
1461         {"sd_cis",      IOV_SDCIS,      0,      IOVT_BUFFER,    DHD_IOCTL_MAXLEN },
1462         {"forcealign",  IOV_FORCEEVEN,  0,      IOVT_BOOL,      0 },
1463         {"txbound",     IOV_TXBOUND,    0,      IOVT_UINT32,    0 },
1464         {"rxbound",     IOV_RXBOUND,    0,      IOVT_UINT32,    0 },
1465         {"txminmax", IOV_TXMINMAX,      0,      IOVT_UINT32,    0 },
1466         {"cpu",         IOV_CPU,        0,      IOVT_BOOL,      0 },
1467 #ifdef DHD_DEBUG
1468         {"checkdied",   IOV_CHECKDIED,  0,      IOVT_BUFFER,    0 },
1469 #endif /* DHD_DEBUG  */
1470 #endif /* DHD_DEBUG */
1471 #ifdef SDTEST
1472         {"extloop",     IOV_EXTLOOP,    0,      IOVT_BOOL,      0 },
1473         {"pktgen",      IOV_PKTGEN,     0,      IOVT_BUFFER,    sizeof(dhd_pktgen_t) },
1474 #endif /* SDTEST */
1475
1476         {NULL, 0, 0, 0, 0 }
1477 };
1478
1479 static void
1480 dhd_dump_pct(struct bcmstrbuf *strbuf, char *desc, uint num, uint div)
1481 {
1482         uint q1, q2;
1483
1484         if (!div) {
1485                 bcm_bprintf(strbuf, "%s N/A", desc);
1486         } else {
1487                 q1 = num / div;
1488                 q2 = (100 * (num - (q1 * div))) / div;
1489                 bcm_bprintf(strbuf, "%s %d.%02d", desc, q1, q2);
1490         }
1491 }
1492
1493 void
1494 dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf)
1495 {
1496         dhd_bus_t *bus = dhdp->bus;
1497
1498         bcm_bprintf(strbuf, "Bus SDIO structure:\n");
1499         bcm_bprintf(strbuf, "hostintmask 0x%08x intstatus 0x%08x sdpcm_ver %d\n",
1500                     bus->hostintmask, bus->intstatus, bus->sdpcm_ver);
1501         bcm_bprintf(strbuf, "fcstate %d qlen %d tx_seq %d, max %d, rxskip %d rxlen %d rx_seq %d\n",
1502                     bus->fcstate, pktq_len(&bus->txq), bus->tx_seq, bus->tx_max, bus->rxskip,
1503                     bus->rxlen, bus->rx_seq);
1504         bcm_bprintf(strbuf, "intr %d intrcount %d lastintrs %d spurious %d\n",
1505                     bus->intr, bus->intrcount, bus->lastintrs, bus->spurious);
1506         bcm_bprintf(strbuf, "pollrate %d pollcnt %d regfails %d\n",
1507                     bus->pollrate, bus->pollcnt, bus->regfails);
1508
1509         bcm_bprintf(strbuf, "\nAdditional counters:\n");
1510         bcm_bprintf(strbuf, "tx_sderrs %d fcqueued %d rxrtx %d rx_toolong %d rxc_errors %d\n",
1511                     bus->tx_sderrs, bus->fcqueued, bus->rxrtx, bus->rx_toolong,
1512                     bus->rxc_errors);
1513         bcm_bprintf(strbuf, "rx_hdrfail %d badhdr %d badseq %d\n",
1514                     bus->rx_hdrfail, bus->rx_badhdr, bus->rx_badseq);
1515         bcm_bprintf(strbuf, "fc_rcvd %d, fc_xoff %d, fc_xon %d\n",
1516                     bus->fc_rcvd, bus->fc_xoff, bus->fc_xon);
1517         bcm_bprintf(strbuf, "rxglomfail %d, rxglomframes %d, rxglompkts %d\n",
1518                     bus->rxglomfail, bus->rxglomframes, bus->rxglompkts);
1519         bcm_bprintf(strbuf, "f2rx (hdrs/data) %d (%d/%d), f2tx %d f1regs %d\n",
1520                     (bus->f2rxhdrs + bus->f2rxdata), bus->f2rxhdrs, bus->f2rxdata,
1521                     bus->f2txdata, bus->f1regdata);
1522         {
1523                 dhd_dump_pct(strbuf, "\nRx: pkts/f2rd", bus->dhd->rx_packets,
1524                              (bus->f2rxhdrs + bus->f2rxdata));
1525                 dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->rx_packets, bus->f1regdata);
1526                 dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->rx_packets,
1527                              (bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata));
1528                 dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->rx_packets, bus->intrcount);
1529                 bcm_bprintf(strbuf, "\n");
1530
1531                 dhd_dump_pct(strbuf, "Rx: glom pct", (100 * bus->rxglompkts),
1532                              bus->dhd->rx_packets);
1533                 dhd_dump_pct(strbuf, ", pkts/glom", bus->rxglompkts, bus->rxglomframes);
1534                 bcm_bprintf(strbuf, "\n");
1535
1536                 dhd_dump_pct(strbuf, "Tx: pkts/f2wr", bus->dhd->tx_packets, bus->f2txdata);
1537                 dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->tx_packets, bus->f1regdata);
1538                 dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->tx_packets,
1539                              (bus->f2txdata + bus->f1regdata));
1540                 dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->tx_packets, bus->intrcount);
1541                 bcm_bprintf(strbuf, "\n");
1542
1543                 dhd_dump_pct(strbuf, "Total: pkts/f2rw",
1544                              (bus->dhd->tx_packets + bus->dhd->rx_packets),
1545                              (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata));
1546                 dhd_dump_pct(strbuf, ", pkts/f1sd",
1547                              (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->f1regdata);
1548                 dhd_dump_pct(strbuf, ", pkts/sd",
1549                              (bus->dhd->tx_packets + bus->dhd->rx_packets),
1550                              (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata));
1551                 dhd_dump_pct(strbuf, ", pkts/int",
1552                              (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->intrcount);
1553                 bcm_bprintf(strbuf, "\n\n");
1554         }
1555
1556 #ifdef SDTEST
1557         if (bus->pktgen_count) {
1558                 bcm_bprintf(strbuf, "pktgen config and count:\n");
1559                 bcm_bprintf(strbuf, "freq %d count %d print %d total %d min %d len %d\n",
1560                             bus->pktgen_freq, bus->pktgen_count, bus->pktgen_print,
1561                             bus->pktgen_total, bus->pktgen_minlen, bus->pktgen_maxlen);
1562                 bcm_bprintf(strbuf, "send attempts %d rcvd %d fail %d\n",
1563                             bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail);
1564         }
1565 #endif /* SDTEST */
1566 #ifdef DHD_DEBUG
1567         bcm_bprintf(strbuf, "dpc_sched %d host interrupt%spending\n",
1568                     bus->dpc_sched, (bcmsdh_intr_pending(bus->sdh) ? " " : " not "));
1569         bcm_bprintf(strbuf, "blocksize %d roundup %d\n", bus->blocksize, bus->roundup);
1570 #endif /* DHD_DEBUG */
1571         bcm_bprintf(strbuf, "clkstate %d activity %d idletime %d idlecount %d sleeping %d\n",
1572                     bus->clkstate, bus->activity, bus->idletime, bus->idlecount, bus->sleeping);
1573 }
1574
1575 void
1576 dhd_bus_clearcounts(dhd_pub_t *dhdp)
1577 {
1578         dhd_bus_t *bus = (dhd_bus_t *)dhdp->bus;
1579
1580         bus->intrcount = bus->lastintrs = bus->spurious = bus->regfails = 0;
1581         bus->rxrtx = bus->rx_toolong = bus->rxc_errors = 0;
1582         bus->rx_hdrfail = bus->rx_badhdr = bus->rx_badseq = 0;
1583         bus->tx_sderrs = bus->fc_rcvd = bus->fc_xoff = bus->fc_xon = 0;
1584         bus->rxglomfail = bus->rxglomframes = bus->rxglompkts = 0;
1585         bus->f2rxhdrs = bus->f2rxdata = bus->f2txdata = bus->f1regdata = 0;
1586 }
1587
1588 #ifdef SDTEST
1589 static int
1590 dhdsdio_pktgen_get(dhd_bus_t *bus, uint8 *arg)
1591 {
1592         dhd_pktgen_t pktgen;
1593
1594         pktgen.version = DHD_PKTGEN_VERSION;
1595         pktgen.freq = bus->pktgen_freq;
1596         pktgen.count = bus->pktgen_count;
1597         pktgen.print = bus->pktgen_print;
1598         pktgen.total = bus->pktgen_total;
1599         pktgen.minlen = bus->pktgen_minlen;
1600         pktgen.maxlen = bus->pktgen_maxlen;
1601         pktgen.numsent = bus->pktgen_sent;
1602         pktgen.numrcvd = bus->pktgen_rcvd;
1603         pktgen.numfail = bus->pktgen_fail;
1604         pktgen.mode = bus->pktgen_mode;
1605         pktgen.stop = bus->pktgen_stop;
1606
1607         bcopy(&pktgen, arg, sizeof(pktgen));
1608
1609         return 0;
1610 }
1611
1612 static int
1613 dhdsdio_pktgen_set(dhd_bus_t *bus, uint8 *arg)
1614 {
1615         dhd_pktgen_t pktgen;
1616         uint oldcnt, oldmode;
1617
1618         bcopy(arg, &pktgen, sizeof(pktgen));
1619         if (pktgen.version != DHD_PKTGEN_VERSION)
1620                 return BCME_BADARG;
1621
1622         oldcnt = bus->pktgen_count;
1623         oldmode = bus->pktgen_mode;
1624
1625         bus->pktgen_freq = pktgen.freq;
1626         bus->pktgen_count = pktgen.count;
1627         bus->pktgen_print = pktgen.print;
1628         bus->pktgen_total = pktgen.total;
1629         bus->pktgen_minlen = pktgen.minlen;
1630         bus->pktgen_maxlen = pktgen.maxlen;
1631         bus->pktgen_mode = pktgen.mode;
1632         bus->pktgen_stop = pktgen.stop;
1633
1634         bus->pktgen_tick = bus->pktgen_ptick = 0;
1635         bus->pktgen_len = MAX(bus->pktgen_len, bus->pktgen_minlen);
1636         bus->pktgen_len = MIN(bus->pktgen_len, bus->pktgen_maxlen);
1637
1638         /* Clear counts for a new pktgen (mode change, or was stopped) */
1639         if (bus->pktgen_count && (!oldcnt || oldmode != bus->pktgen_mode))
1640                 bus->pktgen_sent = bus->pktgen_rcvd = bus->pktgen_fail = 0;
1641
1642         return 0;
1643 }
1644 #endif /* SDTEST */
1645
1646 static int
1647 dhdsdio_membytes(dhd_bus_t *bus, bool write, uint32 address, uint8 *data, uint size)
1648 {
1649         int bcmerror = 0;
1650         uint32 sdaddr;
1651         uint dsize;
1652
1653         /* Determine initial transfer parameters */
1654         sdaddr = address & SBSDIO_SB_OFT_ADDR_MASK;
1655         if ((sdaddr + size) & SBSDIO_SBWINDOW_MASK)
1656                 dsize = (SBSDIO_SB_OFT_ADDR_LIMIT - sdaddr);
1657         else
1658                 dsize = size;
1659
1660         /* Set the backplane window to include the start address */
1661         if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) {
1662                 DHD_ERROR(("%s: window change failed\n", __FUNCTION__));
1663                 goto xfer_done;
1664         }
1665
1666         /* Do the transfer(s) */
1667         while (size) {
1668                 DHD_INFO(("%s: %s %d bytes at offset 0x%08x in window 0x%08x\n",
1669                           __FUNCTION__, (write ? "write" : "read"), dsize, sdaddr,
1670                           (address & SBSDIO_SBWINDOW_MASK)));
1671                 if ((bcmerror = bcmsdh_rwdata(bus->sdh, write, sdaddr, data, dsize))) {
1672                         DHD_ERROR(("%s: membytes transfer failed\n", __FUNCTION__));
1673                         break;
1674                 }
1675
1676                 /* Adjust for next transfer (if any) */
1677                 if ((size -= dsize)) {
1678                         data += dsize;
1679                         address += dsize;
1680                         if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) {
1681                                 DHD_ERROR(("%s: window change failed\n", __FUNCTION__));
1682                                 break;
1683                         }
1684                         sdaddr = 0;
1685                         dsize = MIN(SBSDIO_SB_OFT_ADDR_LIMIT, size);
1686                 }
1687         }
1688
1689 xfer_done:
1690         /* Return the window to backplane enumeration space for core access */
1691         if (dhdsdio_set_siaddr_window(bus, bcmsdh_cur_sbwad(bus->sdh))) {
1692                 DHD_ERROR(("%s: FAILED to set window back to 0x%x\n", __FUNCTION__,
1693                         bcmsdh_cur_sbwad(bus->sdh)));
1694         }
1695
1696         return bcmerror;
1697 }
1698
1699 #ifdef DHD_DEBUG
1700 static int
1701 dhdsdio_readshared(dhd_bus_t *bus, sdpcm_shared_t *sh)
1702 {
1703         uint32 addr;
1704         int rv;
1705
1706         /* Read last word in memory to determine address of sdpcm_shared structure */
1707         if ((rv = dhdsdio_membytes(bus, FALSE, bus->ramsize - 4, (uint8 *)&addr, 4)) < 0)
1708                 return rv;
1709
1710         addr = ltoh32(addr);
1711
1712         DHD_INFO(("sdpcm_shared address 0x%08X\n", addr));
1713
1714         /*
1715          * Check if addr is valid.
1716          * NVRAM length at the end of memory should have been overwritten.
1717          */
1718         if (addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff)) {
1719                 DHD_ERROR(("%s: address (0x%08x) of sdpcm_shared invalid\n", __FUNCTION__, addr));
1720                 return BCME_ERROR;
1721         }
1722
1723         /* Read hndrte_shared structure */
1724         if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)sh, sizeof(sdpcm_shared_t))) < 0)
1725                 return rv;
1726
1727         /* Endianness */
1728         sh->flags = ltoh32(sh->flags);
1729         sh->trap_addr = ltoh32(sh->trap_addr);
1730         sh->assert_exp_addr = ltoh32(sh->assert_exp_addr);
1731         sh->assert_file_addr = ltoh32(sh->assert_file_addr);
1732         sh->assert_line = ltoh32(sh->assert_line);
1733         sh->console_addr = ltoh32(sh->console_addr);
1734         sh->msgtrace_addr = ltoh32(sh->msgtrace_addr);
1735
1736         if ((sh->flags & SDPCM_SHARED_VERSION_MASK) != SDPCM_SHARED_VERSION) {
1737                 DHD_ERROR(("%s: sdpcm_shared version %d in dhd "
1738                            "is different than sdpcm_shared version %d in dongle\n",
1739                            __FUNCTION__, SDPCM_SHARED_VERSION,
1740                            sh->flags & SDPCM_SHARED_VERSION_MASK));
1741                 return BCME_ERROR;
1742         }
1743
1744         return BCME_OK;
1745 }
1746
1747 static int
1748 dhdsdio_checkdied(dhd_bus_t *bus, uint8 *data, uint size)
1749 {
1750         int bcmerror = 0;
1751         uint msize = 512;
1752         char *mbuffer = NULL;
1753         uint maxstrlen = 256;
1754         char *str = NULL;
1755         trap_t tr;
1756         sdpcm_shared_t sdpcm_shared;
1757         struct bcmstrbuf strbuf;
1758
1759         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1760
1761         if (data == NULL) {
1762                 /*
1763                  * Called after a rx ctrl timeout. "data" is NULL.
1764                  * allocate memory to trace the trap or assert.
1765                  */
1766                 size = msize;
1767                 mbuffer = data = MALLOC(bus->dhd->osh, msize);
1768                 if (mbuffer == NULL) {
1769                         DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, msize));
1770                         bcmerror = BCME_NOMEM;
1771                         goto done;
1772                 }
1773         }
1774
1775         if ((str = MALLOC(bus->dhd->osh, maxstrlen)) == NULL) {
1776                 DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, maxstrlen));
1777                 bcmerror = BCME_NOMEM;
1778                 goto done;
1779         }
1780
1781         if ((bcmerror = dhdsdio_readshared(bus, &sdpcm_shared)) < 0)
1782                 goto done;
1783
1784         bcm_binit(&strbuf, data, size);
1785
1786         bcm_bprintf(&strbuf, "msgtrace address : 0x%08X\nconsole address  : 0x%08X\n",
1787                     sdpcm_shared.msgtrace_addr, sdpcm_shared.console_addr);
1788
1789         if ((sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT) == 0) {
1790                 /* NOTE: Misspelled assert is intentional - DO NOT FIX.
1791                  * (Avoids conflict with real asserts for programmatic parsing of output.)
1792                  */
1793                 bcm_bprintf(&strbuf, "Assrt not built in dongle\n");
1794         }
1795
1796         if ((sdpcm_shared.flags & (SDPCM_SHARED_ASSERT|SDPCM_SHARED_TRAP)) == 0) {
1797                 /* NOTE: Misspelled assert is intentional - DO NOT FIX.
1798                  * (Avoids conflict with real asserts for programmatic parsing of output.)
1799                  */
1800                 bcm_bprintf(&strbuf, "No trap%s in dongle",
1801                           (sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT)
1802                           ?"/assrt" :"");
1803         } else {
1804                 if (sdpcm_shared.flags & SDPCM_SHARED_ASSERT) {
1805                         /* Download assert */
1806                         bcm_bprintf(&strbuf, "Dongle assert");
1807                         if (sdpcm_shared.assert_exp_addr != 0) {
1808                                 str[0] = '\0';
1809                                 if ((bcmerror = dhdsdio_membytes(bus, FALSE,
1810                                                                  sdpcm_shared.assert_exp_addr,
1811                                                                  (uint8 *)str, maxstrlen)) < 0)
1812                                         goto done;
1813
1814                                 str[maxstrlen - 1] = '\0';
1815                                 bcm_bprintf(&strbuf, " expr \"%s\"", str);
1816                         }
1817
1818                         if (sdpcm_shared.assert_file_addr != 0) {
1819                                 str[0] = '\0';
1820                                 if ((bcmerror = dhdsdio_membytes(bus, FALSE,
1821                                                                  sdpcm_shared.assert_file_addr,
1822                                                                  (uint8 *)str, maxstrlen)) < 0)
1823                                         goto done;
1824
1825                                 str[maxstrlen - 1] = '\0';
1826                                 bcm_bprintf(&strbuf, " file \"%s\"", str);
1827                         }
1828
1829                         bcm_bprintf(&strbuf, " line %d ", sdpcm_shared.assert_line);
1830                 }
1831
1832                 if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) {
1833                         if ((bcmerror = dhdsdio_membytes(bus, FALSE,
1834                                                          sdpcm_shared.trap_addr,
1835                                                          (uint8*)&tr, sizeof(trap_t))) < 0)
1836                                 goto done;
1837
1838                         bcm_bprintf(&strbuf,
1839                         "Dongle trap type 0x%x @ epc 0x%x, cpsr 0x%x, spsr 0x%x, sp 0x%x,"
1840                         "lp 0x%x, rpc 0x%x Trap offset 0x%x, "
1841                         "r0 0x%x, r1 0x%x, r2 0x%x, r3 0x%x, r4 0x%x, r5 0x%x, r6 0x%x, r7 0x%x\n",
1842                         tr.type, tr.epc, tr.cpsr, tr.spsr, tr.r13, tr.r14, tr.pc,
1843                         sdpcm_shared.trap_addr,
1844                         tr.r0, tr.r1, tr.r2, tr.r3, tr.r4, tr.r5, tr.r6, tr.r7);
1845                 }
1846         }
1847
1848         if (sdpcm_shared.flags & (SDPCM_SHARED_ASSERT | SDPCM_SHARED_TRAP)) {
1849                 DHD_ERROR(("%s: %s\n", __FUNCTION__, strbuf.origbuf));
1850         }
1851
1852 #ifdef DHD_DEBUG
1853         if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) {
1854                 /* Mem dump to a file on device */
1855                 dhdsdio_mem_dump(bus);
1856         }
1857 #endif /* DHD_DEBUG */
1858
1859 done:
1860         if (mbuffer)
1861                 MFREE(bus->dhd->osh, mbuffer, msize);
1862         if (str)
1863                 MFREE(bus->dhd->osh, str, maxstrlen);
1864
1865         return bcmerror;
1866 }
1867
1868 static int
1869 dhdsdio_mem_dump(dhd_bus_t *bus)
1870 {
1871         int ret = 0;
1872         int size; /* Full mem size */
1873         int start = 0; /* Start address */
1874         int read_size = 0; /* Read size of each iteration */
1875         uint8 *buf = NULL, *databuf = NULL;
1876
1877         /* Get full mem size */
1878         size = bus->ramsize;
1879         buf = MALLOC(bus->dhd->osh, size);
1880         if (!buf) {
1881                 printf("%s: Out of memory (%d bytes)\n", __FUNCTION__, size);
1882                 return -1;
1883         }
1884
1885         /* Read mem content */
1886         printf("Dump dongle memory");
1887         databuf = buf;
1888         while (size)
1889         {
1890                 read_size = MIN(MEMBLOCK, size);
1891                 if ((ret = dhdsdio_membytes(bus, FALSE, start, databuf, read_size)))
1892                 {
1893                         printf("%s: Error membytes %d\n", __FUNCTION__, ret);
1894                         if (buf) {
1895                                 MFREE(bus->dhd->osh, buf, size);
1896                         }
1897                         return -1;
1898                 }
1899                 printf(".");
1900
1901                 /* Decrement size and increment start address */
1902                 size -= read_size;
1903                 start += read_size;
1904                 databuf += read_size;
1905         }
1906         printf("Done\n");
1907
1908         /* free buf before return !!! */
1909         if (write_to_file(bus->dhd, buf, bus->ramsize))
1910         {
1911                 printf("%s: Error writing to files\n", __FUNCTION__);
1912                 return -1;
1913         }
1914
1915         /* buf free handled in write_to_file, not here */
1916         return 0;
1917 }
1918
1919 #define CONSOLE_LINE_MAX        192
1920
1921 static int
1922 dhdsdio_readconsole(dhd_bus_t *bus)
1923 {
1924         dhd_console_t *c = &bus->console;
1925         uint8 line[CONSOLE_LINE_MAX], ch;
1926         uint32 n, idx, addr;
1927         int rv;
1928
1929         /* Don't do anything until FWREADY updates console address */
1930         if (bus->console_addr == 0)
1931                 return 0;
1932
1933         /* Read console log struct */
1934         addr = bus->console_addr + OFFSETOF(hndrte_cons_t, log);
1935         if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)&c->log, sizeof(c->log))) < 0)
1936                 return rv;
1937
1938         /* Allocate console buffer (one time only) */
1939         if (c->buf == NULL) {
1940                 c->bufsize = ltoh32(c->log.buf_size);
1941                 if ((c->buf = MALLOC(bus->dhd->osh, c->bufsize)) == NULL)
1942                         return BCME_NOMEM;
1943         }
1944
1945         idx = ltoh32(c->log.idx);
1946
1947         /* Protect against corrupt value */
1948         if (idx > c->bufsize)
1949                 return BCME_ERROR;
1950
1951         /* Skip reading the console buffer if the index pointer has not moved */
1952         if (idx == c->last)
1953                 return BCME_OK;
1954
1955         /* Read the console buffer */
1956         addr = ltoh32(c->log.buf);
1957         if ((rv = dhdsdio_membytes(bus, FALSE, addr, c->buf, c->bufsize)) < 0)
1958                 return rv;
1959
1960         while (c->last != idx) {
1961                 for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) {
1962                         if (c->last == idx) {
1963                                 /* This would output a partial line.  Instead, back up
1964                                  * the buffer pointer and output this line next time around.
1965                                  */
1966                                 if (c->last >= n)
1967                                         c->last -= n;
1968                                 else
1969                                         c->last = c->bufsize - n;
1970                                 goto break2;
1971                         }
1972                         ch = c->buf[c->last];
1973                         c->last = (c->last + 1) % c->bufsize;
1974                         if (ch == '\n')
1975                                 break;
1976                         line[n] = ch;
1977                 }
1978
1979                 if (n > 0) {
1980                         if (line[n - 1] == '\r')
1981                                 n--;
1982                         line[n] = 0;
1983                         printf("CONSOLE: %s\n", line);
1984                 }
1985         }
1986 break2:
1987
1988         return BCME_OK;
1989 }
1990 #endif /* DHD_DEBUG */
1991
1992 int
1993 dhdsdio_downloadvars(dhd_bus_t *bus, void *arg, int len)
1994 {
1995         int bcmerror = BCME_OK;
1996
1997         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1998
1999         /* Basic sanity checks */
2000         if (bus->dhd->up) {
2001                 bcmerror = BCME_NOTDOWN;
2002                 goto err;
2003         }
2004         if (!len) {
2005                 bcmerror = BCME_BUFTOOSHORT;
2006                 goto err;
2007         }
2008
2009         /* Free the old ones and replace with passed variables */
2010         if (bus->vars)
2011                 MFREE(bus->dhd->osh, bus->vars, bus->varsz);
2012
2013         bus->vars = MALLOC(bus->dhd->osh, len);
2014         bus->varsz = bus->vars ? len : 0;
2015         if (bus->vars == NULL) {
2016                 bcmerror = BCME_NOMEM;
2017                 goto err;
2018         }
2019
2020         /* Copy the passed variables, which should include the terminating double-null */
2021         bcopy(arg, bus->vars, bus->varsz);
2022 err:
2023         return bcmerror;
2024 }
2025
2026 static int
2027 dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const char *name,
2028                 void *params, int plen, void *arg, int len, int val_size)
2029 {
2030         int bcmerror = 0;
2031         int32 int_val = 0;
2032         bool bool_val = 0;
2033
2034         DHD_TRACE(("%s: Enter, action %d name %s params %p plen %d arg %p len %d val_size %d\n",
2035                    __FUNCTION__, actionid, name, params, plen, arg, len, val_size));
2036
2037         if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0)
2038                 goto exit;
2039
2040         if (plen >= (int)sizeof(int_val))
2041                 bcopy(params, &int_val, sizeof(int_val));
2042
2043         bool_val = (int_val != 0) ? TRUE : FALSE;
2044
2045
2046         /* Some ioctls use the bus */
2047         dhd_os_sdlock(bus->dhd);
2048
2049         /* Check if dongle is in reset. If so, only allow DEVRESET iovars */
2050         if (bus->dhd->dongle_reset && !(actionid == IOV_SVAL(IOV_DEVRESET) ||
2051                                         actionid == IOV_GVAL(IOV_DEVRESET))) {
2052                 bcmerror = BCME_NOTREADY;
2053                 goto exit;
2054         }
2055
2056         /* Handle sleep stuff before any clock mucking */
2057         if (vi->varid == IOV_SLEEP) {
2058                 if (IOV_ISSET(actionid)) {
2059                         bcmerror = dhdsdio_bussleep(bus, bool_val);
2060                 } else {
2061                         int_val = (int32)bus->sleeping;
2062                         bcopy(&int_val, arg, val_size);
2063                 }
2064                 goto exit;
2065         }
2066
2067         /* Request clock to allow SDIO accesses */
2068         if (!bus->dhd->dongle_reset) {
2069                 BUS_WAKE(bus);
2070                 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
2071         }
2072
2073         switch (actionid) {
2074         case IOV_GVAL(IOV_INTR):
2075                 int_val = (int32)bus->intr;
2076                 bcopy(&int_val, arg, val_size);
2077                 break;
2078
2079         case IOV_SVAL(IOV_INTR):
2080                 bus->intr = bool_val;
2081                 bus->intdis = FALSE;
2082                 if (bus->dhd->up) {
2083                         if (bus->intr) {
2084                                 DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__));
2085                                 bcmsdh_intr_enable(bus->sdh);
2086                         } else {
2087                                 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
2088                                 bcmsdh_intr_disable(bus->sdh);
2089                         }
2090                 }
2091                 break;
2092
2093         case IOV_GVAL(IOV_POLLRATE):
2094                 int_val = (int32)bus->pollrate;
2095                 bcopy(&int_val, arg, val_size);
2096                 break;
2097
2098         case IOV_SVAL(IOV_POLLRATE):
2099                 bus->pollrate = (uint)int_val;
2100                 bus->poll = (bus->pollrate != 0);
2101                 break;
2102
2103         case IOV_GVAL(IOV_IDLETIME):
2104                 int_val = bus->idletime;
2105                 bcopy(&int_val, arg, val_size);
2106                 break;
2107
2108         case IOV_SVAL(IOV_IDLETIME):
2109                 if ((int_val < 0) && (int_val != DHD_IDLE_IMMEDIATE)) {
2110                         bcmerror = BCME_BADARG;
2111                 } else {
2112                         bus->idletime = int_val;
2113                 }
2114                 break;
2115
2116         case IOV_GVAL(IOV_IDLECLOCK):
2117                 int_val = (int32)bus->idleclock;
2118                 bcopy(&int_val, arg, val_size);
2119                 break;
2120
2121         case IOV_SVAL(IOV_IDLECLOCK):
2122                 bus->idleclock = int_val;
2123                 break;
2124
2125         case IOV_GVAL(IOV_SD1IDLE):
2126                 int_val = (int32)sd1idle;
2127                 bcopy(&int_val, arg, val_size);
2128                 break;
2129
2130         case IOV_SVAL(IOV_SD1IDLE):
2131                 sd1idle = bool_val;
2132                 break;
2133
2134
2135         case IOV_SVAL(IOV_MEMBYTES):
2136         case IOV_GVAL(IOV_MEMBYTES):
2137         {
2138                 uint32 address;
2139                 uint size, dsize;
2140                 uint8 *data;
2141
2142                 bool set = (actionid == IOV_SVAL(IOV_MEMBYTES));
2143
2144                 ASSERT(plen >= 2*sizeof(int));
2145
2146                 address = (uint32)int_val;
2147                 bcopy((char *)params + sizeof(int_val), &int_val, sizeof(int_val));
2148                 size = (uint)int_val;
2149
2150                 /* Do some validation */
2151                 dsize = set ? plen - (2 * sizeof(int)) : len;
2152                 if (dsize < size) {
2153                         DHD_ERROR(("%s: error on %s membytes, addr 0x%08x size %d dsize %d\n",
2154                                    __FUNCTION__, (set ? "set" : "get"), address, size, dsize));
2155                         bcmerror = BCME_BADARG;
2156                         break;
2157                 }
2158
2159                 DHD_INFO(("%s: Request to %s %d bytes at address 0x%08x\n", __FUNCTION__,
2160                           (set ? "write" : "read"), size, address));
2161
2162                 /* If we know about SOCRAM, check for a fit */
2163                 if ((bus->orig_ramsize) &&
2164                     ((address > bus->orig_ramsize) || (address + size > bus->orig_ramsize))) {
2165                         DHD_ERROR(("%s: ramsize 0x%08x doesn't have %d bytes at 0x%08x\n",
2166                                    __FUNCTION__, bus->orig_ramsize, size, address));
2167                         bcmerror = BCME_BADARG;
2168                         break;
2169                 }
2170
2171                 /* Generate the actual data pointer */
2172                 data = set ? (uint8*)params + 2 * sizeof(int): (uint8*)arg;
2173
2174                 /* Call to do the transfer */
2175                 bcmerror = dhdsdio_membytes(bus, set, address, data, size);
2176
2177                 break;
2178         }
2179
2180         case IOV_GVAL(IOV_MEMSIZE):
2181                 int_val = (int32)bus->ramsize;
2182                 bcopy(&int_val, arg, val_size);
2183                 break;
2184
2185         case IOV_GVAL(IOV_SDIOD_DRIVE):
2186                 int_val = (int32)dhd_sdiod_drive_strength;
2187                 bcopy(&int_val, arg, val_size);
2188                 break;
2189
2190         case IOV_SVAL(IOV_SDIOD_DRIVE):
2191                 dhd_sdiod_drive_strength = int_val;
2192                 si_sdiod_drive_strength_init(bus->sih, bus->dhd->osh, dhd_sdiod_drive_strength);
2193                 break;
2194
2195         case IOV_SVAL(IOV_DOWNLOAD):
2196                 bcmerror = dhdsdio_download_state(bus, bool_val);
2197                 break;
2198
2199         case IOV_SVAL(IOV_VARS):
2200                 bcmerror = dhdsdio_downloadvars(bus, arg, len);
2201                 break;
2202
2203         case IOV_GVAL(IOV_READAHEAD):
2204                 int_val = (int32)dhd_readahead;
2205                 bcopy(&int_val, arg, val_size);
2206                 break;
2207
2208         case IOV_SVAL(IOV_READAHEAD):
2209                 if (bool_val && !dhd_readahead)
2210                         bus->nextlen = 0;
2211                 dhd_readahead = bool_val;
2212                 break;
2213
2214         case IOV_GVAL(IOV_SDRXCHAIN):
2215                 int_val = (int32)bus->use_rxchain;
2216                 bcopy(&int_val, arg, val_size);
2217                 break;
2218
2219         case IOV_SVAL(IOV_SDRXCHAIN):
2220                 if (bool_val && !bus->sd_rxchain)
2221                         bcmerror = BCME_UNSUPPORTED;
2222                 else
2223                         bus->use_rxchain = bool_val;
2224                 break;
2225         case IOV_GVAL(IOV_ALIGNCTL):
2226                 int_val = (int32)dhd_alignctl;
2227                 bcopy(&int_val, arg, val_size);
2228                 break;
2229
2230         case IOV_SVAL(IOV_ALIGNCTL):
2231                 dhd_alignctl = bool_val;
2232                 break;
2233
2234         case IOV_GVAL(IOV_SDALIGN):
2235                 int_val = DHD_SDALIGN;
2236                 bcopy(&int_val, arg, val_size);
2237                 break;
2238
2239 #ifdef DHD_DEBUG
2240         case IOV_GVAL(IOV_VARS):
2241                 if (bus->varsz < (uint)len)
2242                         bcopy(bus->vars, arg, bus->varsz);
2243                 else
2244                         bcmerror = BCME_BUFTOOSHORT;
2245                 break;
2246 #endif /* DHD_DEBUG */
2247
2248 #ifdef DHD_DEBUG
2249         case IOV_GVAL(IOV_SDREG):
2250         {
2251                 sdreg_t *sd_ptr;
2252                 uint32 addr, size;
2253
2254                 sd_ptr = (sdreg_t *)params;
2255
2256                 addr = (uintptr)bus->regs + sd_ptr->offset;
2257                 size = sd_ptr->func;
2258                 int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size);
2259                 if (bcmsdh_regfail(bus->sdh))
2260                         bcmerror = BCME_SDIO_ERROR;
2261                 bcopy(&int_val, arg, sizeof(int32));
2262                 break;
2263         }
2264
2265         case IOV_SVAL(IOV_SDREG):
2266         {
2267                 sdreg_t *sd_ptr;
2268                 uint32 addr, size;
2269
2270                 sd_ptr = (sdreg_t *)params;
2271
2272                 addr = (uintptr)bus->regs + sd_ptr->offset;
2273                 size = sd_ptr->func;
2274                 bcmsdh_reg_write(bus->sdh, addr, size, sd_ptr->value);
2275                 if (bcmsdh_regfail(bus->sdh))
2276                         bcmerror = BCME_SDIO_ERROR;
2277                 break;
2278         }
2279
2280         /* Same as above, but offset is not backplane (not SDIO core) */
2281         case IOV_GVAL(IOV_SBREG):
2282         {
2283                 sdreg_t sdreg;
2284                 uint32 addr, size;
2285
2286                 bcopy(params, &sdreg, sizeof(sdreg));
2287
2288                 addr = SI_ENUM_BASE + sdreg.offset;
2289                 size = sdreg.func;
2290                 int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size);
2291                 if (bcmsdh_regfail(bus->sdh))
2292                         bcmerror = BCME_SDIO_ERROR;
2293                 bcopy(&int_val, arg, sizeof(int32));
2294                 break;
2295         }
2296
2297         case IOV_SVAL(IOV_SBREG):
2298         {
2299                 sdreg_t sdreg;
2300                 uint32 addr, size;
2301
2302                 bcopy(params, &sdreg, sizeof(sdreg));
2303
2304                 addr = SI_ENUM_BASE + sdreg.offset;
2305                 size = sdreg.func;
2306                 bcmsdh_reg_write(bus->sdh, addr, size, sdreg.value);
2307                 if (bcmsdh_regfail(bus->sdh))
2308                         bcmerror = BCME_SDIO_ERROR;
2309                 break;
2310         }
2311
2312         case IOV_GVAL(IOV_SDCIS):
2313         {
2314                 *(char *)arg = 0;
2315
2316                 bcmstrcat(arg, "\nFunc 0\n");
2317                 bcmsdh_cis_read(bus->sdh, 0x10, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
2318                 bcmstrcat(arg, "\nFunc 1\n");
2319                 bcmsdh_cis_read(bus->sdh, 0x11, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
2320                 bcmstrcat(arg, "\nFunc 2\n");
2321                 bcmsdh_cis_read(bus->sdh, 0x12, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
2322                 break;
2323         }
2324
2325         case IOV_GVAL(IOV_FORCEEVEN):
2326                 int_val = (int32)forcealign;
2327                 bcopy(&int_val, arg, val_size);
2328                 break;
2329
2330         case IOV_SVAL(IOV_FORCEEVEN):
2331                 forcealign = bool_val;
2332                 break;
2333
2334         case IOV_GVAL(IOV_TXBOUND):
2335                 int_val = (int32)dhd_txbound;
2336                 bcopy(&int_val, arg, val_size);
2337                 break;
2338
2339         case IOV_SVAL(IOV_TXBOUND):
2340                 dhd_txbound = (uint)int_val;
2341                 break;
2342
2343         case IOV_GVAL(IOV_RXBOUND):
2344                 int_val = (int32)dhd_rxbound;
2345                 bcopy(&int_val, arg, val_size);
2346                 break;
2347
2348         case IOV_SVAL(IOV_RXBOUND):
2349                 dhd_rxbound = (uint)int_val;
2350                 break;
2351
2352         case IOV_GVAL(IOV_TXMINMAX):
2353                 int_val = (int32)dhd_txminmax;
2354                 bcopy(&int_val, arg, val_size);
2355                 break;
2356
2357         case IOV_SVAL(IOV_TXMINMAX):
2358                 dhd_txminmax = (uint)int_val;
2359                 break;
2360
2361
2362
2363 #endif /* DHD_DEBUG */
2364
2365
2366 #ifdef SDTEST
2367         case IOV_GVAL(IOV_EXTLOOP):
2368                 int_val = (int32)bus->ext_loop;
2369                 bcopy(&int_val, arg, val_size);
2370                 break;
2371
2372         case IOV_SVAL(IOV_EXTLOOP):
2373                 bus->ext_loop = bool_val;
2374                 break;
2375
2376         case IOV_GVAL(IOV_PKTGEN):
2377                 bcmerror = dhdsdio_pktgen_get(bus, arg);
2378                 break;
2379
2380         case IOV_SVAL(IOV_PKTGEN):
2381                 bcmerror = dhdsdio_pktgen_set(bus, arg);
2382                 break;
2383 #endif /* SDTEST */
2384
2385
2386         case IOV_SVAL(IOV_DEVRESET):
2387                 DHD_TRACE(("%s: Called set IOV_DEVRESET=%d dongle_reset=%d busstate=%d\n",
2388                            __FUNCTION__, bool_val, bus->dhd->dongle_reset,
2389                            bus->dhd->busstate));
2390
2391                 ASSERT(bus->dhd->osh);
2392                 /* ASSERT(bus->cl_devid); */
2393
2394                 dhd_bus_devreset(bus->dhd, (uint8)bool_val);
2395
2396                 break;
2397
2398         case IOV_GVAL(IOV_DEVRESET):
2399                 DHD_TRACE(("%s: Called get IOV_DEVRESET\n", __FUNCTION__));
2400
2401                 /* Get its status */
2402                 int_val = (bool) bus->dhd->dongle_reset;
2403                 bcopy(&int_val, arg, val_size);
2404
2405                 break;
2406
2407         default:
2408                 bcmerror = BCME_UNSUPPORTED;
2409                 break;
2410         }
2411
2412 exit:
2413         if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
2414                 bus->activity = FALSE;
2415                 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
2416         }
2417
2418         dhd_os_sdunlock(bus->dhd);
2419
2420         if (actionid == IOV_SVAL(IOV_DEVRESET) && bool_val == FALSE)
2421                 dhd_preinit_ioctls((dhd_pub_t *) bus->dhd);
2422
2423         return bcmerror;
2424 }
2425
2426 static int
2427 dhdsdio_write_vars(dhd_bus_t *bus)
2428 {
2429         int bcmerror = 0;
2430         uint32 varsize;
2431         uint32 varaddr;
2432         uint8 *vbuffer;
2433         uint32 varsizew;
2434 #ifdef DHD_DEBUG
2435         char *nvram_ularray;
2436 #endif /* DHD_DEBUG */
2437
2438         /* Even if there are no vars are to be written, we still need to set the ramsize. */
2439         varsize = bus->varsz ? ROUNDUP(bus->varsz, 4) : 0;
2440         varaddr = (bus->ramsize - 4) - varsize;
2441
2442         if (bus->vars) {
2443                 vbuffer = (uint8 *)MALLOC(bus->dhd->osh, varsize);
2444                 if (!vbuffer)
2445                         return BCME_NOMEM;
2446
2447                 bzero(vbuffer, varsize);
2448                 bcopy(bus->vars, vbuffer, bus->varsz);
2449
2450                 /* Write the vars list */
2451                 bcmerror = dhdsdio_membytes(bus, TRUE, varaddr, vbuffer, varsize);
2452 #ifdef DHD_DEBUG
2453                 /* Verify NVRAM bytes */
2454                 DHD_INFO(("Compare NVRAM dl & ul; varsize=%d\n", varsize));
2455                 nvram_ularray = (char*)MALLOC(bus->dhd->osh, varsize);
2456                 if (!nvram_ularray)
2457                         return BCME_NOMEM;
2458
2459                 /* Upload image to verify downloaded contents. */
2460                 memset(nvram_ularray, 0xaa, varsize);
2461
2462                 /* Read the vars list to temp buffer for comparison */
2463                 bcmerror = dhdsdio_membytes(bus, FALSE, varaddr, nvram_ularray, varsize);
2464                 if (bcmerror) {
2465                                 DHD_ERROR(("%s: error %d on reading %d nvram bytes at 0x%08x\n",
2466                                         __FUNCTION__, bcmerror, varsize, varaddr));
2467                 }
2468                 /* Compare the org NVRAM with the one read from RAM */
2469                 if (memcmp(vbuffer, nvram_ularray, varsize)) {
2470                         DHD_ERROR(("%s: Downloaded NVRAM image is corrupted.\n", __FUNCTION__));
2471                 } else
2472                         DHD_ERROR(("%s: Download, Upload and compare of NVRAM succeeded.\n",
2473                         __FUNCTION__));
2474
2475                 MFREE(bus->dhd->osh, nvram_ularray, varsize);
2476 #endif /* DHD_DEBUG */
2477
2478                 MFREE(bus->dhd->osh, vbuffer, varsize);
2479         }
2480
2481         /* adjust to the user specified RAM */
2482         DHD_INFO(("Physical memory size: %d, usable memory size: %d\n",
2483                 bus->orig_ramsize, bus->ramsize));
2484         DHD_INFO(("Vars are at %d, orig varsize is %d\n",
2485                 varaddr, varsize));
2486         varsize = ((bus->orig_ramsize - 4) - varaddr);
2487
2488         /*
2489          * Determine the length token:
2490          * Varsize, converted to words, in lower 16-bits, checksum in upper 16-bits.
2491          */
2492         if (bcmerror) {
2493                 varsizew = 0;
2494         } else {
2495                 varsizew = varsize / 4;
2496                 varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF);
2497                 varsizew = htol32(varsizew);
2498         }
2499
2500         DHD_INFO(("New varsize is %d, length token=0x%08x\n", varsize, varsizew));
2501
2502         /* Write the length token to the last word */
2503         bcmerror = dhdsdio_membytes(bus, TRUE, (bus->orig_ramsize - 4),
2504                 (uint8*)&varsizew, 4);
2505
2506         return bcmerror;
2507 }
2508
2509 static int
2510 dhdsdio_download_state(dhd_bus_t *bus, bool enter)
2511 {
2512         uint retries;
2513         int bcmerror = 0;
2514
2515         /* To enter download state, disable ARM and reset SOCRAM.
2516          * To exit download state, simply reset ARM (default is RAM boot).
2517          */
2518         if (enter) {
2519
2520                 bus->alp_only = TRUE;
2521
2522                 if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) &&
2523                     !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) {
2524                         DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__));
2525                         bcmerror = BCME_ERROR;
2526                         goto fail;
2527                 }
2528
2529                 si_core_disable(bus->sih, 0);
2530                 if (bcmsdh_regfail(bus->sdh)) {
2531                         bcmerror = BCME_SDIO_ERROR;
2532                         goto fail;
2533                 }
2534
2535                 if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) {
2536                         DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__));
2537                         bcmerror = BCME_ERROR;
2538                         goto fail;
2539                 }
2540
2541                 si_core_reset(bus->sih, 0, 0);
2542                 if (bcmsdh_regfail(bus->sdh)) {
2543                         DHD_ERROR(("%s: Failure trying reset SOCRAM core?\n", __FUNCTION__));
2544                         bcmerror = BCME_SDIO_ERROR;
2545                         goto fail;
2546                 }
2547
2548                 /* Clear the top bit of memory */
2549                 if (bus->ramsize) {
2550                         uint32 zeros = 0;
2551                         dhdsdio_membytes(bus, TRUE, bus->ramsize - 4, (uint8*)&zeros, 4);
2552                 }
2553         } else {
2554                 if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) {
2555                         DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__));
2556                         bcmerror = BCME_ERROR;
2557                         goto fail;
2558                 }
2559
2560                 if (!si_iscoreup(bus->sih)) {
2561                         DHD_ERROR(("%s: SOCRAM core is down after reset?\n", __FUNCTION__));
2562                         bcmerror = BCME_ERROR;
2563                         goto fail;
2564                 }
2565
2566                 if ((bcmerror = dhdsdio_write_vars(bus))) {
2567                         DHD_ERROR(("%s: no vars written to RAM\n", __FUNCTION__));
2568                         bcmerror = 0;
2569                 }
2570
2571                 if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) &&
2572                     !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) {
2573                         DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__));
2574                         bcmerror = BCME_ERROR;
2575                         goto fail;
2576                 }
2577                 W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries);
2578
2579
2580                 if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) &&
2581                     !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) {
2582                         DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__));
2583                         bcmerror = BCME_ERROR;
2584                         goto fail;
2585                 }
2586
2587                 si_core_reset(bus->sih, 0, 0);
2588                 if (bcmsdh_regfail(bus->sdh)) {
2589                         DHD_ERROR(("%s: Failure trying to reset ARM core?\n", __FUNCTION__));
2590                         bcmerror = BCME_SDIO_ERROR;
2591                         goto fail;
2592                 }
2593
2594                 /* Allow HT Clock now that the ARM is running. */
2595                 bus->alp_only = FALSE;
2596
2597                 bus->dhd->busstate = DHD_BUS_LOAD;
2598         }
2599
2600 fail:
2601         /* Always return to SDIOD core */
2602         if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0))
2603                 si_setcore(bus->sih, SDIOD_CORE_ID, 0);
2604
2605         return bcmerror;
2606 }
2607
2608 int
2609 dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name,
2610                  void *params, int plen, void *arg, int len, bool set)
2611 {
2612         dhd_bus_t *bus = dhdp->bus;
2613         const bcm_iovar_t *vi = NULL;
2614         int bcmerror = 0;
2615         int val_size;
2616         uint32 actionid;
2617
2618         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2619
2620         ASSERT(name);
2621         ASSERT(len >= 0);
2622
2623         /* Get MUST have return space */
2624         ASSERT(set || (arg && len));
2625
2626         /* Set does NOT take qualifiers */
2627         ASSERT(!set || (!params && !plen));
2628
2629         /* Look up var locally; if not found pass to host driver */
2630         if ((vi = bcm_iovar_lookup(dhdsdio_iovars, name)) == NULL) {
2631                 dhd_os_sdlock(bus->dhd);
2632
2633                 BUS_WAKE(bus);
2634
2635                 /* Turn on clock in case SD command needs backplane */
2636                 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
2637
2638                 bcmerror = bcmsdh_iovar_op(bus->sdh, name, params, plen, arg, len, set);
2639
2640                 /* Check for bus configuration changes of interest */
2641
2642                 /* If it was divisor change, read the new one */
2643                 if (set && strcmp(name, "sd_divisor") == 0) {
2644                         if (bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
2645                                             &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) {
2646                                 bus->sd_divisor = -1;
2647                                 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, name));
2648                         } else {
2649                                 DHD_INFO(("%s: noted %s update, value now %d\n",
2650                                           __FUNCTION__, name, bus->sd_divisor));
2651                         }
2652                 }
2653                 /* If it was a mode change, read the new one */
2654                 if (set && strcmp(name, "sd_mode") == 0) {
2655                         if (bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
2656                                             &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) {
2657                                 bus->sd_mode = -1;
2658                                 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, name));
2659                         } else {
2660                                 DHD_INFO(("%s: noted %s update, value now %d\n",
2661                                           __FUNCTION__, name, bus->sd_mode));
2662                         }
2663                 }
2664                 /* Similar check for blocksize change */
2665                 if (set && strcmp(name, "sd_blocksize") == 0) {
2666                         int32 fnum = 2;
2667                         if (bcmsdh_iovar_op(bus->sdh, "sd_blocksize", &fnum, sizeof(int32),
2668                                             &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) {
2669                                 bus->blocksize = 0;
2670                                 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize"));
2671                         } else {
2672                                 DHD_INFO(("%s: noted %s update, value now %d\n",
2673                                           __FUNCTION__, "sd_blocksize", bus->blocksize));
2674                         }
2675                 }
2676                 bus->roundup = MIN(max_roundup, bus->blocksize);
2677
2678                 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
2679                         bus->activity = FALSE;
2680                         dhdsdio_clkctl(bus, CLK_NONE, TRUE);
2681                 }
2682
2683                 dhd_os_sdunlock(bus->dhd);
2684                 goto exit;
2685         }
2686
2687         DHD_CTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__,
2688                  name, (set ? "set" : "get"), len, plen));
2689
2690         /* set up 'params' pointer in case this is a set command so that
2691          * the convenience int and bool code can be common to set and get
2692          */
2693         if (params == NULL) {
2694                 params = arg;
2695                 plen = len;
2696         }
2697
2698         if (vi->type == IOVT_VOID)
2699                 val_size = 0;
2700         else if (vi->type == IOVT_BUFFER)
2701                 val_size = len;
2702         else
2703                 /* all other types are integer sized */
2704                 val_size = sizeof(int);
2705
2706         actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
2707         bcmerror = dhdsdio_doiovar(bus, vi, actionid, name, params, plen, arg, len, val_size);
2708
2709 exit:
2710         return bcmerror;
2711 }
2712
2713 void
2714 dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex)
2715 {
2716         osl_t *osh = bus->dhd->osh;
2717         uint32 local_hostintmask;
2718         uint8 saveclk;
2719         uint retries;
2720         int err;
2721
2722         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2723
2724         if (enforce_mutex)
2725                 dhd_os_sdlock(bus->dhd);
2726
2727         BUS_WAKE(bus);
2728
2729         /* Enable clock for device interrupts */
2730         dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
2731
2732         /* Disable and clear interrupts at the chip level also */
2733         W_SDREG(0, &bus->regs->hostintmask, retries);
2734         local_hostintmask = bus->hostintmask;
2735         bus->hostintmask = 0;
2736
2737         /* Change our idea of bus state */
2738         bus->dhd->busstate = DHD_BUS_DOWN;
2739
2740         /* Force clocks on backplane to be sure F2 interrupt propagates */
2741         saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
2742         if (!err) {
2743                 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
2744                                  (saveclk | SBSDIO_FORCE_HT), &err);
2745         }
2746         if (err) {
2747                 DHD_ERROR(("%s: Failed to force clock for F2: err %d\n", __FUNCTION__, err));
2748         }
2749
2750         /* Turn off the bus (F2), free any pending packets */
2751         DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
2752         bcmsdh_intr_disable(bus->sdh);
2753         bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL);
2754
2755         /* Clear any pending interrupts now that F2 is disabled */
2756         W_SDREG(local_hostintmask, &bus->regs->intstatus, retries);
2757
2758         /* Turn off the backplane clock (only) */
2759         dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
2760
2761         /* Clear the data packet queues */
2762         pktq_flush(osh, &bus->txq, TRUE);
2763
2764         /* Clear any held glomming stuff */
2765         if (bus->glomd)
2766                 PKTFREE(osh, bus->glomd, FALSE);
2767
2768         if (bus->glom)
2769                 PKTFREE(osh, bus->glom, FALSE);
2770
2771         bus->glom = bus->glomd = NULL;
2772
2773         /* Clear rx control and wake any waiters */
2774         bus->rxlen = 0;
2775         dhd_os_ioctl_resp_wake(bus->dhd);
2776
2777         /* Reset some F2 state stuff */
2778         bus->rxskip = FALSE;
2779         bus->tx_seq = bus->rx_seq = 0;
2780
2781         if (enforce_mutex)
2782                 dhd_os_sdunlock(bus->dhd);
2783 }
2784
2785 int
2786 dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex)
2787 {
2788         dhd_bus_t *bus = dhdp->bus;
2789         dhd_timeout_t tmo;
2790         uint retries = 0;
2791         uint8 ready, enable;
2792         int err, ret = 0;
2793         uint8 saveclk;
2794
2795         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2796
2797         ASSERT(bus->dhd);
2798         if (!bus->dhd)
2799                 return 0;
2800
2801         if (enforce_mutex)
2802                 dhd_os_sdlock(bus->dhd);
2803
2804         /* Make sure backplane clock is on, needed to generate F2 interrupt */
2805         dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
2806         if (bus->clkstate != CLK_AVAIL)
2807                 goto exit;
2808
2809
2810         /* Force clocks on backplane to be sure F2 interrupt propagates */
2811         saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
2812         if (!err) {
2813                 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
2814                                  (saveclk | SBSDIO_FORCE_HT), &err);
2815         }
2816         if (err) {
2817                 DHD_ERROR(("%s: Failed to force clock for F2: err %d\n", __FUNCTION__, err));
2818                 goto exit;
2819         }
2820
2821         /* Enable function 2 (frame transfers) */
2822         W_SDREG((SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT),
2823                 &bus->regs->tosbmailboxdata, retries);
2824         enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2);
2825
2826         bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL);
2827
2828         /* Give the dongle some time to do its thing and set IOR2 */
2829         dhd_timeout_start(&tmo, DHD_WAIT_F2RDY * 1000);
2830
2831         ready = 0;
2832         while (ready != enable && !dhd_timeout_expired(&tmo))
2833                 ready = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IORDY, NULL);
2834
2835
2836         DHD_INFO(("%s: enable 0x%02x, ready 0x%02x (waited %uus)\n",
2837                   __FUNCTION__, enable, ready, tmo.elapsed));
2838
2839
2840         /* If F2 successfully enabled, set core and enable interrupts */
2841         if (ready == enable) {
2842                 /* Make sure we're talking to the core. */
2843                 if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0)))
2844                         bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0);
2845
2846                 /* Set up the interrupt mask and enable interrupts */
2847                 bus->hostintmask = HOSTINTMASK;
2848                 W_SDREG(bus->hostintmask, &bus->regs->hostintmask, retries);
2849
2850                 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, (uint8)watermark, &err);
2851
2852                 /* Set bus state according to enable result */
2853                 dhdp->busstate = DHD_BUS_DATA;
2854
2855                 /* bcmsdh_intr_unmask(bus->sdh); */
2856
2857                 bus->intdis = FALSE;
2858                 if (bus->intr) {
2859                         DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__));
2860                         bcmsdh_intr_enable(bus->sdh);
2861                 } else {
2862                         DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
2863                         bcmsdh_intr_disable(bus->sdh);
2864                 }
2865
2866         }
2867
2868
2869         else {
2870                 /* Disable F2 again */
2871                 enable = SDIO_FUNC_ENABLE_1;
2872                 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL);
2873         }
2874
2875         /* Restore previous clock setting */
2876         bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err);
2877
2878
2879         /* If we didn't come up, turn off backplane clock */
2880         if (dhdp->busstate != DHD_BUS_DATA)
2881                 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
2882
2883 exit:
2884         if (enforce_mutex)
2885                 dhd_os_sdunlock(bus->dhd);
2886
2887         return ret;
2888 }
2889
2890 static void
2891 dhdsdio_rxfail(dhd_bus_t *bus, bool abort, bool rtx)
2892 {
2893         bcmsdh_info_t *sdh = bus->sdh;
2894         sdpcmd_regs_t *regs = bus->regs;
2895         uint retries = 0;
2896         uint16 lastrbc;
2897         uint8 hi, lo;
2898         int err;
2899
2900         DHD_ERROR(("%s: %sterminate frame%s\n", __FUNCTION__,
2901                    (abort ? "abort command, " : ""), (rtx ? ", send NAK" : "")));
2902
2903         if (abort) {
2904                 bcmsdh_abort(sdh, SDIO_FUNC_2);
2905         }
2906
2907         bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, SFC_RF_TERM, &err);
2908         bus->f1regdata++;
2909
2910         /* Wait until the packet has been flushed (device/FIFO stable) */
2911         for (lastrbc = retries = 0xffff; retries > 0; retries--) {
2912                 hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCHI, NULL);
2913                 lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCLO, NULL);
2914                 bus->f1regdata += 2;
2915
2916                 if ((hi == 0) && (lo == 0))
2917                         break;
2918
2919                 if ((hi > (lastrbc >> 8)) && (lo > (lastrbc & 0x00ff))) {
2920                         DHD_ERROR(("%s: count growing: last 0x%04x now 0x%04x\n",
2921                                    __FUNCTION__, lastrbc, ((hi << 8) + lo)));
2922                 }
2923                 lastrbc = (hi << 8) + lo;
2924         }
2925
2926         if (!retries) {
2927                 DHD_ERROR(("%s: count never zeroed: last 0x%04x\n", __FUNCTION__, lastrbc));
2928         } else {
2929                 DHD_INFO(("%s: flush took %d iterations\n", __FUNCTION__, (0xffff - retries)));
2930         }
2931
2932         if (rtx) {
2933                 bus->rxrtx++;
2934                 W_SDREG(SMB_NAK, &regs->tosbmailbox, retries);
2935                 bus->f1regdata++;
2936                 if (retries <= retry_limit) {
2937                         bus->rxskip = TRUE;
2938                 }
2939         }
2940
2941         /* Clear partial in any case */
2942         bus->nextlen = 0;
2943
2944         /* If we can't reach the device, signal failure */
2945         if (err || bcmsdh_regfail(sdh))
2946                 bus->dhd->busstate = DHD_BUS_DOWN;
2947 }
2948
2949 static void
2950 dhdsdio_read_control(dhd_bus_t *bus, uint8 *hdr, uint len, uint doff)
2951 {
2952         bcmsdh_info_t *sdh = bus->sdh;
2953         uint rdlen, pad;
2954
2955         int sdret;
2956
2957         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2958
2959         /* Control data already received in aligned rxctl */
2960         if ((bus->bus == SPI_BUS) && (!bus->usebufpool))
2961                 goto gotpkt;
2962
2963         ASSERT(bus->rxbuf);
2964         /* Set rxctl for frame (w/optional alignment) */
2965         bus->rxctl = bus->rxbuf;
2966         if (dhd_alignctl) {
2967                 bus->rxctl += firstread;
2968                 if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN)))
2969                         bus->rxctl += (DHD_SDALIGN - pad);
2970                 bus->rxctl -= firstread;
2971         }
2972         ASSERT(bus->rxctl >= bus->rxbuf);
2973
2974         /* Copy the already-read portion over */
2975         bcopy(hdr, bus->rxctl, firstread);
2976         if (len <= firstread)
2977                 goto gotpkt;
2978
2979         /* Copy the full data pkt in gSPI case and process ioctl. */
2980         if (bus->bus == SPI_BUS) {
2981                 bcopy(hdr, bus->rxctl, len);
2982                 goto gotpkt;
2983         }
2984
2985         /* Raise rdlen to next SDIO block to avoid tail command */
2986         rdlen = len - firstread;
2987         if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
2988                 pad = bus->blocksize - (rdlen % bus->blocksize);
2989                 if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
2990                     ((len + pad) < bus->dhd->maxctl))
2991                         rdlen += pad;
2992         } else if (rdlen % DHD_SDALIGN) {
2993                 rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
2994         }
2995
2996         /* Satisfy length-alignment requirements */
2997         if (forcealign && (rdlen & (ALIGNMENT - 1)))
2998                 rdlen = ROUNDUP(rdlen, ALIGNMENT);
2999
3000         /* Drop if the read is too big or it exceeds our maximum */
3001         if ((rdlen + firstread) > bus->dhd->maxctl) {
3002                 DHD_ERROR(("%s: %d-byte control read exceeds %d-byte buffer\n",
3003                            __FUNCTION__, rdlen, bus->dhd->maxctl));
3004                 bus->dhd->rx_errors++;
3005                 dhdsdio_rxfail(bus, FALSE, FALSE);
3006                 goto done;
3007         }
3008
3009         if ((len - doff) > bus->dhd->maxctl) {
3010                 DHD_ERROR(("%s: %d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n",
3011                            __FUNCTION__, len, (len - doff), bus->dhd->maxctl));
3012                 bus->dhd->rx_errors++; bus->rx_toolong++;
3013                 dhdsdio_rxfail(bus, FALSE, FALSE);
3014                 goto done;
3015         }
3016
3017
3018         /* Read remainder of frame body into the rxctl buffer */
3019         sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
3020                                     (bus->rxctl + firstread), rdlen, NULL, NULL, NULL);
3021         bus->f2rxdata++;
3022         ASSERT(sdret != BCME_PENDING);
3023
3024         /* Control frame failures need retransmission */
3025         if (sdret < 0) {
3026                 DHD_ERROR(("%s: read %d control bytes failed: %d\n", __FUNCTION__, rdlen, sdret));
3027                 bus->rxc_errors++; /* dhd.rx_ctlerrs is higher level */
3028                 dhdsdio_rxfail(bus, TRUE, TRUE);
3029                 goto done;
3030         }
3031
3032 gotpkt:
3033
3034 #ifdef DHD_DEBUG
3035         if (DHD_BYTES_ON() && DHD_CTL_ON()) {
3036                 prhex("RxCtrl", bus->rxctl, len);
3037         }
3038 #endif
3039
3040         /* Point to valid data and indicate its length */
3041         bus->rxctl += doff;
3042         bus->rxlen = len - doff;
3043
3044 done:
3045         /* Awake any waiters */
3046         dhd_os_ioctl_resp_wake(bus->dhd);
3047 }
3048
3049 static uint8
3050 dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq)
3051 {
3052         uint16 dlen, totlen;
3053         uint8 *dptr, num = 0;
3054
3055         uint16 sublen, check;
3056         void *pfirst, *plast, *pnext, *save_pfirst;
3057         osl_t *osh = bus->dhd->osh;
3058
3059         int errcode;
3060         uint8 chan, seq, doff, sfdoff;
3061         uint8 txmax;
3062
3063         int ifidx = 0;
3064         bool usechain = bus->use_rxchain;
3065
3066         /* If packets, issue read(s) and send up packet chain */
3067         /* Return sequence numbers consumed? */
3068
3069         DHD_TRACE(("dhdsdio_rxglom: start: glomd %p glom %p\n", bus->glomd, bus->glom));
3070
3071         /* If there's a descriptor, generate the packet chain */
3072         if (bus->glomd) {
3073                 dhd_os_sdlock_rxq(bus->dhd);
3074
3075                 pfirst = plast = pnext = NULL;
3076                 dlen = (uint16)PKTLEN(osh, bus->glomd);
3077                 dptr = PKTDATA(osh, bus->glomd);
3078                 if (!dlen || (dlen & 1)) {
3079                         DHD_ERROR(("%s: bad glomd len (%d), ignore descriptor\n",
3080                                    __FUNCTION__, dlen));
3081                         dlen = 0;
3082                 }
3083
3084                 for (totlen = num = 0; dlen; num++) {
3085                         /* Get (and move past) next length */
3086                         sublen = ltoh16_ua(dptr);
3087                         dlen -= sizeof(uint16);
3088                         dptr += sizeof(uint16);
3089                         if ((sublen < SDPCM_HDRLEN) ||
3090                             ((num == 0) && (sublen < (2 * SDPCM_HDRLEN)))) {
3091                                 DHD_ERROR(("%s: descriptor len %d bad: %d\n",
3092                                            __FUNCTION__, num, sublen));
3093                                 pnext = NULL;
3094                                 break;
3095                         }
3096                         if (sublen % DHD_SDALIGN) {
3097                                 DHD_ERROR(("%s: sublen %d not a multiple of %d\n",
3098                                            __FUNCTION__, sublen, DHD_SDALIGN));
3099                                 usechain = FALSE;
3100                         }
3101                         totlen += sublen;
3102
3103                         /* For last frame, adjust read len so total is a block multiple */
3104                         if (!dlen) {
3105                                 sublen += (ROUNDUP(totlen, bus->blocksize) - totlen);
3106                                 totlen = ROUNDUP(totlen, bus->blocksize);
3107                         }
3108
3109                         /* Allocate/chain packet for next subframe */
3110                         if ((pnext = PKTGET(osh, sublen + DHD_SDALIGN, FALSE)) == NULL) {
3111                                 DHD_ERROR(("%s: PKTGET failed, num %d len %d\n",
3112                                            __FUNCTION__, num, sublen));
3113                                 break;
3114                         }
3115                         ASSERT(!PKTLINK(pnext));
3116                         if (!pfirst) {
3117                                 ASSERT(!plast);
3118                                 pfirst = plast = pnext;
3119                         } else {
3120                                 ASSERT(plast);
3121                                 PKTSETNEXT(osh, plast, pnext);
3122                                 plast = pnext;
3123                         }
3124
3125                         /* Adhere to start alignment requirements */
3126                         PKTALIGN(osh, pnext, sublen, DHD_SDALIGN);
3127                 }
3128
3129                 /* If all allocations succeeded, save packet chain in bus structure */
3130                 if (pnext) {
3131                         DHD_GLOM(("%s: allocated %d-byte packet chain for %d subframes\n",
3132                                   __FUNCTION__, totlen, num));
3133                         if (DHD_GLOM_ON() && bus->nextlen) {
3134                                 if (totlen != bus->nextlen) {
3135                                         DHD_GLOM(("%s: glomdesc mismatch: nextlen %d glomdesc %d "
3136                                                   "rxseq %d\n", __FUNCTION__, bus->nextlen,
3137                                                   totlen, rxseq));
3138                                 }
3139                         }
3140                         bus->glom = pfirst;
3141                         pfirst = pnext = NULL;
3142                 } else {
3143                         if (pfirst)
3144                                 PKTFREE(osh, pfirst, FALSE);
3145                         bus->glom = NULL;
3146                         num = 0;
3147                 }
3148
3149                 /* Done with descriptor packet */
3150                 PKTFREE(osh, bus->glomd, FALSE);
3151                 bus->glomd = NULL;
3152                 bus->nextlen = 0;
3153
3154                 dhd_os_sdunlock_rxq(bus->dhd);
3155         }
3156
3157         /* Ok -- either we just generated a packet chain, or had one from before */
3158         if (bus->glom) {
3159                 if (DHD_GLOM_ON()) {
3160                         DHD_GLOM(("%s: attempt superframe read, packet chain:\n", __FUNCTION__));
3161                         for (pnext = bus->glom; pnext; pnext = PKTNEXT(osh, pnext)) {
3162                                 DHD_GLOM(("    %p: %p len 0x%04x (%d)\n",
3163                                           pnext, (uint8*)PKTDATA(osh, pnext),
3164                                           PKTLEN(osh, pnext), PKTLEN(osh, pnext)));
3165                         }
3166                 }
3167
3168                 pfirst = bus->glom;
3169                 dlen = (uint16)pkttotlen(osh, pfirst);
3170
3171                 /* Do an SDIO read for the superframe.  Configurable iovar to
3172                  * read directly into the chained packet, or allocate a large
3173                  * packet and and copy into the chain.
3174                  */
3175                 if (usechain) {
3176                         errcode = dhd_bcmsdh_recv_buf(bus,
3177                                                       bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2,
3178                                                       F2SYNC, (uint8*)PKTDATA(osh, pfirst),
3179                                                       dlen, pfirst, NULL, NULL);
3180                 } else if (bus->dataptr) {
3181                         errcode = dhd_bcmsdh_recv_buf(bus,
3182                                                       bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2,
3183                                                       F2SYNC, bus->dataptr,
3184                                                       dlen, NULL, NULL, NULL);
3185                         sublen = (uint16)pktfrombuf(osh, pfirst, 0, dlen, bus->dataptr);
3186                         if (sublen != dlen) {
3187                                 DHD_ERROR(("%s: FAILED TO COPY, dlen %d sublen %d\n",
3188                                            __FUNCTION__, dlen, sublen));
3189                                 errcode = -1;
3190                         }
3191                         pnext = NULL;
3192                 } else {
3193                         DHD_ERROR(("COULDN'T ALLOC %d-BYTE GLOM, FORCE FAILURE\n", dlen));
3194                         errcode = -1;
3195                 }
3196                 bus->f2rxdata++;
3197                 ASSERT(errcode != BCME_PENDING);
3198
3199                 /* On failure, kill the superframe, allow a couple retries */
3200                 if (errcode < 0) {
3201                         DHD_ERROR(("%s: glom read of %d bytes failed: %d\n",
3202                                    __FUNCTION__, dlen, errcode));
3203                         bus->dhd->rx_errors++;
3204
3205                         if (bus->glomerr++ < 3) {
3206                                 dhdsdio_rxfail(bus, TRUE, TRUE);
3207                         } else {
3208                                 bus->glomerr = 0;
3209                                 dhdsdio_rxfail(bus, TRUE, FALSE);
3210                                 dhd_os_sdlock_rxq(bus->dhd);
3211                                 PKTFREE(osh, bus->glom, FALSE);
3212                                 dhd_os_sdunlock_rxq(bus->dhd);
3213                                 bus->rxglomfail++;
3214                                 bus->glom = NULL;
3215                         }
3216                         return 0;
3217                 }
3218
3219 #ifdef DHD_DEBUG
3220                 if (DHD_GLOM_ON()) {
3221                         prhex("SUPERFRAME", PKTDATA(osh, pfirst),
3222                               MIN(PKTLEN(osh, pfirst), 48));
3223                 }
3224 #endif
3225
3226
3227                 /* Validate the superframe header */
3228                 dptr = (uint8 *)PKTDATA(osh, pfirst);
3229                 sublen = ltoh16_ua(dptr);
3230                 check = ltoh16_ua(dptr + sizeof(uint16));
3231
3232                 chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
3233                 seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
3234                 bus->nextlen = dptr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
3235                 if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
3236                         DHD_INFO(("%s: got frame w/nextlen too large (%d) seq %d\n",
3237                                   __FUNCTION__, bus->nextlen, seq));
3238                         bus->nextlen = 0;
3239                 }
3240                 doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
3241                 txmax = SDPCM_WINDOW_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
3242
3243                 errcode = 0;
3244                 if ((uint16)~(sublen^check)) {
3245                         DHD_ERROR(("%s (superframe): HW hdr error: len/check 0x%04x/0x%04x\n",
3246                                    __FUNCTION__, sublen, check));
3247                         errcode = -1;
3248                 } else if (ROUNDUP(sublen, bus->blocksize) != dlen) {
3249                         DHD_ERROR(("%s (superframe): len 0x%04x, rounded 0x%04x, expect 0x%04x\n",
3250                                    __FUNCTION__, sublen, ROUNDUP(sublen, bus->blocksize), dlen));
3251                         errcode = -1;
3252                 } else if (SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]) != SDPCM_GLOM_CHANNEL) {
3253                         DHD_ERROR(("%s (superframe): bad channel %d\n", __FUNCTION__,
3254                                    SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN])));
3255                         errcode = -1;
3256                 } else if (SDPCM_GLOMDESC(&dptr[SDPCM_FRAMETAG_LEN])) {
3257                         DHD_ERROR(("%s (superframe): got second descriptor?\n", __FUNCTION__));
3258                         errcode = -1;
3259                 } else if ((doff < SDPCM_HDRLEN) ||
3260                            (doff > (PKTLEN(osh, pfirst) - SDPCM_HDRLEN))) {
3261                         DHD_ERROR(("%s (superframe): Bad data offset %d: HW %d pkt %d min %d\n",
3262                                    __FUNCTION__, doff, sublen, PKTLEN(osh, pfirst), SDPCM_HDRLEN));
3263                         errcode = -1;
3264                 }
3265
3266                 /* Check sequence number of superframe SW header */
3267                 if (rxseq != seq) {
3268                         DHD_INFO(("%s: (superframe) rx_seq %d, expected %d\n",
3269                                   __FUNCTION__, seq, rxseq));
3270                         bus->rx_badseq++;
3271                         rxseq = seq;
3272                 }
3273
3274                 /* Check window for sanity */
3275                 if ((uint8)(txmax - bus->tx_seq) > 0x40) {
3276                         DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
3277                                    __FUNCTION__, txmax, bus->tx_seq));
3278                         txmax = bus->tx_seq + 2;
3279                 }
3280                 bus->tx_max = txmax;
3281
3282                 /* Remove superframe header, remember offset */
3283                 PKTPULL(osh, pfirst, doff);
3284                 sfdoff = doff;
3285
3286                 /* Validate all the subframe headers */
3287                 for (num = 0, pnext = pfirst; pnext && !errcode;
3288                      num++, pnext = PKTNEXT(osh, pnext)) {
3289                         dptr = (uint8 *)PKTDATA(osh, pnext);
3290                         dlen = (uint16)PKTLEN(osh, pnext);
3291                         sublen = ltoh16_ua(dptr);
3292                         check = ltoh16_ua(dptr + sizeof(uint16));
3293                         chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
3294                         doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
3295 #ifdef DHD_DEBUG
3296                         if (DHD_GLOM_ON()) {
3297                                 prhex("subframe", dptr, 32);
3298                         }
3299 #endif
3300
3301                         if ((uint16)~(sublen^check)) {
3302                                 DHD_ERROR(("%s (subframe %d): HW hdr error: "
3303                                            "len/check 0x%04x/0x%04x\n",
3304                                            __FUNCTION__, num, sublen, check));
3305                                 errcode = -1;
3306                         } else if ((sublen > dlen) || (sublen < SDPCM_HDRLEN)) {
3307                                 DHD_ERROR(("%s (subframe %d): length mismatch: "
3308                                            "len 0x%04x, expect 0x%04x\n",
3309                                            __FUNCTION__, num, sublen, dlen));
3310                                 errcode = -1;
3311                         } else if ((chan != SDPCM_DATA_CHANNEL) &&
3312                                    (chan != SDPCM_EVENT_CHANNEL)) {
3313                                 DHD_ERROR(("%s (subframe %d): bad channel %d\n",
3314                                            __FUNCTION__, num, chan));
3315                                 errcode = -1;
3316                         } else if ((doff < SDPCM_HDRLEN) || (doff > sublen)) {
3317                                 DHD_ERROR(("%s (subframe %d): Bad data offset %d: HW %d min %d\n",
3318                                            __FUNCTION__, num, doff, sublen, SDPCM_HDRLEN));
3319                                 errcode = -1;
3320                         }
3321                 }
3322
3323                 if (errcode) {
3324                         /* Terminate frame on error, request a couple retries */
3325                         if (bus->glomerr++ < 3) {
3326                                 /* Restore superframe header space */
3327                                 PKTPUSH(osh, pfirst, sfdoff);
3328                                 dhdsdio_rxfail(bus, TRUE, TRUE);
3329                         } else {
3330                                 bus->glomerr = 0;
3331                                 dhdsdio_rxfail(bus, TRUE, FALSE);
3332                                 dhd_os_sdlock_rxq(bus->dhd);
3333                                 PKTFREE(osh, bus->glom, FALSE);
3334                                 dhd_os_sdunlock_rxq(bus->dhd);
3335                                 bus->rxglomfail++;
3336                                 bus->glom = NULL;
3337                         }
3338                         bus->nextlen = 0;
3339                         return 0;
3340                 }
3341
3342                 /* Basic SD framing looks ok - process each packet (header) */
3343                 save_pfirst = pfirst;
3344                 bus->glom = NULL;
3345                 plast = NULL;
3346
3347                 dhd_os_sdlock_rxq(bus->dhd);
3348                 for (num = 0; pfirst; rxseq++, pfirst = pnext) {
3349                         pnext = PKTNEXT(osh, pfirst);
3350                         PKTSETNEXT(osh, pfirst, NULL);
3351
3352                         dptr = (uint8 *)PKTDATA(osh, pfirst);
3353                         sublen = ltoh16_ua(dptr);
3354                         chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
3355                         seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
3356                         doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
3357
3358                         DHD_GLOM(("%s: Get subframe %d, %p(%p/%d), sublen %d chan %d seq %d\n",
3359                                   __FUNCTION__, num, pfirst, PKTDATA(osh, pfirst),
3360                                   PKTLEN(osh, pfirst), sublen, chan, seq));
3361
3362                         ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL));
3363
3364                         if (rxseq != seq) {
3365                                 DHD_GLOM(("%s: rx_seq %d, expected %d\n",
3366                                           __FUNCTION__, seq, rxseq));
3367                                 bus->rx_badseq++;
3368                                 rxseq = seq;
3369                         }
3370
3371 #ifdef DHD_DEBUG
3372                         if (DHD_BYTES_ON() && DHD_DATA_ON()) {
3373                                 prhex("Rx Subframe Data", dptr, dlen);
3374                         }
3375 #endif
3376
3377                         PKTSETLEN(osh, pfirst, sublen);
3378                         PKTPULL(osh, pfirst, doff);
3379
3380                         if (PKTLEN(osh, pfirst) == 0) {
3381                                 PKTFREE(bus->dhd->osh, pfirst, FALSE);
3382                                 if (plast) {
3383                                         PKTSETNEXT(osh, plast, pnext);
3384                                 } else {
3385                                         ASSERT(save_pfirst == pfirst);
3386                                         save_pfirst = pnext;
3387                                 }
3388                                 continue;
3389                         } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pfirst) != 0) {
3390                                 DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__));
3391                                 bus->dhd->rx_errors++;
3392                                 PKTFREE(osh, pfirst, FALSE);
3393                                 if (plast) {
3394                                         PKTSETNEXT(osh, plast, pnext);
3395                                 } else {
3396                                         ASSERT(save_pfirst == pfirst);
3397                                         save_pfirst = pnext;
3398                                 }
3399                                 continue;
3400                         }
3401
3402                         /* this packet will go up, link back into chain and count it */
3403                         PKTSETNEXT(osh, pfirst, pnext);
3404                         plast = pfirst;
3405                         num++;
3406
3407 #ifdef DHD_DEBUG
3408                         if (DHD_GLOM_ON()) {
3409                                 DHD_GLOM(("%s subframe %d to stack, %p(%p/%d) nxt/lnk %p/%p\n",
3410                                           __FUNCTION__, num, pfirst,
3411                                           PKTDATA(osh, pfirst), PKTLEN(osh, pfirst),
3412                                           PKTNEXT(osh, pfirst), PKTLINK(pfirst)));
3413                                 prhex("", (uint8 *)PKTDATA(osh, pfirst),
3414                                       MIN(PKTLEN(osh, pfirst), 32));
3415                         }
3416 #endif /* DHD_DEBUG */
3417                 }
3418                 dhd_os_sdunlock_rxq(bus->dhd);
3419                 if (num) {
3420                         dhd_os_sdunlock(bus->dhd);
3421                         dhd_rx_frame(bus->dhd, ifidx, save_pfirst, num);
3422                         dhd_os_sdlock(bus->dhd);
3423                 }
3424
3425                 bus->rxglomframes++;
3426                 bus->rxglompkts += num;
3427         }
3428         return num;
3429 }
3430
3431 /* Return TRUE if there may be more frames to read */
3432 static uint
3433 dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished)
3434 {
3435         osl_t *osh = bus->dhd->osh;
3436         bcmsdh_info_t *sdh = bus->sdh;
3437
3438         uint16 len, check;      /* Extracted hardware header fields */
3439         uint8 chan, seq, doff;  /* Extracted software header fields */
3440         uint8 fcbits;           /* Extracted fcbits from software header */
3441         uint8 delta;
3442
3443         void *pkt;      /* Packet for event or data frames */
3444         uint16 pad;     /* Number of pad bytes to read */
3445         uint16 rdlen;   /* Total number of bytes to read */
3446         uint8 rxseq;    /* Next sequence number to expect */
3447         uint rxleft = 0;        /* Remaining number of frames allowed */
3448         int sdret;      /* Return code from bcmsdh calls */
3449         uint8 txmax;    /* Maximum tx sequence offered */
3450         bool len_consistent; /* Result of comparing readahead len and len from hw-hdr */
3451         uint8 *rxbuf;
3452         int ifidx = 0;
3453         uint rxcount = 0; /* Total frames read */
3454
3455 #if defined(DHD_DEBUG) || defined(SDTEST)
3456         bool sdtest = FALSE;    /* To limit message spew from test mode */
3457 #endif
3458
3459         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3460
3461         ASSERT(maxframes);
3462
3463 #ifdef SDTEST
3464         /* Allow pktgen to override maxframes */
3465         if (bus->pktgen_count && (bus->pktgen_mode == DHD_PKTGEN_RECV)) {
3466                 maxframes = bus->pktgen_count;
3467                 sdtest = TRUE;
3468         }
3469 #endif
3470
3471         /* Not finished unless we encounter no more frames indication */
3472         *finished = FALSE;
3473
3474
3475         for (rxseq = bus->rx_seq, rxleft = maxframes;
3476              !bus->rxskip && rxleft && bus->dhd->busstate != DHD_BUS_DOWN;
3477              rxseq++, rxleft--) {
3478
3479                 /* Handle glomming separately */
3480                 if (bus->glom || bus->glomd) {
3481                         uint8 cnt;
3482                         DHD_GLOM(("%s: calling rxglom: glomd %p, glom %p\n",
3483                                   __FUNCTION__, bus->glomd, bus->glom));
3484                         cnt = dhdsdio_rxglom(bus, rxseq);
3485                         DHD_GLOM(("%s: rxglom returned %d\n", __FUNCTION__, cnt));
3486                         rxseq += cnt - 1;
3487                         rxleft = (rxleft > cnt) ? (rxleft - cnt) : 1;
3488                         continue;
3489                 }
3490
3491                 /* Try doing single read if we can */
3492                 if (dhd_readahead && bus->nextlen) {
3493                         uint16 nextlen = bus->nextlen;
3494                         bus->nextlen = 0;
3495
3496                         if (bus->bus == SPI_BUS) {
3497                                 rdlen = len = nextlen;
3498                         }
3499                         else {
3500                                 rdlen = len = nextlen << 4;
3501
3502                                 /* Pad read to blocksize for efficiency */
3503                                 if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
3504                                         pad = bus->blocksize - (rdlen % bus->blocksize);
3505                                         if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
3506                                                 ((rdlen + pad + firstread) < MAX_RX_DATASZ))
3507                                                 rdlen += pad;
3508                                 } else if (rdlen % DHD_SDALIGN) {
3509                                         rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
3510                                 }
3511                         }
3512
3513                         /* We use bus->rxctl buffer in WinXP for initial control pkt receives.
3514                          * Later we use buffer-poll for data as well as control packets.
3515                          * This is required becuase dhd receives full frame in gSPI unlike SDIO.
3516                          * After the frame is received we have to distinguish whether it is data
3517                          * or non-data frame.
3518                          */
3519                         /* Allocate a packet buffer */
3520                         dhd_os_sdlock_rxq(bus->dhd);
3521                         if (!(pkt = PKTGET(osh, rdlen + DHD_SDALIGN, FALSE))) {
3522                                 if (bus->bus == SPI_BUS) {
3523                                         bus->usebufpool = FALSE;
3524                                         bus->rxctl = bus->rxbuf;
3525                                         if (dhd_alignctl) {
3526                                                 bus->rxctl += firstread;
3527                                                 if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN)))
3528                                                         bus->rxctl += (DHD_SDALIGN - pad);
3529                                                 bus->rxctl -= firstread;
3530                                         }
3531                                         ASSERT(bus->rxctl >= bus->rxbuf);
3532                                         rxbuf = bus->rxctl;
3533                                         /* Read the entire frame */
3534                                         sdret = dhd_bcmsdh_recv_buf(bus,
3535                                                                     bcmsdh_cur_sbwad(sdh),
3536                                                                     SDIO_FUNC_2,
3537                                                                     F2SYNC, rxbuf, rdlen,
3538                                                                     NULL, NULL, NULL);
3539                                         bus->f2rxdata++;
3540                                         ASSERT(sdret != BCME_PENDING);
3541
3542
3543                                         /* Control frame failures need retransmission */
3544                                         if (sdret < 0) {
3545                                                 DHD_ERROR(("%s: read %d control bytes failed: %d\n",
3546                                                    __FUNCTION__, rdlen, sdret));
3547                                                 /* dhd.rx_ctlerrs is higher level */
3548                                                 bus->rxc_errors++;
3549                                                 dhd_os_sdunlock_rxq(bus->dhd);
3550                                                 dhdsdio_rxfail(bus, TRUE,
3551                                                     (bus->bus == SPI_BUS) ? FALSE : TRUE);
3552                                                 continue;
3553                                         }
3554                                 } else {
3555                                         /* Give up on data, request rtx of events */
3556                                         DHD_ERROR(("%s (nextlen): PKTGET failed: len %d rdlen %d "
3557                                                    "expected rxseq %d\n",
3558                                                    __FUNCTION__, len, rdlen, rxseq));
3559                                         /* Just go try again w/normal header read */
3560                                         dhd_os_sdunlock_rxq(bus->dhd);
3561                                         continue;
3562                                 }
3563                         } else {
3564                                 if (bus->bus == SPI_BUS)
3565                                         bus->usebufpool = TRUE;
3566
3567                                 ASSERT(!PKTLINK(pkt));
3568                                 PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN);
3569                                 rxbuf = (uint8 *)PKTDATA(osh, pkt);
3570                                 /* Read the entire frame */
3571                                 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh),
3572                                                             SDIO_FUNC_2,
3573                                                             F2SYNC, rxbuf, rdlen,
3574                                                             pkt, NULL, NULL);
3575                                 bus->f2rxdata++;
3576                                 ASSERT(sdret != BCME_PENDING);
3577
3578                                 if (sdret < 0) {
3579                                         DHD_ERROR(("%s (nextlen): read %d bytes failed: %d\n",
3580                                            __FUNCTION__, rdlen, sdret));
3581                                         PKTFREE(bus->dhd->osh, pkt, FALSE);
3582                                         bus->dhd->rx_errors++;
3583                                         dhd_os_sdunlock_rxq(bus->dhd);
3584                                         /* Force retry w/normal header read.  Don't attemp NAK for
3585                                          * gSPI
3586                                          */
3587                                         dhdsdio_rxfail(bus, TRUE,
3588                                               (bus->bus == SPI_BUS) ? FALSE : TRUE);
3589                                         continue;
3590                                 }
3591                         }
3592                         dhd_os_sdunlock_rxq(bus->dhd);
3593
3594                         /* Now check the header */
3595                         bcopy(rxbuf, bus->rxhdr, SDPCM_HDRLEN);
3596
3597                         /* Extract hardware header fields */
3598                         len = ltoh16_ua(bus->rxhdr);
3599                         check = ltoh16_ua(bus->rxhdr + sizeof(uint16));
3600
3601                         /* All zeros means readahead info was bad */
3602                         if (!(len|check)) {
3603                                 DHD_INFO(("%s (nextlen): read zeros in HW header???\n",
3604                                            __FUNCTION__));
3605                                 dhd_os_sdlock_rxq(bus->dhd);
3606                                 PKTFREE2();
3607                                 dhd_os_sdunlock_rxq(bus->dhd);
3608                                 GSPI_PR55150_BAILOUT;
3609                                 continue;
3610                         }
3611
3612                         /* Validate check bytes */
3613                         if ((uint16)~(len^check)) {
3614                                 DHD_ERROR(("%s (nextlen): HW hdr error: nextlen/len/check"
3615                                            " 0x%04x/0x%04x/0x%04x\n", __FUNCTION__, nextlen,
3616                                            len, check));
3617                                 dhd_os_sdlock_rxq(bus->dhd);
3618                                 PKTFREE2();
3619                                 dhd_os_sdunlock_rxq(bus->dhd);
3620                                 bus->rx_badhdr++;
3621                                 dhdsdio_rxfail(bus, FALSE, FALSE);
3622                                 GSPI_PR55150_BAILOUT;
3623                                 continue;
3624                         }
3625
3626                         /* Validate frame length */
3627                         if (len < SDPCM_HDRLEN) {
3628                                 DHD_ERROR(("%s (nextlen): HW hdr length invalid: %d\n",
3629                                            __FUNCTION__, len));
3630                                 dhd_os_sdlock_rxq(bus->dhd);
3631                                 PKTFREE2();
3632                                 dhd_os_sdunlock_rxq(bus->dhd);
3633                                 GSPI_PR55150_BAILOUT;
3634                                 continue;
3635                         }
3636
3637                         /* Check for consistency with readahead info */
3638                                 len_consistent = (nextlen != (ROUNDUP(len, 16) >> 4));
3639                         if (len_consistent) {
3640                                 /* Mismatch, force retry w/normal header (may be >4K) */
3641                                 DHD_ERROR(("%s (nextlen): mismatch, nextlen %d len %d rnd %d; "
3642                                            "expected rxseq %d\n",
3643                                            __FUNCTION__, nextlen, len, ROUNDUP(len, 16), rxseq));
3644                                 dhd_os_sdlock_rxq(bus->dhd);
3645                                 PKTFREE2();
3646                                 dhd_os_sdunlock_rxq(bus->dhd);
3647                                 dhdsdio_rxfail(bus, TRUE, (bus->bus == SPI_BUS) ? FALSE : TRUE);
3648                                 GSPI_PR55150_BAILOUT;
3649                                 continue;
3650                         }
3651
3652
3653                         /* Extract software header fields */
3654                         chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
3655                         seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
3656                         doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
3657                         txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
3658
3659                                 bus->nextlen =
3660                                          bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
3661                                 if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
3662                                         DHD_INFO(("%s (nextlen): got frame w/nextlen too large"
3663                                                   " (%d), seq %d\n", __FUNCTION__, bus->nextlen,
3664                                                   seq));
3665                                         bus->nextlen = 0;
3666                                 }
3667
3668                                 bus->dhd->rx_readahead_cnt ++;
3669                         /* Handle Flow Control */
3670                         fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
3671
3672                         delta = 0;
3673                         if (~bus->flowcontrol & fcbits) {
3674                                 bus->fc_xoff++;
3675                                 delta = 1;
3676                         }
3677                         if (bus->flowcontrol & ~fcbits) {
3678                                 bus->fc_xon++;
3679                                 delta = 1;
3680                         }
3681
3682                         if (delta) {
3683                                 bus->fc_rcvd++;
3684                                 bus->flowcontrol = fcbits;
3685                         }
3686
3687                         /* Check and update sequence number */
3688                         if (rxseq != seq) {
3689                                 DHD_INFO(("%s (nextlen): rx_seq %d, expected %d\n",
3690                                           __FUNCTION__, seq, rxseq));
3691                                 bus->rx_badseq++;
3692                                 rxseq = seq;
3693                         }
3694
3695                         /* Check window for sanity */
3696                         if ((uint8)(txmax - bus->tx_seq) > 0x40) {
3697                                         DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
3698                                                 __FUNCTION__, txmax, bus->tx_seq));
3699                                         txmax = bus->tx_seq + 2;
3700                         }
3701                         bus->tx_max = txmax;
3702
3703 #ifdef DHD_DEBUG
3704                         if (DHD_BYTES_ON() && DHD_DATA_ON()) {
3705                                 prhex("Rx Data", rxbuf, len);
3706                         } else if (DHD_HDRS_ON()) {
3707                                 prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN);
3708                         }
3709 #endif
3710
3711                         if (chan == SDPCM_CONTROL_CHANNEL) {
3712                                 if (bus->bus == SPI_BUS) {
3713                                         dhdsdio_read_control(bus, rxbuf, len, doff);
3714                                         if (bus->usebufpool) {
3715                                                 dhd_os_sdlock_rxq(bus->dhd);
3716                                                 PKTFREE(bus->dhd->osh, pkt, FALSE);
3717                                                 dhd_os_sdunlock_rxq(bus->dhd);
3718                                         }
3719                                         continue;
3720                                 } else {
3721                                         DHD_ERROR(("%s (nextlen): readahead on control"
3722                                                    " packet %d?\n", __FUNCTION__, seq));
3723                                         /* Force retry w/normal header read */
3724                                         bus->nextlen = 0;
3725                                         dhdsdio_rxfail(bus, FALSE, TRUE);
3726                                         dhd_os_sdlock_rxq(bus->dhd);
3727                                         PKTFREE2();
3728                                         dhd_os_sdunlock_rxq(bus->dhd);
3729                                         continue;
3730                                 }
3731                         }
3732
3733                         if ((bus->bus == SPI_BUS) && !bus->usebufpool) {
3734                                 DHD_ERROR(("Received %d bytes on %d channel. Running out of "
3735                                            "rx pktbuf's or not yet malloced.\n", len, chan));
3736                                 continue;
3737                         }
3738
3739                         /* Validate data offset */
3740                         if ((doff < SDPCM_HDRLEN) || (doff > len)) {
3741                                 DHD_ERROR(("%s (nextlen): bad data offset %d: HW len %d min %d\n",
3742                                            __FUNCTION__, doff, len, SDPCM_HDRLEN));
3743                                 dhd_os_sdlock_rxq(bus->dhd);
3744                                 PKTFREE2();
3745                                 dhd_os_sdunlock_rxq(bus->dhd);
3746                                 ASSERT(0);
3747                                 dhdsdio_rxfail(bus, FALSE, FALSE);
3748                                 continue;
3749                         }
3750
3751                         /* All done with this one -- now deliver the packet */
3752                         goto deliver;
3753                 }
3754                 /* gSPI frames should not be handled in fractions */
3755                 if (bus->bus == SPI_BUS) {
3756                         break;
3757                 }
3758
3759                 /* Read frame header (hardware and software) */
3760                 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
3761                                             bus->rxhdr, firstread, NULL, NULL, NULL);
3762                 bus->f2rxhdrs++;
3763                 ASSERT(sdret != BCME_PENDING);
3764
3765                 if (sdret < 0) {
3766                         DHD_ERROR(("%s: RXHEADER FAILED: %d\n", __FUNCTION__, sdret));
3767                         bus->rx_hdrfail++;
3768                         dhdsdio_rxfail(bus, TRUE, TRUE);
3769                         continue;
3770                 }
3771
3772 #ifdef DHD_DEBUG
3773                 if (DHD_BYTES_ON() || DHD_HDRS_ON()) {
3774                         prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN);
3775                 }
3776 #endif
3777
3778                 /* Extract hardware header fields */
3779                 len = ltoh16_ua(bus->rxhdr);
3780                 check = ltoh16_ua(bus->rxhdr + sizeof(uint16));
3781
3782                 /* All zeros means no more frames */
3783                 if (!(len|check)) {
3784                         *finished = TRUE;
3785                         break;
3786                 }
3787
3788                 /* Validate check bytes */
3789                 if ((uint16)~(len^check)) {
3790                         DHD_ERROR(("%s: HW hdr error: len/check 0x%04x/0x%04x\n",
3791                                    __FUNCTION__, len, check));
3792                         bus->rx_badhdr++;
3793                         dhdsdio_rxfail(bus, FALSE, FALSE);
3794                         continue;
3795                 }
3796
3797                 /* Validate frame length */
3798                 if (len < SDPCM_HDRLEN) {
3799                         DHD_ERROR(("%s: HW hdr length invalid: %d\n", __FUNCTION__, len));
3800                         continue;
3801                 }
3802
3803                 /* Extract software header fields */
3804                 chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
3805                 seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
3806                 doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
3807                 txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
3808
3809                 /* Validate data offset */
3810                 if ((doff < SDPCM_HDRLEN) || (doff > len)) {
3811                         DHD_ERROR(("%s: Bad data offset %d: HW len %d, min %d seq %d\n",
3812                                    __FUNCTION__, doff, len, SDPCM_HDRLEN, seq));
3813                         bus->rx_badhdr++;
3814                         ASSERT(0);
3815                         dhdsdio_rxfail(bus, FALSE, FALSE);
3816                         continue;
3817                 }
3818
3819                 /* Save the readahead length if there is one */
3820                 bus->nextlen = bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
3821                 if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
3822                         DHD_INFO(("%s (nextlen): got frame w/nextlen too large (%d), seq %d\n",
3823                                   __FUNCTION__, bus->nextlen, seq));
3824                         bus->nextlen = 0;
3825                 }
3826
3827                 /* Handle Flow Control */
3828                 fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
3829
3830                 delta = 0;
3831                 if (~bus->flowcontrol & fcbits) {
3832                         bus->fc_xoff++;
3833                         delta = 1;
3834                 }
3835                 if (bus->flowcontrol & ~fcbits) {
3836                         bus->fc_xon++;
3837                         delta = 1;
3838                 }
3839
3840                 if (delta) {
3841                         bus->fc_rcvd++;
3842                         bus->flowcontrol = fcbits;
3843                 }
3844
3845                 /* Check and update sequence number */
3846                 if (rxseq != seq) {
3847                         DHD_INFO(("%s: rx_seq %d, expected %d\n", __FUNCTION__, seq, rxseq));
3848                         bus->rx_badseq++;
3849                         rxseq = seq;
3850                 }
3851
3852                 /* Check window for sanity */
3853                 if ((uint8)(txmax - bus->tx_seq) > 0x40) {
3854                         DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
3855                                    __FUNCTION__, txmax, bus->tx_seq));
3856                         txmax = bus->tx_seq + 2;
3857                 }
3858                 bus->tx_max = txmax;
3859
3860                 /* Call a separate function for control frames */
3861                 if (chan == SDPCM_CONTROL_CHANNEL) {
3862                         dhdsdio_read_control(bus, bus->rxhdr, len, doff);
3863                         continue;
3864                 }
3865
3866                 ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL) ||
3867                        (chan == SDPCM_TEST_CHANNEL) || (chan == SDPCM_GLOM_CHANNEL));
3868
3869                 /* Length to read */
3870                 rdlen = (len > firstread) ? (len - firstread) : 0;
3871
3872                 /* May pad read to blocksize for efficiency */
3873                 if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
3874                         pad = bus->blocksize - (rdlen % bus->blocksize);
3875                         if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
3876                             ((rdlen + pad + firstread) < MAX_RX_DATASZ))
3877                                 rdlen += pad;
3878                 } else if (rdlen % DHD_SDALIGN) {
3879                         rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
3880                 }
3881
3882                 /* Satisfy length-alignment requirements */
3883                 if (forcealign && (rdlen & (ALIGNMENT - 1)))
3884                         rdlen = ROUNDUP(rdlen, ALIGNMENT);
3885
3886                 if ((rdlen + firstread) > MAX_RX_DATASZ) {
3887                         /* Too long -- skip this frame */
3888                         DHD_ERROR(("%s: too long: len %d rdlen %d\n", __FUNCTION__, len, rdlen));
3889                         bus->dhd->rx_errors++; bus->rx_toolong++;
3890                         dhdsdio_rxfail(bus, FALSE, FALSE);
3891                         continue;
3892                 }
3893
3894                 dhd_os_sdlock_rxq(bus->dhd);
3895                 if (!(pkt = PKTGET(osh, (rdlen + firstread + DHD_SDALIGN), FALSE))) {
3896                         /* Give up on data, request rtx of events */
3897                         DHD_ERROR(("%s: PKTGET failed: rdlen %d chan %d\n",
3898                                    __FUNCTION__, rdlen, chan));
3899                         bus->dhd->rx_dropped++;
3900                         dhd_os_sdunlock_rxq(bus->dhd);
3901                         dhdsdio_rxfail(bus, FALSE, RETRYCHAN(chan));
3902                         continue;
3903                 }
3904                 dhd_os_sdunlock_rxq(bus->dhd);
3905
3906                 ASSERT(!PKTLINK(pkt));
3907
3908                 /* Leave room for what we already read, and align remainder */
3909                 ASSERT(firstread < (PKTLEN(osh, pkt)));
3910                 PKTPULL(osh, pkt, firstread);
3911                 PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN);
3912
3913                 /* Read the remaining frame data */
3914                 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
3915                                             ((uint8 *)PKTDATA(osh, pkt)), rdlen, pkt, NULL, NULL);
3916                 bus->f2rxdata++;
3917                 ASSERT(sdret != BCME_PENDING);
3918
3919                 if (sdret < 0) {
3920                         DHD_ERROR(("%s: read %d %s bytes failed: %d\n", __FUNCTION__, rdlen,
3921                                    ((chan == SDPCM_EVENT_CHANNEL) ? "event" :
3922                                     ((chan == SDPCM_DATA_CHANNEL) ? "data" : "test")), sdret));
3923                         dhd_os_sdlock_rxq(bus->dhd);
3924                         PKTFREE(bus->dhd->osh, pkt, FALSE);
3925                         dhd_os_sdunlock_rxq(bus->dhd);
3926                         bus->dhd->rx_errors++;
3927                         dhdsdio_rxfail(bus, TRUE, RETRYCHAN(chan));
3928                         continue;
3929                 }
3930
3931                 /* Copy the already-read portion */
3932                 PKTPUSH(osh, pkt, firstread);
3933                 bcopy(bus->rxhdr, PKTDATA(osh, pkt), firstread);
3934
3935 #ifdef DHD_DEBUG
3936                 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
3937                         prhex("Rx Data", PKTDATA(osh, pkt), len);
3938                 }
3939 #endif
3940
3941 deliver:
3942                 /* Save superframe descriptor and allocate packet frame */
3943                 if (chan == SDPCM_GLOM_CHANNEL) {
3944                         if (SDPCM_GLOMDESC(&bus->rxhdr[SDPCM_FRAMETAG_LEN])) {
3945                                 DHD_GLOM(("%s: got glom descriptor, %d bytes:\n",
3946                                           __FUNCTION__, len));
3947 #ifdef DHD_DEBUG
3948                                 if (DHD_GLOM_ON()) {
3949                                         prhex("Glom Data", PKTDATA(osh, pkt), len);
3950                                 }
3951 #endif
3952                                 PKTSETLEN(osh, pkt, len);
3953                                 ASSERT(doff == SDPCM_HDRLEN);
3954                                 PKTPULL(osh, pkt, SDPCM_HDRLEN);
3955                                 bus->glomd = pkt;
3956                         } else {
3957                                 DHD_ERROR(("%s: glom superframe w/o descriptor!\n", __FUNCTION__));
3958                                 dhdsdio_rxfail(bus, FALSE, FALSE);
3959                         }
3960                         continue;
3961                 }
3962
3963                 /* Fill in packet len and prio, deliver upward */
3964                 PKTSETLEN(osh, pkt, len);
3965                 PKTPULL(osh, pkt, doff);
3966
3967 #ifdef SDTEST
3968                 /* Test channel packets are processed separately */
3969                 if (chan == SDPCM_TEST_CHANNEL) {
3970                         dhdsdio_testrcv(bus, pkt, seq);
3971                         continue;
3972                 }
3973 #endif /* SDTEST */
3974
3975                 if (PKTLEN(osh, pkt) == 0) {
3976                         dhd_os_sdlock_rxq(bus->dhd);
3977                         PKTFREE(bus->dhd->osh, pkt, FALSE);
3978                         dhd_os_sdunlock_rxq(bus->dhd);
3979                         continue;
3980                 } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pkt) != 0) {
3981                         DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__));
3982                         dhd_os_sdlock_rxq(bus->dhd);
3983                         PKTFREE(bus->dhd->osh, pkt, FALSE);
3984                         dhd_os_sdunlock_rxq(bus->dhd);
3985                         bus->dhd->rx_errors++;
3986                         continue;
3987                 }
3988
3989
3990                 /* Unlock during rx call */
3991                 dhd_os_sdunlock(bus->dhd);
3992                 dhd_rx_frame(bus->dhd, ifidx, pkt, 1);
3993                 dhd_os_sdlock(bus->dhd);
3994         }
3995         rxcount = maxframes - rxleft;
3996 #ifdef DHD_DEBUG
3997         /* Message if we hit the limit */
3998         if (!rxleft && !sdtest)
3999                 DHD_DATA(("%s: hit rx limit of %d frames\n", __FUNCTION__, maxframes));
4000         else
4001 #endif /* DHD_DEBUG */
4002         DHD_DATA(("%s: processed %d frames\n", __FUNCTION__, rxcount));
4003         /* Back off rxseq if awaiting rtx, update rx_seq */
4004         if (bus->rxskip)
4005                 rxseq--;
4006         bus->rx_seq = rxseq;
4007
4008         return rxcount;
4009 }
4010
4011 static uint32
4012 dhdsdio_hostmail(dhd_bus_t *bus)
4013 {
4014         sdpcmd_regs_t *regs = bus->regs;
4015         uint32 intstatus = 0;
4016         uint32 hmb_data;
4017         uint8 fcbits;
4018         uint retries = 0;
4019
4020         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4021
4022         /* Read mailbox data and ack that we did so */
4023         R_SDREG(hmb_data, &regs->tohostmailboxdata, retries);
4024         if (retries <= retry_limit)
4025                 W_SDREG(SMB_INT_ACK, &regs->tosbmailbox, retries);
4026         bus->f1regdata += 2;
4027
4028         /* Dongle recomposed rx frames, accept them again */
4029         if (hmb_data & HMB_DATA_NAKHANDLED) {
4030                 DHD_INFO(("Dongle reports NAK handled, expect rtx of %d\n", bus->rx_seq));
4031                 if (!bus->rxskip) {
4032                         DHD_ERROR(("%s: unexpected NAKHANDLED!\n", __FUNCTION__));
4033                 }
4034                 bus->rxskip = FALSE;
4035                 intstatus |= I_HMB_FRAME_IND;
4036         }
4037
4038         /*
4039          * DEVREADY does not occur with gSPI.
4040          */
4041         if (hmb_data & (HMB_DATA_DEVREADY | HMB_DATA_FWREADY)) {
4042                 bus->sdpcm_ver = (hmb_data & HMB_DATA_VERSION_MASK) >> HMB_DATA_VERSION_SHIFT;
4043                 if (bus->sdpcm_ver != SDPCM_PROT_VERSION)
4044                         DHD_ERROR(("Version mismatch, dongle reports %d, expecting %d\n",
4045                                    bus->sdpcm_ver, SDPCM_PROT_VERSION));
4046                 else
4047                         DHD_INFO(("Dongle ready, protocol version %d\n", bus->sdpcm_ver));
4048         }
4049
4050         /*
4051          * Flow Control has been moved into the RX headers and this out of band
4052          * method isn't used any more.  Leae this here for possibly remaining backward
4053          * compatible with older dongles
4054          */
4055         if (hmb_data & HMB_DATA_FC) {
4056                 fcbits = (hmb_data & HMB_DATA_FCDATA_MASK) >> HMB_DATA_FCDATA_SHIFT;
4057
4058                 if (fcbits & ~bus->flowcontrol)
4059                         bus->fc_xoff++;
4060                 if (bus->flowcontrol & ~fcbits)
4061                         bus->fc_xon++;
4062
4063                 bus->fc_rcvd++;
4064                 bus->flowcontrol = fcbits;
4065         }
4066
4067         /* Shouldn't be any others */
4068         if (hmb_data & ~(HMB_DATA_DEVREADY |
4069                          HMB_DATA_NAKHANDLED |
4070                          HMB_DATA_FC |
4071                          HMB_DATA_FWREADY |
4072                          HMB_DATA_FCDATA_MASK |
4073                          HMB_DATA_VERSION_MASK)) {
4074                 DHD_ERROR(("Unknown mailbox data content: 0x%02x\n", hmb_data));
4075         }
4076
4077         return intstatus;
4078 }
4079
4080 bool
4081 dhdsdio_dpc(dhd_bus_t *bus)
4082 {
4083         bcmsdh_info_t *sdh = bus->sdh;
4084         sdpcmd_regs_t *regs = bus->regs;
4085         uint32 intstatus, newstatus = 0;
4086         uint retries = 0;
4087         uint rxlimit = dhd_rxbound; /* Rx frames to read before resched */
4088         uint txlimit = dhd_txbound; /* Tx frames to send before resched */
4089         uint framecnt = 0;                /* Temporary counter of tx/rx frames */
4090         bool rxdone = TRUE;               /* Flag for no more read data */
4091         bool resched = FALSE;     /* Flag indicating resched wanted */
4092
4093         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4094
4095         /* Start with leftover status bits */
4096         intstatus = bus->intstatus;
4097
4098         dhd_os_sdlock(bus->dhd);
4099
4100         /* If waiting for HTAVAIL, check status */
4101         if (bus->clkstate == CLK_PENDING) {
4102                 int err;
4103                 uint8 clkctl, devctl = 0;
4104
4105 #ifdef DHD_DEBUG
4106                 /* Check for inconsistent device control */
4107                 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
4108                 if (err) {
4109                         DHD_ERROR(("%s: error reading DEVCTL: %d\n", __FUNCTION__, err));
4110                         bus->dhd->busstate = DHD_BUS_DOWN;
4111                 } else {
4112                         ASSERT(devctl & SBSDIO_DEVCTL_CA_INT_ONLY);
4113                 }
4114 #endif /* DHD_DEBUG */
4115
4116                 /* Read CSR, if clock on switch to AVAIL, else ignore */
4117                 clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
4118                 if (err) {
4119                         DHD_ERROR(("%s: error reading CSR: %d\n", __FUNCTION__, err));
4120                         bus->dhd->busstate = DHD_BUS_DOWN;
4121                 }
4122
4123                 DHD_INFO(("DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n", devctl, clkctl));
4124
4125                 if (SBSDIO_HTAV(clkctl)) {
4126                         devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
4127                         if (err) {
4128                                 DHD_ERROR(("%s: error reading DEVCTL: %d\n",
4129                                            __FUNCTION__, err));
4130                                 bus->dhd->busstate = DHD_BUS_DOWN;
4131                         }
4132                         devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
4133                         bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
4134                         if (err) {
4135                                 DHD_ERROR(("%s: error writing DEVCTL: %d\n",
4136                                            __FUNCTION__, err));
4137                                 bus->dhd->busstate = DHD_BUS_DOWN;
4138                         }
4139                         bus->clkstate = CLK_AVAIL;
4140                 } else {
4141                         goto clkwait;
4142                 }
4143         }
4144
4145         BUS_WAKE(bus);
4146
4147         /* Make sure backplane clock is on */
4148         dhdsdio_clkctl(bus, CLK_AVAIL, TRUE);
4149         if (bus->clkstate == CLK_PENDING)
4150                 goto clkwait;
4151
4152         /* Pending interrupt indicates new device status */
4153         if (bus->ipend) {
4154                 bus->ipend = FALSE;
4155                 R_SDREG(newstatus, &regs->intstatus, retries);
4156                 bus->f1regdata++;
4157                 if (bcmsdh_regfail(bus->sdh))
4158                         newstatus = 0;
4159                 newstatus &= bus->hostintmask;
4160                 bus->fcstate = !!(newstatus & I_HMB_FC_STATE);
4161                 if (newstatus) {
4162                         W_SDREG(newstatus, &regs->intstatus, retries);
4163                         bus->f1regdata++;
4164                 }
4165         }
4166
4167         /* Merge new bits with previous */
4168         intstatus |= newstatus;
4169         bus->intstatus = 0;
4170
4171         /* Handle flow-control change: read new state in case our ack
4172          * crossed another change interrupt.  If change still set, assume
4173          * FC ON for safety, let next loop through do the debounce.
4174          */
4175         if (intstatus & I_HMB_FC_CHANGE) {
4176                 intstatus &= ~I_HMB_FC_CHANGE;
4177                 W_SDREG(I_HMB_FC_CHANGE, &regs->intstatus, retries);
4178                 R_SDREG(newstatus, &regs->intstatus, retries);
4179                 bus->f1regdata += 2;
4180                 bus->fcstate = !!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE));
4181                 intstatus |= (newstatus & bus->hostintmask);
4182         }
4183
4184         /* Handle host mailbox indication */
4185         if (intstatus & I_HMB_HOST_INT) {
4186                 intstatus &= ~I_HMB_HOST_INT;
4187                 intstatus |= dhdsdio_hostmail(bus);
4188         }
4189
4190         /* Generally don't ask for these, can get CRC errors... */
4191         if (intstatus & I_WR_OOSYNC) {
4192                 DHD_ERROR(("Dongle reports WR_OOSYNC\n"));
4193                 intstatus &= ~I_WR_OOSYNC;
4194         }
4195
4196         if (intstatus & I_RD_OOSYNC) {
4197                 DHD_ERROR(("Dongle reports RD_OOSYNC\n"));
4198                 intstatus &= ~I_RD_OOSYNC;
4199         }
4200
4201         if (intstatus & I_SBINT) {
4202                 DHD_ERROR(("Dongle reports SBINT\n"));
4203                 intstatus &= ~I_SBINT;
4204         }
4205
4206         /* Would be active due to wake-wlan in gSPI */
4207         if (intstatus & I_CHIPACTIVE) {
4208                 DHD_INFO(("Dongle reports CHIPACTIVE\n"));
4209                 intstatus &= ~I_CHIPACTIVE;
4210         }
4211
4212         /* Ignore frame indications if rxskip is set */
4213         if (bus->rxskip)
4214                 intstatus &= ~I_HMB_FRAME_IND;
4215
4216         /* On frame indication, read available frames */
4217         if (PKT_AVAILABLE()) {
4218                 framecnt = dhdsdio_readframes(bus, rxlimit, &rxdone);
4219                 if (rxdone || bus->rxskip)
4220                         intstatus &= ~I_HMB_FRAME_IND;
4221                 rxlimit -= MIN(framecnt, rxlimit);
4222         }
4223
4224         /* Keep still-pending events for next scheduling */
4225         bus->intstatus = intstatus;
4226
4227 clkwait:
4228         /* Re-enable interrupts to detect new device events (mailbox, rx frame)
4229          * or clock availability.  (Allows tx loop to check ipend if desired.)
4230          * (Unless register access seems hosed, as we may not be able to ACK...)
4231          */
4232         if (bus->intr && bus->intdis && !bcmsdh_regfail(sdh)) {
4233                 DHD_INTR(("%s: enable SDIO interrupts, rxdone %d framecnt %d\n",
4234                           __FUNCTION__, rxdone, framecnt));
4235                 bus->intdis = FALSE;
4236                 bcmsdh_intr_enable(sdh);
4237         }
4238
4239         if (DATAOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL)) {
4240                 int ret, i;
4241
4242                 ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
4243                                       (uint8 *)bus->ctrl_frame_buf, (uint32)bus->ctrl_frame_len,
4244                         NULL, NULL, NULL);
4245                 ASSERT(ret != BCME_PENDING);
4246
4247                 if (ret < 0) {
4248                         /* On failure, abort the command and terminate the frame */
4249                         DHD_INFO(("%s: sdio error %d, abort command and terminate frame.\n",
4250                                   __FUNCTION__, ret));
4251                         bus->tx_sderrs++;
4252
4253                         bcmsdh_abort(sdh, SDIO_FUNC_2);
4254
4255                         bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
4256                                          SFC_WF_TERM, NULL);
4257                         bus->f1regdata++;
4258
4259                         for (i = 0; i < 3; i++) {
4260                                 uint8 hi, lo;
4261                                 hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
4262                                                      SBSDIO_FUNC1_WFRAMEBCHI, NULL);
4263                                 lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
4264                                                      SBSDIO_FUNC1_WFRAMEBCLO, NULL);
4265                                 bus->f1regdata += 2;
4266                                 if ((hi == 0) && (lo == 0))
4267                                         break;
4268                         }
4269
4270                 }
4271                 if (ret == 0) {
4272                                 bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
4273                 }
4274
4275                 printf("Return_dpc value is : %d\n", ret);
4276                 bus->ctrl_frame_stat = FALSE;
4277                 dhd_wait_event_wakeup(bus->dhd);
4278         }
4279         /* Send queued frames (limit 1 if rx may still be pending) */
4280         else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate &&
4281             pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit && DATAOK(bus)) {
4282                 framecnt = rxdone ? txlimit : MIN(txlimit, dhd_txminmax);
4283                 framecnt = dhdsdio_sendfromq(bus, framecnt);
4284                 txlimit -= framecnt;
4285         }
4286
4287         /* Resched if events or tx frames are pending, else await next interrupt */
4288         /* On failed register access, all bets are off: no resched or interrupts */
4289         if ((bus->dhd->busstate == DHD_BUS_DOWN) || bcmsdh_regfail(sdh)) {
4290                 DHD_ERROR(("%s: failed backplane access over SDIO, halting operation %d \n",
4291                            __FUNCTION__, bcmsdh_regfail(sdh)));
4292                 bus->dhd->busstate = DHD_BUS_DOWN;
4293                 bus->intstatus = 0;
4294         } else if (bus->clkstate == CLK_PENDING) {
4295                 DHD_INFO(("%s: rescheduled due to CLK_PENDING awaiting \
4296                         I_CHIPACTIVE interrupt", __FUNCTION__));
4297                         resched = TRUE;
4298         } else if (bus->intstatus || bus->ipend ||
4299                    (!bus->fcstate && pktq_mlen(&bus->txq, ~bus->flowcontrol) && DATAOK(bus)) ||
4300                         PKT_AVAILABLE()) {  /* Read multiple frames */
4301                 resched = TRUE;
4302         }
4303
4304
4305         bus->dpc_sched = resched;
4306
4307         /* If we're done for now, turn off clock request. */
4308         if ((bus->clkstate != CLK_PENDING) && bus->idletime == DHD_IDLE_IMMEDIATE) {
4309                 bus->activity = FALSE;
4310                 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
4311         }
4312
4313         dhd_os_sdunlock(bus->dhd);
4314
4315         return resched;
4316 }
4317
4318 bool
4319 dhd_bus_dpc(struct dhd_bus *bus)
4320 {
4321         bool resched;
4322
4323         /* Call the DPC directly. */
4324         DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__));
4325         resched = dhdsdio_dpc(bus);
4326
4327         return resched;
4328 }
4329
4330 void
4331 dhdsdio_isr(void *arg)
4332 {
4333         dhd_bus_t *bus = (dhd_bus_t*)arg;
4334         bcmsdh_info_t *sdh;
4335
4336         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4337
4338         if (!bus) {
4339                 DHD_ERROR(("%s : bus is null pointer , exit \n", __FUNCTION__));
4340                 return;
4341         }
4342         sdh = bus->sdh;
4343
4344         if (bus->dhd->busstate == DHD_BUS_DOWN) {
4345                 DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__));
4346                 return;
4347         }
4348         /* Count the interrupt call */
4349         bus->intrcount++;
4350         bus->ipend = TRUE;
4351
4352         /* Shouldn't get this interrupt if we're sleeping? */
4353         if (bus->sleeping) {
4354                 DHD_ERROR(("INTERRUPT WHILE SLEEPING??\n"));
4355                 return;
4356         }
4357
4358         /* Disable additional interrupts (is this needed now)? */
4359         if (bus->intr) {
4360                 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
4361         } else {
4362                 DHD_ERROR(("dhdsdio_isr() w/o interrupt configured!\n"));
4363         }
4364
4365         bcmsdh_intr_disable(sdh);
4366         bus->intdis = TRUE;
4367
4368 #if defined(SDIO_ISR_THREAD)
4369         DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__));
4370         while (dhdsdio_dpc(bus));
4371 #else
4372         bus->dpc_sched = TRUE;
4373         dhd_sched_dpc(bus->dhd);
4374 #endif 
4375
4376
4377 }
4378
4379 #ifdef SDTEST
4380 static void
4381 dhdsdio_pktgen_init(dhd_bus_t *bus)
4382 {
4383         /* Default to specified length, or full range */
4384         if (dhd_pktgen_len) {
4385                 bus->pktgen_maxlen = MIN(dhd_pktgen_len, MAX_PKTGEN_LEN);
4386                 bus->pktgen_minlen = bus->pktgen_maxlen;
4387         } else {
4388                 bus->pktgen_maxlen = MAX_PKTGEN_LEN;
4389                 bus->pktgen_minlen = 0;
4390         }
4391         bus->pktgen_len = (uint16)bus->pktgen_minlen;
4392
4393         /* Default to per-watchdog burst with 10s print time */
4394         bus->pktgen_freq = 1;
4395         bus->pktgen_print = 10000 / dhd_watchdog_ms;
4396         bus->pktgen_count = (dhd_pktgen * dhd_watchdog_ms + 999) / 1000;
4397
4398         /* Default to echo mode */
4399         bus->pktgen_mode = DHD_PKTGEN_ECHO;
4400         bus->pktgen_stop = 1;
4401 }
4402
4403 static void
4404 dhdsdio_pktgen(dhd_bus_t *bus)
4405 {
4406         void *pkt;
4407         uint8 *data;
4408         uint pktcount;
4409         uint fillbyte;
4410         osl_t *osh = bus->dhd->osh;
4411         uint16 len;
4412
4413         /* Display current count if appropriate */
4414         if (bus->pktgen_print && (++bus->pktgen_ptick >= bus->pktgen_print)) {
4415                 bus->pktgen_ptick = 0;
4416                 printf("%s: send attempts %d rcvd %d\n",
4417                        __FUNCTION__, bus->pktgen_sent, bus->pktgen_rcvd);
4418         }
4419
4420         /* For recv mode, just make sure dongle has started sending */
4421         if (bus->pktgen_mode == DHD_PKTGEN_RECV) {
4422                 if (!bus->pktgen_rcvd)
4423                         dhdsdio_sdtest_set(bus, TRUE);
4424                 return;
4425         }
4426
4427         /* Otherwise, generate or request the specified number of packets */
4428         for (pktcount = 0; pktcount < bus->pktgen_count; pktcount++) {
4429                 /* Stop if total has been reached */
4430                 if (bus->pktgen_total && (bus->pktgen_sent >= bus->pktgen_total)) {
4431                         bus->pktgen_count = 0;
4432                         break;
4433                 }
4434
4435                 /* Allocate an appropriate-sized packet */
4436                 len = bus->pktgen_len;
4437                 if (!(pkt = PKTGET(osh, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN),
4438                                    TRUE))) {;
4439                         DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__));
4440                         break;
4441                 }
4442                 PKTALIGN(osh, pkt, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN), DHD_SDALIGN);
4443                 data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
4444
4445                 /* Write test header cmd and extra based on mode */
4446                 switch (bus->pktgen_mode) {
4447                 case DHD_PKTGEN_ECHO:
4448                         *data++ = SDPCM_TEST_ECHOREQ;
4449                         *data++ = (uint8)bus->pktgen_sent;
4450                         break;
4451
4452                 case DHD_PKTGEN_SEND:
4453                         *data++ = SDPCM_TEST_DISCARD;
4454                         *data++ = (uint8)bus->pktgen_sent;
4455                         break;
4456
4457                 case DHD_PKTGEN_RXBURST:
4458                         *data++ = SDPCM_TEST_BURST;
4459                         *data++ = (uint8)bus->pktgen_count;
4460                         break;
4461
4462                 default:
4463                         DHD_ERROR(("Unrecognized pktgen mode %d\n", bus->pktgen_mode));
4464                         PKTFREE(osh, pkt, TRUE);
4465                         bus->pktgen_count = 0;
4466                         return;
4467                 }
4468
4469                 /* Write test header length field */
4470                 *data++ = (len >> 0);
4471                 *data++ = (len >> 8);
4472
4473                 /* Then fill in the remainder -- N/A for burst, but who cares... */
4474                 for (fillbyte = 0; fillbyte < len; fillbyte++)
4475                         *data++ = SDPCM_TEST_FILL(fillbyte, (uint8)bus->pktgen_sent);
4476
4477 #ifdef DHD_DEBUG
4478                 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
4479                         data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
4480                         prhex("dhdsdio_pktgen: Tx Data", data, PKTLEN(osh, pkt) - SDPCM_HDRLEN);
4481                 }
4482 #endif
4483
4484                 /* Send it */
4485                 if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE)) {
4486                         bus->pktgen_fail++;
4487                         if (bus->pktgen_stop && bus->pktgen_stop == bus->pktgen_fail)
4488                                 bus->pktgen_count = 0;
4489                 }
4490                 bus->pktgen_sent++;
4491
4492                 /* Bump length if not fixed, wrap at max */
4493                 if (++bus->pktgen_len > bus->pktgen_maxlen)
4494                         bus->pktgen_len = (uint16)bus->pktgen_minlen;
4495
4496                 /* Special case for burst mode: just send one request! */
4497                 if (bus->pktgen_mode == DHD_PKTGEN_RXBURST)
4498                         break;
4499         }
4500 }
4501
4502 static void
4503 dhdsdio_sdtest_set(dhd_bus_t *bus, bool start)
4504 {
4505         void *pkt;
4506         uint8 *data;
4507         osl_t *osh = bus->dhd->osh;
4508
4509         /* Allocate the packet */
4510         if (!(pkt = PKTGET(osh, SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN, TRUE))) {
4511                 DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__));
4512                 return;
4513         }
4514         PKTALIGN(osh, pkt, (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN), DHD_SDALIGN);
4515         data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
4516
4517         /* Fill in the test header */
4518         *data++ = SDPCM_TEST_SEND;
4519         *data++ = start;
4520         *data++ = (bus->pktgen_maxlen >> 0);
4521         *data++ = (bus->pktgen_maxlen >> 8);
4522
4523         /* Send it */
4524         if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE))
4525                 bus->pktgen_fail++;
4526 }
4527
4528
4529 static void
4530 dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq)
4531 {
4532         osl_t *osh = bus->dhd->osh;
4533         uint8 *data;
4534         uint pktlen;
4535
4536         uint8 cmd;
4537         uint8 extra;
4538         uint16 len;
4539         uint16 offset;
4540
4541         /* Check for min length */
4542         if ((pktlen = PKTLEN(osh, pkt)) < SDPCM_TEST_HDRLEN) {
4543                 DHD_ERROR(("dhdsdio_restrcv: toss runt frame, pktlen %d\n", pktlen));
4544                 PKTFREE(osh, pkt, FALSE);
4545                 return;
4546         }
4547
4548         /* Extract header fields */
4549         data = PKTDATA(osh, pkt);
4550         cmd = *data++;
4551         extra = *data++;
4552         len = *data++; len += *data++ << 8;
4553
4554         /* Check length for relevant commands */
4555         if (cmd == SDPCM_TEST_DISCARD || cmd == SDPCM_TEST_ECHOREQ || cmd == SDPCM_TEST_ECHORSP) {
4556                 if (pktlen != len + SDPCM_TEST_HDRLEN) {
4557                         DHD_ERROR(("dhdsdio_testrcv: frame length mismatch, pktlen %d seq %d"
4558                                    " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len));
4559                         PKTFREE(osh, pkt, FALSE);
4560                         return;
4561                 }
4562         }
4563
4564         /* Process as per command */
4565         switch (cmd) {
4566         case SDPCM_TEST_ECHOREQ:
4567                 /* Rx->Tx turnaround ok (even on NDIS w/current implementation) */
4568                 *(uint8 *)(PKTDATA(osh, pkt)) = SDPCM_TEST_ECHORSP;
4569                 if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE) == 0) {
4570                         bus->pktgen_sent++;
4571                 } else {
4572                         bus->pktgen_fail++;
4573                         PKTFREE(osh, pkt, FALSE);
4574                 }
4575                 bus->pktgen_rcvd++;
4576                 break;
4577
4578         case SDPCM_TEST_ECHORSP:
4579                 if (bus->ext_loop) {
4580                         PKTFREE(osh, pkt, FALSE);
4581                         bus->pktgen_rcvd++;
4582                         break;
4583                 }
4584
4585                 for (offset = 0; offset < len; offset++, data++) {
4586                         if (*data != SDPCM_TEST_FILL(offset, extra)) {
4587                                 DHD_ERROR(("dhdsdio_testrcv: echo data mismatch: "
4588                                            "offset %d (len %d) expect 0x%02x rcvd 0x%02x\n",
4589                                            offset, len, SDPCM_TEST_FILL(offset, extra), *data));
4590                                 break;
4591                         }
4592                 }
4593                 PKTFREE(osh, pkt, FALSE);
4594                 bus->pktgen_rcvd++;
4595                 break;
4596
4597         case SDPCM_TEST_DISCARD:
4598                 PKTFREE(osh, pkt, FALSE);
4599                 bus->pktgen_rcvd++;
4600                 break;
4601
4602         case SDPCM_TEST_BURST:
4603         case SDPCM_TEST_SEND:
4604         default:
4605                 DHD_INFO(("dhdsdio_testrcv: unsupported or unknown command, pktlen %d seq %d"
4606                           " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len));
4607                 PKTFREE(osh, pkt, FALSE);
4608                 break;
4609         }
4610
4611         /* For recv mode, stop at limie (and tell dongle to stop sending) */
4612         if (bus->pktgen_mode == DHD_PKTGEN_RECV) {
4613                 if (bus->pktgen_total && (bus->pktgen_rcvd >= bus->pktgen_total)) {
4614                         bus->pktgen_count = 0;
4615                         dhdsdio_sdtest_set(bus, FALSE);
4616                 }
4617         }
4618 }
4619 #endif /* SDTEST */
4620
4621 extern bool
4622 dhd_bus_watchdog(dhd_pub_t *dhdp)
4623 {
4624         dhd_bus_t *bus;
4625
4626         DHD_TIMER(("%s: Enter\n", __FUNCTION__));
4627
4628         bus = dhdp->bus;
4629
4630         if (bus->dhd->dongle_reset)
4631                 return FALSE;
4632
4633         /* Ignore the timer if simulating bus down */
4634         if (bus->sleeping)
4635                 return FALSE;
4636
4637         dhd_os_sdlock(bus->dhd);
4638
4639         /* Poll period: check device if appropriate. */
4640         if (bus->poll && (++bus->polltick >= bus->pollrate)) {
4641                 uint32 intstatus = 0;
4642
4643                 /* Reset poll tick */
4644                 bus->polltick = 0;
4645
4646                 /* Check device if no interrupts */
4647                 if (!bus->intr || (bus->intrcount == bus->lastintrs)) {
4648
4649                         if (!bus->dpc_sched) {
4650                                 uint8 devpend;
4651                                 devpend = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0,
4652                                                           SDIOD_CCCR_INTPEND, NULL);
4653                                 intstatus = devpend & (INTR_STATUS_FUNC1 | INTR_STATUS_FUNC2);
4654                         }
4655
4656                         /* If there is something, make like the ISR and schedule the DPC */
4657                         if (intstatus) {
4658                                 bus->pollcnt++;
4659                                 bus->ipend = TRUE;
4660                                 if (bus->intr) {
4661                                         bcmsdh_intr_disable(bus->sdh);
4662                                 }
4663                                 bus->dpc_sched = TRUE;
4664                                 dhd_sched_dpc(bus->dhd);
4665
4666                         }
4667                 }
4668
4669                 /* Update interrupt tracking */
4670                 bus->lastintrs = bus->intrcount;
4671         }
4672
4673 #ifdef DHD_DEBUG
4674         /* Poll for console output periodically */
4675         if (dhdp->busstate == DHD_BUS_DATA && dhd_console_ms != 0) {
4676                 bus->console.count += dhd_watchdog_ms;
4677                 if (bus->console.count >= dhd_console_ms) {
4678                         bus->console.count -= dhd_console_ms;
4679                         /* Make sure backplane clock is on */
4680                         dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
4681                         if (dhdsdio_readconsole(bus) < 0)
4682                                 dhd_console_ms = 0;     /* On error, stop trying */
4683                 }
4684         }
4685 #endif /* DHD_DEBUG */
4686
4687 #ifdef SDTEST
4688         /* Generate packets if configured */
4689         if (bus->pktgen_count && (++bus->pktgen_tick >= bus->pktgen_freq)) {
4690                 /* Make sure backplane clock is on */
4691                 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
4692                 bus->pktgen_tick = 0;
4693                 dhdsdio_pktgen(bus);
4694         }
4695 #endif
4696
4697         /* On idle timeout clear activity flag and/or turn off clock */
4698         if ((bus->idletime > 0) && (bus->clkstate == CLK_AVAIL)) {
4699                 if (++bus->idlecount >= bus->idletime) {
4700                         bus->idlecount = 0;
4701                         if (bus->activity) {
4702                                 bus->activity = FALSE;
4703                                 dhd_os_wd_timer(bus->dhd,dhd_watchdog_ms);
4704                         } else {
4705                                 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
4706                         }
4707                 }
4708         }
4709
4710         dhd_os_sdunlock(bus->dhd);
4711
4712         return bus->ipend;
4713 }
4714
4715 #ifdef DHD_DEBUG
4716 extern int
4717 dhd_bus_console_in(dhd_pub_t *dhdp, uchar *msg, uint msglen)
4718 {
4719         dhd_bus_t *bus = dhdp->bus;
4720         uint32 addr, val;
4721         int rv;
4722         void *pkt;
4723
4724         /* Address could be zero if CONSOLE := 0 in dongle Makefile */
4725         if (bus->console_addr == 0)
4726                 return BCME_UNSUPPORTED;
4727
4728         /* Exclusive bus access */
4729         dhd_os_sdlock(bus->dhd);
4730
4731         /* Don't allow input if dongle is in reset */
4732         if (bus->dhd->dongle_reset) {
4733                 dhd_os_sdunlock(bus->dhd);
4734                 return BCME_NOTREADY;
4735         }
4736
4737         /* Request clock to allow SDIO accesses */
4738         BUS_WAKE(bus);
4739         /* No pend allowed since txpkt is called later, ht clk has to be on */
4740         dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
4741
4742         /* Zero cbuf_index */
4743         addr = bus->console_addr + OFFSETOF(hndrte_cons_t, cbuf_idx);
4744         val = htol32(0);
4745         if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0)
4746                 goto done;
4747
4748         /* Write message into cbuf */
4749         addr = bus->console_addr + OFFSETOF(hndrte_cons_t, cbuf);
4750         if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)msg, msglen)) < 0)
4751                 goto done;
4752
4753         /* Write length into vcons_in */
4754         addr = bus->console_addr + OFFSETOF(hndrte_cons_t, vcons_in);
4755         val = htol32(msglen);
4756         if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0)
4757                 goto done;
4758
4759         /* Bump dongle by sending an empty event pkt.
4760          * sdpcm_sendup (RX) checks for virtual console input.
4761          */
4762         if (((pkt = PKTGET(bus->dhd->osh, 4 + SDPCM_RESERVE, TRUE)) != NULL) &&
4763                 bus->clkstate == CLK_AVAIL)
4764                 dhdsdio_txpkt(bus, pkt, SDPCM_EVENT_CHANNEL, TRUE);
4765
4766 done:
4767         if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
4768                 bus->activity = FALSE;
4769                 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
4770         }
4771
4772         dhd_os_sdunlock(bus->dhd);
4773
4774         return rv;
4775 }
4776 #endif /* DHD_DEBUG */
4777
4778 #ifdef DHD_DEBUG
4779 static void
4780 dhd_dump_cis(uint fn, uint8 *cis)
4781 {
4782         uint byte, tag, tdata;
4783         DHD_INFO(("Function %d CIS:\n", fn));
4784
4785         for (tdata = byte = 0; byte < SBSDIO_CIS_SIZE_LIMIT; byte++) {
4786                 if ((byte % 16) == 0)
4787                         DHD_INFO(("    "));
4788                 DHD_INFO(("%02x ", cis[byte]));
4789                 if ((byte % 16) == 15)
4790                         DHD_INFO(("\n"));
4791                 if (!tdata--) {
4792                         tag = cis[byte];
4793                         if (tag == 0xff)
4794                                 break;
4795                         else if (!tag)
4796                                 tdata = 0;
4797                         else if ((byte + 1) < SBSDIO_CIS_SIZE_LIMIT)
4798                                 tdata = cis[byte + 1] + 1;
4799                         else
4800                                 DHD_INFO(("]"));
4801                 }
4802         }
4803         if ((byte % 16) != 15)
4804                 DHD_INFO(("\n"));
4805 }
4806 #endif /* DHD_DEBUG */
4807
4808 static bool
4809 dhdsdio_chipmatch(uint16 chipid)
4810 {
4811         if (chipid == BCM4325_CHIP_ID)
4812                 return TRUE;
4813         if (chipid == BCM4329_CHIP_ID)
4814                 return TRUE;
4815         if (chipid == BCM4315_CHIP_ID)
4816                 return TRUE;
4817         if (chipid == BCM4319_CHIP_ID)
4818                 return TRUE;
4819         return FALSE;
4820 }
4821
4822 static void *
4823 dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot,
4824         uint16 func, uint bustype, void *regsva, osl_t * osh, void *sdh)
4825 {
4826         int ret;
4827         dhd_bus_t *bus;
4828
4829         /* Init global variables at run-time, not as part of the declaration.
4830          * This is required to support init/de-init of the driver. Initialization
4831          * of globals as part of the declaration results in non-deterministic
4832          * behavior since the value of the globals may be different on the
4833          * first time that the driver is initialized vs subsequent initializations.
4834          */
4835         dhd_txbound = DHD_TXBOUND;
4836         dhd_rxbound = DHD_RXBOUND;
4837         dhd_alignctl = TRUE;
4838         sd1idle = TRUE;
4839         dhd_readahead = TRUE;
4840         retrydata = FALSE;
4841         dhd_doflow = FALSE;
4842         dhd_dongle_memsize = 0;
4843         dhd_txminmax = DHD_TXMINMAX;
4844
4845         forcealign = TRUE;
4846
4847
4848         dhd_common_init();
4849
4850         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4851         DHD_INFO(("%s: venid 0x%04x devid 0x%04x\n", __FUNCTION__, venid, devid));
4852
4853         /* We make assumptions about address window mappings */
4854         ASSERT((uintptr)regsva == SI_ENUM_BASE);
4855
4856         /* BCMSDH passes venid and devid based on CIS parsing -- but low-power start
4857          * means early parse could fail, so here we should get either an ID
4858          * we recognize OR (-1) indicating we must request power first.
4859          */
4860         /* Check the Vendor ID */
4861         switch (venid) {
4862                 case 0x0000:
4863                 case VENDOR_BROADCOM:
4864                         break;
4865                 default:
4866                         DHD_ERROR(("%s: unknown vendor: 0x%04x\n",
4867                                    __FUNCTION__, venid));
4868                         return NULL;
4869         }
4870
4871         /* Check the Device ID and make sure it's one that we support */
4872         switch (devid) {
4873                 case BCM4325_D11DUAL_ID:                /* 4325 802.11a/g id */
4874                 case BCM4325_D11G_ID:                   /* 4325 802.11g 2.4Ghz band id */
4875                 case BCM4325_D11A_ID:                   /* 4325 802.11a 5Ghz band id */
4876                         DHD_INFO(("%s: found 4325 Dongle\n", __FUNCTION__));
4877                         break;
4878                 case BCM4329_D11NDUAL_ID:               /* 4329 802.11n dualband device */
4879                 case BCM4329_D11N2G_ID:         /* 4329 802.11n 2.4G device */
4880                 case BCM4329_D11N5G_ID:         /* 4329 802.11n 5G device */
4881                 case 0x4329:
4882                         DHD_INFO(("%s: found 4329 Dongle\n", __FUNCTION__));
4883                         break;
4884                 case BCM4315_D11DUAL_ID:                /* 4315 802.11a/g id */
4885                 case BCM4315_D11G_ID:                   /* 4315 802.11g id */
4886                 case BCM4315_D11A_ID:                   /* 4315 802.11a id */
4887                         DHD_INFO(("%s: found 4315 Dongle\n", __FUNCTION__));
4888                         break;
4889                 case BCM4319_D11N_ID:                   /* 4319 802.11n id */
4890                 case BCM4319_D11N2G_ID:                 /* 4319 802.11n2g id */
4891                 case BCM4319_D11N5G_ID:                 /* 4319 802.11n5g id */
4892                         DHD_INFO(("%s: found 4319 Dongle\n", __FUNCTION__));
4893                         break;
4894                 case 0:
4895                         DHD_INFO(("%s: allow device id 0, will check chip internals\n",
4896                                   __FUNCTION__));
4897                         break;
4898
4899                 default:
4900                         DHD_ERROR(("%s: skipping 0x%04x/0x%04x, not a dongle\n",
4901                                    __FUNCTION__, venid, devid));
4902                         return NULL;
4903         }
4904
4905         if (osh == NULL) {
4906                 /* Ask the OS interface part for an OSL handle */
4907                 if (!(osh = dhd_osl_attach(sdh, DHD_BUS))) {
4908                         DHD_ERROR(("%s: osl_attach failed!\n", __FUNCTION__));
4909                         return NULL;
4910                 }
4911         }
4912
4913         /* Allocate private bus interface state */
4914         if (!(bus = MALLOC(osh, sizeof(dhd_bus_t)))) {
4915                 DHD_ERROR(("%s: MALLOC of dhd_bus_t failed\n", __FUNCTION__));
4916                 goto fail;
4917         }
4918         bzero(bus, sizeof(dhd_bus_t));
4919         bus->sdh = sdh;
4920         bus->cl_devid = (uint16)devid;
4921         bus->bus = DHD_BUS;
4922         bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1;
4923         bus->usebufpool = FALSE; /* Use bufpool if allocated, else use locally malloced rxbuf */
4924
4925         /* attempt to attach to the dongle */
4926         if (!(dhdsdio_probe_attach(bus, osh, sdh, regsva, devid))) {
4927                 DHD_ERROR(("%s: dhdsdio_probe_attach failed\n", __FUNCTION__));
4928                 goto fail;
4929         }
4930
4931         /* Attach to the dhd/OS/network interface */
4932         if (!(bus->dhd = dhd_attach(osh, bus, SDPCM_RESERVE))) {
4933                 DHD_ERROR(("%s: dhd_attach failed\n", __FUNCTION__));
4934                 goto fail;
4935         }
4936
4937         /* Allocate buffers */
4938         if (!(dhdsdio_probe_malloc(bus, osh, sdh))) {
4939                 DHD_ERROR(("%s: dhdsdio_probe_malloc failed\n", __FUNCTION__));
4940                 goto fail;
4941         }
4942
4943         if (!(dhdsdio_probe_init(bus, osh, sdh))) {
4944                 DHD_ERROR(("%s: dhdsdio_probe_init failed\n", __FUNCTION__));
4945                 goto fail;
4946         }
4947
4948         /* Register interrupt callback, but mask it (not operational yet). */
4949         DHD_INTR(("%s: disable SDIO interrupts (not interested yet)\n", __FUNCTION__));
4950         bcmsdh_intr_disable(sdh);
4951         if ((ret = bcmsdh_intr_reg(sdh, dhdsdio_isr, bus)) != 0) {
4952                 DHD_ERROR(("%s: FAILED: bcmsdh_intr_reg returned %d\n",
4953                            __FUNCTION__, ret));
4954                 goto fail;
4955         }
4956         DHD_INTR(("%s: registered SDIO interrupt function ok\n", __FUNCTION__));
4957
4958         DHD_INFO(("%s: completed!!\n", __FUNCTION__));
4959
4960
4961         /* if firmware path present try to download and bring up bus */
4962         if ((ret = dhd_bus_start(bus->dhd)) != 0) {
4963                 DHD_ERROR(("%s: failed\n", __FUNCTION__));
4964                 goto fail;
4965                 if (ret == BCME_NOTUP)  {
4966                         DHD_ERROR(("%s: dongle is not responding\n", __FUNCTION__));
4967                         goto fail;
4968                 }
4969         }
4970         /* Ok, have the per-port tell the stack we're open for business */
4971         if (dhd_net_attach(bus->dhd, 0) != 0) {
4972                 DHD_ERROR(("%s: Net attach failed!!\n", __FUNCTION__));
4973                 goto fail;
4974         }
4975
4976         return bus;
4977
4978 fail:
4979         dhdsdio_release(bus, osh);
4980         return NULL;
4981 }
4982
4983
4984 static bool
4985 dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva,
4986                     uint16 devid)
4987 {
4988         uint8 clkctl = 0;
4989         int err = 0;
4990
4991         bus->alp_only = TRUE;
4992
4993         /* Return the window to backplane enumeration space for core access */
4994         if (dhdsdio_set_siaddr_window(bus, SI_ENUM_BASE)) {
4995                 DHD_ERROR(("%s: FAILED to return to SI_ENUM_BASE\n", __FUNCTION__));
4996         }
4997
4998 #ifdef DHD_DEBUG
4999         printf("F1 signature read @0x18000000=0x%4x\n",
5000                bcmsdh_reg_read(bus->sdh, SI_ENUM_BASE, 4));
5001
5002
5003 #endif /* DHD_DEBUG */
5004
5005
5006         /* Force PLL off until si_attach() programs PLL control regs */
5007
5008
5009
5010         bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, DHD_INIT_CLKCTL1, &err);
5011         if (!err)
5012                 clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
5013
5014         if (err || ((clkctl & ~SBSDIO_AVBITS) != DHD_INIT_CLKCTL1)) {
5015                 DHD_ERROR(("dhdsdio_probe: ChipClkCSR access: err %d wrote 0x%02x read 0x%02x\n",
5016                            err, DHD_INIT_CLKCTL1, clkctl));
5017                 goto fail;
5018         }
5019
5020
5021 #ifdef DHD_DEBUG
5022         if (DHD_INFO_ON()) {
5023                 uint fn, numfn;
5024                 uint8 *cis[SDIOD_MAX_IOFUNCS];
5025                 int err = 0;
5026
5027                 numfn = bcmsdh_query_iofnum(sdh);
5028                 ASSERT(numfn <= SDIOD_MAX_IOFUNCS);
5029
5030                 /* Make sure ALP is available before trying to read CIS */
5031                 SPINWAIT(((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
5032                                                     SBSDIO_FUNC1_CHIPCLKCSR, NULL)),
5033                           !SBSDIO_ALPAV(clkctl)), PMU_MAX_TRANSITION_DLY);
5034
5035                 /* Now request ALP be put on the bus */
5036                 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
5037                                  DHD_INIT_CLKCTL2, &err);
5038                 OSL_DELAY(65);
5039
5040                 for (fn = 0; fn <= numfn; fn++) {
5041                         if (!(cis[fn] = MALLOC(osh, SBSDIO_CIS_SIZE_LIMIT))) {
5042                                 DHD_INFO(("dhdsdio_probe: fn %d cis malloc failed\n", fn));
5043                                 break;
5044                         }
5045                         bzero(cis[fn], SBSDIO_CIS_SIZE_LIMIT);
5046
5047                         if ((err = bcmsdh_cis_read(sdh, fn, cis[fn], SBSDIO_CIS_SIZE_LIMIT))) {
5048                                 DHD_INFO(("dhdsdio_probe: fn %d cis read err %d\n", fn, err));
5049                                 MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT);
5050                                 break;
5051                         }
5052                         dhd_dump_cis(fn, cis[fn]);
5053                 }
5054
5055                 while (fn-- > 0) {
5056                         ASSERT(cis[fn]);
5057                         MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT);
5058                 }
5059
5060                 if (err) {
5061                         DHD_ERROR(("dhdsdio_probe: failure reading or parsing CIS\n"));
5062                         goto fail;
5063                 }
5064         }
5065 #endif /* DHD_DEBUG */
5066
5067         /* si_attach() will provide an SI handle and scan the backplane */
5068         if (!(bus->sih = si_attach((uint)devid, osh, regsva, DHD_BUS, sdh,
5069                                    &bus->vars, &bus->varsz))) {
5070                 DHD_ERROR(("%s: si_attach failed!\n", __FUNCTION__));
5071                 goto fail;
5072         }
5073
5074         bcmsdh_chipinfo(sdh, bus->sih->chip, bus->sih->chiprev);
5075
5076         if (!dhdsdio_chipmatch((uint16)bus->sih->chip)) {
5077                 DHD_ERROR(("%s: unsupported chip: 0x%04x\n",
5078                            __FUNCTION__, bus->sih->chip));
5079                 goto fail;
5080         }
5081
5082         si_sdiod_drive_strength_init(bus->sih, osh, dhd_sdiod_drive_strength);
5083
5084
5085         /* Get info on the ARM and SOCRAM cores... */
5086         if (!DHD_NOPMU(bus)) {
5087                 if ((si_setcore(bus->sih, ARM7S_CORE_ID, 0)) ||
5088                     (si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) {
5089                         bus->armrev = si_corerev(bus->sih);
5090                 } else {
5091                         DHD_ERROR(("%s: failed to find ARM core!\n", __FUNCTION__));
5092                         goto fail;
5093                 }
5094                 if (!(bus->orig_ramsize = si_socram_size(bus->sih))) {
5095                         DHD_ERROR(("%s: failed to find SOCRAM memory!\n", __FUNCTION__));
5096                         goto fail;
5097                 }
5098                 bus->ramsize = bus->orig_ramsize;
5099                 if (dhd_dongle_memsize)
5100                         dhd_dongle_setmemsize(bus, dhd_dongle_memsize);
5101
5102                 DHD_ERROR(("DHD: dongle ram size is set to %d(orig %d)\n",
5103                         bus->ramsize, bus->orig_ramsize));
5104         }
5105
5106         /* ...but normally deal with the SDPCMDEV core */
5107         if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0)) &&
5108             !(bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0))) {
5109                 DHD_ERROR(("%s: failed to find SDIODEV core!\n", __FUNCTION__));
5110                 goto fail;
5111         }
5112         bus->sdpcmrev = si_corerev(bus->sih);
5113
5114         /* Set core control so an SDIO reset does a backplane reset */
5115         OR_REG(osh, &bus->regs->corecontrol, CC_BPRESEN);
5116
5117         pktq_init(&bus->txq, (PRIOMASK + 1), QLEN);
5118
5119         /* Locate an appropriately-aligned portion of hdrbuf */
5120         bus->rxhdr = (uint8 *)ROUNDUP((uintptr)&bus->hdrbuf[0], DHD_SDALIGN);
5121
5122         /* Set the poll and/or interrupt flags */
5123         bus->intr = (bool)dhd_intr;
5124         if ((bus->poll = (bool)dhd_poll))
5125                 bus->pollrate = 1;
5126
5127         return TRUE;
5128
5129 fail:
5130         return FALSE;
5131 }
5132
5133 static bool
5134 dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh)
5135 {
5136         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5137
5138 #ifndef DHD_USE_STATIC_BUF
5139         if (bus->dhd->maxctl) {
5140                 bus->rxblen = ROUNDUP((bus->dhd->maxctl + SDPCM_HDRLEN), ALIGNMENT) + DHD_SDALIGN;
5141                 if (!(bus->rxbuf = MALLOC(osh, bus->rxblen))) {
5142                         DHD_ERROR(("%s: MALLOC of %d-byte rxbuf failed\n",
5143                                    __FUNCTION__, bus->rxblen));
5144                         goto fail;
5145                 }
5146         }
5147
5148         /* Allocate buffer to receive glomed packet */
5149         if (!(bus->databuf = MALLOC(osh, MAX_DATA_BUF))) {
5150                 DHD_ERROR(("%s: MALLOC of %d-byte databuf failed\n",
5151                         __FUNCTION__, MAX_DATA_BUF));
5152                 /* release rxbuf which was already located as above */
5153                 if (!bus->rxblen) MFREE(osh, bus->rxbuf, bus->rxblen);
5154                 goto fail;
5155         }
5156 #else
5157         if (bus->dhd->maxctl) {
5158                 bus->rxblen = ROUNDUP((bus->dhd->maxctl + SDPCM_HDRLEN), ALIGNMENT) + DHD_SDALIGN;
5159                 if (!(bus->rxbuf = dhd_os_prealloc(DHD_PREALLOC_RXBUF, bus->rxblen))) {
5160                         DHD_ERROR(("%s: MALLOC of %d-byte rxbuf failed\n",
5161                                    __FUNCTION__, bus->rxblen));
5162                         goto fail;
5163                 }
5164         }
5165         /* Allocate buffer to receive glomed packet */
5166         if (!(bus->databuf = dhd_os_prealloc(DHD_PREALLOC_DATABUF, MAX_DATA_BUF))) {
5167                 DHD_ERROR(("%s: MALLOC of %d-byte databuf failed\n",
5168                         __FUNCTION__, MAX_DATA_BUF));
5169                 goto fail;
5170         }
5171 #endif /* DHD_USE_STATIC_BUF */
5172
5173         /* Align the buffer */
5174         if ((uintptr)bus->databuf % DHD_SDALIGN)
5175                 bus->dataptr = bus->databuf + (DHD_SDALIGN - ((uintptr)bus->databuf % DHD_SDALIGN));
5176         else
5177                 bus->dataptr = bus->databuf;
5178
5179         return TRUE;
5180
5181 fail:
5182         return FALSE;
5183 }
5184
5185
5186 static bool
5187 dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh)
5188 {
5189         int32 fnum;
5190
5191         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5192
5193 #ifdef SDTEST
5194         dhdsdio_pktgen_init(bus);
5195 #endif /* SDTEST */
5196
5197         /* Disable F2 to clear any intermediate frame state on the dongle */
5198         bcmsdh_cfg_write(sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL);
5199
5200         bus->dhd->busstate = DHD_BUS_DOWN;
5201         bus->sleeping = FALSE;
5202         bus->rxflow = FALSE;
5203         bus->prev_rxlim_hit = 0;
5204
5205
5206         /* Done with backplane-dependent accesses, can drop clock... */
5207         bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
5208
5209         /* ...and initialize clock/power states */
5210         bus->clkstate = CLK_SDONLY;
5211         bus->idletime = (int32)dhd_idletime;
5212         bus->idleclock = DHD_IDLE_ACTIVE;
5213
5214         /* Query the SD clock speed */
5215         if (bcmsdh_iovar_op(sdh, "sd_divisor", NULL, 0,
5216                             &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) {
5217                 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_divisor"));
5218                 bus->sd_divisor = -1;
5219         } else {
5220                 DHD_INFO(("%s: Initial value for %s is %d\n",
5221                           __FUNCTION__, "sd_divisor", bus->sd_divisor));
5222         }
5223
5224         /* Query the SD bus mode */
5225         if (bcmsdh_iovar_op(sdh, "sd_mode", NULL, 0,
5226                             &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) {
5227                 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_mode"));
5228                 bus->sd_mode = -1;
5229         } else {
5230                 DHD_INFO(("%s: Initial value for %s is %d\n",
5231                           __FUNCTION__, "sd_mode", bus->sd_mode));
5232         }
5233
5234         /* Query the F2 block size, set roundup accordingly */
5235         fnum = 2;
5236         if (bcmsdh_iovar_op(sdh, "sd_blocksize", &fnum, sizeof(int32),
5237                             &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) {
5238                 bus->blocksize = 0;
5239                 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize"));
5240         } else {
5241                 DHD_INFO(("%s: Initial value for %s is %d\n",
5242                           __FUNCTION__, "sd_blocksize", bus->blocksize));
5243         }
5244         bus->roundup = MIN(max_roundup, bus->blocksize);
5245
5246         /* Query if bus module supports packet chaining, default to use if supported */
5247         if (bcmsdh_iovar_op(sdh, "sd_rxchain", NULL, 0,
5248                             &bus->sd_rxchain, sizeof(int32), FALSE) != BCME_OK) {
5249                 bus->sd_rxchain = FALSE;
5250         } else {
5251                 DHD_INFO(("%s: bus module (through bcmsdh API) %s chaining\n",
5252                           __FUNCTION__, (bus->sd_rxchain ? "supports" : "does not support")));
5253         }
5254         bus->use_rxchain = (bool)bus->sd_rxchain;
5255
5256         return TRUE;
5257 }
5258
5259 bool
5260 dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh,
5261                           char *fw_path, char *nv_path)
5262 {
5263         bool ret;
5264         bus->fw_path = fw_path;
5265         bus->nv_path = nv_path;
5266
5267         ret = dhdsdio_download_firmware(bus, osh, bus->sdh);
5268
5269
5270         return ret;
5271 }
5272
5273 static bool
5274 dhdsdio_download_firmware(struct dhd_bus *bus, osl_t *osh, void *sdh)
5275 {
5276         bool ret;
5277
5278         /* Download the firmware */
5279         dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
5280
5281         ret = _dhdsdio_download_firmware(bus) == 0;
5282
5283         dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
5284
5285         return ret;
5286 }
5287
5288 /* Detach and free everything */
5289 static void
5290 dhdsdio_release(dhd_bus_t *bus, osl_t *osh)
5291 {
5292         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5293
5294         if (bus) {
5295                 ASSERT(osh);
5296
5297
5298                 /* De-register interrupt handler */
5299                 bcmsdh_intr_disable(bus->sdh);
5300                 bcmsdh_intr_dereg(bus->sdh);
5301
5302                 if (bus->dhd) {
5303
5304                         dhdsdio_release_dongle(bus, osh);
5305
5306                         dhd_detach(bus->dhd);
5307                         bus->dhd = NULL;
5308                 }
5309
5310                 dhdsdio_release_malloc(bus, osh);
5311
5312
5313                 MFREE(osh, bus, sizeof(dhd_bus_t));
5314         }
5315
5316         if (osh)
5317                 dhd_osl_detach(osh);
5318
5319         DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
5320 }
5321
5322 static void
5323 dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh)
5324 {
5325         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5326
5327         if (bus->dhd && bus->dhd->dongle_reset)
5328                 return;
5329
5330         if (bus->rxbuf) {
5331 #ifndef DHD_USE_STATIC_BUF
5332                 MFREE(osh, bus->rxbuf, bus->rxblen);
5333 #endif
5334                 bus->rxctl = bus->rxbuf = NULL;
5335                 bus->rxlen = 0;
5336         }
5337
5338         if (bus->databuf) {
5339 #ifndef DHD_USE_STATIC_BUF
5340                 MFREE(osh, bus->databuf, MAX_DATA_BUF);
5341 #endif
5342                 bus->databuf = NULL;
5343         }
5344 }
5345
5346
5347 static void
5348 dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh)
5349 {
5350         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5351
5352         if (bus->dhd && bus->dhd->dongle_reset)
5353                 return;
5354
5355         if (bus->sih) {
5356                 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
5357 #if !defined(BCMLXSDMMC)
5358                 si_watchdog(bus->sih, 4);
5359 #endif /* !defined(BCMLXSDMMC) */
5360                 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
5361                 si_detach(bus->sih);
5362                 if (bus->vars && bus->varsz)
5363                         MFREE(osh, bus->vars, bus->varsz);
5364                 bus->vars = NULL;
5365         }
5366
5367         DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
5368 }
5369
5370 static void
5371 dhdsdio_disconnect(void *ptr)
5372 {
5373         dhd_bus_t *bus = (dhd_bus_t *)ptr;
5374
5375         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5376
5377         if (bus) {
5378                 ASSERT(bus->dhd);
5379                 dhdsdio_release(bus, bus->dhd->osh);
5380         }
5381
5382         DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
5383 }
5384
5385
5386 /* Register/Unregister functions are called by the main DHD entry
5387  * point (e.g. module insertion) to link with the bus driver, in
5388  * order to look for or await the device.
5389  */
5390
5391 static bcmsdh_driver_t dhd_sdio = {
5392         dhdsdio_probe,
5393         dhdsdio_disconnect
5394 };
5395
5396 int
5397 dhd_bus_register(void)
5398 {
5399         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5400
5401         return bcmsdh_register(&dhd_sdio);
5402 }
5403
5404 void
5405 dhd_bus_unregister(void)
5406 {
5407         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5408
5409         bcmsdh_unregister();
5410 }
5411
5412 #ifdef BCMEMBEDIMAGE
5413 static int
5414 dhdsdio_download_code_array(struct dhd_bus *bus)
5415 {
5416         int bcmerror = -1;
5417         int offset = 0;
5418
5419         DHD_INFO(("%s: download embedded firmware...\n", __FUNCTION__));
5420
5421         /* Download image */
5422         while ((offset + MEMBLOCK) < sizeof(dlarray)) {
5423                 bcmerror = dhdsdio_membytes(bus, TRUE, offset, dlarray + offset, MEMBLOCK);
5424                 if (bcmerror) {
5425                         DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
5426                                 __FUNCTION__, bcmerror, MEMBLOCK, offset));
5427                         goto err;
5428                 }
5429
5430                 offset += MEMBLOCK;
5431         }
5432
5433         if (offset < sizeof(dlarray)) {
5434                 bcmerror = dhdsdio_membytes(bus, TRUE, offset,
5435                         dlarray + offset, sizeof(dlarray) - offset);
5436                 if (bcmerror) {
5437                         DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
5438                                 __FUNCTION__, bcmerror, sizeof(dlarray) - offset, offset));
5439                         goto err;
5440                 }
5441         }
5442
5443 #ifdef DHD_DEBUG
5444         /* Upload and compare the downloaded code */
5445         {
5446                 unsigned char *ularray;
5447
5448                 ularray = MALLOC(bus->dhd->osh, bus->ramsize);
5449                 /* Upload image to verify downloaded contents. */
5450                 offset = 0;
5451                 memset(ularray, 0xaa, bus->ramsize);
5452                 while ((offset + MEMBLOCK) < sizeof(dlarray)) {
5453                         bcmerror = dhdsdio_membytes(bus, FALSE, offset, ularray + offset, MEMBLOCK);
5454                         if (bcmerror) {
5455                                 DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n",
5456                                         __FUNCTION__, bcmerror, MEMBLOCK, offset));
5457                                 goto err;
5458                         }
5459
5460                         offset += MEMBLOCK;
5461                 }
5462
5463                 if (offset < sizeof(dlarray)) {
5464                         bcmerror = dhdsdio_membytes(bus, FALSE, offset,
5465                                 ularray + offset, sizeof(dlarray) - offset);
5466                         if (bcmerror) {
5467                                 DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n",
5468                                         __FUNCTION__, bcmerror, sizeof(dlarray) - offset, offset));
5469                                 goto err;
5470                         }
5471                 }
5472
5473                 if (memcmp(dlarray, ularray, sizeof(dlarray))) {
5474                         DHD_ERROR(("%s: Downloaded image is corrupted.\n", __FUNCTION__));
5475                         ASSERT(0);
5476                         goto err;
5477                 } else
5478                         DHD_ERROR(("%s: Download, Upload and compare succeeded.\n", __FUNCTION__));
5479
5480                 MFREE(bus->dhd->osh, ularray, bus->ramsize);
5481         }
5482 #endif /* DHD_DEBUG */
5483
5484 err:
5485         return bcmerror;
5486 }
5487 #endif /* BCMEMBEDIMAGE */
5488
5489 static int
5490 dhdsdio_download_code_file(struct dhd_bus *bus, char *fw_path)
5491 {
5492         int bcmerror = -1;
5493         int offset = 0;
5494         uint len;
5495         void *image = NULL;
5496         uint8 *memblock = NULL, *memptr;
5497
5498         DHD_INFO(("%s: download firmware %s\n", __FUNCTION__, fw_path));
5499
5500         image = dhd_os_open_image(fw_path);
5501         if (image == NULL)
5502                 goto err;
5503
5504         memptr = memblock = MALLOC(bus->dhd->osh, MEMBLOCK + DHD_SDALIGN);
5505         if (memblock == NULL) {
5506                 DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, MEMBLOCK));
5507                 goto err;
5508         }
5509         if ((uint32)(uintptr)memblock % DHD_SDALIGN)
5510                 memptr += (DHD_SDALIGN - ((uint32)(uintptr)memblock % DHD_SDALIGN));
5511
5512         /* Download image */
5513         while ((len = dhd_os_get_image_block((char*)memptr, MEMBLOCK, image))) {
5514                 bcmerror = dhdsdio_membytes(bus, TRUE, offset, memptr, len);
5515                 if (bcmerror) {
5516                         DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
5517                                 __FUNCTION__, bcmerror, MEMBLOCK, offset));
5518                         goto err;
5519                 }
5520
5521                 offset += MEMBLOCK;
5522         }
5523
5524 err:
5525         if (memblock)
5526                 MFREE(bus->dhd->osh, memblock, MEMBLOCK + DHD_SDALIGN);
5527
5528         if (image)
5529                 dhd_os_close_image(image);
5530
5531         return bcmerror;
5532 }
5533
5534 /*
5535  * ProcessVars:Takes a buffer of "<var>=<value>\n" lines read from a file and ending in a NUL.
5536  * Removes carriage returns, empty lines, comment lines, and converts newlines to NULs.
5537  * Shortens buffer as needed and pads with NULs.  End of buffer is marked by two NULs.
5538 */
5539
5540 static uint
5541 process_nvram_vars(char *varbuf, uint len)
5542 {
5543         char *dp;
5544         bool findNewline;
5545         int column;
5546         uint buf_len, n;
5547
5548         dp = varbuf;
5549
5550         findNewline = FALSE;
5551         column = 0;
5552
5553         for (n = 0; n < len; n++) {
5554                 if (varbuf[n] == 0)
5555                         break;
5556                 if (varbuf[n] == '\r')
5557                         continue;
5558                 if (findNewline && varbuf[n] != '\n')
5559                         continue;
5560                 findNewline = FALSE;
5561                 if (varbuf[n] == '#') {
5562                         findNewline = TRUE;
5563                         continue;
5564                 }
5565                 if (varbuf[n] == '\n') {
5566                         if (column == 0)
5567                                 continue;
5568                         *dp++ = 0;
5569                         column = 0;
5570                         continue;
5571                 }
5572                 *dp++ = varbuf[n];
5573                 column++;
5574         }
5575         buf_len = dp - varbuf;
5576
5577         while (dp < varbuf + n)
5578                 *dp++ = 0;
5579
5580         return buf_len;
5581 }
5582
5583 /*
5584         EXAMPLE: nvram_array
5585         nvram_arry format:
5586         name=value
5587         Use carriage return at the end of each assignment, and an empty string with
5588         carriage return at the end of array.
5589
5590         For example:
5591         unsigned char  nvram_array[] = {"name1=value1\n", "name2=value2\n", "\n"};
5592         Hex values start with 0x, and mac addr format: xx:xx:xx:xx:xx:xx.
5593
5594         Search "EXAMPLE: nvram_array" to see how the array is activated.
5595 */
5596
5597 void
5598 dhd_bus_set_nvram_params(struct dhd_bus * bus, const char *nvram_params)
5599 {
5600         bus->nvram_params = nvram_params;
5601 }
5602
5603 static int
5604 dhdsdio_download_nvram(struct dhd_bus *bus)
5605 {
5606         int bcmerror = -1;
5607         uint len;
5608         void * image = NULL;
5609         char * memblock = NULL;
5610         char *bufp;
5611         char *nv_path;
5612         bool nvram_file_exists;
5613
5614         nv_path = bus->nv_path;
5615
5616         nvram_file_exists = ((nv_path != NULL) && (nv_path[0] != '\0'));
5617         if (!nvram_file_exists && (bus->nvram_params == NULL))
5618                 return (0);
5619
5620         if (nvram_file_exists) {
5621                 image = dhd_os_open_image(nv_path);
5622                 if (image == NULL)
5623                         goto err;
5624         }
5625
5626         memblock = MALLOC(bus->dhd->osh, MEMBLOCK);
5627         if (memblock == NULL) {
5628                 DHD_ERROR(("%s: Failed to allocate memory %d bytes\n",
5629                            __FUNCTION__, MEMBLOCK));
5630                 goto err;
5631         }
5632
5633         /* Download variables */
5634         if (nvram_file_exists) {
5635                 len = dhd_os_get_image_block(memblock, MEMBLOCK, image);
5636         }
5637         else {
5638                 len = strlen(bus->nvram_params);
5639                 ASSERT(len <= MEMBLOCK);
5640                 if (len > MEMBLOCK)
5641                         len = MEMBLOCK;
5642                 memcpy(memblock, bus->nvram_params, len);
5643         }
5644
5645         if (len > 0 && len < MEMBLOCK) {
5646                 bufp = (char *)memblock;
5647                 bufp[len] = 0;
5648                 len = process_nvram_vars(bufp, len);
5649                 bufp += len;
5650                 *bufp++ = 0;
5651                 if (len)
5652                         bcmerror = dhdsdio_downloadvars(bus, memblock, len + 1);
5653                 if (bcmerror) {
5654                         DHD_ERROR(("%s: error downloading vars: %d\n",
5655                                    __FUNCTION__, bcmerror));
5656                 }
5657         }
5658         else {
5659                 DHD_ERROR(("%s: error reading nvram file: %d\n",
5660                            __FUNCTION__, len));
5661                 bcmerror = BCME_SDIO_ERROR;
5662         }
5663
5664 err:
5665         if (memblock)
5666                 MFREE(bus->dhd->osh, memblock, MEMBLOCK);
5667
5668         if (image)
5669                 dhd_os_close_image(image);
5670
5671         return bcmerror;
5672 }
5673
5674 static int
5675 _dhdsdio_download_firmware(struct dhd_bus *bus)
5676 {
5677         int bcmerror = -1;
5678
5679         bool embed = FALSE;     /* download embedded firmware */
5680         bool dlok = FALSE;      /* download firmware succeeded */
5681
5682         /* Out immediately if no image to download */
5683         if ((bus->fw_path == NULL) || (bus->fw_path[0] == '\0')) {
5684 #ifdef BCMEMBEDIMAGE
5685                 embed = TRUE;
5686 #else
5687                 return bcmerror;
5688 #endif
5689         }
5690
5691         /* Keep arm in reset */
5692         if (dhdsdio_download_state(bus, TRUE)) {
5693                 DHD_ERROR(("%s: error placing ARM core in reset\n", __FUNCTION__));
5694                 goto err;
5695         }
5696
5697         /* External image takes precedence if specified */
5698         if ((bus->fw_path != NULL) && (bus->fw_path[0] != '\0')) {
5699                 if (dhdsdio_download_code_file(bus, bus->fw_path)) {
5700                         DHD_ERROR(("%s: dongle image file download failed\n", __FUNCTION__));
5701 #ifdef BCMEMBEDIMAGE
5702                         embed = TRUE;
5703 #else
5704                         goto err;
5705 #endif
5706                 }
5707                 else {
5708                         embed = FALSE;
5709                         dlok = TRUE;
5710                 }
5711         }
5712 #ifdef BCMEMBEDIMAGE
5713         if (embed) {
5714                 if (dhdsdio_download_code_array(bus)) {
5715                         DHD_ERROR(("%s: dongle image array download failed\n", __FUNCTION__));
5716                         goto err;
5717                 }
5718                 else {
5719                         dlok = TRUE;
5720                 }
5721         }
5722 #endif
5723         if (!dlok) {
5724                 DHD_ERROR(("%s: dongle image download failed\n", __FUNCTION__));
5725                 goto err;
5726         }
5727
5728         /* EXAMPLE: nvram_array */
5729         /* If a valid nvram_arry is specified as above, it can be passed down to dongle */
5730         /* dhd_bus_set_nvram_params(bus, (char *)&nvram_array); */
5731
5732         /* External nvram takes precedence if specified */
5733         if (dhdsdio_download_nvram(bus)) {
5734                 DHD_ERROR(("%s: dongle nvram file download failed\n", __FUNCTION__));
5735         }
5736
5737         /* Take arm out of reset */
5738         if (dhdsdio_download_state(bus, FALSE)) {
5739                 DHD_ERROR(("%s: error getting out of ARM core reset\n", __FUNCTION__));
5740                 goto err;
5741         }
5742
5743         bcmerror = 0;
5744
5745 err:
5746         return bcmerror;
5747 }
5748
5749 static int
5750 dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes,
5751         void *pkt, bcmsdh_cmplt_fn_t complete, void *handle)
5752 {
5753         int status;
5754
5755         /* 4329: GSPI check */
5756         status = bcmsdh_recv_buf(bus->sdh, addr, fn, flags, buf, nbytes, pkt, complete, handle);
5757         return status;
5758 }
5759
5760 static int
5761 dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes,
5762         void *pkt, bcmsdh_cmplt_fn_t complete, void *handle)
5763 {
5764         return (bcmsdh_send_buf(bus->sdh, addr, fn, flags, buf, nbytes, pkt, complete, handle));
5765 }
5766
5767 uint
5768 dhd_bus_chip(struct dhd_bus *bus)
5769 {
5770         ASSERT(bus->sih != NULL);
5771         return bus->sih->chip;
5772 }
5773
5774 void *
5775 dhd_bus_pub(struct dhd_bus *bus)
5776 {
5777         return bus->dhd;
5778 }
5779
5780 void *
5781 dhd_bus_txq(struct dhd_bus *bus)
5782 {
5783         return &bus->txq;
5784 }
5785
5786 uint
5787 dhd_bus_hdrlen(struct dhd_bus *bus)
5788 {
5789         return SDPCM_HDRLEN;
5790 }
5791
5792 int
5793 dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag)
5794 {
5795         int bcmerror = 0;
5796         dhd_bus_t *bus;
5797
5798         bus = dhdp->bus;
5799
5800         if (flag == TRUE) {
5801                 if (!bus->dhd->dongle_reset) {
5802 #if !defined(IGNORE_ETH0_DOWN)
5803                         /* Force flow control as protection when stop come before ifconfig_down */
5804                         dhd_txflowcontrol(bus->dhd, 0, ON);
5805 #endif /* !defined(IGNORE_ETH0_DOWN) */
5806                         /* save country settinng if was pre-setup with priv ioctl */
5807                         dhd_os_proto_block(dhdp);
5808                         dhdcdc_query_ioctl(bus->dhd, 0, WLC_GET_COUNTRY,
5809                                 bus->dhd->country_code, sizeof(bus->dhd->country_code));
5810                         dhd_os_proto_unblock(dhdp);
5811                         /* Expect app to have torn down any connection before calling */
5812                         /* Stop the bus, disable F2 */
5813                         dhd_bus_stop(bus, FALSE);
5814
5815                         /* Clean tx/rx buffer pointers, detach from the dongle */
5816                         dhdsdio_release_dongle(bus, bus->dhd->osh);
5817
5818                         bus->dhd->dongle_reset = TRUE;
5819                         bus->dhd->up = FALSE;
5820
5821                         DHD_TRACE(("%s:  WLAN OFF DONE\n", __FUNCTION__));
5822                         /* App can now remove power from device */
5823                 } else
5824                         bcmerror = BCME_SDIO_ERROR;
5825         } else {
5826                 /* App must have restored power to device before calling */
5827
5828                 DHD_TRACE(("\n\n%s: == WLAN ON ==\n", __FUNCTION__));
5829
5830                 if (bus->dhd->dongle_reset) {
5831                         /* Turn on WLAN */
5832                         /* Reset SD client */
5833                         bcmsdh_reset(bus->sdh);
5834
5835                         /* Attempt to re-attach & download */
5836                         if (dhdsdio_probe_attach(bus, bus->dhd->osh, bus->sdh,
5837                                                 (uint32 *)SI_ENUM_BASE,
5838                                                 bus->cl_devid)) {
5839                                 /* Attempt to download binary to the dongle */
5840                                 if (dhdsdio_probe_init(bus, bus->dhd->osh, bus->sdh) &&
5841                                         dhdsdio_download_firmware(bus, bus->dhd->osh, bus->sdh)) {
5842
5843                                         /* Re-init bus, enable F2 transfer */
5844                                         dhd_bus_init((dhd_pub_t *) bus->dhd, FALSE);
5845
5846 #if defined(OOB_INTR_ONLY)
5847                                         dhd_enable_oob_intr(bus, TRUE);
5848 #endif /* defined(OOB_INTR_ONLY) */
5849
5850                                         bus->dhd->dongle_reset = FALSE;
5851                                         bus->dhd->up = TRUE;
5852
5853 #if !defined(IGNORE_ETH0_DOWN)
5854                                         /* Restore flow control  */
5855                                         dhd_txflowcontrol(bus->dhd, 0, OFF);
5856 #endif 
5857
5858                                         DHD_TRACE(("%s: WLAN ON DONE\n", __FUNCTION__));
5859                                 } else
5860                                         bcmerror = BCME_SDIO_ERROR;
5861                         } else
5862                                 bcmerror = BCME_SDIO_ERROR;
5863                 } else {
5864                         bcmerror = BCME_NOTDOWN;
5865                         DHD_ERROR(("%s: Set DEVRESET=FALSE invoked when device is on\n",
5866                                 __FUNCTION__));
5867                         bcmerror = BCME_SDIO_ERROR;
5868                 }
5869         }
5870         return bcmerror;
5871 }