GUI: Fix Tomato RAF theme for all builds. Compilation typo.
[tomato.git] / release / src-rt-6.x.4708 / shared / dbus_sdh.c
blob92ab6f3275be9b0b4f0addbdf8ab857b39900942
1 /*
2 * Dongle BUS interface
3 * Common to all SDIO interface
5 * Copyright (C) 2012, Broadcom Corporation
6 * All Rights Reserved.
7 *
8 * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation;
9 * the contents of this file may not be disclosed to third parties, copied
10 * or duplicated in any form, in whole or in part, without the prior
11 * written permission of Broadcom Corporation.
13 * $Id: dbus_sdh.c 300516 2011-12-04 17:39:44Z $
16 #include <typedefs.h>
17 #include <osl.h>
19 #include <bcmsdh.h>
20 #include <bcmdefs.h>
21 #include <bcmutils.h>
22 #include <bcmendian.h>
23 #include <bcmdevs.h>
25 #include <siutils.h>
26 #include <hndpmu.h>
27 #include <hndsoc.h>
28 #include <sbchipc.h>
29 #include <sbhnddma.h>
30 #include <bcmsrom.h>
32 #include <sdio.h>
33 #include <spid.h>
34 #include <sbsdio.h>
35 #include <sbsdpcmdev.h>
36 #include <bcmsdpcm.h>
38 #include <proto/ethernet.h>
39 #include <proto/802.1d.h>
40 #include <proto/802.11.h>
41 #include <sdiovar.h>
42 #include "dbus.h"
44 #if defined(BCM_DNGL_EMBEDIMAGE)
45 #ifdef EMBED_IMAGE_4325sd
46 #include "rtecdc_4325sd.h"
47 #endif /* EMBED_IMAGE_4325sd */
48 #ifdef EMBED_IMAGE_4319sd
49 #include "rtecdc_4319sd.h"
50 #endif /* EMBED_IMAGE_4319sd */
51 #ifdef EMBED_IMAGE_GENERIC
52 #include "rtecdc.h"
53 #endif
54 #endif /* BCM_DNGL_EMBEDIMAGE */
56 /* FIX: Some of these are brought in from dhdioctl.h. We'll move
57 * DHD-specific features/test code out of DBUS, but for now just don't
58 * include dhdioctl.h.
60 #define DHD_IOCTL_MAXLEN 8192
61 #ifdef SDTEST
62 /* For pktgen iovar */
63 typedef struct dhd_pktgen {
64 uint version; /* To allow structure change tracking */
65 uint freq; /* Max ticks between tx/rx attempts */
66 uint count; /* Test packets to send/rcv each attempt */
67 uint print; /* Print counts every <print> attempts */
68 uint total; /* Total packets (or bursts) */
69 uint minlen; /* Minimum length of packets to send */
70 uint maxlen; /* Maximum length of packets to send */
71 uint numsent; /* Count of test packets sent */
72 uint numrcvd; /* Count of test packets received */
73 uint numfail; /* Count of test send failures */
74 uint mode; /* Test mode (type of test packets) */
75 uint stop; /* Stop after this many tx failures */
76 } dhd_pktgen_t;
78 /* Version in case structure changes */
79 #define DHD_PKTGEN_VERSION 2
81 /* Type of test packets to use */
82 #define DHD_PKTGEN_ECHO 1 /* Send echo requests */
83 #define DHD_PKTGEN_SEND 2 /* Send discard packets */
84 #define DHD_PKTGEN_RXBURST 3 /* Request dongle send N packets */
85 #define DHD_PKTGEN_RECV 4 /* Continuous rx from continuous tx dongle */
86 #endif /* SDTEST */
88 #define IDLE_IMMEDIATE (-1) /* Enter idle immediately (no timeout) */
89 /* Values for idleclock iovar: other values are the sd_divisor to use when idle */
90 #define IDLE_ACTIVE 0 /* Do not request any SD clock change when idle */
91 #define IDLE_STOP (-1) /* Request SD clock be stopped (and use SD1 mode) */
93 #define PRIOMASK 7
95 #define TXRETRIES 2 /* # of retries for tx frames */
97 #define DHD_RXBOUND 50 /* Default for max rx frames in one scheduling */
99 #define DHD_TXBOUND 20 /* Default for max tx frames in one scheduling */
100 #define DHD_TXMINMAX 1 /* Max tx frames if rx still pending */
102 #define MEMBLOCK 2048 /* Block size used for downloading of dongle image */
103 #define MAX_DATA_BUF (32 * 1024) /* which should be more than
104 * and to hold biggest glom possible
107 /* Packet alignment for most efficient SDIO (can change based on platform) */
108 #ifndef SDALIGN
109 #define SDALIGN 32
110 #endif
111 #if !ISPOWEROF2(SDALIGN)
112 #error SDALIGN is not a power of 2!
113 #endif
115 /* Total length of frame header for dongle protocol */
116 #define SDPCM_HDRLEN (SDPCM_FRAMETAG_LEN + SDPCM_SWHEADER_LEN)
117 #ifdef SDTEST
118 #define SDPCM_RESERVE (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + SDALIGN)
119 #else
120 #define SDPCM_RESERVE (SDPCM_HDRLEN + SDALIGN)
121 #endif
123 /* Space for header read, limit for data packets */
124 #undef MAX_HDR_READ
125 #define MAX_HDR_READ 32
126 #define MAX_RX_DATASZ 2048
128 /* Maximum milliseconds to wait for F2 to come up */
129 #define DHD_WAIT_F2RDY 4000
131 /* Value for ChipClockCSR during initial setup */
132 #define DHD_INIT_CLKCTL1 (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ)
133 #define DHD_INIT_CLKCTL2 (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP)
135 /* Flags for SDH calls */
136 #define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED)
138 /* Packet free applicable unconditionally for sdio and sdspi. Contional if
139 * bufpool was present for gspi bus.
141 #define PKTFREE2() if ((sdio_info->bus != SPI_BUS) || sdio_info->usebufpool) \
142 dbus_sdcb_pktfree(sdio_info, pkt, FALSE);
144 typedef struct {
145 bool pending;
146 bool is_iovar;
148 union {
149 struct {
150 uint8 *buf;
151 int len;
152 } ctl;
153 struct {
154 const char *name;
155 void *params;
156 int plen;
157 void *arg;
158 int len;
159 bool set;
160 } iovar;
162 } sdctl_info_t;
164 typedef struct {
165 dbus_pub_t *pub; /* Must be first */
167 void *cbarg;
168 dbus_intf_callbacks_t *cbs;
169 dbus_intf_t *drvintf;
170 void *sdos_info;
172 /* FIX: Ported from dhd_info_t */
173 uint maxctl; /* Max size rxctl request from proto to bus */
174 ulong rx_readahead_cnt; /* Number of packets where header read-ahead was used. */
175 ulong tx_realloc; /* Number of tx packets we had to realloc for headroom */
176 uint32 tx_ctlerrs;
177 uint32 tx_ctlpkts;
178 uint32 rx_ctlerrs;
179 uint32 rx_ctlpkts;
180 bool up; /* Driver up/down (to OS) */
181 bool dongle_reset; /* TRUE = DEVRESET put dongle into reset */
182 uint8 wme_dp; /* wme discard priority */
184 sdctl_info_t rxctl_req;
185 sdctl_info_t txctl_req;
186 bool sdlocked;
188 /* FIX: Ported from dhd_bus_t */
189 bcmsdh_info_t *sdh; /* Handle for BCMSDH calls */
190 si_t *sih; /* Handle for SI calls */
191 char *vars; /* Variables (from CIS and/or other) */
192 uint varsz; /* Size of variables buffer */
194 sdpcmd_regs_t *regs; /* Registers for SDIO core */
195 uint sdpcmrev; /* SDIO core revision */
196 uint armrev; /* CPU core revision */
197 uint ramrev; /* SOCRAM core revision */
198 uint32 ramsize; /* Size of RAM in SOCRAM (bytes) */
199 uint32 orig_ramsize; /* Size of RAM in SOCRAM (bytes) */
201 uint32 bus; /* gSPI or SDIO bus */
202 uint32 hostintmask; /* Copy of Host Interrupt Mask */
203 uint32 intstatus; /* Intstatus bits (events) pending */
204 bool dpc_sched; /* Indicates DPC schedule (intrpt rcvd) */
205 bool fcstate; /* State of dongle flow-control */
207 char *firmware_path; /* module_param: path to firmware image */
208 char *nvram_path; /* module_param: path to nvram vars file */
210 uint blocksize; /* Block size of SDIO transfers */
211 uint roundup; /* Max roundup limit */
213 struct pktq txq; /* Queue length used for flow-control */
214 uint8 flowcontrol; /* per prio flow control bitmask */
215 uint8 tx_seq; /* Transmit sequence number (next) */
216 uint8 tx_max; /* Maximum transmit sequence allowed */
218 uint8 hdrbuf[MAX_HDR_READ + SDALIGN];
219 uint8 *rxhdr; /* Header of current rx frame (in hdrbuf) */
220 uint16 nextlen; /* Next Read Len from last header */
221 uint8 rx_seq; /* Receive sequence number (expected) */
222 bool rxskip; /* Skip receive (awaiting NAK ACK) */
224 void *glomd; /* Packet containing glomming descriptor */
225 void *glom; /* Packet chain for glommed superframe */
226 uint glomerr; /* Glom packet read errors */
228 uint8 *rxbuf; /* Buffer for receiving control packets */
229 uint rxblen; /* Allocated length of rxbuf */
230 uint8 *rxctl; /* Aligned pointer into rxbuf */
231 uint8 *databuf; /* Buffer for receiving big glom packet */
232 uint8 *dataptr; /* Aligned pointer into databuf */
233 uint rxlen; /* Length of valid data in buffer */
235 uint8 sdpcm_ver; /* Bus protocol reported by dongle */
237 bool intr; /* Use interrupts */
238 bool poll; /* Use polling */
239 bool ipend; /* Device interrupt is pending */
240 bool intdis; /* Interrupts disabled by isr */
241 uint intrcount; /* Count of device interrupt callbacks */
242 uint lastintrs; /* Count as of last watchdog timer */
243 uint spurious; /* Count of spurious interrupts */
244 uint pollrate; /* Ticks between device polls */
245 uint polltick; /* Tick counter */
246 uint pollcnt; /* Count of active polls */
248 uint regfails; /* Count of R_REG/W_REG failures */
250 uint clkstate; /* State of sd and backplane clock(s) */
251 bool activity; /* Activity flag for clock down */
252 int32 idletime; /* Control for activity timeout */
253 uint32 idlecount; /* Activity timeout counter */
254 int32 idleclock; /* How to set bus driver when idle */
255 uint32 sd_divisor; /* Speed control to bus driver */
256 uint32 sd_mode; /* Mode control to bus driver */
257 uint32 sd_rxchain; /* If bcmsdh api accepts PKT chains */
258 bool use_rxchain; /* If dhd should use PKT chains */
259 bool sleeping; /* Is SDIO bus sleeping? */
260 /* Field to decide if rx of control frames happen in rxbuf or lb-pool */
261 bool usebufpool;
263 #ifdef SDTEST
264 /* external loopback */
265 bool ext_loop;
266 uint8 loopid;
268 /* pktgen configuration */
269 uint pktgen_freq; /* Ticks between bursts */
270 uint pktgen_count; /* Packets to send each burst */
271 uint pktgen_print; /* Bursts between count displays */
272 uint pktgen_total; /* Stop after this many */
273 uint pktgen_minlen; /* Minimum packet data len */
274 uint pktgen_maxlen; /* Maximum packet data len */
275 uint pktgen_mode; /* Configured mode: tx, rx, or echo */
276 uint pktgen_stop; /* Number of tx failures causing stop */
278 /* active pktgen fields */
279 uint pktgen_tick; /* Tick counter for bursts */
280 uint pktgen_ptick; /* Burst counter for printing */
281 uint pktgen_sent; /* Number of test packets generated */
282 uint pktgen_rcvd; /* Number of test packets received */
283 uint pktgen_fail; /* Number of failed send attempts */
284 uint16 pktgen_len; /* Length of next packet to send */
285 #endif /* SDTEST */
287 /* Some additional counters */
288 uint tx_sderrs; /* Count of tx attempts with sd errors */
289 uint fcqueued; /* Tx packets that got queued */
290 uint rxrtx; /* Count of rtx requests (NAK to dongle) */
291 uint rx_toolong; /* Receive frames too long to receive */
292 uint rxc_errors; /* SDIO errors when reading control frames */
293 uint rx_hdrfail; /* SDIO errors on header reads */
294 uint rx_badhdr; /* Bad received headers (roosync?) */
295 uint rx_badseq; /* Mismatched rx sequence number */
296 uint fc_rcvd; /* Number of flow-control events received */
297 uint fc_xoff; /* Number which turned on flow-control */
298 uint fc_xon; /* Number which turned off flow-control */
299 uint rxglomfail; /* Failed deglom attempts */
300 uint rxglomframes; /* Number of glom frames (superframes) */
301 uint rxglompkts; /* Number of packets from glom frames */
302 uint f2rxhdrs; /* Number of header reads */
303 uint f2rxdata; /* Number of frame data reads */
304 uint f2txdata; /* Number of f2 frame writes */
305 uint f1regdata; /* Number of f1 register accesses */
307 } sdio_info_t;
309 typedef struct {
310 sdio_info_t *sdio_info;
311 dbus_irb_tx_t *txirb;
312 } pkttag_t;
314 struct exec_parms {
315 union {
316 struct {
317 sdio_info_t *sdio_info;
318 int tx_prec_map;
319 int *prec_out;
320 } pdeq;
322 struct {
323 sdio_info_t *sdio_info;
324 void *pkt;
325 int prec;
326 } penq;
330 /* clkstate */
331 #define CLK_NONE 0
332 #define CLK_SDONLY 1
333 #define CLK_PENDING 2 /* Not used yet */
334 #define CLK_AVAIL 3
336 #define DHD_NOPMU(dhd) (FALSE)
338 #ifdef BCMDBG
339 static int qcount[NUMPRIO];
340 #endif /* BCMDBG */
342 /* Tx/Rx bounds */
343 uint dhd_txbound = DHD_TXBOUND;
344 uint dhd_rxbound = DHD_RXBOUND;
345 /* static uint dhd_txminmax = DHD_TXMINMAX; */
347 /* overrride the RAM size if possible */
348 #define DONGLE_MIN_MEMSIZE (128 *1024)
349 int dhd_dongle_memsize = 0;
352 static bool dhd_alignctl = TRUE;
354 static bool sd1idle = TRUE;
356 static bool retrydata = FALSE;
357 #define RETRYCHAN(chan) (((chan) == SDPCM_EVENT_CHANNEL) || retrydata)
359 #ifdef BCMSPI
360 /* At a watermark around 8 the spid hits underflow error. */
361 static const uint watermark = 32;
362 #else
363 static const uint watermark = 8;
364 #endif /* BCMSPI */
365 static const uint firstread = 32;
367 #ifdef SDTEST
368 /* Echo packet generator (SDIO), pkts/s */
369 extern uint dhd_pktgen;
371 /* Echo packet len (0 => sawtooth, max 1800) */
372 extern uint dhd_pktgen_len;
373 #define MAX_PKTGEN_LEN 1800
374 #endif
375 extern uint dhd_watchdog_ms;
377 /* optionally set by a module_param_string() */
378 #define MOD_PARAM_PATHLEN 2048
379 char firmware_path[MOD_PARAM_PATHLEN];
380 char nvram_path[MOD_PARAM_PATHLEN];
382 /* Use interrupts */
383 extern uint dhd_intr;
385 /* Use polling */
386 extern uint dhd_poll;
388 /* Initial idletime behavior (immediate, never, or ticks) */
389 extern int dhd_idletime;
390 #define DHD_IDLETIME_TICKS 1;
392 /* SDIO Drive Strength */
393 extern uint dhd_sdiod_drive_strength;
395 /* Override to force tx queueing all the time */
396 extern uint dhd_force_tx_queueing;
398 #define HDATLEN (firstread - (SDPCM_HDRLEN))
400 /* Retry count for register access failures */
401 static uint retry_limit = 2;
403 /* Force even SD lengths (some host controllers mess up on odd bytes) */
404 #ifdef BCMSPI
405 static bool forcealign = FALSE;
406 #else
407 static bool forcealign = TRUE;
408 #endif /* !BCMSPI */
411 * Default is to bring up eth1 immediately.
413 uint delay_eth = 0;
415 #define ALIGNMENT 4
417 #define PKTALIGN(osh, p, len, align) \
418 do { \
419 uintptr datalign; \
421 datalign = (uintptr)PKTDATA((osh), (p)); \
422 datalign = ROUNDUP(datalign, (align)) - datalign; \
423 ASSERT(datalign < (align)); \
424 ASSERT(PKTLEN((osh), (p)) >= ((len) + datalign)); \
425 if (datalign) \
426 PKTPULL((osh), (p), (uint)datalign); \
427 PKTSETLEN((osh), (p), (len)); \
428 } while (0)
430 /* Limit on rounding up frames */
431 static uint max_roundup = 512;
433 /* Try doing readahead */
434 static bool dhd_readahead = TRUE;
436 /* To check if there's window offered */
437 #define DATAOK(bus) \
438 (((uint8)(sdio_info->tx_max - sdio_info->tx_seq) != 0) && \
439 (((uint8)(sdio_info->tx_max - sdio_info->tx_seq) & 0x80) == 0))
441 /* Macros to get register read/write status */
442 /* NOTE: these assume a local dbus_sdio_bus_t *bus! */
444 #define R_SDREG(regvar, regaddr, retryvar) \
445 do { \
446 retryvar = 0; \
447 do { \
448 regvar = R_REG(sdio_info->pub->osh, regaddr); \
449 } while (bcmsdh_regfail(sdio_info->sdh) && (++retryvar <= retry_limit)); \
450 if (retryvar) { \
451 sdio_info->regfails += (retryvar-1); \
452 if (retryvar > retry_limit) { \
453 DBUSERR(("%s: FAILED" #regvar "READ, LINE %d\n", \
454 __FUNCTION__, __LINE__)); \
455 regvar = 0; \
458 } while (0)
460 #define W_SDREG(regval, regaddr, retryvar) \
461 do { \
462 retryvar = 0; \
463 do { \
464 W_REG(sdio_info->pub->osh, regaddr, regval); \
465 } while (bcmsdh_regfail(sdio_info->sdh) && (++retryvar <= retry_limit)); \
466 if (retryvar) { \
467 sdio_info->regfails += (retryvar-1); \
468 if (retryvar > retry_limit) \
469 DBUSERR(("%s: FAILED REGISTER WRITE, LINE %d\n", \
470 __FUNCTION__, __LINE__)); \
472 } while (0)
474 #ifdef BCMSPI
476 #define SD_BUSTYPE SPI_BUS
478 /* check packet-available-interrupt in piggybacked dstatus */
479 #define PKT_AVAILABLE() (bcmsdh_get_dstatus(sdio_info->sdh) & STATUS_F2_PKT_AVAILABLE)
481 #define HOSTINTMASK (I_HMB_FC_CHANGE | I_HMB_HOST_INT)
483 #define GSPI_PR55150_BAILOUT \
484 do { \
485 uint32 dstatussw = bcmsdh_get_dstatus((void *)sdio_info->sdh); \
486 uint32 dstatushw = bcmsdh_cfg_read_word(sdio_info->sdh, \
487 SDIO_FUNC_0, SPID_STATUS_REG, NULL); \
488 uint32 intstatuserr = 0; \
489 uint retries = 0; \
491 R_SDREG(intstatuserr, &sdio_info->regs->intstatus, retries); \
492 printf("dstatussw = 0x%x, dstatushw = 0x%x, intstatus = 0x%x\n", \
493 dstatussw, dstatushw, intstatuserr); \
495 sdio_info->nextlen = 0; \
496 *finished = TRUE; \
497 } while (0)
499 #else /* BCMSDIO */
501 #define SD_BUSTYPE SDIO_BUS
503 #define PKT_AVAILABLE() (intstatus & I_HMB_FRAME_IND)
505 #define HOSTINTMASK (I_TOHOSTMAIL | I_CHIPACTIVE)
507 #define GSPI_PR55150_BAILOUT
509 #endif /* BCMSPI */
511 #define BUS_WAKE(sdio_info) \
512 do { \
513 if ((sdio_info)->sleeping) \
514 dbus_sdio_bussleep((sdio_info), FALSE); \
515 } while (0);
517 /* Debug */
518 #define DBUSINTR DBUSTRACE
519 #define DBUSTIMER DBUSTRACE
520 #define DBUSGLOM DBUSTRACE
521 #define DBUSDATA DBUSTRACE
522 #define DBUSCTL DBUSTRACE
523 #define DBUSGLOM_ON() 0
525 /* IOVar table */
526 enum {
527 IOV_INTR = 1,
528 IOV_POLLRATE,
529 IOV_SDREG,
530 IOV_SBREG,
531 IOV_SDCIS,
532 IOV_MEMBYTES,
533 IOV_MEMSIZE,
534 IOV_SET_DOWNLOAD_STATE,
535 IOV_FORCEEVEN,
536 IOV_SDIOD_DRIVE,
537 IOV_READAHEAD,
538 IOV_SDRXCHAIN,
539 IOV_ALIGNCTL,
540 IOV_SDALIGN,
541 IOV_DEVRESET,
542 #ifdef SDTEST
543 IOV_PKTGEN,
544 IOV_EXTLOOP,
545 #endif /* SDTEST */
546 IOV_SPROM,
547 IOV_TXBOUND,
548 IOV_RXBOUND,
549 IOV_IDLETIME,
550 IOV_IDLECLOCK,
551 IOV_SD1IDLE,
552 IOV_SLEEP,
553 IOV_VARS
556 static const bcm_iovar_t dbus_sdio_iovars[] = {
557 {"intr", IOV_INTR, 0, IOVT_BOOL, 0 },
558 {"sleep", IOV_SLEEP, 0, IOVT_BOOL, 0 },
559 {"pollrate", IOV_POLLRATE, 0, IOVT_UINT32, 0 },
560 {"idletime", IOV_IDLETIME, 0, IOVT_INT32, 0 },
561 {"idleclock", IOV_IDLECLOCK, 0, IOVT_INT32, 0 },
562 {"sd1idle", IOV_SD1IDLE, 0, IOVT_BOOL, 0 },
563 {"membytes", IOV_MEMBYTES, 0, IOVT_BUFFER, 2 * sizeof(int) },
564 {"memsize", IOV_MEMSIZE, 0, IOVT_UINT32, 0 },
565 {"dwnldstate", IOV_SET_DOWNLOAD_STATE, 0, IOVT_BOOL, 0 },
566 {"vars", IOV_VARS, 0, IOVT_BUFFER, 0 },
567 {"sdiod_drive", IOV_SDIOD_DRIVE, 0, IOVT_UINT32, 0 },
568 {"readahead", IOV_READAHEAD, 0, IOVT_BOOL, 0 },
569 {"sdrxchain", IOV_SDRXCHAIN, 0, IOVT_BOOL, 0 },
570 {"alignctl", IOV_ALIGNCTL, 0, IOVT_BOOL, 0 },
571 {"sdalign", IOV_SDALIGN, 0, IOVT_BOOL, 0 },
572 {"devreset", IOV_DEVRESET, 0, IOVT_BOOL, 0 },
573 #ifdef BCMDBG
574 {"sdreg", IOV_SDREG, 0, IOVT_BUFFER, sizeof(sdreg_t) },
575 {"sbreg", IOV_SBREG, 0, IOVT_BUFFER, sizeof(sdreg_t) },
576 {"sd_cis", IOV_SDCIS, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN },
577 {"forcealign", IOV_FORCEEVEN, 0, IOVT_BOOL, 0 },
578 {"txbound", IOV_TXBOUND, 0, IOVT_UINT32, 0 },
579 {"rxbound", IOV_RXBOUND, 0, IOVT_UINT32, 0 },
580 #endif /* BCMDBG */
581 #if defined(BCMDBG) || defined(DHD_SPROM)
582 {"sprom", IOV_SPROM, 0, IOVT_BUFFER, 2 * sizeof(int) },
583 #endif
584 #ifdef SDTEST
585 {"extloop", IOV_EXTLOOP, 0, IOVT_BOOL, 0 },
586 {"pktgen", IOV_PKTGEN, 0, IOVT_BUFFER, sizeof(dhd_pktgen_t) },
587 #endif /* SDTEST */
589 {NULL, 0, 0, 0, 0 }
592 typedef struct {
593 chipcregs_t *ccregs;
594 sdpcmd_regs_t *sdregs;
595 uint32 socram_size;
596 } chipinfo_t;
598 /* This stores SD Host info during probe callback
599 * since attach() is not called yet at this point
601 typedef struct {
602 uint16 venid;
603 uint16 devid;
604 uint16 bus_no;
605 uint16 slot;
606 uint16 func;
607 uint bustype;
608 void *regsva;
609 osl_t *osh; /* Comes from SD Host */
610 bool free_probe_osh;
612 bcmsdh_info_t *sdh; /* Handle for BCMSDH calls */
613 si_t *sih; /* Handle for SI calls */
615 uint32 ramsize; /* Size of RAM in SOCRAM (bytes) */
616 uint32 orig_ramsize; /* Size of RAM in SOCRAM (bytes) */
617 char *vars; /* Variables (from CIS and/or other) */
618 uint varsz; /* Size of variables buffer */
619 bool alp_only; /* Don't use HT clock (ALP only) */
621 char *firmware_file;
622 char *nvram_file;
623 bool devready;
625 uint32 dl_addr;
626 const chipinfo_t *chinfo;
627 } probe_sdh_info_t;
629 static probe_sdh_info_t g_probe_info;
632 * FIX: Basic information needed to prep dongle for download.
633 * The goal is to simplify probe setup before a valid
634 * image has been downloaded. Also, can we avoid si_attach() during
635 * probe setup since it brings in a lot of unnecessary dependencies?
638 /* 4325 and 4315 have the same address map */
639 static const chipinfo_t chipinfo_4325_15 = {
640 (chipcregs_t *) 0x18000000,
641 (sdpcmd_regs_t *) 0x18002000,
642 (384 * 1024)
645 static const chipinfo_t chipinfo_4329 = {
646 (chipcregs_t *) 0x18000000,
647 (sdpcmd_regs_t *) 0x18011000,
648 (288 * 1024)
651 static const chipinfo_t chipinfo_4336 = {
652 (chipcregs_t *) 0x18000000,
653 (sdpcmd_regs_t *) 0x18002000,
654 (240 * 1024)
657 static const chipinfo_t chipinfo_4330 = {
658 (chipcregs_t *) 0x18000000,
659 (sdpcmd_regs_t *) 0x18002000,
660 (240 * 1024)
663 static const chipinfo_t chipinfo_43237 = {
664 (chipcregs_t *) 0x18000000,
665 (sdpcmd_regs_t *) 0x18002000,
666 (320 * 1024)
669 static const chipinfo_t chipinfo_4314 = {
670 (chipcregs_t *) 0x18000000,
671 (sdpcmd_regs_t *) 0x18003000,
672 (256 * 1024)
675 static const chipinfo_t chipinfo_4334 = {
676 (chipcregs_t *) 0x18000000,
677 (sdpcmd_regs_t *) 0x18002000,
678 (512 * 1024)
682 * SDH registration callbacks
684 static void * dbus_sdh_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot,
685 uint16 func, uint bustype, void *regsva, osl_t * osh,
686 void *sdh);
687 static void dbus_sdh_disconnect(void *ptr);
688 static void dbus_sdh_isr(void *handle);
691 * Local function prototypes
693 static void *dbus_sdio_probe_cb(void *handle, const char *desc, uint32 bustype, uint32 hdrlen);
694 static void dbus_sdio_disconnect_cb(void *handle);
696 #ifdef SDTEST
697 static void dbus_sdio_sdtest_set(sdio_info_t *sdio_info, bool start);
698 static void dbus_sdio_testrcv(sdio_info_t *sdio_info, void *pkt, uint seq);
699 #endif
700 static bool dbus_sdio_attach_init(sdio_info_t *sdio_info, void *sdh,
701 char *firmware_path, char * nvram_path);
702 static void dbus_sdio_release(sdio_info_t *sdio_info, osl_t *osh);
703 static void dbus_sdio_release_dongle(sdio_info_t *sdio_info, osl_t *osh);
704 static int dbus_sdio_rxctl(sdio_info_t *sdio_info, uchar *msg, uint msglen);
705 static uint dbus_sdio_sendfromq(sdio_info_t *sdio_info, uint maxframes);
706 static int dbus_sdio_txctl(sdio_info_t *sdio_info, uchar *msg, uint msglen);
707 static void dbus_sdio_txq_flush(sdio_info_t *sdio_info);
710 * NOTE: These functions can also be called before attach() occurs
711 * so do not access sdio_info from them. This is to support DBUS
712 * async probe callback to upper layer such as DHD/BMAC/etc. Another
713 * alternative was to modify SDH to do async probe callback only
714 * when a valid image is downloaded to the dongle.
716 static bool dbus_sdio_probe_init(probe_sdh_info_t *pinfo);
717 static void dbus_sdio_probe_deinit(probe_sdh_info_t *pinfo);
718 static int dbus_sdio_download_state(probe_sdh_info_t *pinfo, bool enter);
719 static int dbus_sdio_membytes(probe_sdh_info_t *pinfo, bool write,
720 uint32 address, uint8 *data, uint size);
721 static int dbus_sdio_write_vars(probe_sdh_info_t *pinfo);
722 static int dbus_sdio_downloadvars(probe_sdh_info_t *pinfo, void *arg, int len);
723 #ifdef BCM_DNGL_EMBEDIMAGE
724 static int dhd_bus_download_nvram_file(probe_sdh_info_t *pinfo, char * nvram_path);
725 static int dhd_bus_download_image_array(probe_sdh_info_t *pinfo,
726 char * nvram_path, uint8 *fw, int len);
727 #endif
730 * Wrappers to interface functions in dbus_sdio_os.c
732 static void dbus_sdos_lock(sdio_info_t *sdio_info);
733 static void dbus_sdos_unlock(sdio_info_t *sdio_info);
734 static void * dbus_sdos_exec_txlock(sdio_info_t *sdio_info, exec_cb_t cb, struct exec_parms *args);
735 static int dbus_sdos_sched_dpc(sdio_info_t *sdio_info);
736 #ifndef BCM_DNGL_EMBEDIMAGE
737 static int dbus_sdos_sched_probe_cb(void);
738 #endif
741 * Wrappers to callback functions in dbus.c
743 static void *dbus_sdcb_pktget(sdio_info_t *sdio_info, uint len, bool send);
744 static void dbus_sdcb_pktfree(sdio_info_t *sdio_info, void *p, bool send);
745 static dbus_irb_t *dbus_sdcb_getirb(sdio_info_t *sdio_info, bool send);
748 * Callbacks common to all SDIO
750 static void dbus_sdio_disconnect_cb(void *handle);
751 static void dbus_sdio_send_irb_timeout(void *handle, dbus_irb_tx_t *txirb);
752 static void dbus_sdio_send_irb_complete(void *handle, dbus_irb_tx_t *txirb, int status);
753 static void dbus_sdio_recv_irb_complete(void *handle, dbus_irb_rx_t *rxirb, int status);
754 static void dbus_sdio_errhandler(void *handle, int err);
755 static void dbus_sdio_ctl_complete(void *handle, int type, int status);
756 static void dbus_sdio_state_change(void *handle, int state);
757 static bool dbus_sdio_isr(void *handle, bool *wantdpc);
758 static bool dbus_sdio_dpc(void *handle, bool bounded);
759 static void dbus_sdio_watchdog(void *handle);
761 static dbus_intf_callbacks_t dbus_sdio_intf_cbs = {
762 dbus_sdio_send_irb_timeout,
763 dbus_sdio_send_irb_complete,
764 dbus_sdio_recv_irb_complete,
765 dbus_sdio_errhandler,
766 dbus_sdio_ctl_complete,
767 dbus_sdio_state_change,
768 dbus_sdio_isr,
769 dbus_sdio_dpc,
770 dbus_sdio_watchdog
774 * Need global for probe() and disconnect() since
775 * attach() is not called at probe and detach()
776 * can be called inside disconnect()
778 static probe_cb_t probe_cb = NULL;
779 static disconnect_cb_t disconnect_cb = NULL;
780 static void *probe_arg = NULL;
781 static void *disc_arg = NULL;
784 * dbus_intf_t common to all SDIO
785 * These functions override dbus_sdio_os.c.
787 static void *dbus_sdif_attach(dbus_pub_t *pub, void *cbarg, dbus_intf_callbacks_t *cbs);
788 static void dbus_sdif_detach(dbus_pub_t *pub, void *info);
789 static int dbus_sdif_send_irb(void *bus, dbus_irb_tx_t *txirb);
790 static int dbus_sdif_send_ctl(void *bus, uint8 *buf, int len);
791 static int dbus_sdif_recv_ctl(void *bus, uint8 *buf, int len);
792 static int dbus_sdif_up(void *bus);
793 static int dbus_sdif_iovar_op(void *bus, const char *name,
794 void *params, int plen, void *arg, int len, bool set);
795 static bool dbus_sdif_device_exists(void *bus);
796 static bool dbus_sdif_dlneeded(void *bus);
797 static int dbus_sdif_dlstart(void *bus, uint8 *fw, int len);
798 static int dbus_sdif_dlrun(void *bus);
799 static int dbus_sdif_stop(void *bus);
800 static int dbus_sdif_down(void *bus);
801 static int dbus_sdif_get_attrib(void *bus, dbus_attrib_t *attrib);
803 static dbus_intf_t dbus_sdio_intf;
804 static dbus_intf_t *g_dbusintf = NULL;
806 /* Register/Unregister functions are called by the main DHD entry
807 * point (e.g. module insertion) to link with the bus driver, in
808 * order to look for or await the device.
811 bcmsdh_driver_t sdh_driver = {
812 dbus_sdh_probe,
813 dbus_sdh_disconnect
816 /* Functions shared between dbus_sdio.c/dbus_sdio_os.c */
817 extern int dbus_sdio_txq_sched(void *bus);
818 extern int dbus_sdio_txq_stop(void *bus);
819 extern int dbus_sdio_txq_process(void *bus);
820 extern int probe_dlstart(void);
821 extern int probe_dlstop(void);
822 extern int probe_dlwrite(uint8 *buf, int count, bool isvars);
823 extern int probe_iovar(const char *name, void *params, int plen, void *arg, int len, bool set,
824 void **val, int *val_len);
828 static int
829 dbus_sdio_alpclk(bcmsdh_info_t *sdh)
831 int err;
832 #ifndef BCMSPI
833 uint8 clkctl = 0;
834 #endif /* !BCMSPI */
837 * Request ALP clock; ALP is required before starting a download
839 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, SBSDIO_ALP_AVAIL_REQ, &err);
840 if (err) {
841 DBUSERR(("%s: HT Avail request error: %d\n", __FUNCTION__, err));
842 return DBUS_ERR;
845 #ifndef BCMSPI
846 /* Check current status */
847 clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
848 if (err) {
849 DBUSERR(("%s: HT Avail read error: %d\n", __FUNCTION__, err));
850 return DBUS_ERR;
853 if (!SBSDIO_CLKAV(clkctl, TRUE)) {
854 SPINWAIT(((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
855 SBSDIO_FUNC1_CHIPCLKCSR, &err)),
856 !SBSDIO_CLKAV(clkctl, TRUE)), PMU_MAX_TRANSITION_DLY);
858 #endif
860 return DBUS_OK;
863 /* Turn backplane clock on or off */
864 static int
865 dbus_sdio_htclk(sdio_info_t *sdio_info, bool on, bool pendok)
867 int err;
868 uint8 clkctl, clkreq, devctl;
869 bcmsdh_info_t *sdh;
871 DBUSTRACE(("%s: Enter\n", __FUNCTION__));
873 clkctl = 0;
874 sdh = sdio_info->sdh;
877 if (on) {
878 /* Request HT Avail */
879 clkreq = g_probe_info.alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ;
882 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
883 if (err) {
884 DBUSERR(("%s: HT Avail request error: %d\n", __FUNCTION__, err));
885 return BCME_ERROR;
888 if (pendok &&
889 ((sdio_info->sih->buscoretype == PCMCIA_CORE_ID) &&
890 (sdio_info->sih->buscorerev == 9))) {
891 uint32 dummy, retries;
892 R_SDREG(dummy, &sdio_info->regs->clockctlstatus, retries);
895 /* Check current status */
896 clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
897 if (err) {
898 DBUSERR(("%s: HT Avail read error: %d\n", __FUNCTION__, err));
899 return BCME_ERROR;
902 /* Go to pending and await interrupt if appropriate */
903 if (!SBSDIO_CLKAV(clkctl, g_probe_info.alp_only) && pendok) {
904 DBUSINFO(("CLKCTL: set PENDING\n"));
905 sdio_info->clkstate = CLK_PENDING;
907 /* Allow only clock-available interrupt */
908 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
909 if (err) {
910 DBUSERR(("%s: Devctl access error setting CA: %d\n",
911 __FUNCTION__, err));
912 return BCME_ERROR;
915 devctl |= SBSDIO_DEVCTL_CA_INT_ONLY;
916 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
917 return BCME_OK;
918 } else if (sdio_info->clkstate == CLK_PENDING) {
919 /* Cancel CA-only interrupt filter */
920 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
921 devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
922 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
925 /* Otherwise, wait here (polling) for HT Avail */
926 if (!SBSDIO_CLKAV(clkctl, g_probe_info.alp_only)) {
927 SPINWAIT(((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
928 SBSDIO_FUNC1_CHIPCLKCSR, &err)),
929 !SBSDIO_CLKAV(clkctl, g_probe_info.alp_only)),
930 PMU_MAX_TRANSITION_DLY);
932 if (err) {
933 DBUSERR(("%s: HT Avail request error: %d\n", __FUNCTION__, err));
934 return BCME_ERROR;
936 if (!SBSDIO_CLKAV(clkctl, g_probe_info.alp_only)) {
937 DBUSERR(("%s: HT Avail timeout (%d): clkctl 0x%02x\n",
938 __FUNCTION__, PMU_MAX_TRANSITION_DLY, clkctl));
939 return BCME_ERROR;
942 /* Mark clock available */
943 sdio_info->clkstate = CLK_AVAIL;
944 DBUSINFO(("CLKCTL: turned ON\n"));
946 #if defined(BCMDBG)
947 if (g_probe_info.alp_only == TRUE) {
948 if (!SBSDIO_ALPONLY(clkctl)) {
949 DBUSERR(("%s: HT Clock, when ALP Only\n", __FUNCTION__));
951 } else {
952 if (SBSDIO_ALPONLY(clkctl)) {
953 DBUSERR(("%s: HT Clock should be on.\n", __FUNCTION__));
956 #endif /* defined (BCMDBG) */
958 sdio_info->activity = TRUE;
959 } else {
960 clkreq = 0;
962 if (sdio_info->clkstate == CLK_PENDING) {
963 /* Cancel CA-only interrupt filter */
964 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
965 devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
966 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
969 sdio_info->clkstate = CLK_SDONLY;
970 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
971 DBUSINFO(("CLKCTL: turned OFF\n"));
972 if (err) {
973 DBUSERR(("%s: Failed access turning clock off: %d\n",
974 __FUNCTION__, err));
975 return BCME_ERROR;
978 return BCME_OK;
981 /* Change idle/active SD state */
982 static int
983 dbus_sdio_sdclk(sdio_info_t *sdio_info, bool on)
985 int err;
986 int32 iovalue;
988 DBUSTRACE(("%s: Enter\n", __FUNCTION__));
990 if (on) {
991 if (sdio_info->idleclock == IDLE_STOP) {
992 /* Turn on clock and restore mode */
993 iovalue = 1;
994 err = bcmsdh_iovar_op(sdio_info->sdh, "sd_clock", NULL, 0,
995 &iovalue, sizeof(iovalue), TRUE);
996 if (err) {
997 DBUSERR(("%s: error enabling sd_clock: %d\n",
998 __FUNCTION__, err));
999 return BCME_ERROR;
1002 iovalue = sdio_info->sd_mode;
1003 err = bcmsdh_iovar_op(sdio_info->sdh, "sd_mode", NULL, 0,
1004 &iovalue, sizeof(iovalue), TRUE);
1005 if (err) {
1006 DBUSERR(("%s: error changing sd_mode: %d\n",
1007 __FUNCTION__, err));
1008 return BCME_ERROR;
1010 } else if (sdio_info->idleclock != IDLE_ACTIVE) {
1011 /* Restore clock speed */
1012 iovalue = sdio_info->sd_divisor;
1013 err = bcmsdh_iovar_op(sdio_info->sdh, "sd_divisor", NULL, 0,
1014 &iovalue, sizeof(iovalue), TRUE);
1015 if (err) {
1016 DBUSERR(("%s: error restoring sd_divisor: %d\n",
1017 __FUNCTION__, err));
1018 return BCME_ERROR;
1021 sdio_info->clkstate = CLK_SDONLY;
1022 } else {
1023 /* Stop or slow the SD clock itself */
1024 if ((sdio_info->sd_divisor == -1) || (sdio_info->sd_mode == -1)) {
1025 DBUSTRACE(("%s: can't idle clock, divisor %d mode %d\n",
1026 __FUNCTION__, sdio_info->sd_divisor, sdio_info->sd_mode));
1027 return BCME_ERROR;
1029 if (sdio_info->idleclock == IDLE_STOP) {
1030 if (sd1idle) {
1031 /* Change to SD1 mode and turn off clock */
1032 iovalue = 1;
1033 err = bcmsdh_iovar_op(sdio_info->sdh, "sd_mode", NULL, 0,
1034 &iovalue, sizeof(iovalue), TRUE);
1035 if (err) {
1036 DBUSERR(("%s: error changing sd_clock: %d\n",
1037 __FUNCTION__, err));
1038 return BCME_ERROR;
1042 iovalue = 0;
1043 err = bcmsdh_iovar_op(sdio_info->sdh, "sd_clock", NULL, 0,
1044 &iovalue, sizeof(iovalue), TRUE);
1045 if (err) {
1046 DBUSERR(("%s: error disabling sd_clock: %d\n",
1047 __FUNCTION__, err));
1048 return BCME_ERROR;
1050 } else if (sdio_info->idleclock != IDLE_ACTIVE) {
1051 /* Set divisor to idle value */
1052 iovalue = sdio_info->idleclock;
1053 err = bcmsdh_iovar_op(sdio_info->sdh, "sd_divisor", NULL, 0,
1054 &iovalue, sizeof(iovalue), TRUE);
1055 if (err) {
1056 DBUSERR(("%s: error changing sd_divisor: %d\n",
1057 __FUNCTION__, err));
1058 return BCME_ERROR;
1061 sdio_info->clkstate = CLK_NONE;
1064 return BCME_OK;
1067 /* Transition SD and backplane clock readiness */
1068 static int
1069 dbus_sdio_clkctl(sdio_info_t *sdio_info, uint target, bool pendok)
1071 DBUSTRACE(("%s: Enter\n", __FUNCTION__));
1073 /* Early exit if we're already there */
1074 if (sdio_info->clkstate == target) {
1075 if (target == CLK_AVAIL)
1076 sdio_info->activity = TRUE;
1077 return BCME_OK;
1080 switch (target) {
1081 case CLK_AVAIL:
1082 /* Make sure SD clock is available */
1083 if (sdio_info->clkstate == CLK_NONE)
1084 dbus_sdio_sdclk(sdio_info, TRUE);
1085 /* Now request HT Avail on the backplane */
1086 dbus_sdio_htclk(sdio_info, TRUE, pendok);
1087 sdio_info->activity = TRUE;
1088 break;
1090 case CLK_SDONLY:
1091 /* Remove HT request, or bring up SD clock */
1092 if (sdio_info->clkstate == CLK_NONE)
1093 dbus_sdio_sdclk(sdio_info, TRUE);
1094 else if (sdio_info->clkstate == CLK_AVAIL)
1095 dbus_sdio_htclk(sdio_info, FALSE, FALSE);
1096 else
1097 DBUSERR(("dbus_sdio_clkctl: request for %d -> %d\n",
1098 sdio_info->clkstate, target));
1099 break;
1101 case CLK_NONE:
1102 /* Make sure to remove HT request */
1103 if (sdio_info->clkstate == CLK_AVAIL)
1104 dbus_sdio_htclk(sdio_info, FALSE, FALSE);
1105 /* Now remove the SD clock */
1106 dbus_sdio_sdclk(sdio_info, FALSE);
1107 break;
1109 DBUSINFO(("dbus_sdio_clkctl: %d -> %d\n", oldstate, sdio_info->clkstate));
1111 return BCME_OK;
1114 static int
1115 dbus_sdio_bussleep(sdio_info_t *sdio_info, bool sleep)
1117 bcmsdh_info_t *sdh = sdio_info->sdh;
1118 sdpcmd_regs_t *regs = sdio_info->regs;
1119 uint retries = 0;
1121 DBUSINFO(("dbus_sdio_bussleep: request %s (currently %s)\n",
1122 (sleep ? "SLEEP" : "WAKE"),
1123 (sdio_info->sleeping ? "SLEEP" : "WAKE")));
1125 /* Done if we're already in the requested state */
1126 if (sleep == sdio_info->sleeping)
1127 return BCME_OK;
1129 /* Going to sleep: set the alarm and turn off the lights... */
1130 if (sleep) {
1131 /* Don't sleep if something is pending */
1132 if (sdio_info->dpc_sched || sdio_info->rxskip || pktq_len(&sdio_info->txq))
1133 return BCME_BUSY;
1136 /* Disable SDIO interrupts (no longer interested) */
1137 bcmsdh_intr_disable(sdio_info->sdh);
1139 /* Make sure the controller has the bus up */
1140 dbus_sdio_clkctl(sdio_info, CLK_AVAIL, FALSE);
1142 /* Tell device to start using OOB wakeup */
1143 W_SDREG(SMB_USE_OOB, &regs->tosbmailbox, retries);
1144 if (retries > retry_limit)
1145 DBUSERR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
1147 /* Turn off our contribution to the HT clock request */
1148 dbus_sdio_clkctl(sdio_info, CLK_SDONLY, FALSE);
1150 /* Isolate the bus */
1151 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL,
1152 SBSDIO_DEVCTL_PADS_ISO, NULL);
1154 /* Change state */
1155 sdio_info->sleeping = TRUE;
1157 } else {
1158 /* Waking up: bus power up is ok, set local state */
1160 /* Force pad isolation off if possible (in case power never toggled) */
1161 if ((sdio_info->sih->buscoretype == PCMCIA_CORE_ID) &&
1162 (sdio_info->sih->buscorerev >= 10))
1163 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, 0, NULL);
1166 /* Make sure we have SD bus access */
1167 if (sdio_info->clkstate == CLK_NONE)
1168 dbus_sdio_clkctl(sdio_info, CLK_SDONLY, FALSE);
1170 /* Send misc interrupt to indicate OOB not needed */
1171 W_SDREG(0, &regs->tosbmailboxdata, retries);
1172 if (retries <= retry_limit)
1173 W_SDREG(SMB_DEV_INT, &regs->tosbmailbox, retries);
1175 if (retries > retry_limit)
1176 DBUSERR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n"));
1178 /* Change state */
1179 sdio_info->sleeping = FALSE;
1181 /* Enable interrupts again */
1182 if (sdio_info->intr && (sdio_info->pub->busstate == DBUS_STATE_UP)) {
1183 sdio_info->intdis = FALSE;
1184 bcmsdh_intr_enable(sdio_info->sdh);
1188 return BCME_OK;
1191 /* Writes a HW/SW header into the packet and sends it. */
1192 /* Assumes: (a) header space already there, (b) caller holds lock */
1193 static int
1194 dbus_sdio_txpkt(sdio_info_t *sdio_info, void *pkt, uint chan)
1196 int ret;
1197 osl_t *osh;
1198 uint8 *frame;
1199 uint16 len, pad;
1200 uint32 swheader;
1201 uint retries = 0;
1202 bcmsdh_info_t *sdh;
1203 void *new;
1204 pkttag_t *ptag;
1205 int i;
1207 DBUSTRACE(("%s: Enter\n", __FUNCTION__));
1209 sdh = sdio_info->sdh;
1210 osh = sdio_info->pub->osh;
1212 if (sdio_info->dongle_reset) {
1213 ret = BCME_NOTREADY;
1214 goto done;
1217 frame = (uint8*)PKTDATA(osh, pkt);
1219 /* Add alignment padding, allocate new packet if needed */
1220 if ((pad = ((uintptr)frame % SDALIGN))) {
1221 if (PKTHEADROOM(osh, pkt) < pad) {
1222 DBUSINFO(("%s: insufficient headroom %d for %d pad\n",
1223 __FUNCTION__, (int)PKTHEADROOM(osh, pkt), pad));
1224 sdio_info->tx_realloc++;
1225 new = dbus_sdcb_pktget(sdio_info, (PKTLEN(osh, pkt) + SDALIGN), TRUE);
1226 if (!new) {
1227 DBUSERR(("%s: couldn't allocate new %d-byte packet\n",
1228 __FUNCTION__, PKTLEN(osh, pkt) + SDALIGN));
1229 ret = BCME_NOMEM;
1230 goto done;
1233 PKTALIGN(osh, new, PKTLEN(osh, pkt), SDALIGN);
1234 bcopy(PKTDATA(osh, pkt), PKTDATA(osh, new), PKTLEN(osh, pkt));
1236 *((pkttag_t *)PKTTAG(new)) = *((pkttag_t *)PKTTAG(pkt));
1237 ((pkttag_t *)PKTTAG(new))->txirb->pkt = new;
1238 ((pkttag_t *)PKTTAG(new))->txirb->info = new;
1240 dbus_sdcb_pktfree(sdio_info, pkt, TRUE);
1241 pkt = new;
1242 frame = (uint8*)PKTDATA(osh, pkt);
1243 ASSERT(((uintptr)frame % SDALIGN) == 0);
1244 pad = 0;
1245 } else {
1246 PKTPUSH(osh, pkt, pad);
1247 frame = (uint8*)PKTDATA(osh, pkt);
1248 bzero(frame, pad + SDPCM_HDRLEN);
1251 ASSERT(pad < SDALIGN);
1253 /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
1254 len = (uint16)PKTLEN(osh, pkt);
1255 *(uint16*)frame = htol16(len);
1256 *(((uint16*)frame) + 1) = htol16(~len);
1258 /* Software tag: channel, sequence number, data offset */
1259 swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) | sdio_info->tx_seq |
1260 (((pad + SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
1261 htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN);
1262 htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
1263 sdio_info->tx_seq = (sdio_info->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
1265 /* Raise len to next SDIO block to eliminate tail command */
1266 if (sdio_info->roundup && sdio_info->blocksize && (len > sdio_info->blocksize)) {
1267 pad = sdio_info->blocksize - (len % sdio_info->blocksize);
1268 if ((pad <= sdio_info->roundup) && (pad < sdio_info->blocksize))
1269 #ifdef NOTUSED
1270 if (pad <= PKTTAILROOM(osh, pkt))
1271 #endif
1272 len += pad;
1275 /* Some controllers have trouble with odd bytes -- round to even */
1276 if (forcealign && (len & (ALIGNMENT - 1))) {
1277 #ifdef NOTUSED
1278 if (PKTTAILROOM(osh, pkt))
1279 #endif
1280 len = ROUNDUP(len, ALIGNMENT);
1281 #ifdef NOTUSED
1282 else
1283 DBUSERR(("%s: sending unrounded %d-byte packet\n", __FUNCTION__, len));
1284 #endif
1287 do {
1288 ret = bcmsdh_send_buf(sdh, SI_ENUM_BASE, SDIO_FUNC_2, F2SYNC,
1289 frame, len, pkt, NULL, NULL);
1290 sdio_info->f2txdata++;
1291 ASSERT(ret != BCME_PENDING);
1293 if (ret < 0) {
1294 /* On failure, abort the command and terminate the frame */
1295 DBUSINFO(("%s: sdio error %d, abort command and terminate frame.\n",
1296 __FUNCTION__, ret));
1297 sdio_info->tx_sderrs++;
1299 ret = bcmsdh_abort(sdh, SDIO_FUNC_2);
1300 if (ret == BCME_NODEVICE) {
1301 dbus_sdio_state_change(sdio_info, DBUS_STATE_DISCONNECT);
1302 break;
1304 #ifdef BCMSPI
1305 DBUSERR(("%s: gSPI transmit error. Check Overflow or F2-fifo-not-ready"
1306 " counters.\n", __FUNCTION__));
1307 #endif /* BCMSPI */
1308 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
1309 SFC_WF_TERM, NULL);
1310 sdio_info->f1regdata++;
1312 for (i = 0; i < 3; i++) {
1313 uint8 hi, lo;
1314 hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
1315 SBSDIO_FUNC1_WFRAMEBCHI, NULL);
1316 lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
1317 SBSDIO_FUNC1_WFRAMEBCLO, NULL);
1318 sdio_info->f1regdata += 2;
1319 if ((hi == 0) && (lo == 0))
1320 break;
1323 } while ((ret < 0) && retrydata && retries++ < TXRETRIES);
1325 done:
1326 ASSERT(OSL_PKTTAG_SZ >= sizeof(pkttag_t));
1327 ptag = (pkttag_t *) PKTTAG(pkt);
1328 ASSERT(ptag);
1329 dbus_sdio_send_irb_complete(sdio_info, ptag->txirb, (ret ? DBUS_ERR_TXFAIL : DBUS_OK));
1331 dbus_sdcb_pktfree(sdio_info, pkt, TRUE);
1332 return ret;
1335 static void *
1336 dbus_prec_pkt_deq(sdio_info_t *sdio_info, int tx_prec_map, int *prec_out)
1338 return pktq_mdeq(&sdio_info->txq, tx_prec_map, prec_out);
1341 static void *
1342 dbus_prec_pkt_deq_exec(struct exec_parms *args)
1344 return dbus_prec_pkt_deq(args->pdeq.sdio_info, args->pdeq.tx_prec_map,
1345 args->pdeq.prec_out);
1349 * FIX: Move WMM pkt prioritization out of DBUS/SDIO to DHD so
1350 * USB can leverage the same logic
1352 static bool
1353 dbus_prec_pkt_enq(sdio_info_t *sdio_info, void *pkt, int prec)
1355 void *p;
1356 int eprec = -1; /* precedence to evict from */
1357 bool discard_oldest;
1358 struct pktq *q = &sdio_info->txq;
1360 /* Fast case, precedence queue is not full and we are also not
1361 * exceeding total queue length
1363 if (!pktq_pfull(q, prec) && !pktq_full(q)) {
1364 pktq_penq(q, prec, pkt);
1365 return TRUE;
1368 /* Determine precedence from which to evict packet, if any */
1369 if (pktq_pfull(q, prec))
1370 eprec = prec;
1371 else if (pktq_full(q)) {
1372 p = pktq_peek_tail(q, &eprec);
1373 ASSERT(p);
1374 if (eprec > prec)
1375 goto err;
1378 /* Evict if needed */
1379 if (eprec >= 0) {
1380 /* Detect queueing to unconfigured precedence */
1381 ASSERT(!pktq_pempty(q, eprec));
1382 discard_oldest = AC_BITMAP_TST(sdio_info->wme_dp, eprec);
1383 if (eprec == prec && !discard_oldest)
1384 goto err; /* refuse newer (incoming) packet */
1385 /* Evict packet according to discard policy */
1386 p = discard_oldest ? pktq_pdeq(q, eprec) : pktq_pdeq_tail(q, eprec);
1387 ASSERT(p);
1389 dbus_sdcb_pktfree(sdio_info, p, TRUE);
1392 /* Enqueue */
1393 p = pktq_penq(q, prec, pkt);
1394 ASSERT(p);
1396 return TRUE;
1397 err:
1398 return FALSE;
1401 static void *
1402 dbus_prec_pkt_enq_exec(struct exec_parms *args)
1404 return (void *) (uintptr) dbus_prec_pkt_enq(args->penq.sdio_info, args->penq.pkt,
1405 args->penq.prec);
1408 static int
1409 dbus_sdio_txbuf_submit(sdio_info_t *sdio_info, dbus_irb_tx_t *txirb)
1411 int ret = 0;
1412 void *berr;
1413 osl_t *osh;
1414 uint datalen, prec;
1415 void *pkt;
1416 pkttag_t *ptag;
1417 struct exec_parms exec_args;
1419 DBUSTRACE(("%s: Enter\n", __FUNCTION__));
1421 osh = sdio_info->pub->osh;
1422 pkt = txirb->pkt;
1423 if (pkt == NULL) {
1425 * For BMAC sdio high driver that uses send_buf,
1426 * we need to convert the buf into pkt for dbus.
1428 datalen = txirb->len;
1429 DBUSTRACE(("%s: Converting buf(%d bytes) to pkt.\n", __FUNCTION__, datalen));
1430 pkt = dbus_sdcb_pktget(sdio_info, datalen, TRUE);
1431 if (pkt == NULL) {
1432 DBUSERR(("%s: Out of Tx buf.\n", __FUNCTION__));
1433 return DBUS_ERR_TXDROP;
1436 txirb->pkt = pkt;
1437 bcopy(txirb->buf, PKTDATA(osh, pkt), datalen);
1438 PKTLEN(osh, pkt) = datalen;
1439 } else
1440 datalen = PKTLEN(osh, pkt);
1442 ASSERT(OSL_PKTTAG_SZ >= sizeof(pkttag_t));
1443 ptag = (pkttag_t *) PKTTAG(pkt);
1444 ptag->sdio_info = sdio_info;
1445 ptag->txirb = txirb;
1447 #ifdef SDTEST
1448 /* Push the test header if doing loopback */
1449 if (sdio_info->ext_loop) {
1450 uint8* data;
1451 PKTPUSH(osh, pkt, SDPCM_TEST_HDRLEN);
1452 data = PKTDATA(osh, pkt);
1453 *data++ = SDPCM_TEST_ECHOREQ;
1454 *data++ = (uint8)sdio_info->loopid++;
1455 *data++ = (datalen >> 0);
1456 *data++ = (datalen >> 8);
1457 datalen += SDPCM_TEST_HDRLEN;
1459 #endif /* SDTEST */
1461 ASSERT(PKTHEADROOM(osh, pkt) >= SDPCM_HDRLEN);
1462 /* Add space for the header */
1463 PKTPUSH(osh, pkt, SDPCM_HDRLEN);
1464 ASSERT(ISALIGNED(PKTDATA(osh, pkt), 2));
1466 prec = PRIO2PREC((PKTPRIO(pkt) & PRIOMASK));
1468 sdio_info->fcqueued++;
1470 /* Priority based enq */
1471 exec_args.penq.sdio_info = sdio_info;
1472 exec_args.penq.pkt = pkt;
1473 exec_args.penq.prec = prec;
1474 berr = dbus_sdos_exec_txlock(sdio_info,
1475 (exec_cb_t) dbus_prec_pkt_enq_exec, &exec_args);
1476 if (berr == NULL) {
1477 DBUSERR(("%s: Dropping pkt!\n", __FUNCTION__));
1478 ASSERT(0); /* FIX: Should not be dropping pkts */
1479 ret = DBUS_ERR_TXFAIL;
1480 goto err;
1483 #ifdef BCMDBG
1484 if (pktq_plen(&sdio_info->txq, prec) > qcount[prec])
1485 qcount[prec] = pktq_plen(&sdio_info->txq, prec);
1486 #endif
1487 dbus_sdio_txq_sched(sdio_info->sdos_info);
1489 err:
1490 return ret;
1493 static void
1494 dbus_bus_stop(sdio_info_t *sdio_info)
1496 uint8 saveclk;
1497 uint retries;
1498 int err;
1500 DBUSTRACE(("%s: Enter\n", __FUNCTION__));
1502 BUS_WAKE(sdio_info);
1504 dbus_sdio_txq_stop(sdio_info->sdos_info);
1506 /* Enable clock for device interrupts */
1507 dbus_sdio_clkctl(sdio_info, CLK_AVAIL, FALSE);
1509 /* Disable and clear interrupts at the chip level also */
1510 W_SDREG(0, &sdio_info->regs->hostintmask, retries);
1511 W_SDREG(sdio_info->hostintmask, &sdio_info->regs->intstatus, retries);
1512 sdio_info->hostintmask = 0;
1514 /* Change our idea of bus state */
1515 sdio_info->pub->busstate = DBUS_STATE_DOWN;
1517 /* Force clocks on backplane to be sure F2 interrupt propagates */
1518 saveclk = bcmsdh_cfg_read(sdio_info->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
1519 if (!err) {
1520 bcmsdh_cfg_write(sdio_info->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
1521 (saveclk | SBSDIO_FORCE_HT), &err);
1523 if (err) {
1524 DBUSERR(("%s: Failed to force clock for F2: err %d\n", __FUNCTION__, err));
1527 /* Turn off the bus (F2), free any pending packets */
1528 DBUSINTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
1529 bcmsdh_intr_disable(sdio_info->sdh);
1530 #ifndef BCMSPI
1531 bcmsdh_cfg_write(sdio_info->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL);
1532 #endif /* !BCMSPI */
1534 /* Turn off the backplane clock (only) */
1535 dbus_sdio_clkctl(sdio_info, CLK_SDONLY, FALSE);
1537 dbus_sdio_txq_flush(sdio_info);
1539 /* Clear any held glomming stuff */
1540 if (sdio_info->glomd) {
1541 dbus_sdcb_pktfree(sdio_info, sdio_info->glomd, FALSE);
1542 sdio_info->glomd = NULL;
1545 if (sdio_info->glom) {
1546 dbus_sdcb_pktfree(sdio_info, sdio_info->glom, FALSE);
1547 sdio_info->glom = NULL;
1550 /* Clear rx control and wake any waiters */
1551 sdio_info->rxlen = 0;
1553 /* Reset some F2 state stuff */
1554 sdio_info->rxskip = FALSE;
1555 sdio_info->tx_seq = sdio_info->rx_seq = 0;
1558 static int
1559 dbus_sdio_init(sdio_info_t *sdio_info)
1561 uint retries = 0;
1563 uint8 ready = 0, enable;
1564 int err, ret = 0;
1565 #ifdef BCMSPI
1566 uint32 dstatus = 0; /* gSPI device status bits of */
1567 #else /* BCMSPI */
1568 uint8 saveclk;
1569 #endif /* BCMSPI */
1571 DBUSTRACE(("%s: Enter\n", __FUNCTION__));
1573 /* Make sure backplane clock is on, needed to generate F2 interrupt */
1574 dbus_sdio_clkctl(sdio_info, CLK_AVAIL, FALSE);
1575 if (sdio_info->clkstate != CLK_AVAIL)
1576 goto exit;
1578 #ifdef BCMSPI
1579 /* fake "ready" for spi, wake-wlan would have already enabled F1 and F2 */
1580 ready = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2);
1582 /* Give the dongle some time to do its thing and set IOR2 */
1583 retries = WAIT_F2RXFIFORDY;
1584 enable = 0;
1585 while (retries-- && !enable) {
1586 OSL_DELAY(WAIT_F2RXFIFORDY_DELAY * 1000);
1587 dstatus = bcmsdh_cfg_read_word(sdio_info->sdh, SDIO_FUNC_0, SPID_STATUS_REG, NULL);
1588 if (dstatus && STATUS_F2_RX_READY)
1589 enable = TRUE;
1591 if (enable) {
1592 DBUSERR(("Took %d retries before dongle is ready with delay %d(ms) in between\n",
1593 WAIT_F2RXFIFORDY - retries, WAIT_F2RXFIFORDY_DELAY));
1594 enable = ready;
1596 else {
1597 DBUSERR(("dstatus when timed out on f2-fifo not ready = 0x%x\n", dstatus));
1598 DBUSERR(("Waited %d retries, dongle is not ready with delay %d(ms) in between\n",
1599 WAIT_F2RXFIFORDY, WAIT_F2RXFIFORDY_DELAY));
1600 ret = -1;
1601 goto exit;
1603 #else /* BCMSPI */
1604 /* Force clocks on backplane to be sure F2 interrupt propagates */
1605 saveclk = bcmsdh_cfg_read(sdio_info->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
1606 if (!err) {
1607 bcmsdh_cfg_write(sdio_info->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
1608 (saveclk | SBSDIO_FORCE_HT), &err);
1610 if (err) {
1611 DBUSERR(("%s: Failed to force clock for F2: err %d\n", __FUNCTION__, err));
1612 goto exit;
1615 /* Enable function 2 (frame transfers) */
1616 W_SDREG((SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT),
1617 &sdio_info->regs->tosbmailboxdata, retries);
1618 enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2);
1620 bcmsdh_cfg_write(sdio_info->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL);
1623 /* Give the dongle some time to do its thing and set IOR2 */
1624 retries = DHD_WAIT_F2RDY;
1626 #ifdef BCMSLTGT
1627 retries *= htclkratio;
1628 #endif /* BCMSLTGT */
1629 while ((enable !=
1630 ((ready = bcmsdh_cfg_read(sdio_info->sdh, SDIO_FUNC_0, SDIOD_CCCR_IORDY, NULL)))) &&
1631 retries--) {
1632 OSL_DELAY(1000);
1634 #endif /* !BCMSPI */
1636 retries = 0;
1638 DBUSERR(("%s: enable 0x%02x, ready 0x%02x\n", __FUNCTION__, enable, ready));
1641 /* If F2 successfully enabled, set core and enable interrupts */
1642 if (ready == enable) {
1643 /* Make sure we're talking to the core. */
1644 if (!(sdio_info->regs = si_setcore(sdio_info->sih, PCMCIA_CORE_ID, 0)))
1645 sdio_info->regs = si_setcore(sdio_info->sih, SDIOD_CORE_ID, 0);
1647 bcmsdh_cfg_write(sdio_info->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK,
1648 (uint8)watermark, &err);
1650 /* bcmsdh_intr_unmask(sdio_info->sdh); */
1652 sdio_info->pub->busstate = DBUS_STATE_UP;
1653 sdio_info->intdis = FALSE;
1654 if (sdio_info->intr) {
1655 DBUSINTR(("%s: enable SDIO device interrupts\n", __FUNCTION__));
1656 bcmsdh_intr_enable(sdio_info->sdh);
1657 } else {
1658 DBUSINTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
1659 bcmsdh_intr_disable(sdio_info->sdh);
1662 #ifdef DEBUG_LOST_INTERRUPTS
1664 uint32 intstatus;
1665 bool hostpending;
1666 uint8 devena, devpend;
1667 uint sdr_retries = 0;
1669 hostpending = bcmsdh_intr_pending(sdio_info->sdh);
1670 devena = bcmsdh_cfg_read(sdio_info->sdh, SDIO_FUNC_0,
1671 SDIOD_CCCR_INTEN, NULL);
1672 devpend = bcmsdh_cfg_read(sdio_info->sdh, SDIO_FUNC_0,
1673 SDIOD_CCCR_INTPEND, NULL);
1675 R_SDREG(intstatus, &sdio_info->regs->intstatus, sdr_retries);
1676 intstatus &= sdio_info->hostintmask;
1678 DBUSERR(("%s: interrupts -- host %s device ena/pend 0x%02x/0x%02x\n"
1679 "intstatus 0x%08x, hostmask 0x%08x\n", __FUNCTION__,
1680 (hostpending ? "PENDING" : "NOT PENDING"),
1681 devena, devpend, intstatus, sdio_info->hostintmask));
1683 #endif /* DEBUG_LOST_INTERRUPTS */
1686 #ifndef BCMSPI
1688 else {
1689 ret = DBUS_ERR;
1691 /* Disable F2 again */
1692 enable = SDIO_FUNC_ENABLE_1;
1693 bcmsdh_cfg_write(sdio_info->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL);
1696 /* Restore previous clock setting */
1697 bcmsdh_cfg_write(sdio_info->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err);
1699 #endif /* !BCMSPI */
1701 /* If we didn't come up, turn off backplane clock */
1702 if (sdio_info->pub->busstate != DBUS_STATE_UP) {
1703 DBUSERR(("Error: Not up yet!\n"));
1704 dbus_sdio_clkctl(sdio_info, CLK_NONE, FALSE);
1706 exit:
1707 return ret;
1710 static void
1711 dbus_sdio_rxfail(sdio_info_t *sdio_info, bool abort, bool rtx)
1713 bcmsdh_info_t *sdh = sdio_info->sdh;
1714 sdpcmd_regs_t *regs = sdio_info->regs;
1715 uint retries = 0;
1716 uint16 lastrbc;
1717 uint8 hi, lo;
1718 int err;
1720 DBUSERR(("%s: %sterminate frame%s\n", __FUNCTION__,
1721 (abort ? "abort command, " : ""), (rtx ? ", send NAK" : "")));
1723 if (abort) {
1724 err = bcmsdh_abort(sdh, SDIO_FUNC_2);
1725 if (err == BCME_NODEVICE) {
1726 dbus_sdio_state_change(sdio_info, DBUS_STATE_DISCONNECT);
1727 return;
1731 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, SFC_RF_TERM, &err);
1732 sdio_info->f1regdata++;
1734 /* Wait until the packet has been flushed (device/FIFO stable) */
1735 for (lastrbc = retries = 0xffff; retries > 0; retries--) {
1736 hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCHI, NULL);
1737 lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCLO, NULL);
1738 sdio_info->f1regdata += 2;
1740 if ((hi == 0) && (lo == 0))
1741 break;
1743 if ((hi > (lastrbc >> 8)) && (lo > (lastrbc & 0x00ff))) {
1744 DBUSERR(("%s: count growing: last 0x%04x now 0x%04x\n",
1745 __FUNCTION__, lastrbc, ((hi << 8) + lo)));
1747 lastrbc = (hi << 8) + lo;
1750 if (!retries) {
1751 DBUSERR(("%s: count never zeroed: last 0x%04x\n", __FUNCTION__, lastrbc));
1752 } else {
1753 DBUSINFO(("%s: flush took %d iterations\n", __FUNCTION__, (0xffff - retries)));
1756 if (rtx) {
1757 sdio_info->rxrtx++;
1758 W_SDREG(SMB_NAK, &regs->tosbmailbox, retries);
1759 sdio_info->f1regdata++;
1760 if (retries <= retry_limit) {
1761 sdio_info->rxskip = TRUE;
1765 /* Clear partial in any case */
1766 sdio_info->nextlen = 0;
1768 /* If we can't reach the device, signal failure */
1769 if (err || bcmsdh_regfail(sdh))
1770 sdio_info->pub->busstate = DBUS_STATE_DOWN;
1773 static void
1774 dbus_sdio_read_control(sdio_info_t *sdio_info, uint8 *hdr, uint len, uint doff)
1776 bcmsdh_info_t *sdh = sdio_info->sdh;
1777 uint rdlen, pad;
1779 int sdret;
1781 DBUSTRACE(("%s: Enter\n", __FUNCTION__));
1783 /* Control data already received in aligned rxctl */
1784 if ((sdio_info->bus == SPI_BUS) && (!sdio_info->usebufpool))
1785 goto gotpkt;
1787 ASSERT(sdio_info->rxbuf);
1788 /* Set rxctl for frame (w/optional alignment) */
1789 sdio_info->rxctl = sdio_info->rxbuf;
1790 if (dhd_alignctl) {
1791 sdio_info->rxctl += firstread;
1792 if ((pad = ((uintptr)sdio_info->rxctl % SDALIGN)))
1793 sdio_info->rxctl += (SDALIGN - pad);
1794 sdio_info->rxctl -= firstread;
1796 ASSERT(sdio_info->rxctl >= sdio_info->rxbuf);
1798 /* Copy the already-read portion over */
1799 bcopy(hdr, sdio_info->rxctl, firstread);
1800 if (len <= firstread)
1801 goto gotpkt;
1803 /* Copy the full data pkt in gSPI case and process ioctl. */
1804 if (sdio_info->bus == SPI_BUS) {
1805 bcopy(hdr, sdio_info->rxctl, len);
1806 goto gotpkt;
1809 /* Raise rdlen to next SDIO block to avoid tail command */
1810 rdlen = len - firstread;
1811 if (sdio_info->roundup && sdio_info->blocksize && (rdlen > sdio_info->blocksize)) {
1812 pad = sdio_info->blocksize - (rdlen % sdio_info->blocksize);
1813 if ((pad <= sdio_info->roundup) && (pad < sdio_info->blocksize) &&
1814 ((len + pad) < sdio_info->maxctl))
1815 rdlen += pad;
1818 /* Satisfy length-alignment requirements */
1819 if (forcealign && (rdlen & (ALIGNMENT - 1)))
1820 rdlen = ROUNDUP(rdlen, ALIGNMENT);
1822 /* Drop if the read is too big or it exceeds our maximum */
1823 if ((rdlen + firstread) > sdio_info->maxctl) {
1824 DBUSERR(("%s: %d-byte control read exceeds %d-byte buffer\n",
1825 __FUNCTION__, rdlen, sdio_info->maxctl));
1826 sdio_info->pub->stats.rx_errors++;
1827 dbus_sdio_rxfail(sdio_info, FALSE, FALSE);
1828 goto done;
1831 if ((len - doff) > sdio_info->maxctl) {
1832 DBUSERR(("%s: %d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n",
1833 __FUNCTION__, len, (len - doff), sdio_info->maxctl));
1834 sdio_info->pub->stats.rx_errors++; sdio_info->rx_toolong++;
1835 dbus_sdio_rxfail(sdio_info, FALSE, FALSE);
1836 goto done;
1840 /* Read remainder of frame body into the rxctl buffer */
1841 sdret = bcmsdh_recv_buf(sdh, SI_ENUM_BASE, SDIO_FUNC_2, F2SYNC,
1842 (sdio_info->rxctl + firstread), rdlen, NULL, NULL, NULL);
1843 sdio_info->f2rxdata++;
1844 ASSERT(sdret != BCME_PENDING);
1846 /* Control frame failures need retransmission */
1847 if (sdret < 0) {
1848 DBUSERR(("%s: read %d control bytes failed: %d\n", __FUNCTION__, rdlen, sdret));
1849 sdio_info->rxc_errors++; /* dhd.rx_ctlerrs is higher level */
1850 dbus_sdio_rxfail(sdio_info, TRUE, TRUE);
1851 goto done;
1854 gotpkt:
1855 /* Point to valid data and indicate its length */
1856 sdio_info->rxctl += doff;
1858 if (sdio_info->rxlen != 0) {
1859 DBUSERR(("dropping previous recv ctl pkt\n"));
1861 sdio_info->rxlen = len - doff;
1863 if (sdio_info->cbarg && sdio_info->cbs) {
1864 if (sdio_info->rxctl_req.pending == TRUE) {
1865 dbus_sdio_rxctl(sdio_info, sdio_info->rxctl_req.ctl.buf,
1866 sdio_info->rxctl_req.ctl.len);
1867 bzero(&sdio_info->rxctl_req, sizeof(sdio_info->rxctl_req));
1868 dbus_sdio_ctl_complete(sdio_info, DBUS_CBCTL_READ, DBUS_OK);
1870 /* If receive ctl pkt before user request, leave in cache
1871 * and retrieve it next time recv_ctl() is called.
1874 done:
1875 return;
1878 static uint8
1879 dbus_sdio_rxglom(sdio_info_t *sdio_info, uint8 rxseq)
1881 uint16 dlen, totlen;
1882 uint8 *dptr, num = 0;
1884 uint16 sublen, check;
1885 void *pfirst, *plast, *pnext, *save_pfirst;
1886 osl_t *osh = sdio_info->pub->osh;
1888 int errcode;
1889 uint8 chan, seq, doff, sfdoff;
1890 uint8 txmax;
1892 bool usechain = sdio_info->use_rxchain;
1894 /* If packets, issue read(s) and send up packet chain */
1895 /* Return sequence numbers consumed? */
1897 DBUSTRACE(("dbus_sdio_rxglom: start: glomd %p glom %p\n",
1898 sdio_info->glomd, sdio_info->glom));
1900 /* If there's a descriptor, generate the packet chain */
1901 if (sdio_info->glomd) {
1902 dlen = (uint16)PKTLEN(osh, sdio_info->glomd);
1903 dptr = PKTDATA(osh, sdio_info->glomd);
1904 if (!dlen || (dlen & 1)) {
1905 DBUSERR(("%s: bad glomd len (%d), toss descriptor\n",
1906 __FUNCTION__, dlen));
1907 dbus_sdcb_pktfree(sdio_info, sdio_info->glomd, FALSE);
1908 sdio_info->glomd = NULL;
1909 sdio_info->nextlen = 0;
1910 return 0;
1913 pfirst = plast = pnext = NULL;
1915 for (totlen = num = 0; dlen; num++) {
1916 /* Get (and move past) next length */
1917 sublen = ltoh16_ua(dptr);
1918 dlen -= sizeof(uint16);
1919 dptr += sizeof(uint16);
1920 if ((sublen < SDPCM_HDRLEN) ||
1921 ((num == 0) && (sublen < (2 * SDPCM_HDRLEN)))) {
1922 DBUSERR(("%s: desciptor len %d bad: %d\n",
1923 __FUNCTION__, num, sublen));
1924 pnext = NULL;
1925 break;
1927 if (sublen % SDALIGN) {
1928 DBUSERR(("%s: sublen %d not a multiple of %d\n",
1929 __FUNCTION__, sublen, SDALIGN));
1930 usechain = FALSE;
1932 totlen += sublen;
1934 /* For last frame, adjust read len so total is a block multiple */
1935 if (!dlen) {
1936 sublen += (ROUNDUP(totlen, sdio_info->blocksize) - totlen);
1937 totlen = ROUNDUP(totlen, sdio_info->blocksize);
1940 /* Allocate/chain packet for next subframe */
1941 if ((pnext = dbus_sdcb_pktget(sdio_info,
1942 sublen + SDALIGN, FALSE)) == NULL) {
1943 DBUSERR(("%s: dbus_sdio_pktget failed, num %d len %d\n",
1944 __FUNCTION__, num, sublen));
1945 break;
1947 ASSERT(!PKTLINK(pnext));
1948 if (!pfirst) {
1949 ASSERT(!plast);
1950 pfirst = plast = pnext;
1951 } else {
1952 ASSERT(plast);
1953 PKTSETNEXT(osh, plast, pnext);
1954 plast = pnext;
1957 /* Adhere to start alignment requirements */
1958 PKTALIGN(osh, pnext, sublen, SDALIGN);
1961 /* If allocation failed, toss entirely and increment count */
1962 if (!pnext) {
1963 if (pfirst)
1964 dbus_sdcb_pktfree(sdio_info, pfirst, FALSE);
1965 dbus_sdcb_pktfree(sdio_info, sdio_info->glomd, FALSE);
1966 sdio_info->glomd = NULL;
1967 sdio_info->nextlen = 0;
1968 return 0;
1971 /* Ok, we have a packet chain, save in bus structure */
1972 DBUSGLOM(("%s: allocated %d-byte packet chain for %d subframes\n",
1973 __FUNCTION__, totlen, num));
1974 if (DBUSGLOM_ON() && sdio_info->nextlen) {
1975 if (totlen != sdio_info->nextlen) {
1976 DBUSGLOM(("%s: glomdesc mismatch: nextlen %d glomdesc %d "
1977 "rxseq %d\n", __FUNCTION__, sdio_info->nextlen,
1978 totlen, rxseq));
1981 sdio_info->glom = pfirst;
1983 /* Done with descriptor packet */
1984 dbus_sdcb_pktfree(sdio_info, sdio_info->glomd, FALSE);
1985 sdio_info->glomd = NULL;
1986 sdio_info->nextlen = 0;
1989 /* Ok -- either we just generated a packet chain, or had one from before */
1990 if (sdio_info->glom) {
1991 if (DBUSGLOM_ON()) {
1992 DBUSGLOM(("%s: attempt superframe read, packet chain:\n", __FUNCTION__));
1993 for (pnext = sdio_info->glom; pnext; pnext = PKTNEXT(osh, pnext)) {
1994 DBUSGLOM((" %p: %p len 0x%04x (%d)\n",
1995 pnext, (uint8*)PKTDATA(osh, pnext),
1996 PKTLEN(osh, pnext), PKTLEN(osh, pnext)));
2000 pfirst = sdio_info->glom;
2001 dlen = (uint16)pkttotlen(osh, pfirst);
2003 /* Do an SDIO read for the superframe. Configurable iovar to
2004 * read directly into the chained packet, or allocate a large
2005 * packet and and copy into the chain.
2007 if (usechain) {
2008 errcode = bcmsdh_recv_buf(sdio_info->sdh, SI_ENUM_BASE, SDIO_FUNC_2,
2009 F2SYNC, (uint8*)PKTDATA(osh, pfirst),
2010 dlen, pfirst, NULL, NULL);
2011 } else if (sdio_info->dataptr) {
2012 errcode = bcmsdh_recv_buf(sdio_info->sdh, SI_ENUM_BASE, SDIO_FUNC_2,
2013 F2SYNC, sdio_info->dataptr,
2014 dlen, NULL, NULL, NULL);
2015 sublen = (uint16)pktfrombuf(osh, pfirst, 0, dlen, sdio_info->dataptr);
2016 if (sublen != dlen) {
2017 DBUSERR(("%s: FAILED TO COPY, dlen %d sublen %d\n",
2018 __FUNCTION__, dlen, sublen));
2019 errcode = -1;
2021 pnext = NULL;
2022 } else {
2023 DBUSERR(("COULDN'T ALLOC %d-BYTE GLOM, FORCE FAILURE\n", dlen));
2024 errcode = -1;
2026 sdio_info->f2rxdata++;
2027 ASSERT(errcode != BCME_PENDING);
2029 /* On failure, kill the superframe, allow a couple retries */
2030 if (errcode < 0) {
2031 DBUSERR(("%s: glom read of %d bytes failed: %d\n",
2032 __FUNCTION__, dlen, errcode));
2033 sdio_info->pub->stats.rx_errors++;
2035 if (sdio_info->glomerr++ < 3) {
2036 dbus_sdio_rxfail(sdio_info, TRUE, TRUE);
2037 } else {
2038 sdio_info->glomerr = 0;
2039 dbus_sdio_rxfail(sdio_info, TRUE, FALSE);
2040 dbus_sdcb_pktfree(sdio_info, sdio_info->glom, FALSE);
2041 sdio_info->rxglomfail++;
2042 sdio_info->glom = NULL;
2044 OSL_DELAY(dlen/128);
2045 return 0;
2048 #ifdef BCMDBG
2049 if (DBUSGLOM_ON()) {
2050 prhex("SUPERFRAME", PKTDATA(osh, pfirst),
2051 MIN(PKTLEN(osh, pfirst), 48));
2053 #endif
2056 /* Validate the superframe header */
2057 dptr = (uint8 *)PKTDATA(osh, pfirst);
2058 sublen = ltoh16_ua(dptr);
2059 check = ltoh16_ua(dptr + sizeof(uint16));
2061 chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
2062 seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
2063 sdio_info->nextlen = dptr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
2064 if ((sdio_info->nextlen << 4) > MAX_RX_DATASZ) {
2065 DBUSINFO(("%s: got frame w/nextlen too large (%d) seq %d\n",
2066 __FUNCTION__, sdio_info->nextlen, seq));
2067 sdio_info->nextlen = 0;
2069 doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
2070 txmax = SDPCM_WINDOW_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
2072 errcode = 0;
2073 if ((uint16)~(sublen^check)) {
2074 DBUSERR(("%s (superframe): HW hdr error: len/check 0x%04x/0x%04x\n",
2075 __FUNCTION__, sublen, check));
2076 errcode = -1;
2077 } else if (ROUNDUP(sublen, sdio_info->blocksize) != dlen) {
2078 DBUSERR(("%s (superframe): len 0x%04x, rounded 0x%04x, expect 0x%04x\n",
2079 __FUNCTION__, sublen,
2080 ROUNDUP(sublen, sdio_info->blocksize), dlen));
2081 errcode = -1;
2082 } else if (SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]) != SDPCM_GLOM_CHANNEL) {
2083 DBUSERR(("%s (superframe): bad channel %d\n", __FUNCTION__,
2084 SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN])));
2085 errcode = -1;
2086 } else if (SDPCM_GLOMDESC(&dptr[SDPCM_FRAMETAG_LEN])) {
2087 DBUSERR(("%s (superframe): got second descriptor?\n", __FUNCTION__));
2088 errcode = -1;
2089 } else if ((doff < SDPCM_HDRLEN) ||
2090 (doff > (PKTLEN(osh, pfirst) - SDPCM_HDRLEN))) {
2091 DBUSERR(("%s (superframe): Bad data offset %d: HW %d pkt %d min %d\n",
2092 __FUNCTION__, doff, sublen, PKTLEN(osh, pfirst), SDPCM_HDRLEN));
2093 errcode = -1;
2096 /* Check sequence number of superframe SW header */
2097 if (rxseq != seq) {
2098 DBUSINFO(("%s: (superframe) rx_seq %d, expected %d\n",
2099 __FUNCTION__, seq, rxseq));
2100 sdio_info->rx_badseq++;
2101 rxseq = seq;
2104 /* Check window for sanity */
2105 if ((uint8)(txmax - sdio_info->tx_seq) > 0x40) {
2106 DBUSERR(("%s: got unlikely tx max %d with tx_seq %d\n",
2107 __FUNCTION__, txmax, sdio_info->tx_seq));
2108 txmax = sdio_info->tx_seq + 2;
2110 sdio_info->tx_max = txmax;
2112 /* Remove superframe header, remember offset */
2113 PKTPULL(osh, pfirst, doff);
2114 sfdoff = doff;
2116 /* Validate all the subframe headers */
2117 for (num = 0, pnext = pfirst; pnext && !errcode;
2118 num++, pnext = PKTNEXT(osh, pnext)) {
2119 dptr = (uint8 *)PKTDATA(osh, pnext);
2120 dlen = (uint16)PKTLEN(osh, pnext);
2121 sublen = ltoh16_ua(dptr);
2122 check = ltoh16_ua(dptr + sizeof(uint16));
2123 chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
2124 doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
2125 #ifdef BCMDBG
2126 if (DBUSGLOM_ON()) {
2127 prhex("subframe", dptr, 32);
2129 #endif
2131 if ((uint16)~(sublen^check)) {
2132 DBUSERR(("%s (subframe %d): HW hdr error: "
2133 "len/check 0x%04x/0x%04x\n",
2134 __FUNCTION__, num, sublen, check));
2135 errcode = -1;
2136 } else if ((sublen > dlen) || (sublen < SDPCM_HDRLEN)) {
2137 DBUSERR(("%s (subframe %d): length mismatch: "
2138 "len 0x%04x, expect 0x%04x\n",
2139 __FUNCTION__, num, sublen, dlen));
2140 errcode = -1;
2141 } else if ((chan != SDPCM_DATA_CHANNEL) &&
2142 (chan != SDPCM_EVENT_CHANNEL)) {
2143 DBUSERR(("%s (subframe %d): bad channel %d\n",
2144 __FUNCTION__, num, chan));
2145 errcode = -1;
2146 } else if ((doff < SDPCM_HDRLEN) || (doff > sublen)) {
2147 DBUSERR(("%s (subframe %d): Bad data offset %d: HW %d min %d\n",
2148 __FUNCTION__, num, doff, sublen, SDPCM_HDRLEN));
2149 errcode = -1;
2153 if (errcode) {
2154 /* Terminate frame on error, request a couple retries */
2155 if (sdio_info->glomerr++ < 3) {
2156 /* Restore superframe header space */
2157 PKTPUSH(osh, pfirst, sfdoff);
2158 dbus_sdio_rxfail(sdio_info, TRUE, TRUE);
2159 } else {
2160 sdio_info->glomerr = 0;
2161 dbus_sdio_rxfail(sdio_info, TRUE, FALSE);
2162 dbus_sdcb_pktfree(sdio_info, sdio_info->glom, FALSE);
2163 sdio_info->rxglomfail++;
2164 sdio_info->glom = NULL;
2166 sdio_info->nextlen = 0;
2167 return 0;
2170 /* Basic SD framing looks ok - process each packet (header) */
2171 save_pfirst = pfirst;
2172 sdio_info->glom = NULL;
2173 plast = NULL;
2175 for (num = 0; pfirst; rxseq++, pfirst = pnext) {
2176 pnext = PKTNEXT(osh, pfirst);
2177 PKTSETNEXT(osh, pfirst, NULL);
2179 dptr = (uint8 *)PKTDATA(osh, pfirst);
2180 sublen = ltoh16_ua(dptr);
2181 chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
2182 seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
2183 doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
2185 DBUSGLOM(("%s: Get subframe %d, %p(%p/%d), sublen %d chan %d seq %d\n",
2186 __FUNCTION__, num, pfirst, PKTDATA(osh, pfirst),
2187 PKTLEN(osh, pfirst), sublen, chan, seq));
2189 ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL));
2191 if (rxseq != seq) {
2192 DBUSGLOM(("%s: rx_seq %d, expected %d\n",
2193 __FUNCTION__, seq, rxseq));
2194 sdio_info->rx_badseq++;
2195 rxseq = seq;
2198 PKTSETLEN(osh, pfirst, sublen);
2199 PKTPULL(osh, pfirst, doff);
2201 if (PKTLEN(osh, pfirst) == 0) {
2202 dbus_sdcb_pktfree(sdio_info, pfirst, FALSE);
2203 if (plast) {
2204 PKTSETNEXT(osh, plast, pnext);
2205 } else {
2206 ASSERT(save_pfirst == pfirst);
2207 save_pfirst = pnext;
2209 continue;
2212 /* this packet will go up, link back into chain and count it */
2213 PKTSETNEXT(osh, pfirst, pnext);
2214 plast = pfirst;
2215 num++;
2217 #ifdef BCMDBG
2218 if (DBUSGLOM_ON()) {
2219 DBUSGLOM(("%s subframe %d to stack, %p(%p/%d) nxt/lnk %p/%p\n",
2220 __FUNCTION__, num, pfirst,
2221 PKTDATA(osh, pfirst), PKTLEN(osh, pfirst),
2222 PKTNEXT(osh, pfirst), PKTLINK(pfirst)));
2223 prhex("", (uint8 *)PKTDATA(osh, pfirst),
2224 MIN(PKTLEN(osh, pfirst), 32));
2226 #endif /* BCMDBG */
2230 int i;
2231 void *pnext;
2232 void *plist;
2233 dbus_irb_rx_t *rxirb;
2235 plist = save_pfirst;
2236 for (i = 0; plist && i < num; i++, plist = pnext) {
2237 pnext = PKTNEXT(osh, plist);
2238 PKTSETNEXT(osh, plist, NULL);
2240 rxirb = (dbus_irb_rx_t *) dbus_sdcb_getirb(sdio_info, FALSE);
2241 if (rxirb != NULL) {
2242 rxirb->pkt = plist;
2243 dbus_sdio_recv_irb_complete(sdio_info, rxirb, DBUS_OK);
2244 } else {
2245 ASSERT(0); /* FIX: Handle this case */
2250 sdio_info->rxglomframes++;
2251 sdio_info->rxglompkts += num;
2253 return num;
2256 /* Return TRUE if there may be more frames to read */
2257 static uint
2258 dbus_sdio_readframes(sdio_info_t *sdio_info, uint maxframes, bool *finished)
2260 bcmsdh_info_t *sdh = sdio_info->sdh;
2262 uint16 len, check; /* Extracted hardware header fields */
2263 uint8 chan, seq, doff; /* Extracted software header fields */
2264 uint8 fcbits; /* Extracted fcbits from software header */
2265 uint8 delta;
2267 void *pkt; /* Packet for event or data frames */
2268 uint16 pad; /* Number of pad bytes to read */
2269 uint16 rdlen; /* Total number of bytes to read */
2270 uint8 rxseq; /* Next sequence number to expect */
2271 uint rxleft = 0; /* Remaining number of frames allowed */
2272 int sdret; /* Return code from bcmsdh calls */
2273 uint8 txmax; /* Maximum tx sequence offered */
2274 uint32 dstatus = 0; /* gSPI device status bits of */
2275 bool len_consistent; /* Result of comparing readahead len and len from hw-hdr */
2276 uint8 *rxbuf;
2277 dbus_irb_rx_t *rxirb;
2279 #if defined(BCMDBG) || defined(SDTEST)
2280 bool sdtest = FALSE; /* To limit message spew from test mode */
2281 #endif
2283 DBUSTRACE(("%s: Enter\n", __FUNCTION__));
2285 ASSERT(maxframes);
2287 #ifdef SDTEST
2288 /* Allow pktgen to override maxframes */
2289 if (sdio_info->pktgen_count && (sdio_info->pktgen_mode == DHD_PKTGEN_RECV)) {
2290 maxframes = sdio_info->pktgen_count;
2291 sdtest = TRUE;
2293 #endif
2295 /* Not finished unless we encounter no more frames indication */
2296 *finished = FALSE;
2298 #ifdef BCMSPI
2299 /* Get pktlen from gSPI device F0 reg. */
2300 if (sdio_info->bus == SPI_BUS) {
2301 /* Peek in dstatus bits and find out size to do rx-read. */
2302 dstatus = bcmsdh_get_dstatus(sdio_info->sdh);
2303 DBUSTRACE(("Device status from regread = 0x%x\n", dstatus));
2304 DBUSTRACE(("Device status from bit-reconstruction = 0x%x\n",
2305 bcmsdh_get_dstatus((void *)sdio_info->sdh)));
2307 if ((dstatus & STATUS_F2_PKT_AVAILABLE) && (((dstatus & STATUS_UNDERFLOW)) == 0)) {
2308 sdio_info->nextlen = (dstatus & STATUS_F2_PKT_LEN) >> STATUS_F2_PKT_SHIFT;
2309 /* '0' size with pkt-available interrupt is eqvt to 2048 bytes */
2310 sdio_info->nextlen =
2311 (sdio_info->nextlen == 0) ? SPI_MAX_PKT_LEN : sdio_info->nextlen;
2312 DBUSINFO(("Entering %s: length to be read from gSPI = %d\n",
2313 __FUNCTION__, sdio_info->nextlen));
2314 } else {
2315 if (dstatus & STATUS_F2_PKT_AVAILABLE)
2316 DBUSERR(("Underflow during %s.\n", __FUNCTION__));
2317 else
2318 DBUSERR(("False pkt-available intr.\n"));
2319 *finished = TRUE;
2320 return (maxframes - rxleft);
2323 #endif /* BCMSPI */
2325 for (rxseq = sdio_info->rx_seq, rxleft = maxframes;
2326 !sdio_info->rxskip && rxleft && sdio_info->pub->busstate != DBUS_STATE_DOWN;
2327 rxseq++, rxleft--) {
2329 /* Handle glomming separately */
2330 if (sdio_info->glom || sdio_info->glomd) {
2331 uint8 cnt;
2332 DBUSGLOM(("%s: calling rxglom: glomd %p, glom %p\n",
2333 __FUNCTION__, sdio_info->glomd, sdio_info->glom));
2335 cnt = dbus_sdio_rxglom(sdio_info, rxseq);
2336 DBUSGLOM(("%s: rxglom returned %d\n", __FUNCTION__, cnt));
2337 rxseq += cnt - 1;
2338 rxleft = (rxleft > cnt) ? (rxleft - cnt) : 1;
2339 continue;
2342 /* Try doing single read if we can */
2343 if (dhd_readahead && sdio_info->nextlen) {
2344 uint16 nextlen = sdio_info->nextlen;
2345 sdio_info->nextlen = 0;
2347 if (sdio_info->bus == SPI_BUS) {
2348 rdlen = len = nextlen;
2350 else {
2351 rdlen = len = nextlen << 4;
2353 /* Pad read to blocksize for efficiency */
2354 if (sdio_info->roundup && sdio_info->blocksize &&
2355 (rdlen > sdio_info->blocksize)) {
2356 pad = sdio_info->blocksize - (rdlen % sdio_info->blocksize);
2357 if ((pad <= sdio_info->roundup) &&
2358 (pad < sdio_info->blocksize) &&
2359 ((rdlen + pad + firstread) < MAX_RX_DATASZ))
2360 rdlen += pad;
2364 /* We use sdio_info->rxctl buffer in WinXP for initial control pkt receives.
2365 * Later we use buffer-poll for data as well as control packets.
2366 * This is required becuase dhd receives full frame in gSPI unlike SDIO.
2367 * After the frame is received we have to distinguish whether it is data
2368 * or non-data frame.
2370 /* Allocate a packet buffer */
2371 if (!(pkt = dbus_sdcb_pktget(sdio_info, rdlen + SDALIGN, FALSE))) {
2372 if (sdio_info->bus == SPI_BUS) {
2373 sdio_info->usebufpool = FALSE;
2374 sdio_info->rxctl = sdio_info->rxbuf;
2375 if (dhd_alignctl) {
2376 sdio_info->rxctl += firstread;
2377 if ((pad = ((uintptr)sdio_info->rxctl % SDALIGN)))
2378 sdio_info->rxctl += (SDALIGN - pad);
2379 sdio_info->rxctl -= firstread;
2381 ASSERT(sdio_info->rxctl >= sdio_info->rxbuf);
2382 rxbuf = sdio_info->rxctl;
2383 /* Read the entire frame */
2384 sdret = bcmsdh_recv_buf(sdh, SI_ENUM_BASE, SDIO_FUNC_2,
2385 F2SYNC, rxbuf, rdlen, NULL, NULL, NULL);
2386 sdio_info->f2rxdata++;
2387 ASSERT(sdret != BCME_PENDING);
2389 #ifdef BCMSPI
2390 if (bcmsdh_get_dstatus((void *)sdio_info->sdh) &
2391 STATUS_UNDERFLOW) {
2392 sdio_info->nextlen = 0;
2393 *finished = TRUE;
2394 DBUSERR(("%s: read %d control bytes failed "
2395 "due to spi underflow\n",
2396 __FUNCTION__, rdlen));
2397 /* dhd.rx_ctlerrs is higher level */
2398 sdio_info->rxc_errors++;
2399 continue;
2401 #endif /* BCMSPI */
2403 /* Control frame failures need retransmission */
2404 if (sdret < 0) {
2405 DBUSERR(("%s: read %d control bytes failed: %d\n",
2406 __FUNCTION__, rdlen, sdret));
2407 /* dhd.rx_ctlerrs is higher level */
2408 sdio_info->rxc_errors++;
2409 dbus_sdio_rxfail(sdio_info, TRUE,
2410 (sdio_info->bus == SPI_BUS) ? FALSE : TRUE);
2411 continue;
2413 } else {
2414 /* Give up on data, request rtx of events */
2415 DBUSERR(("%s (nextlen): dbus_sdio_pktget failed: len %d rdlen %d "
2416 "expected rxseq %d\n",
2417 __FUNCTION__, len, rdlen, rxseq));
2418 /* Just go try again w/normal header read */
2419 continue;
2421 } else {
2422 if (sdio_info->bus == SPI_BUS)
2423 sdio_info->usebufpool = TRUE;
2425 ASSERT(!PKTLINK(pkt));
2426 PKTALIGN(sdio_info->pub->osh, pkt, rdlen, SDALIGN);
2427 rxbuf = (uint8 *)PKTDATA(sdio_info->pub->osh, pkt);
2428 /* Read the entire frame */
2429 sdret = bcmsdh_recv_buf(sdh, SI_ENUM_BASE, SDIO_FUNC_2, F2SYNC,
2430 rxbuf, rdlen, pkt, NULL, NULL);
2431 sdio_info->f2rxdata++;
2432 ASSERT(sdret != BCME_PENDING);
2434 if (bcmsdh_get_dstatus((void *)sdio_info->sdh) & STATUS_UNDERFLOW) {
2435 sdio_info->nextlen = 0;
2436 *finished = TRUE;
2437 DBUSERR(("%s (nextlen): read %d bytes failed due "
2438 "to spi underflow\n",
2439 __FUNCTION__, rdlen));
2440 dbus_sdcb_pktfree(sdio_info, pkt, FALSE);
2441 sdio_info->pub->stats.rx_errors++;
2442 continue;
2445 if (sdret < 0) {
2446 DBUSERR(("%s (nextlen): read %d bytes failed: %d\n",
2447 __FUNCTION__, rdlen, sdret));
2448 dbus_sdcb_pktfree(sdio_info, pkt, FALSE);
2449 sdio_info->pub->stats.rx_errors++;
2450 /* Force retry w/normal header read. Don't attemp NAK for
2451 * gSPI
2453 dbus_sdio_rxfail(sdio_info, TRUE,
2454 (sdio_info->bus == SPI_BUS) ? FALSE : TRUE);
2455 continue;
2459 /* Now check the header */
2460 bcopy(rxbuf, sdio_info->rxhdr, SDPCM_HDRLEN);
2462 /* Extract hardware header fields */
2463 len = ltoh16_ua(sdio_info->rxhdr);
2464 check = ltoh16_ua(sdio_info->rxhdr + sizeof(uint16));
2466 /* All zeros means readahead info was bad */
2467 if (!(len|check)) {
2468 DBUSINFO(("%s (nextlen): read zeros in HW header???\n",
2469 __FUNCTION__));
2470 PKTFREE2();
2471 GSPI_PR55150_BAILOUT;
2472 continue;
2475 /* Validate check bytes */
2476 if ((uint16)~(len^check)) {
2477 DBUSERR(("%s (nextlen): HW hdr error: nextlen/len/check"
2478 " 0x%04x/0x%04x/0x%04x\n", __FUNCTION__, nextlen,
2479 len, check));
2480 PKTFREE2();
2481 sdio_info->rx_badhdr++;
2482 dbus_sdio_rxfail(sdio_info, FALSE, FALSE);
2483 GSPI_PR55150_BAILOUT;
2484 continue;
2487 /* Validate frame length */
2488 if (len < SDPCM_HDRLEN) {
2489 DBUSERR(("%s (nextlen): HW hdr length invalid: %d\n",
2490 __FUNCTION__, len));
2491 PKTFREE2();
2492 GSPI_PR55150_BAILOUT;
2493 continue;
2496 /* Check for consistency with readahead info */
2497 if (sdio_info->bus == SPI_BUS)
2498 len_consistent = (nextlen != len);
2499 else
2500 len_consistent = (nextlen != (ROUNDUP(len, 16) >> 4));
2501 if (len_consistent) {
2502 /* Mismatch, force retry w/normal header (may be >4K) */
2503 DBUSERR(("%s (nextlen): mismatch, nextlen %d len %d rnd %d; "
2504 "expected rxseq %d\n",
2505 __FUNCTION__, nextlen, len, ROUNDUP(len, 16), rxseq));
2506 PKTFREE2();
2507 dbus_sdio_rxfail(sdio_info, TRUE,
2508 (sdio_info->bus == SPI_BUS) ? FALSE : TRUE);
2509 GSPI_PR55150_BAILOUT;
2510 continue;
2514 /* Extract software header fields */
2515 chan = SDPCM_PACKET_CHANNEL(&sdio_info->rxhdr[SDPCM_FRAMETAG_LEN]);
2516 seq = SDPCM_PACKET_SEQUENCE(&sdio_info->rxhdr[SDPCM_FRAMETAG_LEN]);
2517 doff = SDPCM_DOFFSET_VALUE(&sdio_info->rxhdr[SDPCM_FRAMETAG_LEN]);
2518 txmax = SDPCM_WINDOW_VALUE(&sdio_info->rxhdr[SDPCM_FRAMETAG_LEN]);
2520 #ifdef BCMSPI
2521 /* Save the readahead length if there is one */
2522 if (sdio_info->bus == SPI_BUS) {
2523 /* Use reconstructed dstatus bits and find out readahead size */
2524 dstatus = bcmsdh_get_dstatus((void *)sdio_info->sdh);
2525 DBUSINFO(("Device status from bit-reconstruction = 0x%x\n",
2526 bcmsdh_get_dstatus((void *)sdio_info->sdh)));
2527 if (dstatus & STATUS_F2_PKT_AVAILABLE) {
2528 sdio_info->nextlen = (dstatus & STATUS_F2_PKT_LEN) >>
2529 STATUS_F2_PKT_SHIFT;
2530 sdio_info->nextlen = (sdio_info->nextlen == 0) ?
2531 SPI_MAX_PKT_LEN : sdio_info->nextlen;
2532 DBUSINFO(("readahead len from gSPI = %d \n",
2533 sdio_info->nextlen));
2534 sdio_info->rx_readahead_cnt ++;
2535 } else {
2536 sdio_info->nextlen = 0;
2537 *finished = TRUE;
2539 } else {
2540 #endif /* BCMSPI */
2541 sdio_info->nextlen =
2542 sdio_info->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
2543 if ((sdio_info->nextlen << 4) > MAX_RX_DATASZ) {
2544 DBUSINFO(("%s (nextlen): got frame w/nextlen too large"
2545 " (%d), seq %d\n", __FUNCTION__, sdio_info->nextlen,
2546 seq));
2547 sdio_info->nextlen = 0;
2550 sdio_info->rx_readahead_cnt ++;
2551 #ifdef BCMSPI
2553 #endif /* BCMSPI */
2555 /* Handle Flow Control - Brett */
2556 fcbits = SDPCM_FCMASK_VALUE(&sdio_info->rxhdr[SDPCM_FRAMETAG_LEN]);
2558 delta = 0;
2559 if (~sdio_info->flowcontrol & fcbits) {
2560 sdio_info->fc_xoff++;
2561 delta = 1;
2563 if (sdio_info->flowcontrol & ~fcbits) {
2564 sdio_info->fc_xon++;
2565 delta = 1;
2568 if (delta) {
2569 sdio_info->fc_rcvd++;
2570 sdio_info->flowcontrol = fcbits;
2573 /* Check and update sequence number */
2574 if (rxseq != seq) {
2575 DBUSINFO(("%s (nextlen): rx_seq %d, expected %d\n",
2576 __FUNCTION__, seq, rxseq));
2577 sdio_info->rx_badseq++;
2578 rxseq = seq;
2581 /* Check window for sanity */
2582 if ((uint8)(txmax - sdio_info->tx_seq) > 0x40) {
2583 if ((sdio_info->bus == SPI_BUS) &&
2584 !(dstatus & STATUS_F2_RX_READY)) {
2585 DBUSERR(("%s: got unlikely tx max %d with tx_seq %d\n",
2586 __FUNCTION__, txmax, sdio_info->tx_seq));
2587 txmax = sdio_info->tx_seq + 2;
2588 } else {
2589 DBUSERR(("%s: got unlikely tx max %d with tx_seq %d\n",
2590 __FUNCTION__, txmax, sdio_info->tx_seq));
2591 txmax = sdio_info->tx_seq + 2;
2594 sdio_info->tx_max = txmax;
2596 if (chan == SDPCM_CONTROL_CHANNEL) {
2597 if (sdio_info->bus == SPI_BUS) {
2598 dbus_sdio_read_control(sdio_info, rxbuf, len, doff);
2599 if (sdio_info->usebufpool) {
2600 dbus_sdcb_pktfree(sdio_info, pkt, FALSE);
2602 continue;
2603 } else {
2604 DBUSERR(("%s (nextlen): readahead on control"
2605 " packet %d?\n", __FUNCTION__, seq));
2606 /* Force retry w/normal header read */
2607 sdio_info->nextlen = 0;
2608 dbus_sdio_rxfail(sdio_info, FALSE, TRUE);
2609 PKTFREE2();
2610 continue;
2614 if ((sdio_info->bus == SPI_BUS) && !sdio_info->usebufpool) {
2615 DBUSERR(("Received %d bytes on %d channel. Running out of "
2616 "rx pktbuf's or not yet malloced.\n", len, chan));
2617 continue;
2620 /* Validate data offset */
2621 if ((doff < SDPCM_HDRLEN) || (doff > len)) {
2622 DBUSERR(("%s (nextlen): bad data offset %d: HW len %d min %d\n",
2623 __FUNCTION__, doff, len, SDPCM_HDRLEN));
2624 PKTFREE2();
2625 ASSERT(0);
2626 dbus_sdio_rxfail(sdio_info, FALSE, FALSE);
2627 continue;
2630 /* All done with this one -- now deliver the packet */
2631 goto deliver;
2633 /* gSPI frames should not be handled in fractions */
2634 if (sdio_info->bus == SPI_BUS) {
2635 break;
2638 /* Read frame header (hardware and software) */
2639 sdret = bcmsdh_recv_buf(sdio_info->sdh, SI_ENUM_BASE, SDIO_FUNC_2, F2SYNC,
2640 sdio_info->rxhdr, firstread, NULL, NULL, NULL);
2641 sdio_info->f2rxhdrs++;
2642 ASSERT(sdret != BCME_PENDING);
2644 if (sdret < 0) {
2645 DBUSERR(("%s: RXHEADER FAILED: %d\n", __FUNCTION__, sdret));
2646 sdio_info->rx_hdrfail++;
2647 dbus_sdio_rxfail(sdio_info, TRUE, TRUE);
2648 continue;
2651 /* Extract hardware header fields */
2652 len = ltoh16_ua(sdio_info->rxhdr);
2653 check = ltoh16_ua(sdio_info->rxhdr + sizeof(uint16));
2655 /* All zeros means no more frames */
2656 if (!(len|check)) {
2657 *finished = TRUE;
2658 break;
2661 /* Validate check bytes */
2662 if ((uint16)~(len^check)) {
2663 DBUSERR(("%s: HW hdr error: len/check 0x%04x/0x%04x\n",
2664 __FUNCTION__, len, check));
2665 sdio_info->rx_badhdr++;
2666 dbus_sdio_rxfail(sdio_info, FALSE, FALSE);
2667 continue;
2670 /* Validate frame length */
2671 if (len < SDPCM_HDRLEN) {
2672 DBUSERR(("%s: HW hdr length invalid: %d\n", __FUNCTION__, len));
2673 continue;
2676 /* Extract software header fields */
2677 chan = SDPCM_PACKET_CHANNEL(&sdio_info->rxhdr[SDPCM_FRAMETAG_LEN]);
2678 seq = SDPCM_PACKET_SEQUENCE(&sdio_info->rxhdr[SDPCM_FRAMETAG_LEN]);
2679 doff = SDPCM_DOFFSET_VALUE(&sdio_info->rxhdr[SDPCM_FRAMETAG_LEN]);
2680 txmax = SDPCM_WINDOW_VALUE(&sdio_info->rxhdr[SDPCM_FRAMETAG_LEN]);
2682 /* Validate data offset */
2683 if ((doff < SDPCM_HDRLEN) || (doff > len)) {
2684 DBUSERR(("%s: Bad data offset %d: HW len %d, min %d seq %d\n",
2685 __FUNCTION__, doff, len, SDPCM_HDRLEN, seq));
2686 sdio_info->rx_badhdr++;
2687 ASSERT(0);
2688 dbus_sdio_rxfail(sdio_info, FALSE, FALSE);
2689 continue;
2692 /* Save the readahead length if there is one */
2693 sdio_info->nextlen = sdio_info->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
2694 if ((sdio_info->nextlen << 4) > MAX_RX_DATASZ) {
2695 DBUSINFO(("%s (nextlen): got frame w/nextlen too large (%d), seq %d\n",
2696 __FUNCTION__, sdio_info->nextlen, seq));
2697 sdio_info->nextlen = 0;
2700 /* Handle Flow Control */
2701 fcbits = SDPCM_FCMASK_VALUE(&sdio_info->rxhdr[SDPCM_FRAMETAG_LEN]);
2703 delta = 0;
2704 if (~sdio_info->flowcontrol & fcbits) {
2705 sdio_info->fc_xoff++;
2706 delta = 1;
2708 if (sdio_info->flowcontrol & ~fcbits) {
2709 sdio_info->fc_xon++;
2710 delta = 1;
2713 if (delta) {
2714 sdio_info->fc_rcvd++;
2715 sdio_info->flowcontrol = fcbits;
2718 /* Check and update sequence number */
2719 if (rxseq != seq) {
2720 DBUSINFO(("%s: rx_seq %d, expected %d\n", __FUNCTION__, seq, rxseq));
2721 sdio_info->rx_badseq++;
2722 rxseq = seq;
2725 /* Check window for sanity */
2726 if ((uint8)(txmax - sdio_info->tx_seq) > 0x40) {
2727 DBUSERR(("%s: got unlikely tx max %d with tx_seq %d\n",
2728 __FUNCTION__, txmax, sdio_info->tx_seq));
2729 txmax = sdio_info->tx_seq + 2;
2731 sdio_info->tx_max = txmax;
2733 /* Call a separate function for control frames */
2734 if (chan == SDPCM_CONTROL_CHANNEL) {
2735 dbus_sdio_read_control(sdio_info, sdio_info->rxhdr, len, doff);
2736 continue;
2739 ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL) ||
2740 (chan == SDPCM_TEST_CHANNEL) || (chan == SDPCM_GLOM_CHANNEL));
2742 /* Length to read */
2743 rdlen = (len > firstread) ? (len - firstread) : 0;
2745 /* May pad read to blocksize for efficiency */
2746 if (sdio_info->roundup && sdio_info->blocksize && (rdlen > sdio_info->blocksize)) {
2747 pad = sdio_info->blocksize - (rdlen % sdio_info->blocksize);
2748 if ((pad <= sdio_info->roundup) && (pad < sdio_info->blocksize) &&
2749 ((rdlen + pad + firstread) < MAX_RX_DATASZ))
2750 rdlen += pad;
2753 /* Satisfy length-alignment requirements */
2754 if (forcealign && (rdlen & (ALIGNMENT - 1)))
2755 rdlen = ROUNDUP(rdlen, ALIGNMENT);
2757 if ((rdlen + firstread) > MAX_RX_DATASZ) {
2758 /* Too long -- skip this frame */
2759 DBUSERR(("%s: too long: len %d rdlen %d\n", __FUNCTION__, len, rdlen));
2760 sdio_info->pub->stats.rx_errors++; sdio_info->rx_toolong++;
2761 dbus_sdio_rxfail(sdio_info, FALSE, FALSE);
2762 continue;
2765 if (!(pkt = dbus_sdcb_pktget(sdio_info, (rdlen + firstread + SDALIGN), FALSE))) {
2766 /* Give up on data, request rtx of events */
2767 DBUSERR(("%s: dbus_sdio_pktget failed: rdlen %d chan %d\n",
2768 __FUNCTION__, rdlen, chan));
2769 sdio_info->pub->stats.rx_dropped++;
2770 dbus_sdio_rxfail(sdio_info, FALSE, RETRYCHAN(chan));
2771 continue;
2774 ASSERT(!PKTLINK(pkt));
2776 /* Leave room for what we already read, and align remainder */
2777 ASSERT(firstread < (PKTLEN(sdio_info->pub->osh, pkt)));
2778 PKTPULL(sdio_info->pub->osh, pkt, firstread);
2779 PKTALIGN(sdio_info->pub->osh, pkt, rdlen, SDALIGN);
2781 /* Read the remaining frame data */
2782 sdret = bcmsdh_recv_buf(sdh, SI_ENUM_BASE, SDIO_FUNC_2, F2SYNC,
2783 ((uint8 *)PKTDATA(osh, pkt)), rdlen, pkt, NULL, NULL);
2784 sdio_info->f2rxdata++;
2785 ASSERT(sdret != BCME_PENDING);
2787 if (sdret < 0) {
2788 DBUSERR(("%s: read %d %s bytes failed: %d\n", __FUNCTION__, rdlen,
2789 ((chan == SDPCM_EVENT_CHANNEL) ? "event" :
2790 ((chan == SDPCM_DATA_CHANNEL) ? "data" : "test")), sdret));
2791 dbus_sdcb_pktfree(sdio_info, pkt, FALSE);
2792 sdio_info->pub->stats.rx_errors++;
2793 dbus_sdio_rxfail(sdio_info, TRUE, RETRYCHAN(chan));
2794 continue;
2797 /* Copy the already-read portion */
2798 PKTPUSH(sdio_info->pub->osh, pkt, firstread);
2799 bcopy(sdio_info->rxhdr, PKTDATA(sdio_info->pub->osh, pkt), firstread);
2801 deliver:
2802 /* Save superframe descriptor and allocate packet frame */
2803 if (chan == SDPCM_GLOM_CHANNEL) {
2804 if (SDPCM_GLOMDESC(&sdio_info->rxhdr[SDPCM_FRAMETAG_LEN])) {
2805 DBUSGLOM(("%s: got glom descriptor, %d bytes:\n",
2806 __FUNCTION__, len));
2807 #ifdef BCMDBG
2808 if (DBUSGLOM_ON()) {
2809 prhex("Glom Data", PKTDATA(sdio_info->pub->osh, pkt), len);
2811 #endif
2812 PKTSETLEN(sdio_info->pub->osh, pkt, len);
2813 ASSERT(doff == SDPCM_HDRLEN);
2814 PKTPULL(sdio_info->pub->osh, pkt, SDPCM_HDRLEN);
2815 sdio_info->glomd = pkt;
2816 } else {
2817 DBUSERR(("%s: glom superframe w/o descriptor!\n", __FUNCTION__));
2818 dbus_sdio_rxfail(sdio_info, FALSE, FALSE);
2820 continue;
2823 /* Fill in packet len and prio, deliver upward */
2824 PKTSETLEN(sdio_info->pub->osh, pkt, len);
2825 PKTPULL(sdio_info->pub->osh, pkt, doff);
2827 #ifdef SDTEST
2828 /* Test channel packets are processed separately */
2829 if (chan == SDPCM_TEST_CHANNEL) {
2830 dbus_sdio_testrcv(sdio_info, pkt, seq);
2831 continue;
2833 #endif /* SDTEST */
2835 if (PKTLEN(sdio_info->pub->osh, pkt) == 0) {
2836 dbus_sdcb_pktfree(sdio_info, pkt, FALSE);
2837 continue;
2840 rxirb = (dbus_irb_rx_t *) dbus_sdcb_getirb(sdio_info, FALSE);
2841 if (rxirb != NULL) {
2842 rxirb->pkt = pkt;
2843 dbus_sdio_recv_irb_complete(sdio_info, rxirb, DBUS_OK);
2844 } else {
2845 DBUSERR(("ERROR: failed to get rx irb\n"));
2846 dbus_sdcb_pktfree(sdio_info, pkt, FALSE);
2850 #ifdef BCMDBG
2851 /* Message if we hit the limit */
2852 if (!rxleft && !sdtest)
2853 DBUSERR(("%s: hit rx limit of %d frames\n", __FUNCTION__, maxframes));
2854 else
2855 #endif /* BCMDBG */
2856 DBUSDATA(("%s: processed %d frames\n", __FUNCTION__, (maxframes - rxleft)));
2858 /* Back off rxseq if awaiting rtx, upate rx_seq */
2859 if (sdio_info->rxskip)
2860 rxseq--;
2861 sdio_info->rx_seq = rxseq;
2863 return (maxframes - rxleft);
2866 static uint32
2867 dbus_sdio_hostmail(sdio_info_t *sdio_info)
2869 sdpcmd_regs_t *regs = sdio_info->regs;
2870 uint32 intstatus = 0;
2871 uint32 hmb_data;
2872 uint8 fcbits;
2873 uint retries = 0;
2875 DBUSTRACE(("%s: Enter\n", __FUNCTION__));
2877 /* Read mailbox data and ack that we did so */
2878 R_SDREG(hmb_data, &regs->tohostmailboxdata, retries);
2879 if (retries <= retry_limit)
2880 W_SDREG(SMB_INT_ACK, &regs->tosbmailbox, retries);
2881 sdio_info->f1regdata += 2;
2883 /* Dongle recomposed rx frames, accept them again */
2884 if (hmb_data & HMB_DATA_NAKHANDLED) {
2885 DBUSINFO(("Dongle reports NAK handled, expect rtx of %d\n", sdio_info->rx_seq));
2886 if (!sdio_info->rxskip) {
2887 DBUSERR(("%s: unexpected NAKHANDLED!\n", __FUNCTION__));
2889 sdio_info->rxskip = FALSE;
2890 intstatus |= I_HMB_FRAME_IND;
2894 * Not using DEVREADY or FWREADY at the moment; just print.
2895 * DEVREADY does not occur with gSPI.
2897 if (hmb_data & (HMB_DATA_DEVREADY | HMB_DATA_FWREADY)) {
2898 sdio_info->sdpcm_ver = (hmb_data & HMB_DATA_VERSION_MASK) >> HMB_DATA_VERSION_SHIFT;
2899 if (sdio_info->sdpcm_ver != SDPCM_PROT_VERSION)
2900 DBUSERR(("Version mismatch, dongle reports %d, expecting %d\n",
2901 sdio_info->sdpcm_ver, SDPCM_PROT_VERSION));
2902 else
2903 DBUSINFO(("Dongle ready, protocol version %d\n", sdio_info->sdpcm_ver));
2907 * Flow Control has been moved into the RX headers and this out of band
2908 * method isn't used any more. Leae this here for possibly remaining backward
2909 * compatible with older dongles
2911 if (hmb_data & HMB_DATA_FC) {
2912 fcbits = (hmb_data & HMB_DATA_FCDATA_MASK) >> HMB_DATA_FCDATA_SHIFT;
2914 if (fcbits & ~sdio_info->flowcontrol)
2915 sdio_info->fc_xoff++;
2916 if (sdio_info->flowcontrol & ~fcbits)
2917 sdio_info->fc_xon++;
2919 sdio_info->fc_rcvd++;
2920 sdio_info->flowcontrol = fcbits;
2923 /* Shouldn't be any others */
2924 if (hmb_data & ~(HMB_DATA_DEVREADY |
2925 HMB_DATA_NAKHANDLED |
2926 HMB_DATA_FC |
2927 HMB_DATA_FWREADY |
2928 HMB_DATA_FCDATA_MASK |
2929 HMB_DATA_VERSION_MASK)) {
2930 DBUSERR(("Unknown mailbox data content: 0x%02x\n", hmb_data));
2933 return intstatus;
2936 #ifndef BCM_DNGL_EMBEDIMAGE
2937 static void
2938 dbus_sdh_devrdy_isr(void *handle)
2940 probe_sdh_info_t *pinfo = handle;
2941 bcmsdh_info_t *sdh = pinfo->sdh;
2942 uint32 intstatus = 0, hmb_data = 0;
2944 if (pinfo->devready == FALSE) {
2945 intstatus = R_REG(pinfo->osh, &pinfo->chinfo->sdregs->intstatus);
2946 if (intstatus & I_HMB_HOST_INT) {
2947 hmb_data = R_REG(pinfo->osh, &pinfo->chinfo->sdregs->tohostmailboxdata);
2948 if (hmb_data & (HMB_DATA_DEVREADY|HMB_DATA_FWREADY)) {
2949 bcmsdh_intr_disable(sdh);
2950 pinfo->devready = TRUE;
2951 dbus_sdos_sched_probe_cb();
2957 #endif /* BCM_DNGL_EMBEDIMAGE */
2959 static void
2960 dbus_sdh_isr(void *handle)
2962 sdio_info_t *sdio_info = (sdio_info_t *) handle;
2963 bool wantdpc;
2965 ASSERT(sdio_info);
2966 ASSERT(sdio_info->sdh);
2968 if (dbus_sdio_isr(sdio_info, &wantdpc) == TRUE) {
2969 bcmsdh_intr_disable(sdio_info->sdh);
2970 sdio_info->intdis = TRUE;
2974 static bool
2975 dbus_sdio_isr(void *handle, bool *wantdpc)
2977 sdio_info_t *sdio_info = (sdio_info_t *) handle;
2978 bool handle_int = FALSE;
2980 DBUSTRACE(("%s: Enter\n", __FUNCTION__));
2984 * NOTE for NDIS:
2986 * Do not use spinlock in isr() to share
2987 * resources with other lower priority functions
2988 * because isr() runs at DIRQL which can preempt
2989 * them and cause race condition/deadlock.
2990 * To share resources with isr() use NdisMSynchronizeWithInterrupt()
2991 * Functions that indirectly use spinlock bcmsdh_reg_read(),
2992 * bcmsdh_intr_disable(), etc.
2995 ASSERT(sdio_info);
2997 *wantdpc = FALSE;
2999 /* Count the interrupt call */
3000 sdio_info->intrcount++;
3001 sdio_info->ipend = TRUE;
3003 /* Shouldn't get this interrupt if we're sleeping? */
3004 if (sdio_info->sleeping) {
3005 DBUSERR(("INTERRUPT WHILE SLEEPING??\n"));
3006 handle_int = FALSE;
3007 goto err;
3010 /* Disable additional interrupts (is this needed now)? */
3011 if (sdio_info->intr) {
3012 DBUSINTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
3013 } else {
3014 DBUSERR(("dbus_sdio_isr() w/o interrupt configured!\n"));
3017 sdio_info->intdis = TRUE;
3019 dbus_sdos_sched_dpc(sdio_info);
3020 sdio_info->dpc_sched = TRUE;
3021 *wantdpc = TRUE;
3023 handle_int = TRUE;
3024 err:
3025 return handle_int;
3028 #ifdef SDTEST
3029 static void
3030 dbus_sdio_pktgen_init(sdio_info_t *sdio_info)
3032 /* Default to specified length, or full range */
3033 if (dhd_pktgen_len) {
3034 sdio_info->pktgen_maxlen = MIN(dhd_pktgen_len, MAX_PKTGEN_LEN);
3035 sdio_info->pktgen_minlen = sdio_info->pktgen_maxlen;
3036 } else {
3037 sdio_info->pktgen_maxlen = MAX_PKTGEN_LEN;
3038 sdio_info->pktgen_minlen = 0;
3040 sdio_info->pktgen_len = (uint16)sdio_info->pktgen_minlen;
3042 /* Default to per-watchdog burst with 10s print time */
3043 sdio_info->pktgen_freq = 1;
3044 sdio_info->pktgen_print = 10000/dhd_watchdog_ms;
3045 sdio_info->pktgen_count = (dhd_pktgen * dhd_watchdog_ms + 999) / 1000;
3047 /* Default to echo mode */
3048 sdio_info->pktgen_mode = DHD_PKTGEN_ECHO;
3049 sdio_info->pktgen_stop = 1;
3052 static void
3053 dbus_sdio_pktgen(sdio_info_t *sdio_info)
3055 void *pkt;
3056 uint8 *data;
3057 uint pktcount;
3058 uint fillbyte;
3059 uint16 len;
3061 /* Display current count if appropriate */
3062 if (sdio_info->pktgen_print && (++sdio_info->pktgen_ptick >= sdio_info->pktgen_print)) {
3063 sdio_info->pktgen_ptick = 0;
3064 printf("%s: send attempts %d rcvd %d\n",
3065 __FUNCTION__, sdio_info->pktgen_sent, sdio_info->pktgen_rcvd);
3068 /* For recv mode, just make sure dongle has started sending */
3069 if (sdio_info->pktgen_mode == DHD_PKTGEN_RECV) {
3070 if (!sdio_info->pktgen_rcvd)
3071 dbus_sdio_sdtest_set(sdio_info, TRUE);
3072 return;
3075 /* Otherwise, generate or request the specified number of packets */
3076 for (pktcount = 0; pktcount < sdio_info->pktgen_count; pktcount++) {
3077 /* Stop if total has been reached */
3078 if (sdio_info->pktgen_total &&
3079 (sdio_info->pktgen_sent >= sdio_info->pktgen_total)) {
3080 sdio_info->pktgen_count = 0;
3081 break;
3084 /* Allocate an appropriate-sized packet */
3085 len = sdio_info->pktgen_len;
3086 if (!(pkt = dbus_sdcb_pktget(sdio_info,
3087 (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + SDALIGN), TRUE))) {
3088 DBUSERR(("%s: dbus_sdio_pktget failed!\n", __FUNCTION__));
3089 break;
3091 PKTALIGN(sdio_info->pub->osh, pkt,
3092 (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN), SDALIGN);
3093 data = (uint8*)PKTDATA(sdio_info->pub->osh, pkt) + SDPCM_HDRLEN;
3095 /* Write test header cmd and extra based on mode */
3096 switch (sdio_info->pktgen_mode) {
3097 case DHD_PKTGEN_ECHO:
3098 *data++ = SDPCM_TEST_ECHOREQ;
3099 *data++ = (uint8)sdio_info->pktgen_sent;
3100 break;
3102 case DHD_PKTGEN_SEND:
3103 *data++ = SDPCM_TEST_DISCARD;
3104 *data++ = (uint8)sdio_info->pktgen_sent;
3105 break;
3107 case DHD_PKTGEN_RXBURST:
3108 *data++ = SDPCM_TEST_BURST;
3109 *data++ = (uint8)sdio_info->pktgen_count;
3110 break;
3112 default:
3113 DBUSERR(("Unrecognized pktgen mode %d\n", sdio_info->pktgen_mode));
3114 dbus_sdcb_pktfree(sdio_info, pkt, TRUE);
3115 sdio_info->pktgen_count = 0;
3116 return;
3119 /* Write test header length field */
3120 *data++ = (len >> 0);
3121 *data++ = (len >> 8);
3123 /* Then fill in the remainder -- N/A for burst, but who cares... */
3124 for (fillbyte = 0; fillbyte < len; fillbyte++)
3125 *data++ = SDPCM_TEST_FILL(fillbyte, (uint8)sdio_info->pktgen_sent);
3127 /* Send it */
3128 if (dbus_sdio_txpkt(sdio_info, pkt, SDPCM_TEST_CHANNEL)) {
3129 sdio_info->pktgen_fail++;
3130 if (sdio_info->pktgen_stop &&
3131 sdio_info->pktgen_stop == sdio_info->pktgen_fail)
3132 sdio_info->pktgen_count = 0;
3134 sdio_info->pktgen_sent++;
3136 /* Bump length if not fixed, wrap at max */
3137 if (++sdio_info->pktgen_len > sdio_info->pktgen_maxlen)
3138 sdio_info->pktgen_len = (uint16)sdio_info->pktgen_minlen;
3140 /* Special case for burst mode: just send one request! */
3141 if (sdio_info->pktgen_mode == DHD_PKTGEN_RXBURST)
3142 break;
3146 static void
3147 dbus_sdio_sdtest_set(sdio_info_t *sdio_info, bool start)
3149 void *pkt;
3150 uint8 *data;
3152 /* Allocate the packet */
3153 if (!(pkt = dbus_sdcb_pktget(sdio_info,
3154 SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + SDALIGN, TRUE))) {
3155 DBUSERR(("%s: dbus_sdio_pktget failed!\n", __FUNCTION__));
3156 return;
3158 PKTALIGN(sdio_info->pub->osh, pkt, (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN), SDALIGN);
3159 data = (uint8*)PKTDATA(sdio_info->pub->osh, pkt) + SDPCM_HDRLEN;
3161 /* Fill in the test header */
3162 *data++ = SDPCM_TEST_SEND;
3163 *data++ = start;
3164 *data++ = (sdio_info->pktgen_maxlen >> 0);
3165 *data++ = (sdio_info->pktgen_maxlen >> 8);
3167 /* Send it */
3168 if (dbus_sdio_txpkt(sdio_info, pkt, SDPCM_TEST_CHANNEL))
3169 sdio_info->pktgen_fail++;
3173 static void
3174 dbus_sdio_testrcv(sdio_info_t *sdio_info, void *pkt, uint seq)
3176 osl_t *osh;
3177 uint8 *data;
3178 uint pktlen;
3179 uint8 cmd;
3180 uint8 extra;
3181 uint16 len;
3182 uint16 offset;
3184 osh = sdio_info->pub->osh;
3186 /* Check for min length */
3187 if ((pktlen = PKTLEN(sdio_info->pub->osh, pkt)) < SDPCM_TEST_HDRLEN) {
3188 DBUSERR(("dbus_sdio_restrcv: toss runt frame, pktlen %d\n", pktlen));
3189 dbus_sdcb_pktfree(sdio_info, pkt, FALSE);
3190 return;
3193 /* Extract header fields */
3194 data = PKTDATA(sdio_info->pub->osh, pkt);
3195 cmd = *data++;
3196 extra = *data++;
3197 len = *data++; len += *data++ << 8;
3199 /* Check length for relevant commands */
3200 if (cmd == SDPCM_TEST_DISCARD || cmd == SDPCM_TEST_ECHOREQ || cmd == SDPCM_TEST_ECHORSP) {
3201 if (pktlen != len + SDPCM_TEST_HDRLEN) {
3202 DBUSERR(("dbus_sdio_testrcv: frame length mismatch, pktlen %d seq %d"
3203 " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len));
3204 dbus_sdcb_pktfree(sdio_info, pkt, FALSE);
3205 return;
3209 /* Process as per command */
3210 switch (cmd) {
3211 case SDPCM_TEST_ECHOREQ:
3212 /* Rx->Tx turnaround ok (even on NDIS w/current implementation) */
3213 *(uint8 *)(PKTDATA(sdio_info->pub->osh, pkt)) = SDPCM_TEST_ECHORSP;
3214 if (dbus_sdio_txpkt(sdio_info, pkt, SDPCM_TEST_CHANNEL) == 0) {
3215 sdio_info->pktgen_sent++;
3216 } else {
3217 sdio_info->pktgen_fail++;
3218 dbus_sdcb_pktfree(sdio_info, pkt, FALSE);
3220 sdio_info->pktgen_rcvd++;
3221 break;
3223 case SDPCM_TEST_ECHORSP:
3224 if (sdio_info->ext_loop) {
3225 dbus_sdcb_pktfree(sdio_info, pkt, FALSE);
3226 sdio_info->pktgen_rcvd++;
3227 break;
3230 for (offset = 0; offset < len; offset++, data++) {
3231 if (*data != SDPCM_TEST_FILL(offset, extra)) {
3232 DBUSERR(("dbus_sdio_testrcv: echo data mismatch: "
3233 "offset %d (len %d) expect 0x%02x rcvd 0x%02x\n",
3234 offset, len, SDPCM_TEST_FILL(offset, extra), *data));
3235 break;
3238 dbus_sdcb_pktfree(sdio_info, pkt, FALSE);
3239 sdio_info->pktgen_rcvd++;
3240 break;
3242 case SDPCM_TEST_DISCARD:
3243 dbus_sdcb_pktfree(sdio_info, pkt, FALSE);
3244 sdio_info->pktgen_rcvd++;
3245 break;
3247 case SDPCM_TEST_BURST:
3248 case SDPCM_TEST_SEND:
3249 default:
3250 DBUSINFO(("dbus_sdio_testrcv: unsupported or unknown command, pktlen %d seq %d"
3251 " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len));
3252 dbus_sdcb_pktfree(sdio_info, pkt, FALSE);
3253 break;
3256 /* For recv mode, stop at limie (and tell dongle to stop sending) */
3257 if (sdio_info->pktgen_mode == DHD_PKTGEN_RECV) {
3258 if (sdio_info->pktgen_total &&
3259 (sdio_info->pktgen_rcvd >= sdio_info->pktgen_total)) {
3260 sdio_info->pktgen_count = 0;
3261 dbus_sdio_sdtest_set(sdio_info, FALSE);
3265 #endif /* SDTEST */
3267 #ifdef SDTEST
3268 static int
3269 dbus_sdio_pktgen_get(sdio_info_t *sdio_info, uint8 *arg)
3271 dhd_pktgen_t pktgen;
3273 pktgen.version = DHD_PKTGEN_VERSION;
3274 pktgen.freq = sdio_info->pktgen_freq;
3275 pktgen.count = sdio_info->pktgen_count;
3276 pktgen.print = sdio_info->pktgen_print;
3277 pktgen.total = sdio_info->pktgen_total;
3278 pktgen.minlen = sdio_info->pktgen_minlen;
3279 pktgen.maxlen = sdio_info->pktgen_maxlen;
3280 pktgen.numsent = sdio_info->pktgen_sent;
3281 pktgen.numrcvd = sdio_info->pktgen_rcvd;
3282 pktgen.numfail = sdio_info->pktgen_fail;
3283 pktgen.mode = sdio_info->pktgen_mode;
3284 pktgen.stop = sdio_info->pktgen_stop;
3286 bcopy(&pktgen, arg, sizeof(pktgen));
3288 return 0;
3291 static int
3292 dbus_sdio_pktgen_set(sdio_info_t *sdio_info, uint8 *arg)
3294 dhd_pktgen_t pktgen;
3295 uint oldcnt, oldmode;
3297 bcopy(arg, &pktgen, sizeof(pktgen));
3298 if (pktgen.version != DHD_PKTGEN_VERSION)
3299 return BCME_BADARG;
3301 oldcnt = sdio_info->pktgen_count;
3302 oldmode = sdio_info->pktgen_mode;
3304 sdio_info->pktgen_freq = pktgen.freq;
3305 sdio_info->pktgen_count = pktgen.count;
3306 sdio_info->pktgen_print = pktgen.print;
3307 sdio_info->pktgen_total = pktgen.total;
3308 sdio_info->pktgen_minlen = pktgen.minlen;
3309 sdio_info->pktgen_maxlen = pktgen.maxlen;
3310 sdio_info->pktgen_mode = pktgen.mode;
3311 sdio_info->pktgen_stop = pktgen.stop;
3313 sdio_info->pktgen_tick = sdio_info->pktgen_ptick = 0;
3314 sdio_info->pktgen_len = MAX(sdio_info->pktgen_len, sdio_info->pktgen_minlen);
3315 sdio_info->pktgen_len = MIN(sdio_info->pktgen_len, sdio_info->pktgen_maxlen);
3317 /* Clear counts for a new pktgen (mode change, or was stopped) */
3318 if (sdio_info->pktgen_count && (!oldcnt || oldmode != sdio_info->pktgen_mode))
3319 sdio_info->pktgen_sent = sdio_info->pktgen_rcvd = sdio_info->pktgen_fail = 0;
3321 return 0;
3323 #endif /* SDTEST */
3325 static int
3326 dbus_sdio_membytes(probe_sdh_info_t *pinfo, bool write, uint32 address, uint8 *data, uint size)
3328 int bcmerror = 0;
3329 uint32 sdaddr;
3330 uint dsize;
3331 bcmsdh_info_t *sdh;
3333 ASSERT(pinfo->sdh);
3334 sdh = pinfo->sdh;
3336 /* Determine initial transfer parameters */
3337 sdaddr = address & SBSDIO_SB_OFT_ADDR_MASK;
3338 if ((sdaddr + size) & SBSDIO_SBWINDOW_MASK)
3339 dsize = (SBSDIO_SB_OFT_ADDR_LIMIT - sdaddr);
3340 else
3341 dsize = size;
3343 /* Set the backplane window to include the start address */
3344 if ((bcmerror = bcmsdhsdio_set_sbaddr_window(sdh, address, TRUE))) {
3345 DBUSERR(("%s: window change failed\n", __FUNCTION__));
3346 goto xfer_done;
3349 /* Do the transfer(s) */
3350 while (size) {
3351 DBUSINFO(("%s: %s %d bytes at offset 0x%08x in window 0x%08x\n",
3352 __FUNCTION__, (write ? "write" : "read"), dsize, sdaddr,
3353 (address & SBSDIO_SBWINDOW_MASK)));
3354 if ((bcmerror = bcmsdh_rwdata(sdh, write, sdaddr, data, dsize))) {
3355 DBUSERR(("%s: membytes transfer failed\n", __FUNCTION__));
3356 break;
3359 /* Adjust for next transfer (if any) */
3360 if ((size -= dsize)) {
3361 data += dsize;
3362 address += dsize;
3363 if ((bcmerror = bcmsdhsdio_set_sbaddr_window(sdh, address, FALSE))) {
3364 DBUSERR(("%s: window change failed\n", __FUNCTION__));
3365 break;
3367 sdaddr = 0;
3368 dsize = MIN(SBSDIO_SB_OFT_ADDR_LIMIT, size);
3372 xfer_done:
3373 /* Return the window to backplane enumeration space for core access */
3374 if (bcmsdhsdio_set_sbaddr_window(sdh, SI_ENUM_BASE, FALSE)) {
3375 DBUSERR(("%s: FAILED to return to SI_ENUM_BASE\n", __FUNCTION__));
3378 return bcmerror;
3381 static int
3382 dbus_sdio_downloadvars(probe_sdh_info_t *pinfo, void *arg, int len)
3384 int bcmerror = BCME_OK;
3386 if (!len) {
3387 bcmerror = BCME_BUFTOOSHORT;
3388 goto err;
3391 if (pinfo->vars) {
3392 MFREE(pinfo->osh, pinfo->vars, pinfo->varsz);
3393 pinfo->vars = NULL;
3394 pinfo->varsz = 0;
3396 pinfo->vars = MALLOC(pinfo->osh, len);
3397 pinfo->varsz = pinfo->vars ? len : 0;
3398 if (pinfo->vars == NULL) {
3399 pinfo->varsz = 0;
3400 bcmerror = BCME_NOMEM;
3401 goto err;
3403 bcopy(arg, pinfo->vars, pinfo->varsz);
3404 err:
3405 return bcmerror;
3408 static int
3409 dbus_sdio_doiovar(sdio_info_t *sdio_info, const bcm_iovar_t *vi, uint32 actionid, const char *name,
3410 void *params, int plen, void *arg, int len, int val_size)
3412 int bcmerror = 0;
3413 int32 int_val = 0;
3414 bool bool_val;
3416 DBUSTRACE(("%s: Enter, action %d name %s params %p plen %d arg %p len %d val_size %d\n",
3417 __FUNCTION__, actionid, name, params, plen, arg, len, val_size));
3419 if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0)
3420 goto exit;
3422 if (plen >= (int)sizeof(int_val))
3423 bcopy(params, &int_val, sizeof(int_val));
3425 bool_val = (int_val != 0) ? TRUE : FALSE;
3428 /* Some ioctls use the bus */
3429 /* Check if dongle is in reset. If so, only allow DEVRESET iovars */
3430 if (sdio_info->dongle_reset && !(actionid == IOV_SVAL(IOV_DEVRESET) ||
3431 actionid == IOV_GVAL(IOV_DEVRESET))) {
3432 bcmerror = BCME_NOTREADY;
3433 goto exit;
3436 /* Handle sleep stuff before any clock mucking */
3437 if (vi->varid == IOV_SLEEP) {
3438 if (IOV_ISSET(actionid)) {
3439 bcmerror = dbus_sdio_bussleep(sdio_info, bool_val);
3440 } else {
3441 int_val = (int32)sdio_info->sleeping;
3442 bcopy(&int_val, arg, val_size);
3444 goto exit;
3447 /* Request clock to allow SDIO accesses */
3448 if (!sdio_info->dongle_reset) {
3449 BUS_WAKE(sdio_info);
3450 dbus_sdio_clkctl(sdio_info, CLK_AVAIL, FALSE);
3453 switch (actionid) {
3454 case IOV_GVAL(IOV_INTR):
3455 int_val = (int32)sdio_info->intr;
3456 bcopy(&int_val, arg, val_size);
3457 break;
3459 case IOV_SVAL(IOV_INTR):
3460 sdio_info->intr = bool_val;
3461 sdio_info->intdis = FALSE;
3463 /* FIX: Change to use busstate instead of up flag */
3464 if (sdio_info->up) {
3465 if (sdio_info->intr) {
3466 DBUSINTR(("%s: enable SDIO device interrupts\n", __FUNCTION__));
3467 bcmsdh_intr_enable(sdio_info->sdh);
3468 } else {
3469 DBUSINTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
3470 bcmsdh_intr_disable(sdio_info->sdh);
3473 break;
3475 case IOV_GVAL(IOV_POLLRATE):
3476 int_val = (int32)sdio_info->pollrate;
3477 bcopy(&int_val, arg, val_size);
3478 break;
3480 case IOV_SVAL(IOV_POLLRATE):
3481 sdio_info->pollrate = (uint)int_val;
3482 sdio_info->poll = (sdio_info->pollrate != 0);
3483 break;
3485 case IOV_GVAL(IOV_IDLETIME):
3486 int_val = sdio_info->idletime;
3487 bcopy(&int_val, arg, val_size);
3488 break;
3490 case IOV_SVAL(IOV_IDLETIME):
3491 if ((int_val < 0) && (int_val != IDLE_IMMEDIATE)) {
3492 bcmerror = BCME_BADARG;
3493 } else {
3494 sdio_info->idletime = int_val;
3496 break;
3498 case IOV_GVAL(IOV_IDLECLOCK):
3499 int_val = (int32)sdio_info->idleclock;
3500 bcopy(&int_val, arg, val_size);
3501 break;
3503 case IOV_SVAL(IOV_IDLECLOCK):
3504 sdio_info->idleclock = int_val;
3505 break;
3507 case IOV_GVAL(IOV_SD1IDLE):
3508 int_val = (int32)sd1idle;
3509 bcopy(&int_val, arg, val_size);
3510 break;
3512 case IOV_SVAL(IOV_SD1IDLE):
3513 sd1idle = bool_val;
3514 break;
3516 case IOV_SVAL(IOV_MEMBYTES):
3517 case IOV_GVAL(IOV_MEMBYTES):
3519 uint32 address;
3520 uint size, dsize;
3521 uint8 *data;
3523 bool set = (actionid == IOV_SVAL(IOV_MEMBYTES));
3525 ASSERT(plen >= 2*sizeof(int));
3527 address = (uint32)int_val;
3528 bcopy((char *)params + sizeof(int_val), &int_val, sizeof(int_val));
3529 size = (uint)int_val;
3531 /* Do some validation */
3532 dsize = set ? plen - (2 * sizeof(int)) : len;
3533 if (dsize < size) {
3534 DBUSERR(("%s: error on %s membytes, addr 0x%08x size %d dsize %d\n",
3535 __FUNCTION__, (set ? "set" : "get"), address, size, dsize));
3536 bcmerror = BCME_BADARG;
3537 break;
3540 DBUSINFO(("%s: Request to %s %d bytes at address 0x%08x\n", __FUNCTION__,
3541 (set ? "write" : "read"), size, address));
3543 /* If we know about SOCRAM, check for a fit */
3544 if ((sdio_info->orig_ramsize) &&
3545 ((address > sdio_info->orig_ramsize) ||
3546 (address + size > sdio_info->orig_ramsize))) {
3547 DBUSERR(("%s: ramsize 0x%08x doesn't have %d bytes at 0x%08x\n",
3548 __FUNCTION__, sdio_info->orig_ramsize, size, address));
3549 bcmerror = BCME_BADARG;
3550 break;
3553 /* Generate the actual data pointer */
3554 data = set ? (uint8*)params + 2 * sizeof(int): (uint8*)arg;
3556 /* Call to do the transfer */
3557 bcmerror = dbus_sdio_membytes(&g_probe_info, set, address, data, size);
3559 break;
3562 case IOV_GVAL(IOV_MEMSIZE):
3563 int_val = (int32)sdio_info->ramsize;
3564 bcopy(&int_val, arg, val_size);
3565 break;
3567 case IOV_GVAL(IOV_SDIOD_DRIVE):
3568 int_val = (int32)dhd_sdiod_drive_strength;
3569 bcopy(&int_val, arg, val_size);
3570 break;
3572 case IOV_SVAL(IOV_SDIOD_DRIVE):
3573 dhd_sdiod_drive_strength = int_val;
3574 si_sdiod_drive_strength_init(sdio_info->sih,
3575 sdio_info->pub->osh, dhd_sdiod_drive_strength);
3576 break;
3578 case IOV_SVAL(IOV_SET_DOWNLOAD_STATE):
3579 bcmerror = dbus_sdio_download_state(&g_probe_info, bool_val);
3581 #ifndef BCM_DNGL_EMBEDIMAGE
3582 if ((bool_val == FALSE) && (delay_eth == 0)) {
3583 g_probe_info.devready = TRUE;
3584 sdio_info->pub->busstate = DBUS_STATE_DL_DONE;
3586 #endif
3587 break;
3589 case IOV_SVAL(IOV_VARS):
3590 bcmerror = dbus_sdio_downloadvars(&g_probe_info, arg, len);
3591 break;
3593 case IOV_GVAL(IOV_READAHEAD):
3594 int_val = (int32)dhd_readahead;
3595 bcopy(&int_val, arg, val_size);
3596 break;
3598 case IOV_SVAL(IOV_READAHEAD):
3599 if (bool_val && !dhd_readahead)
3600 sdio_info->nextlen = 0;
3601 dhd_readahead = bool_val;
3602 break;
3604 case IOV_GVAL(IOV_SDRXCHAIN):
3605 int_val = (int32)sdio_info->use_rxchain;
3606 bcopy(&int_val, arg, val_size);
3607 break;
3609 case IOV_SVAL(IOV_SDRXCHAIN):
3610 if (bool_val && !sdio_info->sd_rxchain)
3611 bcmerror = BCME_UNSUPPORTED;
3612 else
3613 sdio_info->use_rxchain = bool_val;
3614 break;
3616 case IOV_GVAL(IOV_ALIGNCTL):
3617 int_val = (int32)dhd_alignctl;
3618 bcopy(&int_val, arg, val_size);
3619 break;
3621 case IOV_SVAL(IOV_ALIGNCTL):
3622 dhd_alignctl = bool_val;
3623 break;
3625 case IOV_GVAL(IOV_SDALIGN):
3626 int_val = SDALIGN;
3627 bcopy(&int_val, arg, val_size);
3628 break;
3630 #ifdef BCMDBG
3631 case IOV_GVAL(IOV_VARS):
3632 if (sdio_info->varsz < (uint)len)
3633 bcopy(sdio_info->vars, arg, sdio_info->varsz);
3634 else
3635 bcmerror = BCME_BUFTOOSHORT;
3636 break;
3637 #endif /* BCMDBG */
3639 #ifdef BCMDBG
3640 case IOV_GVAL(IOV_SDREG):
3642 sdreg_t *sd_ptr;
3643 uint32 addr, size;
3645 sd_ptr = (sdreg_t *)params;
3647 addr = (uintptr)sdio_info->regs + sd_ptr->offset;
3648 size = sd_ptr->func;
3649 int_val = (int32)bcmsdh_reg_read(sdio_info->sdh, addr, size);
3650 if (bcmsdh_regfail(sdio_info->sdh))
3651 bcmerror = BCME_SDIO_ERROR;
3652 bcopy(&int_val, arg, sizeof(int32));
3653 break;
3656 case IOV_SVAL(IOV_SDREG):
3658 sdreg_t *sd_ptr;
3659 uint32 addr, size;
3661 sd_ptr = (sdreg_t *)params;
3663 addr = (uintptr)sdio_info->regs + sd_ptr->offset;
3664 size = sd_ptr->func;
3665 bcmsdh_reg_write(sdio_info->sdh, addr, size, sd_ptr->value);
3666 if (bcmsdh_regfail(sdio_info->sdh))
3667 bcmerror = BCME_SDIO_ERROR;
3668 break;
3671 /* Same as above, but offset is not backplane (not SDIO core) */
3672 case IOV_GVAL(IOV_SBREG):
3674 sdreg_t *sd_ptr;
3675 uint32 addr, size;
3677 sd_ptr = (sdreg_t *)params;
3679 addr = SI_ENUM_BASE + sd_ptr->offset;
3680 size = sd_ptr->func;
3681 int_val = (int32)bcmsdh_reg_read(sdio_info->sdh, addr, size);
3682 if (bcmsdh_regfail(sdio_info->sdh))
3683 bcmerror = BCME_SDIO_ERROR;
3684 bcopy(&int_val, arg, sizeof(int32));
3685 break;
3688 case IOV_SVAL(IOV_SBREG):
3690 sdreg_t *sd_ptr;
3691 uint32 addr, size;
3693 sd_ptr = (sdreg_t *)params;
3695 addr = SI_ENUM_BASE + sd_ptr->offset;
3696 size = sd_ptr->func;
3697 bcmsdh_reg_write(sdio_info->sdh, addr, size, sd_ptr->value);
3698 if (bcmsdh_regfail(sdio_info->sdh))
3699 bcmerror = BCME_SDIO_ERROR;
3700 break;
3703 case IOV_GVAL(IOV_SDCIS):
3705 *(char *)arg = 0;
3707 bcmstrcat(arg, "\nFunc 0\n");
3708 bcmsdh_cis_read(sdio_info->sdh, 0x10, (char *)arg + strlen(arg), 49 * 32);
3709 bcmstrcat(arg, "\nFunc 1\n");
3710 bcmsdh_cis_read(sdio_info->sdh, 0x11, (char *)arg + strlen(arg), 49 * 32);
3711 bcmstrcat(arg, "\nFunc 2\n");
3712 bcmsdh_cis_read(sdio_info->sdh, 0x12, (char *)arg + strlen(arg), 49 * 32);
3713 break;
3716 case IOV_GVAL(IOV_FORCEEVEN):
3717 int_val = (int32)forcealign;
3718 bcopy(&int_val, arg, val_size);
3719 break;
3721 case IOV_SVAL(IOV_FORCEEVEN):
3722 forcealign = bool_val;
3723 break;
3725 case IOV_GVAL(IOV_TXBOUND):
3726 int_val = (int32)dhd_txbound;
3727 bcopy(&int_val, arg, val_size);
3728 break;
3730 case IOV_SVAL(IOV_TXBOUND):
3731 dhd_txbound = (uint)int_val;
3732 break;
3734 case IOV_GVAL(IOV_RXBOUND):
3735 int_val = (int32)dhd_rxbound;
3736 bcopy(&int_val, arg, val_size);
3737 break;
3739 case IOV_SVAL(IOV_RXBOUND):
3740 dhd_rxbound = (uint)int_val;
3741 break;
3742 #endif /* BCMDBG */
3744 #if defined(BCMDBG) || defined(DHD_SPROM)
3745 case IOV_SVAL(IOV_SPROM):
3746 case IOV_GVAL(IOV_SPROM):
3748 uint32 offset;
3749 uint size, dsize;
3751 bool set = (actionid == IOV_SVAL(IOV_SPROM));
3753 ASSERT(plen >= 2*sizeof(int));
3755 offset = (uint32)int_val;
3756 bcopy((char *)params + sizeof(int_val), &int_val, sizeof(int_val));
3757 size = (uint)int_val;
3759 /* Avoid bigger size of srom reads that may be requested from app.
3760 * gSPI has only F1 OTP visible from CC. There is no CIS in gSPI.
3762 if (sdio_info->bus == SPI_BUS)
3763 size = SBSDIO_CIS_SIZE_LIMIT;
3765 /* Do some validation */
3766 dsize = set ? plen - (2 * sizeof(int)) : len;
3767 if (dsize < size) {
3768 DBUSERR(("%s: error on srom %s, addr 0x%08x size %d dsize %d\n",
3769 __FUNCTION__, (set ? "write" : "read"), offset, size, dsize));
3770 bcmerror = BCME_BADARG;
3771 break;
3774 if ((offset > SROM_MAX) || ((offset + size) > SROM_MAX)) {
3775 DBUSERR(("%s: error on srom %s, offset %d size %d exceeds limit %d\n",
3776 __FUNCTION__, (set ? "write" : "read"), offset, size, SROM_MAX));
3777 bcmerror = BCME_BADARG;
3778 break;
3781 if (!set) {
3782 if (!ISALIGNED(arg, sizeof(uint16))) {
3783 DBUSERR(("%s: srom data pointer %p not word-aligned\n",
3784 __FUNCTION__, arg));
3785 bcmerror = BCME_BADARG;
3786 break;
3788 bcmerror = srom_read(sdio_info->sih, SD_BUSTYPE,
3789 (void*)sdio_info->regs, sdio_info->pub->osh,
3790 offset, size, (uint16*)arg, FALSE);
3792 } else {
3793 arg = (void*)((uintptr)arg + 2 * sizeof(int));
3794 if (!ISALIGNED(arg, sizeof(uint16))) {
3795 DBUSERR(("%s: srom data pointer %p not word-aligned\n",
3796 __FUNCTION__, arg));
3797 bcmerror = BCME_BADARG;
3798 break;
3800 bcmerror = srom_write(sdio_info->sih, SD_BUSTYPE,
3801 (void*)sdio_info->regs, sdio_info->pub->osh,
3802 offset, size, (uint16*)arg);
3804 break;
3806 #endif
3808 #ifdef SDTEST
3809 case IOV_GVAL(IOV_EXTLOOP):
3810 int_val = (int32)sdio_info->ext_loop;
3811 bcopy(&int_val, arg, val_size);
3812 break;
3814 case IOV_SVAL(IOV_EXTLOOP):
3815 sdio_info->ext_loop = bool_val;
3816 break;
3818 case IOV_GVAL(IOV_PKTGEN):
3819 bcmerror = dbus_sdio_pktgen_get(sdio_info, arg);
3820 break;
3822 case IOV_SVAL(IOV_PKTGEN):
3823 bcmerror = dbus_sdio_pktgen_set(sdio_info, arg);
3824 break;
3825 #endif /* SDTEST */
3828 case IOV_SVAL(IOV_DEVRESET):
3829 DBUSTRACE(("%s: Called set IOV_DEVRESET=%d dongle_reset=%d busstate=%d\n",
3830 __FUNCTION__, bool_val, sdio_info->dongle_reset,
3831 sdio_info->pub->busstate));
3833 ASSERT(sdio_info->pub->osh);
3835 /* FIX: Need to change to support async probe callback.
3837 DBUSERR(("DEVRESET unsupported for async probe callback \n"));
3838 break;
3840 if (bool_val == TRUE) {
3841 if (sdio_info->dongle_reset)
3842 break;
3843 /* Expect app to have torn down any connection before calling */
3844 /* Stop the bus, disable F2 */
3845 dbus_bus_stop(sdio_info);
3847 /* Release tx/rx buffer, detach from the dongle */
3848 dbus_sdio_release_dongle(sdio_info, sdio_info->pub->osh);
3849 dbus_sdio_probe_deinit(&g_probe_info);
3851 sdio_info->dongle_reset = TRUE;
3852 sdio_info->up = FALSE;
3854 DBUSTRACE(("%s: WLAN OFF DONE\n", __FUNCTION__));
3855 /* App can now remove power from device */
3856 } else {
3857 /* App must have restored power to device before calling */
3859 DBUSTRACE(("\n\n%s: == WLAN ON ==\n", __FUNCTION__));
3861 if (!sdio_info->dongle_reset) {
3862 bcmerror = BCME_NOTDOWN;
3863 DBUSERR(("%s: Set DEVRESET=FALSE invoked when device is on\n",
3864 __FUNCTION__));
3865 break;
3868 /* Turn on WLAN */
3869 /* Reset SD client */
3870 bcmsdh_reset(sdio_info->sdh);
3872 /* Attempt to re-attach & download */
3873 if (dbus_sdio_probe_init(&g_probe_info)) {
3874 /* Attempt to download binary to the dongle */
3875 if ((dbus_sdio_attach_init(sdio_info, sdio_info->sdh,
3876 sdio_info->firmware_path, sdio_info->nvram_path))) {
3877 /* Re-init bus, enable F2 transfer */
3878 dbus_sdio_init(sdio_info);
3880 sdio_info->dongle_reset = FALSE;
3881 sdio_info->up = TRUE;
3882 DBUSTRACE(("%s: == WLAN ON DONE ===\n",
3883 __FUNCTION__));
3884 } else
3885 bcmerror = BCME_SDIO_ERROR;
3886 } else
3887 bcmerror = BCME_SDIO_ERROR;
3889 break;
3891 case IOV_GVAL(IOV_DEVRESET):
3892 DBUSTRACE(("%s: Called get IOV_DEVRESET\n", __FUNCTION__));
3894 /* Get its status */
3895 int_val = (bool) sdio_info->dongle_reset;
3896 bcopy(&int_val, arg, val_size);
3898 break;
3900 default:
3901 bcmerror = BCME_UNSUPPORTED;
3902 break;
3905 exit:
3906 if ((sdio_info->idletime == IDLE_IMMEDIATE) && !sdio_info->dpc_sched) {
3907 sdio_info->activity = FALSE;
3908 dbus_sdio_clkctl(sdio_info, CLK_NONE, TRUE);
3911 return bcmerror;
3914 static int
3915 dbus_sdio_write_vars(probe_sdh_info_t *pinfo)
3917 int bcmerror = 0;
3918 uint32 varsize;
3919 uint32 varaddr;
3920 char *vbuffer;
3921 uint32 varsizew;
3923 if (!pinfo->varsz || !pinfo->vars)
3924 return BCME_OK;
3926 varsize = ROUNDUP(pinfo->varsz, 4);
3927 varaddr = (pinfo->ramsize - 4) - varsize;
3929 vbuffer = (char*)MALLOC(pinfo->osh, varsize);
3930 if (!vbuffer)
3931 return BCME_NOMEM;
3933 bzero(vbuffer, varsize);
3934 bcopy(pinfo->vars, vbuffer, pinfo->varsz);
3936 /* Write the vars list */
3937 bcmerror = dbus_sdio_membytes(pinfo, TRUE, varaddr, vbuffer, varsize);
3939 MFREE(pinfo->osh, vbuffer, varsize);
3941 /* adjust to the user specified RAM */
3942 DBUSINFO(("origram size is %d and used ramsize is %d, vars are at %d, orig varsize is %d\n",
3943 pinfo->orig_ramsize, pinfo->ramsize, varaddr, varsize));
3944 varsize = ((pinfo->orig_ramsize - 4) - varaddr);
3945 varsizew = varsize >> 2;
3946 DBUSINFO(("new varsize is %d, varsizew is %d\n", varsize, varsizew));
3948 /* Write the length to the last word */
3949 if (bcmerror) {
3950 varsizew = 0;
3951 DBUSINFO(("bcmerror : Varsizew is being written as %d\n", varsizew));
3952 dbus_sdio_membytes(pinfo, TRUE, (pinfo->orig_ramsize - 4), (uint8*)&varsizew, 4);
3953 } else {
3954 DBUSINFO(("Varsize is %d and varsizew is %d\n", varsize, varsizew));
3955 varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF);
3956 varsizew = htol32(varsizew);
3957 DBUSINFO(("Varsizew is 0x%x and htol is 0x%x\n", varsizew, htol32(varsizew)));
3958 bcmerror = dbus_sdio_membytes(pinfo, TRUE, (pinfo->orig_ramsize - 4),
3959 (uint8*)&varsizew, 4);
3962 return bcmerror;
3965 static int
3966 dbus_sdio_download_state(probe_sdh_info_t *pinfo, bool enter)
3968 int bcmerror = 0;
3969 si_t *sih;
3971 ASSERT(pinfo->sih);
3972 ASSERT(pinfo->sdh);
3974 sih = pinfo->sih;
3976 /* To enter download state, disable ARM and reset SOCRAM.
3977 * To exit download state, simply reset ARM (default is RAM boot).
3979 if (enter) {
3981 pinfo->alp_only = TRUE;
3983 if (!(si_setcore(sih, ARM7S_CORE_ID, 0)) &&
3984 !(si_setcore(sih, ARMCM3_CORE_ID, 0))) {
3985 DBUSERR(("%s: Failed to find ARM core!\n", __FUNCTION__));
3986 bcmerror = BCME_ERROR;
3987 goto fail;
3990 si_core_disable(sih, 0);
3991 if (bcmsdh_regfail(pinfo->sdh)) {
3992 DBUSERR(("%s: Failed to disable ARM core!\n", __FUNCTION__));
3993 bcmerror = BCME_SDIO_ERROR;
3994 goto fail;
3997 if (!(si_setcore(sih, SOCRAM_CORE_ID, 0))) {
3998 DBUSERR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__));
3999 bcmerror = BCME_ERROR;
4000 goto fail;
4003 si_core_reset(sih, 0, 0);
4004 if (bcmsdh_regfail(pinfo->sdh)) {
4005 DBUSERR(("%s: Failure trying reset SOCRAM core?\n", __FUNCTION__));
4006 bcmerror = BCME_SDIO_ERROR;
4007 goto fail;
4010 /* Clear the top bit of memory */
4011 if (pinfo->ramsize) {
4012 uint32 zeros = 0;
4013 dbus_sdio_membytes(pinfo, TRUE, pinfo->ramsize - 4, (uint8*)&zeros, 4);
4015 } else {
4016 if (!(si_setcore(sih, SOCRAM_CORE_ID, 0))) {
4017 DBUSERR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__));
4018 bcmerror = BCME_ERROR;
4019 goto fail;
4022 if (!si_iscoreup(sih)) {
4023 DBUSERR(("%s: SOCRAM core is down after reset?\n", __FUNCTION__));
4024 bcmerror = BCME_ERROR;
4025 goto fail;
4028 if ((bcmerror = dbus_sdio_write_vars(pinfo))) {
4029 DBUSERR(("%s: could not write vars to ram\n", __FUNCTION__));
4030 goto fail;
4033 if (!si_setcore(sih, PCMCIA_CORE_ID, 0) &&
4034 !si_setcore(sih, SDIOD_CORE_ID, 0)) {
4035 DBUSERR(("%s: Can't change back to SDIO core?\n", __FUNCTION__));
4036 bcmerror = BCME_ERROR;
4037 goto fail;
4039 W_REG(pinfo->osh, &pinfo->chinfo->sdregs->intstatus, 0xFFFFFFFF);
4042 if (!(si_setcore(sih, ARM7S_CORE_ID, 0)) &&
4043 !(si_setcore(sih, ARMCM3_CORE_ID, 0))) {
4044 DBUSERR(("%s: Failed to find ARM core!\n", __FUNCTION__));
4045 bcmerror = BCME_ERROR;
4046 goto fail;
4049 si_core_reset(sih, 0, 0);
4050 if (bcmsdh_regfail(pinfo->sdh)) {
4051 DBUSERR(("%s: Failure trying to reset ARM core?\n", __FUNCTION__));
4052 bcmerror = BCME_SDIO_ERROR;
4053 goto fail;
4056 /* Allow HT Clock now that the ARM is running. */
4057 pinfo->alp_only = FALSE;
4060 fail:
4061 /* Always return to SDIOD core */
4062 if (!si_setcore(sih, PCMCIA_CORE_ID, 0))
4063 si_setcore(sih, SDIOD_CORE_ID, 0);
4065 return bcmerror;
4068 static int
4069 dbus_iovar_process(sdio_info_t *sdio_info, const char *name,
4070 void *params, int plen, void *arg, int len, bool set)
4072 const bcm_iovar_t *vi = NULL;
4073 int bcmerror = 0;
4074 int val_size;
4075 uint32 actionid;
4077 DBUSTRACE(("%s: Enter\n", __FUNCTION__));
4079 ASSERT(name);
4080 ASSERT(len >= 0);
4082 /* Get MUST have return space */
4083 ASSERT(set || (arg && len));
4085 /* Set does NOT take qualifiers */
4086 ASSERT(!set || (!params && !plen));
4088 /* Look up var locally; if not found pass to host driver */
4089 if ((vi = bcm_iovar_lookup(dbus_sdio_iovars, name)) == NULL) {
4090 BUS_WAKE(sdio_info);
4092 /* Turn on clock in case SD command needs backplane */
4093 dbus_sdio_clkctl(sdio_info, CLK_AVAIL, FALSE);
4095 bcmerror = bcmsdh_iovar_op(sdio_info->sdh, name, params, plen, arg, len, set);
4097 /* Check for bus configuration changes of interest */
4099 /* If it was divisor change, read the new one */
4100 if (set && strcmp(name, "sd_divisor") == 0) {
4101 if (bcmsdh_iovar_op(sdio_info->sdh, "sd_divisor", NULL, 0,
4102 &sdio_info->sd_divisor, sizeof(int32), FALSE) != BCME_OK) {
4103 sdio_info->sd_divisor = -1;
4104 DBUSERR(("%s: fail on %s get\n", __FUNCTION__, name));
4105 } else {
4106 DBUSINFO(("%s: noted %s update, value now %d\n",
4107 __FUNCTION__, name, sdio_info->sd_divisor));
4110 /* If it was a mode change, read the new one */
4111 if (set && strcmp(name, "sd_mode") == 0) {
4112 if (bcmsdh_iovar_op(sdio_info->sdh, "sd_mode", NULL, 0,
4113 &sdio_info->sd_mode, sizeof(int32), FALSE) != BCME_OK) {
4114 sdio_info->sd_mode = -1;
4115 DBUSERR(("%s: fail on %s get\n", __FUNCTION__, name));
4116 } else {
4117 DBUSINFO(("%s: noted %s update, value now %d\n",
4118 __FUNCTION__, name, sdio_info->sd_mode));
4121 /* Similar check for blocksize change */
4122 if (set && strcmp(name, "sd_blocksize") == 0) {
4123 int32 fnum = 2;
4124 if (bcmsdh_iovar_op(sdio_info->sdh, "sd_blocksize", &fnum, sizeof(int32),
4125 &sdio_info->blocksize, sizeof(int32), FALSE) != BCME_OK) {
4126 sdio_info->blocksize = 0;
4127 DBUSERR(("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize"));
4128 } else {
4129 DBUSINFO(("%s: noted %s update, value now %d\n",
4130 __FUNCTION__, "sd_blocksize", sdio_info->blocksize));
4133 sdio_info->roundup = MIN(max_roundup, sdio_info->blocksize);
4135 if ((sdio_info->idletime == IDLE_IMMEDIATE) && !sdio_info->dpc_sched) {
4136 sdio_info->activity = FALSE;
4137 dbus_sdio_clkctl(sdio_info, CLK_NONE, TRUE);
4140 goto exit;
4143 DBUSCTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__,
4144 name, (set ? "set" : "get"), len, plen));
4146 /* set up 'params' pointer in case this is a set command so that
4147 * the convenience int and bool code can be common to set and get
4149 if (params == NULL) {
4150 params = arg;
4151 plen = len;
4154 if (vi->type == IOVT_VOID)
4155 val_size = 0;
4156 else if (vi->type == IOVT_BUFFER)
4157 val_size = len;
4158 else
4159 /* all other types are integer sized */
4160 val_size = sizeof(int);
4162 actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
4163 bcmerror = dbus_sdio_doiovar(sdio_info, vi, actionid,
4164 name, params, plen, arg, len, val_size);
4166 exit:
4167 return bcmerror;
4170 static int
4171 dbus_sdio_txctlq_process(void *bus)
4173 sdio_info_t *sdio_info = bus;
4174 int err = DBUS_OK;
4176 if (sdio_info->txctl_req.pending == TRUE) {
4177 if (sdio_info->txctl_req.is_iovar == FALSE) {
4178 ASSERT(sdio_info->txctl_req.ctl.buf);
4179 ASSERT(sdio_info->txctl_req.ctl.len);
4181 err = dbus_sdio_txctl(sdio_info, sdio_info->txctl_req.ctl.buf,
4182 sdio_info->txctl_req.ctl.len);
4183 } else {
4184 err = dbus_iovar_process(sdio_info,
4185 sdio_info->txctl_req.iovar.name,
4186 sdio_info->txctl_req.iovar.params,
4187 sdio_info->txctl_req.iovar.plen,
4188 sdio_info->txctl_req.iovar.arg,
4189 sdio_info->txctl_req.iovar.len,
4190 sdio_info->txctl_req.iovar.set);
4193 bzero(&sdio_info->txctl_req, sizeof(sdio_info->txctl_req));
4194 dbus_sdio_ctl_complete(sdio_info, DBUS_CBCTL_WRITE, err);
4197 return err;
4200 static void
4201 dbus_sdio_txq_flush(sdio_info_t *sdio_info)
4203 int prec_out;
4204 struct exec_parms exec_args;
4205 pkttag_t *ptag;
4206 void *pkt;
4208 exec_args.pdeq.sdio_info = sdio_info;
4209 exec_args.pdeq.tx_prec_map = ALLPRIO;
4210 exec_args.pdeq.prec_out = &prec_out;
4212 /* Cancel all pending pkts */
4213 while ((pkt = dbus_sdos_exec_txlock(sdio_info,
4214 (exec_cb_t) dbus_prec_pkt_deq_exec, &exec_args)) != NULL) {
4215 ptag = (pkttag_t *) PKTTAG(pkt);
4216 ASSERT(ptag);
4218 dbus_sdio_send_irb_complete(sdio_info, ptag->txirb, DBUS_STATUS_CANCELLED);
4219 dbus_sdcb_pktfree(sdio_info, pkt, TRUE);
4224 dbus_sdio_txq_process(void *bus)
4226 sdio_info_t *sdio_info = bus;
4227 bcmsdh_info_t *sdh;
4228 uint framecnt = 0; /* Temporary counter of tx/rx frames */
4229 uint txlimit = dhd_txbound; /* Tx frames to send before resched */
4231 dbus_sdos_lock(sdio_info);
4233 sdh = sdio_info->sdh;
4235 if (sdio_info->pub->busstate == DBUS_STATE_DOWN) {
4236 dbus_sdio_txq_flush(sdio_info);
4237 goto exit;
4240 /* Send ctl requests first */
4241 dbus_sdio_txctlq_process(sdio_info);
4243 /* If waiting for HTAVAIL, check status */
4244 if (sdio_info->clkstate == CLK_PENDING) {
4245 int err;
4246 uint8 clkctl, devctl = 0;
4248 /* Read CSR, if clock on switch to AVAIL, else ignore */
4249 clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
4250 if (err) {
4251 DBUSERR(("%s: error reading CSR: %d\n", __FUNCTION__, err));
4252 sdio_info->pub->busstate = DBUS_STATE_DOWN;
4255 DBUSINFO(("DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n", devctl, clkctl));
4257 if (SBSDIO_HTAV(clkctl)) {
4258 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
4259 if (err) {
4260 DBUSERR(("%s: error reading DEVCTL: %d\n",
4261 __FUNCTION__, err));
4262 sdio_info->pub->busstate = DBUS_STATE_DOWN;
4264 devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
4265 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
4266 if (err) {
4267 DBUSERR(("%s: error writing DEVCTL: %d\n",
4268 __FUNCTION__, err));
4269 sdio_info->pub->busstate = DBUS_STATE_DOWN;
4271 sdio_info->clkstate = CLK_AVAIL;
4273 else {
4274 goto exit;
4278 BUS_WAKE(sdio_info);
4280 /* Make sure backplane clock is on */
4281 dbus_sdio_clkctl(sdio_info, CLK_AVAIL, TRUE);
4282 if (sdio_info->clkstate == CLK_PENDING)
4283 goto exit;
4285 /* Send queued frames (limit 1 if rx may still be pending) */
4286 if ((sdio_info->clkstate != CLK_PENDING) && !sdio_info->fcstate &&
4287 pktq_mlen(&sdio_info->txq, ~sdio_info->flowcontrol) && txlimit && DATAOK(sdio_info)) {
4288 framecnt = dbus_sdio_sendfromq(sdio_info, txlimit);
4291 /* FIX: Check ctl requests again
4292 * It's possible to have ctl request while dbus_sdio_sendfromq()
4293 * is active. Possibly check for pending ctl requests before sending
4294 * each pkt??
4296 dbus_sdio_txctlq_process(sdio_info);
4298 #ifdef SDTEST
4299 /* Generate packets if configured */
4300 if (sdio_info->pktgen_count && (++sdio_info->pktgen_tick >= sdio_info->pktgen_freq)) {
4301 /* Make sure backplane clock is on */
4302 dbus_sdio_clkctl(sdio_info, CLK_AVAIL, FALSE);
4303 sdio_info->pktgen_tick = 0;
4304 dbus_sdio_pktgen(sdio_info);
4306 #endif
4308 exit:
4309 dbus_sdos_unlock(sdio_info);
4311 return DBUS_OK;
4314 static int
4315 probe_htclk(probe_sdh_info_t *pinfo)
4317 int err = 0;
4318 uint8 clkctl;
4319 bcmsdh_info_t *sdh;
4321 sdh = pinfo->sdh;
4323 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
4324 (SBSDIO_ALP_AVAIL_REQ | SBSDIO_HT_AVAIL_REQ), &err);
4325 if (err) {
4326 DBUSERR(("%s: HT Avail request error: %d\n", __FUNCTION__, err));
4327 return BCME_ERROR;
4330 clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
4331 if (err) {
4332 DBUSERR(("%s: HT Avail read error: %d\n", __FUNCTION__, err));
4333 return BCME_ERROR;
4336 if (!SBSDIO_HTAV(clkctl)) {
4337 SPINWAIT(((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
4338 SBSDIO_FUNC1_CHIPCLKCSR, &err)),
4339 !SBSDIO_HTAV(clkctl)), PMU_MAX_TRANSITION_DLY);
4342 return err;
4346 probe_dlstart()
4348 int err;
4349 uint8 clkctl;
4351 /* Need at least ALP */
4352 clkctl = bcmsdh_cfg_read(g_probe_info.sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
4353 if (!SBSDIO_ALPAV(clkctl))
4354 err = probe_htclk(&g_probe_info);
4356 dbus_sdio_download_state(&g_probe_info, TRUE);
4357 g_probe_info.dl_addr = 0;
4358 return 0;
4362 probe_dlstop()
4364 dbus_sdio_download_state(&g_probe_info, FALSE);
4365 g_probe_info.dl_addr = 0;
4366 return 0;
4370 probe_dlwrite(uint8 *buf, int count, bool isvars)
4372 if (isvars)
4373 dbus_sdio_downloadvars(&g_probe_info, buf, count);
4374 else {
4375 dbus_sdio_membytes(&g_probe_info, TRUE, g_probe_info.dl_addr, buf, count);
4376 g_probe_info.dl_addr += count;
4379 return 0;
4383 * Download iovars
4385 * This handles iovars before dbus_attach() and
4386 * before bringing up eth interface
4389 probe_iovar(const char *name, void *params, int plen, void *arg, int len, bool set,
4390 void **val, int *val_len)
4392 int actionid, err = 0;
4393 int32 int_val = 0;
4394 bool bool_val;
4395 uint8 clkctl;
4396 const bcm_iovar_t *vi = NULL;
4398 if (name)
4399 vi = bcm_iovar_lookup(dbus_sdio_iovars, (char *) name);
4401 if (vi == NULL) {
4402 DBUSERR(("Unsupported probe iovar: %s\n", name));
4403 return -1;
4406 bcopy(params, &int_val, sizeof(int_val));
4407 bool_val = (int_val != 0) ? TRUE : FALSE;
4409 actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
4411 /* Need at least ALP */
4412 clkctl = bcmsdh_cfg_read(g_probe_info.sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
4413 if (!SBSDIO_ALPAV(clkctl))
4414 err = probe_htclk(&g_probe_info);
4416 /* Handle pre-attach() requests */
4417 switch (actionid) {
4418 case IOV_SVAL(IOV_SET_DOWNLOAD_STATE):
4419 err = dbus_sdio_download_state(&g_probe_info, bool_val);
4420 g_probe_info.dl_addr = 0;
4421 break;
4422 case IOV_SVAL(IOV_MEMBYTES): {
4423 uint32 address;
4424 uint size;
4425 char *image;
4427 address = (uint32)int_val;
4428 g_probe_info.dl_addr = address;
4430 bcopy((char *)params + sizeof(int_val), &int_val, sizeof(int_val));
4431 size = (uint)int_val; /* in 2048 (2K) chunks */
4433 image = (char *)params + sizeof(int_val) + sizeof(int_val);
4434 dbus_sdio_membytes(&g_probe_info, TRUE, address, image, size);
4435 } break;
4436 case IOV_SVAL(IOV_VARS):
4437 /* FIX: Need vars len in iovar string */
4438 break;
4439 case IOV_GVAL(IOV_MEMSIZE):
4440 *val = (void *)&g_probe_info.ramsize;
4441 *val_len = sizeof(uint32);
4442 break;
4443 default:
4444 DBUSERR(("Pre-attach probe actionid (%d) unsupported\n", actionid));
4445 break;
4448 return err;
4452 static uint
4453 dbus_sdio_sendfromq(sdio_info_t *sdio_info, uint maxframes)
4455 void *pkt;
4456 int ret = 0, prec_out;
4457 uint cnt = 0;
4458 uint datalen;
4459 uint8 tx_prec_map;
4460 struct exec_parms exec_args;
4462 DBUSTRACE(("%s: Enter\n", __FUNCTION__));
4464 tx_prec_map = ~sdio_info->flowcontrol;
4466 /* Send frames until the limit or some other event */
4467 for (cnt = 0; (cnt < maxframes) && DATAOK(sdio_info); cnt++) {
4468 exec_args.pdeq.sdio_info = sdio_info;
4469 exec_args.pdeq.tx_prec_map = tx_prec_map;
4470 exec_args.pdeq.prec_out = &prec_out;
4471 pkt = dbus_sdos_exec_txlock(sdio_info,
4472 (exec_cb_t) dbus_prec_pkt_deq_exec, &exec_args);
4473 if (pkt == NULL)
4474 break;
4476 datalen = PKTLEN(sdio_info->pub->osh, pkt) - SDPCM_HDRLEN;
4478 #ifndef SDTEST
4479 ret = dbus_sdio_txpkt(sdio_info, pkt, SDPCM_DATA_CHANNEL);
4480 #else
4481 ret = dbus_sdio_txpkt(sdio_info, pkt,
4482 (sdio_info->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL));
4483 #endif
4484 if (ret) {
4485 sdio_info->pub->stats.tx_errors++;
4486 if (sdio_info->pub->busstate == DBUS_STATE_DOWN)
4487 break;
4491 return cnt;
4494 static int
4495 dbus_sdio_txctl(sdio_info_t *sdio_info, uchar *msg, uint msglen)
4497 uint8 *frame;
4498 uint16 len, pad;
4499 uint32 swheader;
4500 uint retries = 0;
4501 bcmsdh_info_t *sdh = sdio_info->sdh;
4502 uint8 doff = 0;
4503 int ret = 0;
4504 int i;
4506 DBUSTRACE(("%s: Enter\n", __FUNCTION__));
4508 if (sdio_info->dongle_reset)
4509 return DBUS_ERR;
4511 /* Back the pointer to make a room for bus header */
4512 frame = msg - SDPCM_HDRLEN;
4513 len = (msglen += SDPCM_HDRLEN);
4515 /* Add alignment padding (optional for ctl frames) */
4516 if (dhd_alignctl) {
4517 if ((doff = ((uintptr)frame % SDALIGN))) {
4518 frame -= doff;
4519 len += doff;
4520 msglen += doff;
4521 bzero(frame, doff + SDPCM_HDRLEN);
4523 ASSERT(doff < SDALIGN);
4525 doff += SDPCM_HDRLEN;
4527 /* Round send length to next SDIO block */
4528 if (sdio_info->roundup && sdio_info->blocksize && (len > sdio_info->blocksize)) {
4529 pad = sdio_info->blocksize - (len % sdio_info->blocksize);
4530 if ((pad <= sdio_info->roundup) && (pad < sdio_info->blocksize))
4531 len += pad;
4534 /* Satisfy length-alignment requirements */
4535 if (forcealign && (len & (ALIGNMENT - 1)))
4536 len = ROUNDUP(len, ALIGNMENT);
4538 ASSERT(ISALIGNED(frame, 2));
4540 /* Need to lock here to protect txseq and SDIO tx calls */
4541 BUS_WAKE(sdio_info);
4543 /* Make sure backplane clock is on */
4544 dbus_sdio_clkctl(sdio_info, CLK_AVAIL, FALSE);
4546 /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
4547 *(uint16*)frame = htol16((uint16)msglen);
4548 *(((uint16*)frame) + 1) = htol16(~msglen);
4550 /* Software tag: channel, sequence number, data offset */
4551 swheader = ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK)
4552 | sdio_info->tx_seq | ((doff << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
4553 htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN);
4554 htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
4555 sdio_info->tx_seq = (sdio_info->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
4557 do {
4558 ret = bcmsdh_send_buf(sdh, SI_ENUM_BASE, SDIO_FUNC_2, F2SYNC,
4559 frame, len, NULL, NULL, NULL);
4560 ASSERT(ret != BCME_PENDING);
4562 if (ret < 0) {
4563 /* On failure, abort the command and terminate the frame */
4564 DBUSINFO(("%s: sdio error %d, abort command and terminate frame.\n",
4565 __FUNCTION__, ret));
4566 sdio_info->tx_sderrs++;
4568 ret = bcmsdh_abort(sdh, SDIO_FUNC_2);
4569 if (ret == BCME_NODEVICE) {
4570 dbus_sdio_state_change(sdio_info, DBUS_STATE_DISCONNECT);
4571 break;
4574 #ifdef BCMSPI
4575 DBUSERR(("%s: Check Overflow or F2-fifo-not-ready counters."
4576 " gSPI transmit error on control channel.\n", __FUNCTION__));
4577 #endif /* BCMSPI */
4578 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
4579 SFC_WF_TERM, NULL);
4580 sdio_info->f1regdata++;
4582 for (i = 0; i < 3; i++) {
4583 uint8 hi, lo;
4584 hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
4585 SBSDIO_FUNC1_WFRAMEBCHI, NULL);
4586 lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
4587 SBSDIO_FUNC1_WFRAMEBCLO, NULL);
4588 sdio_info->f1regdata += 2;
4589 if ((hi == 0) && (lo == 0))
4590 break;
4593 } while ((ret < 0) && retries++ < TXRETRIES);
4595 if ((sdio_info->idletime == IDLE_IMMEDIATE) && !sdio_info->dpc_sched) {
4596 sdio_info->activity = FALSE;
4597 dbus_sdio_clkctl(sdio_info, CLK_NONE, TRUE);
4600 if (ret)
4601 sdio_info->tx_ctlerrs++;
4602 else
4603 sdio_info->tx_ctlpkts++;
4605 return ret ? DBUS_ERR : DBUS_OK;
4608 static int
4609 dbus_sdio_rxctl(sdio_info_t *sdio_info, uchar *msg, uint msglen)
4611 uint rxlen = 0;
4613 DBUSTRACE(("%s: Enter\n", __FUNCTION__));
4615 if (sdio_info->dongle_reset)
4616 return DBUS_ERR;
4618 /* FIX: Since rxctl() is async, need to fix case where ctl pkt is recevied
4619 * before this function is called. We need to buffer incoming ctl pkts.
4621 rxlen = sdio_info->rxlen;
4622 bcopy(sdio_info->rxctl, msg, MIN(msglen, rxlen));
4623 sdio_info->rxlen = 0;
4625 return DBUS_OK;
4631 static void *
4632 dbus_sdh_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot,
4633 uint16 func, uint bustype, void *regsva, osl_t * osh,
4634 void *sdh)
4636 int err;
4637 void *prarg;
4638 #ifndef BCMSPI
4639 uint8 clkctl = 0;
4640 #endif /* !BCMSPI */
4642 DBUSTRACE(("%s\n", __FUNCTION__));
4644 prarg = NULL;
4645 /* We make assumptions about address window mappings */
4646 ASSERT((uintptr)regsva == SI_ENUM_BASE);
4648 /* BCMSDH passes venid and devid based on CIS parsing -- but low-power start
4649 * means early parse could fail, so here we should get either an ID
4650 * we recognize OR (-1) indicating we must request power first.
4652 /* Check the Vendor ID */
4653 switch (venid) {
4654 case 0x0000:
4655 case VENDOR_BROADCOM:
4656 break;
4657 default:
4658 DBUSERR(("%s: unknown vendor: 0x%04x\n",
4659 __FUNCTION__, venid));
4660 return NULL;
4661 break;
4664 if (devid == 0)
4665 devid = bcmsdh_reg_read(sdh, SI_ENUM_BASE, 4) & CID_ID_MASK;
4667 /* Check the Device ID and make sure it's one that we support */
4668 switch (devid) {
4669 case BCM4325_CHIP_ID:
4670 case BCM4325_D11DUAL_ID: /* 4325 802.11a/g id */
4671 case BCM4325_D11G_ID: /* 4325 802.11g 2.4Ghz band id */
4672 case BCM4325_D11A_ID: /* 4325 802.11a 5Ghz band id */
4673 DBUSERR(("%s: found 4325 Dongle\n", __FUNCTION__));
4674 g_probe_info.chinfo = &chipinfo_4325_15;
4675 break;
4676 case BCM4329_D11N_ID: /* 4329 802.11n dualband device */
4677 case BCM4329_D11N2G_ID: /* 4329 802.11n 2.4G device */
4678 case BCM4329_D11N5G_ID: /* 4329 802.11n 5G device */
4679 case BCM4321_D11N2G_ID:
4680 DBUSERR(("%s: found 4329 Dongle\n", __FUNCTION__));
4681 g_probe_info.chinfo = &chipinfo_4329;
4682 break;
4683 case BCM4315_CHIP_ID:
4684 case BCM4315_D11G_ID: /* 4315 802.11g id */
4685 case BCM4315_D11A_ID: /* 4315 802.11a id */
4686 DBUSINFO(("%s: found 4315 Dongle\n", __FUNCTION__));
4687 g_probe_info.chinfo = &chipinfo_4325_15;
4688 break;
4689 case BCM4336_D11N_ID:
4690 DBUSINFO(("%s: found 4336 Dongle\n", __FUNCTION__));
4691 g_probe_info.chinfo = &chipinfo_4336;
4692 break;
4694 case BCM4330_D11N_ID:
4695 DBUSINFO(("%s: found 4330 Dongle\n", __FUNCTION__));
4696 g_probe_info.chinfo = &chipinfo_4330;
4697 break;
4699 case BCM43237_D11N_ID:
4700 DBUSINFO(("%s: found 43237 Dongle\n", __FUNCTION__));
4701 g_probe_info.chinfo = &chipinfo_43237;
4702 break;
4704 case BCM4314_CHIP_ID:
4705 DBUSINFO(("%s: found 4314 Dongle\n", __FUNCTION__));
4706 g_probe_info.chinfo = &chipinfo_4314;
4707 break;
4709 case BCM4334_CHIP_ID:
4710 DBUSINFO(("%s: found 4334 Dongle\n", __FUNCTION__));
4711 g_probe_info.chinfo = &chipinfo_4334;
4712 break;
4714 case 0:
4715 DBUSINFO(("%s: allow device id 0, will check chip internals\n",
4716 __FUNCTION__));
4717 /* FIX: Need to query chip */
4718 g_probe_info.chinfo = &chipinfo_4325_15;
4719 break;
4721 default:
4722 DBUSERR(("%s: skipping 0x%04x/0x%04x, not a dongle\n",
4723 __FUNCTION__, venid, devid));
4724 return NULL;
4725 break;
4728 if (osh == NULL) {
4729 /* FIX: This osh is needed for si_attach() and R_REG()
4730 * If we simplify and do away with si_attach() at this stage,
4731 * then remove this as well.
4733 /* FIX: Linux needs this, but not NDIS
4734 * Remove this LINUX define; Don't put
4735 * OS defines in this file.
4736 * Have DBUS maintain it's own osh and remove it from
4737 * dbus_attach() as an argument.
4739 osh = osl_attach(NULL, SD_BUSTYPE, TRUE);
4740 g_probe_info.free_probe_osh = TRUE;
4742 ASSERT(osh);
4744 g_probe_info.venid = venid;
4745 g_probe_info.devid = devid;
4746 g_probe_info.bus_no = bus_no;
4747 g_probe_info.slot = slot;
4748 g_probe_info.func = func;
4749 g_probe_info.bustype = bustype;
4750 g_probe_info.regsva = regsva;
4751 g_probe_info.osh = osh;
4752 g_probe_info.sdh = sdh;
4753 g_probe_info.firmware_file = NULL;
4754 g_probe_info.nvram_file = NULL;
4756 ASSERT(g_probe_info.chinfo);
4757 g_probe_info.ramsize = g_probe_info.orig_ramsize = g_probe_info.chinfo->socram_size;
4759 #ifndef BCMSPI /* wake-wlan in gSPI will bring up the htavail/alpavail clocks. */
4760 /* Force PLL off until si_attach() programs PLL control regs */
4764 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, DHD_INIT_CLKCTL1, &err);
4765 if (!err)
4766 clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
4768 if (err || ((clkctl & ~SBSDIO_AVBITS) != DHD_INIT_CLKCTL1)) {
4769 DBUSERR(("dbus_sdio_probe: ChipClkCSR access: err %d wrote 0x%02x read 0x%02x\n",
4770 err, DHD_INIT_CLKCTL1, clkctl));
4771 return NULL;
4773 #endif /* !BCMSPI */
4775 /* The si_attach() will provide an SI handle, scan the
4776 * backplane, and initialize the PLL.
4778 if (!(g_probe_info.sih = si_attach((uint)devid, osh, regsva, SD_BUSTYPE, sdh,
4779 &g_probe_info.vars, &g_probe_info.varsz))) {
4780 DBUSERR(("%s: si_attach failed!\n", __FUNCTION__));
4781 return NULL;
4784 ASSERT(g_probe_info.orig_ramsize == si_socram_size(g_probe_info.sih));
4786 /* FIX: this is needed on some boards for download. If not, it can
4787 * cause data errors if drive strength is not correct.
4788 * Default is 10mA, but 6mA is optimal.
4790 si_sdiod_drive_strength_init(g_probe_info.sih, osh, dhd_sdiod_drive_strength);
4793 /* prepare dongle for download */
4794 if (!(dbus_sdio_probe_init(&g_probe_info))) {
4795 DBUSERR(("%s: dbus_sdio_probe_init failed\n", __FUNCTION__));
4796 return NULL;
4799 /* Set up the interrupt mask */
4800 W_REG(osh, &g_probe_info.chinfo->sdregs->hostintmask, HOSTINTMASK);
4802 #ifdef BCM_DNGL_EMBEDIMAGE
4803 prarg = dbus_sdio_probe_cb(&g_probe_info, "", SD_BUSTYPE, SDPCM_RESERVE);
4805 if (prarg != NULL)
4806 return &g_probe_info;
4807 else
4808 return NULL;
4809 #else
4810 dbus_sdio_alpclk(sdh);
4812 if (delay_eth == 0) {
4813 dbus_sdio_probe_cb(&g_probe_info, "", SD_BUSTYPE, SDPCM_RESERVE);
4814 } else {
4815 DBUSERR(("Delay eth1 bringup\n"));
4817 * Enable interrupt for DEVREADY when a valid image is downloaded
4819 bcmsdh_intr_disable(sdh);
4821 if ((err = bcmsdh_intr_reg(sdh, dbus_sdh_devrdy_isr, &g_probe_info)) != 0) {
4822 DBUSERR(("%s: FAILED: bcmsdh_intr_reg returned %d\n",
4823 __FUNCTION__, err));
4826 bcmsdh_intr_enable(sdh);
4829 return &g_probe_info;
4830 #endif /* BCM_DNGL_EMBEDIMAGE */
4833 static void
4834 dbus_sdh_disconnect(void *ptr)
4836 probe_sdh_info_t *pinfo = (probe_sdh_info_t *)ptr;
4838 DBUSTRACE(("%s: Enter\n", __FUNCTION__));
4840 if (pinfo == NULL) {
4841 DBUSERR(("%s: pinfo is NULL\n", __FUNCTION__));
4842 return;
4844 dbus_sdio_disconnect_cb(NULL);
4846 /* After this point, sdio_info is free'd;
4847 * Clean up stuff from dbus_sdh_probe()
4849 dbus_sdio_probe_deinit(pinfo);
4851 if (pinfo->sih) {
4852 si_detach(pinfo->sih);
4853 if (pinfo->vars && pinfo->varsz) {
4854 MFREE(pinfo->osh, pinfo->vars, pinfo->varsz);
4858 if (pinfo->osh && (pinfo->free_probe_osh == TRUE)) {
4859 if (MALLOCED(pinfo->osh)) {
4860 DBUSERR(("%s: PROBE MEMORY LEAK %d bytes\n", __FUNCTION__,
4861 MALLOCED(pinfo->osh)));
4863 osl_detach(pinfo->osh);
4867 static bool
4868 dbus_sdio_probe_init(probe_sdh_info_t *pinfo)
4870 bcmsdh_info_t *sdh; /* Handle for BCMSDH calls */
4871 osl_t *osh;
4873 DBUSTRACE(("%s\n", __FUNCTION__));
4875 ASSERT(pinfo);
4876 ASSERT(pinfo->sdh);
4877 ASSERT(pinfo->osh);
4879 sdh = pinfo->sdh;
4880 osh = pinfo->osh;
4882 pinfo->alp_only = TRUE;
4883 pinfo->devready = FALSE;
4885 #ifdef BCMDBG
4886 /* Return the window to backplane enumeration space for core access */
4887 if (bcmsdhsdio_set_sbaddr_window(sdh, SI_ENUM_BASE, TRUE)) {
4888 DBUSERR(("%s: FAILED to return to SI_ENUM_BASE\n", __FUNCTION__));
4889 goto fail;
4892 if (CHIPTYPE(pinfo->sih->socitype) != SOCI_AI) {
4893 printf("F1 signature read @0x18000ffc=0x%4x\n",
4894 bcmsdh_reg_read(sdh, SI_ENUM_BASE + 0xffc, 4));
4897 printf("F1 signature read @0x18000000=0x%4x\n",
4898 bcmsdh_reg_read(sdh, SI_ENUM_BASE, 4));
4900 #endif /* BCMDBG */
4902 /* Set core control so an SDIO reset does a backplane reset */
4903 OR_REG(osh, &pinfo->chinfo->sdregs->corecontrol, CC_BPRESEN);
4905 return TRUE;
4907 #ifdef BCMDBG
4908 fail:
4909 #endif
4910 return FALSE;
4913 static void
4914 dbus_sdio_probe_deinit(probe_sdh_info_t *pinfo)
4916 int err;
4918 ASSERT(pinfo);
4919 /* FIX: Not consolidating this with dbus_sdh_disconnect
4920 * because it's used during DEVRESET. Need to resolve.
4922 if (pinfo->sih) {
4923 bcmsdh_cfg_write(pinfo->sdh, SDIO_FUNC_1,
4924 SBSDIO_FUNC1_CHIPCLKCSR, SBSDIO_HT_AVAIL_REQ, &err);
4925 si_watchdog(pinfo->sih, 4);
4926 bcmsdh_cfg_write(pinfo->sdh, SDIO_FUNC_1,
4927 SBSDIO_FUNC1_CHIPCLKCSR, 0, &err);
4932 bool
4933 dbus_sdio_attach_init(sdio_info_t *sdio_info, void *sdh, char *firmware_path,
4934 char * nvram_path)
4936 int ret;
4937 int32 fnum;
4939 DBUSTRACE(("%s: Enter\n", __FUNCTION__));
4941 #ifdef SDTEST
4942 dbus_sdio_pktgen_init(sdio_info);
4943 #endif /* SDTEST */
4945 #ifndef BCMSPI
4946 /* Disable F2 to clear any intermediate frame state on the dongle */
4947 bcmsdh_cfg_write(sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL);
4948 #endif /* !BCMSPI */
4950 #ifndef BCMSPI
4951 /* Done with backplane-dependent accesses, can drop clock... */
4952 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
4953 sdio_info->clkstate = CLK_SDONLY;
4954 #endif /* !BCMSPI */
4956 /* Query the SD clock speed */
4957 if (bcmsdh_iovar_op(sdh, "sd_divisor", NULL, 0,
4958 &sdio_info->sd_divisor, sizeof(int32), FALSE) != BCME_OK) {
4959 DBUSERR(("%s: fail on %s get\n", __FUNCTION__, "sd_divisor"));
4960 sdio_info->sd_divisor = -1;
4961 } else {
4962 DBUSINFO(("%s: Initial value for %s is %d\n",
4963 __FUNCTION__, "sd_divisor", sdio_info->sd_divisor));
4966 /* Query the SD bus mode */
4967 if (bcmsdh_iovar_op(sdh, "sd_mode", NULL, 0,
4968 &sdio_info->sd_mode, sizeof(int32), FALSE) != BCME_OK) {
4969 DBUSERR(("%s: fail on %s get\n", __FUNCTION__, "sd_mode"));
4970 sdio_info->sd_mode = -1;
4971 } else {
4972 DBUSINFO(("%s: Initial value for %s is %d\n",
4973 __FUNCTION__, "sd_mode", sdio_info->sd_mode));
4976 /* Query the F2 block size, set roundup accordingly */
4977 fnum = 2;
4978 if (bcmsdh_iovar_op(sdh, "sd_blocksize", &fnum, sizeof(int32),
4979 &sdio_info->blocksize, sizeof(int32), FALSE) != BCME_OK) {
4980 sdio_info->blocksize = 0;
4981 DBUSERR(("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize"));
4982 } else {
4983 DBUSINFO(("%s: Initial value for %s is %d\n",
4984 __FUNCTION__, "sd_blocksize", sdio_info->blocksize));
4986 sdio_info->roundup = MIN(max_roundup, sdio_info->blocksize);
4988 /* Query if bus module supports packet chaining, default to use if supported */
4989 if (bcmsdh_iovar_op(sdh, "sd_rxchain", NULL, 0,
4990 &sdio_info->sd_rxchain, sizeof(int32), FALSE) != BCME_OK) {
4991 sdio_info->sd_rxchain = FALSE;
4992 } else {
4993 DBUSINFO(("%s: bus module (through bcmsdh API) %s chaining\n",
4994 __FUNCTION__, (sdio_info->sd_rxchain ? "supports" : "does not support")));
4996 sdio_info->use_rxchain = (bool)sdio_info->sd_rxchain;
4998 /* Register interrupt callback, but mask it (not operational yet). */
4999 DBUSINTR(("%s: disable SDIO interrupts (not interested yet)\n", __FUNCTION__));
5000 bcmsdh_intr_disable(sdh);
5001 if ((ret = bcmsdh_intr_reg(sdh, dbus_sdh_isr, sdio_info)) != 0) {
5002 DBUSERR(("%s: FAILED: bcmsdh_intr_reg returned %d\n",
5003 __FUNCTION__, ret));
5004 goto fail;
5006 DBUSINTR(("%s: registered SDIO interrupt function ok\n", __FUNCTION__));
5008 return TRUE;
5010 fail:
5011 return FALSE;
5014 static void
5015 dbus_sdio_release(sdio_info_t *sdio_info, osl_t *osh)
5017 DBUSTRACE(("%s: Enter\n", __FUNCTION__));
5019 if (sdio_info) {
5020 ASSERT(osh);
5021 dbus_sdio_release_dongle(sdio_info, osh);
5025 static void
5026 dbus_sdio_release_dongle(sdio_info_t *sdio_info, osl_t *osh)
5028 DBUSTRACE(("%s: Enter\n", __FUNCTION__));
5030 if (sdio_info->dongle_reset)
5031 return;
5033 if (sdio_info->rxbuf) {
5034 MFREE(osh, sdio_info->rxbuf, sdio_info->rxblen);
5035 sdio_info->rxctl = sdio_info->rxbuf = NULL;
5036 sdio_info->rxlen = 0;
5039 if (sdio_info->databuf) {
5040 MFREE(osh, sdio_info->databuf, MAX_DATA_BUF);
5041 sdio_info->databuf = NULL;
5045 #ifdef BCM_DNGL_EMBEDIMAGE
5047 dhd_bus_download_image_array(probe_sdh_info_t *pinfo, char * nvram_path, uint8 *fw, int len)
5049 int bcmerror = -1;
5050 int offset = 0;
5052 /* Download image */
5053 while ((offset + MEMBLOCK) < len) {
5054 bcmerror = dbus_sdio_membytes(pinfo, TRUE,
5055 offset, fw + offset, MEMBLOCK);
5056 if (bcmerror) {
5057 DBUSERR(("%s: error %d on writing %d membytes at 0x%08x\n",
5058 __FUNCTION__, bcmerror, MEMBLOCK, offset));
5059 goto err;
5062 offset += MEMBLOCK;
5065 if (offset < len) {
5066 bcmerror = dbus_sdio_membytes(pinfo, TRUE, offset,
5067 fw + offset, len - offset);
5068 if (bcmerror) {
5069 DBUSERR(("%s: error %d on writing %d membytes at 0x%08x\n",
5070 __FUNCTION__, bcmerror, len - offset, offset));
5071 goto err;
5075 /* Download SROM if provided externally through file */
5076 dhd_bus_download_nvram_file(pinfo, nvram_path);
5077 err:
5078 return bcmerror;
5080 #endif /* BCM_DNGL_EMBEDIMAGE */
5084 * ProcessVars:Takes a buffer of "<var>=<value>\n" lines read from a file and ending in a NUL.
5085 * Removes carriage returns, empty lines, comment lines, and converts newlines to NULs.
5086 * Shortens buffer as needed and pads with NULs. End of buffer is marked by two NULs.
5089 #if defined(BCM_DNGL_EMBEDIMAGE)
5091 dhd_bus_download_nvram_file(probe_sdh_info_t *pinfo, char * nvram_path)
5093 int bcmerror = -1;
5094 uint len = 0;
5095 void * image = NULL;
5096 uint8 * memblock = NULL;
5097 char *bufp;
5099 if (!nvram_path[0])
5100 return 0;
5102 /* FIX: Need to implement dhd_os_open_image() */
5103 /* image = dhd_os_open_image(nvram_path); */
5104 if (image == NULL)
5105 goto err;
5107 memblock = MALLOC(pinfo->osh, MEMBLOCK);
5108 if (memblock == NULL) {
5109 DBUSERR(("%s: Failed to allocate memory %d bytes\n",
5110 __FUNCTION__, MEMBLOCK));
5111 goto err;
5114 /* Download variables */
5115 /* FIX: Need to implement dhd_os_get_image_block() */
5116 /* len = dhd_os_get_image_block(memblock, MEMBLOCK, image); */
5118 if (len != MEMBLOCK && len > 0) {
5119 bufp = (char *)memblock;
5120 len = process_nvram_vars(bufp, len);
5121 if (len % 4)
5122 len += (4 - len % 4);
5123 bufp += len;
5124 *bufp++ = 0;
5125 if (len)
5126 bcmerror = dbus_sdio_downloadvars(pinfo, memblock, len + 1);
5127 if (bcmerror) {
5128 DBUSERR(("%s: error downloading vars: %d\n",
5129 __FUNCTION__, bcmerror));
5131 } else {
5132 DBUSERR(("%s: error reading nvram file: %d\n",
5133 __FUNCTION__, len));
5134 bcmerror = BCME_SDIO_ERROR;
5137 err:
5138 if (memblock)
5139 MFREE(pinfo->osh, memblock, MEMBLOCK);
5141 /* FIX: Need to implement dhd_os_close_image() */
5143 return bcmerror;
5145 #endif /* BCM_DNGL_EMBEDIMAGE */
5147 static void
5148 dbus_sdos_lock(sdio_info_t *sdio_info)
5150 if (sdio_info == NULL)
5151 return;
5153 if (sdio_info->drvintf && sdio_info->drvintf->lock)
5154 sdio_info->drvintf->lock(sdio_info->sdos_info);
5155 else
5156 ASSERT(0);
5158 ASSERT(sdio_info->sdlocked == FALSE);
5159 sdio_info->sdlocked = TRUE;
5162 static void
5163 dbus_sdos_unlock(sdio_info_t *sdio_info)
5165 ASSERT(sdio_info->sdlocked == TRUE);
5166 sdio_info->sdlocked = FALSE;
5168 if (sdio_info->drvintf && sdio_info->drvintf->unlock)
5169 sdio_info->drvintf->unlock(sdio_info->sdos_info);
5170 else
5171 ASSERT(0);
5174 static void *
5175 dbus_sdos_exec_txlock(sdio_info_t *sdio_info, exec_cb_t cb, struct exec_parms *args)
5177 ASSERT(cb);
5178 if (sdio_info->drvintf && sdio_info->drvintf->exec_txlock)
5179 return sdio_info->drvintf->exec_txlock(sdio_info->sdos_info, cb, args);
5181 return NULL;
5184 static void *
5185 dbus_sdcb_pktget(sdio_info_t *sdio_info, uint len, bool send)
5187 void *p = NULL;
5189 DBUSTRACE(("%s\n", __FUNCTION__));
5191 if (sdio_info == NULL)
5192 return NULL;
5194 if (sdio_info->cbs && sdio_info->cbs->pktget)
5195 p = sdio_info->cbs->pktget(sdio_info->cbarg, len, send);
5197 return p;
5200 static void
5201 dbus_sdcb_pktfree(sdio_info_t *sdio_info, void *p, bool send)
5203 DBUSTRACE(("%s\n", __FUNCTION__));
5205 if (sdio_info == NULL)
5206 return;
5208 if (sdio_info->cbs && sdio_info->cbs->pktfree)
5209 sdio_info->cbs->pktfree(sdio_info->cbarg, p, send);
5212 static dbus_irb_t *
5213 dbus_sdcb_getirb(sdio_info_t *sdio_info, bool send)
5215 DBUSTRACE(("%s\n", __FUNCTION__));
5217 if (sdio_info == NULL)
5218 return NULL;
5220 if (sdio_info->cbs && sdio_info->cbs->getirb)
5221 return sdio_info->cbs->getirb(sdio_info->cbarg, send);
5223 return NULL;
5227 * Interface functions
5229 static int
5230 dbus_sdif_send_irb(void *bus, dbus_irb_tx_t *txirb)
5232 sdio_info_t *sdio_info = BUS_INFO(bus, sdio_info_t);
5233 int err;
5235 if (sdio_info == NULL)
5236 return DBUS_ERR;
5238 err = dbus_sdio_txbuf_submit(sdio_info, txirb);
5239 if (err != DBUS_OK) {
5240 err = DBUS_ERR_TXFAIL;
5243 return err;
5246 static int
5247 dbus_sdif_send_ctl(void *bus, uint8 *buf, int len)
5249 sdio_info_t *sdio_info = BUS_INFO(bus, sdio_info_t);
5250 int err = DBUS_OK;
5252 if (sdio_info == NULL)
5253 return DBUS_ERR;
5255 if (sdio_info->txctl_req.pending == TRUE) {
5256 DBUSERR(("%s: ctl is pending!\n", __FUNCTION__));
5257 return DBUS_ERR_PENDING;
5260 sdio_info->txctl_req.ctl.buf = buf;
5261 sdio_info->txctl_req.ctl.len = len;
5262 sdio_info->txctl_req.is_iovar = FALSE;
5263 sdio_info->txctl_req.pending = TRUE;
5264 dbus_sdio_txq_sched(sdio_info->sdos_info);
5265 return err;
5268 static int
5269 dbus_sdif_recv_ctl(void *bus, uint8 *buf, int len)
5271 sdio_info_t *sdio_info = BUS_INFO(bus, sdio_info_t);
5273 if (sdio_info == NULL)
5274 return DBUS_ERR;
5276 if (sdio_info->rxctl_req.pending == TRUE) {
5277 DBUSERR(("%s: ctl is pending!\n", __FUNCTION__));
5278 return DBUS_ERR_PENDING;
5281 /* Do have a rxctl pkt available? */
5282 if (sdio_info->rxlen > 0) {
5283 dbus_sdio_rxctl(sdio_info, buf, len);
5284 dbus_sdio_ctl_complete(sdio_info, DBUS_CBCTL_READ, DBUS_OK);
5285 } else {
5286 sdio_info->rxctl_req.ctl.buf = buf;
5287 sdio_info->rxctl_req.ctl.len = len;
5288 sdio_info->rxctl_req.pending = TRUE;
5290 return DBUS_OK;
5293 static int
5294 dbus_sdif_up(void *bus)
5296 sdio_info_t *sdio_info = BUS_INFO(bus, sdio_info_t);
5297 int err = DBUS_ERR;
5299 if (sdio_info == NULL)
5300 return DBUS_ERR;
5302 if (sdio_info->drvintf && sdio_info->drvintf->up) {
5303 err = sdio_info->drvintf->up(sdio_info->sdos_info);
5306 dbus_sdos_lock(sdio_info);
5307 err = dbus_sdio_init(sdio_info);
5308 if (err != 0)
5309 err = DBUS_ERR;
5310 dbus_sdos_unlock(sdio_info);
5312 return err;
5315 static int
5316 dbus_sdif_iovar_op(void *bus, const char *name,
5317 void *params, int plen, void *arg, int len, bool set)
5319 sdio_info_t *sdio_info = BUS_INFO(bus, sdio_info_t);
5320 int err = DBUS_OK;
5322 if (sdio_info == NULL)
5323 return DBUS_ERR;
5325 err = dbus_iovar_process(sdio_info, name, params, plen, arg, len, set);
5326 return err;
5329 static bool
5330 dbus_sdif_device_exists(void *bus)
5332 return TRUE;
5335 static bool
5336 dbus_sdif_dlneeded(void *bus)
5338 sdio_info_t *sdio_info = BUS_INFO(bus, sdio_info_t);
5340 if (sdio_info == NULL)
5341 return FALSE;
5343 #ifdef BCM_DNGL_EMBEDIMAGE
5344 return (g_probe_info.devready == FALSE);
5345 #else
5346 return FALSE;
5347 #endif
5350 static int
5351 dbus_sdif_dlstart(void *bus, uint8 *fw, int len)
5353 sdio_info_t *sdio_info = BUS_INFO(bus, sdio_info_t);
5354 int err = DBUS_ERR;
5356 if (sdio_info == NULL)
5357 return DBUS_ERR;
5359 dbus_sdio_alpclk(g_probe_info.sdh);
5360 sdio_info->clkstate = CLK_AVAIL;
5362 /* Put ARM in reset for download */
5363 err = dbus_sdio_download_state(&g_probe_info, TRUE);
5364 if (err) {
5365 DBUSERR(("%s: error placing ARM core in reset\n", __FUNCTION__));
5366 err = DBUS_ERR;
5367 goto err;
5370 /* FIX: Which embedded image has priority?
5372 #ifdef BCM_DNGL_EMBEDIMAGE
5373 if (dhd_bus_download_image_array(&g_probe_info, nvram_path, fw, len)) {
5374 DBUSERR(("%s: dongle image download failed\n", __FUNCTION__));
5375 err = DBUS_ERR;
5376 goto err;
5378 #endif /* BCM_DNGL_EMBEDIMAGE */
5380 /* FIX: Skip this for now
5381 * If above succeeds, do we still download this one?
5384 err = DBUS_OK;
5385 g_probe_info.devready = TRUE;
5386 sdio_info->pub->busstate = DBUS_STATE_DL_DONE;
5387 err:
5388 return err;
5391 static int
5392 dbus_sdif_dlrun(void *bus)
5394 sdio_info_t *sdio_info;
5395 int err = DBUS_ERR;
5397 sdio_info = BUS_INFO(bus, sdio_info_t);
5399 /* Take ARM out of reset */
5400 err = dbus_sdio_download_state(&g_probe_info, FALSE);
5401 if (err) {
5402 DBUSERR(("%s: error getting out of ARM reset\n", __FUNCTION__));
5403 err = DBUS_ERR;
5404 } else
5405 err = DBUS_OK;
5407 return err;
5410 static int
5411 dbus_sdif_stop(void *bus)
5413 sdio_info_t *sdio_info = BUS_INFO(bus, sdio_info_t);
5414 int err;
5416 if (sdio_info->drvintf && sdio_info->drvintf->stop)
5417 err = sdio_info->drvintf->stop(sdio_info->sdos_info);
5419 dbus_bus_stop(sdio_info);
5420 return DBUS_OK;
5423 static int
5424 dbus_sdif_down(void *bus)
5426 sdio_info_t *sdio_info = BUS_INFO(bus, sdio_info_t);
5427 int err;
5429 if (sdio_info->drvintf && sdio_info->drvintf->down)
5430 err = sdio_info->drvintf->down(sdio_info->sdos_info);
5432 dbus_bus_stop(sdio_info);
5433 return DBUS_OK;
5436 static int
5437 dbus_sdif_get_attrib(void *bus, dbus_attrib_t *attrib)
5439 sdio_info_t *sdio_info = BUS_INFO(bus, sdio_info_t);
5441 if ((sdio_info == NULL) || (attrib == NULL))
5442 return DBUS_ERR;
5444 attrib->bustype = DBUS_SDIO;
5445 attrib->vid = g_probe_info.venid;
5446 attrib->pid = 0;
5447 attrib->devid = g_probe_info.devid;
5448 attrib->nchan = 1;
5449 attrib->mtu = 512;
5451 return DBUS_OK;
5454 static int
5455 dbus_sdos_sched_dpc(sdio_info_t *sdio_info)
5457 if (sdio_info->pub->busstate == DBUS_STATE_DOWN) {
5458 DBUSERR(("Bus down. Do not sched dpc\n"));
5459 return DBUS_ERR;
5462 if (sdio_info && sdio_info->drvintf && sdio_info->drvintf->sched_dpc)
5463 return sdio_info->drvintf->sched_dpc(sdio_info->sdos_info);
5464 else
5465 return DBUS_ERR;
5468 #ifndef BCM_DNGL_EMBEDIMAGE
5469 static int
5470 dbus_sdos_sched_probe_cb()
5472 if (g_dbusintf && g_dbusintf->sched_probe_cb)
5473 return g_dbusintf->sched_probe_cb(NULL);
5475 return DBUS_ERR;
5477 #endif
5480 /* This callback is overloaded to also handle pre-attach() requests
5481 * such as downloading an image to the dongle.
5482 * Before attach(), we're limited to what can be done since
5483 * sdio_info handle is not available yet:
5484 * - Reading/writing registers
5485 * - Querying cores using si handle
5487 static void *
5488 dbus_sdio_probe_cb(void *handle, const char *desc, uint32 bustype, uint32 hdrlen)
5490 DBUSTRACE(("%s\n", __FUNCTION__));
5492 if (handle == &g_probe_info) {
5494 if (g_dbusintf != NULL) {
5496 /* First, initialize all lower-level functions as default
5497 * so that dbus.c simply calls directly to dbus_sdio_os.c.
5499 bcopy(g_dbusintf, &dbus_sdio_intf, sizeof(dbus_intf_t));
5501 /* Second, selectively override functions we need.
5503 dbus_sdio_intf.attach = dbus_sdif_attach;
5504 dbus_sdio_intf.detach = dbus_sdif_detach;
5505 dbus_sdio_intf.send_irb = dbus_sdif_send_irb;
5506 /* SDIO does not need pre-submitted IRBs like USB
5507 * so set recv_irb() to NULL so dbus.c would not call
5508 * this function.
5510 dbus_sdio_intf.recv_irb = NULL;
5511 dbus_sdio_intf.send_ctl = dbus_sdif_send_ctl;
5512 dbus_sdio_intf.recv_ctl = dbus_sdif_recv_ctl;
5513 dbus_sdio_intf.up = dbus_sdif_up;
5514 dbus_sdio_intf.iovar_op = dbus_sdif_iovar_op;
5515 dbus_sdio_intf.device_exists = dbus_sdif_device_exists;
5516 dbus_sdio_intf.dlneeded = dbus_sdif_dlneeded;
5517 dbus_sdio_intf.dlstart = dbus_sdif_dlstart;
5518 dbus_sdio_intf.dlrun = dbus_sdif_dlrun;
5519 dbus_sdio_intf.stop = dbus_sdif_stop;
5520 dbus_sdio_intf.down = dbus_sdif_down;
5521 dbus_sdio_intf.get_attrib = dbus_sdif_get_attrib;
5524 /* Assume a valid image has been downloaded when
5525 * the handle matches ours so propagate probe callback to upper
5526 * layer
5528 if (probe_cb) {
5529 disc_arg = probe_cb(probe_arg, "DBUS SDIO", SD_BUSTYPE, SDPCM_RESERVE);
5530 return disc_arg;
5534 return NULL;
5537 static void
5538 dbus_sdio_disconnect_cb(void *handle)
5540 DBUSTRACE(("%s\n", __FUNCTION__));
5542 if (disconnect_cb)
5543 disconnect_cb(disc_arg);
5547 dbus_bus_register(int vid, int pid, probe_cb_t prcb,
5548 disconnect_cb_t discb, void *prarg, dbus_intf_t **intf, void *param1, void *param2)
5550 int err;
5552 probe_cb = prcb;
5553 disconnect_cb = discb;
5554 probe_arg = prarg;
5556 DBUSTRACE(("%s\n", __FUNCTION__));
5558 bzero(&g_probe_info, sizeof(probe_sdh_info_t));
5559 *intf = &dbus_sdio_intf;
5561 err = dbus_bus_osl_register(vid, pid, dbus_sdio_probe_cb,
5562 dbus_sdio_disconnect_cb, &g_probe_info, &g_dbusintf, param1, param2);
5564 ASSERT(g_dbusintf);
5566 return err;
5570 dbus_bus_deregister()
5572 dbus_bus_osl_deregister();
5573 return DBUS_OK;
5576 void *
5577 dbus_sdif_attach(dbus_pub_t *pub, void *cbarg, dbus_intf_callbacks_t *cbs)
5579 sdio_info_t *sdio_info;
5581 DBUSTRACE(("%s\n", __FUNCTION__));
5582 if ((g_dbusintf == NULL) || (g_dbusintf->attach == NULL))
5583 return NULL;
5585 /* Sanity check for BUS_INFO() */
5586 ASSERT(OFFSETOF(sdio_info_t, pub) == 0);
5588 sdio_info = MALLOC(pub->osh, sizeof(sdio_info_t));
5589 if (sdio_info == NULL)
5590 return NULL;
5592 bzero(sdio_info, sizeof(sdio_info_t));
5594 sdio_info->pub = pub;
5595 sdio_info->cbarg = cbarg;
5596 sdio_info->cbs = cbs;
5597 sdio_info->bus = SD_BUSTYPE;
5598 /* Use bufpool if allocated, else use locally malloced rxbuf */
5599 sdio_info->usebufpool = FALSE;
5601 /* Update sdio_info with probe info */
5602 sdio_info->sdh = g_probe_info.sdh;
5603 sdio_info->sih = g_probe_info.sih;
5604 sdio_info->ramsize = g_probe_info.ramsize;
5605 sdio_info->orig_ramsize = g_probe_info.orig_ramsize;
5607 ASSERT(g_probe_info.chinfo);
5608 sdio_info->regs = g_probe_info.chinfo->sdregs;
5609 sdio_info->vars = g_probe_info.vars;
5610 sdio_info->varsz = g_probe_info.varsz;
5611 sdio_info->hostintmask = HOSTINTMASK;
5613 if (g_probe_info.firmware_file)
5614 sdio_info->firmware_path = g_probe_info.firmware_file;
5615 else
5616 sdio_info->firmware_path = firmware_path;
5618 if (g_probe_info.nvram_file)
5619 sdio_info->nvram_path = g_probe_info.nvram_file;
5620 else
5621 sdio_info->nvram_path = nvram_path;
5623 /* FIX: Need to redo this maxctl stuff since we don't want cdc and IOCTL
5624 * info in DBUS. maxctl is used by rxbuf for static allocation.
5626 * sdio_info->maxctl = WLC_IOCTL_MAXLEN + sizeof(cdc_ioctl_t) + ROUND_UP_MARGIN;
5628 sdio_info->maxctl = 8192 + 16 + 2048;
5629 if (sdio_info->maxctl) {
5630 sdio_info->rxblen =
5631 ROUNDUP((sdio_info->maxctl + SDPCM_HDRLEN), ALIGNMENT) + SDALIGN;
5632 if (!(sdio_info->rxbuf = MALLOC(pub->osh, sdio_info->rxblen))) {
5633 DBUSERR(("%s: MALLOC of %d-byte rxbuf failed\n",
5634 __FUNCTION__, sdio_info->rxblen));
5635 goto err;
5639 /* Allocate buffer to receive glomed packet */
5640 if (!(sdio_info->databuf = MALLOC(pub->osh, MAX_DATA_BUF))) {
5641 DBUSERR(("%s: MALLOC of %d-byte databuf failed\n",
5642 __FUNCTION__, MAX_DATA_BUF));
5643 goto err;
5646 /* Align the buffer */
5647 if ((uintptr)sdio_info->databuf % SDALIGN)
5648 sdio_info->dataptr =
5649 sdio_info->databuf + (SDALIGN - ((uintptr)sdio_info->databuf % SDALIGN));
5650 else
5651 sdio_info->dataptr = sdio_info->databuf;
5653 /* ...and initialize clock/power states */
5654 sdio_info->sleeping = FALSE;
5655 sdio_info->idletime = (int32)dhd_idletime;
5656 sdio_info->idleclock = IDLE_ACTIVE;
5658 if (!(dbus_sdio_attach_init(sdio_info, sdio_info->sdh,
5659 sdio_info->firmware_path, sdio_info->nvram_path))) {
5660 DBUSERR(("%s: dbus_sdio_attach_init failed\n", __FUNCTION__));
5661 goto err;
5664 ASSERT(sdio_info->pub->ntxq > 0);
5665 pktq_init(&sdio_info->txq, (PRIOMASK+1), sdio_info->pub->ntxq);
5667 /* Locate an appropriately-aligned portion of hdrbuf */
5668 sdio_info->rxhdr = (uint8*)ROUNDUP((uintptr)&sdio_info->hdrbuf[0], SDALIGN);
5670 /* Set the poll and/or interrupt flags */
5671 sdio_info->intr = (bool)dhd_intr;
5672 if ((sdio_info->poll = (bool)dhd_poll))
5673 sdio_info->pollrate = 1;
5675 sdio_info->sdos_info = (dbus_pub_t *)g_dbusintf->attach(pub,
5676 sdio_info, &dbus_sdio_intf_cbs);
5677 if (sdio_info->sdos_info == NULL)
5678 goto err;
5680 /* Save SDIO OS-specific driver entry points */
5681 sdio_info->drvintf = g_dbusintf;
5683 if (g_probe_info.devready == TRUE)
5684 sdio_info->pub->busstate = DBUS_STATE_DL_DONE;
5686 pub->bus = sdio_info;
5688 return (void *) sdio_info->sdos_info; /* Return Lower layer info */
5689 err:
5690 if (sdio_info) {
5691 MFREE(pub->osh, sdio_info, sizeof(sdio_info_t));
5693 return NULL;
5697 void
5698 dbus_sdif_detach(dbus_pub_t *pub, void *info)
5700 sdio_info_t *sdio_info = pub->bus;
5701 osl_t *osh = pub->osh;
5703 dbus_bus_stop(sdio_info);
5705 if (sdio_info->drvintf && sdio_info->drvintf->detach)
5706 sdio_info->drvintf->detach(pub, sdio_info->sdos_info);
5708 dbus_sdio_release(sdio_info, sdio_info->pub->osh);
5709 MFREE(osh, sdio_info, sizeof(sdio_info_t));
5712 static void
5713 dbus_sdio_send_irb_timeout(void *handle, dbus_irb_tx_t *txirb)
5715 sdio_info_t *sdio_info = (sdio_info_t *) handle;
5717 DBUSTRACE(("%s\n", __FUNCTION__));
5719 if (sdio_info == NULL)
5720 return;
5722 if (sdio_info->cbs && sdio_info->cbs->send_irb_timeout)
5723 sdio_info->cbs->send_irb_timeout(sdio_info->cbarg, txirb);
5726 static void
5727 dbus_sdio_send_irb_complete(void *handle, dbus_irb_tx_t *txirb, int status)
5729 sdio_info_t *sdio_info = (sdio_info_t *) handle;
5731 if (sdio_info == NULL)
5732 return;
5734 if (sdio_info->cbs && sdio_info->cbs->send_irb_complete)
5735 sdio_info->cbs->send_irb_complete(sdio_info->cbarg, txirb, status);
5738 static void
5739 dbus_sdio_recv_irb_complete(void *handle, dbus_irb_rx_t *rxirb, int status)
5741 sdio_info_t *sdio_info = (sdio_info_t *) handle;
5743 if (sdio_info == NULL)
5744 return;
5746 if (sdio_info->cbs && sdio_info->cbs->recv_irb_complete)
5747 sdio_info->cbs->recv_irb_complete(sdio_info->cbarg, rxirb, status);
5750 static void
5751 dbus_sdio_errhandler(void *handle, int err)
5753 sdio_info_t *sdio_info = (sdio_info_t *) handle;
5755 if (sdio_info == NULL)
5756 return;
5758 if (sdio_info->cbs && sdio_info->cbs->errhandler)
5759 sdio_info->cbs->errhandler(sdio_info->cbarg, err);
5762 static void
5763 dbus_sdio_ctl_complete(void *handle, int type, int status)
5765 sdio_info_t *sdio_info = (sdio_info_t *) handle;
5767 if (sdio_info == NULL)
5768 return;
5770 if (sdio_info->cbs && sdio_info->cbs->ctl_complete)
5771 sdio_info->cbs->ctl_complete(sdio_info->cbarg, type, status);
5774 static void
5775 dbus_sdio_state_change(void *handle, int state)
5777 sdio_info_t *sdio_info = (sdio_info_t *) handle;
5779 if (sdio_info == NULL)
5780 return;
5782 if (sdio_info->cbs && sdio_info->cbs->state_change)
5783 sdio_info->cbs->state_change(sdio_info->cbarg, state);
5785 if (state == DBUS_STATE_DISCONNECT) {
5786 if (sdio_info->drvintf && sdio_info->drvintf->remove)
5787 sdio_info->drvintf->remove(sdio_info->sdos_info);
5789 sdio_info->pub->busstate = DBUS_STATE_DOWN;
5794 static bool
5795 dbus_sdio_dpc(void *handle, bool bounded)
5797 sdio_info_t *sdio_info = (sdio_info_t *) handle;
5798 bcmsdh_info_t *sdh;
5799 sdpcmd_regs_t *regs;
5800 uint32 intstatus, newstatus = 0;
5801 uint retries = 0;
5803 uint rxlimit = dhd_rxbound; /* Rx frames to read before resched */
5804 uint framecnt = 0; /* Temporary counter of tx/rx frames */
5805 bool rxdone = TRUE; /* Flag for no more read data */
5806 bool resched = FALSE; /* Flag indicating resched wanted */
5808 DBUSTRACE(("%s: Enter\n", __FUNCTION__));
5810 if (sdio_info == NULL) {
5811 DBUSERR(("%s: sdio_info == NULL!\n", __FUNCTION__));
5812 return FALSE;
5815 dbus_sdos_lock(sdio_info);
5817 sdh = sdio_info->sdh;
5818 regs = sdio_info->regs;
5820 /* Start with leftover status bits */
5821 intstatus = sdio_info->intstatus;
5823 /* If waiting for HTAVAIL, check status */
5824 if (sdio_info->clkstate == CLK_PENDING) {
5825 int err;
5826 uint8 clkctl, devctl = 0;
5828 #ifdef BCMDBG
5829 /* Check for inconsistent device control */
5830 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
5831 if (err) {
5832 DBUSERR(("%s: error reading DEVCTL: %d\n", __FUNCTION__, err));
5833 sdio_info->pub->busstate = DBUS_STATE_DOWN;
5835 ASSERT(devctl & SBSDIO_DEVCTL_CA_INT_ONLY);
5836 #endif /* BCMDBG */
5838 /* Read CSR, if clock on switch to AVAIL, else ignore */
5839 clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
5840 if (err) {
5841 DBUSERR(("%s: error reading CSR: %d\n", __FUNCTION__, err));
5842 sdio_info->pub->busstate = DBUS_STATE_DOWN;
5845 DBUSINFO(("DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n", devctl, clkctl));
5847 if (SBSDIO_HTAV(clkctl)) {
5848 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
5849 if (err) {
5850 DBUSERR(("%s: error reading DEVCTL: %d\n",
5851 __FUNCTION__, err));
5852 sdio_info->pub->busstate = DBUS_STATE_DOWN;
5854 devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
5855 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
5856 if (err) {
5857 DBUSERR(("%s: error writing DEVCTL: %d\n",
5858 __FUNCTION__, err));
5859 sdio_info->pub->busstate = DBUS_STATE_DOWN;
5861 sdio_info->clkstate = CLK_AVAIL;
5862 } else {
5863 goto clkwait;
5867 BUS_WAKE(sdio_info);
5869 /* Make sure backplane clock is on */
5870 dbus_sdio_clkctl(sdio_info, CLK_AVAIL, TRUE);
5871 if (sdio_info->clkstate == CLK_PENDING)
5872 goto clkwait;
5874 /* Pending interrupt indicates new device status */
5875 if (sdio_info->ipend) {
5876 sdio_info->ipend = FALSE;
5877 R_SDREG(newstatus, &regs->intstatus, retries);
5878 sdio_info->f1regdata++;
5879 if (bcmsdh_regfail(sdio_info->sdh))
5880 newstatus = 0;
5881 newstatus &= sdio_info->hostintmask;
5882 sdio_info->fcstate = !!(newstatus & I_HMB_FC_STATE);
5883 if (newstatus) {
5884 W_SDREG(newstatus, &regs->intstatus, retries);
5885 sdio_info->f1regdata++;
5889 /* Merge new bits with previous */
5890 intstatus |= newstatus;
5891 sdio_info->intstatus = 0;
5893 /* Handle flow-control change: read new state in case our ack
5894 * crossed another change interrupt. If change still set, assume
5895 * FC ON for safety, let next loop through do the debounce.
5897 if (intstatus & I_HMB_FC_CHANGE) {
5898 intstatus &= ~I_HMB_FC_CHANGE;
5899 W_SDREG(I_HMB_FC_CHANGE, &regs->intstatus, retries);
5900 R_SDREG(newstatus, &regs->intstatus, retries);
5901 sdio_info->f1regdata += 2;
5902 sdio_info->fcstate = !!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE));
5903 intstatus |= (newstatus & sdio_info->hostintmask);
5906 /* Just being here means nothing more to do for chipactive */
5907 if (intstatus & I_CHIPACTIVE) {
5908 /* ASSERT(sdio_info->clkstate == CLK_AVAIL); */
5909 intstatus &= ~I_CHIPACTIVE;
5912 /* Handle host mailbox indication */
5913 if (intstatus & I_HMB_HOST_INT) {
5914 intstatus &= ~I_HMB_HOST_INT;
5915 intstatus |= dbus_sdio_hostmail(sdio_info);
5918 /* Generally don't ask for these, can get CRC errors... */
5919 if (intstatus & I_WR_OOSYNC) {
5920 DBUSERR(("Dongle reports WR_OOSYNC\n"));
5921 intstatus &= ~I_WR_OOSYNC;
5924 if (intstatus & I_RD_OOSYNC) {
5925 DBUSERR(("Dongle reports RD_OOSYNC\n"));
5926 intstatus &= ~I_RD_OOSYNC;
5929 if (intstatus & I_SBINT) {
5930 DBUSERR(("Dongle reports SBINT\n"));
5931 intstatus &= ~I_SBINT;
5934 /* Would be active due to wake-wlan in gSPI */
5935 if (intstatus & I_CHIPACTIVE) {
5936 DBUSERR(("Dongle reports CHIPACTIVE\n"));
5937 intstatus &= ~I_CHIPACTIVE;
5940 /* Ignore frame indications if rxskip is set */
5941 if (sdio_info->rxskip)
5942 intstatus &= ~I_HMB_FRAME_IND;
5944 /* On frame indication, read available frames */
5945 if (PKT_AVAILABLE()) {
5946 framecnt = dbus_sdio_readframes(sdio_info, rxlimit, &rxdone);
5947 if (rxdone || sdio_info->rxskip)
5948 intstatus &= ~I_HMB_FRAME_IND;
5949 rxlimit -= MIN(framecnt, rxlimit);
5952 if (pktq_mlen(&sdio_info->txq, ~sdio_info->flowcontrol) > 0) {
5953 /* reschedule txq */
5954 dbus_sdio_txq_sched(sdio_info->sdos_info);
5957 /* Keep still-pending events for next scheduling */
5958 sdio_info->intstatus = intstatus;
5960 clkwait:
5961 /* Re-enable interrupts to detect new device events (mailbox, rx frame)
5962 * or clock availability. (Allows tx loop to check ipend if desired.)
5963 * (Unless register access seems hosed, as we may not be able to ACK...)
5965 if (sdio_info->intr && sdio_info->intdis && !bcmsdh_regfail(sdh)) {
5966 DBUSINTR(("%s: enable SDIO interrupts, rxdone %d framecnt %d\n",
5967 __FUNCTION__, rxdone, framecnt));
5968 sdio_info->intdis = FALSE;
5969 bcmsdh_intr_enable(sdh);
5972 /* Resched if events or tx frames are pending, else await next interrupt */
5973 /* On failed register access, all bets are off: no resched or interrupts */
5974 if ((sdio_info->pub->busstate == DBUS_STATE_DOWN) || bcmsdh_regfail(sdh)) {
5975 DBUSERR(("%s: failed backplane access over SDIO, halting operation\n",
5976 __FUNCTION__));
5977 dbus_sdio_state_change(sdio_info, DBUS_STATE_DISCONNECT);
5978 sdio_info->intstatus = 0;
5979 dbus_bus_stop(sdio_info);
5980 } else if (sdio_info->clkstate == CLK_PENDING) {
5981 /* Awaiting I_CHIP_ACTIVE, don't resched */
5982 } else if (sdio_info->intstatus || sdio_info->ipend || PKT_AVAILABLE()) {
5983 resched = TRUE;
5986 /* If we're done for now, turn off clock request. */
5987 if (sdio_info->idletime == IDLE_IMMEDIATE) {
5988 sdio_info->activity = FALSE;
5989 dbus_sdio_clkctl(sdio_info, CLK_NONE, FALSE);
5992 sdio_info->dpc_sched = resched;
5993 dbus_sdos_unlock(sdio_info);
5995 return resched;
5998 static void
5999 dbus_sdio_watchdog(void *handle)
6003 void
6004 dbus_bus_fw_get(void *bus, uint8 **fw, int *fwlen, int *decomp)
6006 sdio_info_t *sdio_info = BUS_INFO(bus, sdio_info_t);
6007 unsigned int devid;
6008 unsigned int crev;
6010 devid = sdio_info->pub->attrib.devid;
6011 crev = sdio_info->pub->attrib.chiprev;
6013 *fw = NULL;
6014 *fwlen = 0;
6016 switch (devid) {
6017 case BCM4319_CHIP_ID:
6018 #if defined(EMBED_IMAGE_4319sd)
6019 *fw = (uint8 *)dlarray_4319sd;
6020 *fwlen = sizeof(dlarray_4319sd);
6021 #endif
6022 break;
6023 case BCM4325_CHIP_ID:
6024 #ifdef EMBED_IMAGE_4325sd
6025 *fw = (uint8 *)dlarray_4325sd;
6026 *fwlen = sizeof(dlarray_4325sd);
6027 #endif
6028 break;
6029 default:
6030 #ifdef EMBED_IMAGE_GENERIC
6031 *fw = (uint8 *)dlarray;
6032 *fwlen = sizeof(dlarray);
6033 #endif
6034 break;