/drivers/net/wireless/bcmdhd/dhd_sdio.c
C | 6359 lines | 4798 code | 999 blank | 562 comment | 1138 complexity | 3c52bd19fa50b30dca420548ef79f3e5 MD5 | raw file
Possible License(s): LGPL-2.0, AGPL-1.0, GPL-2.0
1/*
2 * DHD Bus Module for SDIO
3 *
4 * Copyright (C) 1999-2011, 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 326662 2012-04-10 06:38:08Z $
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 <bcmsdpcm.h>
44#if defined(DHD_DEBUG)
45#include <hndrte_armtrap.h>
46#include <hndrte_cons.h>
47#endif /* defined(DHD_DEBUG) */
48#include <sbchipc.h>
49#include <sbhnddma.h>
50
51#include <sdio.h>
52#include <sbsdio.h>
53#include <sbsdpcmdev.h>
54#include <bcmsdpcm.h>
55#include <bcmsdbus.h>
56
57#include <proto/ethernet.h>
58#include <proto/802.1d.h>
59#include <proto/802.11.h>
60
61#include <dngl_stats.h>
62#include <dhd.h>
63#include <dhd_bus.h>
64#include <dhd_proto.h>
65#include <dhd_dbg.h>
66#include <dhdioctl.h>
67#include <sdiovar.h>
68
69#ifndef DHDSDIO_MEM_DUMP_FNAME
70#define DHDSDIO_MEM_DUMP_FNAME "mem_dump"
71#endif
72
73#define QLEN 256 /* bulk rx and tx queue lengths */
74#define FCHI (QLEN - 10)
75#define FCLOW (FCHI / 2)
76#define PRIOMASK 7
77
78#define TXRETRIES 2 /* # of retries for tx frames */
79
80#define DHD_RXBOUND 50 /* Default for max rx frames in one scheduling */
81
82#define DHD_TXBOUND 20 /* Default for max tx frames in one scheduling */
83
84#define DHD_TXMINMAX 1 /* Max tx frames if rx still pending */
85
86#define MEMBLOCK 2048 /* Block size used for downloading of dongle image */
87#define MAX_NVRAMBUF_SIZE 4096 /* max nvram buf size */
88#define MAX_DATA_BUF (32 * 1024) /* Must be large enough to hold biggest possible glom */
89
90#ifndef DHD_FIRSTREAD
91#define DHD_FIRSTREAD 32
92#endif
93#if !ISPOWEROF2(DHD_FIRSTREAD)
94#error DHD_FIRSTREAD is not a power of 2!
95#endif
96
97/* Total length of frame header for dongle protocol */
98#define SDPCM_HDRLEN (SDPCM_FRAMETAG_LEN + SDPCM_SWHEADER_LEN)
99#ifdef SDTEST
100#define SDPCM_RESERVE (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN)
101#else
102#define SDPCM_RESERVE (SDPCM_HDRLEN + DHD_SDALIGN)
103#endif
104
105/* Space for header read, limit for data packets */
106#ifndef MAX_HDR_READ
107#define MAX_HDR_READ 32
108#endif
109#if !ISPOWEROF2(MAX_HDR_READ)
110#error MAX_HDR_READ is not a power of 2!
111#endif
112
113#define MAX_RX_DATASZ 2048
114
115/* Maximum milliseconds to wait for F2 to come up */
116#define DHD_WAIT_F2RDY 3000
117
118/* Bump up limit on waiting for HT to account for first startup;
119 * if the image is doing a CRC calculation before programming the PMU
120 * for HT availability, it could take a couple hundred ms more, so
121 * max out at a 1 second (1000000us).
122 */
123#if (PMU_MAX_TRANSITION_DLY <= 1000000)
124#undef PMU_MAX_TRANSITION_DLY
125#define PMU_MAX_TRANSITION_DLY 1000000
126#endif
127
128/* Value for ChipClockCSR during initial setup */
129#define DHD_INIT_CLKCTL1 (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ)
130#define DHD_INIT_CLKCTL2 (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP)
131
132/* Flags for SDH calls */
133#define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED)
134
135/* Packet free applicable unconditionally for sdio and sdspi. Conditional if
136 * bufpool was present for gspi bus.
137 */
138#define PKTFREE2() if ((bus->bus != SPI_BUS) || bus->usebufpool) \
139 PKTFREE(bus->dhd->osh, pkt, FALSE);
140DHD_SPINWAIT_SLEEP_INIT(sdioh_spinwait_sleep);
141#if defined(OOB_INTR_ONLY)
142extern void bcmsdh_set_irq(int flag);
143#endif /* defined(OOB_INTR_ONLY) */
144#ifdef PROP_TXSTATUS
145extern void dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success);
146#endif
147
148#ifdef DHD_DEBUG
149/* Device console log buffer state */
150#define CONSOLE_LINE_MAX 192
151#define CONSOLE_BUFFER_MAX 2024
152typedef struct dhd_console {
153 uint count; /* Poll interval msec counter */
154 uint log_addr; /* Log struct address (fixed) */
155 hndrte_log_t log; /* Log struct (host copy) */
156 uint bufsize; /* Size of log buffer */
157 uint8 *buf; /* Log buffer (host copy) */
158 uint last; /* Last buffer read index */
159} dhd_console_t;
160#endif /* DHD_DEBUG */
161
162/* Private data for SDIO bus interaction */
163typedef struct dhd_bus {
164 dhd_pub_t *dhd;
165
166 bcmsdh_info_t *sdh; /* Handle for BCMSDH calls */
167 si_t *sih; /* Handle for SI calls */
168 char *vars; /* Variables (from CIS and/or other) */
169 uint varsz; /* Size of variables buffer */
170 uint32 sbaddr; /* Current SB window pointer (-1, invalid) */
171
172 sdpcmd_regs_t *regs; /* Registers for SDIO core */
173 uint sdpcmrev; /* SDIO core revision */
174 uint armrev; /* CPU core revision */
175 uint ramrev; /* SOCRAM core revision */
176 uint32 ramsize; /* Size of RAM in SOCRAM (bytes) */
177 uint32 orig_ramsize; /* Size of RAM in SOCRAM (bytes) */
178
179 uint32 bus; /* gSPI or SDIO bus */
180 uint32 hostintmask; /* Copy of Host Interrupt Mask */
181 uint32 intstatus; /* Intstatus bits (events) pending */
182 bool dpc_sched; /* Indicates DPC schedule (intrpt rcvd) */
183 bool fcstate; /* State of dongle flow-control */
184
185 uint16 cl_devid; /* cached devid for dhdsdio_probe_attach() */
186 char *fw_path; /* module_param: path to firmware image */
187 char *nv_path; /* module_param: path to nvram vars file */
188 const char *nvram_params; /* user specified nvram params. */
189
190 uint blocksize; /* Block size of SDIO transfers */
191 uint roundup; /* Max roundup limit */
192
193 struct pktq txq; /* Queue length used for flow-control */
194 uint8 flowcontrol; /* per prio flow control bitmask */
195 uint8 tx_seq; /* Transmit sequence number (next) */
196 uint8 tx_max; /* Maximum transmit sequence allowed */
197
198 uint8 hdrbuf[MAX_HDR_READ + DHD_SDALIGN];
199 uint8 *rxhdr; /* Header of current rx frame (in hdrbuf) */
200 uint16 nextlen; /* Next Read Len from last header */
201 uint8 rx_seq; /* Receive sequence number (expected) */
202 bool rxskip; /* Skip receive (awaiting NAK ACK) */
203
204 void *glomd; /* Packet containing glomming descriptor */
205 void *glom; /* Packet chain for glommed superframe */
206 uint glomerr; /* Glom packet read errors */
207
208 uint8 *rxbuf; /* Buffer for receiving control packets */
209 uint rxblen; /* Allocated length of rxbuf */
210 uint8 *rxctl; /* Aligned pointer into rxbuf */
211 uint8 *databuf; /* Buffer for receiving big glom packet */
212 uint8 *dataptr; /* Aligned pointer into databuf */
213 uint rxlen; /* Length of valid data in buffer */
214
215 uint8 sdpcm_ver; /* Bus protocol reported by dongle */
216
217 bool intr; /* Use interrupts */
218 bool poll; /* Use polling */
219 bool ipend; /* Device interrupt is pending */
220 bool intdis; /* Interrupts disabled by isr */
221 uint intrcount; /* Count of device interrupt callbacks */
222 uint lastintrs; /* Count as of last watchdog timer */
223 uint spurious; /* Count of spurious interrupts */
224 uint pollrate; /* Ticks between device polls */
225 uint polltick; /* Tick counter */
226 uint pollcnt; /* Count of active polls */
227
228#ifdef DHD_DEBUG
229 dhd_console_t console; /* Console output polling support */
230 uint console_addr; /* Console address from shared struct */
231#endif /* DHD_DEBUG */
232
233 uint regfails; /* Count of R_REG/W_REG failures */
234
235 uint clkstate; /* State of sd and backplane clock(s) */
236 bool activity; /* Activity flag for clock down */
237 int32 idletime; /* Control for activity timeout */
238 int32 idlecount; /* Activity timeout counter */
239 int32 idleclock; /* How to set bus driver when idle */
240 int32 sd_divisor; /* Speed control to bus driver */
241 int32 sd_mode; /* Mode control to bus driver */
242 int32 sd_rxchain; /* If bcmsdh api accepts PKT chains */
243 bool use_rxchain; /* If dhd should use PKT chains */
244 bool sleeping; /* Is SDIO bus sleeping? */
245 bool rxflow_mode; /* Rx flow control mode */
246 bool rxflow; /* Is rx flow control on */
247 uint prev_rxlim_hit; /* Is prev rx limit exceeded (per dpc schedule) */
248 bool alp_only; /* Don't use HT clock (ALP only) */
249 /* Field to decide if rx of control frames happen in rxbuf or lb-pool */
250 bool usebufpool;
251
252#ifdef SDTEST
253 /* external loopback */
254 bool ext_loop;
255 uint8 loopid;
256
257 /* pktgen configuration */
258 uint pktgen_freq; /* Ticks between bursts */
259 uint pktgen_count; /* Packets to send each burst */
260 uint pktgen_print; /* Bursts between count displays */
261 uint pktgen_total; /* Stop after this many */
262 uint pktgen_minlen; /* Minimum packet data len */
263 uint pktgen_maxlen; /* Maximum packet data len */
264 uint pktgen_mode; /* Configured mode: tx, rx, or echo */
265 uint pktgen_stop; /* Number of tx failures causing stop */
266
267 /* active pktgen fields */
268 uint pktgen_tick; /* Tick counter for bursts */
269 uint pktgen_ptick; /* Burst counter for printing */
270 uint pktgen_sent; /* Number of test packets generated */
271 uint pktgen_rcvd; /* Number of test packets received */
272 uint pktgen_fail; /* Number of failed send attempts */
273 uint16 pktgen_len; /* Length of next packet to send */
274#define PKTGEN_RCV_IDLE (0)
275#define PKTGEN_RCV_ONGOING (1)
276 uint16 pktgen_rcv_state; /* receive state */
277 uint pktgen_rcvd_rcvsession; /* test pkts rcvd per rcv session. */
278#endif /* SDTEST */
279
280 /* Some additional counters */
281 uint tx_sderrs; /* Count of tx attempts with sd errors */
282 uint fcqueued; /* Tx packets that got queued */
283 uint rxrtx; /* Count of rtx requests (NAK to dongle) */
284 uint rx_toolong; /* Receive frames too long to receive */
285 uint rxc_errors; /* SDIO errors when reading control frames */
286 uint rx_hdrfail; /* SDIO errors on header reads */
287 uint rx_badhdr; /* Bad received headers (roosync?) */
288 uint rx_badseq; /* Mismatched rx sequence number */
289 uint fc_rcvd; /* Number of flow-control events received */
290 uint fc_xoff; /* Number which turned on flow-control */
291 uint fc_xon; /* Number which turned off flow-control */
292 uint rxglomfail; /* Failed deglom attempts */
293 uint rxglomframes; /* Number of glom frames (superframes) */
294 uint rxglompkts; /* Number of packets from glom frames */
295 uint f2rxhdrs; /* Number of header reads */
296 uint f2rxdata; /* Number of frame data reads */
297 uint f2txdata; /* Number of f2 frame writes */
298 uint f1regdata; /* Number of f1 register accesses */
299
300 uint8 *ctrl_frame_buf;
301 uint32 ctrl_frame_len;
302 bool ctrl_frame_stat;
303 uint32 rxint_mode; /* rx interrupt mode */
304} dhd_bus_t;
305
306/* clkstate */
307#define CLK_NONE 0
308#define CLK_SDONLY 1
309#define CLK_PENDING 2 /* Not used yet */
310#define CLK_AVAIL 3
311
312#define DHD_NOPMU(dhd) (FALSE)
313
314#ifdef DHD_DEBUG
315static int qcount[NUMPRIO];
316static int tx_packets[NUMPRIO];
317#endif /* DHD_DEBUG */
318
319/* Deferred transmit */
320const uint dhd_deferred_tx = 1;
321
322extern uint dhd_watchdog_ms;
323extern void dhd_os_wd_timer(void *bus, uint wdtick);
324
325/* Tx/Rx bounds */
326uint dhd_txbound;
327uint dhd_rxbound;
328uint dhd_txminmax = DHD_TXMINMAX;
329
330/* override the RAM size if possible */
331#define DONGLE_MIN_MEMSIZE (128 *1024)
332int dhd_dongle_memsize;
333
334static bool dhd_doflow;
335static bool dhd_alignctl;
336
337static bool sd1idle;
338
339static bool retrydata;
340#define RETRYCHAN(chan) (((chan) == SDPCM_EVENT_CHANNEL) || retrydata)
341
342static const uint watermark = 8;
343static const uint firstread = DHD_FIRSTREAD;
344
345#define HDATLEN (firstread - (SDPCM_HDRLEN))
346
347/* Retry count for register access failures */
348static const uint retry_limit = 20;
349
350/* Force even SD lengths (some host controllers mess up on odd bytes) */
351static bool forcealign;
352
353/* Flag to indicate if we should download firmware on driver load */
354uint dhd_download_fw_on_driverload = TRUE;
355
356#define ALIGNMENT 4
357
358#if defined(OOB_INTR_ONLY) && defined(HW_OOB)
359extern void bcmsdh_enable_hw_oob_intr(void *sdh, bool enable);
360#endif
361
362#if defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD)
363#error OOB_INTR_ONLY is NOT working with SDIO_ISR_THREAD
364#endif /* defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD) */
365#define PKTALIGN(osh, p, len, align) \
366 do { \
367 uint datalign; \
368 datalign = (uintptr)PKTDATA((osh), (p)); \
369 datalign = ROUNDUP(datalign, (align)) - datalign; \
370 ASSERT(datalign < (align)); \
371 ASSERT(PKTLEN((osh), (p)) >= ((len) + datalign)); \
372 if (datalign) \
373 PKTPULL((osh), (p), datalign); \
374 PKTSETLEN((osh), (p), (len)); \
375 } while (0)
376
377/* Limit on rounding up frames */
378static const uint max_roundup = 512;
379
380/* Try doing readahead */
381static bool dhd_readahead;
382
383/* To check if there's window offered */
384#define DATAOK(bus) \
385 (((uint8)(bus->tx_max - bus->tx_seq) > 1) && \
386 (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0))
387
388/* To check if there's window offered for ctrl frame */
389#define TXCTLOK(bus) \
390 (((uint8)(bus->tx_max - bus->tx_seq) != 0) && \
391 (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0))
392
393/* Macros to get register read/write status */
394/* NOTE: these assume a local dhdsdio_bus_t *bus! */
395#define R_SDREG(regvar, regaddr, retryvar) \
396do { \
397 retryvar = 0; \
398 do { \
399 regvar = R_REG(bus->dhd->osh, regaddr); \
400 } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \
401 if(retryvar > 1) \
402 DHD_ERROR(("%s: regvar[ %d ], retryvar[ %d ], regfails[ %d ], bcmsdh_regfail[ %d ] \n",__FUNCTION__,regvar, retryvar ,bus->regfails, bcmsdh_regfail(bus->sdh))); \
403 if (retryvar) { \
404 bus->regfails += (retryvar-1); \
405 if (retryvar > retry_limit) { \
406 DHD_ERROR(("%s: FAILED" #regvar "READ, LINE %d\n", \
407 __FUNCTION__, __LINE__)); \
408 regvar = 0; \
409 } \
410 } \
411} while (0)
412
413#define W_SDREG(regval, regaddr, retryvar) \
414do { \
415 retryvar = 0; \
416 do { \
417 W_REG(bus->dhd->osh, regaddr, regval); \
418 } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \
419 if (retryvar) { \
420 bus->regfails += (retryvar-1); \
421 if (retryvar > retry_limit) \
422 DHD_ERROR(("%s: FAILED REGISTER WRITE, LINE %d\n", \
423 __FUNCTION__, __LINE__)); \
424 } \
425} while (0)
426
427#define BUS_WAKE(bus) \
428 do { \
429 if ((bus)->sleeping) \
430 dhdsdio_bussleep((bus), FALSE); \
431 } while (0);
432
433/*
434 * pktavail interrupts from dongle to host can be managed in 3 different ways
435 * whenever there is a packet available in dongle to transmit to host.
436 *
437 * Mode 0: Dongle writes the software host mailbox and host is interrupted.
438 * Mode 1: (sdiod core rev >= 4)
439 * Device sets a new bit in the intstatus whenever there is a packet
440 * available in fifo. Host can't clear this specific status bit until all the
441 * packets are read from the FIFO. No need to ack dongle intstatus.
442 * Mode 2: (sdiod core rev >= 4)
443 * Device sets a bit in the intstatus, and host acks this by writing
444 * one to this bit. Dongle won't generate anymore packet interrupts
445 * until host reads all the packets from the dongle and reads a zero to
446 * figure that there are no more packets. No need to disable host ints.
447 * Need to ack the intstatus.
448 */
449
450#define SDIO_DEVICE_HMB_RXINT 0 /* default old way */
451#define SDIO_DEVICE_RXDATAINT_MODE_0 1 /* from sdiod rev 4 */
452#define SDIO_DEVICE_RXDATAINT_MODE_1 2 /* from sdiod rev 4 */
453
454
455#define FRAME_AVAIL_MASK(bus) \
456 ((bus->rxint_mode == SDIO_DEVICE_HMB_RXINT) ? I_HMB_FRAME_IND : I_XMTDATA_AVAIL)
457
458#define DHD_BUS SDIO_BUS
459
460#define PKT_AVAILABLE(bus, intstatus) ((intstatus) & (FRAME_AVAIL_MASK(bus)))
461
462#define HOSTINTMASK (I_HMB_SW_MASK | I_CHIPACTIVE)
463
464#define GSPI_PR55150_BAILOUT
465
466
467#ifdef SDTEST
468static void dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq);
469static void dhdsdio_sdtest_set(dhd_bus_t *bus, uint8 count);
470#endif
471
472#ifdef DHD_DEBUG
473static int dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size);
474static int dhd_serialconsole(dhd_bus_t *bus, bool get, bool enable, int *bcmerror);
475#endif /* DHD_DEBUG */
476
477static int dhdsdio_download_state(dhd_bus_t *bus, bool enter);
478
479static void dhdsdio_release(dhd_bus_t *bus, osl_t *osh);
480static void dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh);
481static void dhdsdio_disconnect(void *ptr);
482static bool dhdsdio_chipmatch(uint16 chipid);
483static bool dhdsdio_probe_attach(dhd_bus_t *bus, osl_t *osh, void *sdh,
484 void * regsva, uint16 devid);
485static bool dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh);
486static bool dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh);
487static void dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation,
488 bool reset_flag);
489
490static void dhd_dongle_setmemsize(struct dhd_bus *bus, int mem_size);
491static int dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags,
492 uint8 *buf, uint nbytes,
493 void *pkt, bcmsdh_cmplt_fn_t complete, void *handle);
494static int dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags,
495 uint8 *buf, uint nbytes,
496 void *pkt, bcmsdh_cmplt_fn_t complete, void *handle);
497
498static bool dhdsdio_download_firmware(dhd_bus_t *bus, osl_t *osh, void *sdh);
499static int _dhdsdio_download_firmware(dhd_bus_t *bus);
500
501static int dhdsdio_download_code_file(dhd_bus_t *bus, char *image_path);
502static int dhdsdio_download_nvram(dhd_bus_t *bus);
503#ifdef BCMEMBEDIMAGE
504static int dhdsdio_download_code_array(dhd_bus_t *bus);
505#endif
506
507#ifdef WLMEDIA_HTSF
508#include <htsf.h>
509extern uint32 dhd_get_htsf(void *dhd, int ifidx);
510#endif /* WLMEDIA_HTSF */
511
512extern int chip_is_b1;
513
514static void
515dhd_dongle_setmemsize(struct dhd_bus *bus, int mem_size)
516{
517 int32 min_size = DONGLE_MIN_MEMSIZE;
518 /* Restrict the memsize to user specified limit */
519 DHD_ERROR(("user: Restrict the dongle ram size to %d, min accepted %d\n",
520 dhd_dongle_memsize, min_size));
521 if ((dhd_dongle_memsize > min_size) &&
522 (dhd_dongle_memsize < (int32)bus->orig_ramsize))
523 bus->ramsize = dhd_dongle_memsize;
524}
525
526static int
527dhdsdio_set_siaddr_window(dhd_bus_t *bus, uint32 address)
528{
529 int err = 0;
530 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW,
531 (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err);
532 if (!err)
533 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID,
534 (address >> 16) & SBSDIO_SBADDRMID_MASK, &err);
535 if (!err)
536 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH,
537 (address >> 24) & SBSDIO_SBADDRHIGH_MASK, &err);
538 return err;
539}
540
541
542/* Turn backplane clock on or off */
543static int
544dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok)
545{
546 int err;
547 uint8 clkctl, clkreq, devctl;
548 bcmsdh_info_t *sdh;
549
550 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
551
552#if defined(OOB_INTR_ONLY)
553 pendok = FALSE;
554#endif
555 clkctl = 0;
556 sdh = bus->sdh;
557
558
559 if (on) {
560 /* Request HT Avail */
561 clkreq = bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ;
562
563
564
565
566 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
567 if (err) {
568 DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err));
569 return BCME_ERROR;
570 }
571
572 if (pendok &&
573 ((bus->sih->buscoretype == PCMCIA_CORE_ID) && (bus->sih->buscorerev == 9))) {
574 uint32 dummy, retries;
575 R_SDREG(dummy, &bus->regs->clockctlstatus, retries);
576 }
577
578 /* Check current status */
579 clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
580 if (err) {
581 DHD_ERROR(("%s: HT Avail read error: %d\n", __FUNCTION__, err));
582 return BCME_ERROR;
583 }
584
585 /* Go to pending and await interrupt if appropriate */
586 if (!SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) {
587 /* Allow only clock-available interrupt */
588 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
589 if (err) {
590 DHD_ERROR(("%s: Devctl access error setting CA: %d\n",
591 __FUNCTION__, err));
592 return BCME_ERROR;
593 }
594
595 devctl |= SBSDIO_DEVCTL_CA_INT_ONLY;
596 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
597 DHD_INFO(("CLKCTL: set PENDING\n"));
598 bus->clkstate = CLK_PENDING;
599 return BCME_OK;
600 } else if (bus->clkstate == CLK_PENDING) {
601 /* Cancel CA-only interrupt filter */
602 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
603 devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
604 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
605 }
606
607 /* Otherwise, wait here (polling) for HT Avail */
608 if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
609 SPINWAIT_SLEEP(sdioh_spinwait_sleep,
610 ((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
611 SBSDIO_FUNC1_CHIPCLKCSR, &err)),
612 !SBSDIO_CLKAV(clkctl, bus->alp_only)), PMU_MAX_TRANSITION_DLY);
613 }
614 if (err) {
615 DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err));
616 return BCME_ERROR;
617 }
618 if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
619 DHD_ERROR(("%s: HT Avail timeout (%d): clkctl 0x%02x\n",
620 __FUNCTION__, PMU_MAX_TRANSITION_DLY, clkctl));
621 return BCME_ERROR;
622 }
623
624
625 /* Mark clock available */
626 bus->clkstate = CLK_AVAIL;
627 DHD_INFO(("CLKCTL: turned ON\n"));
628
629#if defined(DHD_DEBUG)
630 if (bus->alp_only == TRUE) {
631#if !defined(BCMLXSDMMC)
632 if (!SBSDIO_ALPONLY(clkctl)) {
633 DHD_ERROR(("%s: HT Clock, when ALP Only\n", __FUNCTION__));
634 }
635#endif /* !defined(BCMLXSDMMC) */
636 } else {
637 if (SBSDIO_ALPONLY(clkctl)) {
638 DHD_ERROR(("%s: HT Clock should be on.\n", __FUNCTION__));
639 }
640 }
641#endif /* defined (DHD_DEBUG) */
642
643 bus->activity = TRUE;
644 } else {
645 clkreq = 0;
646
647 if (bus->clkstate == CLK_PENDING) {
648 /* Cancel CA-only interrupt filter */
649 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
650 devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
651 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
652 }
653
654 bus->clkstate = CLK_SDONLY;
655 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
656 DHD_INFO(("CLKCTL: turned OFF\n"));
657 if (err) {
658 DHD_ERROR(("%s: Failed access turning clock off: %d\n",
659 __FUNCTION__, err));
660 return BCME_ERROR;
661 }
662 }
663 return BCME_OK;
664}
665
666/* Change idle/active SD state */
667static int
668dhdsdio_sdclk(dhd_bus_t *bus, bool on)
669{
670 int err;
671 int32 iovalue;
672
673 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
674
675 if (on) {
676 if (bus->idleclock == DHD_IDLE_STOP) {
677 /* Turn on clock and restore mode */
678 iovalue = 1;
679 err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0,
680 &iovalue, sizeof(iovalue), TRUE);
681 if (err) {
682 DHD_ERROR(("%s: error enabling sd_clock: %d\n",
683 __FUNCTION__, err));
684 return BCME_ERROR;
685 }
686
687 iovalue = bus->sd_mode;
688 err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
689 &iovalue, sizeof(iovalue), TRUE);
690 if (err) {
691 DHD_ERROR(("%s: error changing sd_mode: %d\n",
692 __FUNCTION__, err));
693 return BCME_ERROR;
694 }
695 } else if (bus->idleclock != DHD_IDLE_ACTIVE) {
696 /* Restore clock speed */
697 iovalue = bus->sd_divisor;
698 err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
699 &iovalue, sizeof(iovalue), TRUE);
700 if (err) {
701 DHD_ERROR(("%s: error restoring sd_divisor: %d\n",
702 __FUNCTION__, err));
703 return BCME_ERROR;
704 }
705 }
706 bus->clkstate = CLK_SDONLY;
707 } else {
708 /* Stop or slow the SD clock itself */
709 if ((bus->sd_divisor == -1) || (bus->sd_mode == -1)) {
710 DHD_TRACE(("%s: can't idle clock, divisor %d mode %d\n",
711 __FUNCTION__, bus->sd_divisor, bus->sd_mode));
712 return BCME_ERROR;
713 }
714 if (bus->idleclock == DHD_IDLE_STOP) {
715 if (sd1idle) {
716 /* Change to SD1 mode and turn off clock */
717 iovalue = 1;
718 err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
719 &iovalue, sizeof(iovalue), TRUE);
720 if (err) {
721 DHD_ERROR(("%s: error changing sd_clock: %d\n",
722 __FUNCTION__, err));
723 return BCME_ERROR;
724 }
725 }
726
727 iovalue = 0;
728 err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0,
729 &iovalue, sizeof(iovalue), TRUE);
730 if (err) {
731 DHD_ERROR(("%s: error disabling sd_clock: %d\n",
732 __FUNCTION__, err));
733 return BCME_ERROR;
734 }
735 } else if (bus->idleclock != DHD_IDLE_ACTIVE) {
736 /* Set divisor to idle value */
737 iovalue = bus->idleclock;
738 err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
739 &iovalue, sizeof(iovalue), TRUE);
740 if (err) {
741 DHD_ERROR(("%s: error changing sd_divisor: %d\n",
742 __FUNCTION__, err));
743 return BCME_ERROR;
744 }
745 }
746 bus->clkstate = CLK_NONE;
747 }
748
749 return BCME_OK;
750}
751
752/* Transition SD and backplane clock readiness */
753static int
754dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok)
755{
756 int ret = BCME_OK;
757#ifdef DHD_DEBUG
758 uint oldstate = bus->clkstate;
759#endif /* DHD_DEBUG */
760
761 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
762
763 /* Early exit if we're already there */
764 if (bus->clkstate == target) {
765 if (target == CLK_AVAIL) {
766 dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
767 bus->activity = TRUE;
768 }
769 return ret;
770 }
771
772 switch (target) {
773 case CLK_AVAIL:
774 /* Make sure SD clock is available */
775 if (bus->clkstate == CLK_NONE)
776 dhdsdio_sdclk(bus, TRUE);
777 /* Now request HT Avail on the backplane */
778 ret = dhdsdio_htclk(bus, TRUE, pendok);
779 if (ret == BCME_OK) {
780 dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
781 bus->activity = TRUE;
782 }
783 break;
784
785 case CLK_SDONLY:
786 /* Remove HT request, or bring up SD clock */
787 if (bus->clkstate == CLK_NONE)
788 ret = dhdsdio_sdclk(bus, TRUE);
789 else if (bus->clkstate == CLK_AVAIL)
790 ret = dhdsdio_htclk(bus, FALSE, FALSE);
791 else
792 DHD_ERROR(("dhdsdio_clkctl: request for %d -> %d\n",
793 bus->clkstate, target));
794 if (ret == BCME_OK) {
795 dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
796 }
797 break;
798
799 case CLK_NONE:
800 /* Make sure to remove HT request */
801 if (bus->clkstate == CLK_AVAIL)
802 ret = dhdsdio_htclk(bus, FALSE, FALSE);
803 /* Now remove the SD clock */
804 ret = dhdsdio_sdclk(bus, FALSE);
805#ifdef DHD_DEBUG
806 if (dhd_console_ms == 0)
807#endif /* DHD_DEBUG */
808 if (bus->poll == 0)
809 dhd_os_wd_timer(bus->dhd, 0);
810 break;
811 }
812#ifdef DHD_DEBUG
813 DHD_INFO(("dhdsdio_clkctl: %d -> %d\n", oldstate, bus->clkstate));
814#endif /* DHD_DEBUG */
815
816 return ret;
817}
818
819static int
820dhdsdio_bussleep(dhd_bus_t *bus, bool sleep)
821{
822 bcmsdh_info_t *sdh = bus->sdh;
823 sdpcmd_regs_t *regs = bus->regs;
824 uint retries = 0;
825
826 DHD_INFO(("dhdsdio_bussleep: request %s (currently %s)\n",
827 (sleep ? "SLEEP" : "WAKE"),
828 (bus->sleeping ? "SLEEP" : "WAKE")));
829
830 /* Done if we're already in the requested state */
831 if (sleep == bus->sleeping)
832 return BCME_OK;
833
834 /* Going to sleep: set the alarm and turn off the lights... */
835 if (sleep) {
836 /* Don't sleep if something is pending */
837 if (bus->dpc_sched || bus->rxskip || pktq_len(&bus->txq))
838 return BCME_BUSY;
839
840
841 /* Disable SDIO interrupts (no longer interested) */
842 bcmsdh_intr_disable(bus->sdh);
843
844 /* Make sure the controller has the bus up */
845 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
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 /* Turn off our contribution to the HT clock request */
853 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
854
855 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
856 SBSDIO_FORCE_HW_CLKREQ_OFF, NULL);
857
858 /* Isolate the bus */
859 if (bus->sih->chip != BCM4329_CHIP_ID && bus->sih->chip != BCM4319_CHIP_ID) {
860 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL,
861 SBSDIO_DEVCTL_PADS_ISO, NULL);
862 }
863
864 /* Change state */
865 bus->sleeping = TRUE;
866
867 } else {
868 /* Waking up: bus power up is ok, set local state */
869
870 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
871 0, NULL);
872
873 /* Force pad isolation off if possible (in case power never toggled) */
874 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, 0, NULL);
875
876
877 /* Make sure the controller has the bus up */
878 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
879
880 /* Send misc interrupt to indicate OOB not needed */
881 W_SDREG(0, ®s->tosbmailboxdata, retries);
882 if (retries <= retry_limit)
883 W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries);
884
885 if (retries > retry_limit)
886 DHD_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n"));
887
888 /* Make sure we have SD bus access */
889 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
890
891 /* Change state */
892 bus->sleeping = FALSE;
893
894 /* Enable interrupts again */
895 if (bus->intr && (bus->dhd->busstate == DHD_BUS_DATA)) {
896 bus->intdis = FALSE;
897 bcmsdh_intr_enable(bus->sdh);
898 }
899 }
900
901 return BCME_OK;
902}
903
904#if defined(OOB_INTR_ONLY)
905void
906dhd_enable_oob_intr(struct dhd_bus *bus, bool enable)
907{
908#if defined(HW_OOB)
909 bcmsdh_enable_hw_oob_intr(bus->sdh, enable);
910#else
911 sdpcmd_regs_t *regs = bus->regs;
912 uint retries = 0;
913
914 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
915 if (enable == TRUE) {
916
917 /* Tell device to start using OOB wakeup */
918 W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries);
919 if (retries > retry_limit)
920 DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
921
922 } else {
923 /* Send misc interrupt to indicate OOB not needed */
924 W_SDREG(0, ®s->tosbmailboxdata, retries);
925 if (retries <= retry_limit)
926 W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries);
927 }
928
929 /* Turn off our contribution to the HT clock request */
930 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
931#endif /* !defined(HW_OOB) */
932}
933#endif /* defined(OOB_INTR_ONLY) */
934
935/* Writes a HW/SW header into the packet and sends it. */
936/* Assumes: (a) header space already there, (b) caller holds lock */
937static int
938dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt)
939{
940 int ret;
941 osl_t *osh;
942 uint8 *frame;
943 uint16 len, pad1 = 0;
944 uint32 swheader;
945 uint retries = 0;
946 bcmsdh_info_t *sdh;
947 void *new;
948 int i;
949#ifdef WLMEDIA_HTSF
950 char *p;
951 htsfts_t *htsf_ts;
952#endif
953
954
955 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
956
957 sdh = bus->sdh;
958 osh = bus->dhd->osh;
959
960 if (bus->dhd->dongle_reset) {
961 ret = BCME_NOTREADY;
962 goto done;
963 }
964
965 frame = (uint8*)PKTDATA(osh, pkt);
966
967#ifdef WLMEDIA_HTSF
968 if (PKTLEN(osh, pkt) >= 100) {
969 p = PKTDATA(osh, pkt);
970 htsf_ts = (htsfts_t*) (p + HTSF_HOSTOFFSET + 12);
971 if (htsf_ts->magic == HTSFMAGIC) {
972 htsf_ts->c20 = get_cycles();
973 htsf_ts->t20 = dhd_get_htsf(bus->dhd->info, 0);
974 }
975 }
976#endif /* WLMEDIA_HTSF */
977
978 /* Add alignment padding, allocate new packet if needed */
979 if ((pad1 = ((uintptr)frame % DHD_SDALIGN))) {
980 if (PKTHEADROOM(osh, pkt) < pad1) {
981 DHD_INFO(("%s: insufficient headroom %d for %d pad1\n",
982 __FUNCTION__, (int)PKTHEADROOM(osh, pkt), pad1));
983 bus->dhd->tx_realloc++;
984 new = PKTGET(osh, (PKTLEN(osh, pkt) + DHD_SDALIGN), TRUE);
985 if (!new) {
986 DHD_ERROR(("%s: couldn't allocate new %d-byte packet\n",
987 __FUNCTION__, PKTLEN(osh, pkt) + DHD_SDALIGN));
988 ret = BCME_NOMEM;
989 goto done;
990 }
991
992 PKTALIGN(osh, new, PKTLEN(osh, pkt), DHD_SDALIGN);
993 bcopy(PKTDATA(osh, pkt), PKTDATA(osh, new), PKTLEN(osh, pkt));
994 if (free_pkt)
995 PKTFREE(osh, pkt, TRUE);
996 /* free the pkt if canned one is not used */
997 free_pkt = TRUE;
998 pkt = new;
999 frame = (uint8*)PKTDATA(osh, pkt);
1000 ASSERT(((uintptr)frame % DHD_SDALIGN) == 0);
1001 pad1 = 0;
1002 } else {
1003 PKTPUSH(osh, pkt, pad1);
1004 frame = (uint8*)PKTDATA(osh, pkt);
1005
1006 ASSERT((pad1 + SDPCM_HDRLEN) <= (int) PKTLEN(osh, pkt));
1007 bzero(frame, pad1 + SDPCM_HDRLEN);
1008 }
1009 }
1010 ASSERT(pad1 < DHD_SDALIGN);
1011
1012 /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
1013 len = (uint16)PKTLEN(osh, pkt);
1014 *(uint16*)frame = htol16(len);
1015 *(((uint16*)frame) + 1) = htol16(~len);
1016
1017 /* Software tag: channel, sequence number, data offset */
1018 swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) | bus->tx_seq |
1019 (((pad1 + SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
1020 htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN);
1021 htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
1022
1023#ifdef DHD_DEBUG
1024 if (PKTPRIO(pkt) < ARRAYSIZE(tx_packets)) {
1025 tx_packets[PKTPRIO(pkt)]++;
1026 }
1027 if (DHD_BYTES_ON() &&
1028 (((DHD_CTL_ON() && (chan == SDPCM_CONTROL_CHANNEL)) ||
1029 (DHD_DATA_ON() && (chan != SDPCM_CONTROL_CHANNEL))))) {
1030 prhex("Tx Frame", frame, len);
1031 } else if (DHD_HDRS_ON()) {
1032 prhex("TxHdr", frame, MIN(len, 16));
1033 }
1034#endif
1035
1036 /* Raise len to next SDIO block to eliminate tail command */
1037 if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
1038 uint16 pad2 = bus->blocksize - (len % bus->blocksize);
1039 if ((pad2 <= bus->roundup) && (pad2 < bus->blocksize))
1040#ifdef NOTUSED
1041 if (pad2 <= PKTTAILROOM(osh, pkt))
1042#endif /* NOTUSED */
1043 len += pad2;
1044 } else if (len % DHD_SDALIGN) {
1045 len += DHD_SDALIGN - (len % DHD_SDALIGN);
1046 }
1047
1048 /* Some controllers have trouble with odd bytes -- round to even */
1049 if (forcealign && (len & (ALIGNMENT - 1))) {
1050#ifdef NOTUSED
1051 if (PKTTAILROOM(osh, pkt))
1052#endif
1053 len = ROUNDUP(len, ALIGNMENT);
1054#ifdef NOTUSED
1055 else
1056 DHD_ERROR(("%s: sending unrounded %d-byte packet\n", __FUNCTION__, len));
1057#endif
1058 }
1059
1060 do {
1061 ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
1062 frame, len, pkt, NULL, NULL);
1063 bus->f2txdata++;
1064 ASSERT(ret != BCME_PENDING);
1065
1066 if (ret < 0) {
1067 /* On failure, abort the command and terminate the frame */
1068 DHD_INFO(("%s: sdio error %d, abort command and terminate frame.\n",
1069 __FUNCTION__, ret));
1070 bus->tx_sderrs++;
1071
1072 bcmsdh_abort(sdh, SDIO_FUNC_2);
1073 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
1074 SFC_WF_TERM, NULL);
1075 bus->f1regdata++;
1076
1077 for (i = 0; i < 3; i++) {
1078 uint8 hi, lo;
1079 hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
1080 SBSDIO_FUNC1_WFRAMEBCHI, NULL);
1081 lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
1082 SBSDIO_FUNC1_WFRAMEBCLO, NULL);
1083 bus->f1regdata += 2;
1084 if ((hi == 0) && (lo == 0))
1085 break;
1086 }
1087
1088 }
1089 if (ret == 0) {
1090 bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
1091 }
1092 } while ((ret < 0) && retrydata && retries++ < TXRETRIES);
1093
1094done:
1095 /* restore pkt buffer pointer before calling tx complete routine */
1096 PKTPULL(osh, pkt, SDPCM_HDRLEN + pad1);
1097#ifdef PROP_TXSTATUS
1098 if (bus->dhd->wlfc_state) {
1099 dhd_os_sdunlock(bus->dhd);
1100 dhd_wlfc_txcomplete(bus->dhd, pkt, ret == 0);
1101 dhd_os_sdlock(bus->dhd);
1102 } else {
1103#endif /* PROP_TXSTATUS */
1104 dhd_txcomplete(bus->dhd, pkt, ret != 0);
1105 if (free_pkt)
1106 PKTFREE(osh, pkt, TRUE);
1107
1108#ifdef PROP_TXSTATUS
1109 }
1110#endif
1111 return ret;
1112}
1113
1114int
1115dhd_bus_txdata(struct dhd_bus *bus, void *pkt)
1116{
1117 int ret = BCME_ERROR;
1118 osl_t *osh;
1119 uint datalen, prec;
1120
1121 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1122
1123 osh = bus->dhd->osh;
1124 datalen = PKTLEN(osh, pkt);
1125
1126#ifdef SDTEST
1127 /* Push the test header if doing loopback */
1128 if (bus->ext_loop) {
1129 uint8* data;
1130 PKTPUSH(osh, pkt, SDPCM_TEST_HDRLEN);
1131 data = PKTDATA(osh, pkt);
1132 *data++ = SDPCM_TEST_ECHOREQ;
1133 *data++ = (uint8)bus->loopid++;
1134 *data++ = (datalen >> 0);
1135 *data++ = (datalen >> 8);
1136 datalen += SDPCM_TEST_HDRLEN;
1137 }
1138#endif /* SDTEST */
1139
1140 /* Add space for the header */
1141 PKTPUSH(osh, pkt, SDPCM_HDRLEN);
1142 ASSERT(ISALIGNED((uintptr)PKTDATA(osh, pkt), 2));
1143
1144 prec = PRIO2PREC((PKTPRIO(pkt) & PRIOMASK));
1145#ifndef DHDTHREAD
1146 /* Lock: we're about to use shared data/code (and SDIO) */
1147 dhd_os_sdlock(bus->dhd);
1148#endif /* DHDTHREAD */
1149
1150 /* Check for existing queue, current flow-control, pending event, or pending clock */
1151 if (dhd_deferred_tx || bus->fcstate || pktq_len(&bus->txq) || bus->dpc_sched ||
1152 (!DATAOK(bus)) || (bus->flowcontrol & NBITVAL(prec)) ||
1153 (bus->clkstate != CLK_AVAIL)) {
1154 DHD_TRACE(("%s: deferring pktq len %d\n", __FUNCTION__,
1155 pktq_len(&bus->txq)));
1156 bus->fcqueued++;
1157
1158 /* Priority based enq */
1159 dhd_os_sdlock_txq(bus->dhd);
1160 if (dhd_prec_enq(bus->dhd, &bus->txq, pkt, prec) == FALSE) {
1161 PKTPULL(osh, pkt, SDPCM_HDRLEN);
1162#ifndef DHDTHREAD
1163 /* Need to also release txqlock before releasing sdlock.
1164 * This thread still has txqlock and releases sdlock.
1165 * Deadlock happens when dpc() grabs sdlock first then
1166 * attempts to grab txqlock.
1167 */
1168 dhd_os_sdunlock_txq(bus->dhd);
1169 dhd_os_sdunlock(bus->dhd);
1170#endif
1171#ifdef PROP_TXSTATUS
1172 if (bus->dhd->wlfc_state)
1173 dhd_wlfc_txcomplete(bus->dhd, pkt, FALSE);
1174 else
1175#endif
1176 dhd_txcomplete(bus->dhd, pkt, FALSE);
1177#ifndef DHDTHREAD
1178 dhd_os_sdlock(bus->dhd);
1179 dhd_os_sdlock_txq(bus->dhd);
1180#endif
1181#ifdef PROP_TXSTATUS
1182 /* let the caller decide whether to free the packet */
1183 if (!bus->dhd->wlfc_state)
1184#endif
1185 PKTFREE(osh, pkt, TRUE);
1186 ret = BCME_NORESOURCE;
1187 }
1188 else
1189 ret = BCME_OK;
1190 dhd_os_sdunlock_txq(bus->dhd);
1191
1192 if ((pktq_len(&bus->txq) >= FCHI) && dhd_doflow)
1193 dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON);
1194
1195#ifdef DHD_DEBUG
1196 if (pktq_plen(&bus->txq, prec) > qcount[prec])
1197 qcount[prec] = pktq_plen(&bus->txq, prec);
1198#endif
1199 /* Schedule DPC if needed to send queued packet(s) */
1200 if (dhd_deferred_tx && !bus->dpc_sched) {
1201 bus->dpc_sched = TRUE;
1202 dhd_sched_dpc(bus->dhd);
1203 }
1204 } else {
1205#ifdef DHDTHREAD
1206 /* Lock: we're about to use shared data/code (and SDIO) */
1207 dhd_os_sdlock(bus->dhd);
1208#endif /* DHDTHREAD */
1209
1210 /* Otherwise, send it now */
1211 BUS_WAKE(bus);
1212 /* Make sure back plane ht clk is on, no pending allowed */
1213 dhdsdio_clkctl(bus, CLK_AVAIL, TRUE);
1214#ifndef SDTEST
1215 ret = dhdsdio_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, TRUE);
1216#else
1217 ret = dhdsdio_txpkt(bus, pkt,
1218 (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL), TRUE);
1219#endif
1220 if (ret)
1221 bus->dhd->tx_errors++;
1222 else
1223 bus->dhd->dstats.tx_bytes += datalen;
1224
1225 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
1226 bus->activity = FALSE;
1227 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
1228 }
1229
1230#ifdef DHDTHREAD
1231 dhd_os_sdunlock(bus->dhd);
1232#endif /* DHDTHREAD */
1233 }
1234
1235#ifndef DHDTHREAD
1236 dhd_os_sdunlock(bus->dhd);
1237#endif /* DHDTHREAD */
1238
1239 return ret;
1240}
1241
1242static uint
1243dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes)
1244{
1245 void *pkt;
1246 uint32 intstatus = 0;
1247 uint retries = 0;
1248 int ret = 0, prec_out;
1249 uint cnt = 0;
1250 uint datalen;
1251 uint8 tx_prec_map;
1252
1253 dhd_pub_t *dhd = bus->dhd;
1254 sdpcmd_regs_t *regs = bus->regs;
1255
1256 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1257
1258 tx_prec_map = ~bus->flowcontrol;
1259
1260 /* Send frames until the limit or some other event */
1261 for (cnt = 0; (cnt < maxframes) && DATAOK(bus); cnt++) {
1262 dhd_os_sdlock_txq(bus->dhd);
1263 if ((pkt = pktq_mdeq(&bus->txq, tx_prec_map, &prec_out)) == NULL) {
1264 dhd_os_sdunlock_txq(bus->dhd);
1265 break;
1266 }
1267 dhd_os_sdunlock_txq(bus->dhd);
1268 datalen = PKTLEN(bus->dhd->osh, pkt) - SDPCM_HDRLEN;
1269
1270#ifndef SDTEST
1271 ret = dhdsdio_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, TRUE);
1272#else
1273 ret = dhdsdio_txpkt(bus, pkt,
1274 (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL), TRUE);
1275#endif
1276 if (ret)
1277 bus->dhd->tx_errors++;
1278 else
1279 bus->dhd->dstats.tx_bytes += datalen;
1280
1281 /* In poll mode, need to check for other events */
1282 if (!bus->intr && cnt)
1283 {
1284 /* Check device status, signal pending interrupt */
1285 R_SDREG(intstatus, ®s->intstatus, retries);
1286 bus->f2txdata++;
1287 if (bcmsdh_regfail(bus->sdh))
1288 break;
1289 if (intstatus & bus->hostintmask)
1290 bus->ipend = TRUE;
1291 }
1292 }
1293
1294 /* Deflow-control stack if needed */
1295 if (dhd_doflow && dhd->up && (dhd->busstate == DHD_BUS_DATA) &&
1296 dhd->txoff && (pktq_len(&bus->txq) < FCLOW))
1297 dhd_txflowcontrol(dhd, ALL_INTERFACES, OFF);
1298
1299 return cnt;
1300}
1301
1302int
1303dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen)
1304{
1305 uint8 *frame;
1306 uint16 len;
1307 uint32 swheader;
1308 uint retries = 0;
1309 bcmsdh_info_t *sdh = bus->sdh;
1310 uint8 doff = 0;
1311 int ret = -1;
1312 int i;
1313
1314 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1315
1316 if (bus->dhd->dongle_reset)
1317 return -EIO;
1318
1319 /* Back the pointer to make a room for bus header */
1320 frame = msg - SDPCM_HDRLEN;
1321 len = (msglen += SDPCM_HDRLEN);
1322
1323 /* Add alignment padding (optional for ctl frames) */
1324 if (dhd_alignctl) {
1325 if ((doff = ((uintptr)frame % DHD_SDALIGN))) {
1326 frame -= doff;
1327 len += doff;
1328 msglen += doff;
1329 bzero(frame, doff + SDPCM_HDRLEN);
1330 }
1331 ASSERT(doff < DHD_SDALIGN);
1332 }
1333 doff += SDPCM_HDRLEN;
1334
1335 /* Round send length to next SDIO block */
1336 if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
1337 uint16 pad = bus->blocksize - (len % bus->blocksize);
1338 if ((pad <= bus->roundup) && (pad < bus->blocksize))
1339 len += pad;
1340 } else if (len % DHD_SDALIGN) {
1341 len += DHD_SDALIGN - (len % DHD_SDALIGN);
1342 }
1343
1344 /* Satisfy length-alignment requirements */
1345 if (forcealign && (len & (ALIGNMENT - 1)))
1346 len = ROUNDUP(len, ALIGNMENT);
1347
1348 ASSERT(ISALIGNED((uintptr)frame, 2));
1349
1350
1351 /* Need to lock here to protect txseq and SDIO tx calls */
1352 dhd_os_sdlock(bus->dhd);
1353
1354 BUS_WAKE(bus);
1355
1356 /* Make sure backplane clock is on */
1357 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
1358
1359 /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
1360 *(uint16*)frame = htol16((uint16)msglen);
1361 *(((uint16*)frame) + 1) = htol16(~msglen);
1362
1363 /* Software tag: channel, sequence number, data offset */
1364 swheader = ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK)
1365 | bus->tx_seq | ((doff << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
1366 htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN);
1367 htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
1368
1369 if (!TXCTLOK(bus)) {
1370 DHD_INFO(("%s: No bus credit bus->tx_max %d, bus->tx_seq %d\n",
1371 __FUNCTION__, bus->tx_max, bus->tx_seq));
1372 bus->ctrl_frame_stat = TRUE;
1373 /* Send from dpc */
1374 bus->ctrl_frame_buf = frame;
1375 bus->ctrl_frame_len = len;
1376 dhd_wait_for_event(bus->dhd, &bus->ctrl_frame_stat);
1377 if (bus->ctrl_frame_stat == FALSE) {
1378 DHD_INFO(("%s: ctrl_frame_stat == FALSE\n", __FUNCTION__));
1379 ret = 0;
1380 } else {
1381 bus->dhd->txcnt_timeout++;
1382 if (!bus->dhd->hang_was_sent)
1383 DHD_ERROR(("%s: ctrl_frame_stat == TRUE txcnt_timeout=%d\n",
1384 __FUNCTION__, bus->dhd->txcnt_timeout));
1385 ret = -1;
1386 bus->ctrl_frame_stat = FALSE;
1387 goto done;
1388 }
1389 }
1390
1391 bus->dhd->txcnt_timeout = 0;
1392
1393 if (ret == -1) {
1394#ifdef DHD_DEBUG
1395 if (DHD_BYTES_ON() && DHD_CTL_ON()) {
1396 prhex("Tx Frame", frame, len);
1397 } else if (DHD_HDRS_ON()) {
1398 prhex("TxHdr", frame, MIN(len, 16));
1399 }
1400#endif
1401
1402 do {
1403 ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
1404 frame, len, NULL, NULL, NULL);
1405 ASSERT(ret != BCME_PENDING);
1406
1407 if (ret < 0) {
1408 /* On failure, abort the command and terminate the frame */
1409 DHD_INFO(("%s: sdio error %d, abort command and terminate frame.\n",
1410 __FUNCTION__, ret));
1411 bus->tx_sderrs++;
1412
1413 bcmsdh_abort(sdh, SDIO_FUNC_2);
1414
1415 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
1416 SFC_WF_TERM, NULL);
1417 bus->f1regdata++;
1418
1419 for (i = 0; i < 3; i++) {
1420 uint8 hi, lo;
1421 hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
1422 SBSDIO_FUNC1_WFRAMEBCHI, NULL);
1423 lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
1424 SBSDIO_FUNC1_WFRAMEBCLO, NULL);
1425 bus->f1regdata += 2;
1426 if ((hi == 0) && (lo == 0))
1427 break;
1428 }
1429
1430 }
1431 if (ret == 0) {
1432 bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
1433 }
1434 } while ((ret < 0) && retries++ < TXRETRIES);
1435 }
1436
1437done:
1438 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
1439 bus->activity = FALSE;
1440 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
1441 }
1442
1443 dhd_os_sdunlock(bus->dhd);
1444
1445 if (ret)
1446 bus->dhd->tx_ctlerrs++;
1447 else
1448 bus->dhd->tx_ctlpkts++;
1449
1450 if (bus->dhd->txcnt_timeout >= MAX_CNTL_TIMEOUT)
1451 return -ETIMEDOUT;
1452
1453 return ret ? -EIO : 0;
1454}
1455
1456int
1457dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen)
1458{
1459 int timeleft;
1460 uint rxlen = 0;
1461 bool pending = FALSE;
1462
1463 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1464
1465 if (bus->dhd->dongle_reset)
1466 return -EIO;
1467
1468 /* Wait until control frame is available */
1469 timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->rxlen, &pending);
1470
1471 dhd_os_sdlock(bus->dhd);
1472 rxlen = bus->rxlen;
1473 bcopy(bus->rxctl, msg, MIN(msglen, rxlen));
1474 bus->rxlen = 0;
1475 dhd_os_sdunlock(bus->dhd);
1476
1477 if (rxlen) {
1478 DHD_CTL(("%s: resumed on rxctl frame, got %d expected %d\n",
1479 __FUNCTION__, rxlen, msglen));
1480 } else if (timeleft == 0) {
1481 DHD_ERROR(("%s: resumed on timeout\n", __FUNCTION__));
1482#ifdef DHD_DEBUG
1483 dhd_os_sdlock(bus->dhd);
1484 dhdsdio_checkdied(bus, NULL, 0);
1485 dhd_os_sdunlock(bus->dhd);
1486#endif /* DHD_DEBUG */
1487 } else if (pending == TRUE) {
1488 /* signal pending */
1489 DHD_ERROR(("%s: signal pending\n", __FUNCTION__));
1490 return -EINTR;
1491 } else {
1492 DHD_CTL(("%s: resumed for unknown reason?\n", __FUNCTION__));
1493#ifdef DHD_DEBUG
1494 dhd_os_sdlock(bus->dhd);
1495 dhdsdio_checkdied(bus, NULL, 0);
1496 dhd_os_sdunlock(bus->dhd);
1497#endif /* DHD_DEBUG */
1498 }
1499 if (timeleft == 0) {
1500 bus->dhd->rxcnt_timeout++;
1501 DHD_ERROR(("%s: rxcnt_timeout=%d\n", __FUNCTION__, bus->dhd->rxcnt_timeout));
1502 }
1503 else
1504 bus->dhd->rxcnt_timeout = 0;
1505
1506 if (rxlen)
1507 bus->dhd->rx_ctlpkts++;
1508 else
1509 bus->dhd->rx_ctlerrs++;
1510
1511 if (bus->dhd->rxcnt_timeout >= MAX_CNTL_TIMEOUT)
1512 return -ETIMEDOUT;
1513
1514 return rxlen ? (int)rxlen : -EIO;
1515}
1516
1517/* IOVar table */
1518enum {
1519 IOV_INTR = 1,
1520 IOV_POLLRATE,
1521 IOV_SDREG,
1522 IOV_SBREG,
1523 IOV_SDCIS,
1524 IOV_MEMBYTES,
1525 IOV_MEMSIZE,
1526#ifdef DHD_DEBUG
1527 IOV_CHECKDIED,
1528 IOV_SERIALCONS,
1529#endif /* DHD_DEBUG */
1530 IOV_DOWNLOAD,
1531 IOV_SOCRAM_STATE,
1532 IOV_FORCEEVEN,
1533 IOV_SDIOD_DRIVE,
1534 IOV_READAHEAD,
1535 IOV_SDRXCHAIN,
1536 IOV_ALIGNCTL,
1537 IOV_SDALIGN,
1538 IOV_DEVRESET,
1539 IOV_CPU,
1540#ifdef SDTEST
1541 IOV_PKTGEN,
1542 IOV_EXTLOOP,
1543#endif /* SDTEST */
1544 IOV_SPROM,
1545 IOV_TXBOUND,
1546 IOV_RXBOUND,
1547 IOV_TXMINMAX,
1548 IOV_IDLETIME,
1549 IOV_IDLECLOCK,
1550 IOV_SD1IDLE,
1551 IOV_SLEEP,
1552 IOV_DONGLEISOLATION,
1553 IOV_VARS,
1554#ifdef SOFTAP
1555 IOV_FWPATH
1556#endif
1557};
1558
1559const bcm_iovar_t dhdsdio_iovars[] = {
1560 {"intr", IOV_INTR, 0, IOVT_BOOL, 0 },
1561 {"sleep", IOV_SLEEP, 0, IOVT_BOOL, 0 },
1562 {"pollrate", IOV_POLLRATE, 0, IOVT_UINT32, 0 },
1563 {"idletime", IOV_IDLETIME, 0, IOVT_INT32, 0 },
1564 {"idleclock", IOV_IDLECLOCK, 0, IOVT_INT32, 0 },
1565 {"sd1idle", IOV_SD1IDLE, 0, IOVT_BOOL, 0 },
1566 {"membytes", IOV_MEMBYTES, 0, IOVT_BUFFER, 2 * sizeof(int) },
1567 {"memsize", IOV_MEMSIZE, 0, IOVT_UINT32, 0 },
1568 {"download", IOV_DOWNLOAD, 0, IOVT_BOOL, 0 },
1569 {"socram_state", IOV_SOCRAM_STATE, 0, IOVT_BOOL, 0 },
1570 {"vars", IOV_VARS, 0, IOVT_BUFFER, 0 },
1571 {"sdiod_drive", IOV_SDIOD_DRIVE, 0, IOVT_UINT32, 0 },
1572 {"readahead", IOV_READAHEAD, 0, IOVT_BOOL, 0 },
1573 {"sdrxchain", IOV_SDRXCHAIN, 0, IOVT_BOOL, 0 },
1574 {"alignctl", IOV_ALIGNCTL, 0, IOVT_BOOL, 0 },
1575 {"sdalign", IOV_SDALIGN, 0, IOVT_BOOL, 0 },
1576 {"devreset", IOV_DEVRESET, 0, IOVT_BOOL, 0 },
1577#ifdef DHD_DEBUG
1578 {"sdreg", IOV_SDREG, 0, IOVT_BUFFER, sizeof(sdreg_t) },
1579 {"sbreg", IOV_SBREG, 0, IOVT_BUFFER, sizeof(sdreg_t) },
1580 {"sd_cis", IOV_SDCIS, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN },
1581 {"forcealign", IOV_FORCEEVEN, 0, IOVT_BOOL, 0 },
1582 {"txbound", IOV_TXBOUND, 0, IOVT_UINT32, 0 },
1583 {"rxbound", IOV_RXBOUND, 0, IOVT_UINT32, 0 },
1584 {"txminmax", IOV_TXMINMAX, 0, IOVT_UINT32, 0 },
1585 {"cpu", IOV_CPU, 0, IOVT_BOOL, 0 },
1586#ifdef DHD_DEBUG
1587 {"checkdied", IOV_CHECKDIED, 0, IOVT_BUFFER, 0 },
1588 {"serial", IOV_SERIALCONS, 0, IOVT_UINT32, 0 },
1589#endif /* DHD_DEBUG */
1590#endif /* DHD_DEBUG */
1591#ifdef SDTEST
1592 {"extloop", IOV_EXTLOOP, 0, IOVT_BOOL, 0 },
1593 {"pktgen", IOV_PKTGEN, 0, IOVT_BUFFER, sizeof(dhd_pktgen_t) },
1594#endif /* SDTEST */
1595 {"dngl_isolation", IOV_DONGLEISOLATION, 0, IOVT_UINT32, 0 },
1596#ifdef SOFTAP
1597 {"fwpath", IOV_FWPATH, 0, IOVT_BUFFER, 0 },
1598#endif
1599 {NULL, 0, 0, 0, 0 }
1600};
1601
1602static void
1603dhd_dump_pct(struct bcmstrbuf *strbuf, char *desc, uint num, uint div)
1604{
1605 uint q1, q2;
1606
1607 if (!div) {
1608 bcm_bprintf(strbuf, "%s N/A", desc);
1609 } else {
1610 q1 = num / div;
1611 q2 = (100 * (num - (q1 * div))) / div;
1612 bcm_bprintf(strbuf, "%s %d.%02d", desc, q1, q2);
1613 }
1614}
1615
1616void
1617dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf)
1618{
1619 dhd_bus_t *bus = dhdp->bus;
1620
1621 bcm_bprintf(strbuf, "Bus SDIO structure:\n");
1622 bcm_bprintf(strbuf, "hostintmask 0x%08x intstatus 0x%08x sdpcm_ver %d\n",
1623 bus->hostintmask, bus->intstatus, bus->sdpcm_ver);
1624 bcm_bprintf(strbuf, "fcstate %d qlen %d tx_seq %d, max %d, rxskip %d rxlen %d rx_seq %d\n",
1625 bus->fcstate, pktq_len(&bus->txq), bus->tx_seq, bus->tx_max, bus->rxskip,
1626 bus->rxlen, bus->rx_seq);
1627 bcm_bprintf(strbuf, "intr %d intrcount %d lastintrs %d spurious %d\n",
1628 bus->intr, bus->intrcount, bus->lastintrs, bus->spurious);
1629 bcm_bprintf(strbuf, "pollrate %d pollcnt %d regfails %d\n",
1630 bus->pollrate, bus->pollcnt, bus->regfails);
1631
1632 bcm_bprintf(strbuf, "\nAdditional counters:\n");
1633 bcm_bprintf(strbuf, "tx_sderrs %d fcqueued %d rxrtx %d rx_toolong %d rxc_errors %d\n",
1634 bus->tx_sderrs, bus->fcqueued, bus->rxrtx, bus->rx_toolong,
1635 bus->rxc_errors);
1636 bcm_bprintf(strbuf, "rx_hdrfail %d badhdr %d badseq %d\n",
1637 bus->rx_hdrfail, bus->rx_badhdr, bus->rx_badseq);
1638 bcm_bprintf(strbuf, "fc_rcvd %d, fc_xoff %d, fc_xon %d\n",
1639 bus->fc_rcvd, bus->fc_xoff, bus->fc_xon);
1640 bcm_bprintf(strbuf, "rxglomfail %d, rxglomframes %d, rxglompkts %d\n",
1641 bus->rxglomfail, bus->rxglomframes, bus->rxglompkts);
1642 bcm_bprintf(strbuf, "f2rx (hdrs/data) %d (%d/%d), f2tx %d f1regs %d\n",
1643 (bus->f2rxhdrs + bus->f2rxdata), bus->f2rxhdrs, bus->f2rxdata,
1644 bus->f2txdata, bus->f1regdata);
1645 {
1646 dhd_dump_pct(strbuf, "\nRx: pkts/f2rd", bus->dhd->rx_packets,
1647 (bus->f2rxhdrs + bus->f2rxdata));
1648 dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->rx_packets, bus->f1regdata);
1649 dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->rx_packets,
1650 (bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata));
1651 dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->rx_packets, bus->intrcount);
1652 bcm_bprintf(strbuf, "\n");
1653
1654 dhd_dump_pct(strbuf, "Rx: glom pct", (100 * bus->rxglompkts),
1655 bus->dhd->rx_packets);
1656 dhd_dump_pct(strbuf, ", pkts/glom", bus->rxglompkts, bus->rxglomframes);
1657 bcm_bprintf(strbuf, "\n");
1658
1659 dhd_dump_pct(strbuf, "Tx: pkts/f2wr", bus->dhd->tx_packets, bus->f2txdata);
1660 dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->tx_packets, bus->f1regdata);
1661 dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->tx_packets,
1662 (bus->f2txdata + bus->f1regdata));
1663 dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->tx_packets, bus->intrcount);
1664 bcm_bprintf(strbuf, "\n");
1665
1666 dhd_dump_pct(strbuf, "Total: pkts/f2rw",
1667 (bus->dhd->tx_packets + bus->dhd->rx_packets),
1668 (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata));
1669 dhd_dump_pct(strbuf, ", pkts/f1sd",
1670 (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->f1regdata);
1671 dhd_dump_pct(strbuf, ", pkts/sd",
1672 (bus->dhd->tx_packets + bus->dhd->rx_packets),
1673 (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata));
1674 dhd_dump_pct(strbuf, ", pkts/int",
1675 (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->intrcount);
1676 bcm_bprintf(strbuf, "\n\n");
1677 }
1678
1679#ifdef SDTEST
1680 if (bus->pktgen_count) {
1681 bcm_bprintf(strbuf, "pktgen config and count:\n");
1682 bcm_bprintf(strbuf, "freq %d count %d print %d total %d min %d len %d\n",
1683 bus->pktgen_freq, bus->pktgen_count, bus->pktgen_print,
1684 bus->pktgen_total, bus->pktgen_minlen, bus->pktgen_maxlen);
1685 bcm_bprintf(strbuf, "send attempts %d rcvd %d fail %d\n",
1686 bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail);
1687 }
1688#endif /* SDTEST */
1689#ifdef DHD_DEBUG
1690 bcm_bprintf(strbuf, "dpc_sched %d host interrupt%spending\n",
1691 bus->dpc_sched, (bcmsdh_intr_pending(bus->sdh) ? " " : " not "));
1692 bcm_bprintf(strbuf, "blocksize %d roundup %d\n", bus->blocksize, bus->roundup);
1693#endif /* DHD_DEBUG */
1694 bcm_bprintf(strbuf, "clkstate %d activity %d idletime %d idlecount %d sleeping %d\n",
1695 bus->clkstate, bus->activity, bus->idletime, bus->idlecount, bus->sleeping);
1696}
1697
1698void
1699dhd_bus_clearcounts(dhd_pub_t *dhdp)
1700{
1701 dhd_bus_t *bus = (dhd_bus_t *)dhdp->bus;
1702
1703 bus->intrcount = bus->lastintrs = bus->spurious = bus->regfails = 0;
1704 bus->rxrtx = bus->rx_toolong = bus->rxc_errors = 0;
1705 bus->rx_hdrfail = bus->rx_badhdr = bus->rx_badseq = 0;
1706 bus->tx_sderrs = bus->fc_rcvd = bus->fc_xoff = bus->fc_xon = 0;
1707 bus->rxglomfail = bus->rxglomframes = bus->rxglompkts = 0;
1708 bus->f2rxhdrs = bus->f2rxdata = bus->f2txdata = bus->f1regdata = 0;
1709}
1710
1711#ifdef SDTEST
1712static int
1713dhdsdio_pktgen_get(dhd_bus_t *bus, uint8 *arg)
1714{
1715 dhd_pktgen_t pktgen;
1716
1717 pktgen.version = DHD_PKTGEN_VERSION;
1718 pktgen.freq = bus->pktgen_freq;
1719 pktgen.count = bus->pktgen_count;
1720 pktgen.print = bus->pktgen_print;
1721 pktgen.total = bus->pktgen_total;
1722 pktgen.minlen = bus->pktgen_minlen;
1723 pktgen.maxlen = bus->pktgen_maxlen;
1724 pktgen.numsent = bus->pktgen_sent;
1725 pktgen.numrcvd = bus->pktgen_rcvd;
1726 pktgen.numfail = bus->pktgen_fail;
1727 pktgen.mode = bus->pktgen_mode;
1728 pktgen.stop = bus->pktgen_stop;
1729
1730 bcopy(&pktgen, arg, sizeof(pktgen));
1731
1732 return 0;
1733}
1734
1735static int
1736dhdsdio_pktgen_set(dhd_bus_t *bus, uint8 *arg)
1737{
1738 dhd_pktgen_t pktgen;
1739 uint oldcnt, oldmode;
1740
1741 bcopy(arg, &pktgen, sizeof(pktgen));
1742 if (pktgen.version != DHD_PKTGEN_VERSION)
1743 return BCME_BADARG;
1744
1745 oldcnt = bus->pktgen_count;
1746 oldmode = bus->pktgen_mode;
1747
1748 bus->pktgen_freq = pktgen.freq;
1749 bus->pktgen_count = pktgen.count;
1750 bus->pktgen_print = pktgen.print;
1751 bus->pktgen_total = pktgen.total;
1752 bus->pktgen_minlen = pktgen.minlen;
1753 bus->pktgen_maxlen = pktgen.maxlen;
1754 bus->pktgen_mode = pktgen.mode;
1755 bus->pktgen_stop = pktgen.stop;
1756
1757 bus->pktgen_tick = bus->pktgen_ptick = 0;
1758 bus->pktgen_len = MAX(bus->pktgen_len, bus->pktgen_minlen);
1759 bus->pktgen_len = MIN(bus->pktgen_len, bus->pktgen_maxlen);
1760
1761 /* Clear counts for a new pktgen (mode change, or was stopped) */
1762 if (bus->pktgen_count && (!oldcnt || oldmode != bus->pktgen_mode))
1763 bus->pktgen_sent = bus->pktgen_rcvd = bus->pktgen_fail = 0;
1764
1765 return 0;
1766}
1767#endif /* SDTEST */
1768
1769static int
1770dhdsdio_membytes(dhd_bus_t *bus, bool write, uint32 address, uint8 *data, uint size)
1771{
1772 int bcmerror = 0;
1773 uint32 sdaddr;
1774 uint dsize;
1775
1776 /* Determine initial transfer parameters */
1777 sdaddr = address & SBSDIO_SB_OFT_ADDR_MASK;
1778 if ((sdaddr + size) & SBSDIO_SBWINDOW_MASK)
1779 dsize = (SBSDIO_SB_OFT_ADDR_LIMIT - sdaddr);
1780 else
1781 dsize = size;
1782
1783 /* Set the backplane window to include the start address */
1784 if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) {
1785 DHD_ERROR(("%s: window change failed\n", __FUNCTION__));
1786 goto xfer_done;
1787 }
1788
1789 /* Do the transfer(s) */
1790 while (size) {
1791 DHD_INFO(("%s: %s %d bytes at offset 0x%08x in window 0x%08x\n",
1792 __FUNCTION__, (write ? "write" : "read"), dsize, sdaddr,
1793 (address & SBSDIO_SBWINDOW_MASK)));
1794 if ((bcmerror = bcmsdh_rwdata(bus->sdh, write, sdaddr, data, dsize))) {
1795 DHD_ERROR(("%s: membytes transfer failed\n", __FUNCTION__));
1796 break;
1797 }
1798
1799 /* Adjust for next transfer (if any) */
1800 if ((size -= dsize)) {
1801 data += dsize;
1802 address += dsize;
1803 if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) {
1804 DHD_ERROR(("%s: window change failed\n", __FUNCTION__));
1805 break;
1806 }
1807 sdaddr = 0;
1808 dsize = MIN(SBSDIO_SB_OFT_ADDR_LIMIT, size);
1809 }
1810
1811 }
1812
1813xfer_done:
1814 /* Return the window to backplane enumeration space for core access */
1815 if (dhdsdio_set_siaddr_window(bus, bcmsdh_cur_sbwad(bus->sdh))) {
1816 DHD_ERROR(("%s: FAILED to set window back to 0x%x\n", __FUNCTION__,
1817 bcmsdh_cur_sbwad(bus->sdh)));
1818 }
1819
1820 return bcmerror;
1821}
1822
1823#ifdef DHD_DEBUG
1824static int
1825dhdsdio_readshared(dhd_bus_t *bus, sdpcm_shared_t *sh)
1826{
1827 uint32 addr;
1828 int rv;
1829
1830 /* Read last word in memory to determine address of sdpcm_shared structure */
1831 if ((rv = dhdsdio_membytes(bus, FALSE, bus->ramsize - 4, (uint8 *)&addr, 4)) < 0)
1832 return rv;
1833
1834 addr = ltoh32(addr);
1835
1836 DHD_INFO(("sdpcm_shared address 0x%08X\n", addr));
1837
1838 /*
1839 * Check if addr is valid.
1840 * NVRAM length at the end of memory should have been overwritten.
1841 */
1842 if (addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff)) {
1843 DHD_ERROR(("%s: address (0x%08x) of sdpcm_shared invalid\n", __FUNCTION__, addr));
1844 return BCME_ERROR;
1845 }
1846
1847 /* Read hndrte_shared structure */
1848 if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)sh, sizeof(sdpcm_shared_t))) < 0)
1849 return rv;
1850
1851 /* Endianness */
1852 sh->flags = ltoh32(sh->flags);
1853 sh->trap_addr = ltoh32(sh->trap_addr);
1854 sh->assert_exp_addr = ltoh32(sh->assert_exp_addr);
1855 sh->assert_file_addr = ltoh32(sh->assert_file_addr);
1856 sh->assert_line = ltoh32(sh->assert_line);
1857 sh->console_addr = ltoh32(sh->console_addr);
1858 sh->msgtrace_addr = ltoh32(sh->msgtrace_addr);
1859
1860 if ((sh->flags & SDPCM_SHARED_VERSION_MASK) == 3 && SDPCM_SHARED_VERSION == 1)
1861 return BCME_OK;
1862
1863 if ((sh->flags & SDPCM_SHARED_VERSION_MASK) != SDPCM_SHARED_VERSION) {
1864 DHD_ERROR(("%s: sdpcm_shared version %d in dhd "
1865 "is different than sdpcm_shared version %d in dongle\n",
1866 __FUNCTION__, SDPCM_SHARED_VERSION,
1867 sh->flags & SDPCM_SHARED_VERSION_MASK));
1868 return BCME_ERROR;
1869 }
1870
1871 return BCME_OK;
1872}
1873
1874
1875static int
1876dhdsdio_readconsole(dhd_bus_t *bus)
1877{
1878 dhd_console_t *c = &bus->console;
1879 uint8 line[CONSOLE_LINE_MAX], ch;
1880 uint32 n, idx, addr;
1881 int rv;
1882
1883 /* Don't do anything until FWREADY updates console address */
1884 if (bus->console_addr == 0)
1885 return 0;
1886
1887 /* Read console log struct */
1888 addr = bus->console_addr + OFFSETOF(hndrte_cons_t, log);
1889 if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)&c->log, sizeof(c->log))) < 0)
1890 return rv;
1891
1892 /* Allocate console buffer (one time only) */
1893 if (c->buf == NULL) {
1894 c->bufsize = ltoh32(c->log.buf_size);
1895 if ((c->buf = MALLOC(bus->dhd->osh, c->bufsize)) == NULL)
1896 return BCME_NOMEM;
1897 }
1898
1899 idx = ltoh32(c->log.idx);
1900
1901 /* Protect against corrupt value */
1902 if (idx > c->bufsize)
1903 return BCME_ERROR;
1904
1905 /* Skip reading the console buffer if the index pointer has not moved */
1906 if (idx == c->last)
1907 return BCME_OK;
1908
1909 /* Read the console buffer */
1910 addr = ltoh32(c->log.buf);
1911 if ((rv = dhdsdio_membytes(bus, FALSE, addr, c->buf, c->bufsize)) < 0)
1912 return rv;
1913
1914 while (c->last != idx) {
1915 for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) {
1916 if (c->last == idx) {
1917 /* This would output a partial line. Instead, back up
1918 * the buffer pointer and output this line next time around.
1919 */
1920 if (c->last >= n)
1921 c->last -= n;
1922 else
1923 c->last = c->bufsize - n;
1924 goto break2;
1925 }
1926 ch = c->buf[c->last];
1927 c->last = (c->last + 1) % c->bufsize;
1928 if (ch == '\n')
1929 break;
1930 line[n] = ch;
1931 }
1932
1933 if (n > 0) {
1934 if (line[n - 1] == '\r')
1935 n--;
1936 line[n] = 0;
1937 printf("CONSOLE: %s\n", line);
1938 }
1939 }
1940break2:
1941
1942 return BCME_OK;
1943}
1944
1945static int
1946dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size)
1947{
1948 int bcmerror = 0;
1949 uint msize = 512;
1950 char *mbuffer = NULL;
1951 char *console_buffer = NULL;
1952 uint maxstrlen = 256;
1953 char *str = NULL;
1954 trap_t tr;
1955 sdpcm_shared_t sdpcm_shared;
1956 struct bcmstrbuf strbuf;
1957 uint32 console_ptr, console_size, console_index;
1958 uint8 line[CONSOLE_LINE_MAX], ch;
1959 uint32 n, i, addr;
1960 int rv;
1961
1962 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1963
1964 if (data == NULL) {
1965 /*
1966 * Called after a rx ctrl timeout. "data" is NULL.
1967 * allocate memory to trace the trap or assert.
1968 */
1969 size = msize;
1970 mbuffer = data = MALLOC(bus->dhd->osh, msize);
1971 if (mbuffer == NULL) {
1972 DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, msize));
1973 bcmerror = BCME_NOMEM;
1974 goto done;
1975 }
1976 }
1977
1978 if ((str = MALLOC(bus->dhd->osh, maxstrlen)) == NULL) {
1979 DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, maxstrlen));
1980 bcmerror = BCME_NOMEM;
1981 goto done;
1982 }
1983
1984 if ((bcmerror = dhdsdio_readshared(bus, &sdpcm_shared)) < 0)
1985 goto done;
1986
1987 bcm_binit(&strbuf, data, size);
1988
1989 bcm_bprintf(&strbuf, "msgtrace address : 0x%08X\nconsole address : 0x%08X\n",
1990 sdpcm_shared.msgtrace_addr, sdpcm_shared.console_addr);
1991
1992 if ((sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT) == 0) {
1993 /* NOTE: Misspelled assert is intentional - DO NOT FIX.
1994 * (Avoids conflict with real asserts for programmatic parsing of output.)
1995 */
1996 bcm_bprintf(&strbuf, "Assrt not built in dongle\n");
1997 }
1998
1999 if ((sdpcm_shared.flags & (SDPCM_SHARED_ASSERT|SDPCM_SHARED_TRAP)) == 0) {
2000 /* NOTE: Misspelled assert is intentional - DO NOT FIX.
2001 * (Avoids conflict with real asserts for programmatic parsing of output.)
2002 */
2003 bcm_bprintf(&strbuf, "No trap%s in dongle",
2004 (sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT)
2005 ?"/assrt" :"");
2006 } else {
2007 if (sdpcm_shared.flags & SDPCM_SHARED_ASSERT) {
2008 /* Download assert */
2009 bcm_bprintf(&strbuf, "Dongle assert");
2010 if (sdpcm_shared.assert_exp_addr != 0) {
2011 str[0] = '\0';
2012 if ((bcmerror = dhdsdio_membytes(bus, FALSE,
2013 sdpcm_shared.assert_exp_addr,
2014 (uint8 *)str, maxstrlen)) < 0)
2015 goto done;
2016
2017 str[maxstrlen - 1] = '\0';
2018 bcm_bprintf(&strbuf, " expr \"%s\"", str);
2019 }
2020
2021 if (sdpcm_shared.assert_file_addr != 0) {
2022 str[0] = '\0';
2023 if ((bcmerror = dhdsdio_membytes(bus, FALSE,
2024 sdpcm_shared.assert_file_addr,
2025 (uint8 *)str, maxstrlen)) < 0)
2026 goto done;
2027
2028 str[maxstrlen - 1] = '\0';
2029 bcm_bprintf(&strbuf, " file \"%s\"", str);
2030 }
2031
2032 bcm_bprintf(&strbuf, " line %d ", sdpcm_shared.assert_line);
2033 }
2034
2035 if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) {
2036 if ((bcmerror = dhdsdio_membytes(bus, FALSE,
2037 sdpcm_shared.trap_addr,
2038 (uint8*)&tr, sizeof(trap_t))) < 0)
2039 goto done;
2040
2041 bcm_bprintf(&strbuf,
2042 "Dongle trap type 0x%x @ epc 0x%x, cpsr 0x%x, spsr 0x%x, sp 0x%x,"
2043 "lp 0x%x, rpc 0x%x Trap offset 0x%x, "
2044 "r0 0x%x, r1 0x%x, r2 0x%x, r3 0x%x, "
2045 "r4 0x%x, r5 0x%x, r6 0x%x, r7 0x%x\n\n",
2046 ltoh32(tr.type), ltoh32(tr.epc), ltoh32(tr.cpsr), ltoh32(tr.spsr),
2047 ltoh32(tr.r13), ltoh32(tr.r14), ltoh32(tr.pc),
2048 ltoh32(sdpcm_shared.trap_addr),
2049 ltoh32(tr.r0), ltoh32(tr.r1), ltoh32(tr.r2), ltoh32(tr.r3),
2050 ltoh32(tr.r4), ltoh32(tr.r5), ltoh32(tr.r6), ltoh32(tr.r7));
2051
2052 addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log);
2053 if ((rv = dhdsdio_membytes(bus, FALSE, addr,
2054 (uint8 *)&console_ptr, sizeof(console_ptr))) < 0)
2055 goto printbuf;
2056
2057 addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log.buf_size);
2058 if ((rv = dhdsdio_membytes(bus, FALSE, addr,
2059 (uint8 *)&console_size, sizeof(console_size))) < 0)
2060 goto printbuf;
2061
2062 addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log.idx);
2063 if ((rv = dhdsdio_membytes(bus, FALSE, addr,
2064 (uint8 *)&console_index, sizeof(console_index))) < 0)
2065 goto printbuf;
2066
2067 console_ptr = ltoh32(console_ptr);
2068 console_size = ltoh32(console_size);
2069 console_index = ltoh32(console_index);
2070
2071 if (console_size > CONSOLE_BUFFER_MAX ||
2072 !(console_buffer = MALLOC(bus->dhd->osh, console_size)))
2073 goto printbuf;
2074
2075 if ((rv = dhdsdio_membytes(bus, FALSE, console_ptr,
2076 (uint8 *)console_buffer, console_size)) < 0)
2077 goto printbuf;
2078
2079 for (i = 0, n = 0; i < console_size; i += n + 1) {
2080 for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) {
2081 ch = console_buffer[(console_index + i + n) % console_size];
2082 if (ch == '\n')
2083 break;
2084 line[n] = ch;
2085 }
2086
2087
2088 if (n > 0) {
2089 if (line[n - 1] == '\r')
2090 n--;
2091 line[n] = 0;
2092 /* Don't use DHD_ERROR macro since we print
2093 * a lot of information quickly. The macro
2094 * will truncate a lot of the printfs
2095 */
2096
2097 if (dhd_msg_level & DHD_ERROR_VAL) {
2098 printf("CONSOLE: %s\n", line);
2099 DHD_BLOG(line, strlen(line) + 1);
2100 }
2101 }
2102 }
2103 }
2104 }
2105
2106printbuf:
2107 if (sdpcm_shared.flags & (SDPCM_SHARED_ASSERT | SDPCM_SHARED_TRAP)) {
2108 DHD_ERROR(("%s: %s\n", __FUNCTION__, strbuf.origbuf));
2109 }
2110
2111
2112done:
2113 if (mbuffer)
2114 MFREE(bus->dhd->osh, mbuffer, msize);
2115 if (str)
2116 MFREE(bus->dhd->osh, str, maxstrlen);
2117 if (console_buffer)
2118 MFREE(bus->dhd->osh, console_buffer, console_size);
2119
2120 return bcmerror;
2121}
2122#endif /* #ifdef DHD_DEBUG */
2123
2124
2125int
2126dhdsdio_downloadvars(dhd_bus_t *bus, void *arg, int len)
2127{
2128 int bcmerror = BCME_OK;
2129
2130 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2131
2132 /* Basic sanity checks */
2133 if (bus->dhd->up) {
2134 bcmerror = BCME_NOTDOWN;
2135 goto err;
2136 }
2137 if (!len) {
2138 bcmerror = BCME_BUFTOOSHORT;
2139 goto err;
2140 }
2141
2142 /* Free the old ones and replace with passed variables */
2143 if (bus->vars)
2144 MFREE(bus->dhd->osh, bus->vars, bus->varsz);
2145
2146 bus->vars = MALLOC(bus->dhd->osh, len);
2147 bus->varsz = bus->vars ? len : 0;
2148 if (bus->vars == NULL) {
2149 bcmerror = BCME_NOMEM;
2150 goto err;
2151 }
2152
2153 /* Copy the passed variables, which should include the terminating double-null */
2154 bcopy(arg, bus->vars, bus->varsz);
2155err:
2156 return bcmerror;
2157}
2158
2159#ifdef DHD_DEBUG
2160
2161#define CC_PLL_CHIPCTRL_SERIAL_ENAB (1 << 24)
2162static int
2163dhd_serialconsole(dhd_bus_t *bus, bool set, bool enable, int *bcmerror)
2164{
2165 int int_val;
2166 uint32 addr, data;
2167
2168
2169 addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr);
2170 data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data);
2171 *bcmerror = 0;
2172
2173 bcmsdh_reg_write(bus->sdh, addr, 4, 1);
2174 if (bcmsdh_regfail(bus->sdh)) {
2175 *bcmerror = BCME_SDIO_ERROR;
2176 return -1;
2177 }
2178 int_val = bcmsdh_reg_read(bus->sdh, data, 4);
2179 if (bcmsdh_regfail(bus->sdh)) {
2180 *bcmerror = BCME_SDIO_ERROR;
2181 return -1;
2182 }
2183 if (!set)
2184 return (int_val & CC_PLL_CHIPCTRL_SERIAL_ENAB);
2185 if (enable)
2186 int_val |= CC_PLL_CHIPCTRL_SERIAL_ENAB;
2187 else
2188 int_val &= ~CC_PLL_CHIPCTRL_SERIAL_ENAB;
2189 bcmsdh_reg_write(bus->sdh, data, 4, int_val);
2190 if (bcmsdh_regfail(bus->sdh)) {
2191 *bcmerror = BCME_SDIO_ERROR;
2192 return -1;
2193 }
2194 if (bus->sih->chip == BCM4330_CHIP_ID) {
2195 uint32 chipcontrol;
2196 addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol);
2197 chipcontrol = bcmsdh_reg_read(bus->sdh, addr, 4);
2198 chipcontrol &= ~0x8;
2199 if (enable) {
2200 chipcontrol |= 0x8;
2201 chipcontrol &= ~0x3;
2202 }
2203 bcmsdh_reg_write(bus->sdh, addr, 4, chipcontrol);
2204 }
2205
2206 return (int_val & CC_PLL_CHIPCTRL_SERIAL_ENAB);
2207}
2208#endif
2209
2210static int
2211dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const char *name,
2212 void *params, int plen, void *arg, int len, int val_size)
2213{
2214 int bcmerror = 0;
2215 int32 int_val = 0;
2216 bool bool_val = 0;
2217
2218 DHD_TRACE(("%s: Enter, action %d name %s params %p plen %d arg %p len %d val_size %d\n",
2219 __FUNCTION__, actionid, name, params, plen, arg, len, val_size));
2220
2221 if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0)
2222 goto exit;
2223
2224 if (plen >= (int)sizeof(int_val))
2225 bcopy(params, &int_val, sizeof(int_val));
2226
2227 bool_val = (int_val != 0) ? TRUE : FALSE;
2228
2229
2230 /* Some ioctls use the bus */
2231 dhd_os_sdlock(bus->dhd);
2232
2233 /* Check if dongle is in reset. If so, only allow DEVRESET iovars */
2234 if (bus->dhd->dongle_reset && !(actionid == IOV_SVAL(IOV_DEVRESET) ||
2235 actionid == IOV_GVAL(IOV_DEVRESET))) {
2236 bcmerror = BCME_NOTREADY;
2237 goto exit;
2238 }
2239
2240 /* Handle sleep stuff before any clock mucking */
2241 if (vi->varid == IOV_SLEEP) {
2242 if (IOV_ISSET(actionid)) {
2243 bcmerror = dhdsdio_bussleep(bus, bool_val);
2244 } else {
2245 int_val = (int32)bus->sleeping;
2246 bcopy(&int_val, arg, val_size);
2247 }
2248 goto exit;
2249 }
2250
2251 /* Request clock to allow SDIO accesses */
2252 if (!bus->dhd->dongle_reset) {
2253 BUS_WAKE(bus);
2254 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
2255 }
2256
2257 switch (actionid) {
2258 case IOV_GVAL(IOV_INTR):
2259 int_val = (int32)bus->intr;
2260 bcopy(&int_val, arg, val_size);
2261 break;
2262
2263 case IOV_SVAL(IOV_INTR):
2264 bus->intr = bool_val;
2265 bus->intdis = FALSE;
2266 if (bus->dhd->up) {
2267 if (bus->intr) {
2268 DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__));
2269 bcmsdh_intr_enable(bus->sdh);
2270 } else {
2271 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
2272 bcmsdh_intr_disable(bus->sdh);
2273 }
2274 }
2275 break;
2276
2277 case IOV_GVAL(IOV_POLLRATE):
2278 int_val = (int32)bus->pollrate;
2279 bcopy(&int_val, arg, val_size);
2280 break;
2281
2282 case IOV_SVAL(IOV_POLLRATE):
2283 bus->pollrate = (uint)int_val;
2284 bus->poll = (bus->pollrate != 0);
2285 break;
2286
2287 case IOV_GVAL(IOV_IDLETIME):
2288 int_val = bus->idletime;
2289 bcopy(&int_val, arg, val_size);
2290 break;
2291
2292 case IOV_SVAL(IOV_IDLETIME):
2293 if ((int_val < 0) && (int_val != DHD_IDLE_IMMEDIATE)) {
2294 bcmerror = BCME_BADARG;
2295 } else {
2296 bus->idletime = int_val;
2297 }
2298 break;
2299
2300 case IOV_GVAL(IOV_IDLECLOCK):
2301 int_val = (int32)bus->idleclock;
2302 bcopy(&int_val, arg, val_size);
2303 break;
2304
2305 case IOV_SVAL(IOV_IDLECLOCK):
2306 bus->idleclock = int_val;
2307 break;
2308
2309 case IOV_GVAL(IOV_SD1IDLE):
2310 int_val = (int32)sd1idle;
2311 bcopy(&int_val, arg, val_size);
2312 break;
2313
2314 case IOV_SVAL(IOV_SD1IDLE):
2315 sd1idle = bool_val;
2316 break;
2317
2318
2319 case IOV_SVAL(IOV_MEMBYTES):
2320 case IOV_GVAL(IOV_MEMBYTES):
2321 {
2322 uint32 address;
2323 uint size, dsize;
2324 uint8 *data;
2325
2326 bool set = (actionid == IOV_SVAL(IOV_MEMBYTES));
2327
2328 ASSERT(plen >= 2*sizeof(int));
2329
2330 address = (uint32)int_val;
2331 bcopy((char *)params + sizeof(int_val), &int_val, sizeof(int_val));
2332 size = (uint)int_val;
2333
2334 /* Do some validation */
2335 dsize = set ? plen - (2 * sizeof(int)) : len;
2336 if (dsize < size) {
2337 DHD_ERROR(("%s: error on %s membytes, addr 0x%08x size %d dsize %d\n",
2338 __FUNCTION__, (set ? "set" : "get"), address, size, dsize));
2339 bcmerror = BCME_BADARG;
2340 break;
2341 }
2342
2343 DHD_INFO(("%s: Request to %s %d bytes at address 0x%08x\n", __FUNCTION__,
2344 (set ? "write" : "read"), size, address));
2345
2346 /* If we know about SOCRAM, check for a fit */
2347 if ((bus->orig_ramsize) &&
2348 ((address > bus->orig_ramsize) || (address + size > bus->orig_ramsize)))
2349 {
2350 uint8 enable, protect;
2351 si_socdevram(bus->sih, FALSE, &enable, &protect);
2352 if (!enable || protect) {
2353 DHD_ERROR(("%s: ramsize 0x%08x doesn't have %d bytes at 0x%08x\n",
2354 __FUNCTION__, bus->orig_ramsize, size, address));
2355 DHD_ERROR(("%s: socram enable %d, protect %d\n",
2356 __FUNCTION__, enable, protect));
2357 bcmerror = BCME_BADARG;
2358 break;
2359 }
2360 if (enable && (bus->sih->chip == BCM4330_CHIP_ID)) {
2361 uint32 devramsize = si_socdevram_size(bus->sih);
2362 if ((address < SOCDEVRAM_4330_ARM_ADDR) ||
2363 (address + size > (SOCDEVRAM_4330_ARM_ADDR + devramsize))) {
2364 DHD_ERROR(("%s: bad address 0x%08x, size 0x%08x\n",
2365 __FUNCTION__, address, size));
2366 DHD_ERROR(("%s: socram range 0x%08x,size 0x%08x\n",
2367 __FUNCTION__, SOCDEVRAM_4330_ARM_ADDR, devramsize));
2368 bcmerror = BCME_BADARG;
2369 break;
2370 }
2371 /* move it such that address is real now */
2372 address -= SOCDEVRAM_4330_ARM_ADDR;
2373 address += SOCDEVRAM_4330_BP_ADDR;
2374 DHD_INFO(("%s: Request to %s %d bytes @ Mapped address 0x%08x\n",
2375 __FUNCTION__, (set ? "write" : "read"), size, address));
2376 }
2377 }
2378
2379 /* Generate the actual data pointer */
2380 data = set ? (uint8*)params + 2 * sizeof(int): (uint8*)arg;
2381
2382 /* Call to do the transfer */
2383 bcmerror = dhdsdio_membytes(bus, set, address, data, size);
2384
2385 break;
2386 }
2387
2388 case IOV_GVAL(IOV_MEMSIZE):
2389 int_val = (int32)bus->ramsize;
2390 bcopy(&int_val, arg, val_size);
2391 break;
2392
2393 case IOV_GVAL(IOV_SDIOD_DRIVE):
2394 int_val = (int32)dhd_sdiod_drive_strength;
2395 bcopy(&int_val, arg, val_size);
2396 break;
2397
2398 case IOV_SVAL(IOV_SDIOD_DRIVE):
2399 dhd_sdiod_drive_strength = int_val;
2400 si_sdiod_drive_strength_init(bus->sih, bus->dhd->osh, dhd_sdiod_drive_strength);
2401 break;
2402
2403 case IOV_SVAL(IOV_DOWNLOAD):
2404 bcmerror = dhdsdio_download_state(bus, bool_val);
2405 break;
2406
2407 case IOV_SVAL(IOV_SOCRAM_STATE):
2408 bcmerror = dhdsdio_download_state(bus, bool_val);
2409 break;
2410
2411 case IOV_SVAL(IOV_VARS):
2412 bcmerror = dhdsdio_downloadvars(bus, arg, len);
2413 break;
2414
2415 case IOV_GVAL(IOV_READAHEAD):
2416 int_val = (int32)dhd_readahead;
2417 bcopy(&int_val, arg, val_size);
2418 break;
2419
2420 case IOV_SVAL(IOV_READAHEAD):
2421 if (bool_val && !dhd_readahead)
2422 bus->nextlen = 0;
2423 dhd_readahead = bool_val;
2424 break;
2425
2426 case IOV_GVAL(IOV_SDRXCHAIN):
2427 int_val = (int32)bus->use_rxchain;
2428 bcopy(&int_val, arg, val_size);
2429 break;
2430
2431 case IOV_SVAL(IOV_SDRXCHAIN):
2432 if (bool_val && !bus->sd_rxchain)
2433 bcmerror = BCME_UNSUPPORTED;
2434 else
2435 bus->use_rxchain = bool_val;
2436 break;
2437 case IOV_GVAL(IOV_ALIGNCTL):
2438 int_val = (int32)dhd_alignctl;
2439 bcopy(&int_val, arg, val_size);
2440 break;
2441
2442 case IOV_SVAL(IOV_ALIGNCTL):
2443 dhd_alignctl = bool_val;
2444 break;
2445
2446 case IOV_GVAL(IOV_SDALIGN):
2447 int_val = DHD_SDALIGN;
2448 bcopy(&int_val, arg, val_size);
2449 break;
2450
2451#ifdef DHD_DEBUG
2452 case IOV_GVAL(IOV_VARS):
2453 if (bus->varsz < (uint)len)
2454 bcopy(bus->vars, arg, bus->varsz);
2455 else
2456 bcmerror = BCME_BUFTOOSHORT;
2457 break;
2458#endif /* DHD_DEBUG */
2459
2460#ifdef DHD_DEBUG
2461 case IOV_GVAL(IOV_SDREG):
2462 {
2463 sdreg_t *sd_ptr;
2464 uint32 addr, size;
2465
2466 sd_ptr = (sdreg_t *)params;
2467
2468 addr = (uintptr)bus->regs + sd_ptr->offset;
2469 size = sd_ptr->func;
2470 int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size);
2471 if (bcmsdh_regfail(bus->sdh))
2472 bcmerror = BCME_SDIO_ERROR;
2473 bcopy(&int_val, arg, sizeof(int32));
2474 break;
2475 }
2476
2477 case IOV_SVAL(IOV_SDREG):
2478 {
2479 sdreg_t *sd_ptr;
2480 uint32 addr, size;
2481
2482 sd_ptr = (sdreg_t *)params;
2483
2484 addr = (uintptr)bus->regs + sd_ptr->offset;
2485 size = sd_ptr->func;
2486 bcmsdh_reg_write(bus->sdh, addr, size, sd_ptr->value);
2487 if (bcmsdh_regfail(bus->sdh))
2488 bcmerror = BCME_SDIO_ERROR;
2489 break;
2490 }
2491
2492 /* Same as above, but offset is not backplane (not SDIO core) */
2493 case IOV_GVAL(IOV_SBREG):
2494 {
2495 sdreg_t sdreg;
2496 uint32 addr, size;
2497
2498 bcopy(params, &sdreg, sizeof(sdreg));
2499
2500 addr = SI_ENUM_BASE + sdreg.offset;
2501 size = sdreg.func;
2502 int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size);
2503 if (bcmsdh_regfail(bus->sdh))
2504 bcmerror = BCME_SDIO_ERROR;
2505 bcopy(&int_val, arg, sizeof(int32));
2506 break;
2507 }
2508
2509 case IOV_SVAL(IOV_SBREG):
2510 {
2511 sdreg_t sdreg;
2512 uint32 addr, size;
2513
2514 bcopy(params, &sdreg, sizeof(sdreg));
2515
2516 addr = SI_ENUM_BASE + sdreg.offset;
2517 size = sdreg.func;
2518 bcmsdh_reg_write(bus->sdh, addr, size, sdreg.value);
2519 if (bcmsdh_regfail(bus->sdh))
2520 bcmerror = BCME_SDIO_ERROR;
2521 break;
2522 }
2523
2524 case IOV_GVAL(IOV_SDCIS):
2525 {
2526 *(char *)arg = 0;
2527
2528 bcmstrcat(arg, "\nFunc 0\n");
2529 bcmsdh_cis_read(bus->sdh, 0x10, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
2530 bcmstrcat(arg, "\nFunc 1\n");
2531 bcmsdh_cis_read(bus->sdh, 0x11, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
2532 bcmstrcat(arg, "\nFunc 2\n");
2533 bcmsdh_cis_read(bus->sdh, 0x12, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
2534 break;
2535 }
2536
2537 case IOV_GVAL(IOV_FORCEEVEN):
2538 int_val = (int32)forcealign;
2539 bcopy(&int_val, arg, val_size);
2540 break;
2541
2542 case IOV_SVAL(IOV_FORCEEVEN):
2543 forcealign = bool_val;
2544 break;
2545
2546 case IOV_GVAL(IOV_TXBOUND):
2547 int_val = (int32)dhd_txbound;
2548 bcopy(&int_val, arg, val_size);
2549 break;
2550
2551 case IOV_SVAL(IOV_TXBOUND):
2552 dhd_txbound = (uint)int_val;
2553 break;
2554
2555 case IOV_GVAL(IOV_RXBOUND):
2556 int_val = (int32)dhd_rxbound;
2557 bcopy(&int_val, arg, val_size);
2558 break;
2559
2560 case IOV_SVAL(IOV_RXBOUND):
2561 dhd_rxbound = (uint)int_val;
2562 break;
2563
2564 case IOV_GVAL(IOV_TXMINMAX):
2565 int_val = (int32)dhd_txminmax;
2566 bcopy(&int_val, arg, val_size);
2567 break;
2568
2569 case IOV_SVAL(IOV_TXMINMAX):
2570 dhd_txminmax = (uint)int_val;
2571 break;
2572
2573 case IOV_GVAL(IOV_SERIALCONS):
2574 int_val = dhd_serialconsole(bus, FALSE, 0, &bcmerror);
2575 if (bcmerror != 0)
2576 break;
2577
2578 bcopy(&int_val, arg, val_size);
2579 break;
2580
2581 case IOV_SVAL(IOV_SERIALCONS):
2582 dhd_serialconsole(bus, TRUE, bool_val, &bcmerror);
2583 break;
2584
2585
2586
2587#endif /* DHD_DEBUG */
2588
2589
2590#ifdef SDTEST
2591 case IOV_GVAL(IOV_EXTLOOP):
2592 int_val = (int32)bus->ext_loop;
2593 bcopy(&int_val, arg, val_size);
2594 break;
2595
2596 case IOV_SVAL(IOV_EXTLOOP):
2597 bus->ext_loop = bool_val;
2598 break;
2599
2600 case IOV_GVAL(IOV_PKTGEN):
2601 bcmerror = dhdsdio_pktgen_get(bus, arg);
2602 break;
2603
2604 case IOV_SVAL(IOV_PKTGEN):
2605 bcmerror = dhdsdio_pktgen_set(bus, arg);
2606 break;
2607#endif /* SDTEST */
2608
2609
2610 case IOV_GVAL(IOV_DONGLEISOLATION):
2611 int_val = bus->dhd->dongle_isolation;
2612 bcopy(&int_val, arg, val_size);
2613 break;
2614
2615 case IOV_SVAL(IOV_DONGLEISOLATION):
2616 bus->dhd->dongle_isolation = bool_val;
2617 break;
2618
2619 case IOV_SVAL(IOV_DEVRESET):
2620 DHD_TRACE(("%s: Called set IOV_DEVRESET=%d dongle_reset=%d busstate=%d\n",
2621 __FUNCTION__, bool_val, bus->dhd->dongle_reset,
2622 bus->dhd->busstate));
2623
2624 ASSERT(bus->dhd->osh);
2625 /* ASSERT(bus->cl_devid); */
2626
2627 dhd_bus_devreset(bus->dhd, (uint8)bool_val);
2628
2629 break;
2630#ifdef SOFTAP
2631 case IOV_GVAL(IOV_FWPATH):
2632 {
2633 uint32 fw_path_len;
2634
2635 fw_path_len = strlen(bus->fw_path);
2636 DHD_INFO(("[softap] get fwpath, l=%d\n", len));
2637
2638 if (fw_path_len > len-1) {
2639 bcmerror = BCME_BUFTOOSHORT;
2640 break;
2641 }
2642
2643 if (fw_path_len) {
2644 bcopy(bus->fw_path, arg, fw_path_len);
2645 ((uchar*)arg)[fw_path_len] = 0;
2646 }
2647 break;
2648 }
2649
2650 case IOV_SVAL(IOV_FWPATH):
2651 DHD_INFO(("[softap] set fwpath, idx=%d\n", int_val));
2652
2653 switch (int_val) {
2654 case 1:
2655 bus->fw_path = fw_path; /* ordinary one */
2656 break;
2657 case 2:
2658 bus->fw_path = fw_path2;
2659 break;
2660 default:
2661 bcmerror = BCME_BADARG;
2662 break;
2663 }
2664
2665 DHD_INFO(("[softap] new fw path: %s\n", (bus->fw_path[0] ? bus->fw_path : "NULL")));
2666 break;
2667
2668#endif /* SOFTAP */
2669 case IOV_GVAL(IOV_DEVRESET):
2670 DHD_TRACE(("%s: Called get IOV_DEVRESET\n", __FUNCTION__));
2671
2672 /* Get its status */
2673 int_val = (bool) bus->dhd->dongle_reset;
2674 bcopy(&int_val, arg, val_size);
2675
2676 break;
2677
2678 default:
2679 bcmerror = BCME_UNSUPPORTED;
2680 break;
2681 }
2682
2683exit:
2684 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
2685 bus->activity = FALSE;
2686 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
2687 }
2688
2689 dhd_os_sdunlock(bus->dhd);
2690
2691 if (actionid == IOV_SVAL(IOV_DEVRESET) && bool_val == FALSE)
2692 dhd_preinit_ioctls((dhd_pub_t *) bus->dhd);
2693
2694 return bcmerror;
2695}
2696
2697static int
2698dhdsdio_write_vars(dhd_bus_t *bus)
2699{
2700 int bcmerror = 0;
2701 uint32 varsize;
2702 uint32 varaddr;
2703 uint8 *vbuffer;
2704 uint32 varsizew;
2705#ifdef DHD_DEBUG
2706 uint8 *nvram_ularray;
2707#endif /* DHD_DEBUG */
2708
2709 /* Even if there are no vars are to be written, we still need to set the ramsize. */
2710 varsize = bus->varsz ? ROUNDUP(bus->varsz, 4) : 0;
2711 varaddr = (bus->ramsize - 4) - varsize;
2712
2713 if (bus->vars) {
2714 if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 7)) {
2715 if (((varaddr & 0x3C) == 0x3C) && (varsize > 4)) {
2716 DHD_ERROR(("PR85623WAR in place\n"));
2717 varsize += 4;
2718 varaddr -= 4;
2719 }
2720 }
2721
2722 vbuffer = (uint8 *)MALLOC(bus->dhd->osh, varsize);
2723 if (!vbuffer)
2724 return BCME_NOMEM;
2725
2726 bzero(vbuffer, varsize);
2727 bcopy(bus->vars, vbuffer, bus->varsz);
2728
2729 /* Write the vars list */
2730 bcmerror = dhdsdio_membytes(bus, TRUE, varaddr, vbuffer, varsize);
2731#ifdef DHD_DEBUG
2732 /* Verify NVRAM bytes */
2733 DHD_INFO(("Compare NVRAM dl & ul; varsize=%d\n", varsize));
2734 nvram_ularray = (uint8*)MALLOC(bus->dhd->osh, varsize);
2735 if (!nvram_ularray)
2736 return BCME_NOMEM;
2737
2738 /* Upload image to verify downloaded contents. */
2739 memset(nvram_ularray, 0xaa, varsize);
2740
2741 /* Read the vars list to temp buffer for comparison */
2742 bcmerror = dhdsdio_membytes(bus, FALSE, varaddr, nvram_ularray, varsize);
2743 if (bcmerror) {
2744 DHD_ERROR(("%s: error %d on reading %d nvram bytes at 0x%08x\n",
2745 __FUNCTION__, bcmerror, varsize, varaddr));
2746 }
2747 /* Compare the org NVRAM with the one read from RAM */
2748 if (memcmp(vbuffer, nvram_ularray, varsize)) {
2749 DHD_ERROR(("%s: Downloaded NVRAM image is corrupted.\n", __FUNCTION__));
2750 } else
2751 DHD_ERROR(("%s: Download, Upload and compare of NVRAM succeeded.\n",
2752 __FUNCTION__));
2753
2754 MFREE(bus->dhd->osh, nvram_ularray, varsize);
2755#endif /* DHD_DEBUG */
2756
2757 MFREE(bus->dhd->osh, vbuffer, varsize);
2758 }
2759
2760 /* adjust to the user specified RAM */
2761 DHD_INFO(("Physical memory size: %d, usable memory size: %d\n",
2762 bus->orig_ramsize, bus->ramsize));
2763 DHD_INFO(("Vars are at %d, orig varsize is %d\n",
2764 varaddr, varsize));
2765 varsize = ((bus->orig_ramsize - 4) - varaddr);
2766
2767 /*
2768 * Determine the length token:
2769 * Varsize, converted to words, in lower 16-bits, checksum in upper 16-bits.
2770 */
2771 if (bcmerror) {
2772 varsizew = 0;
2773 } else {
2774 varsizew = varsize / 4;
2775 varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF);
2776 varsizew = htol32(varsizew);
2777 }
2778
2779 DHD_INFO(("New varsize is %d, length token=0x%08x\n", varsize, varsizew));
2780
2781 /* Write the length token to the last word */
2782 bcmerror = dhdsdio_membytes(bus, TRUE, (bus->orig_ramsize - 4),
2783 (uint8*)&varsizew, 4);
2784
2785 return bcmerror;
2786}
2787
2788static int
2789dhdsdio_download_state(dhd_bus_t *bus, bool enter)
2790{
2791 uint retries;
2792 int bcmerror = 0;
2793
2794 if (!bus->sih)
2795 return BCME_ERROR;
2796
2797 /* To enter download state, disable ARM and reset SOCRAM.
2798 * To exit download state, simply reset ARM (default is RAM boot).
2799 */
2800 if (enter) {
2801 bus->alp_only = TRUE;
2802
2803 if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) &&
2804 !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) {
2805 DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__));
2806 bcmerror = BCME_ERROR;
2807 goto fail;
2808 }
2809
2810 si_core_disable(bus->sih, 0);
2811 if (bcmsdh_regfail(bus->sdh)) {
2812 bcmerror = BCME_SDIO_ERROR;
2813 goto fail;
2814 }
2815
2816 if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) {
2817 DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__));
2818 bcmerror = BCME_ERROR;
2819 goto fail;
2820 }
2821
2822 si_core_reset(bus->sih, 0, 0);
2823 if (bcmsdh_regfail(bus->sdh)) {
2824 DHD_ERROR(("%s: Failure trying reset SOCRAM core?\n", __FUNCTION__));
2825 bcmerror = BCME_SDIO_ERROR;
2826 goto fail;
2827 }
2828
2829 /* Clear the top bit of memory */
2830 if (bus->ramsize) {
2831 uint32 zeros = 0;
2832 if (dhdsdio_membytes(bus, TRUE, bus->ramsize - 4, (uint8*)&zeros, 4) < 0) {
2833 bcmerror = BCME_SDIO_ERROR;
2834 goto fail;
2835 }
2836 }
2837 } else {
2838 if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) {
2839 DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__));
2840 bcmerror = BCME_ERROR;
2841 goto fail;
2842 }
2843
2844 if (!si_iscoreup(bus->sih)) {
2845 DHD_ERROR(("%s: SOCRAM core is down after reset?\n", __FUNCTION__));
2846 bcmerror = BCME_ERROR;
2847 goto fail;
2848 }
2849
2850 if ((bcmerror = dhdsdio_write_vars(bus))) {
2851 DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__));
2852 goto fail;
2853 }
2854
2855 if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) &&
2856 !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) {
2857 DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__));
2858 bcmerror = BCME_ERROR;
2859 goto fail;
2860 }
2861 W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries);
2862
2863
2864 if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) &&
2865 !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) {
2866 DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__));
2867 bcmerror = BCME_ERROR;
2868 goto fail;
2869 }
2870
2871 si_core_reset(bus->sih, 0, 0);
2872 if (bcmsdh_regfail(bus->sdh)) {
2873 DHD_ERROR(("%s: Failure trying to reset ARM core?\n", __FUNCTION__));
2874 bcmerror = BCME_SDIO_ERROR;
2875 goto fail;
2876 }
2877
2878 /* Allow HT Clock now that the ARM is running. */
2879 bus->alp_only = FALSE;
2880
2881 bus->dhd->busstate = DHD_BUS_LOAD;
2882 }
2883
2884fail:
2885 /* Always return to SDIOD core */
2886 if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0))
2887 si_setcore(bus->sih, SDIOD_CORE_ID, 0);
2888
2889 return bcmerror;
2890}
2891
2892int
2893dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name,
2894 void *params, int plen, void *arg, int len, bool set)
2895{
2896 dhd_bus_t *bus = dhdp->bus;
2897 const bcm_iovar_t *vi = NULL;
2898 int bcmerror = 0;
2899 int val_size;
2900 uint32 actionid;
2901
2902 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2903
2904 ASSERT(name);
2905 ASSERT(len >= 0);
2906
2907 /* Get MUST have return space */
2908 ASSERT(set || (arg && len));
2909
2910 /* Set does NOT take qualifiers */
2911 ASSERT(!set || (!params && !plen));
2912
2913 /* Look up var locally; if not found pass to host driver */
2914 if ((vi = bcm_iovar_lookup(dhdsdio_iovars, name)) == NULL) {
2915 dhd_os_sdlock(bus->dhd);
2916
2917 BUS_WAKE(bus);
2918
2919 /* Turn on clock in case SD command needs backplane */
2920 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
2921
2922 bcmerror = bcmsdh_iovar_op(bus->sdh, name, params, plen, arg, len, set);
2923
2924 /* Check for bus configuration changes of interest */
2925
2926 /* If it was divisor change, read the new one */
2927 if (set && strcmp(name, "sd_divisor") == 0) {
2928 if (bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
2929 &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) {
2930 bus->sd_divisor = -1;
2931 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, name));
2932 } else {
2933 DHD_INFO(("%s: noted %s update, value now %d\n",
2934 __FUNCTION__, name, bus->sd_divisor));
2935 }
2936 }
2937 /* If it was a mode change, read the new one */
2938 if (set && strcmp(name, "sd_mode") == 0) {
2939 if (bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
2940 &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) {
2941 bus->sd_mode = -1;
2942 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, name));
2943 } else {
2944 DHD_INFO(("%s: noted %s update, value now %d\n",
2945 __FUNCTION__, name, bus->sd_mode));
2946 }
2947 }
2948 /* Similar check for blocksize change */
2949 if (set && strcmp(name, "sd_blocksize") == 0) {
2950 int32 fnum = 2;
2951 if (bcmsdh_iovar_op(bus->sdh, "sd_blocksize", &fnum, sizeof(int32),
2952 &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) {
2953 bus->blocksize = 0;
2954 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize"));
2955 } else {
2956 DHD_INFO(("%s: noted %s update, value now %d\n",
2957 __FUNCTION__, "sd_blocksize", bus->blocksize));
2958 }
2959 }
2960 bus->roundup = MIN(max_roundup, bus->blocksize);
2961
2962 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
2963 bus->activity = FALSE;
2964 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
2965 }
2966
2967 dhd_os_sdunlock(bus->dhd);
2968 goto exit;
2969 }
2970
2971 DHD_CTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__,
2972 name, (set ? "set" : "get"), len, plen));
2973
2974 /* set up 'params' pointer in case this is a set command so that
2975 * the convenience int and bool code can be common to set and get
2976 */
2977 if (params == NULL) {
2978 params = arg;
2979 plen = len;
2980 }
2981
2982 if (vi->type == IOVT_VOID)
2983 val_size = 0;
2984 else if (vi->type == IOVT_BUFFER)
2985 val_size = len;
2986 else
2987 /* all other types are integer sized */
2988 val_size = sizeof(int);
2989
2990 actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
2991 bcmerror = dhdsdio_doiovar(bus, vi, actionid, name, params, plen, arg, len, val_size);
2992
2993exit:
2994 return bcmerror;
2995}
2996
2997void
2998dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex)
2999{
3000 osl_t *osh;
3001 uint32 local_hostintmask;
3002 uint8 saveclk;
3003 uint retries;
3004 int err;
3005 if (!bus->dhd)
3006 return;
3007
3008 osh = bus->dhd->osh;
3009 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3010
3011 bcmsdh_waitlockfree(NULL);
3012
3013 if (enforce_mutex)
3014 dhd_os_sdlock(bus->dhd);
3015
3016 BUS_WAKE(bus);
3017
3018 /* Change our idea of bus state */
3019 bus->dhd->busstate = DHD_BUS_DOWN;
3020
3021 /* Enable clock for device interrupts */
3022 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
3023
3024 /* Disable and clear interrupts at the chip level also */
3025 W_SDREG(0, &bus->regs->hostintmask, retries);
3026 local_hostintmask = bus->hostintmask;
3027 bus->hostintmask = 0;
3028
3029 /* Force clocks on backplane to be sure F2 interrupt propagates */
3030 saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
3031 if (!err) {
3032 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
3033 (saveclk | SBSDIO_FORCE_HT), &err);
3034 }
3035 if (err) {
3036 DHD_ERROR(("%s: Failed to force clock for F2: err %d\n", __FUNCTION__, err));
3037 }
3038
3039 /* Turn off the bus (F2), free any pending packets */
3040 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
3041 bcmsdh_intr_disable(bus->sdh);
3042 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL);
3043
3044 /* Clear any pending interrupts now that F2 is disabled */
3045 W_SDREG(local_hostintmask, &bus->regs->intstatus, retries);
3046
3047 /* Turn off the backplane clock (only) */
3048 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
3049
3050 /* Clear the data packet queues */
3051 pktq_flush(osh, &bus->txq, TRUE, NULL, 0);
3052
3053 /* Clear any held glomming stuff */
3054 if (bus->glomd)
3055 PKTFREE(osh, bus->glomd, FALSE);
3056
3057 if (bus->glom)
3058 PKTFREE(osh, bus->glom, FALSE);
3059
3060 bus->glom = bus->glomd = NULL;
3061
3062 /* Clear rx control and wake any waiters */
3063 bus->rxlen = 0;
3064 dhd_os_ioctl_resp_wake(bus->dhd);
3065
3066 /* Reset some F2 state stuff */
3067 bus->rxskip = FALSE;
3068 bus->tx_seq = bus->rx_seq = 0;
3069
3070 /* Set to a safe default. It gets updated when we
3071 * receive a packet from the fw but when we reset,
3072 * we need a safe default to be able to send the
3073 * initial mac address.
3074 */
3075 bus->tx_max = 4;
3076
3077 if (enforce_mutex)
3078 dhd_os_sdunlock(bus->dhd);
3079}
3080
3081
3082int
3083dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex)
3084{
3085 dhd_bus_t *bus = dhdp->bus;
3086 dhd_timeout_t tmo;
3087 uint retries = 0;
3088 uint8 ready, enable;
3089 int err, ret = 0;
3090 uint8 saveclk;
3091
3092 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3093
3094 ASSERT(bus->dhd);
3095 if (!bus->dhd)
3096 return 0;
3097
3098 if (enforce_mutex)
3099 dhd_os_sdlock(bus->dhd);
3100
3101 /* Make sure backplane clock is on, needed to generate F2 interrupt */
3102 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
3103 if (bus->clkstate != CLK_AVAIL) {
3104 DHD_ERROR(("%s: clock state is wrong. state = %d\n", __FUNCTION__, bus->clkstate));
3105 goto exit;
3106 }
3107
3108
3109 /* Force clocks on backplane to be sure F2 interrupt propagates */
3110 saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
3111 if (!err) {
3112 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
3113 (saveclk | SBSDIO_FORCE_HT), &err);
3114 }
3115 if (err) {
3116 DHD_ERROR(("%s: Failed to force clock for F2: err %d\n", __FUNCTION__, err));
3117 goto exit;
3118 }
3119
3120 /* Enable function 2 (frame transfers) */
3121 W_SDREG((SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT),
3122 &bus->regs->tosbmailboxdata, retries);
3123 enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2);
3124
3125 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL);
3126
3127 /* Give the dongle some time to do its thing and set IOR2 */
3128 dhd_timeout_start(&tmo, DHD_WAIT_F2RDY * 1000);
3129
3130 ready = 0;
3131 do {
3132 ready = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IORDY, NULL);
3133 } while (ready != enable && !dhd_timeout_expired(&tmo));
3134
3135 DHD_INFO(("%s: enable 0x%02x, ready 0x%02x (waited %uus)\n",
3136 __FUNCTION__, enable, ready, tmo.elapsed));
3137
3138
3139 /* If F2 successfully enabled, set core and enable interrupts */
3140 if (ready == enable) {
3141 /* Make sure we're talking to the core. */
3142 if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0)))
3143 bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0);
3144 ASSERT(bus->regs != NULL);
3145
3146 /* Set up the interrupt mask and enable interrupts */
3147 bus->hostintmask = HOSTINTMASK;
3148 /* corerev 4 could use the newer interrupt logic to detect the frames */
3149 if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 4) &&
3150 (bus->rxint_mode != SDIO_DEVICE_HMB_RXINT)) {
3151 bus->hostintmask &= ~I_HMB_FRAME_IND;
3152 bus->hostintmask |= I_XMTDATA_AVAIL;
3153 }
3154 W_SDREG(bus->hostintmask, &bus->regs->hostintmask, retries);
3155
3156 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, (uint8)watermark, &err);
3157
3158 /* Set bus state according to enable result */
3159 dhdp->busstate = DHD_BUS_DATA;
3160
3161 /* bcmsdh_intr_unmask(bus->sdh); */
3162
3163 bus->intdis = FALSE;
3164 if (bus->intr) {
3165 DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__));
3166 bcmsdh_intr_enable(bus->sdh);
3167 } else {
3168 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
3169 bcmsdh_intr_disable(bus->sdh);
3170 }
3171
3172 }
3173
3174
3175 else {
3176 /* Disable F2 again */
3177 enable = SDIO_FUNC_ENABLE_1;
3178 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL);
3179 }
3180
3181 /* Restore previous clock setting */
3182 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err);
3183
3184
3185 /* If we didn't come up, turn off backplane clock */
3186 if (dhdp->busstate != DHD_BUS_DATA)
3187 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
3188
3189exit:
3190 if (enforce_mutex)
3191 dhd_os_sdunlock(bus->dhd);
3192
3193 return ret;
3194}
3195
3196static void
3197dhdsdio_rxfail(dhd_bus_t *bus, bool abort, bool rtx)
3198{
3199 bcmsdh_info_t *sdh = bus->sdh;
3200 sdpcmd_regs_t *regs = bus->regs;
3201 uint retries = 0;
3202 uint16 lastrbc;
3203 uint8 hi, lo;
3204 int err;
3205
3206 DHD_ERROR(("%s: %sterminate frame%s\n", __FUNCTION__,
3207 (abort ? "abort command, " : ""), (rtx ? ", send NAK" : "")));
3208
3209 if (abort) {
3210 bcmsdh_abort(sdh, SDIO_FUNC_2);
3211 }
3212
3213 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, SFC_RF_TERM, &err);
3214 bus->f1regdata++;
3215
3216 /* Wait until the packet has been flushed (device/FIFO stable) */
3217 for (lastrbc = retries = 0xffff; retries > 0; retries--) {
3218 hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCHI, NULL);
3219 lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCLO, NULL);
3220 bus->f1regdata += 2;
3221
3222 if ((hi == 0) && (lo == 0))
3223 break;
3224
3225 if ((hi > (lastrbc >> 8)) && (lo > (lastrbc & 0x00ff))) {
3226 DHD_ERROR(("%s: count growing: last 0x%04x now 0x%04x\n",
3227 __FUNCTION__, lastrbc, ((hi << 8) + lo)));
3228 }
3229 lastrbc = (hi << 8) + lo;
3230 }
3231
3232 if (!retries) {
3233 DHD_ERROR(("%s: count never zeroed: last 0x%04x\n", __FUNCTION__, lastrbc));
3234 } else {
3235 DHD_INFO(("%s: flush took %d iterations\n", __FUNCTION__, (0xffff - retries)));
3236 }
3237
3238 if (rtx) {
3239 bus->rxrtx++;
3240 W_SDREG(SMB_NAK, ®s->tosbmailbox, retries);
3241 bus->f1regdata++;
3242 if (retries <= retry_limit) {
3243 bus->rxskip = TRUE;
3244 }
3245 }
3246
3247 /* Clear partial in any case */
3248 bus->nextlen = 0;
3249
3250 /* If we can't reach the device, signal failure */
3251 if (err || bcmsdh_regfail(sdh))
3252 bus->dhd->busstate = DHD_BUS_DOWN;
3253}
3254
3255static void
3256dhdsdio_read_control(dhd_bus_t *bus, uint8 *hdr, uint len, uint doff)
3257{
3258 bcmsdh_info_t *sdh = bus->sdh;
3259 uint rdlen, pad;
3260
3261 int sdret;
3262
3263 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3264
3265 /* Control data already received in aligned rxctl */
3266 if ((bus->bus == SPI_BUS) && (!bus->usebufpool))
3267 goto gotpkt;
3268
3269 ASSERT(bus->rxbuf);
3270 /* Set rxctl for frame (w/optional alignment) */
3271 bus->rxctl = bus->rxbuf;
3272 if (dhd_alignctl) {
3273 bus->rxctl += firstread;
3274 if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN)))
3275 bus->rxctl += (DHD_SDALIGN - pad);
3276 bus->rxctl -= firstread;
3277 }
3278 ASSERT(bus->rxctl >= bus->rxbuf);
3279
3280 /* Copy the already-read portion over */
3281 bcopy(hdr, bus->rxctl, firstread);
3282 if (len <= firstread)
3283 goto gotpkt;
3284
3285 /* Copy the full data pkt in gSPI case and process ioctl. */
3286 if (bus->bus == SPI_BUS) {
3287 bcopy(hdr, bus->rxctl, len);
3288 goto gotpkt;
3289 }
3290
3291 /* Raise rdlen to next SDIO block to avoid tail command */
3292 rdlen = len - firstread;
3293 if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
3294 pad = bus->blocksize - (rdlen % bus->blocksize);
3295 if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
3296 ((len + pad) < bus->dhd->maxctl))
3297 rdlen += pad;
3298 } else if (rdlen % DHD_SDALIGN) {
3299 rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
3300 }
3301
3302 /* Satisfy length-alignment requirements */
3303 if (forcealign && (rdlen & (ALIGNMENT - 1)))
3304 rdlen = ROUNDUP(rdlen, ALIGNMENT);
3305
3306 /* Drop if the read is too big or it exceeds our maximum */
3307 if ((rdlen + firstread) > bus->dhd->maxctl) {
3308 DHD_ERROR(("%s: %d-byte control read exceeds %d-byte buffer\n",
3309 __FUNCTION__, rdlen, bus->dhd->maxctl));
3310 bus->dhd->rx_errors++;
3311 dhdsdio_rxfail(bus, FALSE, FALSE);
3312 goto done;
3313 }
3314
3315 if ((len - doff) > bus->dhd->maxctl) {
3316 DHD_ERROR(("%s: %d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n",
3317 __FUNCTION__, len, (len - doff), bus->dhd->maxctl));
3318 bus->dhd->rx_errors++; bus->rx_toolong++;
3319 dhdsdio_rxfail(bus, FALSE, FALSE);
3320 goto done;
3321 }
3322
3323
3324 /* Read remainder of frame body into the rxctl buffer */
3325 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
3326 (bus->rxctl + firstread), rdlen, NULL, NULL, NULL);
3327 bus->f2rxdata++;
3328 ASSERT(sdret != BCME_PENDING);
3329
3330 /* Control frame failures need retransmission */
3331 if (sdret < 0) {
3332 DHD_ERROR(("%s: read %d control bytes failed: %d\n", __FUNCTION__, rdlen, sdret));
3333 bus->rxc_errors++; /* dhd.rx_ctlerrs is higher level */
3334 dhdsdio_rxfail(bus, TRUE, TRUE);
3335 goto done;
3336 }
3337
3338gotpkt:
3339
3340#ifdef DHD_DEBUG
3341 if (DHD_BYTES_ON() && DHD_CTL_ON()) {
3342 prhex("RxCtrl", bus->rxctl, len);
3343 }
3344#endif
3345
3346 /* Point to valid data and indicate its length */
3347 bus->rxctl += doff;
3348 bus->rxlen = len - doff;
3349
3350done:
3351 /* Awake any waiters */
3352 dhd_os_ioctl_resp_wake(bus->dhd);
3353}
3354
3355static uint8
3356dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq)
3357{
3358 uint16 dlen, totlen;
3359 uint8 *dptr, num = 0;
3360
3361 uint16 sublen, check;
3362 void *pfirst, *plast, *pnext, *save_pfirst;
3363 osl_t *osh = bus->dhd->osh;
3364
3365 int errcode;
3366 uint8 chan, seq, doff, sfdoff;
3367 uint8 txmax;
3368
3369 int ifidx = 0;
3370 bool usechain = bus->use_rxchain;
3371
3372 /* If packets, issue read(s) and send up packet chain */
3373 /* Return sequence numbers consumed? */
3374
3375 DHD_TRACE(("dhdsdio_rxglom: start: glomd %p glom %p\n", bus->glomd, bus->glom));
3376
3377 /* If there's a descriptor, generate the packet chain */
3378 if (bus->glomd) {
3379 dhd_os_sdlock_rxq(bus->dhd);
3380
3381 pfirst = plast = pnext = NULL;
3382 dlen = (uint16)PKTLEN(osh, bus->glomd);
3383 dptr = PKTDATA(osh, bus->glomd);
3384 if (!dlen || (dlen & 1)) {
3385 DHD_ERROR(("%s: bad glomd len (%d), ignore descriptor\n",
3386 __FUNCTION__, dlen));
3387 dlen = 0;
3388 }
3389
3390 for (totlen = num = 0; dlen; num++) {
3391 /* Get (and move past) next length */
3392 sublen = ltoh16_ua(dptr);
3393 dlen -= sizeof(uint16);
3394 dptr += sizeof(uint16);
3395 if ((sublen < SDPCM_HDRLEN) ||
3396 ((num == 0) && (sublen < (2 * SDPCM_HDRLEN)))) {
3397 DHD_ERROR(("%s: descriptor len %d bad: %d\n",
3398 __FUNCTION__, num, sublen));
3399 pnext = NULL;
3400 break;
3401 }
3402 if (sublen % DHD_SDALIGN) {
3403 DHD_ERROR(("%s: sublen %d not a multiple of %d\n",
3404 __FUNCTION__, sublen, DHD_SDALIGN));
3405 usechain = FALSE;
3406 }
3407 totlen += sublen;
3408
3409 /* For last frame, adjust read len so total is a block multiple */
3410 if (!dlen) {
3411 sublen += (ROUNDUP(totlen, bus->blocksize) - totlen);
3412 totlen = ROUNDUP(totlen, bus->blocksize);
3413 }
3414
3415 /* Allocate/chain packet for next subframe */
3416 if ((pnext = PKTGET(osh, sublen + DHD_SDALIGN, FALSE)) == NULL) {
3417 DHD_ERROR(("%s: PKTGET failed, num %d len %d\n",
3418 __FUNCTION__, num, sublen));
3419 break;
3420 }
3421 ASSERT(!PKTLINK(pnext));
3422 if (!pfirst) {
3423 ASSERT(!plast);
3424 pfirst = plast = pnext;
3425 } else {
3426 ASSERT(plast);
3427 PKTSETNEXT(osh, plast, pnext);
3428 plast = pnext;
3429 }
3430
3431 /* Adhere to start alignment requirements */
3432 PKTALIGN(osh, pnext, sublen, DHD_SDALIGN);
3433 }
3434
3435 /* If all allocations succeeded, save packet chain in bus structure */
3436 if (pnext) {
3437 DHD_GLOM(("%s: allocated %d-byte packet chain for %d subframes\n",
3438 __FUNCTION__, totlen, num));
3439 if (DHD_GLOM_ON() && bus->nextlen) {
3440 if (totlen != bus->nextlen) {
3441 DHD_GLOM(("%s: glomdesc mismatch: nextlen %d glomdesc %d "
3442 "rxseq %d\n", __FUNCTION__, bus->nextlen,
3443 totlen, rxseq));
3444 }
3445 }
3446 bus->glom = pfirst;
3447 pfirst = pnext = NULL;
3448 } else {
3449 if (pfirst)
3450 PKTFREE(osh, pfirst, FALSE);
3451 bus->glom = NULL;
3452 num = 0;
3453 }
3454
3455 /* Done with descriptor packet */
3456 PKTFREE(osh, bus->glomd, FALSE);
3457 bus->glomd = NULL;
3458 bus->nextlen = 0;
3459
3460 dhd_os_sdunlock_rxq(bus->dhd);
3461 }
3462
3463 /* Ok -- either we just generated a packet chain, or had one from before */
3464 if (bus->glom) {
3465 if (DHD_GLOM_ON()) {
3466 DHD_GLOM(("%s: attempt superframe read, packet chain:\n", __FUNCTION__));
3467 for (pnext = bus->glom; pnext; pnext = PKTNEXT(osh, pnext)) {
3468 DHD_GLOM((" %p: %p len 0x%04x (%d)\n",
3469 pnext, (uint8*)PKTDATA(osh, pnext),
3470 PKTLEN(osh, pnext), PKTLEN(osh, pnext)));
3471 }
3472 }
3473
3474 pfirst = bus->glom;
3475 dlen = (uint16)pkttotlen(osh, pfirst);
3476
3477 /* Do an SDIO read for the superframe. Configurable iovar to
3478 * read directly into the chained packet, or allocate a large
3479 * packet and and copy into the chain.
3480 */
3481 if (usechain) {
3482 errcode = dhd_bcmsdh_recv_buf(bus,
3483 bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2,
3484 F2SYNC, (uint8*)PKTDATA(osh, pfirst),
3485 dlen, pfirst, NULL, NULL);
3486 } else if (bus->dataptr) {
3487 errcode = dhd_bcmsdh_recv_buf(bus,
3488 bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2,
3489 F2SYNC, bus->dataptr,
3490 dlen, NULL, NULL, NULL);
3491 sublen = (uint16)pktfrombuf(osh, pfirst, 0, dlen, bus->dataptr);
3492 if (sublen != dlen) {
3493 DHD_ERROR(("%s: FAILED TO COPY, dlen %d sublen %d\n",
3494 __FUNCTION__, dlen, sublen));
3495 errcode = -1;
3496 }
3497 pnext = NULL;
3498 } else {
3499 DHD_ERROR(("COULDN'T ALLOC %d-BYTE GLOM, FORCE FAILURE\n", dlen));
3500 errcode = -1;
3501 }
3502 bus->f2rxdata++;
3503 ASSERT(errcode != BCME_PENDING);
3504
3505 /* On failure, kill the superframe, allow a couple retries */
3506 if (errcode < 0) {
3507 DHD_ERROR(("%s: glom read of %d bytes failed: %d\n",
3508 __FUNCTION__, dlen, errcode));
3509 bus->dhd->rx_errors++;
3510
3511 if (bus->glomerr++ < 3) {
3512 dhdsdio_rxfail(bus, TRUE, TRUE);
3513 } else {
3514 bus->glomerr = 0;
3515 dhdsdio_rxfail(bus, TRUE, FALSE);
3516 dhd_os_sdlock_rxq(bus->dhd);
3517 PKTFREE(osh, bus->glom, FALSE);
3518 dhd_os_sdunlock_rxq(bus->dhd);
3519 bus->rxglomfail++;
3520 bus->glom = NULL;
3521 }
3522 return 0;
3523 }
3524
3525#ifdef DHD_DEBUG
3526 if (DHD_GLOM_ON()) {
3527 prhex("SUPERFRAME", PKTDATA(osh, pfirst),
3528 MIN(PKTLEN(osh, pfirst), 48));
3529 }
3530#endif
3531
3532
3533 /* Validate the superframe header */
3534 dptr = (uint8 *)PKTDATA(osh, pfirst);
3535 sublen = ltoh16_ua(dptr);
3536 check = ltoh16_ua(dptr + sizeof(uint16));
3537
3538 chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
3539 seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
3540 bus->nextlen = dptr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
3541 if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
3542 DHD_INFO(("%s: got frame w/nextlen too large (%d) seq %d\n",
3543 __FUNCTION__, bus->nextlen, seq));
3544 bus->nextlen = 0;
3545 }
3546 doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
3547 txmax = SDPCM_WINDOW_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
3548
3549 errcode = 0;
3550 if ((uint16)~(sublen^check)) {
3551 DHD_ERROR(("%s (superframe): HW hdr error: len/check 0x%04x/0x%04x\n",
3552 __FUNCTION__, sublen, check));
3553 errcode = -1;
3554 } else if (ROUNDUP(sublen, bus->blocksize) != dlen) {
3555 DHD_ERROR(("%s (superframe): len 0x%04x, rounded 0x%04x, expect 0x%04x\n",
3556 __FUNCTION__, sublen, ROUNDUP(sublen, bus->blocksize), dlen));
3557 errcode = -1;
3558 } else if (SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]) != SDPCM_GLOM_CHANNEL) {
3559 DHD_ERROR(("%s (superframe): bad channel %d\n", __FUNCTION__,
3560 SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN])));
3561 errcode = -1;
3562 } else if (SDPCM_GLOMDESC(&dptr[SDPCM_FRAMETAG_LEN])) {
3563 DHD_ERROR(("%s (superframe): got second descriptor?\n", __FUNCTION__));
3564 errcode = -1;
3565 } else if ((doff < SDPCM_HDRLEN) ||
3566 (doff > (PKTLEN(osh, pfirst) - SDPCM_HDRLEN))) {
3567 DHD_ERROR(("%s (superframe): Bad data offset %d: HW %d pkt %d min %d\n",
3568 __FUNCTION__, doff, sublen, PKTLEN(osh, pfirst), SDPCM_HDRLEN));
3569 errcode = -1;
3570 }
3571
3572 /* Check sequence number of superframe SW header */
3573 if (rxseq != seq) {
3574 DHD_INFO(("%s: (superframe) rx_seq %d, expected %d\n",
3575 __FUNCTION__, seq, rxseq));
3576 bus->rx_badseq++;
3577 rxseq = seq;
3578 }
3579
3580 /* Check window for sanity */
3581 if ((uint8)(txmax - bus->tx_seq) > 0x40) {
3582 DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
3583 __FUNCTION__, txmax, bus->tx_seq));
3584 txmax = bus->tx_max;
3585 }
3586 bus->tx_max = txmax;
3587
3588 /* Remove superframe header, remember offset */
3589 PKTPULL(osh, pfirst, doff);
3590 sfdoff = doff;
3591
3592 /* Validate all the subframe headers */
3593 for (num = 0, pnext = pfirst; pnext && !errcode;
3594 num++, pnext = PKTNEXT(osh, pnext)) {
3595 dptr = (uint8 *)PKTDATA(osh, pnext);
3596 dlen = (uint16)PKTLEN(osh, pnext);
3597 sublen = ltoh16_ua(dptr);
3598 check = ltoh16_ua(dptr + sizeof(uint16));
3599 chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
3600 doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
3601#ifdef DHD_DEBUG
3602 if (DHD_GLOM_ON()) {
3603 prhex("subframe", dptr, 32);
3604 }
3605#endif
3606
3607 if ((uint16)~(sublen^check)) {
3608 DHD_ERROR(("%s (subframe %d): HW hdr error: "
3609 "len/check 0x%04x/0x%04x\n",
3610 __FUNCTION__, num, sublen, check));
3611 errcode = -1;
3612 } else if ((sublen > dlen) || (sublen < SDPCM_HDRLEN)) {
3613 DHD_ERROR(("%s (subframe %d): length mismatch: "
3614 "len 0x%04x, expect 0x%04x\n",
3615 __FUNCTION__, num, sublen, dlen));
3616 errcode = -1;
3617 } else if ((chan != SDPCM_DATA_CHANNEL) &&
3618 (chan != SDPCM_EVENT_CHANNEL)) {
3619 DHD_ERROR(("%s (subframe %d): bad channel %d\n",
3620 __FUNCTION__, num, chan));
3621 errcode = -1;
3622 } else if ((doff < SDPCM_HDRLEN) || (doff > sublen)) {
3623 DHD_ERROR(("%s (subframe %d): Bad data offset %d: HW %d min %d\n",
3624 __FUNCTION__, num, doff, sublen, SDPCM_HDRLEN));
3625 errcode = -1;
3626 }
3627 }
3628
3629 if (errcode) {
3630 /* Terminate frame on error, request a couple retries */
3631 if (bus->glomerr++ < 3) {
3632 /* Restore superframe header space */
3633 PKTPUSH(osh, pfirst, sfdoff);
3634 dhdsdio_rxfail(bus, TRUE, TRUE);
3635 } else {
3636 bus->glomerr = 0;
3637 dhdsdio_rxfail(bus, TRUE, FALSE);
3638 dhd_os_sdlock_rxq(bus->dhd);
3639 PKTFREE(osh, bus->glom, FALSE);
3640 dhd_os_sdunlock_rxq(bus->dhd);
3641 bus->rxglomfail++;
3642 bus->glom = NULL;
3643 }
3644 bus->nextlen = 0;
3645 return 0;
3646 }
3647
3648 /* Basic SD framing looks ok - process each packet (header) */
3649 save_pfirst = pfirst;
3650 bus->glom = NULL;
3651 plast = NULL;
3652
3653 dhd_os_sdlock_rxq(bus->dhd);
3654 for (num = 0; pfirst; rxseq++, pfirst = pnext) {
3655 pnext = PKTNEXT(osh, pfirst);
3656 PKTSETNEXT(osh, pfirst, NULL);
3657
3658 dptr = (uint8 *)PKTDATA(osh, pfirst);
3659 sublen = ltoh16_ua(dptr);
3660 chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
3661 seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
3662 doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
3663
3664 DHD_GLOM(("%s: Get subframe %d, %p(%p/%d), sublen %d chan %d seq %d\n",
3665 __FUNCTION__, num, pfirst, PKTDATA(osh, pfirst),
3666 PKTLEN(osh, pfirst), sublen, chan, seq));
3667
3668 ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL));
3669
3670 if (rxseq != seq) {
3671 DHD_GLOM(("%s: rx_seq %d, expected %d\n",
3672 __FUNCTION__, seq, rxseq));
3673 bus->rx_badseq++;
3674 rxseq = seq;
3675 }
3676
3677#ifdef DHD_DEBUG
3678 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
3679 prhex("Rx Subframe Data", dptr, dlen);
3680 }
3681#endif
3682
3683 PKTSETLEN(osh, pfirst, sublen);
3684 PKTPULL(osh, pfirst, doff);
3685
3686 if (PKTLEN(osh, pfirst) == 0) {
3687 PKTFREE(bus->dhd->osh, pfirst, FALSE);
3688 if (plast) {
3689 PKTSETNEXT(osh, plast, pnext);
3690 } else {
3691 ASSERT(save_pfirst == pfirst);
3692 save_pfirst = pnext;
3693 }
3694 continue;
3695 } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pfirst) != 0) {
3696 DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__));
3697 bus->dhd->rx_errors++;
3698 PKTFREE(osh, pfirst, FALSE);
3699 if (plast) {
3700 PKTSETNEXT(osh, plast, pnext);
3701 } else {
3702 ASSERT(save_pfirst == pfirst);
3703 save_pfirst = pnext;
3704 }
3705 continue;
3706 }
3707
3708 /* this packet will go up, link back into chain and count it */
3709 PKTSETNEXT(osh, pfirst, pnext);
3710 plast = pfirst;
3711 num++;
3712
3713#ifdef DHD_DEBUG
3714 if (DHD_GLOM_ON()) {
3715 DHD_GLOM(("%s subframe %d to stack, %p(%p/%d) nxt/lnk %p/%p\n",
3716 __FUNCTION__, num, pfirst,
3717 PKTDATA(osh, pfirst), PKTLEN(osh, pfirst),
3718 PKTNEXT(osh, pfirst), PKTLINK(pfirst)));
3719 prhex("", (uint8 *)PKTDATA(osh, pfirst),
3720 MIN(PKTLEN(osh, pfirst), 32));
3721 }
3722#endif /* DHD_DEBUG */
3723 }
3724 dhd_os_sdunlock_rxq(bus->dhd);
3725 if (num) {
3726 dhd_os_sdunlock(bus->dhd);
3727 dhd_rx_frame(bus->dhd, ifidx, save_pfirst, num, 0);
3728 dhd_os_sdlock(bus->dhd);
3729 }
3730
3731 bus->rxglomframes++;
3732 bus->rxglompkts += num;
3733 }
3734 return num;
3735}
3736
3737/* Return TRUE if there may be more frames to read */
3738static uint
3739dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished)
3740{
3741 osl_t *osh = bus->dhd->osh;
3742 bcmsdh_info_t *sdh = bus->sdh;
3743
3744 uint16 len, check; /* Extracted hardware header fields */
3745 uint8 chan, seq, doff; /* Extracted software header fields */
3746 uint8 fcbits; /* Extracted fcbits from software header */
3747 uint8 delta;
3748
3749 void *pkt; /* Packet for event or data frames */
3750 uint16 pad; /* Number of pad bytes to read */
3751 uint16 rdlen; /* Total number of bytes to read */
3752 uint8 rxseq; /* Next sequence number to expect */
3753 uint rxleft = 0; /* Remaining number of frames allowed */
3754 int sdret; /* Return code from bcmsdh calls */
3755 uint8 txmax; /* Maximum tx sequence offered */
3756 bool len_consistent; /* Result of comparing readahead len and len from hw-hdr */
3757 uint8 *rxbuf;
3758 int ifidx = 0;
3759 uint rxcount = 0; /* Total frames read */
3760
3761#if defined(DHD_DEBUG) || defined(SDTEST)
3762 bool sdtest = FALSE; /* To limit message spew from test mode */
3763#endif
3764
3765 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3766
3767 ASSERT(maxframes);
3768
3769#ifdef SDTEST
3770 /* Allow pktgen to override maxframes */
3771 if (bus->pktgen_count && (bus->pktgen_mode == DHD_PKTGEN_RECV)) {
3772 maxframes = bus->pktgen_count;
3773 sdtest = TRUE;
3774 }
3775#endif
3776
3777 /* Not finished unless we encounter no more frames indication */
3778 *finished = FALSE;
3779
3780
3781 for (rxseq = bus->rx_seq, rxleft = maxframes;
3782 !bus->rxskip && rxleft && bus->dhd->busstate != DHD_BUS_DOWN;
3783 rxseq++, rxleft--) {
3784
3785#ifdef DHDTHREAD
3786 /* tx more to improve rx performance */
3787 if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate &&
3788 pktq_mlen(&bus->txq, ~bus->flowcontrol) && DATAOK(bus)) {
3789 dhdsdio_sendfromq(bus, dhd_txbound);
3790 }
3791#endif /* DHDTHREAD */
3792
3793 /* Handle glomming separately */
3794 if (bus->glom || bus->glomd) {
3795 uint8 cnt;
3796 DHD_GLOM(("%s: calling rxglom: glomd %p, glom %p\n",
3797 __FUNCTION__, bus->glomd, bus->glom));
3798 cnt = dhdsdio_rxglom(bus, rxseq);
3799 DHD_GLOM(("%s: rxglom returned %d\n", __FUNCTION__, cnt));
3800 rxseq += cnt - 1;
3801 rxleft = (rxleft > cnt) ? (rxleft - cnt) : 1;
3802 continue;
3803 }
3804
3805 /* Try doing single read if we can */
3806 if (dhd_readahead && bus->nextlen) {
3807 uint16 nextlen = bus->nextlen;
3808 bus->nextlen = 0;
3809
3810 if (bus->bus == SPI_BUS) {
3811 rdlen = len = nextlen;
3812 }
3813 else {
3814 rdlen = len = nextlen << 4;
3815
3816 /* Pad read to blocksize for efficiency */
3817 if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
3818 pad = bus->blocksize - (rdlen % bus->blocksize);
3819 if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
3820 ((rdlen + pad + firstread) < MAX_RX_DATASZ))
3821 rdlen += pad;
3822 } else if (rdlen % DHD_SDALIGN) {
3823 rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
3824 }
3825 }
3826
3827 /* We use bus->rxctl buffer in WinXP for initial control pkt receives.
3828 * Later we use buffer-poll for data as well as control packets.
3829 * This is required because dhd receives full frame in gSPI unlike SDIO.
3830 * After the frame is received we have to distinguish whether it is data
3831 * or non-data frame.
3832 */
3833 /* Allocate a packet buffer */
3834 dhd_os_sdlock_rxq(bus->dhd);
3835 if (!(pkt = PKTGET(osh, rdlen + DHD_SDALIGN, FALSE))) {
3836 if (bus->bus == SPI_BUS) {
3837 bus->usebufpool = FALSE;
3838 bus->rxctl = bus->rxbuf;
3839 if (dhd_alignctl) {
3840 bus->rxctl += firstread;
3841 if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN)))
3842 bus->rxctl += (DHD_SDALIGN - pad);
3843 bus->rxctl -= firstread;
3844 }
3845 ASSERT(bus->rxctl >= bus->rxbuf);
3846 rxbuf = bus->rxctl;
3847 /* Read the entire frame */
3848 sdret = dhd_bcmsdh_recv_buf(bus,
3849 bcmsdh_cur_sbwad(sdh),
3850 SDIO_FUNC_2,
3851 F2SYNC, rxbuf, rdlen,
3852 NULL, NULL, NULL);
3853 bus->f2rxdata++;
3854 ASSERT(sdret != BCME_PENDING);
3855
3856
3857 /* Control frame failures need retransmission */
3858 if (sdret < 0) {
3859 DHD_ERROR(("%s: read %d control bytes failed: %d\n",
3860 __FUNCTION__, rdlen, sdret));
3861 /* dhd.rx_ctlerrs is higher level */
3862 bus->rxc_errors++;
3863 dhd_os_sdunlock_rxq(bus->dhd);
3864 dhdsdio_rxfail(bus, TRUE,
3865 (bus->bus == SPI_BUS) ? FALSE : TRUE);
3866 continue;
3867 }
3868 } else {
3869 /* Give up on data, request rtx of events */
3870 DHD_ERROR(("%s (nextlen): PKTGET failed: len %d rdlen %d "
3871 "expected rxseq %d\n",
3872 __FUNCTION__, len, rdlen, rxseq));
3873 /* Just go try again w/normal header read */
3874 dhd_os_sdunlock_rxq(bus->dhd);
3875 continue;
3876 }
3877 } else {
3878 if (bus->bus == SPI_BUS)
3879 bus->usebufpool = TRUE;
3880
3881 ASSERT(!PKTLINK(pkt));
3882 PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN);
3883 rxbuf = (uint8 *)PKTDATA(osh, pkt);
3884 /* Read the entire frame */
3885 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh),
3886 SDIO_FUNC_2,
3887 F2SYNC, rxbuf, rdlen,
3888 pkt, NULL, NULL);
3889 bus->f2rxdata++;
3890 ASSERT(sdret != BCME_PENDING);
3891
3892 if (sdret < 0) {
3893 DHD_ERROR(("%s (nextlen): read %d bytes failed: %d\n",
3894 __FUNCTION__, rdlen, sdret));
3895 PKTFREE(bus->dhd->osh, pkt, FALSE);
3896 bus->dhd->rx_errors++;
3897 dhd_os_sdunlock_rxq(bus->dhd);
3898 /* Force retry w/normal header read. Don't attempt NAK for
3899 * gSPI
3900 */
3901 dhdsdio_rxfail(bus, TRUE,
3902 (bus->bus == SPI_BUS) ? FALSE : TRUE);
3903 continue;
3904 }
3905 }
3906 dhd_os_sdunlock_rxq(bus->dhd);
3907
3908 /* Now check the header */
3909 bcopy(rxbuf, bus->rxhdr, SDPCM_HDRLEN);
3910
3911 /* Extract hardware header fields */
3912 len = ltoh16_ua(bus->rxhdr);
3913 check = ltoh16_ua(bus->rxhdr + sizeof(uint16));
3914
3915 /* All zeros means readahead info was bad */
3916 if (!(len|check)) {
3917 DHD_INFO(("%s (nextlen): read zeros in HW header???\n",
3918 __FUNCTION__));
3919 dhd_os_sdlock_rxq(bus->dhd);
3920 PKTFREE2();
3921 dhd_os_sdunlock_rxq(bus->dhd);
3922 GSPI_PR55150_BAILOUT;
3923 continue;
3924 }
3925
3926 /* Validate check bytes */
3927 if ((uint16)~(len^check)) {
3928 DHD_ERROR(("%s (nextlen): HW hdr error: nextlen/len/check"
3929 " 0x%04x/0x%04x/0x%04x\n", __FUNCTION__, nextlen,
3930 len, check));
3931 dhd_os_sdlock_rxq(bus->dhd);
3932 PKTFREE2();
3933 dhd_os_sdunlock_rxq(bus->dhd);
3934 bus->rx_badhdr++;
3935 dhdsdio_rxfail(bus, FALSE, FALSE);
3936 GSPI_PR55150_BAILOUT;
3937 continue;
3938 }
3939
3940 /* Validate frame length */
3941 if (len < SDPCM_HDRLEN) {
3942 DHD_ERROR(("%s (nextlen): HW hdr length invalid: %d\n",
3943 __FUNCTION__, len));
3944 dhd_os_sdlock_rxq(bus->dhd);
3945 PKTFREE2();
3946 dhd_os_sdunlock_rxq(bus->dhd);
3947 GSPI_PR55150_BAILOUT;
3948 continue;
3949 }
3950
3951 /* Check for consistency with readahead info */
3952 len_consistent = (nextlen != (ROUNDUP(len, 16) >> 4));
3953 if (len_consistent) {
3954 /* Mismatch, force retry w/normal header (may be >4K) */
3955 DHD_ERROR(("%s (nextlen): mismatch, nextlen %d len %d rnd %d; "
3956 "expected rxseq %d\n",
3957 __FUNCTION__, nextlen, len, ROUNDUP(len, 16), rxseq));
3958 dhd_os_sdlock_rxq(bus->dhd);
3959 PKTFREE2();
3960 dhd_os_sdunlock_rxq(bus->dhd);
3961 dhdsdio_rxfail(bus, TRUE, (bus->bus == SPI_BUS) ? FALSE : TRUE);
3962 GSPI_PR55150_BAILOUT;
3963 continue;
3964 }
3965
3966
3967 /* Extract software header fields */
3968 chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
3969 seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
3970 doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
3971 txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
3972
3973 bus->nextlen =
3974 bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
3975 if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
3976 DHD_INFO(("%s (nextlen): got frame w/nextlen too large"
3977 " (%d), seq %d\n", __FUNCTION__, bus->nextlen,
3978 seq));
3979 bus->nextlen = 0;
3980 }
3981
3982 bus->dhd->rx_readahead_cnt ++;
3983 /* Handle Flow Control */
3984 fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
3985
3986 delta = 0;
3987 if (~bus->flowcontrol & fcbits) {
3988 bus->fc_xoff++;
3989 delta = 1;
3990 }
3991 if (bus->flowcontrol & ~fcbits) {
3992 bus->fc_xon++;
3993 delta = 1;
3994 }
3995
3996 if (delta) {
3997 bus->fc_rcvd++;
3998 bus->flowcontrol = fcbits;
3999 }
4000
4001 /* Check and update sequence number */
4002 if (rxseq != seq) {
4003 DHD_INFO(("%s (nextlen): rx_seq %d, expected %d\n",
4004 __FUNCTION__, seq, rxseq));
4005 bus->rx_badseq++;
4006 rxseq = seq;
4007 }
4008
4009 /* Check window for sanity */
4010 if ((uint8)(txmax - bus->tx_seq) > 0x40) {
4011 DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
4012 __FUNCTION__, txmax, bus->tx_seq));
4013 txmax = bus->tx_max;
4014 }
4015 bus->tx_max = txmax;
4016
4017#ifdef DHD_DEBUG
4018 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
4019 prhex("Rx Data", rxbuf, len);
4020 } else if (DHD_HDRS_ON()) {
4021 prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN);
4022 }
4023#endif
4024
4025 if (chan == SDPCM_CONTROL_CHANNEL) {
4026 if (bus->bus == SPI_BUS) {
4027 dhdsdio_read_control(bus, rxbuf, len, doff);
4028 if (bus->usebufpool) {
4029 dhd_os_sdlock_rxq(bus->dhd);
4030 PKTFREE(bus->dhd->osh, pkt, FALSE);
4031 dhd_os_sdunlock_rxq(bus->dhd);
4032 }
4033 continue;
4034 } else {
4035 DHD_ERROR(("%s (nextlen): readahead on control"
4036 " packet %d?\n", __FUNCTION__, seq));
4037 /* Force retry w/normal header read */
4038 bus->nextlen = 0;
4039 dhdsdio_rxfail(bus, FALSE, TRUE);
4040 dhd_os_sdlock_rxq(bus->dhd);
4041 PKTFREE2();
4042 dhd_os_sdunlock_rxq(bus->dhd);
4043 continue;
4044 }
4045 }
4046
4047 if ((bus->bus == SPI_BUS) && !bus->usebufpool) {
4048 DHD_ERROR(("Received %d bytes on %d channel. Running out of "
4049 "rx pktbuf's or not yet malloced.\n", len, chan));
4050 continue;
4051 }
4052
4053 /* Validate data offset */
4054 if ((doff < SDPCM_HDRLEN) || (doff > len)) {
4055 DHD_ERROR(("%s (nextlen): bad data offset %d: HW len %d min %d\n",
4056 __FUNCTION__, doff, len, SDPCM_HDRLEN));
4057 dhd_os_sdlock_rxq(bus->dhd);
4058 PKTFREE2();
4059 dhd_os_sdunlock_rxq(bus->dhd);
4060 ASSERT(0);
4061 dhdsdio_rxfail(bus, FALSE, FALSE);
4062 continue;
4063 }
4064
4065 /* All done with this one -- now deliver the packet */
4066 goto deliver;
4067 }
4068 /* gSPI frames should not be handled in fractions */
4069 if (bus->bus == SPI_BUS) {
4070 break;
4071 }
4072
4073 /* Read frame header (hardware and software) */
4074 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
4075 bus->rxhdr, firstread, NULL, NULL, NULL);
4076 bus->f2rxhdrs++;
4077 ASSERT(sdret != BCME_PENDING);
4078
4079 if (sdret < 0) {
4080 DHD_ERROR(("%s: RXHEADER FAILED: %d\n", __FUNCTION__, sdret));
4081 bus->rx_hdrfail++;
4082 dhdsdio_rxfail(bus, TRUE, TRUE);
4083 continue;
4084 }
4085
4086#ifdef DHD_DEBUG
4087 if (DHD_BYTES_ON() || DHD_HDRS_ON()) {
4088 prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN);
4089 }
4090#endif
4091
4092 /* Extract hardware header fields */
4093 len = ltoh16_ua(bus->rxhdr);
4094 check = ltoh16_ua(bus->rxhdr + sizeof(uint16));
4095
4096 /* All zeros means no more frames */
4097 if (!(len|check)) {
4098 *finished = TRUE;
4099 break;
4100 }
4101
4102 /* Validate check bytes */
4103 if ((uint16)~(len^check)) {
4104 DHD_ERROR(("%s: HW hdr error: len/check 0x%04x/0x%04x\n",
4105 __FUNCTION__, len, check));
4106 bus->rx_badhdr++;
4107 dhdsdio_rxfail(bus, FALSE, FALSE);
4108 continue;
4109 }
4110
4111 /* Validate frame length */
4112 if (len < SDPCM_HDRLEN) {
4113 DHD_ERROR(("%s: HW hdr length invalid: %d\n", __FUNCTION__, len));
4114 continue;
4115 }
4116
4117 /* Extract software header fields */
4118 chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
4119 seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
4120 doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
4121 txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
4122
4123 /* Validate data offset */
4124 if ((doff < SDPCM_HDRLEN) || (doff > len)) {
4125 DHD_ERROR(("%s: Bad data offset %d: HW len %d, min %d seq %d\n",
4126 __FUNCTION__, doff, len, SDPCM_HDRLEN, seq));
4127 bus->rx_badhdr++;
4128 ASSERT(0);
4129 dhdsdio_rxfail(bus, FALSE, FALSE);
4130 continue;
4131 }
4132
4133 /* Save the readahead length if there is one */
4134 bus->nextlen = bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
4135 if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
4136 DHD_INFO(("%s (nextlen): got frame w/nextlen too large (%d), seq %d\n",
4137 __FUNCTION__, bus->nextlen, seq));
4138 bus->nextlen = 0;
4139 }
4140
4141 /* Handle Flow Control */
4142 fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
4143
4144 delta = 0;
4145 if (~bus->flowcontrol & fcbits) {
4146 bus->fc_xoff++;
4147 delta = 1;
4148 }
4149 if (bus->flowcontrol & ~fcbits) {
4150 bus->fc_xon++;
4151 delta = 1;
4152 }
4153
4154 if (delta) {
4155 bus->fc_rcvd++;
4156 bus->flowcontrol = fcbits;
4157 }
4158
4159 /* Check and update sequence number */
4160 if (rxseq != seq) {
4161 DHD_INFO(("%s: rx_seq %d, expected %d\n", __FUNCTION__, seq, rxseq));
4162 bus->rx_badseq++;
4163 rxseq = seq;
4164 }
4165
4166 /* Check window for sanity */
4167 if ((uint8)(txmax - bus->tx_seq) > 0x40) {
4168 DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
4169 __FUNCTION__, txmax, bus->tx_seq));
4170 txmax = bus->tx_max;
4171 }
4172 bus->tx_max = txmax;
4173
4174 /* Call a separate function for control frames */
4175 if (chan == SDPCM_CONTROL_CHANNEL) {
4176 dhdsdio_read_control(bus, bus->rxhdr, len, doff);
4177 continue;
4178 }
4179
4180 ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL) ||
4181 (chan == SDPCM_TEST_CHANNEL) || (chan == SDPCM_GLOM_CHANNEL));
4182
4183 /* Length to read */
4184 rdlen = (len > firstread) ? (len - firstread) : 0;
4185
4186 /* May pad read to blocksize for efficiency */
4187 if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
4188 pad = bus->blocksize - (rdlen % bus->blocksize);
4189 if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
4190 ((rdlen + pad + firstread) < MAX_RX_DATASZ))
4191 rdlen += pad;
4192 } else if (rdlen % DHD_SDALIGN) {
4193 rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
4194 }
4195
4196 /* Satisfy length-alignment requirements */
4197 if (forcealign && (rdlen & (ALIGNMENT - 1)))
4198 rdlen = ROUNDUP(rdlen, ALIGNMENT);
4199
4200 if ((rdlen + firstread) > MAX_RX_DATASZ) {
4201 /* Too long -- skip this frame */
4202 DHD_ERROR(("%s: too long: len %d rdlen %d\n", __FUNCTION__, len, rdlen));
4203 bus->dhd->rx_errors++; bus->rx_toolong++;
4204 dhdsdio_rxfail(bus, FALSE, FALSE);
4205 continue;
4206 }
4207
4208 dhd_os_sdlock_rxq(bus->dhd);
4209 if (!(pkt = PKTGET(osh, (rdlen + firstread + DHD_SDALIGN), FALSE))) {
4210 /* Give up on data, request rtx of events */
4211 DHD_ERROR(("%s: PKTGET failed: rdlen %d chan %d\n",
4212 __FUNCTION__, rdlen, chan));
4213 bus->dhd->rx_dropped++;
4214 dhd_os_sdunlock_rxq(bus->dhd);
4215 dhdsdio_rxfail(bus, FALSE, RETRYCHAN(chan));
4216 continue;
4217 }
4218 dhd_os_sdunlock_rxq(bus->dhd);
4219
4220 ASSERT(!PKTLINK(pkt));
4221
4222 /* Leave room for what we already read, and align remainder */
4223 ASSERT(firstread < (PKTLEN(osh, pkt)));
4224 PKTPULL(osh, pkt, firstread);
4225 PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN);
4226
4227 /* Read the remaining frame data */
4228 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
4229 ((uint8 *)PKTDATA(osh, pkt)), rdlen, pkt, NULL, NULL);
4230 bus->f2rxdata++;
4231 ASSERT(sdret != BCME_PENDING);
4232
4233 if (sdret < 0) {
4234 DHD_ERROR(("%s: read %d %s bytes failed: %d\n", __FUNCTION__, rdlen,
4235 ((chan == SDPCM_EVENT_CHANNEL) ? "event" :
4236 ((chan == SDPCM_DATA_CHANNEL) ? "data" : "test")), sdret));
4237 dhd_os_sdlock_rxq(bus->dhd);
4238 PKTFREE(bus->dhd->osh, pkt, FALSE);
4239 dhd_os_sdunlock_rxq(bus->dhd);
4240 bus->dhd->rx_errors++;
4241 dhdsdio_rxfail(bus, TRUE, RETRYCHAN(chan));
4242 continue;
4243 }
4244
4245 /* Copy the already-read portion */
4246 PKTPUSH(osh, pkt, firstread);
4247 bcopy(bus->rxhdr, PKTDATA(osh, pkt), firstread);
4248
4249#ifdef DHD_DEBUG
4250 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
4251 prhex("Rx Data", PKTDATA(osh, pkt), len);
4252 }
4253#endif
4254
4255deliver:
4256 /* Save superframe descriptor and allocate packet frame */
4257 if (chan == SDPCM_GLOM_CHANNEL) {
4258 if (SDPCM_GLOMDESC(&bus->rxhdr[SDPCM_FRAMETAG_LEN])) {
4259 DHD_GLOM(("%s: got glom descriptor, %d bytes:\n",
4260 __FUNCTION__, len));
4261#ifdef DHD_DEBUG
4262 if (DHD_GLOM_ON()) {
4263 prhex("Glom Data", PKTDATA(osh, pkt), len);
4264 }
4265#endif
4266 PKTSETLEN(osh, pkt, len);
4267 ASSERT(doff == SDPCM_HDRLEN);
4268 PKTPULL(osh, pkt, SDPCM_HDRLEN);
4269 bus->glomd = pkt;
4270 } else {
4271 DHD_ERROR(("%s: glom superframe w/o descriptor!\n", __FUNCTION__));
4272 dhdsdio_rxfail(bus, FALSE, FALSE);
4273 }
4274 continue;
4275 }
4276
4277 /* Fill in packet len and prio, deliver upward */
4278 PKTSETLEN(osh, pkt, len);
4279 PKTPULL(osh, pkt, doff);
4280
4281#ifdef SDTEST
4282 /* Test channel packets are processed separately */
4283 if (chan == SDPCM_TEST_CHANNEL) {
4284 dhdsdio_testrcv(bus, pkt, seq);
4285 con