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