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