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