1 /*
2 * DHD Bus Module for SDIO
3 *
4 * Copyright (C) 1999-2013, 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 419981 2013-08-23 19:49:45Z $
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 bool dhd_mp_halting(dhd_pub_t *dhdp);
70 extern void bcmsdh_waitfor_iodrain(void *sdh);
71 extern void bcmsdh_reject_ioreqs(void *sdh, bool reject);
72 extern bool bcmsdh_fatal_error(void *sdh);
73
74 #ifndef DHDSDIO_MEM_DUMP_FNAME
75 #define DHDSDIO_MEM_DUMP_FNAME "mem_dump"
76 #endif
77
78 #define QLEN 256 /* bulk rx and tx queue lengths */
79 #define FCHI (QLEN - 10)
80 #define FCLOW (FCHI / 2)
81 #define PRIOMASK 7
82
83 #define TXRETRIES 2 /* # of retries for tx frames */
84 #ifndef DHD_RXBOUND
85 #define DHD_RXBOUND 50 /* Default for max rx frames in one scheduling */
86 #endif
87
88 #ifndef DHD_TXBOUND
89 #define DHD_TXBOUND 20 /* Default for max tx frames in one scheduling */
90 #endif
91
92 #define DHD_TXMINMAX 1 /* Max tx frames if rx still pending */
93
94 #define MEMBLOCK 2048 /* Block size used for downloading of dongle image */
95 #define MAX_NVRAMBUF_SIZE 4096 /* max nvram buf size */
96 #define MAX_DATA_BUF (32 * 1024) /* Must be large enough to hold biggest possible glom */
97
98 #ifndef DHD_FIRSTREAD
99 #define DHD_FIRSTREAD 32
100 #endif
101 #if !ISPOWEROF2(DHD_FIRSTREAD)
102 #error DHD_FIRSTREAD is not a power of 2!
103 #endif
104
105 #ifdef BCMSDIOH_TXGLOM
106 /* Total length of TX frame header for dongle protocol */
107 #define SDPCM_HDRLEN (SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN + SDPCM_SWHEADER_LEN)
108 /* Total length of RX frame for dongle protocol */
109 #else
110 /* Total length of TX frame header for dongle protocol */
111 #define SDPCM_HDRLEN (SDPCM_FRAMETAG_LEN + SDPCM_SWHEADER_LEN)
112 #endif
113
114 #define SDPCM_HDRLEN_RX (SDPCM_FRAMETAG_LEN + SDPCM_SWHEADER_LEN)
115
116 #ifdef SDTEST
117 #define SDPCM_RESERVE (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN)
118 #else
119 #define SDPCM_RESERVE (SDPCM_HDRLEN + DHD_SDALIGN)
120 #endif
121
122 /* Space for header read, limit for data packets */
123 #ifndef MAX_HDR_READ
124 #define MAX_HDR_READ 32
125 #endif
126 #if !ISPOWEROF2(MAX_HDR_READ)
127 #error MAX_HDR_READ is not a power of 2!
128 #endif
129
130 #define MAX_RX_DATASZ 2048
131
132 /* Maximum milliseconds to wait for F2 to come up */
133 #define DHD_WAIT_F2RDY 3000
134
135 /* Bump up limit on waiting for HT to account for first startup;
136 * if the image is doing a CRC calculation before programming the PMU
137 * for HT availability, it could take a couple hundred ms more, so
138 * max out at a 1 second (1000000us).
139 */
140 #if (PMU_MAX_TRANSITION_DLY <= 1000000)
141 #undef PMU_MAX_TRANSITION_DLY
142 #define PMU_MAX_TRANSITION_DLY 1000000
143 #endif
144
145 /* Value for ChipClockCSR during initial setup */
146 #define DHD_INIT_CLKCTL1 (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ)
147 #define DHD_INIT_CLKCTL2 (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP)
148
149 /* Flags for SDH calls */
150 #define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED)
151
152 /* Packet free applicable unconditionally for sdio and sdspi. Conditional if
153 * bufpool was present for gspi bus.
154 */
155 #define PKTFREE2() if ((bus->bus != SPI_BUS) || bus->usebufpool) \
156 PKTFREE(bus->dhd->osh, pkt, FALSE);
157 DHD_SPINWAIT_SLEEP_INIT(sdioh_spinwait_sleep);
158 #if defined(OOB_INTR_ONLY)
159 extern void bcmsdh_set_irq(int flag);
160 #endif
161 #ifdef PROP_TXSTATUS
162 extern void dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success);
163 extern void dhd_wlfc_trigger_pktcommit(dhd_pub_t *dhd);
164 #endif
165
166
167 #ifdef DHD_DEBUG
168 /* Device console log buffer state */
169 #define CONSOLE_LINE_MAX 192
170 #define CONSOLE_BUFFER_MAX 2024
171 typedef struct dhd_console {
172 uint count; /* Poll interval msec counter */
173 uint log_addr; /* Log struct address (fixed) */
174 hndrte_log_t log; /* Log struct (host copy) */
175 uint bufsize; /* Size of log buffer */
176 uint8 *buf; /* Log buffer (host copy) */
177 uint last; /* Last buffer read index */
178 } dhd_console_t;
179 #endif /* DHD_DEBUG */
180
181 #define REMAP_ENAB(bus) ((bus)->remap)
182 #define REMAP_ISADDR(bus, a) (((a) >= ((bus)->orig_ramsize)) && ((a) < ((bus)->ramsize)))
183 #define KSO_ENAB(bus) ((bus)->kso)
184 #define SR_ENAB(bus) ((bus)->_srenab)
185 #define SLPAUTO_ENAB(bus) ((SR_ENAB(bus)) && ((bus)->_slpauto))
186 #define MIN_RSRC_ADDR (SI_ENUM_BASE + 0x618)
187 #define MIN_RSRC_SR 0x3
188 #define CORE_CAPEXT_ADDR (SI_ENUM_BASE + 0x64c)
189 #define CORE_CAPEXT_SR_SUPPORTED_MASK (1 << 1)
190 #define RCTL_MACPHY_DISABLE_MASK (1 << 26)
191 #define RCTL_LOGIC_DISABLE_MASK (1 << 27)
192
193 #define OOB_WAKEUP_ENAB(bus) ((bus)->_oobwakeup)
194 #define GPIO_DEV_SRSTATE 16 /* Host gpio17 mapped to device gpio0 SR state */
195 #define GPIO_DEV_SRSTATE_TIMEOUT 320000 /* 320ms */
196 #define GPIO_DEV_WAKEUP 17 /* Host gpio17 mapped to device gpio1 wakeup */
197 #define CC_CHIPCTRL2_GPIO1_WAKEUP (1 << 0)
198 #define CC_CHIPCTRL3_SR_ENG_ENABLE (1 << 2)
199 #define OVERFLOW_BLKSZ512_WM 48
200 #define OVERFLOW_BLKSZ512_MES 80
201
202 #define CC_PMUCC3 (0x3)
203 /* Private data for SDIO bus interaction */
204 typedef struct dhd_bus {
205 dhd_pub_t *dhd;
206
207 bcmsdh_info_t *sdh; /* Handle for BCMSDH calls */
208 si_t *sih; /* Handle for SI calls */
209 char *vars; /* Variables (from CIS and/or other) */
210 uint varsz; /* Size of variables buffer */
211 uint32 sbaddr; /* Current SB window pointer (-1, invalid) */
212
213 sdpcmd_regs_t *regs; /* Registers for SDIO core */
214 uint sdpcmrev; /* SDIO core revision */
215 uint armrev; /* CPU core revision */
216 uint ramrev; /* SOCRAM core revision */
217 uint32 ramsize; /* Size of RAM in SOCRAM (bytes) */
218 uint32 orig_ramsize; /* Size of RAM in SOCRAM (bytes) */
219 uint32 srmemsize; /* Size of SRMEM */
220
221 uint32 bus; /* gSPI or SDIO bus */
222 uint32 hostintmask; /* Copy of Host Interrupt Mask */
223 uint32 intstatus; /* Intstatus bits (events) pending */
224 bool dpc_sched; /* Indicates DPC schedule (intrpt rcvd) */
225 bool fcstate; /* State of dongle flow-control */
226
227 uint16 cl_devid; /* cached devid for dhdsdio_probe_attach() */
228 char *fw_path; /* module_param: path to firmware image */
229 char *nv_path; /* module_param: path to nvram vars file */
230 const char *nvram_params; /* user specified nvram params. */
231
232 uint blocksize; /* Block size of SDIO transfers */
233 uint roundup; /* Max roundup limit */
234
235 struct pktq txq; /* Queue length used for flow-control */
236 uint8 flowcontrol; /* per prio flow control bitmask */
237 uint8 tx_seq; /* Transmit sequence number (next) */
238 uint8 tx_max; /* Maximum transmit sequence allowed */
239
240 uint8 hdrbuf[MAX_HDR_READ + DHD_SDALIGN];
241 uint8 *rxhdr; /* Header of current rx frame (in hdrbuf) */
242 uint16 nextlen; /* Next Read Len from last header */
243 uint8 rx_seq; /* Receive sequence number (expected) */
244 bool rxskip; /* Skip receive (awaiting NAK ACK) */
245
246 void *glomd; /* Packet containing glomming descriptor */
247 void *glom; /* Packet chain for glommed superframe */
248 uint glomerr; /* Glom packet read errors */
249
250 uint8 *rxbuf; /* Buffer for receiving control packets */
251 uint rxblen; /* Allocated length of rxbuf */
252 uint8 *rxctl; /* Aligned pointer into rxbuf */
253 uint8 *databuf; /* Buffer for receiving big glom packet */
254 uint8 *dataptr; /* Aligned pointer into databuf */
255 uint rxlen; /* Length of valid data in buffer */
256
257 uint8 sdpcm_ver; /* Bus protocol reported by dongle */
258
259 bool intr; /* Use interrupts */
260 bool poll; /* Use polling */
261 bool ipend; /* Device interrupt is pending */
262 bool intdis; /* Interrupts disabled by isr */
263 uint intrcount; /* Count of device interrupt callbacks */
264 uint lastintrs; /* Count as of last watchdog timer */
265 uint spurious; /* Count of spurious interrupts */
266 uint pollrate; /* Ticks between device polls */
267 uint polltick; /* Tick counter */
268 uint pollcnt; /* Count of active polls */
269
270 #ifdef DHD_DEBUG
271 dhd_console_t console; /* Console output polling support */
272 uint console_addr; /* Console address from shared struct */
273 #endif /* DHD_DEBUG */
274
275 uint regfails; /* Count of R_REG/W_REG failures */
276
277 uint clkstate; /* State of sd and backplane clock(s) */
278 bool activity; /* Activity flag for clock down */
279 int32 idletime; /* Control for activity timeout */
280 int32 idlecount; /* Activity timeout counter */
281 int32 idleclock; /* How to set bus driver when idle */
282 int32 sd_divisor; /* Speed control to bus driver */
283 int32 sd_mode; /* Mode control to bus driver */
284 int32 sd_rxchain; /* If bcmsdh api accepts PKT chains */
285 bool use_rxchain; /* If dhd should use PKT chains */
286 bool sleeping; /* Is SDIO bus sleeping? */
287 uint rxflow_mode; /* Rx flow control mode */
288 bool rxflow; /* Is rx flow control on */
289 uint prev_rxlim_hit; /* Is prev rx limit exceeded (per dpc schedule) */
290 bool alp_only; /* Don't use HT clock (ALP only) */
291 /* Field to decide if rx of control frames happen in rxbuf or lb-pool */
292 bool usebufpool;
293
294 #ifdef SDTEST
295 /* external loopback */
296 bool ext_loop;
297 uint8 loopid;
298
299 /* pktgen configuration */
300 uint pktgen_freq; /* Ticks between bursts */
301 uint pktgen_count; /* Packets to send each burst */
302 uint pktgen_print; /* Bursts between count displays */
303 uint pktgen_total; /* Stop after this many */
304 uint pktgen_minlen; /* Minimum packet data len */
305 uint pktgen_maxlen; /* Maximum packet data len */
306 uint pktgen_mode; /* Configured mode: tx, rx, or echo */
307 uint pktgen_stop; /* Number of tx failures causing stop */
308
309 /* active pktgen fields */
310 uint pktgen_tick; /* Tick counter for bursts */
311 uint pktgen_ptick; /* Burst counter for printing */
312 uint pktgen_sent; /* Number of test packets generated */
313 uint pktgen_rcvd; /* Number of test packets received */
314 uint pktgen_prev_time; /* Time at which previous stats where printed */
315 uint pktgen_prev_sent; /* Number of test packets generated when
316 * previous stats were printed
317 */
318 uint pktgen_prev_rcvd; /* Number of test packets received when
319 * previous stats were printed
320 */
321 uint pktgen_fail; /* Number of failed send attempts */
322 uint16 pktgen_len; /* Length of next packet to send */
323 #define PKTGEN_RCV_IDLE (0)
324 #define PKTGEN_RCV_ONGOING (1)
325 uint16 pktgen_rcv_state; /* receive state */
326 uint pktgen_rcvd_rcvsession; /* test pkts rcvd per rcv session. */
327 #endif /* SDTEST */
328
329 /* Some additional counters */
330 uint tx_sderrs; /* Count of tx attempts with sd errors */
331 uint fcqueued; /* Tx packets that got queued */
332 uint rxrtx; /* Count of rtx requests (NAK to dongle) */
333 uint rx_toolong; /* Receive frames too long to receive */
334 uint rxc_errors; /* SDIO errors when reading control frames */
335 uint rx_hdrfail; /* SDIO errors on header reads */
336 uint rx_badhdr; /* Bad received headers (roosync?) */
337 uint rx_badseq; /* Mismatched rx sequence number */
338 uint fc_rcvd; /* Number of flow-control events received */
339 uint fc_xoff; /* Number which turned on flow-control */
340 uint fc_xon; /* Number which turned off flow-control */
341 uint rxglomfail; /* Failed deglom attempts */
342 uint rxglomframes; /* Number of glom frames (superframes) */
343 uint rxglompkts; /* Number of packets from glom frames */
344 uint f2rxhdrs; /* Number of header reads */
345 uint f2rxdata; /* Number of frame data reads */
346 uint f2txdata; /* Number of f2 frame writes */
347 uint f1regdata; /* Number of f1 register accesses */
348
349 uint8 *ctrl_frame_buf;
350 uint32 ctrl_frame_len;
351 bool ctrl_frame_stat;
352 uint32 rxint_mode; /* rx interrupt mode */
353 bool remap; /* Contiguous 1MB RAM: 512K socram + 512K devram
354 * Available with socram rev 16
355 * Remap region not DMA-able
356 */
357 bool kso;
358 bool _slpauto;
359 bool _oobwakeup;
360 bool _srenab;
361 bool readframes;
362 bool reqbussleep;
363 uint32 resetinstr;
364 uint32 dongle_ram_base;
365 #ifdef BCMSDIOH_TXGLOM
366 void *glom_pkt_arr[SDPCM_MAXGLOM_SIZE]; /* Array of pkts for glomming */
367 uint16 glom_cnt; /* Number of pkts in the glom array */
368 uint16 glom_total_len; /* Total length of pkts in glom array */
369 bool glom_enable; /* Flag to indicate whether tx glom is enabled/disabled */
370 uint8 glom_mode; /* Glom mode - 0-copy mode, 1 - Multi-descriptor mode */
371 uint32 glomsize; /* Glom size limitation */
372 #endif
373 } dhd_bus_t;
374
375 /* clkstate */
376 #define CLK_NONE 0
377 #define CLK_SDONLY 1
378 #define CLK_PENDING 2 /* Not used yet */
379 #define CLK_AVAIL 3
380
381 #define DHD_NOPMU(dhd) (FALSE)
382
383 #ifdef DHD_DEBUG
384 static int qcount[NUMPRIO];
385 static int tx_packets[NUMPRIO];
386 #endif /* DHD_DEBUG */
387
388 /* Deferred transmit */
389 const uint dhd_deferred_tx = 1;
390
391 extern uint dhd_watchdog_ms;
392
393 extern void dhd_os_wd_timer(void *bus, uint wdtick);
394
395 /* Tx/Rx bounds */
396 uint dhd_txbound;
397 uint dhd_rxbound;
398 uint dhd_txminmax = DHD_TXMINMAX;
399
400 /* override the RAM size if possible */
401 #define DONGLE_MIN_RAMSIZE (128 *1024)
402 int dhd_dongle_ramsize;
403
404 uint dhd_doflow = TRUE;
405 uint dhd_dpcpoll = FALSE;
406
407 module_param(dhd_doflow, uint, 0644);
408 module_param(dhd_dpcpoll, uint, 0644);
409
410 static bool dhd_alignctl;
411
412 static bool sd1idle;
413
414 static bool retrydata;
415 #define RETRYCHAN(chan) (((chan) == SDPCM_EVENT_CHANNEL) || retrydata)
416
417 #if defined(SDIO_CRC_ERROR_FIX)
418 static uint watermark = 48;
419 static uint mesbusyctrl = 80;
420 #else
421 static const uint watermark = 8;
422 static const uint mesbusyctrl = 0;
423 #endif
424 static const uint firstread = DHD_FIRSTREAD;
425
426 #define HDATLEN (firstread - (SDPCM_HDRLEN))
427
428 /* Retry count for register access failures */
429 static const uint retry_limit = 2;
430
431 /* Force even SD lengths (some host controllers mess up on odd bytes) */
432 static bool forcealign;
433
434 #define ALIGNMENT 4
435
436 #if defined(OOB_INTR_ONLY) && defined(HW_OOB)
437 extern void bcmsdh_enable_hw_oob_intr(void *sdh, bool enable);
438 #endif
439
440 #if defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD)
441 #error OOB_INTR_ONLY is NOT working with SDIO_ISR_THREAD
442 #endif /* defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD) */
443 #define PKTALIGN(osh, p, len, align) \
444 do { \
445 uint datalign; \
446 datalign = (uintptr)PKTDATA((osh), (p)); \
447 datalign = ROUNDUP(datalign, (align)) - datalign; \
448 ASSERT(datalign < (align)); \
449 ASSERT(PKTLEN((osh), (p)) >= ((len) + datalign)); \
450 if (datalign) \
451 PKTPULL((osh), (p), datalign); \
452 PKTSETLEN((osh), (p), (len)); \
453 } while (0)
454
455 /* Limit on rounding up frames */
456 static const uint max_roundup = 512;
457
458 /* Try doing readahead */
459 static bool dhd_readahead;
460
461 /* To check if there's window offered */
462 #define DATAOK(bus) \
463 (((uint8)(bus->tx_max - bus->tx_seq) > 1) && \
464 (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0))
465
466 /* To check if there's window offered for ctrl frame */
467 #define TXCTLOK(bus) \
468 (((uint8)(bus->tx_max - bus->tx_seq) != 0) && \
469 (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0))
470
471 /* Number of pkts available in dongle for data RX */
472 #define DATABUFCNT(bus) \
473 ((uint8)(bus->tx_max - bus->tx_seq) - 1)
474
475 /* Macros to get register read/write status */
476 /* NOTE: these assume a local dhdsdio_bus_t *bus! */
477 #define R_SDREG(regvar, regaddr, retryvar) \
478 do { \
479 retryvar = 0; \
480 do { \
481 regvar = R_REG(bus->dhd->osh, regaddr); \
482 } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \
483 if (retryvar) { \
484 bus->regfails += (retryvar-1); \
485 if (retryvar > retry_limit) { \
486 DHD_ERROR(("%s: FAILED" #regvar "READ, LINE %d\n", \
487 __FUNCTION__, __LINE__)); \
488 regvar = 0; \
489 } \
490 } \
491 } while (0)
492
493 #define W_SDREG(regval, regaddr, retryvar) \
494 do { \
495 retryvar = 0; \
496 do { \
497 W_REG(bus->dhd->osh, regaddr, regval); \
498 } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \
499 if (retryvar) { \
500 bus->regfails += (retryvar-1); \
501 if (retryvar > retry_limit) \
502 DHD_ERROR(("%s: FAILED REGISTER WRITE, LINE %d\n", \
503 __FUNCTION__, __LINE__)); \
504 } \
505 } while (0)
506
507 #define BUS_WAKE(bus) \
508 do { \
509 bus->idlecount = 0; \
510 if ((bus)->sleeping) \
511 dhdsdio_bussleep((bus), FALSE); \
512 } while (0);
513
514 /*
515 * pktavail interrupts from dongle to host can be managed in 3 different ways
516 * whenever there is a packet available in dongle to transmit to host.
517 *
518 * Mode 0: Dongle writes the software host mailbox and host is interrupted.
519 * Mode 1: (sdiod core rev >= 4)
520 * Device sets a new bit in the intstatus whenever there is a packet
521 * available in fifo. Host can't clear this specific status bit until all the
522 * packets are read from the FIFO. No need to ack dongle intstatus.
523 * Mode 2: (sdiod core rev >= 4)
524 * Device sets a bit in the intstatus, and host acks this by writing
525 * one to this bit. Dongle won't generate anymore packet interrupts
526 * until host reads all the packets from the dongle and reads a zero to
527 * figure that there are no more packets. No need to disable host ints.
528 * Need to ack the intstatus.
529 */
530
531 #define SDIO_DEVICE_HMB_RXINT 0 /* default old way */
532 #define SDIO_DEVICE_RXDATAINT_MODE_0 1 /* from sdiod rev 4 */
533 #define SDIO_DEVICE_RXDATAINT_MODE_1 2 /* from sdiod rev 4 */
534
535
536 #define FRAME_AVAIL_MASK(bus) \
537 ((bus->rxint_mode == SDIO_DEVICE_HMB_RXINT) ? I_HMB_FRAME_IND : I_XMTDATA_AVAIL)
538
539 #define DHD_BUS SDIO_BUS
540
541 #define PKT_AVAILABLE(bus, intstatus) ((intstatus) & (FRAME_AVAIL_MASK(bus)))
542
543 #define HOSTINTMASK (I_HMB_SW_MASK | I_CHIPACTIVE)
544
545 #define GSPI_PR55150_BAILOUT
546
547 #ifdef SDTEST
548 static void dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq);
549 static void dhdsdio_sdtest_set(dhd_bus_t *bus, uint count);
550 #endif
551
552 #ifdef DHD_DEBUG
553 static int dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size);
554 static int dhd_serialconsole(dhd_bus_t *bus, bool get, bool enable, int *bcmerror);
555 #endif /* DHD_DEBUG */
556
557 static int dhdsdio_devcap_set(dhd_bus_t *bus, uint8 cap);
558 static int dhdsdio_download_state(dhd_bus_t *bus, bool enter);
559
560 static void dhdsdio_release(dhd_bus_t *bus, osl_t *osh);
561 static void dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh);
562 static void dhdsdio_disconnect(void *ptr);
563 static bool dhdsdio_chipmatch(uint16 chipid);
564 static bool dhdsdio_probe_attach(dhd_bus_t *bus, osl_t *osh, void *sdh,
565 void * regsva, uint16 devid);
566 static bool dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh);
567 static bool dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh);
568 static void dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation,
569 bool reset_flag);
570
571 static void dhd_dongle_setramsize(struct dhd_bus *bus, int mem_size);
572 static int dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags,
573 uint8 *buf, uint nbytes,
574 void *pkt, bcmsdh_cmplt_fn_t complete, void *handle);
575 static int dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags,
576 uint8 *buf, uint nbytes,
577 void *pkt, bcmsdh_cmplt_fn_t complete, void *handle);
578 #ifdef BCMSDIOH_TXGLOM
579 static void dhd_bcmsdh_glom_post(dhd_bus_t *bus, uint8 *frame, void *pkt, uint len);
580 static void dhd_bcmsdh_glom_clear(dhd_bus_t *bus);
581 #endif
582
583 static bool dhdsdio_download_firmware(dhd_bus_t *bus, osl_t *osh, void *sdh);
584 static int _dhdsdio_download_firmware(dhd_bus_t *bus);
585
586 static int dhdsdio_download_code_file(dhd_bus_t *bus, char *image_path);
587 static int dhdsdio_download_nvram(dhd_bus_t *bus);
588 #ifdef BCMEMBEDIMAGE
589 static int dhdsdio_download_code_array(dhd_bus_t *bus);
590 #endif
591 static int dhdsdio_bussleep(dhd_bus_t *bus, bool sleep);
592 static int dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok);
593 static uint8 dhdsdio_sleepcsr_get(dhd_bus_t *bus);
594
595 #ifdef WLMEDIA_HTSF
596 #include <htsf.h>
597 extern uint32 dhd_get_htsf(void *dhd, int ifidx);
598 #endif /* WLMEDIA_HTSF */
599
600 static void
dhd_overflow_war(struct dhd_bus * bus)601 dhd_overflow_war(struct dhd_bus *bus)
602 {
603 int err;
604 uint8 devctl, wm, mes;
605
606 /* See .ppt in PR for these recommended values */
607 if (bus->blocksize == 512) {
608 wm = OVERFLOW_BLKSZ512_WM;
609 mes = OVERFLOW_BLKSZ512_MES;
610 } else {
611 mes = bus->blocksize/4;
612 wm = bus->blocksize/4;
613 }
614
615
616 /* Update watermark */
617 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, wm, &err);
618
619 devctl = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
620 devctl |= SBSDIO_DEVCTL_F2WM_ENAB;
621 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
622
623 /* Update MES */
624 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL,
625 (mes | SBSDIO_MESBUSYCTRL_ENAB), &err);
626
627 DHD_INFO(("Apply overflow WAR: 0x%02x 0x%02x 0x%02x\n",
628 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err),
629 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, &err),
630 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL, &err)));
631 }
632
633 static void
dhd_dongle_setramsize(struct dhd_bus * bus,int mem_size)634 dhd_dongle_setramsize(struct dhd_bus *bus, int mem_size)
635 {
636 int32 min_size = DONGLE_MIN_RAMSIZE;
637 /* Restrict the ramsize to user specified limit */
638 DHD_ERROR(("user: Restrict the dongle ram size to %d, min accepted %d\n",
639 dhd_dongle_ramsize, min_size));
640 if ((dhd_dongle_ramsize > min_size) &&
641 (dhd_dongle_ramsize < (int32)bus->orig_ramsize))
642 bus->ramsize = dhd_dongle_ramsize;
643 }
644
645 static int
dhdsdio_set_siaddr_window(dhd_bus_t * bus,uint32 address)646 dhdsdio_set_siaddr_window(dhd_bus_t *bus, uint32 address)
647 {
648 int err = 0;
649 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW,
650 (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err);
651 if (!err)
652 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID,
653 (address >> 16) & SBSDIO_SBADDRMID_MASK, &err);
654 if (!err)
655 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH,
656 (address >> 24) & SBSDIO_SBADDRHIGH_MASK, &err);
657 return err;
658 }
659
660
661 #ifdef USE_OOB_GPIO1
662 static int
dhdsdio_oobwakeup_init(dhd_bus_t * bus)663 dhdsdio_oobwakeup_init(dhd_bus_t *bus)
664 {
665 uint32 val, addr, data;
666
667 bcmsdh_gpioouten(bus->sdh, GPIO_DEV_WAKEUP);
668
669 addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr);
670 data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data);
671
672 /* Set device for gpio1 wakeup */
673 bcmsdh_reg_write(bus->sdh, addr, 4, 2);
674 val = bcmsdh_reg_read(bus->sdh, data, 4);
675 val |= CC_CHIPCTRL2_GPIO1_WAKEUP;
676 bcmsdh_reg_write(bus->sdh, data, 4, val);
677
678 bus->_oobwakeup = TRUE;
679
680 return 0;
681 }
682 #endif /* USE_OOB_GPIO1 */
683
684 /*
685 * Query if FW is in SR mode
686 */
687 static bool
dhdsdio_sr_cap(dhd_bus_t * bus)688 dhdsdio_sr_cap(dhd_bus_t *bus)
689 {
690 bool cap = FALSE;
691 uint32 core_capext, addr, data;
692 if (bus->sih->chip == BCM4324_CHIP_ID) {
693 addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr);
694 data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data);
695 bcmsdh_reg_write(bus->sdh, addr, 4, 3);
696 core_capext = bcmsdh_reg_read(bus->sdh, data, 4);
697 } else if (bus->sih->chip == BCM4330_CHIP_ID) {
698 core_capext = FALSE;
699 } else if ((bus->sih->chip == BCM4335_CHIP_ID) ||
700 (bus->sih->chip == BCM4339_CHIP_ID) ||
701 (bus->sih->chip == BCM4350_CHIP_ID)) {
702 core_capext = TRUE;
703 } else {
704 core_capext = bcmsdh_reg_read(bus->sdh, CORE_CAPEXT_ADDR, 4);
705 core_capext = (core_capext & CORE_CAPEXT_SR_SUPPORTED_MASK);
706 }
707 if (!(core_capext))
708 return FALSE;
709
710 if (bus->sih->chip == BCM4324_CHIP_ID) {
711 /* FIX: Should change to query SR control register instead */
712 cap = TRUE;
713 } else if ((bus->sih->chip == BCM4335_CHIP_ID) ||
714 (bus->sih->chip == BCM4339_CHIP_ID)) {
715 uint32 enabval = 0;
716 addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr);
717 data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data);
718 bcmsdh_reg_write(bus->sdh, addr, 4, CC_PMUCC3);
719 enabval = bcmsdh_reg_read(bus->sdh, data, 4);
720
721 if ((bus->sih->chip == BCM4350_CHIP_ID) ||
722 0)
723 enabval &= CC_CHIPCTRL3_SR_ENG_ENABLE;
724
725
726 if (enabval)
727 cap = TRUE;
728 } else {
729 data = bcmsdh_reg_read(bus->sdh,
730 SI_ENUM_BASE + OFFSETOF(chipcregs_t, retention_ctl), 4);
731 if ((data & (RCTL_MACPHY_DISABLE_MASK | RCTL_LOGIC_DISABLE_MASK)) == 0)
732 cap = TRUE;
733 }
734
735 return cap;
736 }
737
738 static int
dhdsdio_srwar_init(dhd_bus_t * bus)739 dhdsdio_srwar_init(dhd_bus_t *bus)
740 {
741 bcmsdh_gpio_init(bus->sdh);
742
743 #ifdef USE_OOB_GPIO1
744 dhdsdio_oobwakeup_init(bus);
745 #endif
746
747
748 return 0;
749 }
750
751 static int
dhdsdio_sr_init(dhd_bus_t * bus)752 dhdsdio_sr_init(dhd_bus_t *bus)
753 {
754 uint8 val;
755 int err = 0;
756
757 if ((bus->sih->chip == BCM4334_CHIP_ID) && (bus->sih->chiprev == 2))
758 dhdsdio_srwar_init(bus);
759
760 val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, NULL);
761 val |= 1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT;
762 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL,
763 1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT, &err);
764 val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, NULL);
765
766 /* Add CMD14 Support */
767 dhdsdio_devcap_set(bus,
768 (SDIOD_CCCR_BRCM_CARDCAP_CMD14_SUPPORT | SDIOD_CCCR_BRCM_CARDCAP_CMD14_EXT));
769
770 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1,
771 SBSDIO_FUNC1_CHIPCLKCSR, SBSDIO_FORCE_HT, &err);
772
773 bus->_slpauto = dhd_slpauto ? TRUE : FALSE;
774
775 bus->_srenab = TRUE;
776
777 return 0;
778 }
779
780 /*
781 * FIX: Be sure KSO bit is enabled
782 * Currently, it's defaulting to 0 which should be 1.
783 */
784 static int
dhdsdio_clk_kso_init(dhd_bus_t * bus)785 dhdsdio_clk_kso_init(dhd_bus_t *bus)
786 {
787 uint8 val;
788 int err = 0;
789
790 /* set flag */
791 bus->kso = TRUE;
792
793 /*
794 * Enable KeepSdioOn (KSO) bit for normal operation
795 * Default is 0 (4334A0) so set it. Fixed in B0.
796 */
797 val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, NULL);
798 if (!(val & SBSDIO_FUNC1_SLEEPCSR_KSO_MASK)) {
799 val |= (SBSDIO_FUNC1_SLEEPCSR_KSO_EN << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT);
800 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, val, &err);
801 if (err)
802 DHD_ERROR(("%s: SBSDIO_FUNC1_SLEEPCSR err: 0x%x\n", __FUNCTION__, err));
803 }
804
805 return 0;
806 }
807
808 #define KSO_DBG(x)
809 #define KSO_WAIT_US 50
810 #define MAX_KSO_ATTEMPTS (PMU_MAX_TRANSITION_DLY/KSO_WAIT_US)
811 static int
dhdsdio_clk_kso_enab(dhd_bus_t * bus,bool on)812 dhdsdio_clk_kso_enab(dhd_bus_t *bus, bool on)
813 {
814 uint8 wr_val = 0, rd_val, cmp_val, bmask;
815 int err = 0;
816 int try_cnt = 0;
817
818 KSO_DBG(("%s> op:%s\n", __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR")));
819
820 wr_val |= (on << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT);
821
822 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, wr_val, &err);
823
824 if (on) {
825 cmp_val = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK | SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK;
826 bmask = cmp_val;
827
828 OSL_SLEEP(3);
829 } else {
830 /* Put device to sleep, turn off KSO */
831 cmp_val = 0;
832 bmask = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK;
833 }
834
835 do {
836 rd_val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, &err);
837 if (((rd_val & bmask) == cmp_val) && !err)
838 break;
839
840 KSO_DBG(("%s> KSO wr/rd retry:%d, ERR:%x \n", __FUNCTION__, try_cnt, err));
841 OSL_DELAY(KSO_WAIT_US);
842
843 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, wr_val, &err);
844 } while (try_cnt++ < MAX_KSO_ATTEMPTS);
845
846
847 if (try_cnt > 2)
848 KSO_DBG(("%s> op:%s, try_cnt:%d, rd_val:%x, ERR:%x \n",
849 __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"), try_cnt, rd_val, err));
850
851 if (try_cnt > MAX_KSO_ATTEMPTS) {
852 DHD_ERROR(("%s> op:%s, ERROR: try_cnt:%d, rd_val:%x, ERR:%x \n",
853 __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"), try_cnt, rd_val, err));
854 }
855 return err;
856 }
857
858 static int
dhdsdio_clk_kso_iovar(dhd_bus_t * bus,bool on)859 dhdsdio_clk_kso_iovar(dhd_bus_t *bus, bool on)
860 {
861 int err = 0;
862
863 if (on == FALSE) {
864
865 BUS_WAKE(bus);
866 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
867
868 DHD_ERROR(("%s: KSO disable clk: 0x%x\n", __FUNCTION__,
869 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
870 SBSDIO_FUNC1_CHIPCLKCSR, &err)));
871 dhdsdio_clk_kso_enab(bus, FALSE);
872 } else {
873 DHD_ERROR(("%s: KSO enable\n", __FUNCTION__));
874
875 /* Make sure we have SD bus access */
876 if (bus->clkstate == CLK_NONE) {
877 DHD_ERROR(("%s: Request SD clk\n", __FUNCTION__));
878 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
879 }
880
881 dhdsdio_clk_kso_enab(bus, TRUE);
882
883 DHD_ERROR(("%s: sleepcsr: 0x%x\n", __FUNCTION__,
884 dhdsdio_sleepcsr_get(bus)));
885 }
886
887 bus->kso = on;
888 BCM_REFERENCE(err);
889
890 return 0;
891 }
892
893 static uint8
dhdsdio_sleepcsr_get(dhd_bus_t * bus)894 dhdsdio_sleepcsr_get(dhd_bus_t *bus)
895 {
896 int err = 0;
897 uint8 val = 0;
898
899 val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, &err);
900 if (err)
901 DHD_TRACE(("Failed to read SLEEPCSR: %d\n", err));
902
903 return val;
904 }
905
906 uint8
dhdsdio_devcap_get(dhd_bus_t * bus)907 dhdsdio_devcap_get(dhd_bus_t *bus)
908 {
909 return bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_BRCM_CARDCAP, NULL);
910 }
911
912 static int
dhdsdio_devcap_set(dhd_bus_t * bus,uint8 cap)913 dhdsdio_devcap_set(dhd_bus_t *bus, uint8 cap)
914 {
915 int err = 0;
916
917 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_BRCM_CARDCAP, cap, &err);
918 if (err)
919 DHD_ERROR(("%s: devcap set err: 0x%x\n", __FUNCTION__, err));
920
921 return 0;
922 }
923
924 static int
dhdsdio_clk_devsleep_iovar(dhd_bus_t * bus,bool on)925 dhdsdio_clk_devsleep_iovar(dhd_bus_t *bus, bool on)
926 {
927 int err = 0, retry;
928 uint8 val;
929
930 retry = 0;
931 if (on == TRUE) {
932 /* Enter Sleep */
933
934 /* Be sure we request clk before going to sleep
935 * so we can wake-up with clk request already set
936 * else device can go back to sleep immediately
937 */
938 if (!SLPAUTO_ENAB(bus))
939 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
940 else {
941 val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
942 if ((val & SBSDIO_CSR_MASK) == 0) {
943 DHD_ERROR(("%s: No clock before enter sleep:0x%x\n",
944 __FUNCTION__, val));
945
946 /* Reset clock request */
947 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
948 SBSDIO_ALP_AVAIL_REQ, &err);
949 DHD_ERROR(("%s: clock before sleep:0x%x\n", __FUNCTION__,
950 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
951 SBSDIO_FUNC1_CHIPCLKCSR, &err)));
952 }
953 }
954
955 DHD_TRACE(("%s: clk before sleep: 0x%x\n", __FUNCTION__,
956 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
957 SBSDIO_FUNC1_CHIPCLKCSR, &err)));
958 #ifdef USE_CMD14
959 err = bcmsdh_sleep(bus->sdh, TRUE);
960 #else
961 err = dhdsdio_clk_kso_enab(bus, FALSE);
962 if (OOB_WAKEUP_ENAB(bus))
963 {
964 err = bcmsdh_gpioout(bus->sdh, GPIO_DEV_WAKEUP, FALSE); /* GPIO_1 is off */
965 }
966 #endif /* USE_CMD14 */
967 } else {
968 /* Exit Sleep */
969 /* Make sure we have SD bus access */
970 if (bus->clkstate == CLK_NONE) {
971 DHD_TRACE(("%s: Request SD clk\n", __FUNCTION__));
972 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
973 }
974
975 if ((bus->sih->chip == BCM4334_CHIP_ID) && (bus->sih->chiprev == 2)) {
976 SPINWAIT_SLEEP(sdioh_spinwait_sleep,
977 (bcmsdh_gpioin(bus->sdh, GPIO_DEV_SRSTATE) != TRUE),
978 GPIO_DEV_SRSTATE_TIMEOUT);
979
980 if (bcmsdh_gpioin(bus->sdh, GPIO_DEV_SRSTATE) == FALSE) {
981 DHD_ERROR(("ERROR: GPIO_DEV_SRSTATE still low!\n"));
982 }
983 }
984 #ifdef USE_CMD14
985 err = bcmsdh_sleep(bus->sdh, FALSE);
986 if (SLPAUTO_ENAB(bus) && (err != 0)) {
987 OSL_DELAY(10000);
988 DHD_TRACE(("%s: Resync device sleep\n", __FUNCTION__));
989
990 /* Toggle sleep to resync with host and device */
991 err = bcmsdh_sleep(bus->sdh, TRUE);
992 OSL_DELAY(10000);
993 err = bcmsdh_sleep(bus->sdh, FALSE);
994
995 if (err) {
996 OSL_DELAY(10000);
997 DHD_ERROR(("%s: CMD14 exit failed again!\n", __FUNCTION__));
998
999 /* Toggle sleep to resync with host and device */
1000 err = bcmsdh_sleep(bus->sdh, TRUE);
1001 OSL_DELAY(10000);
1002 err = bcmsdh_sleep(bus->sdh, FALSE);
1003 if (err) {
1004 DHD_ERROR(("%s: CMD14 exit failed twice!\n", __FUNCTION__));
1005 DHD_ERROR(("%s: FATAL: Device non-response!\n",
1006 __FUNCTION__));
1007 err = 0;
1008 }
1009 }
1010 }
1011 #else
1012 if (OOB_WAKEUP_ENAB(bus))
1013 {
1014 err = bcmsdh_gpioout(bus->sdh, GPIO_DEV_WAKEUP, TRUE); /* GPIO_1 is on */
1015 }
1016 do {
1017 err = dhdsdio_clk_kso_enab(bus, TRUE);
1018 if (err)
1019 OSL_SLEEP(10);
1020 } while ((err != 0) && (++retry < 3));
1021
1022 if (err != 0) {
1023 DHD_ERROR(("ERROR: kso set failed retry: %d\n", retry));
1024 err = 0; /* continue anyway */
1025 }
1026 #endif /* !USE_CMD14 */
1027
1028 if (err == 0) {
1029 uint8 csr;
1030
1031 /* Wait for device ready during transition to wake-up */
1032 SPINWAIT_SLEEP(sdioh_spinwait_sleep,
1033 (((csr = dhdsdio_sleepcsr_get(bus)) &
1034 SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK) !=
1035 (SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK)), (20000));
1036
1037 DHD_TRACE(("%s: ExitSleep sleepcsr: 0x%x\n", __FUNCTION__, csr));
1038
1039 if (!(csr & SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK)) {
1040 DHD_ERROR(("%s:ERROR: ExitSleep device NOT Ready! 0x%x\n",
1041 __FUNCTION__, csr));
1042 err = BCME_NODEVICE;
1043 }
1044
1045 SPINWAIT_SLEEP(sdioh_spinwait_sleep,
1046 (((csr = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
1047 SBSDIO_FUNC1_CHIPCLKCSR, &err)) & SBSDIO_HT_AVAIL) !=
1048 (SBSDIO_HT_AVAIL)), (10000));
1049
1050 }
1051 }
1052
1053 /* Update if successful */
1054 if (err == 0)
1055 bus->kso = on ? FALSE : TRUE;
1056 else {
1057 DHD_ERROR(("%s: Sleep request failed: on:%d err:%d\n", __FUNCTION__, on, err));
1058 if (!on && retry > 2)
1059 bus->kso = TRUE;
1060 }
1061
1062 return err;
1063 }
1064
1065 /* Turn backplane clock on or off */
1066 static int
dhdsdio_htclk(dhd_bus_t * bus,bool on,bool pendok)1067 dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok)
1068 {
1069 #define HT_AVAIL_ERROR_MAX 10
1070 static int ht_avail_error = 0;
1071 int err;
1072 uint8 clkctl, clkreq, devctl;
1073 bcmsdh_info_t *sdh;
1074
1075 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1076
1077 clkctl = 0;
1078 sdh = bus->sdh;
1079
1080
1081 if (!KSO_ENAB(bus))
1082 return BCME_OK;
1083
1084 if (SLPAUTO_ENAB(bus)) {
1085 bus->clkstate = (on ? CLK_AVAIL : CLK_SDONLY);
1086 return BCME_OK;
1087 }
1088
1089 if (on) {
1090 /* Request HT Avail */
1091 clkreq = bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ;
1092
1093
1094
1095 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
1096 if (err) {
1097 ht_avail_error++;
1098 if (ht_avail_error < HT_AVAIL_ERROR_MAX) {
1099 DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err));
1100 }
1101
1102 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
1103 else if (ht_avail_error == HT_AVAIL_ERROR_MAX) {
1104 dhd_os_send_hang_message(bus->dhd);
1105 }
1106 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) */
1107 return BCME_ERROR;
1108 } else {
1109 ht_avail_error = 0;
1110 }
1111
1112
1113 /* Check current status */
1114 clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
1115 if (err) {
1116 DHD_ERROR(("%s: HT Avail read error: %d\n", __FUNCTION__, err));
1117 return BCME_ERROR;
1118 }
1119
1120 #if !defined(OOB_INTR_ONLY)
1121 /* Go to pending and await interrupt if appropriate */
1122 if (!SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) {
1123 /* Allow only clock-available interrupt */
1124 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
1125 if (err) {
1126 DHD_ERROR(("%s: Devctl access error setting CA: %d\n",
1127 __FUNCTION__, err));
1128 return BCME_ERROR;
1129 }
1130
1131 devctl |= SBSDIO_DEVCTL_CA_INT_ONLY;
1132 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
1133 DHD_INFO(("CLKCTL: set PENDING\n"));
1134 bus->clkstate = CLK_PENDING;
1135 return BCME_OK;
1136 } else
1137 #endif /* !defined (OOB_INTR_ONLY) */
1138 {
1139 if (bus->clkstate == CLK_PENDING) {
1140 /* Cancel CA-only interrupt filter */
1141 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
1142 devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
1143 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
1144 }
1145 }
1146
1147 /* Otherwise, wait here (polling) for HT Avail */
1148 if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
1149 SPINWAIT_SLEEP(sdioh_spinwait_sleep,
1150 ((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
1151 SBSDIO_FUNC1_CHIPCLKCSR, &err)),
1152 !SBSDIO_CLKAV(clkctl, bus->alp_only)), PMU_MAX_TRANSITION_DLY);
1153 }
1154 if (err) {
1155 DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err));
1156 return BCME_ERROR;
1157 }
1158 if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
1159 DHD_ERROR(("%s: HT Avail timeout (%d): clkctl 0x%02x\n",
1160 __FUNCTION__, PMU_MAX_TRANSITION_DLY, clkctl));
1161 return BCME_ERROR;
1162 }
1163
1164 /* Mark clock available */
1165 bus->clkstate = CLK_AVAIL;
1166 DHD_INFO(("CLKCTL: turned ON\n"));
1167
1168 #if defined(DHD_DEBUG)
1169 if (bus->alp_only == TRUE) {
1170 #if !defined(BCMLXSDMMC)
1171 if (!SBSDIO_ALPONLY(clkctl)) {
1172 DHD_ERROR(("%s: HT Clock, when ALP Only\n", __FUNCTION__));
1173 }
1174 #endif /* !defined(BCMLXSDMMC) */
1175 } else {
1176 if (SBSDIO_ALPONLY(clkctl)) {
1177 DHD_ERROR(("%s: HT Clock should be on.\n", __FUNCTION__));
1178 }
1179 }
1180 #endif /* defined (DHD_DEBUG) */
1181
1182 bus->activity = TRUE;
1183 #ifdef DHD_USE_IDLECOUNT
1184 bus->idlecount = 0;
1185 #endif /* DHD_USE_IDLECOUNT */
1186 } else {
1187 clkreq = 0;
1188
1189 if (bus->clkstate == CLK_PENDING) {
1190 /* Cancel CA-only interrupt filter */
1191 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
1192 devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
1193 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
1194 }
1195
1196 bus->clkstate = CLK_SDONLY;
1197 if (!SR_ENAB(bus)) {
1198 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
1199 DHD_INFO(("CLKCTL: turned OFF\n"));
1200 if (err) {
1201 DHD_ERROR(("%s: Failed access turning clock off: %d\n",
1202 __FUNCTION__, err));
1203 return BCME_ERROR;
1204 }
1205 }
1206 }
1207 return BCME_OK;
1208 }
1209
1210 /* Change idle/active SD state */
1211 static int
dhdsdio_sdclk(dhd_bus_t * bus,bool on)1212 dhdsdio_sdclk(dhd_bus_t *bus, bool on)
1213 {
1214 int err;
1215 int32 iovalue;
1216
1217 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1218
1219 if (on) {
1220 if (bus->idleclock == DHD_IDLE_STOP) {
1221 /* Turn on clock and restore mode */
1222 iovalue = 1;
1223 err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0,
1224 &iovalue, sizeof(iovalue), TRUE);
1225 if (err) {
1226 DHD_ERROR(("%s: error enabling sd_clock: %d\n",
1227 __FUNCTION__, err));
1228 return BCME_ERROR;
1229 }
1230
1231 iovalue = bus->sd_mode;
1232 err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
1233 &iovalue, sizeof(iovalue), TRUE);
1234 if (err) {
1235 DHD_ERROR(("%s: error changing sd_mode: %d\n",
1236 __FUNCTION__, err));
1237 return BCME_ERROR;
1238 }
1239 } else if (bus->idleclock != DHD_IDLE_ACTIVE) {
1240 /* Restore clock speed */
1241 iovalue = bus->sd_divisor;
1242 err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
1243 &iovalue, sizeof(iovalue), TRUE);
1244 if (err) {
1245 DHD_ERROR(("%s: error restoring sd_divisor: %d\n",
1246 __FUNCTION__, err));
1247 return BCME_ERROR;
1248 }
1249 }
1250 bus->clkstate = CLK_SDONLY;
1251 } else {
1252 /* Stop or slow the SD clock itself */
1253 if ((bus->sd_divisor == -1) || (bus->sd_mode == -1)) {
1254 DHD_TRACE(("%s: can't idle clock, divisor %d mode %d\n",
1255 __FUNCTION__, bus->sd_divisor, bus->sd_mode));
1256 return BCME_ERROR;
1257 }
1258 if (bus->idleclock == DHD_IDLE_STOP) {
1259 if (sd1idle) {
1260 /* Change to SD1 mode and turn off clock */
1261 iovalue = 1;
1262 err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
1263 &iovalue, sizeof(iovalue), TRUE);
1264 if (err) {
1265 DHD_ERROR(("%s: error changing sd_clock: %d\n",
1266 __FUNCTION__, err));
1267 return BCME_ERROR;
1268 }
1269 }
1270
1271 iovalue = 0;
1272 err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0,
1273 &iovalue, sizeof(iovalue), TRUE);
1274 if (err) {
1275 DHD_ERROR(("%s: error disabling sd_clock: %d\n",
1276 __FUNCTION__, err));
1277 return BCME_ERROR;
1278 }
1279 } else if (bus->idleclock != DHD_IDLE_ACTIVE) {
1280 /* Set divisor to idle value */
1281 iovalue = bus->idleclock;
1282 err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
1283 &iovalue, sizeof(iovalue), TRUE);
1284 if (err) {
1285 DHD_ERROR(("%s: error changing sd_divisor: %d\n",
1286 __FUNCTION__, err));
1287 return BCME_ERROR;
1288 }
1289 }
1290 bus->clkstate = CLK_NONE;
1291 }
1292
1293 return BCME_OK;
1294 }
1295
1296 /* Transition SD and backplane clock readiness */
1297 static int
dhdsdio_clkctl(dhd_bus_t * bus,uint target,bool pendok)1298 dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok)
1299 {
1300 int ret = BCME_OK;
1301 #ifdef DHD_DEBUG
1302 uint oldstate = bus->clkstate;
1303 #endif /* DHD_DEBUG */
1304
1305 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1306
1307 /* Early exit if we're already there */
1308 if (bus->clkstate == target) {
1309 if (target == CLK_AVAIL) {
1310 dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
1311 bus->activity = TRUE;
1312 #ifdef DHD_USE_IDLECOUNT
1313 bus->idlecount = 0;
1314 #endif /* DHD_USE_IDLECOUNT */
1315 }
1316 return ret;
1317 }
1318
1319 switch (target) {
1320 case CLK_AVAIL:
1321 /* Make sure SD clock is available */
1322 if (bus->clkstate == CLK_NONE)
1323 dhdsdio_sdclk(bus, TRUE);
1324 /* Now request HT Avail on the backplane */
1325 ret = dhdsdio_htclk(bus, TRUE, pendok);
1326 if (ret == BCME_OK) {
1327 dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
1328 bus->activity = TRUE;
1329 #ifdef DHD_USE_IDLECOUNT
1330 bus->idlecount = 0;
1331 #endif /* DHD_USE_IDLECOUNT */
1332 }
1333 break;
1334
1335 case CLK_SDONLY:
1336 /* Remove HT request, or bring up SD clock */
1337 if (bus->clkstate == CLK_NONE)
1338 ret = dhdsdio_sdclk(bus, TRUE);
1339 else if (bus->clkstate == CLK_AVAIL)
1340 ret = dhdsdio_htclk(bus, FALSE, FALSE);
1341 else
1342 DHD_ERROR(("dhdsdio_clkctl: request for %d -> %d\n",
1343 bus->clkstate, target));
1344 if (ret == BCME_OK) {
1345 dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
1346 }
1347 break;
1348
1349 case CLK_NONE:
1350 /* Make sure to remove HT request */
1351 if (bus->clkstate == CLK_AVAIL)
1352 ret = dhdsdio_htclk(bus, FALSE, FALSE);
1353 /* Now remove the SD clock */
1354 ret = dhdsdio_sdclk(bus, FALSE);
1355 #ifdef DHD_DEBUG
1356 if (dhd_console_ms == 0)
1357 #endif /* DHD_DEBUG */
1358 if (bus->poll == 0)
1359 dhd_os_wd_timer(bus->dhd, 0);
1360 break;
1361 }
1362 #ifdef DHD_DEBUG
1363 DHD_INFO(("dhdsdio_clkctl: %d -> %d\n", oldstate, bus->clkstate));
1364 #endif /* DHD_DEBUG */
1365
1366 return ret;
1367 }
1368
1369 static int
dhdsdio_bussleep(dhd_bus_t * bus,bool sleep)1370 dhdsdio_bussleep(dhd_bus_t *bus, bool sleep)
1371 {
1372 int err = 0;
1373 bcmsdh_info_t *sdh = bus->sdh;
1374 sdpcmd_regs_t *regs = bus->regs;
1375 uint retries = 0;
1376
1377 DHD_INFO(("dhdsdio_bussleep: request %s (currently %s)\n",
1378 (sleep ? "SLEEP" : "WAKE"),
1379 (bus->sleeping ? "SLEEP" : "WAKE")));
1380
1381 /* Done if we're already in the requested state */
1382 if (sleep == bus->sleeping)
1383 return BCME_OK;
1384
1385 /* Going to sleep: set the alarm and turn off the lights... */
1386 if (sleep) {
1387 /* Don't sleep if something is pending */
1388 if (bus->dpc_sched || bus->rxskip || pktq_len(&bus->txq))
1389 return BCME_BUSY;
1390
1391
1392 if (!SLPAUTO_ENAB(bus)) {
1393 /* Disable SDIO interrupts (no longer interested) */
1394 bcmsdh_intr_disable(bus->sdh);
1395
1396 /* Make sure the controller has the bus up */
1397 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
1398
1399 /* Tell device to start using OOB wakeup */
1400 W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries);
1401 if (retries > retry_limit)
1402 DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
1403
1404 /* Turn off our contribution to the HT clock request */
1405 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
1406
1407 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
1408 SBSDIO_FORCE_HW_CLKREQ_OFF, NULL);
1409
1410 /* Isolate the bus */
1411 if (bus->sih->chip != BCM4329_CHIP_ID &&
1412 bus->sih->chip != BCM4319_CHIP_ID) {
1413 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL,
1414 SBSDIO_DEVCTL_PADS_ISO, NULL);
1415 }
1416 } else {
1417 /* Leave interrupts enabled since device can exit sleep and
1418 * interrupt host
1419 */
1420 err = dhdsdio_clk_devsleep_iovar(bus, TRUE /* sleep */);
1421 }
1422
1423 /* Change state */
1424 bus->sleeping = TRUE;
1425
1426 } else {
1427 /* Waking up: bus power up is ok, set local state */
1428
1429 if (!SLPAUTO_ENAB(bus)) {
1430 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0, &err);
1431
1432 /* Force pad isolation off if possible (in case power never toggled) */
1433 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, 0, NULL);
1434
1435
1436 /* Make sure the controller has the bus up */
1437 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
1438
1439 /* Send misc interrupt to indicate OOB not needed */
1440 W_SDREG(0, ®s->tosbmailboxdata, retries);
1441 if (retries <= retry_limit)
1442 W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries);
1443
1444 if (retries > retry_limit)
1445 DHD_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n"));
1446
1447 /* Make sure we have SD bus access */
1448 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
1449
1450 /* Enable interrupts again */
1451 if (bus->intr && (bus->dhd->busstate == DHD_BUS_DATA)) {
1452 bus->intdis = FALSE;
1453 bcmsdh_intr_enable(bus->sdh);
1454 }
1455 } else {
1456 err = dhdsdio_clk_devsleep_iovar(bus, FALSE /* wake */);
1457 }
1458
1459 if (err == 0) {
1460 /* Change state */
1461 bus->sleeping = FALSE;
1462 }
1463 }
1464
1465 return err;
1466 }
1467
1468
1469 #if defined(OOB_INTR_ONLY)
1470 void
dhd_enable_oob_intr(struct dhd_bus * bus,bool enable)1471 dhd_enable_oob_intr(struct dhd_bus *bus, bool enable)
1472 {
1473 #if defined(HW_OOB)
1474 bcmsdh_enable_hw_oob_intr(bus->sdh, enable);
1475 #else
1476 sdpcmd_regs_t *regs = bus->regs;
1477 uint retries = 0;
1478
1479 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
1480 if (enable == TRUE) {
1481
1482 /* Tell device to start using OOB wakeup */
1483 W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries);
1484 if (retries > retry_limit)
1485 DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
1486
1487 } else {
1488 /* Send misc interrupt to indicate OOB not needed */
1489 W_SDREG(0, ®s->tosbmailboxdata, retries);
1490 if (retries <= retry_limit)
1491 W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries);
1492 }
1493
1494 /* Turn off our contribution to the HT clock request */
1495 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
1496 #endif /* !defined(HW_OOB) */
1497 }
1498 #endif
1499
1500 #ifdef DHDTCPACK_SUPPRESS
1501 extern bool dhd_use_tcpack_suppress;
1502
1503 /* Please be sure this function is called under dhd_os_tcpacklock() */
dhd_onoff_tcpack_sup(void * pub,bool on)1504 void dhd_onoff_tcpack_sup(void *pub, bool on)
1505 {
1506 dhd_pub_t *dhdp = (dhd_pub_t *)pub;
1507
1508 if (dhd_use_tcpack_suppress != on) {
1509
1510 DHD_ERROR(("dhd_onoff_tcpack_sup: %d -> %d\n", dhd_use_tcpack_suppress, on));
1511 dhd_use_tcpack_suppress = on;
1512 dhdp->tcp_ack_info_cnt = 0;
1513 bzero(dhdp->tcp_ack_info_tbl, sizeof(struct tcp_ack_info)*MAXTCPSTREAMS);
1514
1515 } else
1516 DHD_ERROR(("dhd_onoff_tcpack_sup: alread %d\n", on));
1517
1518 return;
1519 }
1520
dhd_tcpack_check_xmit(dhd_pub_t * dhdp,void * pkt)1521 inline void dhd_tcpack_check_xmit(dhd_pub_t *dhdp, void *pkt)
1522 {
1523 uint8 i;
1524 tcp_ack_info_t *tcp_ack_info = NULL;
1525 int tbl_cnt;
1526
1527 dhd_os_tcpacklock(dhdp);
1528 tbl_cnt = dhdp->tcp_ack_info_cnt;
1529 for (i = 0; i < tbl_cnt; i++) {
1530 tcp_ack_info = &dhdp->tcp_ack_info_tbl[i];
1531 if (tcp_ack_info->p_tcpackinqueue == pkt) {
1532 /* This pkt is being transmitted so remove the tcp_ack_info of it.
1533 * compact the array unless the last element,
1534 * then the pkt's array is removed.
1535 */
1536 if (i < tbl_cnt-1) {
1537 memmove(&dhdp->tcp_ack_info_tbl[i],
1538 &dhdp->tcp_ack_info_tbl[i+1],
1539 sizeof(struct tcp_ack_info)*(tbl_cnt - (i+1)));
1540 }
1541 bzero(&dhdp->tcp_ack_info_tbl[tbl_cnt-1], sizeof(struct tcp_ack_info));
1542 if (--dhdp->tcp_ack_info_cnt < 0) {
1543 DHD_ERROR(("dhdsdio_sendfromq:(ERROR) tcp_ack_info_cnt %d"
1544 " Stop using tcpack_suppress\n", dhdp->tcp_ack_info_cnt));
1545 dhd_onoff_tcpack_sup(dhdp, FALSE);
1546 }
1547 break;
1548 }
1549 }
1550 dhd_os_tcpackunlock(dhdp);
1551 }
1552
1553 bool
dhd_tcpack_suppress(dhd_pub_t * dhdp,void * pkt)1554 dhd_tcpack_suppress(dhd_pub_t *dhdp, void *pkt)
1555 {
1556 uint8 *eh_header;
1557 uint16 eh_type;
1558 uint8 *ip_header;
1559 uint8 *tcp_header;
1560 uint32 ip_hdr_len;
1561 uint32 cur_framelen;
1562 uint8 bdc_hdr_len = BDC_HEADER_LEN;
1563 uint8 wlfc_hdr_len = 0;
1564 uint8 *data = PKTDATA(dhdp->osh, pkt);
1565 cur_framelen = PKTLEN(dhdp->osh, pkt);
1566
1567 #ifdef PROP_TXSTATUS
1568 /* In this case, BDC header is not pushed in dhd_sendpkt() */
1569 if (dhdp->wlfc_state) {
1570 bdc_hdr_len = 0;
1571 wlfc_hdr_len = 8;
1572 }
1573 #endif
1574 if (cur_framelen < bdc_hdr_len + ETHER_HDR_LEN) {
1575 DHD_TRACE(("dhd_tcpack_suppress: Too short packet length %d\n", cur_framelen));
1576 return FALSE;
1577 }
1578
1579 /* Get rid of BDC header */
1580 eh_header = data + bdc_hdr_len;
1581 cur_framelen -= bdc_hdr_len;
1582 eh_type = eh_header[12] << 8 | eh_header[13];
1583
1584 if (eh_type != ETHER_TYPE_IP) {
1585 DHD_TRACE(("dhd_tcpack_suppress: Not a IP packet 0x%x\n", eh_type));
1586 return FALSE;
1587 }
1588
1589 DHD_TRACE(("dhd_tcpack_suppress: IP pkt! 0x%x\n", eh_type));
1590
1591 ip_header = eh_header + ETHER_HDR_LEN;
1592 cur_framelen -= ETHER_HDR_LEN;
1593 ip_hdr_len = 4 * (ip_header[0] & 0x0f);
1594
1595 if ((ip_header[0] & 0xf0) != 0x40) {
1596 DHD_TRACE(("dhd_tcpack_suppress: Not IPv4!\n"));
1597 return FALSE;
1598 }
1599
1600 if (cur_framelen < ip_hdr_len) {
1601 DHD_ERROR(("dhd_tcpack_suppress: IP packet length %d wrong!\n", cur_framelen));
1602 return FALSE;
1603 }
1604
1605 /* not tcp */
1606 if (ip_header[9] != 0x06) {
1607 DHD_TRACE(("dhd_tcpack_suppress: Not a TCP packet 0x%x\n", ip_header[9]));
1608 return FALSE;
1609 }
1610
1611 DHD_TRACE(("dhd_tcpack_suppress: TCP pkt!\n"));
1612
1613 tcp_header = ip_header + ip_hdr_len;
1614
1615 /* is it an ack ? */
1616 if (tcp_header[13] == 0x10) {
1617 #if defined(DHD_DEBUG)
1618 uint32 tcp_seq_num = tcp_header[4] << 24 | tcp_header[5] << 16 |
1619 tcp_header[6] << 8 | tcp_header[7];
1620 #endif
1621 uint32 tcp_ack_num = tcp_header[8] << 24 | tcp_header[9] << 16 |
1622 tcp_header[10] << 8 | tcp_header[11];
1623 uint16 ip_tcp_ttllen = (ip_header[3] & 0xff) + (ip_header[2] << 8);
1624 uint32 tcp_hdr_len = 4*((tcp_header[12] & 0xf0) >> 4);
1625 DHD_TRACE(("dhd_tcpack_suppress: TCP ACK seq %ud ack %ud\n",
1626 tcp_seq_num, tcp_ack_num));
1627
1628
1629 /* zero length ? */
1630 if (ip_tcp_ttllen == ip_hdr_len + tcp_hdr_len) {
1631 int i;
1632 tcp_ack_info_t *tcp_ack_info = NULL;
1633 DHD_TRACE(("dhd_tcpack_suppress: TCP ACK zero length\n"));
1634 /* Look for tcp_ack_info that has the same
1635 * ip src/dst addrs and tcp src/dst ports
1636 */
1637 dhd_os_tcpacklock(dhdp);
1638 for (i = 0; i < dhdp->tcp_ack_info_cnt; i++) {
1639 if (dhdp->tcp_ack_info_tbl[i].p_tcpackinqueue &&
1640 !memcmp(&ip_header[12], dhdp->tcp_ack_info_tbl[i].ipaddrs, 8) &&
1641 !memcmp(tcp_header, dhdp->tcp_ack_info_tbl[i].tcpports, 4)) {
1642 tcp_ack_info = &dhdp->tcp_ack_info_tbl[i];
1643 break;
1644 }
1645 }
1646
1647 if (i == dhdp->tcp_ack_info_cnt && i < MAXTCPSTREAMS)
1648 tcp_ack_info = &dhdp->tcp_ack_info_tbl[dhdp->tcp_ack_info_cnt++];
1649
1650 if (!tcp_ack_info) {
1651 DHD_TRACE(("dhd_tcpack_suppress: No empty tcp ack info"
1652 "%d %d %d %d, %d %d %d %d\n",
1653 tcp_header[0], tcp_header[1], tcp_header[2], tcp_header[3],
1654 dhdp->tcp_ack_info_tbl[i].tcpports[0],
1655 dhdp->tcp_ack_info_tbl[i].tcpports[1],
1656 dhdp->tcp_ack_info_tbl[i].tcpports[2],
1657 dhdp->tcp_ack_info_tbl[i].tcpports[3]));
1658 dhd_os_tcpackunlock(dhdp);
1659 return FALSE;
1660 }
1661
1662 if (tcp_ack_info->p_tcpackinqueue) {
1663 if (tcp_ack_num > tcp_ack_info->tcpack_number) {
1664 void *prevpkt = tcp_ack_info->p_tcpackinqueue;
1665 uint8 pushed_len = SDPCM_HDRLEN +
1666 (BDC_HEADER_LEN - bdc_hdr_len) + wlfc_hdr_len;
1667 #ifdef PROP_TXSTATUS
1668 /* In case the prev pkt is delayenqueued
1669 * but not delayedequeued yet, it may not have
1670 * any additional header yet.
1671 */
1672 if (dhdp->wlfc_state && (PKTLEN(dhdp->osh, prevpkt) ==
1673 tcp_ack_info->ip_tcp_ttllen + ETHER_HDR_LEN))
1674 pushed_len = 0;
1675 #endif
1676 if ((ip_tcp_ttllen == tcp_ack_info->ip_tcp_ttllen) &&
1677 (PKTLEN(dhdp->osh, pkt) ==
1678 PKTLEN(dhdp->osh, prevpkt) - pushed_len)) {
1679 bcopy(PKTDATA(dhdp->osh, pkt),
1680 PKTDATA(dhdp->osh, prevpkt) + pushed_len,
1681 PKTLEN(dhdp->osh, pkt));
1682 PKTFREE(dhdp->osh, pkt, FALSE);
1683 DHD_TRACE(("dhd_tcpack_suppress: pkt 0x%p"
1684 " TCP ACK replace %ud -> %ud\n", prevpkt,
1685 tcp_ack_info->tcpack_number, tcp_ack_num));
1686 tcp_ack_info->tcpack_number = tcp_ack_num;
1687 dhd_os_tcpackunlock(dhdp);
1688 return TRUE;
1689 } else
1690 DHD_TRACE(("dhd_tcpack_suppress: len mismatch"
1691 " %d(%d) %d(%d)\n",
1692 PKTLEN(dhdp->osh, pkt), ip_tcp_ttllen,
1693 PKTLEN(dhdp->osh, prevpkt),
1694 tcp_ack_info->ip_tcp_ttllen));
1695 } else {
1696 #ifdef TCPACK_TEST
1697 void *prevpkt = tcp_ack_info->p_tcpackinqueue;
1698 #endif
1699 DHD_TRACE(("dhd_tcpack_suppress: TCP ACK number reverse"
1700 " prev %ud (0x%p) new %ud (0x%p)\n",
1701 tcp_ack_info->tcpack_number,
1702 tcp_ack_info->p_tcpackinqueue,
1703 tcp_ack_num, pkt));
1704 #ifdef TCPACK_TEST
1705 if (PKTLEN(dhdp->osh, pkt) == PKTLEN(dhdp->osh, prevpkt)) {
1706 PKTFREE(dhdp->osh, pkt, FALSE);
1707 dhd_os_tcpackunlock(dhdp);
1708 return TRUE;
1709 }
1710 #endif
1711 }
1712 } else {
1713 tcp_ack_info->p_tcpackinqueue = pkt;
1714 tcp_ack_info->tcpack_number = tcp_ack_num;
1715 tcp_ack_info->ip_tcp_ttllen = ip_tcp_ttllen;
1716 bcopy(&ip_header[12], tcp_ack_info->ipaddrs, 8);
1717 bcopy(tcp_header, tcp_ack_info->tcpports, 4);
1718 }
1719 dhd_os_tcpackunlock(dhdp);
1720 } else
1721 DHD_TRACE(("dhd_tcpack_suppress: TCP ACK with DATA len %d\n",
1722 ip_tcp_ttllen - ip_hdr_len - tcp_hdr_len));
1723 }
1724 return FALSE;
1725 }
1726 #endif /* DHDTCPACK_SUPPRESS */
1727
1728 /* Writes a HW/SW header into the packet and sends it. */
1729 /* Assumes: (a) header space already there, (b) caller holds lock */
1730 static int
dhdsdio_txpkt(dhd_bus_t * bus,void * pkt,uint chan,bool free_pkt,bool queue_only)1731 dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt, bool queue_only)
1732 {
1733 int ret;
1734 osl_t *osh;
1735 uint8 *frame;
1736 uint16 len, pad1 = 0, act_len = 0;
1737 uint32 swheader;
1738 uint retries = 0;
1739 uint32 real_pad = 0;
1740 bcmsdh_info_t *sdh;
1741 void *new;
1742 int i;
1743 int pkt_cnt;
1744 #ifdef BCMSDIOH_TXGLOM
1745 uint8 *frame_tmp;
1746 #endif
1747 #ifdef WLMEDIA_HTSF
1748 char *p;
1749 htsfts_t *htsf_ts;
1750 #endif
1751
1752 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1753
1754 sdh = bus->sdh;
1755 osh = bus->dhd->osh;
1756
1757 #ifdef DHDTCPACK_SUPPRESS
1758 if (dhd_use_tcpack_suppress) {
1759 dhd_tcpack_check_xmit(bus->dhd, pkt);
1760 }
1761 #endif /* DHDTCPACK_SUPPRESS */
1762
1763 if (bus->dhd->dongle_reset) {
1764 ret = BCME_NOTREADY;
1765 goto done;
1766 }
1767
1768 frame = (uint8*)PKTDATA(osh, pkt);
1769
1770 #ifdef WLMEDIA_HTSF
1771 if (PKTLEN(osh, pkt) >= 100) {
1772 p = PKTDATA(osh, pkt);
1773 htsf_ts = (htsfts_t*) (p + HTSF_HOSTOFFSET + 12);
1774 if (htsf_ts->magic == HTSFMAGIC) {
1775 htsf_ts->c20 = get_cycles();
1776 htsf_ts->t20 = dhd_get_htsf(bus->dhd->info, 0);
1777 }
1778 }
1779 #endif /* WLMEDIA_HTSF */
1780
1781 /* Add alignment padding, allocate new packet if needed */
1782 if ((pad1 = ((uintptr)frame % DHD_SDALIGN))) {
1783 if (PKTHEADROOM(osh, pkt) < pad1) {
1784 DHD_INFO(("%s: insufficient headroom %d for %d pad1\n",
1785 __FUNCTION__, (int)PKTHEADROOM(osh, pkt), pad1));
1786 bus->dhd->tx_realloc++;
1787 new = PKTGET(osh, (PKTLEN(osh, pkt) + DHD_SDALIGN), TRUE);
1788 if (!new) {
1789 DHD_ERROR(("%s: couldn't allocate new %d-byte packet\n",
1790 __FUNCTION__, PKTLEN(osh, pkt) + DHD_SDALIGN));
1791 ret = BCME_NOMEM;
1792 goto done;
1793 }
1794
1795 PKTALIGN(osh, new, PKTLEN(osh, pkt), DHD_SDALIGN);
1796 bcopy(PKTDATA(osh, pkt), PKTDATA(osh, new), PKTLEN(osh, pkt));
1797 if (free_pkt)
1798 PKTFREE(osh, pkt, TRUE);
1799 /* free the pkt if canned one is not used */
1800 free_pkt = TRUE;
1801 pkt = new;
1802 frame = (uint8*)PKTDATA(osh, pkt);
1803 ASSERT(((uintptr)frame % DHD_SDALIGN) == 0);
1804 pad1 = 0;
1805 } else {
1806 PKTPUSH(osh, pkt, pad1);
1807 frame = (uint8*)PKTDATA(osh, pkt);
1808
1809 ASSERT((pad1 + SDPCM_HDRLEN) <= (int) PKTLEN(osh, pkt));
1810 bzero(frame, pad1 + SDPCM_HDRLEN);
1811 }
1812 }
1813 ASSERT(pad1 < DHD_SDALIGN);
1814
1815 /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
1816 len = (uint16)PKTLEN(osh, pkt);
1817 *(uint16*)frame = htol16(len);
1818 *(((uint16*)frame) + 1) = htol16(~len);
1819
1820 #ifdef BCMSDIOH_TXGLOM
1821 if (bus->glom_enable) {
1822 uint32 hwheader1 = 0, hwheader2 = 0;
1823 act_len = len;
1824
1825 /* Software tag: channel, sequence number, data offset */
1826 swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) |
1827 ((bus->tx_seq + bus->glom_cnt) % SDPCM_SEQUENCE_WRAP) |
1828 (((pad1 + SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
1829 htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN);
1830 htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN + sizeof(swheader));
1831
1832 if (queue_only) {
1833 uint8 alignment = ALIGNMENT;
1834 if (forcealign && (len & (alignment - 1)))
1835 len = ROUNDUP(len, alignment);
1836 /* Hardware extention tag */
1837 /* 2byte frame length, 1byte-, 1byte frame flag,
1838 * 2byte-hdrlength, 2byte padlenght
1839 */
1840 hwheader1 = (act_len - SDPCM_FRAMETAG_LEN) | (0 << 24);
1841 hwheader2 = (len - act_len) << 16;
1842 htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN);
1843 htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4);
1844 real_pad = len - act_len;
1845 if (PKTTAILROOM(osh, pkt) < real_pad) {
1846 DHD_INFO(("%s 1: insufficient tailroom %d for %d real_pad\n",
1847 __FUNCTION__, (int)PKTTAILROOM(osh, pkt), real_pad));
1848 if (PKTPADTAILROOM(osh, pkt, real_pad)) {
1849 DHD_ERROR(("CHK1: padding error size %d\n", real_pad));
1850 ret = BCME_NOMEM;
1851 goto done;
1852 }
1853 #ifndef BCMLXSDMMC
1854 else
1855 PKTSETLEN(osh, pkt, act_len);
1856 #endif
1857 }
1858 #ifdef BCMLXSDMMC
1859 PKTSETLEN(osh, pkt, len);
1860 #endif /* BCMLXSDMMC */
1861 /* Post the frame pointer to sdio glom array */
1862 dhd_bcmsdh_glom_post(bus, frame, pkt, len);
1863 /* Save the pkt pointer in bus glom array */
1864 bus->glom_pkt_arr[bus->glom_cnt] = pkt;
1865 bus->glom_total_len += len;
1866 bus->glom_cnt++;
1867 return BCME_OK;
1868 } else {
1869 /* Raise len to next SDIO block to eliminate tail command */
1870 if (bus->roundup && bus->blocksize &&
1871 ((bus->glom_total_len + len) > bus->blocksize)) {
1872 uint16 pad2 = bus->blocksize -
1873 ((bus->glom_total_len + len) % bus->blocksize);
1874 if ((pad2 <= bus->roundup) && (pad2 < bus->blocksize)) {
1875 len += pad2;
1876 } else {
1877 }
1878 } else if ((bus->glom_total_len + len) % DHD_SDALIGN) {
1879 len += DHD_SDALIGN
1880 - ((bus->glom_total_len + len) % DHD_SDALIGN);
1881 }
1882 if (forcealign && (len & (ALIGNMENT - 1))) {
1883 len = ROUNDUP(len, ALIGNMENT);
1884 }
1885
1886 /* Hardware extention tag */
1887 /* 2byte frame length, 1byte-, 1byte frame flag,
1888 * 2byte-hdrlength, 2byte padlenght
1889 */
1890 hwheader1 = (act_len - SDPCM_FRAMETAG_LEN) | (1 << 24);
1891 hwheader2 = (len - act_len) << 16;
1892 htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN);
1893 htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4);
1894 real_pad = len - act_len;
1895 if (PKTTAILROOM(osh, pkt) < real_pad) {
1896 DHD_INFO(("%s 2: insufficient tailroom %d"
1897 " for %d real_pad\n",
1898 __FUNCTION__, (int)PKTTAILROOM(osh, pkt), real_pad));
1899 if (PKTPADTAILROOM(osh, pkt, real_pad)) {
1900 DHD_ERROR(("CHK2: padding error size %d."
1901 " %d more pkts are discarded together.\n",
1902 real_pad, bus->glom_cnt));
1903 /* Save the pkt pointer in bus glom array
1904 * Otherwise, this last pkt will not be
1905 * cleaned under "goto done"
1906 */
1907 bus->glom_pkt_arr[bus->glom_cnt] = pkt;
1908 bus->glom_cnt++;
1909 bus->glom_total_len += len;
1910 ret = BCME_NOMEM;
1911 goto done;
1912 }
1913 #ifndef BCMLXSDMMC
1914 else
1915 PKTSETLEN(osh, pkt, act_len);
1916 #endif
1917 }
1918 #ifdef BCMLXSDMMC
1919 PKTSETLEN(osh, pkt, len);
1920 #endif /* BCMLXSDMMC */
1921
1922 /* Post the frame pointer to sdio glom array */
1923 dhd_bcmsdh_glom_post(bus, frame, pkt, len);
1924 /* Save the pkt pointer in bus glom array */
1925 bus->glom_pkt_arr[bus->glom_cnt] = pkt;
1926 bus->glom_cnt++;
1927 bus->glom_total_len += len;
1928
1929 /* Update the total length on the first pkt */
1930 frame_tmp = (uint8*)PKTDATA(osh, bus->glom_pkt_arr[0]);
1931 *(uint16*)frame_tmp = htol16(bus->glom_total_len);
1932 *(((uint16*)frame_tmp) + 1) = htol16(~bus->glom_total_len);
1933 }
1934 } else
1935 #endif /* BCMSDIOH_TXGLOM */
1936 {
1937 act_len = len;
1938 /* Software tag: channel, sequence number, data offset */
1939 swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) | bus->tx_seq |
1940 (((pad1 + SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
1941 htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN);
1942 htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
1943
1944 #ifdef DHD_DEBUG
1945 if (PKTPRIO(pkt) < ARRAYSIZE(tx_packets)) {
1946 tx_packets[PKTPRIO(pkt)]++;
1947 }
1948 if (DHD_BYTES_ON() &&
1949 (((DHD_CTL_ON() && (chan == SDPCM_CONTROL_CHANNEL)) ||
1950 (DHD_DATA_ON() && (chan != SDPCM_CONTROL_CHANNEL))))) {
1951 prhex("Tx Frame", frame, len);
1952 } else if (DHD_HDRS_ON()) {
1953 prhex("TxHdr", frame, MIN(len, 16));
1954 }
1955 #endif
1956
1957 /* Raise len to next SDIO block to eliminate tail command */
1958 if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
1959 uint16 pad2 = bus->blocksize - (len % bus->blocksize);
1960 if ((pad2 <= bus->roundup) && (pad2 < bus->blocksize))
1961 #ifdef NOTUSED
1962 if (pad2 <= PKTTAILROOM(osh, pkt))
1963 #endif /* NOTUSED */
1964 len += pad2;
1965 } else if (len % DHD_SDALIGN) {
1966 len += DHD_SDALIGN - (len % DHD_SDALIGN);
1967 }
1968
1969 /* Some controllers have trouble with odd bytes -- round to even */
1970 if (forcealign && (len & (ALIGNMENT - 1))) {
1971 #ifdef NOTUSED
1972 if (PKTTAILROOM(osh, pkt))
1973 #endif
1974 len = ROUNDUP(len, ALIGNMENT);
1975 #ifdef NOTUSED
1976 else
1977 DHD_ERROR(("%s: sending unrounded %d-byte packet\n", __FUNCTION__, len));
1978 #endif
1979 }
1980 real_pad = len - act_len;
1981 if (PKTTAILROOM(osh, pkt) < real_pad) {
1982 DHD_INFO(("%s 3: insufficient tailroom %d for %d real_pad\n",
1983 __FUNCTION__, (int)PKTTAILROOM(osh, pkt), real_pad));
1984 if (PKTPADTAILROOM(osh, pkt, real_pad)) {
1985 DHD_ERROR(("CHK3: padding error size %d\n", real_pad));
1986 ret = BCME_NOMEM;
1987 goto done;
1988 }
1989 #ifndef BCMLXSDMMC
1990 else
1991 PKTSETLEN(osh, pkt, act_len);
1992 #endif
1993 }
1994 #ifdef BCMLXSDMMC
1995 PKTSETLEN(osh, pkt, len);
1996 #endif /* BCMLXSDMMC */
1997 }
1998 do {
1999 ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
2000 frame, len, pkt, NULL, NULL);
2001 bus->f2txdata++;
2002 ASSERT(ret != BCME_PENDING);
2003
2004 if (ret == BCME_NODEVICE) {
2005 DHD_ERROR(("%s: Device asleep already\n", __FUNCTION__));
2006 } else if (ret < 0) {
2007 /* On failure, abort the command and terminate the frame */
2008 DHD_ERROR(("%s: sdio error %d, abort command and terminate frame.\n",
2009 __FUNCTION__, ret));
2010 bus->tx_sderrs++;
2011
2012 bcmsdh_abort(sdh, SDIO_FUNC_2);
2013 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
2014 SFC_WF_TERM, NULL);
2015 bus->f1regdata++;
2016
2017 for (i = 0; i < 3; i++) {
2018 uint8 hi, lo;
2019 hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
2020 SBSDIO_FUNC1_WFRAMEBCHI, NULL);
2021 lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
2022 SBSDIO_FUNC1_WFRAMEBCLO, NULL);
2023 bus->f1regdata += 2;
2024 if ((hi == 0) && (lo == 0))
2025 break;
2026 }
2027 }
2028 if (ret == 0) {
2029 #ifdef BCMSDIOH_TXGLOM
2030 if (bus->glom_enable) {
2031 bus->tx_seq = (bus->tx_seq + bus->glom_cnt) % SDPCM_SEQUENCE_WRAP;
2032 } else
2033 #endif
2034 {
2035 bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
2036 }
2037 }
2038 } while ((ret < 0) && retrydata && retries++ < TXRETRIES);
2039
2040 done:
2041
2042 #ifdef BCMSDIOH_TXGLOM
2043 if (bus->glom_enable && !queue_only) {
2044 dhd_bcmsdh_glom_clear(bus);
2045 pkt_cnt = bus->glom_cnt;
2046 } else
2047 #endif
2048 {
2049 pkt_cnt = 1;
2050 }
2051 /* restore pkt buffer pointer before calling tx complete routine */
2052 while (pkt_cnt) {
2053 #ifdef BCMSDIOH_TXGLOM
2054 uint32 doff;
2055 if (bus->glom_enable) {
2056 #ifdef BCMLXSDMMC
2057 uint32 pad2 = 0;
2058 #endif /* BCMLXSDMMC */
2059 if (!queue_only)
2060 pkt = bus->glom_pkt_arr[bus->glom_cnt - pkt_cnt];
2061
2062 frame = (uint8*)PKTDATA(osh, pkt);
2063 doff = ltoh32_ua(frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN);
2064 doff = (doff & SDPCM_DOFFSET_MASK) >> SDPCM_DOFFSET_SHIFT;
2065 #ifdef BCMLXSDMMC
2066 pad2 = ltoh32_ua(frame + SDPCM_FRAMETAG_LEN + 4) >> 16;
2067 PKTSETLEN(osh, pkt, PKTLEN(osh, pkt) - pad2);
2068 #endif /* BCMLXSDMMC */
2069 PKTPULL(osh, pkt, doff);
2070 } else
2071 #endif /* BCMSDIOH_TXGLOM */
2072 {
2073 #ifdef BCMLXSDMMC
2074 if (act_len > 0)
2075 PKTSETLEN(osh, pkt, act_len);
2076 #endif /* BCMLXSDMMC */
2077 PKTPULL(osh, pkt, SDPCM_HDRLEN + pad1);
2078 }
2079 #ifdef PROP_TXSTATUS
2080 if (bus->dhd->wlfc_state) {
2081 dhd_os_sdunlock(bus->dhd);
2082 dhd_wlfc_txcomplete(bus->dhd, pkt, ret == 0);
2083 dhd_os_sdlock(bus->dhd);
2084 } else {
2085 #endif /* PROP_TXSTATUS */
2086 #ifdef SDTEST
2087 if (chan != SDPCM_TEST_CHANNEL) {
2088 dhd_txcomplete(bus->dhd, pkt, ret != 0);
2089 }
2090 #else /* SDTEST */
2091 dhd_txcomplete(bus->dhd, pkt, ret != 0);
2092 #endif /* SDTEST */
2093 if (free_pkt)
2094 PKTFREE(osh, pkt, TRUE);
2095
2096 #ifdef PROP_TXSTATUS
2097 }
2098 #endif
2099 pkt_cnt--;
2100 }
2101
2102 #ifdef BCMSDIOH_TXGLOM
2103 /* Reset the glom array */
2104 if (bus->glom_enable && !queue_only) {
2105 bus->glom_cnt = 0;
2106 bus->glom_total_len = 0;
2107 }
2108 #endif
2109 return ret;
2110 }
2111
2112 int
dhd_bus_txdata(struct dhd_bus * bus,void * pkt)2113 dhd_bus_txdata(struct dhd_bus *bus, void *pkt)
2114 {
2115 int ret = BCME_ERROR;
2116 osl_t *osh;
2117 uint datalen, prec;
2118 #ifdef DHD_TX_DUMP
2119 uint8 *dump_data;
2120 uint16 protocol;
2121 #ifdef DHD_TX_FULL_DUMP
2122 int i;
2123 #endif /* DHD_TX_FULL_DUMP */
2124 #endif /* DHD_TX_DUMP */
2125 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2126
2127 osh = bus->dhd->osh;
2128 datalen = PKTLEN(osh, pkt);
2129
2130 #ifdef SDTEST
2131 /* Push the test header if doing loopback */
2132 if (bus->ext_loop) {
2133 uint8* data;
2134 PKTPUSH(osh, pkt, SDPCM_TEST_HDRLEN);
2135 data = PKTDATA(osh, pkt);
2136 *data++ = SDPCM_TEST_ECHOREQ;
2137 *data++ = (uint8)bus->loopid++;
2138 *data++ = (datalen >> 0);
2139 *data++ = (datalen >> 8);
2140 datalen += SDPCM_TEST_HDRLEN;
2141 }
2142 #endif /* SDTEST */
2143
2144 #ifdef DHD_TX_DUMP
2145 dump_data = PKTDATA(osh, pkt);
2146 dump_data += 4; /* skip 4 bytes header */
2147 protocol = (dump_data[12] << 8) | dump_data[13];
2148 #ifdef DHD_TX_FULL_DUMP
2149 DHD_ERROR(("TX DUMP\n"));
2150
2151 for (i = 0; i < (datalen - 4); i++) {
2152 DHD_ERROR(("%02X ", dump_data[i]));
2153 if ((i & 15) == 15)
2154 printk("\n");
2155 }
2156 DHD_ERROR(("\n"));
2157
2158 #endif /* DHD_TX_FULL_DUMP */
2159 if (protocol == ETHER_TYPE_802_1X) {
2160 DHD_ERROR(("ETHER_TYPE_802_1X: ver %d, type %d, replay %d\n",
2161 dump_data[14], dump_data[15], dump_data[30]));
2162 }
2163 #endif /* DHD_TX_DUMP */
2164
2165 /* Add space for the header */
2166 PKTPUSH(osh, pkt, SDPCM_HDRLEN);
2167 ASSERT(ISALIGNED((uintptr)PKTDATA(osh, pkt), 2));
2168
2169 prec = PRIO2PREC((PKTPRIO(pkt) & PRIOMASK));
2170 #ifndef DHDTHREAD
2171 /* Lock: we're about to use shared data/code (and SDIO) */
2172 dhd_os_sdlock(bus->dhd);
2173 #endif /* DHDTHREAD */
2174
2175 /* Check for existing queue, current flow-control, pending event, or pending clock */
2176 if (dhd_deferred_tx || bus->fcstate || pktq_len(&bus->txq) || bus->dpc_sched ||
2177 (!DATAOK(bus)) || (bus->flowcontrol & NBITVAL(prec)) ||
2178 (bus->clkstate != CLK_AVAIL)) {
2179 DHD_TRACE(("%s: deferring pktq len %d\n", __FUNCTION__,
2180 pktq_len(&bus->txq)));
2181 bus->fcqueued++;
2182
2183 /* Priority based enq */
2184 dhd_os_sdlock_txq(bus->dhd);
2185 if (dhd_prec_enq(bus->dhd, &bus->txq, pkt, prec) == FALSE) {
2186 PKTPULL(osh, pkt, SDPCM_HDRLEN);
2187 #ifndef DHDTHREAD
2188 /* Need to also release txqlock before releasing sdlock.
2189 * This thread still has txqlock and releases sdlock.
2190 * Deadlock happens when dpc() grabs sdlock first then
2191 * attempts to grab txqlock.
2192 */
2193 dhd_os_sdunlock_txq(bus->dhd);
2194 dhd_os_sdunlock(bus->dhd);
2195 #endif
2196 #ifdef PROP_TXSTATUS
2197 if (bus->dhd->wlfc_state)
2198 dhd_wlfc_txcomplete(bus->dhd, pkt, FALSE);
2199 else
2200 #endif
2201 dhd_txcomplete(bus->dhd, pkt, FALSE);
2202 #ifndef DHDTHREAD
2203 dhd_os_sdlock(bus->dhd);
2204 dhd_os_sdlock_txq(bus->dhd);
2205 #endif
2206 #ifdef PROP_TXSTATUS
2207 /* let the caller decide whether to free the packet */
2208 if (!bus->dhd->wlfc_state)
2209 #endif
2210 PKTFREE(osh, pkt, TRUE);
2211 ret = BCME_NORESOURCE;
2212 }
2213 else
2214 ret = BCME_OK;
2215
2216 if ((pktq_len(&bus->txq) >= FCHI) && dhd_doflow)
2217 dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON);
2218
2219 #ifdef DHD_DEBUG
2220 if (pktq_plen(&bus->txq, prec) > qcount[prec])
2221 qcount[prec] = pktq_plen(&bus->txq, prec);
2222 #endif
2223 dhd_os_sdunlock_txq(bus->dhd);
2224
2225 /* Schedule DPC if needed to send queued packet(s) */
2226 if (dhd_deferred_tx && !bus->dpc_sched) {
2227 bus->dpc_sched = TRUE;
2228 dhd_sched_dpc(bus->dhd);
2229 }
2230 } else {
2231 #ifdef DHDTHREAD
2232 /* Lock: we're about to use shared data/code (and SDIO) */
2233 dhd_os_sdlock(bus->dhd);
2234 #endif /* DHDTHREAD */
2235
2236 /* Otherwise, send it now */
2237 BUS_WAKE(bus);
2238 /* Make sure back plane ht clk is on, no pending allowed */
2239 dhdsdio_clkctl(bus, CLK_AVAIL, TRUE);
2240 #ifndef SDTEST
2241 ret = dhdsdio_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, TRUE, FALSE);
2242 #else
2243 ret = dhdsdio_txpkt(bus, pkt,
2244 (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL), TRUE, FALSE);
2245 #endif
2246 if (ret)
2247 bus->dhd->tx_errors++;
2248 else
2249 bus->dhd->dstats.tx_bytes += datalen;
2250
2251 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
2252 bus->activity = FALSE;
2253 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
2254 }
2255
2256 #ifdef DHDTHREAD
2257 dhd_os_sdunlock(bus->dhd);
2258 #endif /* DHDTHREAD */
2259 }
2260
2261 #ifndef DHDTHREAD
2262 dhd_os_sdunlock(bus->dhd);
2263 #endif /* DHDTHREAD */
2264
2265 return ret;
2266 }
2267
2268 static uint
dhdsdio_sendfromq(dhd_bus_t * bus,uint maxframes)2269 dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes)
2270 {
2271 void *pkt;
2272 uint32 intstatus = 0;
2273 uint retries = 0;
2274 int ret = 0, prec_out;
2275 uint cnt = 0;
2276 uint datalen;
2277 uint8 tx_prec_map;
2278 uint16 txpktqlen = 0;
2279 #ifdef BCMSDIOH_TXGLOM
2280 uint i;
2281 uint8 glom_cnt;
2282 #endif
2283
2284 dhd_pub_t *dhd = bus->dhd;
2285 sdpcmd_regs_t *regs = bus->regs;
2286
2287 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2288
2289 if (!KSO_ENAB(bus)) {
2290 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
2291 return BCME_NODEVICE;
2292 }
2293
2294 tx_prec_map = ~bus->flowcontrol;
2295
2296 /* Send frames until the limit or some other event */
2297 for (cnt = 0; (cnt < maxframes) && DATAOK(bus); cnt++) {
2298 #ifdef BCMSDIOH_TXGLOM
2299 if (bus->glom_enable) {
2300 void *pkttable[SDPCM_MAXGLOM_SIZE];
2301 dhd_os_sdlock_txq(bus->dhd);
2302 glom_cnt = MIN(DATABUFCNT(bus), bus->glomsize);
2303 glom_cnt = MIN(glom_cnt, pktq_mlen(&bus->txq, tx_prec_map));
2304 glom_cnt = MIN(glom_cnt, maxframes-cnt);
2305
2306 /* Limiting the size to 2pkts in case of copy */
2307 if (bus->glom_mode == SDPCM_TXGLOM_CPY)
2308 glom_cnt = MIN(glom_cnt, 10);
2309
2310 for (i = 0; i < glom_cnt; i++)
2311 pkttable[i] = pktq_mdeq(&bus->txq, tx_prec_map, &prec_out);
2312
2313 txpktqlen = pktq_len(&bus->txq);
2314 dhd_os_sdunlock_txq(bus->dhd);
2315
2316 if (glom_cnt == 0)
2317 break;
2318 datalen = 0;
2319 for (i = 0; i < glom_cnt; i++) {
2320 uint datalen_tmp = 0;
2321
2322 if ((pkt = pkttable[i]) == NULL) {
2323 /* This case should not happen */
2324 DHD_ERROR(("No pkts in the queue for glomming\n"));
2325 break;
2326 }
2327
2328 datalen_tmp = (PKTLEN(bus->dhd->osh, pkt) - SDPCM_HDRLEN);
2329
2330 #ifndef SDTEST
2331 ret = dhdsdio_txpkt(bus,
2332 pkt,
2333 SDPCM_DATA_CHANNEL,
2334 TRUE,
2335 (i == (glom_cnt-1))? FALSE: TRUE);
2336 #else
2337 ret = dhdsdio_txpkt(bus,
2338 pkt,
2339 (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL),
2340 TRUE,
2341 (i == (glom_cnt-1))? FALSE: TRUE);
2342 #endif
2343 if (ret == BCME_OK)
2344 datalen += datalen_tmp;
2345 }
2346 cnt += i-1;
2347 } else
2348 #endif /* BCMSDIOH_TXGLOM */
2349 {
2350 dhd_os_sdlock_txq(bus->dhd);
2351 if ((pkt = pktq_mdeq(&bus->txq, tx_prec_map, &prec_out)) == NULL) {
2352 txpktqlen = pktq_len(&bus->txq);
2353 dhd_os_sdunlock_txq(bus->dhd);
2354 break;
2355 }
2356 txpktqlen = pktq_len(&bus->txq);
2357 dhd_os_sdunlock_txq(bus->dhd);
2358 datalen = PKTLEN(bus->dhd->osh, pkt) - SDPCM_HDRLEN;
2359
2360 #ifndef SDTEST
2361 ret = dhdsdio_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, TRUE, FALSE);
2362 #else
2363 ret = dhdsdio_txpkt(bus,
2364 pkt,
2365 (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL),
2366 TRUE,
2367 FALSE);
2368 #endif
2369 }
2370
2371 if (ret)
2372 bus->dhd->tx_errors++;
2373 else
2374 bus->dhd->dstats.tx_bytes += datalen;
2375
2376 /* In poll mode, need to check for other events */
2377 if (!bus->intr && cnt)
2378 {
2379 /* Check device status, signal pending interrupt */
2380 R_SDREG(intstatus, ®s->intstatus, retries);
2381 bus->f2txdata++;
2382 if (bcmsdh_regfail(bus->sdh))
2383 break;
2384 if (intstatus & bus->hostintmask)
2385 bus->ipend = TRUE;
2386 }
2387 }
2388
2389 /* Deflow-control stack if needed */
2390 if (dhd_doflow && dhd->up && (dhd->busstate == DHD_BUS_DATA) &&
2391 dhd->txoff && (txpktqlen < FCLOW))
2392 dhd_txflowcontrol(dhd, ALL_INTERFACES, OFF);
2393
2394 return cnt;
2395 }
2396
2397 static void
dhdsdio_sendpendctl(dhd_bus_t * bus)2398 dhdsdio_sendpendctl(dhd_bus_t *bus)
2399 {
2400 bcmsdh_info_t *sdh = bus->sdh;
2401 int ret, i;
2402 uint8* frame_seq = bus->ctrl_frame_buf + SDPCM_FRAMETAG_LEN;
2403
2404 #ifdef BCMSDIOH_TXGLOM
2405 if (bus->glom_enable)
2406 frame_seq += SDPCM_HWEXT_LEN;
2407 #endif
2408
2409 if (*frame_seq != bus->tx_seq) {
2410 DHD_INFO(("%s IOCTL frame seq lag detected!"
2411 " frm_seq:%d != bus->tx_seq:%d, corrected\n",
2412 __FUNCTION__, *frame_seq, bus->tx_seq));
2413 *frame_seq = bus->tx_seq;
2414 }
2415
2416 ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
2417 (uint8 *)bus->ctrl_frame_buf, (uint32)bus->ctrl_frame_len,
2418 NULL, NULL, NULL);
2419 ASSERT(ret != BCME_PENDING);
2420 if (ret == BCME_NODEVICE) {
2421 DHD_ERROR(("%s: Device asleep already\n", __FUNCTION__));
2422 } else if (ret < 0) {
2423 /* On failure, abort the command and terminate the frame */
2424 DHD_INFO(("%s: sdio error %d, abort command and terminate frame.\n",
2425 __FUNCTION__, ret));
2426 bus->tx_sderrs++;
2427
2428 bcmsdh_abort(sdh, SDIO_FUNC_2);
2429
2430 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
2431 SFC_WF_TERM, NULL);
2432 bus->f1regdata++;
2433
2434 for (i = 0; i < 3; i++) {
2435 uint8 hi, lo;
2436 hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
2437 SBSDIO_FUNC1_WFRAMEBCHI, NULL);
2438 lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
2439 SBSDIO_FUNC1_WFRAMEBCLO, NULL);
2440 bus->f1regdata += 2;
2441 if ((hi == 0) && (lo == 0))
2442 break;
2443 }
2444 }
2445 if (ret == 0) {
2446 bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
2447 }
2448
2449 bus->ctrl_frame_stat = FALSE;
2450 dhd_wait_event_wakeup(bus->dhd);
2451 }
2452
2453 int
dhd_bus_txctl(struct dhd_bus * bus,uchar * msg,uint msglen)2454 dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen)
2455 {
2456 uint8 *frame;
2457 uint16 len;
2458 uint32 swheader;
2459 uint retries = 0;
2460 bcmsdh_info_t *sdh = bus->sdh;
2461 uint8 doff = 0;
2462 int ret = -1;
2463 int i;
2464
2465 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2466
2467 if (bus->dhd->dongle_reset)
2468 return -EIO;
2469
2470 /* Back the pointer to make a room for bus header */
2471 frame = msg - SDPCM_HDRLEN;
2472 len = (msglen += SDPCM_HDRLEN);
2473
2474 /* Add alignment padding (optional for ctl frames) */
2475 if (dhd_alignctl) {
2476 if ((doff = ((uintptr)frame % DHD_SDALIGN))) {
2477 frame -= doff;
2478 len += doff;
2479 msglen += doff;
2480 bzero(frame, doff + SDPCM_HDRLEN);
2481 }
2482 ASSERT(doff < DHD_SDALIGN);
2483 }
2484 doff += SDPCM_HDRLEN;
2485
2486 /* Round send length to next SDIO block */
2487 if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
2488 uint16 pad = bus->blocksize - (len % bus->blocksize);
2489 if ((pad <= bus->roundup) && (pad < bus->blocksize))
2490 len += pad;
2491 } else if (len % DHD_SDALIGN) {
2492 len += DHD_SDALIGN - (len % DHD_SDALIGN);
2493 }
2494
2495 /* Satisfy length-alignment requirements */
2496 if (forcealign && (len & (ALIGNMENT - 1)))
2497 len = ROUNDUP(len, ALIGNMENT);
2498
2499 ASSERT(ISALIGNED((uintptr)frame, 2));
2500
2501
2502 /* Need to lock here to protect txseq and SDIO tx calls */
2503 dhd_os_sdlock(bus->dhd);
2504
2505 BUS_WAKE(bus);
2506
2507 /* Make sure backplane clock is on */
2508 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
2509
2510 /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
2511 *(uint16*)frame = htol16((uint16)msglen);
2512 *(((uint16*)frame) + 1) = htol16(~msglen);
2513
2514 #ifdef BCMSDIOH_TXGLOM
2515 if (bus->glom_enable) {
2516 uint32 hwheader1, hwheader2;
2517 /* Software tag: channel, sequence number, data offset */
2518 swheader = ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK)
2519 | bus->tx_seq
2520 | ((doff << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
2521 htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN);
2522 htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN
2523 + SDPCM_HWEXT_LEN + sizeof(swheader));
2524
2525 hwheader1 = (msglen - SDPCM_FRAMETAG_LEN) | (1 << 24);
2526 hwheader2 = (len - (msglen)) << 16;
2527 htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN);
2528 htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4);
2529
2530 *(uint16*)frame = htol16(len);
2531 *(((uint16*)frame) + 1) = htol16(~(len));
2532 } else
2533 #endif /* BCMSDIOH_TXGLOM */
2534 {
2535 /* Software tag: channel, sequence number, data offset */
2536 swheader = ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK)
2537 | bus->tx_seq | ((doff << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
2538 htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN);
2539 htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
2540 }
2541 if (!TXCTLOK(bus)) {
2542 DHD_INFO(("%s: No bus credit bus->tx_max %d, bus->tx_seq %d\n",
2543 __FUNCTION__, bus->tx_max, bus->tx_seq));
2544 bus->ctrl_frame_stat = TRUE;
2545 /* Send from dpc */
2546 bus->ctrl_frame_buf = frame;
2547 bus->ctrl_frame_len = len;
2548
2549 if (!bus->dpc_sched) {
2550 bus->dpc_sched = TRUE;
2551 dhd_sched_dpc(bus->dhd);
2552 }
2553 if (bus->ctrl_frame_stat) {
2554 dhd_wait_for_event(bus->dhd, &bus->ctrl_frame_stat);
2555 }
2556
2557 if (bus->ctrl_frame_stat == FALSE) {
2558 DHD_INFO(("%s: ctrl_frame_stat == FALSE\n", __FUNCTION__));
2559 ret = 0;
2560 } else {
2561 bus->dhd->txcnt_timeout++;
2562 if (!bus->dhd->hang_was_sent) {
2563 DHD_ERROR(("%s: ctrl_frame_stat == TRUE txcnt_timeout=%d\n",
2564 __FUNCTION__, bus->dhd->txcnt_timeout));
2565 }
2566 ret = -1;
2567 bus->ctrl_frame_stat = FALSE;
2568 goto done;
2569 }
2570 }
2571
2572 bus->dhd->txcnt_timeout = 0;
2573
2574 if (ret == -1) {
2575 #ifdef DHD_DEBUG
2576 if (DHD_BYTES_ON() && DHD_CTL_ON()) {
2577 prhex("Tx Frame", frame, len);
2578 } else if (DHD_HDRS_ON()) {
2579 prhex("TxHdr", frame, MIN(len, 16));
2580 }
2581 #endif
2582
2583 do {
2584 ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
2585 frame, len, NULL, NULL, NULL);
2586 ASSERT(ret != BCME_PENDING);
2587
2588 if (ret == BCME_NODEVICE) {
2589 DHD_ERROR(("%s: Device asleep already\n", __FUNCTION__));
2590 } else if (ret < 0) {
2591 /* On failure, abort the command and terminate the frame */
2592 DHD_INFO(("%s: sdio error %d, abort command and terminate frame.\n",
2593 __FUNCTION__, ret));
2594 bus->tx_sderrs++;
2595
2596 bcmsdh_abort(sdh, SDIO_FUNC_2);
2597
2598 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
2599 SFC_WF_TERM, NULL);
2600 bus->f1regdata++;
2601
2602 for (i = 0; i < 3; i++) {
2603 uint8 hi, lo;
2604 hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
2605 SBSDIO_FUNC1_WFRAMEBCHI, NULL);
2606 lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
2607 SBSDIO_FUNC1_WFRAMEBCLO, NULL);
2608 bus->f1regdata += 2;
2609 if ((hi == 0) && (lo == 0))
2610 break;
2611 }
2612 }
2613 if (ret == 0) {
2614 bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
2615 }
2616 } while ((ret < 0) && retries++ < TXRETRIES);
2617 }
2618
2619 done:
2620 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
2621 bus->activity = FALSE;
2622 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
2623 }
2624
2625 dhd_os_sdunlock(bus->dhd);
2626
2627 if (ret)
2628 bus->dhd->tx_ctlerrs++;
2629 else
2630 bus->dhd->tx_ctlpkts++;
2631
2632 if (bus->dhd->txcnt_timeout >= MAX_CNTL_TX_TIMEOUT)
2633 return -ETIMEDOUT;
2634
2635 return ret ? -EIO : 0;
2636 }
2637
2638 int
dhd_bus_rxctl(struct dhd_bus * bus,uchar * msg,uint msglen)2639 dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen)
2640 {
2641 int timeleft;
2642 uint rxlen = 0;
2643 bool pending;
2644
2645 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2646
2647 if (bus->dhd->dongle_reset)
2648 return -EIO;
2649
2650 /* Wait until control frame is available */
2651 timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->rxlen, &pending);
2652
2653 dhd_os_sdlock(bus->dhd);
2654 rxlen = bus->rxlen;
2655 bcopy(bus->rxctl, msg, MIN(msglen, rxlen));
2656 bus->rxlen = 0;
2657 dhd_os_sdunlock(bus->dhd);
2658
2659 if (rxlen) {
2660 DHD_CTL(("%s: resumed on rxctl frame, got %d expected %d\n",
2661 __FUNCTION__, rxlen, msglen));
2662 } else if (timeleft == 0) {
2663 #ifdef DHD_DEBUG
2664 uint32 status, retry = 0;
2665 R_SDREG(status, &bus->regs->intstatus, retry);
2666 DHD_ERROR(("%s: resumed on timeout, INT status=0x%08X\n",
2667 __FUNCTION__, status));
2668 #else
2669 DHD_ERROR(("%s: resumed on timeout\n", __FUNCTION__));
2670 #endif /* DHD_DEBUG */
2671 #ifdef DHD_DEBUG
2672 dhd_os_sdlock(bus->dhd);
2673 dhdsdio_checkdied(bus, NULL, 0);
2674 dhd_os_sdunlock(bus->dhd);
2675 #endif /* DHD_DEBUG */
2676 } else if (pending == TRUE) {
2677 /* signal pending */
2678 DHD_ERROR(("%s: signal pending\n", __FUNCTION__));
2679 return -EINTR;
2680
2681 } else {
2682 DHD_CTL(("%s: resumed for unknown reason?\n", __FUNCTION__));
2683 #ifdef DHD_DEBUG
2684 dhd_os_sdlock(bus->dhd);
2685 dhdsdio_checkdied(bus, NULL, 0);
2686 dhd_os_sdunlock(bus->dhd);
2687 #endif /* DHD_DEBUG */
2688 }
2689 if (timeleft == 0) {
2690 if (rxlen == 0)
2691 bus->dhd->rxcnt_timeout++;
2692 DHD_ERROR(("%s: rxcnt_timeout=%d, rxlen=%d\n", __FUNCTION__,
2693 bus->dhd->rxcnt_timeout, rxlen));
2694 }
2695 else
2696 bus->dhd->rxcnt_timeout = 0;
2697
2698 if (rxlen)
2699 bus->dhd->rx_ctlpkts++;
2700 else
2701 bus->dhd->rx_ctlerrs++;
2702
2703 if (bus->dhd->rxcnt_timeout >= MAX_CNTL_RX_TIMEOUT)
2704 return -ETIMEDOUT;
2705
2706 if (bus->dhd->dongle_trap_occured)
2707 return -EREMOTEIO;
2708
2709 return rxlen ? (int)rxlen : -EIO;
2710 }
2711
2712 /* IOVar table */
2713 enum {
2714 IOV_INTR = 1,
2715 IOV_POLLRATE,
2716 IOV_SDREG,
2717 IOV_SBREG,
2718 IOV_SDCIS,
2719 IOV_MEMBYTES,
2720 IOV_RAMSIZE,
2721 IOV_RAMSTART,
2722 #ifdef DHD_DEBUG
2723 IOV_CHECKDIED,
2724 IOV_SERIALCONS,
2725 #endif /* DHD_DEBUG */
2726 IOV_SET_DOWNLOAD_STATE,
2727 IOV_SOCRAM_STATE,
2728 IOV_FORCEEVEN,
2729 IOV_SDIOD_DRIVE,
2730 IOV_READAHEAD,
2731 IOV_SDRXCHAIN,
2732 IOV_ALIGNCTL,
2733 IOV_SDALIGN,
2734 IOV_DEVRESET,
2735 IOV_CPU,
2736 #if defined(SDIO_CRC_ERROR_FIX)
2737 IOV_WATERMARK,
2738 IOV_MESBUSYCTRL,
2739 #endif /* SDIO_CRC_ERROR_FIX */
2740 #ifdef SDTEST
2741 IOV_PKTGEN,
2742 IOV_EXTLOOP,
2743 #endif /* SDTEST */
2744 IOV_SPROM,
2745 IOV_TXBOUND,
2746 IOV_RXBOUND,
2747 IOV_TXMINMAX,
2748 IOV_IDLETIME,
2749 IOV_IDLECLOCK,
2750 IOV_SD1IDLE,
2751 IOV_SLEEP,
2752 IOV_DONGLEISOLATION,
2753 IOV_KSO,
2754 IOV_DEVSLEEP,
2755 IOV_DEVCAP,
2756 IOV_VARS,
2757 #ifdef SOFTAP
2758 IOV_FWPATH,
2759 #endif
2760 IOV_TXGLOMSIZE,
2761 IOV_TXGLOMMODE,
2762 IOV_HANGREPORT
2763 };
2764
2765 const bcm_iovar_t dhdsdio_iovars[] = {
2766 {"intr", IOV_INTR, 0, IOVT_BOOL, 0 },
2767 {"sleep", IOV_SLEEP, 0, IOVT_BOOL, 0 },
2768 {"pollrate", IOV_POLLRATE, 0, IOVT_UINT32, 0 },
2769 {"idletime", IOV_IDLETIME, 0, IOVT_INT32, 0 },
2770 {"idleclock", IOV_IDLECLOCK, 0, IOVT_INT32, 0 },
2771 {"sd1idle", IOV_SD1IDLE, 0, IOVT_BOOL, 0 },
2772 {"membytes", IOV_MEMBYTES, 0, IOVT_BUFFER, 2 * sizeof(int) },
2773 {"ramsize", IOV_RAMSIZE, 0, IOVT_UINT32, 0 },
2774 {"ramstart", IOV_RAMSTART, 0, IOVT_UINT32, 0 },
2775 {"dwnldstate", IOV_SET_DOWNLOAD_STATE, 0, IOVT_BOOL, 0 },
2776 {"socram_state", IOV_SOCRAM_STATE, 0, IOVT_BOOL, 0 },
2777 {"vars", IOV_VARS, 0, IOVT_BUFFER, 0 },
2778 {"sdiod_drive", IOV_SDIOD_DRIVE, 0, IOVT_UINT32, 0 },
2779 {"readahead", IOV_READAHEAD, 0, IOVT_BOOL, 0 },
2780 {"sdrxchain", IOV_SDRXCHAIN, 0, IOVT_BOOL, 0 },
2781 {"alignctl", IOV_ALIGNCTL, 0, IOVT_BOOL, 0 },
2782 {"sdalign", IOV_SDALIGN, 0, IOVT_BOOL, 0 },
2783 {"devreset", IOV_DEVRESET, 0, IOVT_BOOL, 0 },
2784 #ifdef DHD_DEBUG
2785 {"sdreg", IOV_SDREG, 0, IOVT_BUFFER, sizeof(sdreg_t) },
2786 {"sbreg", IOV_SBREG, 0, IOVT_BUFFER, sizeof(sdreg_t) },
2787 {"sd_cis", IOV_SDCIS, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN },
2788 {"forcealign", IOV_FORCEEVEN, 0, IOVT_BOOL, 0 },
2789 {"txbound", IOV_TXBOUND, 0, IOVT_UINT32, 0 },
2790 {"rxbound", IOV_RXBOUND, 0, IOVT_UINT32, 0 },
2791 {"txminmax", IOV_TXMINMAX, 0, IOVT_UINT32, 0 },
2792 {"cpu", IOV_CPU, 0, IOVT_BOOL, 0 },
2793 #ifdef DHD_DEBUG
2794 {"checkdied", IOV_CHECKDIED, 0, IOVT_BUFFER, 0 },
2795 {"serial", IOV_SERIALCONS, 0, IOVT_UINT32, 0 },
2796 #endif /* DHD_DEBUG */
2797 #endif /* DHD_DEBUG */
2798 #ifdef SDTEST
2799 {"extloop", IOV_EXTLOOP, 0, IOVT_BOOL, 0 },
2800 {"pktgen", IOV_PKTGEN, 0, IOVT_BUFFER, sizeof(dhd_pktgen_t) },
2801 #endif /* SDTEST */
2802 #if defined(SDIO_CRC_ERROR_FIX)
2803 {"watermark", IOV_WATERMARK, 0, IOVT_UINT32, 0 },
2804 {"mesbusyctrl", IOV_MESBUSYCTRL, 0, IOVT_UINT32, 0 },
2805 #endif /* SDIO_CRC_ERROR_FIX */
2806 {"devcap", IOV_DEVCAP, 0, IOVT_UINT32, 0 },
2807 {"dngl_isolation", IOV_DONGLEISOLATION, 0, IOVT_UINT32, 0 },
2808 {"kso", IOV_KSO, 0, IOVT_UINT32, 0 },
2809 {"devsleep", IOV_DEVSLEEP, 0, IOVT_UINT32, 0 },
2810 #ifdef SOFTAP
2811 {"fwpath", IOV_FWPATH, 0, IOVT_BUFFER, 0 },
2812 #endif
2813 {"txglomsize", IOV_TXGLOMSIZE, 0, IOVT_UINT32, 0 },
2814 {"txglommode", IOV_TXGLOMMODE, 0, IOVT_UINT32, 0 },
2815 {"fw_hang_report", IOV_HANGREPORT, 0, IOVT_BOOL, 0 },
2816 {NULL, 0, 0, 0, 0 }
2817 };
2818
2819 static void
dhd_dump_pct(struct bcmstrbuf * strbuf,char * desc,uint num,uint div)2820 dhd_dump_pct(struct bcmstrbuf *strbuf, char *desc, uint num, uint div)
2821 {
2822 uint q1, q2;
2823
2824 if (!div) {
2825 bcm_bprintf(strbuf, "%s N/A", desc);
2826 } else {
2827 q1 = num / div;
2828 q2 = (100 * (num - (q1 * div))) / div;
2829 bcm_bprintf(strbuf, "%s %d.%02d", desc, q1, q2);
2830 }
2831 }
2832
2833 void
dhd_bus_dump(dhd_pub_t * dhdp,struct bcmstrbuf * strbuf)2834 dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf)
2835 {
2836 dhd_bus_t *bus = dhdp->bus;
2837
2838 bcm_bprintf(strbuf, "Bus SDIO structure:\n");
2839 bcm_bprintf(strbuf, "hostintmask 0x%08x intstatus 0x%08x sdpcm_ver %d\n",
2840 bus->hostintmask, bus->intstatus, bus->sdpcm_ver);
2841 bcm_bprintf(strbuf, "fcstate %d qlen %u tx_seq %d, max %d, rxskip %d rxlen %u rx_seq %d\n",
2842 bus->fcstate, pktq_len(&bus->txq), bus->tx_seq, bus->tx_max, bus->rxskip,
2843 bus->rxlen, bus->rx_seq);
2844 bcm_bprintf(strbuf, "intr %d intrcount %u lastintrs %u spurious %u\n",
2845 bus->intr, bus->intrcount, bus->lastintrs, bus->spurious);
2846 bcm_bprintf(strbuf, "pollrate %u pollcnt %u regfails %u\n",
2847 bus->pollrate, bus->pollcnt, bus->regfails);
2848
2849 bcm_bprintf(strbuf, "\nAdditional counters:\n");
2850 bcm_bprintf(strbuf, "tx_sderrs %u fcqueued %u rxrtx %u rx_toolong %u rxc_errors %u\n",
2851 bus->tx_sderrs, bus->fcqueued, bus->rxrtx, bus->rx_toolong,
2852 bus->rxc_errors);
2853 bcm_bprintf(strbuf, "rx_hdrfail %u badhdr %u badseq %u\n",
2854 bus->rx_hdrfail, bus->rx_badhdr, bus->rx_badseq);
2855 bcm_bprintf(strbuf, "fc_rcvd %u, fc_xoff %u, fc_xon %u\n",
2856 bus->fc_rcvd, bus->fc_xoff, bus->fc_xon);
2857 bcm_bprintf(strbuf, "rxglomfail %u, rxglomframes %u, rxglompkts %u\n",
2858 bus->rxglomfail, bus->rxglomframes, bus->rxglompkts);
2859 bcm_bprintf(strbuf, "f2rx (hdrs/data) %u (%u/%u), f2tx %u f1regs %u\n",
2860 (bus->f2rxhdrs + bus->f2rxdata), bus->f2rxhdrs, bus->f2rxdata,
2861 bus->f2txdata, bus->f1regdata);
2862 {
2863 dhd_dump_pct(strbuf, "\nRx: pkts/f2rd", bus->dhd->rx_packets,
2864 (bus->f2rxhdrs + bus->f2rxdata));
2865 dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->rx_packets, bus->f1regdata);
2866 dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->rx_packets,
2867 (bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata));
2868 dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->rx_packets, bus->intrcount);
2869 bcm_bprintf(strbuf, "\n");
2870
2871 dhd_dump_pct(strbuf, "Rx: glom pct", (100 * bus->rxglompkts),
2872 bus->dhd->rx_packets);
2873 dhd_dump_pct(strbuf, ", pkts/glom", bus->rxglompkts, bus->rxglomframes);
2874 bcm_bprintf(strbuf, "\n");
2875
2876 dhd_dump_pct(strbuf, "Tx: pkts/f2wr", bus->dhd->tx_packets, bus->f2txdata);
2877 dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->tx_packets, bus->f1regdata);
2878 dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->tx_packets,
2879 (bus->f2txdata + bus->f1regdata));
2880 dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->tx_packets, bus->intrcount);
2881 bcm_bprintf(strbuf, "\n");
2882
2883 dhd_dump_pct(strbuf, "Total: pkts/f2rw",
2884 (bus->dhd->tx_packets + bus->dhd->rx_packets),
2885 (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata));
2886 dhd_dump_pct(strbuf, ", pkts/f1sd",
2887 (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->f1regdata);
2888 dhd_dump_pct(strbuf, ", pkts/sd",
2889 (bus->dhd->tx_packets + bus->dhd->rx_packets),
2890 (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata));
2891 dhd_dump_pct(strbuf, ", pkts/int",
2892 (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->intrcount);
2893 bcm_bprintf(strbuf, "\n\n");
2894 }
2895
2896 #ifdef SDTEST
2897 if (bus->pktgen_count) {
2898 bcm_bprintf(strbuf, "pktgen config and count:\n");
2899 bcm_bprintf(strbuf, "freq %u count %u print %u total %u min %u len %u\n",
2900 bus->pktgen_freq, bus->pktgen_count, bus->pktgen_print,
2901 bus->pktgen_total, bus->pktgen_minlen, bus->pktgen_maxlen);
2902 bcm_bprintf(strbuf, "send attempts %u rcvd %u fail %u\n",
2903 bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail);
2904 }
2905 #endif /* SDTEST */
2906 #ifdef DHD_DEBUG
2907 bcm_bprintf(strbuf, "dpc_sched %d host interrupt%spending\n",
2908 bus->dpc_sched, (bcmsdh_intr_pending(bus->sdh) ? " " : " not "));
2909 bcm_bprintf(strbuf, "blocksize %u roundup %u\n", bus->blocksize, bus->roundup);
2910 #endif /* DHD_DEBUG */
2911 bcm_bprintf(strbuf, "clkstate %d activity %d idletime %d idlecount %d sleeping %d\n",
2912 bus->clkstate, bus->activity, bus->idletime, bus->idlecount, bus->sleeping);
2913 }
2914
2915 void
dhd_bus_clearcounts(dhd_pub_t * dhdp)2916 dhd_bus_clearcounts(dhd_pub_t *dhdp)
2917 {
2918 dhd_bus_t *bus = (dhd_bus_t *)dhdp->bus;
2919
2920 bus->intrcount = bus->lastintrs = bus->spurious = bus->regfails = 0;
2921 bus->rxrtx = bus->rx_toolong = bus->rxc_errors = 0;
2922 bus->rx_hdrfail = bus->rx_badhdr = bus->rx_badseq = 0;
2923 bus->tx_sderrs = bus->fc_rcvd = bus->fc_xoff = bus->fc_xon = 0;
2924 bus->rxglomfail = bus->rxglomframes = bus->rxglompkts = 0;
2925 bus->f2rxhdrs = bus->f2rxdata = bus->f2txdata = bus->f1regdata = 0;
2926 }
2927
2928 #ifdef SDTEST
2929 static int
dhdsdio_pktgen_get(dhd_bus_t * bus,uint8 * arg)2930 dhdsdio_pktgen_get(dhd_bus_t *bus, uint8 *arg)
2931 {
2932 dhd_pktgen_t pktgen;
2933
2934 pktgen.version = DHD_PKTGEN_VERSION;
2935 pktgen.freq = bus->pktgen_freq;
2936 pktgen.count = bus->pktgen_count;
2937 pktgen.print = bus->pktgen_print;
2938 pktgen.total = bus->pktgen_total;
2939 pktgen.minlen = bus->pktgen_minlen;
2940 pktgen.maxlen = bus->pktgen_maxlen;
2941 pktgen.numsent = bus->pktgen_sent;
2942 pktgen.numrcvd = bus->pktgen_rcvd;
2943 pktgen.numfail = bus->pktgen_fail;
2944 pktgen.mode = bus->pktgen_mode;
2945 pktgen.stop = bus->pktgen_stop;
2946
2947 bcopy(&pktgen, arg, sizeof(pktgen));
2948
2949 return 0;
2950 }
2951
2952 static int
dhdsdio_pktgen_set(dhd_bus_t * bus,uint8 * arg)2953 dhdsdio_pktgen_set(dhd_bus_t *bus, uint8 *arg)
2954 {
2955 dhd_pktgen_t pktgen;
2956 uint oldcnt, oldmode;
2957
2958 bcopy(arg, &pktgen, sizeof(pktgen));
2959 if (pktgen.version != DHD_PKTGEN_VERSION)
2960 return BCME_BADARG;
2961
2962 oldcnt = bus->pktgen_count;
2963 oldmode = bus->pktgen_mode;
2964
2965 bus->pktgen_freq = pktgen.freq;
2966 bus->pktgen_count = pktgen.count;
2967 bus->pktgen_print = pktgen.print;
2968 bus->pktgen_total = pktgen.total;
2969 bus->pktgen_minlen = pktgen.minlen;
2970 bus->pktgen_maxlen = pktgen.maxlen;
2971 bus->pktgen_mode = pktgen.mode;
2972 bus->pktgen_stop = pktgen.stop;
2973
2974 bus->pktgen_tick = bus->pktgen_ptick = 0;
2975 bus->pktgen_prev_time = jiffies;
2976 bus->pktgen_len = MAX(bus->pktgen_len, bus->pktgen_minlen);
2977 bus->pktgen_len = MIN(bus->pktgen_len, bus->pktgen_maxlen);
2978
2979 /* Clear counts for a new pktgen (mode change, or was stopped) */
2980 if (bus->pktgen_count && (!oldcnt || oldmode != bus->pktgen_mode)) {
2981 bus->pktgen_sent = bus->pktgen_prev_sent = bus->pktgen_rcvd = 0;
2982 bus->pktgen_prev_rcvd = bus->pktgen_fail = 0;
2983 }
2984
2985 return 0;
2986 }
2987 #endif /* SDTEST */
2988
2989 static void
dhdsdio_devram_remap(dhd_bus_t * bus,bool val)2990 dhdsdio_devram_remap(dhd_bus_t *bus, bool val)
2991 {
2992 uint8 enable, protect, remap;
2993
2994 si_socdevram(bus->sih, FALSE, &enable, &protect, &remap);
2995 remap = val ? TRUE : FALSE;
2996 si_socdevram(bus->sih, TRUE, &enable, &protect, &remap);
2997 }
2998
2999 static int
dhdsdio_membytes(dhd_bus_t * bus,bool write,uint32 address,uint8 * data,uint size)3000 dhdsdio_membytes(dhd_bus_t *bus, bool write, uint32 address, uint8 *data, uint size)
3001 {
3002 int bcmerror = 0;
3003 uint32 sdaddr;
3004 uint dsize;
3005
3006 /* In remap mode, adjust address beyond socram and redirect
3007 * to devram at SOCDEVRAM_BP_ADDR since remap address > orig_ramsize
3008 * is not backplane accessible
3009 */
3010 if (REMAP_ENAB(bus) && REMAP_ISADDR(bus, address)) {
3011 address -= bus->orig_ramsize;
3012 address += SOCDEVRAM_BP_ADDR;
3013 }
3014
3015 /* Determine initial transfer parameters */
3016 sdaddr = address & SBSDIO_SB_OFT_ADDR_MASK;
3017 if ((sdaddr + size) & SBSDIO_SBWINDOW_MASK)
3018 dsize = (SBSDIO_SB_OFT_ADDR_LIMIT - sdaddr);
3019 else
3020 dsize = size;
3021
3022 /* Set the backplane window to include the start address */
3023 if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) {
3024 DHD_ERROR(("%s: window change failed\n", __FUNCTION__));
3025 goto xfer_done;
3026 }
3027
3028 /* Do the transfer(s) */
3029 while (size) {
3030 DHD_INFO(("%s: %s %d bytes at offset 0x%08x in window 0x%08x\n",
3031 __FUNCTION__, (write ? "write" : "read"), dsize, sdaddr,
3032 (address & SBSDIO_SBWINDOW_MASK)));
3033 if ((bcmerror = bcmsdh_rwdata(bus->sdh, write, sdaddr, data, dsize))) {
3034 DHD_ERROR(("%s: membytes transfer failed\n", __FUNCTION__));
3035 break;
3036 }
3037
3038 /* Adjust for next transfer (if any) */
3039 if ((size -= dsize)) {
3040 data += dsize;
3041 address += dsize;
3042 if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) {
3043 DHD_ERROR(("%s: window change failed\n", __FUNCTION__));
3044 break;
3045 }
3046 sdaddr = 0;
3047 dsize = MIN(SBSDIO_SB_OFT_ADDR_LIMIT, size);
3048 }
3049
3050 }
3051
3052 xfer_done:
3053 /* Return the window to backplane enumeration space for core access */
3054 if (dhdsdio_set_siaddr_window(bus, bcmsdh_cur_sbwad(bus->sdh))) {
3055 DHD_ERROR(("%s: FAILED to set window back to 0x%x\n", __FUNCTION__,
3056 bcmsdh_cur_sbwad(bus->sdh)));
3057 }
3058
3059 return bcmerror;
3060 }
3061
3062 #ifdef DHD_DEBUG
3063 static int
dhdsdio_readshared(dhd_bus_t * bus,sdpcm_shared_t * sh)3064 dhdsdio_readshared(dhd_bus_t *bus, sdpcm_shared_t *sh)
3065 {
3066 uint32 addr;
3067 int rv, i;
3068 uint32 shaddr = 0;
3069
3070 shaddr = bus->dongle_ram_base + bus->ramsize - 4;
3071 i = 0;
3072 do {
3073 /* Read last word in memory to determine address of sdpcm_shared structure */
3074 if ((rv = dhdsdio_membytes(bus, FALSE, shaddr, (uint8 *)&addr, 4)) < 0)
3075 return rv;
3076
3077 addr = ltoh32(addr);
3078
3079 DHD_INFO(("sdpcm_shared address 0x%08X\n", addr));
3080
3081 /*
3082 * Check if addr is valid.
3083 * NVRAM length at the end of memory should have been overwritten.
3084 */
3085 if (addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff)) {
3086 if ((bus->srmemsize > 0) && (i++ == 0)) {
3087 shaddr -= bus->srmemsize;
3088 } else {
3089 DHD_ERROR(("%s: address (0x%08x) of sdpcm_shared invalid\n",
3090 __FUNCTION__, addr));
3091 return BCME_ERROR;
3092 }
3093 } else
3094 break;
3095 } while (i < 2);
3096
3097 /* Read hndrte_shared structure */
3098 if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)sh, sizeof(sdpcm_shared_t))) < 0)
3099 return rv;
3100
3101 /* Endianness */
3102 sh->flags = ltoh32(sh->flags);
3103 sh->trap_addr = ltoh32(sh->trap_addr);
3104 sh->assert_exp_addr = ltoh32(sh->assert_exp_addr);
3105 sh->assert_file_addr = ltoh32(sh->assert_file_addr);
3106 sh->assert_line = ltoh32(sh->assert_line);
3107 sh->console_addr = ltoh32(sh->console_addr);
3108 sh->msgtrace_addr = ltoh32(sh->msgtrace_addr);
3109
3110 if ((sh->flags & SDPCM_SHARED_VERSION_MASK) == 3 && SDPCM_SHARED_VERSION == 1)
3111 return BCME_OK;
3112
3113 if ((sh->flags & SDPCM_SHARED_VERSION_MASK) != SDPCM_SHARED_VERSION) {
3114 DHD_ERROR(("%s: sdpcm_shared version %d in dhd "
3115 "is different than sdpcm_shared version %d in dongle\n",
3116 __FUNCTION__, SDPCM_SHARED_VERSION,
3117 sh->flags & SDPCM_SHARED_VERSION_MASK));
3118 return BCME_ERROR;
3119 }
3120
3121 return BCME_OK;
3122 }
3123
3124 #define CONSOLE_LINE_MAX 192
3125
3126 static int
dhdsdio_readconsole(dhd_bus_t * bus)3127 dhdsdio_readconsole(dhd_bus_t *bus)
3128 {
3129 dhd_console_t *c = &bus->console;
3130 uint8 line[CONSOLE_LINE_MAX], ch;
3131 uint32 n, idx, addr;
3132 int rv;
3133
3134 /* Don't do anything until FWREADY updates console address */
3135 if (bus->console_addr == 0)
3136 return 0;
3137
3138 if (!KSO_ENAB(bus))
3139 return 0;
3140
3141 /* Read console log struct */
3142 addr = bus->console_addr + OFFSETOF(hndrte_cons_t, log);
3143 if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)&c->log, sizeof(c->log))) < 0)
3144 return rv;
3145
3146 /* Allocate console buffer (one time only) */
3147 if (c->buf == NULL) {
3148 c->bufsize = ltoh32(c->log.buf_size);
3149 if ((c->buf = MALLOC(bus->dhd->osh, c->bufsize)) == NULL)
3150 return BCME_NOMEM;
3151 }
3152
3153 idx = ltoh32(c->log.idx);
3154
3155 /* Protect against corrupt value */
3156 if (idx > c->bufsize)
3157 return BCME_ERROR;
3158
3159 /* Skip reading the console buffer if the index pointer has not moved */
3160 if (idx == c->last)
3161 return BCME_OK;
3162
3163 /* Read the console buffer */
3164 addr = ltoh32(c->log.buf);
3165 if ((rv = dhdsdio_membytes(bus, FALSE, addr, c->buf, c->bufsize)) < 0)
3166 return rv;
3167
3168 while (c->last != idx) {
3169 for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) {
3170 if (c->last == idx) {
3171 /* This would output a partial line. Instead, back up
3172 * the buffer pointer and output this line next time around.
3173 */
3174 if (c->last >= n)
3175 c->last -= n;
3176 else
3177 c->last = c->bufsize - n;
3178 goto break2;
3179 }
3180 ch = c->buf[c->last];
3181 c->last = (c->last + 1) % c->bufsize;
3182 if (ch == '\n')
3183 break;
3184 line[n] = ch;
3185 }
3186
3187 if (n > 0) {
3188 if (line[n - 1] == '\r')
3189 n--;
3190 line[n] = 0;
3191 printf("CONSOLE: %s\n", line);
3192 }
3193 }
3194 break2:
3195
3196 return BCME_OK;
3197 }
3198
3199 static int
dhdsdio_checkdied(dhd_bus_t * bus,char * data,uint size)3200 dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size)
3201 {
3202 int bcmerror = 0;
3203 uint msize = 512;
3204 char *mbuffer = NULL;
3205 char *console_buffer = NULL;
3206 uint maxstrlen = 256;
3207 char *str = NULL;
3208 trap_t tr;
3209 sdpcm_shared_t sdpcm_shared;
3210 struct bcmstrbuf strbuf;
3211 uint32 console_ptr, console_size, console_index;
3212 uint8 line[CONSOLE_LINE_MAX], ch;
3213 uint32 n, i, addr;
3214 int rv;
3215
3216 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3217
3218 if (DHD_NOCHECKDIED_ON())
3219 return 0;
3220
3221 if (data == NULL) {
3222 /*
3223 * Called after a rx ctrl timeout. "data" is NULL.
3224 * allocate memory to trace the trap or assert.
3225 */
3226 size = msize;
3227 mbuffer = data = MALLOC(bus->dhd->osh, msize);
3228 if (mbuffer == NULL) {
3229 DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, msize));
3230 bcmerror = BCME_NOMEM;
3231 goto done;
3232 }
3233 }
3234
3235 if ((str = MALLOC(bus->dhd->osh, maxstrlen)) == NULL) {
3236 DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, maxstrlen));
3237 bcmerror = BCME_NOMEM;
3238 goto done;
3239 }
3240
3241 if ((bcmerror = dhdsdio_readshared(bus, &sdpcm_shared)) < 0)
3242 goto done;
3243
3244 bcm_binit(&strbuf, data, size);
3245
3246 bcm_bprintf(&strbuf, "msgtrace address : 0x%08X\nconsole address : 0x%08X\n",
3247 sdpcm_shared.msgtrace_addr, sdpcm_shared.console_addr);
3248
3249 if ((sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT) == 0) {
3250 /* NOTE: Misspelled assert is intentional - DO NOT FIX.
3251 * (Avoids conflict with real asserts for programmatic parsing of output.)
3252 */
3253 bcm_bprintf(&strbuf, "Assrt not built in dongle\n");
3254 }
3255
3256 if ((sdpcm_shared.flags & (SDPCM_SHARED_ASSERT|SDPCM_SHARED_TRAP)) == 0) {
3257 /* NOTE: Misspelled assert is intentional - DO NOT FIX.
3258 * (Avoids conflict with real asserts for programmatic parsing of output.)
3259 */
3260 bcm_bprintf(&strbuf, "No trap%s in dongle",
3261 (sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT)
3262 ?"/assrt" :"");
3263 } else {
3264 if (sdpcm_shared.flags & SDPCM_SHARED_ASSERT) {
3265 /* Download assert */
3266 bcm_bprintf(&strbuf, "Dongle assert");
3267 if (sdpcm_shared.assert_exp_addr != 0) {
3268 str[0] = '\0';
3269 if ((bcmerror = dhdsdio_membytes(bus, FALSE,
3270 sdpcm_shared.assert_exp_addr,
3271 (uint8 *)str, maxstrlen)) < 0)
3272 goto done;
3273
3274 str[maxstrlen - 1] = '\0';
3275 bcm_bprintf(&strbuf, " expr \"%s\"", str);
3276 }
3277
3278 if (sdpcm_shared.assert_file_addr != 0) {
3279 str[0] = '\0';
3280 if ((bcmerror = dhdsdio_membytes(bus, FALSE,
3281 sdpcm_shared.assert_file_addr,
3282 (uint8 *)str, maxstrlen)) < 0)
3283 goto done;
3284
3285 str[maxstrlen - 1] = '\0';
3286 bcm_bprintf(&strbuf, " file \"%s\"", str);
3287 }
3288
3289 bcm_bprintf(&strbuf, " line %d ", sdpcm_shared.assert_line);
3290 }
3291
3292 if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) {
3293 bus->dhd->dongle_trap_occured = TRUE;
3294 if ((bcmerror = dhdsdio_membytes(bus, FALSE,
3295 sdpcm_shared.trap_addr,
3296 (uint8*)&tr, sizeof(trap_t))) < 0)
3297 goto done;
3298
3299 bcm_bprintf(&strbuf,
3300 "Dongle trap type 0x%x @ epc 0x%x, cpsr 0x%x, spsr 0x%x, sp 0x%x,"
3301 "lp 0x%x, rpc 0x%x Trap offset 0x%x, "
3302 "r0 0x%x, r1 0x%x, r2 0x%x, r3 0x%x, "
3303 "r4 0x%x, r5 0x%x, r6 0x%x, r7 0x%x\n\n",
3304 ltoh32(tr.type), ltoh32(tr.epc), ltoh32(tr.cpsr), ltoh32(tr.spsr),
3305 ltoh32(tr.r13), ltoh32(tr.r14), ltoh32(tr.pc),
3306 ltoh32(sdpcm_shared.trap_addr),
3307 ltoh32(tr.r0), ltoh32(tr.r1), ltoh32(tr.r2), ltoh32(tr.r3),
3308 ltoh32(tr.r4), ltoh32(tr.r5), ltoh32(tr.r6), ltoh32(tr.r7));
3309
3310 addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log);
3311 if ((rv = dhdsdio_membytes(bus, FALSE, addr,
3312 (uint8 *)&console_ptr, sizeof(console_ptr))) < 0)
3313 goto printbuf;
3314
3315 addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log.buf_size);
3316 if ((rv = dhdsdio_membytes(bus, FALSE, addr,
3317 (uint8 *)&console_size, sizeof(console_size))) < 0)
3318 goto printbuf;
3319
3320 addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log.idx);
3321 if ((rv = dhdsdio_membytes(bus, FALSE, addr,
3322 (uint8 *)&console_index, sizeof(console_index))) < 0)
3323 goto printbuf;
3324
3325 console_ptr = ltoh32(console_ptr);
3326 console_size = ltoh32(console_size);
3327 console_index = ltoh32(console_index);
3328
3329 if (console_size > CONSOLE_BUFFER_MAX ||
3330 !(console_buffer = MALLOC(bus->dhd->osh, console_size)))
3331 goto printbuf;
3332
3333 if ((rv = dhdsdio_membytes(bus, FALSE, console_ptr,
3334 (uint8 *)console_buffer, console_size)) < 0)
3335 goto printbuf;
3336
3337 for (i = 0, n = 0; i < console_size; i += n + 1) {
3338 for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) {
3339 ch = console_buffer[(console_index + i + n) % console_size];
3340 if (ch == '\n')
3341 break;
3342 line[n] = ch;
3343 }
3344
3345
3346 if (n > 0) {
3347 if (line[n - 1] == '\r')
3348 n--;
3349 line[n] = 0;
3350 /* Don't use DHD_ERROR macro since we print
3351 * a lot of information quickly. The macro
3352 * will truncate a lot of the printfs
3353 */
3354
3355 if (dhd_msg_level & DHD_ERROR_VAL)
3356 printf("CONSOLE: %s\n", line);
3357 }
3358 }
3359 }
3360 }
3361
3362 printbuf:
3363 if (sdpcm_shared.flags & (SDPCM_SHARED_ASSERT | SDPCM_SHARED_TRAP)) {
3364 DHD_ERROR(("%s: %s\n", __FUNCTION__, strbuf.origbuf));
3365 }
3366
3367
3368 done:
3369 if (mbuffer)
3370 MFREE(bus->dhd->osh, mbuffer, msize);
3371 if (str)
3372 MFREE(bus->dhd->osh, str, maxstrlen);
3373 if (console_buffer)
3374 MFREE(bus->dhd->osh, console_buffer, console_size);
3375
3376 return bcmerror;
3377 }
3378 #endif /* #ifdef DHD_DEBUG */
3379
3380
3381 int
dhdsdio_downloadvars(dhd_bus_t * bus,void * arg,int len)3382 dhdsdio_downloadvars(dhd_bus_t *bus, void *arg, int len)
3383 {
3384 int bcmerror = BCME_OK;
3385
3386 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3387
3388 /* Basic sanity checks */
3389 if (bus->dhd->up) {
3390 bcmerror = BCME_NOTDOWN;
3391 goto err;
3392 }
3393 if (!len) {
3394 bcmerror = BCME_BUFTOOSHORT;
3395 goto err;
3396 }
3397
3398 /* Free the old ones and replace with passed variables */
3399 if (bus->vars)
3400 MFREE(bus->dhd->osh, bus->vars, bus->varsz);
3401
3402 bus->vars = MALLOC(bus->dhd->osh, len);
3403 bus->varsz = bus->vars ? len : 0;
3404 if (bus->vars == NULL) {
3405 bcmerror = BCME_NOMEM;
3406 goto err;
3407 }
3408
3409 /* Copy the passed variables, which should include the terminating double-null */
3410 bcopy(arg, bus->vars, bus->varsz);
3411 err:
3412 return bcmerror;
3413 }
3414
3415 #ifdef DHD_DEBUG
3416
3417 #define CC_PLL_CHIPCTRL_SERIAL_ENAB (1 << 24)
3418 #define CC_CHIPCTRL_JTAG_SEL (1 << 3)
3419 #define CC_CHIPCTRL_GPIO_SEL (0x3)
3420 #define CC_PLL_CHIPCTRL_SERIAL_ENAB_4334 (1 << 28)
3421
3422 static int
dhd_serialconsole(dhd_bus_t * bus,bool set,bool enable,int * bcmerror)3423 dhd_serialconsole(dhd_bus_t *bus, bool set, bool enable, int *bcmerror)
3424 {
3425 int int_val;
3426 uint32 addr, data, uart_enab = 0;
3427 uint32 jtag_sel = CC_CHIPCTRL_JTAG_SEL;
3428 uint32 gpio_sel = CC_CHIPCTRL_GPIO_SEL;
3429
3430 addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr);
3431 data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data);
3432 *bcmerror = 0;
3433
3434 bcmsdh_reg_write(bus->sdh, addr, 4, 1);
3435 if (bcmsdh_regfail(bus->sdh)) {
3436 *bcmerror = BCME_SDIO_ERROR;
3437 return -1;
3438 }
3439 int_val = bcmsdh_reg_read(bus->sdh, data, 4);
3440 if (bcmsdh_regfail(bus->sdh)) {
3441 *bcmerror = BCME_SDIO_ERROR;
3442 return -1;
3443 }
3444 if (bus->sih->chip == BCM4330_CHIP_ID) {
3445 uart_enab = CC_PLL_CHIPCTRL_SERIAL_ENAB;
3446 }
3447 else if (bus->sih->chip == BCM4334_CHIP_ID ||
3448 bus->sih->chip == BCM43340_CHIP_ID ||
3449 bus->sih->chip == BCM43341_CHIP_ID) {
3450 if (enable) {
3451 /* Moved to PMU chipcontrol 1 from 4330 */
3452 int_val &= ~gpio_sel;
3453 int_val |= jtag_sel;
3454 } else {
3455 int_val |= gpio_sel;
3456 int_val &= ~jtag_sel;
3457 }
3458 uart_enab = CC_PLL_CHIPCTRL_SERIAL_ENAB_4334;
3459 }
3460
3461 if (!set)
3462 return (int_val & uart_enab);
3463 if (enable)
3464 int_val |= uart_enab;
3465 else
3466 int_val &= ~uart_enab;
3467 bcmsdh_reg_write(bus->sdh, data, 4, int_val);
3468 if (bcmsdh_regfail(bus->sdh)) {
3469 *bcmerror = BCME_SDIO_ERROR;
3470 return -1;
3471 }
3472 if (bus->sih->chip == BCM4330_CHIP_ID) {
3473 uint32 chipcontrol;
3474 addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol);
3475 chipcontrol = bcmsdh_reg_read(bus->sdh, addr, 4);
3476 chipcontrol &= ~jtag_sel;
3477 if (enable) {
3478 chipcontrol |= jtag_sel;
3479 chipcontrol &= ~gpio_sel;
3480 }
3481 bcmsdh_reg_write(bus->sdh, addr, 4, chipcontrol);
3482 }
3483
3484 return (int_val & uart_enab);
3485 }
3486 #endif
3487
3488 static int
dhdsdio_doiovar(dhd_bus_t * bus,const bcm_iovar_t * vi,uint32 actionid,const char * name,void * params,int plen,void * arg,int len,int val_size)3489 dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const char *name,
3490 void *params, int plen, void *arg, int len, int val_size)
3491 {
3492 int bcmerror = 0;
3493 int32 int_val = 0;
3494 bool bool_val = 0;
3495
3496 DHD_TRACE(("%s: Enter, action %d name %s params %p plen %d arg %p len %d val_size %d\n",
3497 __FUNCTION__, actionid, name, params, plen, arg, len, val_size));
3498
3499 if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0)
3500 goto exit;
3501
3502 if (plen >= (int)sizeof(int_val))
3503 bcopy(params, &int_val, sizeof(int_val));
3504
3505 bool_val = (int_val != 0) ? TRUE : FALSE;
3506
3507
3508 /* Some ioctls use the bus */
3509 dhd_os_sdlock(bus->dhd);
3510
3511 /* Check if dongle is in reset. If so, only allow DEVRESET iovars */
3512 if (bus->dhd->dongle_reset && !(actionid == IOV_SVAL(IOV_DEVRESET) ||
3513 actionid == IOV_GVAL(IOV_DEVRESET))) {
3514 bcmerror = BCME_NOTREADY;
3515 goto exit;
3516 }
3517
3518 /*
3519 * Special handling for keepSdioOn: New SDIO Wake-up Mechanism
3520 */
3521 if ((vi->varid == IOV_KSO) && (IOV_ISSET(actionid))) {
3522 dhdsdio_clk_kso_iovar(bus, bool_val);
3523 goto exit;
3524 } else if ((vi->varid == IOV_DEVSLEEP) && (IOV_ISSET(actionid))) {
3525 {
3526 dhdsdio_clk_devsleep_iovar(bus, bool_val);
3527 if (!SLPAUTO_ENAB(bus) && (bool_val == FALSE) && (bus->ipend)) {
3528 DHD_ERROR(("INT pending in devsleep 1, dpc_sched: %d\n",
3529 bus->dpc_sched));
3530 if (!bus->dpc_sched) {
3531 bus->dpc_sched = TRUE;
3532 dhd_sched_dpc(bus->dhd);
3533 }
3534 }
3535 }
3536 goto exit;
3537 }
3538
3539 /* Handle sleep stuff before any clock mucking */
3540 if (vi->varid == IOV_SLEEP) {
3541 if (IOV_ISSET(actionid)) {
3542 bcmerror = dhdsdio_bussleep(bus, bool_val);
3543 } else {
3544 int_val = (int32)bus->sleeping;
3545 bcopy(&int_val, arg, val_size);
3546 }
3547 goto exit;
3548 }
3549
3550 /* Request clock to allow SDIO accesses */
3551 if (!bus->dhd->dongle_reset) {
3552 BUS_WAKE(bus);
3553 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
3554 }
3555
3556 switch (actionid) {
3557 case IOV_GVAL(IOV_INTR):
3558 int_val = (int32)bus->intr;
3559 bcopy(&int_val, arg, val_size);
3560 break;
3561
3562 case IOV_SVAL(IOV_INTR):
3563 bus->intr = bool_val;
3564 bus->intdis = FALSE;
3565 if (bus->dhd->up) {
3566 if (bus->intr) {
3567 DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__));
3568 bcmsdh_intr_enable(bus->sdh);
3569 } else {
3570 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
3571 bcmsdh_intr_disable(bus->sdh);
3572 }
3573 }
3574 break;
3575
3576 case IOV_GVAL(IOV_POLLRATE):
3577 int_val = (int32)bus->pollrate;
3578 bcopy(&int_val, arg, val_size);
3579 break;
3580
3581 case IOV_SVAL(IOV_POLLRATE):
3582 bus->pollrate = (uint)int_val;
3583 bus->poll = (bus->pollrate != 0);
3584 break;
3585
3586 case IOV_GVAL(IOV_IDLETIME):
3587 int_val = bus->idletime;
3588 bcopy(&int_val, arg, val_size);
3589 break;
3590
3591 case IOV_SVAL(IOV_IDLETIME):
3592 if ((int_val < 0) && (int_val != DHD_IDLE_IMMEDIATE)) {
3593 bcmerror = BCME_BADARG;
3594 } else {
3595 bus->idletime = int_val;
3596 }
3597 break;
3598
3599 case IOV_GVAL(IOV_IDLECLOCK):
3600 int_val = (int32)bus->idleclock;
3601 bcopy(&int_val, arg, val_size);
3602 break;
3603
3604 case IOV_SVAL(IOV_IDLECLOCK):
3605 bus->idleclock = int_val;
3606 break;
3607
3608 case IOV_GVAL(IOV_SD1IDLE):
3609 int_val = (int32)sd1idle;
3610 bcopy(&int_val, arg, val_size);
3611 break;
3612
3613 case IOV_SVAL(IOV_SD1IDLE):
3614 sd1idle = bool_val;
3615 break;
3616
3617
3618 case IOV_SVAL(IOV_MEMBYTES):
3619 case IOV_GVAL(IOV_MEMBYTES):
3620 {
3621 uint32 address;
3622 uint size, dsize;
3623 uint8 *data;
3624
3625 bool set = (actionid == IOV_SVAL(IOV_MEMBYTES));
3626
3627 ASSERT(plen >= 2*sizeof(int));
3628
3629 address = (uint32)int_val;
3630 bcopy((char *)params + sizeof(int_val), &int_val, sizeof(int_val));
3631 size = (uint)int_val;
3632
3633 /* Do some validation */
3634 dsize = set ? plen - (2 * sizeof(int)) : len;
3635 if (dsize < size) {
3636 DHD_ERROR(("%s: error on %s membytes, addr 0x%08x size %d dsize %d\n",
3637 __FUNCTION__, (set ? "set" : "get"), address, size, dsize));
3638 bcmerror = BCME_BADARG;
3639 break;
3640 }
3641
3642 DHD_INFO(("%s: Request to %s %d bytes at address 0x%08x\n", __FUNCTION__,
3643 (set ? "write" : "read"), size, address));
3644
3645 /* check if CR4 */
3646 if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
3647 /*
3648 * If address is start of RAM (i.e. a downloaded image),
3649 * store the reset instruction to be written in 0
3650 */
3651 if (address == bus->dongle_ram_base) {
3652 bus->resetinstr = *(((uint32*)params) + 2);
3653 }
3654 } else {
3655 /* If we know about SOCRAM, check for a fit */
3656 if ((bus->orig_ramsize) &&
3657 ((address > bus->orig_ramsize) || (address + size > bus->orig_ramsize)))
3658 {
3659 uint8 enable, protect, remap;
3660 si_socdevram(bus->sih, FALSE, &enable, &protect, &remap);
3661 if (!enable || protect) {
3662 DHD_ERROR(("%s: ramsize 0x%08x doesn't have %d bytes at 0x%08x\n",
3663 __FUNCTION__, bus->orig_ramsize, size, address));
3664 DHD_ERROR(("%s: socram enable %d, protect %d\n",
3665 __FUNCTION__, enable, protect));
3666 bcmerror = BCME_BADARG;
3667 break;
3668 }
3669
3670 if (!REMAP_ENAB(bus) && (address >= SOCDEVRAM_ARM_ADDR)) {
3671 uint32 devramsize = si_socdevram_size(bus->sih);
3672 if ((address < SOCDEVRAM_ARM_ADDR) ||
3673 (address + size > (SOCDEVRAM_ARM_ADDR + devramsize))) {
3674 DHD_ERROR(("%s: bad address 0x%08x, size 0x%08x\n",
3675 __FUNCTION__, address, size));
3676 DHD_ERROR(("%s: socram range 0x%08x,size 0x%08x\n",
3677 __FUNCTION__, SOCDEVRAM_ARM_ADDR, devramsize));
3678 bcmerror = BCME_BADARG;
3679 break;
3680 }
3681 /* move it such that address is real now */
3682 address -= SOCDEVRAM_ARM_ADDR;
3683 address += SOCDEVRAM_BP_ADDR;
3684 DHD_INFO(("%s: Request to %s %d bytes @ Mapped address 0x%08x\n",
3685 __FUNCTION__, (set ? "write" : "read"), size, address));
3686 } else if (REMAP_ENAB(bus) && REMAP_ISADDR(bus, address) && remap) {
3687 /* Can not access remap region while devram remap bit is set
3688 * ROM content would be returned in this case
3689 */
3690 DHD_ERROR(("%s: Need to disable remap for address 0x%08x\n",
3691 __FUNCTION__, address));
3692 bcmerror = BCME_ERROR;
3693 break;
3694 }
3695 }
3696 }
3697
3698 /* Generate the actual data pointer */
3699 data = set ? (uint8*)params + 2 * sizeof(int): (uint8*)arg;
3700
3701 /* Call to do the transfer */
3702 bcmerror = dhdsdio_membytes(bus, set, address, data, size);
3703
3704 break;
3705 }
3706
3707 case IOV_GVAL(IOV_RAMSIZE):
3708 int_val = (int32)bus->ramsize;
3709 bcopy(&int_val, arg, val_size);
3710 break;
3711
3712 case IOV_GVAL(IOV_RAMSTART):
3713 int_val = (int32)bus->dongle_ram_base;
3714 bcopy(&int_val, arg, val_size);
3715 break;
3716
3717 case IOV_GVAL(IOV_SDIOD_DRIVE):
3718 int_val = (int32)dhd_sdiod_drive_strength;
3719 bcopy(&int_val, arg, val_size);
3720 break;
3721
3722 case IOV_SVAL(IOV_SDIOD_DRIVE):
3723 dhd_sdiod_drive_strength = int_val;
3724 si_sdiod_drive_strength_init(bus->sih, bus->dhd->osh, dhd_sdiod_drive_strength);
3725 break;
3726
3727 case IOV_SVAL(IOV_SET_DOWNLOAD_STATE):
3728 bcmerror = dhdsdio_download_state(bus, bool_val);
3729 break;
3730
3731 case IOV_SVAL(IOV_SOCRAM_STATE):
3732 bcmerror = dhdsdio_download_state(bus, bool_val);
3733 break;
3734
3735 case IOV_SVAL(IOV_VARS):
3736 bcmerror = dhdsdio_downloadvars(bus, arg, len);
3737 break;
3738
3739 case IOV_GVAL(IOV_READAHEAD):
3740 int_val = (int32)dhd_readahead;
3741 bcopy(&int_val, arg, val_size);
3742 break;
3743
3744 case IOV_SVAL(IOV_READAHEAD):
3745 if (bool_val && !dhd_readahead)
3746 bus->nextlen = 0;
3747 dhd_readahead = bool_val;
3748 break;
3749
3750 case IOV_GVAL(IOV_SDRXCHAIN):
3751 int_val = (int32)bus->use_rxchain;
3752 bcopy(&int_val, arg, val_size);
3753 break;
3754
3755 case IOV_SVAL(IOV_SDRXCHAIN):
3756 if (bool_val && !bus->sd_rxchain)
3757 bcmerror = BCME_UNSUPPORTED;
3758 else
3759 bus->use_rxchain = bool_val;
3760 break;
3761 case IOV_GVAL(IOV_ALIGNCTL):
3762 int_val = (int32)dhd_alignctl;
3763 bcopy(&int_val, arg, val_size);
3764 break;
3765
3766 case IOV_SVAL(IOV_ALIGNCTL):
3767 dhd_alignctl = bool_val;
3768 break;
3769
3770 case IOV_GVAL(IOV_SDALIGN):
3771 int_val = DHD_SDALIGN;
3772 bcopy(&int_val, arg, val_size);
3773 break;
3774
3775 #ifdef DHD_DEBUG
3776 case IOV_GVAL(IOV_VARS):
3777 if (bus->varsz < (uint)len)
3778 bcopy(bus->vars, arg, bus->varsz);
3779 else
3780 bcmerror = BCME_BUFTOOSHORT;
3781 break;
3782 #endif /* DHD_DEBUG */
3783
3784 #ifdef DHD_DEBUG
3785 case IOV_GVAL(IOV_SDREG):
3786 {
3787 sdreg_t *sd_ptr;
3788 uint32 addr, size;
3789
3790 sd_ptr = (sdreg_t *)params;
3791
3792 addr = (uintptr)bus->regs + sd_ptr->offset;
3793 size = sd_ptr->func;
3794 int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size);
3795 if (bcmsdh_regfail(bus->sdh))
3796 bcmerror = BCME_SDIO_ERROR;
3797 bcopy(&int_val, arg, sizeof(int32));
3798 break;
3799 }
3800
3801 case IOV_SVAL(IOV_SDREG):
3802 {
3803 sdreg_t *sd_ptr;
3804 uint32 addr, size;
3805
3806 sd_ptr = (sdreg_t *)params;
3807
3808 addr = (uintptr)bus->regs + sd_ptr->offset;
3809 size = sd_ptr->func;
3810 bcmsdh_reg_write(bus->sdh, addr, size, sd_ptr->value);
3811 if (bcmsdh_regfail(bus->sdh))
3812 bcmerror = BCME_SDIO_ERROR;
3813 break;
3814 }
3815
3816 /* Same as above, but offset is not backplane (not SDIO core) */
3817 case IOV_GVAL(IOV_SBREG):
3818 {
3819 sdreg_t sdreg;
3820 uint32 addr, size;
3821
3822 bcopy(params, &sdreg, sizeof(sdreg));
3823
3824 addr = SI_ENUM_BASE + sdreg.offset;
3825 size = sdreg.func;
3826 int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size);
3827 if (bcmsdh_regfail(bus->sdh))
3828 bcmerror = BCME_SDIO_ERROR;
3829 bcopy(&int_val, arg, sizeof(int32));
3830 break;
3831 }
3832
3833 case IOV_SVAL(IOV_SBREG):
3834 {
3835 sdreg_t sdreg;
3836 uint32 addr, size;
3837
3838 bcopy(params, &sdreg, sizeof(sdreg));
3839
3840 addr = SI_ENUM_BASE + sdreg.offset;
3841 size = sdreg.func;
3842 bcmsdh_reg_write(bus->sdh, addr, size, sdreg.value);
3843 if (bcmsdh_regfail(bus->sdh))
3844 bcmerror = BCME_SDIO_ERROR;
3845 break;
3846 }
3847
3848 case IOV_GVAL(IOV_SDCIS):
3849 {
3850 *(char *)arg = 0;
3851
3852 bcmstrcat(arg, "\nFunc 0\n");
3853 bcmsdh_cis_read(bus->sdh, 0x10, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
3854 bcmstrcat(arg, "\nFunc 1\n");
3855 bcmsdh_cis_read(bus->sdh, 0x11, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
3856 bcmstrcat(arg, "\nFunc 2\n");
3857 bcmsdh_cis_read(bus->sdh, 0x12, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
3858 break;
3859 }
3860
3861 case IOV_GVAL(IOV_FORCEEVEN):
3862 int_val = (int32)forcealign;
3863 bcopy(&int_val, arg, val_size);
3864 break;
3865
3866 case IOV_SVAL(IOV_FORCEEVEN):
3867 forcealign = bool_val;
3868 break;
3869
3870 case IOV_GVAL(IOV_TXBOUND):
3871 int_val = (int32)dhd_txbound;
3872 bcopy(&int_val, arg, val_size);
3873 break;
3874
3875 case IOV_SVAL(IOV_TXBOUND):
3876 dhd_txbound = (uint)int_val;
3877 break;
3878
3879 case IOV_GVAL(IOV_RXBOUND):
3880 int_val = (int32)dhd_rxbound;
3881 bcopy(&int_val, arg, val_size);
3882 break;
3883
3884 case IOV_SVAL(IOV_RXBOUND):
3885 dhd_rxbound = (uint)int_val;
3886 break;
3887
3888 case IOV_GVAL(IOV_TXMINMAX):
3889 int_val = (int32)dhd_txminmax;
3890 bcopy(&int_val, arg, val_size);
3891 break;
3892
3893 case IOV_SVAL(IOV_TXMINMAX):
3894 dhd_txminmax = (uint)int_val;
3895 break;
3896
3897 case IOV_GVAL(IOV_SERIALCONS):
3898 int_val = dhd_serialconsole(bus, FALSE, 0, &bcmerror);
3899 if (bcmerror != 0)
3900 break;
3901
3902 bcopy(&int_val, arg, val_size);
3903 break;
3904
3905 case IOV_SVAL(IOV_SERIALCONS):
3906 dhd_serialconsole(bus, TRUE, bool_val, &bcmerror);
3907 break;
3908
3909
3910
3911 #endif /* DHD_DEBUG */
3912
3913
3914 #ifdef SDTEST
3915 case IOV_GVAL(IOV_EXTLOOP):
3916 int_val = (int32)bus->ext_loop;
3917 bcopy(&int_val, arg, val_size);
3918 break;
3919
3920 case IOV_SVAL(IOV_EXTLOOP):
3921 bus->ext_loop = bool_val;
3922 break;
3923
3924 case IOV_GVAL(IOV_PKTGEN):
3925 bcmerror = dhdsdio_pktgen_get(bus, arg);
3926 break;
3927
3928 case IOV_SVAL(IOV_PKTGEN):
3929 bcmerror = dhdsdio_pktgen_set(bus, arg);
3930 break;
3931 #endif /* SDTEST */
3932
3933 #if defined(SDIO_CRC_ERROR_FIX)
3934 case IOV_GVAL(IOV_WATERMARK):
3935 int_val = (int32)watermark;
3936 bcopy(&int_val, arg, val_size);
3937 break;
3938
3939 case IOV_SVAL(IOV_WATERMARK):
3940 watermark = (uint)int_val;
3941 watermark = (watermark > SBSDIO_WATERMARK_MASK) ? SBSDIO_WATERMARK_MASK : watermark;
3942 DHD_ERROR(("Setting watermark as 0x%x.\n", watermark));
3943 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, (uint8)watermark, NULL);
3944 break;
3945
3946 case IOV_GVAL(IOV_MESBUSYCTRL):
3947 int_val = (int32)mesbusyctrl;
3948 bcopy(&int_val, arg, val_size);
3949 break;
3950
3951 case IOV_SVAL(IOV_MESBUSYCTRL):
3952 mesbusyctrl = (uint)int_val;
3953 mesbusyctrl = (mesbusyctrl > SBSDIO_MESBUSYCTRL_MASK)
3954 ? SBSDIO_MESBUSYCTRL_MASK : mesbusyctrl;
3955 DHD_ERROR(("Setting mesbusyctrl as 0x%x.\n", mesbusyctrl));
3956 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL,
3957 ((uint8)mesbusyctrl | 0x80), NULL);
3958 break;
3959 #endif /* SDIO_CRC_ERROR_FIX */
3960
3961
3962 case IOV_GVAL(IOV_DONGLEISOLATION):
3963 int_val = bus->dhd->dongle_isolation;
3964 bcopy(&int_val, arg, val_size);
3965 break;
3966
3967 case IOV_SVAL(IOV_DONGLEISOLATION):
3968 bus->dhd->dongle_isolation = bool_val;
3969 break;
3970
3971 case IOV_SVAL(IOV_DEVRESET):
3972 DHD_TRACE(("%s: Called set IOV_DEVRESET=%d dongle_reset=%d busstate=%d\n",
3973 __FUNCTION__, bool_val, bus->dhd->dongle_reset,
3974 bus->dhd->busstate));
3975
3976 ASSERT(bus->dhd->osh);
3977 /* ASSERT(bus->cl_devid); */
3978
3979 dhd_bus_devreset(bus->dhd, (uint8)bool_val);
3980
3981 break;
3982 #ifdef SOFTAP
3983 case IOV_GVAL(IOV_FWPATH):
3984 {
3985 uint32 fw_path_len;
3986
3987 fw_path_len = strlen(bus->fw_path);
3988 DHD_INFO(("[softap] get fwpath, l=%d\n", len));
3989
3990 if (fw_path_len > len-1) {
3991 bcmerror = BCME_BUFTOOSHORT;
3992 break;
3993 }
3994
3995 if (fw_path_len) {
3996 bcopy(bus->fw_path, arg, fw_path_len);
3997 ((uchar*)arg)[fw_path_len] = 0;
3998 }
3999 break;
4000 }
4001
4002 case IOV_SVAL(IOV_FWPATH):
4003 DHD_INFO(("[softap] set fwpath, idx=%d\n", int_val));
4004
4005 switch (int_val) {
4006 case 1:
4007 bus->fw_path = fw_path; /* ordinary one */
4008 break;
4009 case 2:
4010 bus->fw_path = fw_path2;
4011 break;
4012 default:
4013 bcmerror = BCME_BADARG;
4014 break;
4015 }
4016
4017 DHD_INFO(("[softap] new fw path: %s\n", (bus->fw_path[0] ? bus->fw_path : "NULL")));
4018 break;
4019
4020 #endif /* SOFTAP */
4021 case IOV_GVAL(IOV_DEVRESET):
4022 DHD_TRACE(("%s: Called get IOV_DEVRESET\n", __FUNCTION__));
4023
4024 /* Get its status */
4025 int_val = (bool) bus->dhd->dongle_reset;
4026 bcopy(&int_val, arg, val_size);
4027
4028 break;
4029
4030 case IOV_GVAL(IOV_KSO):
4031 int_val = dhdsdio_sleepcsr_get(bus);
4032 bcopy(&int_val, arg, val_size);
4033 break;
4034
4035 case IOV_GVAL(IOV_DEVCAP):
4036 int_val = dhdsdio_devcap_get(bus);
4037 bcopy(&int_val, arg, val_size);
4038 break;
4039
4040 case IOV_SVAL(IOV_DEVCAP):
4041 dhdsdio_devcap_set(bus, (uint8) int_val);
4042 break;
4043
4044 #ifdef BCMSDIOH_TXGLOM
4045 case IOV_GVAL(IOV_TXGLOMSIZE):
4046 int_val = (int32)bus->glomsize;
4047 bcopy(&int_val, arg, val_size);
4048 break;
4049
4050 case IOV_SVAL(IOV_TXGLOMSIZE):
4051 if (int_val > SDPCM_MAXGLOM_SIZE) {
4052 bcmerror = BCME_ERROR;
4053 } else {
4054 bus->glomsize = (uint)int_val;
4055 }
4056 break;
4057 case IOV_GVAL(IOV_TXGLOMMODE):
4058 int_val = (int32)bus->glom_mode;
4059 bcopy(&int_val, arg, val_size);
4060 break;
4061
4062 case IOV_SVAL(IOV_TXGLOMMODE):
4063 if ((int_val != SDPCM_TXGLOM_CPY) && (int_val != SDPCM_TXGLOM_MDESC)) {
4064 bcmerror = BCME_RANGE;
4065 } else {
4066 if ((bus->glom_mode = bcmsdh_set_mode(bus->sdh, (uint)int_val)) != int_val)
4067 bcmerror = BCME_ERROR;
4068 }
4069 break;
4070 #endif /* BCMSDIOH_TXGLOM */
4071
4072 case IOV_SVAL(IOV_HANGREPORT):
4073 bus->dhd->hang_report = bool_val;
4074 DHD_ERROR(("%s: Set hang_report as %d\n", __FUNCTION__, bus->dhd->hang_report));
4075 break;
4076
4077 case IOV_GVAL(IOV_HANGREPORT):
4078 int_val = (int32)bus->dhd->hang_report;
4079 bcopy(&int_val, arg, val_size);
4080 break;
4081 default:
4082 bcmerror = BCME_UNSUPPORTED;
4083 break;
4084 }
4085
4086 exit:
4087 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
4088 bus->activity = FALSE;
4089 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
4090 }
4091
4092 dhd_os_sdunlock(bus->dhd);
4093
4094 return bcmerror;
4095 }
4096
4097 static int
dhdsdio_write_vars(dhd_bus_t * bus)4098 dhdsdio_write_vars(dhd_bus_t *bus)
4099 {
4100 int bcmerror = 0;
4101 uint32 varsize, phys_size;
4102 uint32 varaddr;
4103 uint8 *vbuffer;
4104 uint32 varsizew;
4105 #ifdef DHD_DEBUG
4106 uint8 *nvram_ularray;
4107 #endif /* DHD_DEBUG */
4108
4109 /* Even if there are no vars are to be written, we still need to set the ramsize. */
4110 varsize = bus->varsz ? ROUNDUP(bus->varsz, 4) : 0;
4111 varaddr = (bus->ramsize - 4) - varsize;
4112
4113 varaddr += bus->dongle_ram_base;
4114
4115 if (bus->vars) {
4116 if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 7)) {
4117 if (((varaddr & 0x3C) == 0x3C) && (varsize > 4)) {
4118 DHD_ERROR(("PR85623WAR in place\n"));
4119 varsize += 4;
4120 varaddr -= 4;
4121 }
4122 }
4123
4124 vbuffer = (uint8 *)MALLOC(bus->dhd->osh, varsize);
4125 if (!vbuffer)
4126 return BCME_NOMEM;
4127
4128 bzero(vbuffer, varsize);
4129 bcopy(bus->vars, vbuffer, bus->varsz);
4130
4131 /* Write the vars list */
4132 bcmerror = dhdsdio_membytes(bus, TRUE, varaddr, vbuffer, varsize);
4133 #ifdef DHD_DEBUG
4134 /* Verify NVRAM bytes */
4135 DHD_INFO(("Compare NVRAM dl & ul; varsize=%d\n", varsize));
4136 nvram_ularray = (uint8*)MALLOC(bus->dhd->osh, varsize);
4137 if (!nvram_ularray)
4138 return BCME_NOMEM;
4139
4140 /* Upload image to verify downloaded contents. */
4141 memset(nvram_ularray, 0xaa, varsize);
4142
4143 /* Read the vars list to temp buffer for comparison */
4144 bcmerror = dhdsdio_membytes(bus, FALSE, varaddr, nvram_ularray, varsize);
4145 if (bcmerror) {
4146 DHD_ERROR(("%s: error %d on reading %d nvram bytes at 0x%08x\n",
4147 __FUNCTION__, bcmerror, varsize, varaddr));
4148 }
4149 /* Compare the org NVRAM with the one read from RAM */
4150 if (memcmp(vbuffer, nvram_ularray, varsize)) {
4151 DHD_ERROR(("%s: Downloaded NVRAM image is corrupted.\n", __FUNCTION__));
4152 } else
4153 DHD_ERROR(("%s: Download, Upload and compare of NVRAM succeeded.\n",
4154 __FUNCTION__));
4155
4156 MFREE(bus->dhd->osh, nvram_ularray, varsize);
4157 #endif /* DHD_DEBUG */
4158
4159 MFREE(bus->dhd->osh, vbuffer, varsize);
4160 }
4161
4162 phys_size = REMAP_ENAB(bus) ? bus->ramsize : bus->orig_ramsize;
4163
4164 phys_size += bus->dongle_ram_base;
4165
4166 /* adjust to the user specified RAM */
4167 DHD_INFO(("Physical memory size: %d, usable memory size: %d\n",
4168 phys_size, bus->ramsize));
4169 DHD_INFO(("Vars are at %d, orig varsize is %d\n",
4170 varaddr, varsize));
4171 varsize = ((phys_size - 4) - varaddr);
4172
4173 /*
4174 * Determine the length token:
4175 * Varsize, converted to words, in lower 16-bits, checksum in upper 16-bits.
4176 */
4177 if (bcmerror) {
4178 varsizew = 0;
4179 } else {
4180 varsizew = varsize / 4;
4181 varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF);
4182 varsizew = htol32(varsizew);
4183 }
4184
4185 DHD_INFO(("New varsize is %d, length token=0x%08x\n", varsize, varsizew));
4186
4187 /* Write the length token to the last word */
4188 bcmerror = dhdsdio_membytes(bus, TRUE, (phys_size - 4),
4189 (uint8*)&varsizew, 4);
4190
4191 return bcmerror;
4192 }
4193
4194 static int
dhdsdio_download_state(dhd_bus_t * bus,bool enter)4195 dhdsdio_download_state(dhd_bus_t *bus, bool enter)
4196 {
4197 uint retries;
4198 int bcmerror = 0;
4199 int foundcr4 = 0;
4200
4201 if (!bus->sih)
4202 return BCME_ERROR;
4203 /* To enter download state, disable ARM and reset SOCRAM.
4204 * To exit download state, simply reset ARM (default is RAM boot).
4205 */
4206 if (enter) {
4207 bus->alp_only = TRUE;
4208
4209 if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) &&
4210 !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) {
4211 if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
4212 foundcr4 = 1;
4213 } else {
4214 DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__));
4215 bcmerror = BCME_ERROR;
4216 goto fail;
4217 }
4218 }
4219
4220 if (!foundcr4) {
4221 si_core_disable(bus->sih, 0);
4222 if (bcmsdh_regfail(bus->sdh)) {
4223 bcmerror = BCME_SDIO_ERROR;
4224 goto fail;
4225 }
4226
4227 if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) {
4228 DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__));
4229 bcmerror = BCME_ERROR;
4230 goto fail;
4231 }
4232
4233 si_core_reset(bus->sih, 0, 0);
4234 if (bcmsdh_regfail(bus->sdh)) {
4235 DHD_ERROR(("%s: Failure trying reset SOCRAM core?\n",
4236 __FUNCTION__));
4237 bcmerror = BCME_SDIO_ERROR;
4238 goto fail;
4239 }
4240
4241 /* Disable remap for download */
4242 if (REMAP_ENAB(bus) && si_socdevram_remap_isenb(bus->sih))
4243 dhdsdio_devram_remap(bus, FALSE);
4244
4245 /* Clear the top bit of memory */
4246 if (bus->ramsize) {
4247 uint32 zeros = 0;
4248 if (dhdsdio_membytes(bus, TRUE, bus->ramsize - 4,
4249 (uint8*)&zeros, 4) < 0) {
4250 bcmerror = BCME_SDIO_ERROR;
4251 goto fail;
4252 }
4253 }
4254 } else {
4255 /* For CR4,
4256 * Halt ARM
4257 * Remove ARM reset
4258 * Read RAM base address [0x18_0000]
4259 * [next] Download firmware
4260 * [done at else] Populate the reset vector
4261 * [done at else] Remove ARM halt
4262 */
4263 /* Halt ARM & remove reset */
4264 si_core_reset(bus->sih, SICF_CPUHALT, SICF_CPUHALT);
4265 }
4266 } else {
4267 if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
4268 if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) {
4269 DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__));
4270 bcmerror = BCME_ERROR;
4271 goto fail;
4272 }
4273
4274 if (!si_iscoreup(bus->sih)) {
4275 DHD_ERROR(("%s: SOCRAM core is down after reset?\n", __FUNCTION__));
4276 bcmerror = BCME_ERROR;
4277 goto fail;
4278 }
4279
4280 if ((bcmerror = dhdsdio_write_vars(bus))) {
4281 DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__));
4282 goto fail;
4283 }
4284
4285 /* Enable remap before ARM reset but after vars.
4286 * No backplane access in remap mode
4287 */
4288 if (REMAP_ENAB(bus) && !si_socdevram_remap_isenb(bus->sih))
4289 dhdsdio_devram_remap(bus, TRUE);
4290
4291 if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) &&
4292 !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) {
4293 DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__));
4294 bcmerror = BCME_ERROR;
4295 goto fail;
4296 }
4297 W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries);
4298
4299
4300 if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) &&
4301 !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) {
4302 DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__));
4303 bcmerror = BCME_ERROR;
4304 goto fail;
4305 }
4306 } else {
4307 /* cr4 has no socram, but tcm's */
4308 /* write vars */
4309 if ((bcmerror = dhdsdio_write_vars(bus))) {
4310 DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__));
4311 goto fail;
4312 }
4313
4314 if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) &&
4315 !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) {
4316 DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__));
4317 bcmerror = BCME_ERROR;
4318 goto fail;
4319 }
4320 W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries);
4321
4322 /* switch back to arm core again */
4323 if (!(si_setcore(bus->sih, ARMCR4_CORE_ID, 0))) {
4324 DHD_ERROR(("%s: Failed to find ARM CR4 core!\n", __FUNCTION__));
4325 bcmerror = BCME_ERROR;
4326 goto fail;
4327 }
4328 /* write address 0 with reset instruction */
4329 bcmerror = dhdsdio_membytes(bus, TRUE, 0,
4330 (uint8 *)&bus->resetinstr, sizeof(bus->resetinstr));
4331
4332 /* now remove reset and halt and continue to run CR4 */
4333 }
4334
4335 si_core_reset(bus->sih, 0, 0);
4336 if (bcmsdh_regfail(bus->sdh)) {
4337 DHD_ERROR(("%s: Failure trying to reset ARM core?\n", __FUNCTION__));
4338 bcmerror = BCME_SDIO_ERROR;
4339 goto fail;
4340 }
4341
4342 /* Allow HT Clock now that the ARM is running. */
4343 bus->alp_only = FALSE;
4344
4345 bus->dhd->busstate = DHD_BUS_LOAD;
4346 }
4347
4348 fail:
4349 /* Always return to SDIOD core */
4350 if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0))
4351 si_setcore(bus->sih, SDIOD_CORE_ID, 0);
4352
4353 return bcmerror;
4354 }
4355
4356 int
dhd_bus_iovar_op(dhd_pub_t * dhdp,const char * name,void * params,int plen,void * arg,int len,bool set)4357 dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name,
4358 void *params, int plen, void *arg, int len, bool set)
4359 {
4360 dhd_bus_t *bus = dhdp->bus;
4361 const bcm_iovar_t *vi = NULL;
4362 int bcmerror = 0;
4363 int val_size;
4364 uint32 actionid;
4365
4366 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4367
4368 ASSERT(name);
4369 ASSERT(len >= 0);
4370
4371 /* Get MUST have return space */
4372 ASSERT(set || (arg && len));
4373
4374 /* Set does NOT take qualifiers */
4375 ASSERT(!set || (!params && !plen));
4376
4377 /* Look up var locally; if not found pass to host driver */
4378 if ((vi = bcm_iovar_lookup(dhdsdio_iovars, name)) == NULL) {
4379 dhd_os_sdlock(bus->dhd);
4380
4381 BUS_WAKE(bus);
4382
4383 /* Turn on clock in case SD command needs backplane */
4384 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
4385
4386 bcmerror = bcmsdh_iovar_op(bus->sdh, name, params, plen, arg, len, set);
4387
4388 /* Check for bus configuration changes of interest */
4389
4390 /* If it was divisor change, read the new one */
4391 if (set && strcmp(name, "sd_divisor") == 0) {
4392 if (bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
4393 &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) {
4394 bus->sd_divisor = -1;
4395 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, name));
4396 } else {
4397 DHD_INFO(("%s: noted %s update, value now %d\n",
4398 __FUNCTION__, name, bus->sd_divisor));
4399 }
4400 }
4401 /* If it was a mode change, read the new one */
4402 if (set && strcmp(name, "sd_mode") == 0) {
4403 if (bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
4404 &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) {
4405 bus->sd_mode = -1;
4406 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, name));
4407 } else {
4408 DHD_INFO(("%s: noted %s update, value now %d\n",
4409 __FUNCTION__, name, bus->sd_mode));
4410 }
4411 }
4412 /* Similar check for blocksize change */
4413 if (set && strcmp(name, "sd_blocksize") == 0) {
4414 int32 fnum = 2;
4415 if (bcmsdh_iovar_op(bus->sdh, "sd_blocksize", &fnum, sizeof(int32),
4416 &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) {
4417 bus->blocksize = 0;
4418 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize"));
4419 } else {
4420 DHD_INFO(("%s: noted %s update, value now %d\n",
4421 __FUNCTION__, "sd_blocksize", bus->blocksize));
4422
4423 if ((bus->sih->chip == BCM4335_CHIP_ID) ||
4424 (bus->sih->chip == BCM4339_CHIP_ID))
4425 dhd_overflow_war(bus);
4426 }
4427 }
4428 bus->roundup = MIN(max_roundup, bus->blocksize);
4429
4430 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
4431 bus->activity = FALSE;
4432 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
4433 }
4434
4435 dhd_os_sdunlock(bus->dhd);
4436 goto exit;
4437 }
4438
4439 DHD_CTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__,
4440 name, (set ? "set" : "get"), len, plen));
4441
4442 /* set up 'params' pointer in case this is a set command so that
4443 * the convenience int and bool code can be common to set and get
4444 */
4445 if (params == NULL) {
4446 params = arg;
4447 plen = len;
4448 }
4449
4450 if (vi->type == IOVT_VOID)
4451 val_size = 0;
4452 else if (vi->type == IOVT_BUFFER)
4453 val_size = len;
4454 else
4455 /* all other types are integer sized */
4456 val_size = sizeof(int);
4457
4458 actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
4459 bcmerror = dhdsdio_doiovar(bus, vi, actionid, name, params, plen, arg, len, val_size);
4460
4461 exit:
4462 return bcmerror;
4463 }
4464
4465 void
dhd_bus_stop(struct dhd_bus * bus,bool enforce_mutex)4466 dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex)
4467 {
4468 osl_t *osh;
4469 uint32 local_hostintmask;
4470 uint8 saveclk;
4471 uint retries;
4472 int err;
4473 if (!bus->dhd)
4474 return;
4475
4476 osh = bus->dhd->osh;
4477 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4478
4479 bcmsdh_waitlockfree(NULL);
4480
4481 if (enforce_mutex)
4482 dhd_os_sdlock(bus->dhd);
4483
4484 if ((bus->dhd->busstate == DHD_BUS_DOWN) || bus->dhd->hang_was_sent) {
4485 /* if Firmware already hangs disbale any interrupt */
4486 bus->dhd->busstate = DHD_BUS_DOWN;
4487 bus->hostintmask = 0;
4488 bcmsdh_intr_disable(bus->sdh);
4489 } else {
4490
4491 BUS_WAKE(bus);
4492
4493 /* Change our idea of bus state */
4494 bus->dhd->busstate = DHD_BUS_DOWN;
4495
4496 if (KSO_ENAB(bus)) {
4497
4498 /* Enable clock for device interrupts */
4499 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
4500
4501 /* Disable and clear interrupts at the chip level also */
4502 W_SDREG(0, &bus->regs->hostintmask, retries);
4503 local_hostintmask = bus->hostintmask;
4504 bus->hostintmask = 0;
4505
4506 /* Force clocks on backplane to be sure F2 interrupt propagates */
4507 saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
4508 if (!err) {
4509 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
4510 (saveclk | SBSDIO_FORCE_HT), &err);
4511 }
4512 if (err) {
4513 DHD_ERROR(("%s: Failed to force clock for F2: err %d\n",
4514 __FUNCTION__, err));
4515 }
4516
4517 /* Turn off the bus (F2), free any pending packets */
4518 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
4519 bcmsdh_intr_disable(bus->sdh);
4520 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL);
4521
4522 /* Clear any pending interrupts now that F2 is disabled */
4523 W_SDREG(local_hostintmask, &bus->regs->intstatus, retries);
4524 }
4525
4526 /* Turn off the backplane clock (only) */
4527 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
4528 }
4529
4530 /* Clear the data packet queues */
4531 pktq_flush(osh, &bus->txq, TRUE, NULL, 0);
4532
4533 /* Clear any held glomming stuff */
4534 if (bus->glomd)
4535 PKTFREE(osh, bus->glomd, FALSE);
4536
4537 if (bus->glom)
4538 PKTFREE(osh, bus->glom, FALSE);
4539
4540 bus->glom = bus->glomd = NULL;
4541
4542 /* Clear rx control and wake any waiters */
4543 bus->rxlen = 0;
4544 dhd_os_ioctl_resp_wake(bus->dhd);
4545
4546 /* Reset some F2 state stuff */
4547 bus->rxskip = FALSE;
4548 bus->tx_seq = bus->rx_seq = 0;
4549
4550 bus->tx_max = 4;
4551
4552 if (enforce_mutex)
4553 dhd_os_sdunlock(bus->dhd);
4554 }
4555
4556 #ifdef BCMSDIOH_TXGLOM
4557 void
dhd_txglom_enable(dhd_pub_t * dhdp,bool enable)4558 dhd_txglom_enable(dhd_pub_t *dhdp, bool enable)
4559 {
4560 dhd_bus_t *bus = dhdp->bus;
4561
4562 char buf[256];
4563 uint32 rxglom;
4564 int32 ret;
4565
4566 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4567
4568 if (enable) {
4569 rxglom = 1;
4570 memset(buf, 0, sizeof(buf));
4571 bcm_mkiovar("bus:rxglom",
4572 (void *)&rxglom,
4573 4, buf, sizeof(buf));
4574 ret = dhd_wl_ioctl_cmd(dhdp,
4575 WLC_SET_VAR, buf,
4576 sizeof(buf), TRUE, 0);
4577 if (!(ret < 0)) {
4578 bus->glom_enable = TRUE;
4579 }
4580 } else {
4581 bus->glom_enable = FALSE;
4582 }
4583 }
4584 #endif /* BCMSDIOH_TXGLOM */
4585
4586 int
dhd_bus_init(dhd_pub_t * dhdp,bool enforce_mutex)4587 dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex)
4588 {
4589 dhd_bus_t *bus = dhdp->bus;
4590 dhd_timeout_t tmo;
4591 uint retries = 0;
4592 uint8 ready, enable;
4593 int err, ret = 0;
4594 uint8 saveclk;
4595
4596 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4597
4598 ASSERT(bus->dhd);
4599 if (!bus->dhd)
4600 return 0;
4601
4602 if (enforce_mutex)
4603 dhd_os_sdlock(bus->dhd);
4604
4605 /* Make sure backplane clock is on, needed to generate F2 interrupt */
4606 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
4607 if (bus->clkstate != CLK_AVAIL) {
4608 DHD_ERROR(("%s: clock state is wrong. state = %d\n", __FUNCTION__, bus->clkstate));
4609 ret = -1;
4610 goto exit;
4611 }
4612
4613
4614 /* Force clocks on backplane to be sure F2 interrupt propagates */
4615 saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
4616 if (!err) {
4617 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
4618 (saveclk | SBSDIO_FORCE_HT), &err);
4619 }
4620 if (err) {
4621 DHD_ERROR(("%s: Failed to force clock for F2: err %d\n", __FUNCTION__, err));
4622 ret = -1;
4623 goto exit;
4624 }
4625
4626 /* Enable function 2 (frame transfers) */
4627 W_SDREG((SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT),
4628 &bus->regs->tosbmailboxdata, retries);
4629 enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2);
4630
4631 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL);
4632
4633 /* Give the dongle some time to do its thing and set IOR2 */
4634 dhd_timeout_start(&tmo, DHD_WAIT_F2RDY * 1000);
4635
4636 ready = 0;
4637 while (ready != enable && !dhd_timeout_expired(&tmo))
4638 ready = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IORDY, NULL);
4639
4640 DHD_ERROR(("%s: enable 0x%02x, ready 0x%02x (waited %uus)\n",
4641 __FUNCTION__, enable, ready, tmo.elapsed));
4642
4643
4644 /* If F2 successfully enabled, set core and enable interrupts */
4645 if (ready == enable) {
4646 /* Make sure we're talking to the core. */
4647 if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0)))
4648 bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0);
4649 ASSERT(bus->regs != NULL);
4650
4651 /* Set up the interrupt mask and enable interrupts */
4652 bus->hostintmask = HOSTINTMASK;
4653 /* corerev 4 could use the newer interrupt logic to detect the frames */
4654 if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 4) &&
4655 (bus->rxint_mode != SDIO_DEVICE_HMB_RXINT)) {
4656 bus->hostintmask &= ~I_HMB_FRAME_IND;
4657 bus->hostintmask |= I_XMTDATA_AVAIL;
4658 }
4659 W_SDREG(bus->hostintmask, &bus->regs->hostintmask, retries);
4660 #ifdef SDIO_CRC_ERROR_FIX
4661 if (bus->blocksize < 512) {
4662 mesbusyctrl = watermark = bus->blocksize / 4;
4663 }
4664 #endif /* SDIO_CRC_ERROR_FIX */
4665 if (!((bus->sih->chip == BCM4335_CHIP_ID) ||
4666 (bus->sih->chip == BCM4339_CHIP_ID))) {
4667 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK,
4668 (uint8)watermark, &err);
4669 }
4670 #ifdef SDIO_CRC_ERROR_FIX
4671 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL,
4672 (uint8)mesbusyctrl|0x80, &err);
4673 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL,
4674 SBSDIO_DEVCTL_EN_F2_BLK_WATERMARK, NULL);
4675 #endif /* SDIO_CRC_ERROR_FIX */
4676
4677 /* Set bus state according to enable result */
4678 dhdp->busstate = DHD_BUS_DATA;
4679
4680 /* bcmsdh_intr_unmask(bus->sdh); */
4681
4682 bus->intdis = FALSE;
4683 if (bus->intr) {
4684 DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__));
4685 bcmsdh_intr_enable(bus->sdh);
4686 } else {
4687 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
4688 bcmsdh_intr_disable(bus->sdh);
4689 }
4690
4691 }
4692
4693
4694 else {
4695 /* Disable F2 again */
4696 enable = SDIO_FUNC_ENABLE_1;
4697 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL);
4698 }
4699
4700 if (dhdsdio_sr_cap(bus)) {
4701 dhdsdio_sr_init(bus);
4702 /* Masking the chip active interrupt permanantly */
4703 bus->hostintmask &= ~I_CHIPACTIVE;
4704 W_SDREG(bus->hostintmask, &bus->regs->hostintmask, retries);
4705 DHD_INFO(("%s: disable I_CHIPACTIVE in hostintmask[0x%08x]\n",
4706 __FUNCTION__, bus->hostintmask));
4707 }
4708 else
4709 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1,
4710 SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err);
4711
4712 /* If we didn't come up, turn off backplane clock */
4713 if (dhdp->busstate != DHD_BUS_DATA)
4714 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
4715
4716 exit:
4717 if (enforce_mutex)
4718 dhd_os_sdunlock(bus->dhd);
4719
4720 return ret;
4721 }
4722
4723 static void
dhdsdio_rxfail(dhd_bus_t * bus,bool abort,bool rtx)4724 dhdsdio_rxfail(dhd_bus_t *bus, bool abort, bool rtx)
4725 {
4726 bcmsdh_info_t *sdh = bus->sdh;
4727 sdpcmd_regs_t *regs = bus->regs;
4728 uint retries = 0;
4729 uint16 lastrbc;
4730 uint8 hi, lo;
4731 int err;
4732
4733 DHD_ERROR(("%s: %sterminate frame%s\n", __FUNCTION__,
4734 (abort ? "abort command, " : ""), (rtx ? ", send NAK" : "")));
4735
4736 if (!KSO_ENAB(bus)) {
4737 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
4738 return;
4739 }
4740
4741 if (abort) {
4742 bcmsdh_abort(sdh, SDIO_FUNC_2);
4743 }
4744
4745 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, SFC_RF_TERM, &err);
4746 if (err) {
4747 DHD_ERROR(("%s: SBSDIO_FUNC1_FRAMECTRL cmd err\n", __FUNCTION__));
4748 goto fail;
4749 }
4750 bus->f1regdata++;
4751
4752 /* Wait until the packet has been flushed (device/FIFO stable) */
4753 for (lastrbc = retries = 0xffff; retries > 0; retries--) {
4754 hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCHI, NULL);
4755 lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCLO, &err);
4756 if (err) {
4757 DHD_ERROR(("%s: SBSDIO_FUNC1_RFAMEBCLO cmd err\n", __FUNCTION__));
4758 goto fail;
4759 }
4760
4761 bus->f1regdata += 2;
4762
4763 if ((hi == 0) && (lo == 0))
4764 break;
4765
4766 if ((hi > (lastrbc >> 8)) && (lo > (lastrbc & 0x00ff))) {
4767 DHD_ERROR(("%s: count growing: last 0x%04x now 0x%04x\n",
4768 __FUNCTION__, lastrbc, ((hi << 8) + lo)));
4769 }
4770 lastrbc = (hi << 8) + lo;
4771 }
4772
4773 if (!retries) {
4774 DHD_ERROR(("%s: count never zeroed: last 0x%04x\n", __FUNCTION__, lastrbc));
4775 } else {
4776 DHD_INFO(("%s: flush took %d iterations\n", __FUNCTION__, (0xffff - retries)));
4777 }
4778
4779 if (rtx) {
4780 bus->rxrtx++;
4781 W_SDREG(SMB_NAK, ®s->tosbmailbox, retries);
4782 bus->f1regdata++;
4783 if (retries <= retry_limit) {
4784 bus->rxskip = TRUE;
4785 }
4786 }
4787
4788 /* Clear partial in any case */
4789 bus->nextlen = 0;
4790
4791 fail:
4792 /* If we can't reach the device, signal failure */
4793 if (err || bcmsdh_regfail(sdh))
4794 bus->dhd->busstate = DHD_BUS_DOWN;
4795 }
4796
4797 static void
dhdsdio_read_control(dhd_bus_t * bus,uint8 * hdr,uint len,uint doff)4798 dhdsdio_read_control(dhd_bus_t *bus, uint8 *hdr, uint len, uint doff)
4799 {
4800 bcmsdh_info_t *sdh = bus->sdh;
4801 uint rdlen, pad;
4802
4803 int sdret;
4804
4805 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4806
4807 /* Control data already received in aligned rxctl */
4808 if ((bus->bus == SPI_BUS) && (!bus->usebufpool))
4809 goto gotpkt;
4810
4811 ASSERT(bus->rxbuf);
4812 /* Set rxctl for frame (w/optional alignment) */
4813 bus->rxctl = bus->rxbuf;
4814 if (dhd_alignctl) {
4815 bus->rxctl += firstread;
4816 if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN)))
4817 bus->rxctl += (DHD_SDALIGN - pad);
4818 bus->rxctl -= firstread;
4819 }
4820 ASSERT(bus->rxctl >= bus->rxbuf);
4821
4822 /* Copy the already-read portion over */
4823 bcopy(hdr, bus->rxctl, firstread);
4824 if (len <= firstread)
4825 goto gotpkt;
4826
4827 /* Copy the full data pkt in gSPI case and process ioctl. */
4828 if (bus->bus == SPI_BUS) {
4829 bcopy(hdr, bus->rxctl, len);
4830 goto gotpkt;
4831 }
4832
4833 /* Raise rdlen to next SDIO block to avoid tail command */
4834 rdlen = len - firstread;
4835 if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
4836 pad = bus->blocksize - (rdlen % bus->blocksize);
4837 if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
4838 ((len + pad) < bus->dhd->maxctl))
4839 rdlen += pad;
4840 } else if (rdlen % DHD_SDALIGN) {
4841 rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
4842 }
4843
4844 /* Satisfy length-alignment requirements */
4845 if (forcealign && (rdlen & (ALIGNMENT - 1)))
4846 rdlen = ROUNDUP(rdlen, ALIGNMENT);
4847
4848 /* Drop if the read is too big or it exceeds our maximum */
4849 if ((rdlen + firstread) > bus->dhd->maxctl) {
4850 DHD_ERROR(("%s: %d-byte control read exceeds %d-byte buffer\n",
4851 __FUNCTION__, rdlen, bus->dhd->maxctl));
4852 bus->dhd->rx_errors++;
4853 dhdsdio_rxfail(bus, FALSE, FALSE);
4854 goto done;
4855 }
4856
4857 if ((len - doff) > bus->dhd->maxctl) {
4858 DHD_ERROR(("%s: %d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n",
4859 __FUNCTION__, len, (len - doff), bus->dhd->maxctl));
4860 bus->dhd->rx_errors++; bus->rx_toolong++;
4861 dhdsdio_rxfail(bus, FALSE, FALSE);
4862 goto done;
4863 }
4864
4865
4866 /* Read remainder of frame body into the rxctl buffer */
4867 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
4868 (bus->rxctl + firstread), rdlen, NULL, NULL, NULL);
4869 bus->f2rxdata++;
4870 ASSERT(sdret != BCME_PENDING);
4871
4872 /* Control frame failures need retransmission */
4873 if (sdret < 0) {
4874 DHD_ERROR(("%s: read %d control bytes failed: %d\n", __FUNCTION__, rdlen, sdret));
4875 bus->rxc_errors++; /* dhd.rx_ctlerrs is higher level */
4876 dhdsdio_rxfail(bus, TRUE, TRUE);
4877 goto done;
4878 }
4879
4880 gotpkt:
4881
4882 #ifdef DHD_DEBUG
4883 if (DHD_BYTES_ON() && DHD_CTL_ON()) {
4884 prhex("RxCtrl", bus->rxctl, len);
4885 }
4886 #endif
4887
4888 /* Point to valid data and indicate its length */
4889 bus->rxctl += doff;
4890 bus->rxlen = len - doff;
4891
4892 done:
4893 /* Awake any waiters */
4894 dhd_os_ioctl_resp_wake(bus->dhd);
4895 }
4896 int
4897 dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf, uint reorder_info_len,
4898 void **pkt, uint32 *pkt_count);
4899
4900 static uint8
dhdsdio_rxglom(dhd_bus_t * bus,uint8 rxseq)4901 dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq)
4902 {
4903 uint16 dlen, totlen;
4904 uint8 *dptr, num = 0;
4905
4906 uint16 sublen, check;
4907 void *pfirst, *plast, *pnext;
4908 void * list_tail[DHD_MAX_IFS] = { NULL };
4909 void * list_head[DHD_MAX_IFS] = { NULL };
4910 uint8 idx;
4911 osl_t *osh = bus->dhd->osh;
4912
4913 int errcode;
4914 uint8 chan, seq, doff, sfdoff;
4915 uint8 txmax;
4916 uchar reorder_info_buf[WLHOST_REORDERDATA_TOTLEN];
4917 uint reorder_info_len;
4918
4919 int ifidx = 0;
4920 bool usechain = bus->use_rxchain;
4921
4922 /* If packets, issue read(s) and send up packet chain */
4923 /* Return sequence numbers consumed? */
4924
4925 DHD_TRACE(("dhdsdio_rxglom: start: glomd %p glom %p\n", bus->glomd, bus->glom));
4926
4927 /* If there's a descriptor, generate the packet chain */
4928 if (bus->glomd) {
4929 dhd_os_sdlock_rxq(bus->dhd);
4930
4931 pfirst = plast = pnext = NULL;
4932 dlen = (uint16)PKTLEN(osh, bus->glomd);
4933 dptr = PKTDATA(osh, bus->glomd);
4934 if (!dlen || (dlen & 1)) {
4935 DHD_ERROR(("%s: bad glomd len (%d), ignore descriptor\n",
4936 __FUNCTION__, dlen));
4937 dlen = 0;
4938 }
4939
4940 for (totlen = num = 0; dlen; num++) {
4941 /* Get (and move past) next length */
4942 sublen = ltoh16_ua(dptr);
4943 dlen -= sizeof(uint16);
4944 dptr += sizeof(uint16);
4945 if ((sublen < SDPCM_HDRLEN_RX) ||
4946 ((num == 0) && (sublen < (2 * SDPCM_HDRLEN_RX)))) {
4947 DHD_ERROR(("%s: descriptor len %d bad: %d\n",
4948 __FUNCTION__, num, sublen));
4949 pnext = NULL;
4950 break;
4951 }
4952 if (sublen % DHD_SDALIGN) {
4953 DHD_ERROR(("%s: sublen %d not a multiple of %d\n",
4954 __FUNCTION__, sublen, DHD_SDALIGN));
4955 usechain = FALSE;
4956 }
4957 totlen += sublen;
4958
4959 /* For last frame, adjust read len so total is a block multiple */
4960 if (!dlen) {
4961 sublen += (ROUNDUP(totlen, bus->blocksize) - totlen);
4962 totlen = ROUNDUP(totlen, bus->blocksize);
4963 }
4964
4965 /* Allocate/chain packet for next subframe */
4966 if ((pnext = PKTGET(osh, sublen + DHD_SDALIGN, FALSE)) == NULL) {
4967 DHD_ERROR(("%s: PKTGET failed, num %d len %d\n",
4968 __FUNCTION__, num, sublen));
4969 break;
4970 }
4971 ASSERT(!PKTLINK(pnext));
4972 if (!pfirst) {
4973 ASSERT(!plast);
4974 pfirst = plast = pnext;
4975 } else {
4976 ASSERT(plast);
4977 PKTSETNEXT(osh, plast, pnext);
4978 plast = pnext;
4979 }
4980
4981 /* Adhere to start alignment requirements */
4982 PKTALIGN(osh, pnext, sublen, DHD_SDALIGN);
4983 }
4984
4985 /* If all allocations succeeded, save packet chain in bus structure */
4986 if (pnext) {
4987 DHD_GLOM(("%s: allocated %d-byte packet chain for %d subframes\n",
4988 __FUNCTION__, totlen, num));
4989 if (DHD_GLOM_ON() && bus->nextlen) {
4990 if (totlen != bus->nextlen) {
4991 DHD_GLOM(("%s: glomdesc mismatch: nextlen %d glomdesc %d "
4992 "rxseq %d\n", __FUNCTION__, bus->nextlen,
4993 totlen, rxseq));
4994 }
4995 }
4996 bus->glom = pfirst;
4997 pfirst = pnext = NULL;
4998 } else {
4999 if (pfirst)
5000 PKTFREE(osh, pfirst, FALSE);
5001 bus->glom = NULL;
5002 num = 0;
5003 }
5004
5005 /* Done with descriptor packet */
5006 PKTFREE(osh, bus->glomd, FALSE);
5007 bus->glomd = NULL;
5008 bus->nextlen = 0;
5009
5010 dhd_os_sdunlock_rxq(bus->dhd);
5011 }
5012
5013 /* Ok -- either we just generated a packet chain, or had one from before */
5014 if (bus->glom) {
5015 if (DHD_GLOM_ON()) {
5016 DHD_GLOM(("%s: attempt superframe read, packet chain:\n", __FUNCTION__));
5017 for (pnext = bus->glom; pnext; pnext = PKTNEXT(osh, pnext)) {
5018 DHD_GLOM((" %p: %p len 0x%04x (%d)\n",
5019 pnext, (uint8*)PKTDATA(osh, pnext),
5020 PKTLEN(osh, pnext), PKTLEN(osh, pnext)));
5021 }
5022 }
5023
5024 pfirst = bus->glom;
5025 dlen = (uint16)pkttotlen(osh, pfirst);
5026
5027 /* Do an SDIO read for the superframe. Configurable iovar to
5028 * read directly into the chained packet, or allocate a large
5029 * packet and and copy into the chain.
5030 */
5031 if (usechain) {
5032 errcode = dhd_bcmsdh_recv_buf(bus,
5033 bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2,
5034 F2SYNC, (uint8*)PKTDATA(osh, pfirst),
5035 dlen, pfirst, NULL, NULL);
5036 } else if (bus->dataptr) {
5037 errcode = dhd_bcmsdh_recv_buf(bus,
5038 bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2,
5039 F2SYNC, bus->dataptr,
5040 dlen, NULL, NULL, NULL);
5041 sublen = (uint16)pktfrombuf(osh, pfirst, 0, dlen, bus->dataptr);
5042 if (sublen != dlen) {
5043 DHD_ERROR(("%s: FAILED TO COPY, dlen %d sublen %d\n",
5044 __FUNCTION__, dlen, sublen));
5045 errcode = -1;
5046 }
5047 pnext = NULL;
5048 } else {
5049 DHD_ERROR(("COULDN'T ALLOC %d-BYTE GLOM, FORCE FAILURE\n", dlen));
5050 errcode = -1;
5051 }
5052 bus->f2rxdata++;
5053 ASSERT(errcode != BCME_PENDING);
5054
5055 /* On failure, kill the superframe, allow a couple retries */
5056 if (errcode < 0) {
5057 DHD_ERROR(("%s: glom read of %d bytes failed: %d\n",
5058 __FUNCTION__, dlen, errcode));
5059 bus->dhd->rx_errors++;
5060
5061 if (bus->glomerr++ < 3) {
5062 dhdsdio_rxfail(bus, TRUE, TRUE);
5063 } else {
5064 bus->glomerr = 0;
5065 dhdsdio_rxfail(bus, TRUE, FALSE);
5066 dhd_os_sdlock_rxq(bus->dhd);
5067 PKTFREE(osh, bus->glom, FALSE);
5068 dhd_os_sdunlock_rxq(bus->dhd);
5069 bus->rxglomfail++;
5070 bus->glom = NULL;
5071 }
5072 return 0;
5073 }
5074
5075 #ifdef DHD_DEBUG
5076 if (DHD_GLOM_ON()) {
5077 prhex("SUPERFRAME", PKTDATA(osh, pfirst),
5078 MIN(PKTLEN(osh, pfirst), 48));
5079 }
5080 #endif
5081
5082
5083 /* Validate the superframe header */
5084 dptr = (uint8 *)PKTDATA(osh, pfirst);
5085 sublen = ltoh16_ua(dptr);
5086 check = ltoh16_ua(dptr + sizeof(uint16));
5087
5088 chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
5089 seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
5090 bus->nextlen = dptr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
5091 if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
5092 DHD_INFO(("%s: got frame w/nextlen too large (%d) seq %d\n",
5093 __FUNCTION__, bus->nextlen, seq));
5094 bus->nextlen = 0;
5095 }
5096 doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
5097 txmax = SDPCM_WINDOW_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
5098
5099 errcode = 0;
5100 if ((uint16)~(sublen^check)) {
5101 DHD_ERROR(("%s (superframe): HW hdr error: len/check 0x%04x/0x%04x\n",
5102 __FUNCTION__, sublen, check));
5103 errcode = -1;
5104 } else if (ROUNDUP(sublen, bus->blocksize) != dlen) {
5105 DHD_ERROR(("%s (superframe): len 0x%04x, rounded 0x%04x, expect 0x%04x\n",
5106 __FUNCTION__, sublen, ROUNDUP(sublen, bus->blocksize), dlen));
5107 errcode = -1;
5108 } else if (SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]) != SDPCM_GLOM_CHANNEL) {
5109 DHD_ERROR(("%s (superframe): bad channel %d\n", __FUNCTION__,
5110 SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN])));
5111 errcode = -1;
5112 } else if (SDPCM_GLOMDESC(&dptr[SDPCM_FRAMETAG_LEN])) {
5113 DHD_ERROR(("%s (superframe): got second descriptor?\n", __FUNCTION__));
5114 errcode = -1;
5115 } else if ((doff < SDPCM_HDRLEN_RX) ||
5116 (doff > (PKTLEN(osh, pfirst) - SDPCM_HDRLEN_RX))) {
5117 DHD_ERROR(("%s (superframe): Bad data offset %d: HW %d pkt %d min %d\n",
5118 __FUNCTION__, doff, sublen, PKTLEN(osh, pfirst),
5119 SDPCM_HDRLEN_RX));
5120 errcode = -1;
5121 }
5122
5123 /* Check sequence number of superframe SW header */
5124 if (rxseq != seq) {
5125 DHD_INFO(("%s: (superframe) rx_seq %d, expected %d\n",
5126 __FUNCTION__, seq, rxseq));
5127 bus->rx_badseq++;
5128 rxseq = seq;
5129 }
5130
5131 /* Check window for sanity */
5132 if ((uint8)(txmax - bus->tx_seq) > 0x40) {
5133 DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
5134 __FUNCTION__, txmax, bus->tx_seq));
5135 txmax = bus->tx_max;
5136 }
5137 bus->tx_max = txmax;
5138
5139 /* Remove superframe header, remember offset */
5140 PKTPULL(osh, pfirst, doff);
5141 sfdoff = doff;
5142
5143 /* Validate all the subframe headers */
5144 for (num = 0, pnext = pfirst; pnext && !errcode;
5145 num++, pnext = PKTNEXT(osh, pnext)) {
5146 dptr = (uint8 *)PKTDATA(osh, pnext);
5147 dlen = (uint16)PKTLEN(osh, pnext);
5148 sublen = ltoh16_ua(dptr);
5149 check = ltoh16_ua(dptr + sizeof(uint16));
5150 chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
5151 doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
5152 #ifdef DHD_DEBUG
5153 if (DHD_GLOM_ON()) {
5154 prhex("subframe", dptr, 32);
5155 }
5156 #endif
5157
5158 if ((uint16)~(sublen^check)) {
5159 DHD_ERROR(("%s (subframe %d): HW hdr error: "
5160 "len/check 0x%04x/0x%04x\n",
5161 __FUNCTION__, num, sublen, check));
5162 errcode = -1;
5163 } else if ((sublen > dlen) || (sublen < SDPCM_HDRLEN_RX)) {
5164 DHD_ERROR(("%s (subframe %d): length mismatch: "
5165 "len 0x%04x, expect 0x%04x\n",
5166 __FUNCTION__, num, sublen, dlen));
5167 errcode = -1;
5168 } else if ((chan != SDPCM_DATA_CHANNEL) &&
5169 (chan != SDPCM_EVENT_CHANNEL)) {
5170 DHD_ERROR(("%s (subframe %d): bad channel %d\n",
5171 __FUNCTION__, num, chan));
5172 errcode = -1;
5173 } else if ((doff < SDPCM_HDRLEN_RX) || (doff > sublen)) {
5174 DHD_ERROR(("%s (subframe %d): Bad data offset %d: HW %d min %d\n",
5175 __FUNCTION__, num, doff, sublen, SDPCM_HDRLEN_RX));
5176 errcode = -1;
5177 }
5178 }
5179
5180 if (errcode) {
5181 /* Terminate frame on error, request a couple retries */
5182 if (bus->glomerr++ < 3) {
5183 /* Restore superframe header space */
5184 PKTPUSH(osh, pfirst, sfdoff);
5185 dhdsdio_rxfail(bus, TRUE, TRUE);
5186 } else {
5187 bus->glomerr = 0;
5188 dhdsdio_rxfail(bus, TRUE, FALSE);
5189 dhd_os_sdlock_rxq(bus->dhd);
5190 PKTFREE(osh, bus->glom, FALSE);
5191 dhd_os_sdunlock_rxq(bus->dhd);
5192 bus->rxglomfail++;
5193 bus->glom = NULL;
5194 }
5195 bus->nextlen = 0;
5196 return 0;
5197 }
5198
5199 /* Basic SD framing looks ok - process each packet (header) */
5200 bus->glom = NULL;
5201 plast = NULL;
5202
5203 dhd_os_sdlock_rxq(bus->dhd);
5204 for (num = 0; pfirst; rxseq++, pfirst = pnext) {
5205 pnext = PKTNEXT(osh, pfirst);
5206 PKTSETNEXT(osh, pfirst, NULL);
5207
5208 dptr = (uint8 *)PKTDATA(osh, pfirst);
5209 sublen = ltoh16_ua(dptr);
5210 chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
5211 seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
5212 doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
5213
5214 DHD_GLOM(("%s: Get subframe %d, %p(%p/%d), sublen %d chan %d seq %d\n",
5215 __FUNCTION__, num, pfirst, PKTDATA(osh, pfirst),
5216 PKTLEN(osh, pfirst), sublen, chan, seq));
5217
5218 ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL));
5219
5220 if (rxseq != seq) {
5221 DHD_GLOM(("%s: rx_seq %d, expected %d\n",
5222 __FUNCTION__, seq, rxseq));
5223 bus->rx_badseq++;
5224 rxseq = seq;
5225 }
5226
5227 #ifdef DHD_DEBUG
5228 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
5229 prhex("Rx Subframe Data", dptr, dlen);
5230 }
5231 #endif
5232
5233 PKTSETLEN(osh, pfirst, sublen);
5234 PKTPULL(osh, pfirst, doff);
5235
5236 reorder_info_len = sizeof(reorder_info_buf);
5237
5238 if (PKTLEN(osh, pfirst) == 0) {
5239 PKTFREE(bus->dhd->osh, pfirst, FALSE);
5240 continue;
5241 } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pfirst, reorder_info_buf,
5242 &reorder_info_len) != 0) {
5243 DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__));
5244 bus->dhd->rx_errors++;
5245 PKTFREE(osh, pfirst, FALSE);
5246 continue;
5247 }
5248 if (reorder_info_len) {
5249 uint32 free_buf_count;
5250 void *ppfirst;
5251
5252 ppfirst = pfirst;
5253 /* Reordering info from the firmware */
5254 dhd_process_pkt_reorder_info(bus->dhd, reorder_info_buf,
5255 reorder_info_len, &ppfirst, &free_buf_count);
5256
5257 if (free_buf_count == 0) {
5258 continue;
5259 }
5260 else {
5261 void *temp;
5262
5263 /* go to the end of the chain and attach the pnext there */
5264 temp = ppfirst;
5265 while (PKTNEXT(osh, temp) != NULL) {
5266 temp = PKTNEXT(osh, temp);
5267 }
5268 pfirst = temp;
5269 if (list_tail[ifidx] == NULL)
5270 list_head[ifidx] = ppfirst;
5271 else
5272 PKTSETNEXT(osh, list_tail[ifidx], ppfirst);
5273 list_tail[ifidx] = pfirst;
5274 }
5275
5276 num += (uint8)free_buf_count;
5277 }
5278 else {
5279 /* this packet will go up, link back into chain and count it */
5280
5281 if (list_tail[ifidx] == NULL) {
5282 list_head[ifidx] = list_tail[ifidx] = pfirst;
5283 }
5284 else {
5285 PKTSETNEXT(osh, list_tail[ifidx], pfirst);
5286 list_tail[ifidx] = pfirst;
5287 }
5288 num++;
5289 }
5290 #ifdef DHD_DEBUG
5291 if (DHD_GLOM_ON()) {
5292 DHD_GLOM(("%s subframe %d to stack, %p(%p/%d) nxt/lnk %p/%p\n",
5293 __FUNCTION__, num, pfirst,
5294 PKTDATA(osh, pfirst), PKTLEN(osh, pfirst),
5295 PKTNEXT(osh, pfirst), PKTLINK(pfirst)));
5296 prhex("", (uint8 *)PKTDATA(osh, pfirst),
5297 MIN(PKTLEN(osh, pfirst), 32));
5298 }
5299 #endif /* DHD_DEBUG */
5300 }
5301 dhd_os_sdunlock_rxq(bus->dhd);
5302
5303 for (idx = 0; idx < DHD_MAX_IFS; idx++) {
5304 if (list_head[idx]) {
5305 void *temp;
5306 uint8 cnt = 0;
5307 temp = list_head[idx];
5308 do {
5309 temp = PKTNEXT(osh, temp);
5310 cnt++;
5311 } while (temp);
5312 if (cnt) {
5313 dhd_os_sdunlock(bus->dhd);
5314 dhd_rx_frame(bus->dhd, idx, list_head[idx], cnt, 0);
5315 dhd_os_sdlock(bus->dhd);
5316 }
5317 }
5318 }
5319 bus->rxglomframes++;
5320 bus->rxglompkts += num;
5321 }
5322 return num;
5323 }
5324
5325
5326 /* Return TRUE if there may be more frames to read */
5327 static uint
dhdsdio_readframes(dhd_bus_t * bus,uint maxframes,bool * finished)5328 dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished)
5329 {
5330 osl_t *osh = bus->dhd->osh;
5331 bcmsdh_info_t *sdh = bus->sdh;
5332
5333 uint16 len, check; /* Extracted hardware header fields */
5334 uint8 chan, seq, doff; /* Extracted software header fields */
5335 uint8 fcbits; /* Extracted fcbits from software header */
5336 uint8 delta;
5337
5338 void *pkt; /* Packet for event or data frames */
5339 uint16 pad; /* Number of pad bytes to read */
5340 uint16 rdlen; /* Total number of bytes to read */
5341 uint8 rxseq; /* Next sequence number to expect */
5342 uint rxleft = 0; /* Remaining number of frames allowed */
5343 int sdret; /* Return code from bcmsdh calls */
5344 uint8 txmax; /* Maximum tx sequence offered */
5345 bool len_consistent; /* Result of comparing readahead len and len from hw-hdr */
5346 uint8 *rxbuf;
5347 int ifidx = 0;
5348 uint rxcount = 0; /* Total frames read */
5349 uchar reorder_info_buf[WLHOST_REORDERDATA_TOTLEN];
5350 uint reorder_info_len;
5351 uint pkt_count;
5352
5353 #if defined(DHD_DEBUG) || defined(SDTEST)
5354 bool sdtest = FALSE; /* To limit message spew from test mode */
5355 #endif
5356
5357 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5358
5359 bus->readframes = TRUE;
5360
5361 if (!KSO_ENAB(bus)) {
5362 DHD_ERROR(("%s: KSO off\n", __FUNCTION__));
5363 bus->readframes = FALSE;
5364 return 0;
5365 }
5366
5367 ASSERT(maxframes);
5368
5369 #ifdef SDTEST
5370 /* Allow pktgen to override maxframes */
5371 if (bus->pktgen_count && (bus->pktgen_mode == DHD_PKTGEN_RECV)) {
5372 maxframes = bus->pktgen_count;
5373 sdtest = TRUE;
5374 }
5375 #endif
5376
5377 /* Not finished unless we encounter no more frames indication */
5378 *finished = FALSE;
5379
5380
5381 for (rxseq = bus->rx_seq, rxleft = maxframes;
5382 !bus->rxskip && rxleft && bus->dhd->busstate != DHD_BUS_DOWN;
5383 rxseq++, rxleft--) {
5384
5385 #ifdef DHDTHREAD
5386 /* tx more to improve rx performance */
5387 if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL)) {
5388 dhdsdio_sendpendctl(bus);
5389 } else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate &&
5390 pktq_mlen(&bus->txq, ~bus->flowcontrol) && DATAOK(bus)) {
5391 dhdsdio_sendfromq(bus, dhd_txbound);
5392 }
5393 #endif /* DHDTHREAD */
5394
5395 /* Handle glomming separately */
5396 if (bus->glom || bus->glomd) {
5397 uint8 cnt;
5398 DHD_GLOM(("%s: calling rxglom: glomd %p, glom %p\n",
5399 __FUNCTION__, bus->glomd, bus->glom));
5400 cnt = dhdsdio_rxglom(bus, rxseq);
5401 DHD_GLOM(("%s: rxglom returned %d\n", __FUNCTION__, cnt));
5402 rxseq += cnt - 1;
5403 rxleft = (rxleft > cnt) ? (rxleft - cnt) : 1;
5404 continue;
5405 }
5406
5407 /* Try doing single read if we can */
5408 if (dhd_readahead && bus->nextlen) {
5409 uint16 nextlen = bus->nextlen;
5410 bus->nextlen = 0;
5411
5412 if (bus->bus == SPI_BUS) {
5413 rdlen = len = nextlen;
5414 }
5415 else {
5416 rdlen = len = nextlen << 4;
5417
5418 /* Pad read to blocksize for efficiency */
5419 if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
5420 pad = bus->blocksize - (rdlen % bus->blocksize);
5421 if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
5422 ((rdlen + pad + firstread) < MAX_RX_DATASZ))
5423 rdlen += pad;
5424 } else if (rdlen % DHD_SDALIGN) {
5425 rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
5426 }
5427 }
5428
5429 /* We use bus->rxctl buffer in WinXP for initial control pkt receives.
5430 * Later we use buffer-poll for data as well as control packets.
5431 * This is required because dhd receives full frame in gSPI unlike SDIO.
5432 * After the frame is received we have to distinguish whether it is data
5433 * or non-data frame.
5434 */
5435 /* Allocate a packet buffer */
5436 dhd_os_sdlock_rxq(bus->dhd);
5437 if (!(pkt = PKTGET(osh, rdlen + DHD_SDALIGN, FALSE))) {
5438 if (bus->bus == SPI_BUS) {
5439 bus->usebufpool = FALSE;
5440 bus->rxctl = bus->rxbuf;
5441 if (dhd_alignctl) {
5442 bus->rxctl += firstread;
5443 if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN)))
5444 bus->rxctl += (DHD_SDALIGN - pad);
5445 bus->rxctl -= firstread;
5446 }
5447 ASSERT(bus->rxctl >= bus->rxbuf);
5448 rxbuf = bus->rxctl;
5449 /* Read the entire frame */
5450 sdret = dhd_bcmsdh_recv_buf(bus,
5451 bcmsdh_cur_sbwad(sdh),
5452 SDIO_FUNC_2,
5453 F2SYNC, rxbuf, rdlen,
5454 NULL, NULL, NULL);
5455 bus->f2rxdata++;
5456 ASSERT(sdret != BCME_PENDING);
5457
5458
5459 /* Control frame failures need retransmission */
5460 if (sdret < 0) {
5461 DHD_ERROR(("%s: read %d control bytes failed: %d\n",
5462 __FUNCTION__, rdlen, sdret));
5463 /* dhd.rx_ctlerrs is higher level */
5464 bus->rxc_errors++;
5465 dhd_os_sdunlock_rxq(bus->dhd);
5466 dhdsdio_rxfail(bus, TRUE,
5467 (bus->bus == SPI_BUS) ? FALSE : TRUE);
5468 continue;
5469 }
5470 } else {
5471 /* Give up on data, request rtx of events */
5472 DHD_ERROR(("%s (nextlen): PKTGET failed: len %d rdlen %d "
5473 "expected rxseq %d\n",
5474 __FUNCTION__, len, rdlen, rxseq));
5475 /* Just go try again w/normal header read */
5476 dhd_os_sdunlock_rxq(bus->dhd);
5477 continue;
5478 }
5479 } else {
5480 if (bus->bus == SPI_BUS)
5481 bus->usebufpool = TRUE;
5482
5483 ASSERT(!PKTLINK(pkt));
5484 PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN);
5485 rxbuf = (uint8 *)PKTDATA(osh, pkt);
5486 /* Read the entire frame */
5487 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh),
5488 SDIO_FUNC_2,
5489 F2SYNC, rxbuf, rdlen,
5490 pkt, NULL, NULL);
5491 bus->f2rxdata++;
5492 ASSERT(sdret != BCME_PENDING);
5493
5494 if (sdret < 0) {
5495 DHD_ERROR(("%s (nextlen): read %d bytes failed: %d\n",
5496 __FUNCTION__, rdlen, sdret));
5497 PKTFREE(bus->dhd->osh, pkt, FALSE);
5498 bus->dhd->rx_errors++;
5499 dhd_os_sdunlock_rxq(bus->dhd);
5500 /* Force retry w/normal header read. Don't attempt NAK for
5501 * gSPI
5502 */
5503 dhdsdio_rxfail(bus, TRUE,
5504 (bus->bus == SPI_BUS) ? FALSE : TRUE);
5505 continue;
5506 }
5507 }
5508 dhd_os_sdunlock_rxq(bus->dhd);
5509
5510 /* Now check the header */
5511 bcopy(rxbuf, bus->rxhdr, SDPCM_HDRLEN_RX);
5512
5513 /* Extract hardware header fields */
5514 len = ltoh16_ua(bus->rxhdr);
5515 check = ltoh16_ua(bus->rxhdr + sizeof(uint16));
5516
5517 /* All zeros means readahead info was bad */
5518 if (!(len|check)) {
5519 DHD_INFO(("%s (nextlen): read zeros in HW header???\n",
5520 __FUNCTION__));
5521 dhd_os_sdlock_rxq(bus->dhd);
5522 PKTFREE2();
5523 dhd_os_sdunlock_rxq(bus->dhd);
5524 GSPI_PR55150_BAILOUT;
5525 continue;
5526 }
5527
5528 /* Validate check bytes */
5529 if ((uint16)~(len^check)) {
5530 DHD_ERROR(("%s (nextlen): HW hdr error: nextlen/len/check"
5531 " 0x%04x/0x%04x/0x%04x\n", __FUNCTION__, nextlen,
5532 len, check));
5533 dhd_os_sdlock_rxq(bus->dhd);
5534 PKTFREE2();
5535 dhd_os_sdunlock_rxq(bus->dhd);
5536 bus->rx_badhdr++;
5537 dhdsdio_rxfail(bus, FALSE, FALSE);
5538 GSPI_PR55150_BAILOUT;
5539 continue;
5540 }
5541
5542 /* Validate frame length */
5543 if (len < SDPCM_HDRLEN_RX) {
5544 DHD_ERROR(("%s (nextlen): HW hdr length invalid: %d\n",
5545 __FUNCTION__, len));
5546 dhd_os_sdlock_rxq(bus->dhd);
5547 PKTFREE2();
5548 dhd_os_sdunlock_rxq(bus->dhd);
5549 GSPI_PR55150_BAILOUT;
5550 continue;
5551 }
5552
5553 /* Check for consistency with readahead info */
5554 len_consistent = (nextlen != (ROUNDUP(len, 16) >> 4));
5555 if (len_consistent) {
5556 /* Mismatch, force retry w/normal header (may be >4K) */
5557 DHD_ERROR(("%s (nextlen): mismatch, nextlen %d len %d rnd %d; "
5558 "expected rxseq %d\n",
5559 __FUNCTION__, nextlen, len, ROUNDUP(len, 16), rxseq));
5560 dhd_os_sdlock_rxq(bus->dhd);
5561 PKTFREE2();
5562 dhd_os_sdunlock_rxq(bus->dhd);
5563 dhdsdio_rxfail(bus, TRUE, (bus->bus == SPI_BUS) ? FALSE : TRUE);
5564 GSPI_PR55150_BAILOUT;
5565 continue;
5566 }
5567
5568
5569 /* Extract software header fields */
5570 chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5571 seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5572 doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5573 txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5574
5575 bus->nextlen =
5576 bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
5577 if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
5578 DHD_INFO(("%s (nextlen): got frame w/nextlen too large"
5579 " (%d), seq %d\n", __FUNCTION__, bus->nextlen,
5580 seq));
5581 bus->nextlen = 0;
5582 }
5583
5584 bus->dhd->rx_readahead_cnt ++;
5585 /* Handle Flow Control */
5586 fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5587
5588 delta = 0;
5589 if (~bus->flowcontrol & fcbits) {
5590 bus->fc_xoff++;
5591 delta = 1;
5592 }
5593 if (bus->flowcontrol & ~fcbits) {
5594 bus->fc_xon++;
5595 delta = 1;
5596 }
5597
5598 if (delta) {
5599 bus->fc_rcvd++;
5600 bus->flowcontrol = fcbits;
5601 }
5602
5603 /* Check and update sequence number */
5604 if (rxseq != seq) {
5605 DHD_INFO(("%s (nextlen): rx_seq %d, expected %d\n",
5606 __FUNCTION__, seq, rxseq));
5607 bus->rx_badseq++;
5608 rxseq = seq;
5609 }
5610
5611 /* Check window for sanity */
5612 if ((uint8)(txmax - bus->tx_seq) > 0x40) {
5613 DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
5614 __FUNCTION__, txmax, bus->tx_seq));
5615 txmax = bus->tx_max;
5616 }
5617 bus->tx_max = txmax;
5618
5619 #ifdef DHD_DEBUG
5620 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
5621 prhex("Rx Data", rxbuf, len);
5622 } else if (DHD_HDRS_ON()) {
5623 prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN_RX);
5624 }
5625 #endif
5626
5627 if (chan == SDPCM_CONTROL_CHANNEL) {
5628 if (bus->bus == SPI_BUS) {
5629 dhdsdio_read_control(bus, rxbuf, len, doff);
5630 if (bus->usebufpool) {
5631 dhd_os_sdlock_rxq(bus->dhd);
5632 PKTFREE(bus->dhd->osh, pkt, FALSE);
5633 dhd_os_sdunlock_rxq(bus->dhd);
5634 }
5635 continue;
5636 } else {
5637 DHD_ERROR(("%s (nextlen): readahead on control"
5638 " packet %d?\n", __FUNCTION__, seq));
5639 /* Force retry w/normal header read */
5640 bus->nextlen = 0;
5641 dhdsdio_rxfail(bus, FALSE, TRUE);
5642 dhd_os_sdlock_rxq(bus->dhd);
5643 PKTFREE2();
5644 dhd_os_sdunlock_rxq(bus->dhd);
5645 continue;
5646 }
5647 }
5648
5649 if ((bus->bus == SPI_BUS) && !bus->usebufpool) {
5650 DHD_ERROR(("Received %d bytes on %d channel. Running out of "
5651 "rx pktbuf's or not yet malloced.\n", len, chan));
5652 continue;
5653 }
5654
5655 /* Validate data offset */
5656 if ((doff < SDPCM_HDRLEN_RX) || (doff > len)) {
5657 DHD_ERROR(("%s (nextlen): bad data offset %d: HW len %d min %d\n",
5658 __FUNCTION__, doff, len, SDPCM_HDRLEN_RX));
5659 dhd_os_sdlock_rxq(bus->dhd);
5660 PKTFREE2();
5661 dhd_os_sdunlock_rxq(bus->dhd);
5662 ASSERT(0);
5663 dhdsdio_rxfail(bus, FALSE, FALSE);
5664 continue;
5665 }
5666
5667 /* All done with this one -- now deliver the packet */
5668 goto deliver;
5669 }
5670 /* gSPI frames should not be handled in fractions */
5671 if (bus->bus == SPI_BUS) {
5672 break;
5673 }
5674
5675 /* Read frame header (hardware and software) */
5676 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
5677 bus->rxhdr, firstread, NULL, NULL, NULL);
5678 bus->f2rxhdrs++;
5679 ASSERT(sdret != BCME_PENDING);
5680
5681 if (sdret < 0) {
5682 DHD_ERROR(("%s: RXHEADER FAILED: %d\n", __FUNCTION__, sdret));
5683 bus->rx_hdrfail++;
5684 dhdsdio_rxfail(bus, TRUE, TRUE);
5685 continue;
5686 }
5687
5688 #ifdef DHD_DEBUG
5689 if (DHD_BYTES_ON() || DHD_HDRS_ON()) {
5690 prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN_RX);
5691 }
5692 #endif
5693
5694 /* Extract hardware header fields */
5695 len = ltoh16_ua(bus->rxhdr);
5696 check = ltoh16_ua(bus->rxhdr + sizeof(uint16));
5697
5698 /* All zeros means no more frames */
5699 if (!(len|check)) {
5700 *finished = TRUE;
5701 break;
5702 }
5703
5704 /* Validate check bytes */
5705 if ((uint16)~(len^check)) {
5706 DHD_ERROR(("%s: HW hdr error: len/check 0x%04x/0x%04x\n",
5707 __FUNCTION__, len, check));
5708 bus->rx_badhdr++;
5709 dhdsdio_rxfail(bus, FALSE, FALSE);
5710 continue;
5711 }
5712
5713 /* Validate frame length */
5714 if (len < SDPCM_HDRLEN_RX) {
5715 DHD_ERROR(("%s: HW hdr length invalid: %d\n", __FUNCTION__, len));
5716 continue;
5717 }
5718
5719 /* Extract software header fields */
5720 chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5721 seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5722 doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5723 txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5724
5725 /* Validate data offset */
5726 if ((doff < SDPCM_HDRLEN_RX) || (doff > len)) {
5727 DHD_ERROR(("%s: Bad data offset %d: HW len %d, min %d seq %d\n",
5728 __FUNCTION__, doff, len, SDPCM_HDRLEN_RX, seq));
5729 bus->rx_badhdr++;
5730 ASSERT(0);
5731 dhdsdio_rxfail(bus, FALSE, FALSE);
5732 continue;
5733 }
5734
5735 /* Save the readahead length if there is one */
5736 bus->nextlen = bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
5737 if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
5738 DHD_INFO(("%s (nextlen): got frame w/nextlen too large (%d), seq %d\n",
5739 __FUNCTION__, bus->nextlen, seq));
5740 bus->nextlen = 0;
5741 }
5742
5743 /* Handle Flow Control */
5744 fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
5745
5746 delta = 0;
5747 if (~bus->flowcontrol & fcbits) {
5748 bus->fc_xoff++;
5749 delta = 1;
5750 }
5751 if (bus->flowcontrol & ~fcbits) {
5752 bus->fc_xon++;
5753 delta = 1;
5754 }
5755
5756 if (delta) {
5757 bus->fc_rcvd++;
5758 bus->flowcontrol = fcbits;
5759 }
5760
5761 /* Check and update sequence number */
5762 if (rxseq != seq) {
5763 DHD_INFO(("%s: rx_seq %d, expected %d\n", __FUNCTION__, seq, rxseq));
5764 bus->rx_badseq++;
5765 rxseq = seq;
5766 }
5767
5768 /* Check window for sanity */
5769 if ((uint8)(txmax - bus->tx_seq) > 0x40) {
5770 DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
5771 __FUNCTION__, txmax, bus->tx_seq));
5772 txmax = bus->tx_max;
5773 }
5774 bus->tx_max = txmax;
5775
5776 /* Call a separate function for control frames */
5777 if (chan == SDPCM_CONTROL_CHANNEL) {
5778 dhdsdio_read_control(bus, bus->rxhdr, len, doff);
5779 continue;
5780 }
5781
5782 ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL) ||
5783 (chan == SDPCM_TEST_CHANNEL) || (chan == SDPCM_GLOM_CHANNEL));
5784
5785 /* Length to read */
5786 rdlen = (len > firstread) ? (len - firstread) : 0;
5787
5788 /* May pad read to blocksize for efficiency */
5789 if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
5790 pad = bus->blocksize - (rdlen % bus->blocksize);
5791 if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
5792 ((rdlen + pad + firstread) < MAX_RX_DATASZ))
5793 rdlen += pad;
5794 } else if (rdlen % DHD_SDALIGN) {
5795 rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
5796 }
5797
5798 /* Satisfy length-alignment requirements */
5799 if (forcealign && (rdlen & (ALIGNMENT - 1)))
5800 rdlen = ROUNDUP(rdlen, ALIGNMENT);
5801
5802 if ((rdlen + firstread) > MAX_RX_DATASZ) {
5803 /* Too long -- skip this frame */
5804 DHD_ERROR(("%s: too long: len %d rdlen %d\n", __FUNCTION__, len, rdlen));
5805 bus->dhd->rx_errors++; bus->rx_toolong++;
5806 dhdsdio_rxfail(bus, FALSE, FALSE);
5807 continue;
5808 }
5809
5810 dhd_os_sdlock_rxq(bus->dhd);
5811 if (!(pkt = PKTGET(osh, (rdlen + firstread + DHD_SDALIGN), FALSE))) {
5812 /* Give up on data, request rtx of events */
5813 DHD_ERROR(("%s: PKTGET failed: rdlen %d chan %d\n",
5814 __FUNCTION__, rdlen, chan));
5815 bus->dhd->rx_dropped++;
5816 dhd_os_sdunlock_rxq(bus->dhd);
5817 dhdsdio_rxfail(bus, FALSE, RETRYCHAN(chan));
5818 continue;
5819 }
5820 dhd_os_sdunlock_rxq(bus->dhd);
5821
5822 ASSERT(!PKTLINK(pkt));
5823
5824 /* Leave room for what we already read, and align remainder */
5825 ASSERT(firstread < (PKTLEN(osh, pkt)));
5826 PKTPULL(osh, pkt, firstread);
5827 PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN);
5828
5829 /* Read the remaining frame data */
5830 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
5831 ((uint8 *)PKTDATA(osh, pkt)), rdlen, pkt, NULL, NULL);
5832 bus->f2rxdata++;
5833 ASSERT(sdret != BCME_PENDING);
5834
5835 if (sdret < 0) {
5836 DHD_ERROR(("%s: read %d %s bytes failed: %d\n", __FUNCTION__, rdlen,
5837 ((chan == SDPCM_EVENT_CHANNEL) ? "event" :
5838 ((chan == SDPCM_DATA_CHANNEL) ? "data" : "test")), sdret));
5839 dhd_os_sdlock_rxq(bus->dhd);
5840 PKTFREE(bus->dhd->osh, pkt, FALSE);
5841 dhd_os_sdunlock_rxq(bus->dhd);
5842 bus->dhd->rx_errors++;
5843 dhdsdio_rxfail(bus, TRUE, RETRYCHAN(chan));
5844 continue;
5845 }
5846
5847 /* Copy the already-read portion */
5848 PKTPUSH(osh, pkt, firstread);
5849 bcopy(bus->rxhdr, PKTDATA(osh, pkt), firstread);
5850
5851 #ifdef DHD_DEBUG
5852 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
5853 prhex("Rx Data", PKTDATA(osh, pkt), len);
5854 }
5855 #endif
5856
5857 deliver:
5858 /* Save superframe descriptor and allocate packet frame */
5859 if (chan == SDPCM_GLOM_CHANNEL) {
5860 if (SDPCM_GLOMDESC(&bus->rxhdr[SDPCM_FRAMETAG_LEN])) {
5861 DHD_GLOM(("%s: got glom descriptor, %d bytes:\n",
5862 __FUNCTION__, len));
5863 #ifdef DHD_DEBUG
5864 if (DHD_GLOM_ON()) {
5865 prhex("Glom Data", PKTDATA(osh, pkt), len);
5866 }
5867 #endif
5868 PKTSETLEN(osh, pkt, len);
5869 ASSERT(doff == SDPCM_HDRLEN_RX);
5870 PKTPULL(osh, pkt, SDPCM_HDRLEN_RX);
5871 bus->glomd = pkt;
5872 } else {
5873 DHD_ERROR(("%s: glom superframe w/o descriptor!\n", __FUNCTION__));
5874 dhdsdio_rxfail(bus, FALSE, FALSE);
5875 }
5876 continue;
5877 }
5878
5879 /* Fill in packet len and prio, deliver upward */
5880 PKTSETLEN(osh, pkt, len);
5881 PKTPULL(osh, pkt, doff);
5882
5883 #ifdef SDTEST
5884 /* Test channel packets are processed separately */
5885 if (chan == SDPCM_TEST_CHANNEL) {
5886 dhdsdio_testrcv(bus, pkt, seq);
5887 continue;
5888 }
5889 #endif /* SDTEST */
5890
5891 if (PKTLEN(osh, pkt) == 0) {
5892 dhd_os_sdlock_rxq(bus->dhd);
5893 PKTFREE(bus->dhd->osh, pkt, FALSE);
5894 dhd_os_sdunlock_rxq(bus->dhd);
5895 continue;
5896 } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pkt, reorder_info_buf,
5897 &reorder_info_len) != 0) {
5898 DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__));
5899 dhd_os_sdlock_rxq(bus->dhd);
5900 PKTFREE(bus->dhd->osh, pkt, FALSE);
5901 dhd_os_sdunlock_rxq(bus->dhd);
5902 bus->dhd->rx_errors++;
5903 continue;
5904 }
5905 if (reorder_info_len) {
5906 /* Reordering info from the firmware */
5907 dhd_process_pkt_reorder_info(bus->dhd, reorder_info_buf, reorder_info_len,
5908 &pkt, &pkt_count);
5909 if (pkt_count == 0)
5910 continue;
5911 }
5912 else
5913 pkt_count = 1;
5914
5915 /* Unlock during rx call */
5916 dhd_os_sdunlock(bus->dhd);
5917 dhd_rx_frame(bus->dhd, ifidx, pkt, pkt_count, chan);
5918 dhd_os_sdlock(bus->dhd);
5919 }
5920 rxcount = maxframes - rxleft;
5921 #ifdef DHD_DEBUG
5922 /* Message if we hit the limit */
5923 if (!rxleft && !sdtest)
5924 DHD_DATA(("%s: hit rx limit of %d frames\n", __FUNCTION__, maxframes));
5925 else
5926 #endif /* DHD_DEBUG */
5927 DHD_DATA(("%s: processed %d frames\n", __FUNCTION__, rxcount));
5928 /* Back off rxseq if awaiting rtx, update rx_seq */
5929 if (bus->rxskip)
5930 rxseq--;
5931 bus->rx_seq = rxseq;
5932
5933 if (bus->reqbussleep)
5934 {
5935 dhdsdio_bussleep(bus, TRUE);
5936 bus->reqbussleep = FALSE;
5937 }
5938 bus->readframes = FALSE;
5939
5940 return rxcount;
5941 }
5942
5943 static uint32
dhdsdio_hostmail(dhd_bus_t * bus)5944 dhdsdio_hostmail(dhd_bus_t *bus)
5945 {
5946 sdpcmd_regs_t *regs = bus->regs;
5947 uint32 intstatus = 0;
5948 uint32 hmb_data;
5949 uint8 fcbits;
5950 uint retries = 0;
5951
5952 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5953
5954 /* Read mailbox data and ack that we did so */
5955 R_SDREG(hmb_data, ®s->tohostmailboxdata, retries);
5956 if (retries <= retry_limit)
5957 W_SDREG(SMB_INT_ACK, ®s->tosbmailbox, retries);
5958 bus->f1regdata += 2;
5959
5960 /* Dongle recomposed rx frames, accept them again */
5961 if (hmb_data & HMB_DATA_NAKHANDLED) {
5962 DHD_INFO(("Dongle reports NAK handled, expect rtx of %d\n", bus->rx_seq));
5963 if (!bus->rxskip) {
5964 DHD_ERROR(("%s: unexpected NAKHANDLED!\n", __FUNCTION__));
5965 }
5966 bus->rxskip = FALSE;
5967 intstatus |= FRAME_AVAIL_MASK(bus);
5968 }
5969
5970 /*
5971 * DEVREADY does not occur with gSPI.
5972 */
5973 if (hmb_data & (HMB_DATA_DEVREADY | HMB_DATA_FWREADY)) {
5974 bus->sdpcm_ver = (hmb_data & HMB_DATA_VERSION_MASK) >> HMB_DATA_VERSION_SHIFT;
5975 if (bus->sdpcm_ver != SDPCM_PROT_VERSION)
5976 DHD_ERROR(("Version mismatch, dongle reports %d, expecting %d\n",
5977 bus->sdpcm_ver, SDPCM_PROT_VERSION));
5978 else
5979 DHD_INFO(("Dongle ready, protocol version %d\n", bus->sdpcm_ver));
5980 /* make sure for the SDIO_DEVICE_RXDATAINT_MODE_1 corecontrol is proper */
5981 if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev >= 4) &&
5982 (bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_1)) {
5983 uint32 val;
5984
5985 val = R_REG(bus->dhd->osh, &bus->regs->corecontrol);
5986 val &= ~CC_XMTDATAAVAIL_MODE;
5987 val |= CC_XMTDATAAVAIL_CTRL;
5988 W_REG(bus->dhd->osh, &bus->regs->corecontrol, val);
5989
5990 val = R_REG(bus->dhd->osh, &bus->regs->corecontrol);
5991 }
5992
5993 #ifdef DHD_DEBUG
5994 /* Retrieve console state address now that firmware should have updated it */
5995 {
5996 sdpcm_shared_t shared;
5997 if (dhdsdio_readshared(bus, &shared) == 0)
5998 bus->console_addr = shared.console_addr;
5999 }
6000 #endif /* DHD_DEBUG */
6001 }
6002
6003 /*
6004 * Flow Control has been moved into the RX headers and this out of band
6005 * method isn't used any more. Leave this here for possibly remaining backward
6006 * compatible with older dongles
6007 */
6008 if (hmb_data & HMB_DATA_FC) {
6009 fcbits = (hmb_data & HMB_DATA_FCDATA_MASK) >> HMB_DATA_FCDATA_SHIFT;
6010
6011 if (fcbits & ~bus->flowcontrol)
6012 bus->fc_xoff++;
6013 if (bus->flowcontrol & ~fcbits)
6014 bus->fc_xon++;
6015
6016 bus->fc_rcvd++;
6017 bus->flowcontrol = fcbits;
6018 }
6019
6020 #ifdef DHD_DEBUG
6021 /* At least print a message if FW halted */
6022 if (hmb_data & HMB_DATA_FWHALT) {
6023 DHD_ERROR(("INTERNAL ERROR: FIRMWARE HALTED : set BUS DOWN\n"));
6024 dhdsdio_checkdied(bus, NULL, 0);
6025 bus->dhd->busstate = DHD_BUS_DOWN;
6026 }
6027 #endif /* DHD_DEBUG */
6028
6029 /* Shouldn't be any others */
6030 if (hmb_data & ~(HMB_DATA_DEVREADY |
6031 HMB_DATA_FWHALT |
6032 HMB_DATA_NAKHANDLED |
6033 HMB_DATA_FC |
6034 HMB_DATA_FWREADY |
6035 HMB_DATA_FCDATA_MASK |
6036 HMB_DATA_VERSION_MASK)) {
6037 DHD_ERROR(("Unknown mailbox data content: 0x%02x\n", hmb_data));
6038 }
6039
6040 return intstatus;
6041 }
6042
6043 static bool
dhdsdio_dpc(dhd_bus_t * bus)6044 dhdsdio_dpc(dhd_bus_t *bus)
6045 {
6046 bcmsdh_info_t *sdh = bus->sdh;
6047 sdpcmd_regs_t *regs = bus->regs;
6048 uint32 intstatus, newstatus = 0;
6049 uint retries = 0;
6050 uint rxlimit = dhd_rxbound; /* Rx frames to read before resched */
6051 uint txlimit = dhd_txbound; /* Tx frames to send before resched */
6052 uint framecnt = 0; /* Temporary counter of tx/rx frames */
6053 bool rxdone = TRUE; /* Flag for no more read data */
6054 bool resched = FALSE; /* Flag indicating resched wanted */
6055
6056 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
6057
6058 if (bus->dhd->busstate == DHD_BUS_DOWN) {
6059 DHD_ERROR(("%s: Bus down, ret\n", __FUNCTION__));
6060 bus->intstatus = 0;
6061 return 0;
6062 }
6063
6064 /* Start with leftover status bits */
6065 intstatus = bus->intstatus;
6066
6067 dhd_os_sdlock(bus->dhd);
6068
6069 if (!SLPAUTO_ENAB(bus) && !KSO_ENAB(bus)) {
6070 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
6071 goto exit;
6072 }
6073
6074 /* If waiting for HTAVAIL, check status */
6075 if (!SLPAUTO_ENAB(bus) && (bus->clkstate == CLK_PENDING)) {
6076 int err;
6077 uint8 clkctl, devctl = 0;
6078
6079 #ifdef DHD_DEBUG
6080 /* Check for inconsistent device control */
6081 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
6082 if (err) {
6083 DHD_ERROR(("%s: error reading DEVCTL: %d\n", __FUNCTION__, err));
6084 bus->dhd->busstate = DHD_BUS_DOWN;
6085 } else {
6086 ASSERT(devctl & SBSDIO_DEVCTL_CA_INT_ONLY);
6087 }
6088 #endif /* DHD_DEBUG */
6089
6090 /* Read CSR, if clock on switch to AVAIL, else ignore */
6091 clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
6092 if (err) {
6093 DHD_ERROR(("%s: error reading CSR: %d\n", __FUNCTION__, err));
6094 bus->dhd->busstate = DHD_BUS_DOWN;
6095 }
6096
6097 DHD_INFO(("DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n", devctl, clkctl));
6098
6099 if (SBSDIO_HTAV(clkctl)) {
6100 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
6101 if (err) {
6102 DHD_ERROR(("%s: error reading DEVCTL: %d\n",
6103 __FUNCTION__, err));
6104 bus->dhd->busstate = DHD_BUS_DOWN;
6105 }
6106 devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
6107 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
6108 if (err) {
6109 DHD_ERROR(("%s: error writing DEVCTL: %d\n",
6110 __FUNCTION__, err));
6111 bus->dhd->busstate = DHD_BUS_DOWN;
6112 }
6113 bus->clkstate = CLK_AVAIL;
6114 } else {
6115 goto clkwait;
6116 }
6117 }
6118
6119 BUS_WAKE(bus);
6120
6121 /* Make sure backplane clock is on */
6122 dhdsdio_clkctl(bus, CLK_AVAIL, TRUE);
6123 if (bus->clkstate != CLK_AVAIL)
6124 goto clkwait;
6125
6126 /* Pending interrupt indicates new device status */
6127 if (bus->ipend) {
6128 bus->ipend = FALSE;
6129 R_SDREG(newstatus, ®s->intstatus, retries);
6130 bus->f1regdata++;
6131 if (bcmsdh_regfail(bus->sdh))
6132 newstatus = 0;
6133 newstatus &= bus->hostintmask;
6134 bus->fcstate = !!(newstatus & I_HMB_FC_STATE);
6135 if (newstatus) {
6136 bus->f1regdata++;
6137 if ((bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_0) &&
6138 (newstatus == I_XMTDATA_AVAIL)) {
6139 }
6140 else
6141 W_SDREG(newstatus, ®s->intstatus, retries);
6142 }
6143 }
6144
6145 /* Merge new bits with previous */
6146 intstatus |= newstatus;
6147 bus->intstatus = 0;
6148
6149 /* Handle flow-control change: read new state in case our ack
6150 * crossed another change interrupt. If change still set, assume
6151 * FC ON for safety, let next loop through do the debounce.
6152 */
6153 if (intstatus & I_HMB_FC_CHANGE) {
6154 intstatus &= ~I_HMB_FC_CHANGE;
6155 W_SDREG(I_HMB_FC_CHANGE, ®s->intstatus, retries);
6156 R_SDREG(newstatus, ®s->intstatus, retries);
6157 bus->f1regdata += 2;
6158 bus->fcstate = !!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE));
6159 intstatus |= (newstatus & bus->hostintmask);
6160 }
6161
6162 /* Just being here means nothing more to do for chipactive */
6163 if (intstatus & I_CHIPACTIVE) {
6164 /* ASSERT(bus->clkstate == CLK_AVAIL); */
6165 intstatus &= ~I_CHIPACTIVE;
6166 }
6167
6168 /* Handle host mailbox indication */
6169 if (intstatus & I_HMB_HOST_INT) {
6170 intstatus &= ~I_HMB_HOST_INT;
6171 intstatus |= dhdsdio_hostmail(bus);
6172 }
6173
6174 /* Generally don't ask for these, can get CRC errors... */
6175 if (intstatus & I_WR_OOSYNC) {
6176 DHD_ERROR(("Dongle reports WR_OOSYNC\n"));
6177 intstatus &= ~I_WR_OOSYNC;
6178 }
6179
6180 if (intstatus & I_RD_OOSYNC) {
6181 DHD_ERROR(("Dongle reports RD_OOSYNC\n"));
6182 intstatus &= ~I_RD_OOSYNC;
6183 }
6184
6185 if (intstatus & I_SBINT) {
6186 DHD_ERROR(("Dongle reports SBINT\n"));
6187 intstatus &= ~I_SBINT;
6188 }
6189
6190 /* Would be active due to wake-wlan in gSPI */
6191 if (intstatus & I_CHIPACTIVE) {
6192 DHD_INFO(("Dongle reports CHIPACTIVE\n"));
6193 intstatus &= ~I_CHIPACTIVE;
6194 }
6195
6196 /* Ignore frame indications if rxskip is set */
6197 if (bus->rxskip) {
6198 intstatus &= ~FRAME_AVAIL_MASK(bus);
6199 }
6200
6201 /* On frame indication, read available frames */
6202 if (PKT_AVAILABLE(bus, intstatus)) {
6203 framecnt = dhdsdio_readframes(bus, rxlimit, &rxdone);
6204 if (rxdone || bus->rxskip)
6205 intstatus &= ~FRAME_AVAIL_MASK(bus);
6206 rxlimit -= MIN(framecnt, rxlimit);
6207 }
6208
6209 /* Keep still-pending events for next scheduling */
6210 bus->intstatus = intstatus;
6211
6212 clkwait:
6213 /* Re-enable interrupts to detect new device events (mailbox, rx frame)
6214 * or clock availability. (Allows tx loop to check ipend if desired.)
6215 * (Unless register access seems hosed, as we may not be able to ACK...)
6216 */
6217 if (bus->intr && bus->intdis && !bcmsdh_regfail(sdh)) {
6218 DHD_INTR(("%s: enable SDIO interrupts, rxdone %d framecnt %d\n",
6219 __FUNCTION__, rxdone, framecnt));
6220 bus->intdis = FALSE;
6221 #if defined(OOB_INTR_ONLY)
6222 bcmsdh_oob_intr_set(1);
6223 #endif /* defined(OOB_INTR_ONLY) */
6224 bcmsdh_intr_enable(sdh);
6225 }
6226
6227 #if defined(OOB_INTR_ONLY) && !defined(HW_OOB)
6228 /* In case of SW-OOB(using edge trigger),
6229 * Check interrupt status in the dongle again after enable irq on the host.
6230 * and rechedule dpc if interrupt is pended in the dongle.
6231 * There is a chance to miss OOB interrupt while irq is disabled on the host.
6232 * No need to do this with HW-OOB(level trigger)
6233 */
6234 R_SDREG(newstatus, ®s->intstatus, retries);
6235 if (bcmsdh_regfail(bus->sdh))
6236 newstatus = 0;
6237 if (newstatus & bus->hostintmask) {
6238 bus->ipend = TRUE;
6239 resched = TRUE;
6240 }
6241 #endif /* defined(OOB_INTR_ONLY) && !defined(HW_OOB) */
6242
6243 #ifdef PROP_TXSTATUS
6244 dhd_wlfc_trigger_pktcommit(bus->dhd);
6245 #endif
6246
6247 if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL))
6248 dhdsdio_sendpendctl(bus);
6249
6250 /* Send queued frames (limit 1 if rx may still be pending) */
6251 else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate &&
6252 pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit && DATAOK(bus)) {
6253 framecnt = rxdone ? txlimit : MIN(txlimit, dhd_txminmax);
6254 framecnt = dhdsdio_sendfromq(bus, framecnt);
6255 txlimit -= framecnt;
6256 }
6257 /* Resched the DPC if ctrl cmd is pending on bus credit */
6258 if (bus->ctrl_frame_stat)
6259 resched = TRUE;
6260
6261 /* Resched if events or tx frames are pending, else await next interrupt */
6262 /* On failed register access, all bets are off: no resched or interrupts */
6263 if ((bus->dhd->busstate == DHD_BUS_DOWN) || bcmsdh_regfail(sdh)) {
6264 if ((bus->sih && bus->sih->buscorerev >= 12) && !(dhdsdio_sleepcsr_get(bus) &
6265 SBSDIO_FUNC1_SLEEPCSR_KSO_MASK)) {
6266 /* Bus failed because of KSO */
6267 DHD_ERROR(("%s: Bus failed due to KSO\n", __FUNCTION__));
6268 bus->kso = FALSE;
6269 } else {
6270 DHD_ERROR(("%s: failed backplane access over SDIO, halting operation\n",
6271 __FUNCTION__));
6272 bus->dhd->busstate = DHD_BUS_DOWN;
6273 bus->intstatus = 0;
6274 }
6275 } else if (bus->clkstate == CLK_PENDING) {
6276 /* Awaiting I_CHIPACTIVE; don't resched */
6277 } else if (bus->intstatus || bus->ipend ||
6278 (!bus->fcstate && pktq_mlen(&bus->txq, ~bus->flowcontrol) && DATAOK(bus)) ||
6279 PKT_AVAILABLE(bus, bus->intstatus)) { /* Read multiple frames */
6280 resched = TRUE;
6281 }
6282
6283 bus->dpc_sched = resched;
6284
6285 /* If we're done for now, turn off clock request. */
6286 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && (bus->clkstate != CLK_PENDING)) {
6287 bus->activity = FALSE;
6288 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
6289 }
6290
6291 exit:
6292
6293 if (!resched && dhd_dpcpoll) {
6294 if (dhdsdio_readframes(bus, dhd_rxbound, &rxdone) != 0) {
6295 resched = TRUE;
6296 }
6297 }
6298
6299 dhd_os_sdunlock(bus->dhd);
6300 return resched;
6301 }
6302
6303 bool
dhd_bus_dpc(struct dhd_bus * bus)6304 dhd_bus_dpc(struct dhd_bus *bus)
6305 {
6306 bool resched;
6307
6308 /* Call the DPC directly. */
6309 DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__));
6310 resched = dhdsdio_dpc(bus);
6311
6312 return resched;
6313 }
6314
6315 void
dhdsdio_isr(void * arg)6316 dhdsdio_isr(void *arg)
6317 {
6318 dhd_bus_t *bus = (dhd_bus_t*)arg;
6319 bcmsdh_info_t *sdh;
6320
6321 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
6322
6323 if (!bus) {
6324 DHD_ERROR(("%s : bus is null pointer , exit \n", __FUNCTION__));
6325 return;
6326 }
6327 sdh = bus->sdh;
6328
6329 if (bus->dhd->busstate == DHD_BUS_DOWN) {
6330 DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__));
6331 return;
6332 }
6333
6334 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
6335
6336 /* Count the interrupt call */
6337 bus->intrcount++;
6338 bus->ipend = TRUE;
6339
6340 /* Shouldn't get this interrupt if we're sleeping? */
6341 if (!SLPAUTO_ENAB(bus)) {
6342 if (bus->sleeping) {
6343 DHD_ERROR(("INTERRUPT WHILE SLEEPING??\n"));
6344 return;
6345 } else if (!KSO_ENAB(bus)) {
6346 DHD_ERROR(("ISR in devsleep 1\n"));
6347 }
6348 }
6349
6350 /* Disable additional interrupts (is this needed now)? */
6351 if (bus->intr) {
6352 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
6353 } else {
6354 DHD_ERROR(("dhdsdio_isr() w/o interrupt configured!\n"));
6355 }
6356
6357 bcmsdh_intr_disable(sdh);
6358 bus->intdis = TRUE;
6359
6360 #if defined(SDIO_ISR_THREAD)
6361 DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__));
6362 DHD_OS_WAKE_LOCK(bus->dhd);
6363 dhdsdio_dpc(bus);
6364 DHD_OS_WAKE_UNLOCK(bus->dhd);
6365 #else
6366
6367 bus->dpc_sched = TRUE;
6368 dhd_sched_dpc(bus->dhd);
6369
6370 #endif
6371
6372 }
6373
6374 #ifdef SDTEST
6375 static void
dhdsdio_pktgen_init(dhd_bus_t * bus)6376 dhdsdio_pktgen_init(dhd_bus_t *bus)
6377 {
6378 /* Default to specified length, or full range */
6379 if (dhd_pktgen_len) {
6380 bus->pktgen_maxlen = MIN(dhd_pktgen_len, MAX_PKTGEN_LEN);
6381 bus->pktgen_minlen = bus->pktgen_maxlen;
6382 } else {
6383 bus->pktgen_maxlen = MAX_PKTGEN_LEN;
6384 bus->pktgen_minlen = 0;
6385 }
6386 bus->pktgen_len = (uint16)bus->pktgen_minlen;
6387
6388 /* Default to per-watchdog burst with 10s print time */
6389 bus->pktgen_freq = 1;
6390 bus->pktgen_print = dhd_watchdog_ms ? (10000 / dhd_watchdog_ms) : 0;
6391 bus->pktgen_count = (dhd_pktgen * dhd_watchdog_ms + 999) / 1000;
6392
6393 /* Default to echo mode */
6394 bus->pktgen_mode = DHD_PKTGEN_ECHO;
6395 bus->pktgen_stop = 1;
6396 }
6397
6398 static void
dhdsdio_pktgen(dhd_bus_t * bus)6399 dhdsdio_pktgen(dhd_bus_t *bus)
6400 {
6401 void *pkt;
6402 uint8 *data;
6403 uint pktcount;
6404 uint fillbyte;
6405 osl_t *osh = bus->dhd->osh;
6406 uint16 len;
6407 ulong time_lapse;
6408 uint sent_pkts;
6409 uint rcvd_pkts;
6410
6411 /* Display current count if appropriate */
6412 if (bus->pktgen_print && (++bus->pktgen_ptick >= bus->pktgen_print)) {
6413 bus->pktgen_ptick = 0;
6414 printf("%s: send attempts %d, rcvd %d, errors %d\n",
6415 __FUNCTION__, bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail);
6416
6417 /* Print throughput stats only for constant length packet runs */
6418 if (bus->pktgen_minlen == bus->pktgen_maxlen) {
6419 time_lapse = jiffies - bus->pktgen_prev_time;
6420 bus->pktgen_prev_time = jiffies;
6421 sent_pkts = bus->pktgen_sent - bus->pktgen_prev_sent;
6422 bus->pktgen_prev_sent = bus->pktgen_sent;
6423 rcvd_pkts = bus->pktgen_rcvd - bus->pktgen_prev_rcvd;
6424 bus->pktgen_prev_rcvd = bus->pktgen_rcvd;
6425
6426 printf("%s: Tx Throughput %d kbps, Rx Throughput %d kbps\n",
6427 __FUNCTION__,
6428 (sent_pkts * bus->pktgen_len / jiffies_to_msecs(time_lapse)) * 8,
6429 (rcvd_pkts * bus->pktgen_len / jiffies_to_msecs(time_lapse)) * 8);
6430 }
6431 }
6432
6433 /* For recv mode, just make sure dongle has started sending */
6434 if (bus->pktgen_mode == DHD_PKTGEN_RECV) {
6435 if (bus->pktgen_rcv_state == PKTGEN_RCV_IDLE) {
6436 bus->pktgen_rcv_state = PKTGEN_RCV_ONGOING;
6437 dhdsdio_sdtest_set(bus, bus->pktgen_total);
6438 }
6439 return;
6440 }
6441
6442 /* Otherwise, generate or request the specified number of packets */
6443 for (pktcount = 0; pktcount < bus->pktgen_count; pktcount++) {
6444 /* Stop if total has been reached */
6445 if (bus->pktgen_total && (bus->pktgen_sent >= bus->pktgen_total)) {
6446 bus->pktgen_count = 0;
6447 break;
6448 }
6449
6450 /* Allocate an appropriate-sized packet */
6451 if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) {
6452 len = SDPCM_TEST_PKT_CNT_FLD_LEN;
6453 } else {
6454 len = bus->pktgen_len;
6455 }
6456 if (!(pkt = PKTGET(osh, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN),
6457 TRUE))) {;
6458 DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__));
6459 break;
6460 }
6461 PKTALIGN(osh, pkt, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN), DHD_SDALIGN);
6462 data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
6463
6464 /* Write test header cmd and extra based on mode */
6465 switch (bus->pktgen_mode) {
6466 case DHD_PKTGEN_ECHO:
6467 *data++ = SDPCM_TEST_ECHOREQ;
6468 *data++ = (uint8)bus->pktgen_sent;
6469 break;
6470
6471 case DHD_PKTGEN_SEND:
6472 *data++ = SDPCM_TEST_DISCARD;
6473 *data++ = (uint8)bus->pktgen_sent;
6474 break;
6475
6476 case DHD_PKTGEN_RXBURST:
6477 *data++ = SDPCM_TEST_BURST;
6478 *data++ = (uint8)bus->pktgen_count; /* Just for backward compatability */
6479 break;
6480
6481 default:
6482 DHD_ERROR(("Unrecognized pktgen mode %d\n", bus->pktgen_mode));
6483 PKTFREE(osh, pkt, TRUE);
6484 bus->pktgen_count = 0;
6485 return;
6486 }
6487
6488 /* Write test header length field */
6489 *data++ = (bus->pktgen_len >> 0);
6490 *data++ = (bus->pktgen_len >> 8);
6491
6492 /* Write frame count in a 4 byte field adjucent to SDPCM test header for
6493 * burst mode
6494 */
6495 if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) {
6496 *data++ = (uint8)(bus->pktgen_count >> 0);
6497 *data++ = (uint8)(bus->pktgen_count >> 8);
6498 *data++ = (uint8)(bus->pktgen_count >> 16);
6499 *data++ = (uint8)(bus->pktgen_count >> 24);
6500 } else {
6501
6502 /* Then fill in the remainder -- N/A for burst */
6503 for (fillbyte = 0; fillbyte < len; fillbyte++)
6504 *data++ = SDPCM_TEST_FILL(fillbyte, (uint8)bus->pktgen_sent);
6505 }
6506
6507 #ifdef DHD_DEBUG
6508 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
6509 data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
6510 prhex("dhdsdio_pktgen: Tx Data", data, PKTLEN(osh, pkt) - SDPCM_HDRLEN);
6511 }
6512 #endif
6513
6514 /* Send it */
6515 if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE, FALSE)) {
6516 bus->pktgen_fail++;
6517 if (bus->pktgen_stop && bus->pktgen_stop == bus->pktgen_fail)
6518 bus->pktgen_count = 0;
6519 }
6520 bus->pktgen_sent++;
6521
6522 /* Bump length if not fixed, wrap at max */
6523 if (++bus->pktgen_len > bus->pktgen_maxlen)
6524 bus->pktgen_len = (uint16)bus->pktgen_minlen;
6525
6526 /* Special case for burst mode: just send one request! */
6527 if (bus->pktgen_mode == DHD_PKTGEN_RXBURST)
6528 break;
6529 }
6530 }
6531
6532 static void
dhdsdio_sdtest_set(dhd_bus_t * bus,uint count)6533 dhdsdio_sdtest_set(dhd_bus_t *bus, uint count)
6534 {
6535 void *pkt;
6536 uint8 *data;
6537 osl_t *osh = bus->dhd->osh;
6538
6539 /* Allocate the packet */
6540 if (!(pkt = PKTGET(osh, SDPCM_HDRLEN + SDPCM_TEST_HDRLEN +
6541 SDPCM_TEST_PKT_CNT_FLD_LEN + DHD_SDALIGN, TRUE))) {
6542 DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__));
6543 return;
6544 }
6545 PKTALIGN(osh, pkt, (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN +
6546 SDPCM_TEST_PKT_CNT_FLD_LEN), DHD_SDALIGN);
6547 data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
6548
6549 /* Fill in the test header */
6550 *data++ = SDPCM_TEST_SEND;
6551 *data++ = (count > 0)?TRUE:FALSE;
6552 *data++ = (bus->pktgen_maxlen >> 0);
6553 *data++ = (bus->pktgen_maxlen >> 8);
6554 *data++ = (uint8)(count >> 0);
6555 *data++ = (uint8)(count >> 8);
6556 *data++ = (uint8)(count >> 16);
6557 *data++ = (uint8)(count >> 24);
6558
6559 /* Send it */
6560 if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE, FALSE))
6561 bus->pktgen_fail++;
6562 }
6563
6564
6565 static void
dhdsdio_testrcv(dhd_bus_t * bus,void * pkt,uint seq)6566 dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq)
6567 {
6568 osl_t *osh = bus->dhd->osh;
6569 uint8 *data;
6570 uint pktlen;
6571
6572 uint8 cmd;
6573 uint8 extra;
6574 uint16 len;
6575 uint16 offset;
6576
6577 /* Check for min length */
6578 if ((pktlen = PKTLEN(osh, pkt)) < SDPCM_TEST_HDRLEN) {
6579 DHD_ERROR(("dhdsdio_restrcv: toss runt frame, pktlen %d\n", pktlen));
6580 PKTFREE(osh, pkt, FALSE);
6581 return;
6582 }
6583
6584 /* Extract header fields */
6585 data = PKTDATA(osh, pkt);
6586 cmd = *data++;
6587 extra = *data++;
6588 len = *data++; len += *data++ << 8;
6589 DHD_TRACE(("%s:cmd:%d, xtra:%d,len:%d\n", __FUNCTION__, cmd, extra, len));
6590 /* Check length for relevant commands */
6591 if (cmd == SDPCM_TEST_DISCARD || cmd == SDPCM_TEST_ECHOREQ || cmd == SDPCM_TEST_ECHORSP) {
6592 if (pktlen != len + SDPCM_TEST_HDRLEN) {
6593 DHD_ERROR(("dhdsdio_testrcv: frame length mismatch, pktlen %d seq %d"
6594 " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len));
6595 PKTFREE(osh, pkt, FALSE);
6596 return;
6597 }
6598 }
6599
6600 /* Process as per command */
6601 switch (cmd) {
6602 case SDPCM_TEST_ECHOREQ:
6603 /* Rx->Tx turnaround ok (even on NDIS w/current implementation) */
6604 *(uint8 *)(PKTDATA(osh, pkt)) = SDPCM_TEST_ECHORSP;
6605 if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE, FALSE) == 0) {
6606 bus->pktgen_sent++;
6607 } else {
6608 bus->pktgen_fail++;
6609 PKTFREE(osh, pkt, FALSE);
6610 }
6611 bus->pktgen_rcvd++;
6612 break;
6613
6614 case SDPCM_TEST_ECHORSP:
6615 if (bus->ext_loop) {
6616 PKTFREE(osh, pkt, FALSE);
6617 bus->pktgen_rcvd++;
6618 break;
6619 }
6620
6621 for (offset = 0; offset < len; offset++, data++) {
6622 if (*data != SDPCM_TEST_FILL(offset, extra)) {
6623 DHD_ERROR(("dhdsdio_testrcv: echo data mismatch: "
6624 "offset %d (len %d) expect 0x%02x rcvd 0x%02x\n",
6625 offset, len, SDPCM_TEST_FILL(offset, extra), *data));
6626 break;
6627 }
6628 }
6629 PKTFREE(osh, pkt, FALSE);
6630 bus->pktgen_rcvd++;
6631 break;
6632
6633 case SDPCM_TEST_DISCARD:
6634 {
6635 int i = 0;
6636 uint8 *prn = data;
6637 uint8 testval = extra;
6638 for (i = 0; i < len; i++) {
6639 if (*prn != testval) {
6640 DHD_ERROR(("DIErr@Pkt#:%d,Ix:%d, expected:0x%x, got:0x%x\n",
6641 i, bus->pktgen_rcvd_rcvsession, testval, *prn));
6642 prn++; testval++;
6643 }
6644 }
6645 }
6646 PKTFREE(osh, pkt, FALSE);
6647 bus->pktgen_rcvd++;
6648 break;
6649
6650 case SDPCM_TEST_BURST:
6651 case SDPCM_TEST_SEND:
6652 default:
6653 DHD_INFO(("dhdsdio_testrcv: unsupported or unknown command, pktlen %d seq %d"
6654 " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len));
6655 PKTFREE(osh, pkt, FALSE);
6656 break;
6657 }
6658
6659 /* For recv mode, stop at limit (and tell dongle to stop sending) */
6660 if (bus->pktgen_mode == DHD_PKTGEN_RECV) {
6661 if (bus->pktgen_rcv_state != PKTGEN_RCV_IDLE) {
6662 bus->pktgen_rcvd_rcvsession++;
6663
6664 if (bus->pktgen_total &&
6665 (bus->pktgen_rcvd_rcvsession >= bus->pktgen_total)) {
6666 bus->pktgen_count = 0;
6667 DHD_ERROR(("Pktgen:rcv test complete!\n"));
6668 bus->pktgen_rcv_state = PKTGEN_RCV_IDLE;
6669 dhdsdio_sdtest_set(bus, FALSE);
6670 bus->pktgen_rcvd_rcvsession = 0;
6671 }
6672 }
6673 }
6674 }
6675 #endif /* SDTEST */
6676
6677 extern void
dhd_disable_intr(dhd_pub_t * dhdp)6678 dhd_disable_intr(dhd_pub_t *dhdp)
6679 {
6680 dhd_bus_t *bus;
6681 bus = dhdp->bus;
6682 bcmsdh_intr_disable(bus->sdh);
6683 }
6684
6685 extern bool
dhd_bus_watchdog(dhd_pub_t * dhdp)6686 dhd_bus_watchdog(dhd_pub_t *dhdp)
6687 {
6688 dhd_bus_t *bus;
6689
6690 DHD_TIMER(("%s: Enter\n", __FUNCTION__));
6691
6692 bus = dhdp->bus;
6693
6694 if (bus->dhd->dongle_reset)
6695 return FALSE;
6696
6697 /* Ignore the timer if simulating bus down */
6698 if (!SLPAUTO_ENAB(bus) && bus->sleeping)
6699 return FALSE;
6700
6701 if (dhdp->busstate == DHD_BUS_DOWN)
6702 return FALSE;
6703
6704 /* Poll period: check device if appropriate. */
6705 if (!SLPAUTO_ENAB(bus) && (bus->poll && (++bus->polltick >= bus->pollrate))) {
6706 uint32 intstatus = 0;
6707
6708 /* Reset poll tick */
6709 bus->polltick = 0;
6710
6711 /* Check device if no interrupts */
6712 if (!bus->intr || (bus->intrcount == bus->lastintrs)) {
6713
6714 if (!bus->dpc_sched) {
6715 uint8 devpend;
6716 devpend = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0,
6717 SDIOD_CCCR_INTPEND, NULL);
6718 intstatus = devpend & (INTR_STATUS_FUNC1 | INTR_STATUS_FUNC2);
6719 }
6720
6721 /* If there is something, make like the ISR and schedule the DPC */
6722 if (intstatus) {
6723 bus->pollcnt++;
6724 bus->ipend = TRUE;
6725 if (bus->intr) {
6726 bcmsdh_intr_disable(bus->sdh);
6727 }
6728 bus->dpc_sched = TRUE;
6729 dhd_sched_dpc(bus->dhd);
6730
6731 }
6732 }
6733
6734 /* Update interrupt tracking */
6735 bus->lastintrs = bus->intrcount;
6736 }
6737
6738 #ifdef DHD_DEBUG
6739 /* Poll for console output periodically */
6740 if (dhdp->busstate == DHD_BUS_DATA && dhd_console_ms != 0) {
6741 bus->console.count += dhd_watchdog_ms;
6742 if (bus->console.count >= dhd_console_ms) {
6743 bus->console.count -= dhd_console_ms;
6744 /* Make sure backplane clock is on */
6745 if (SLPAUTO_ENAB(bus))
6746 dhdsdio_bussleep(bus, FALSE);
6747 else
6748 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
6749 if (dhdsdio_readconsole(bus) < 0)
6750 dhd_console_ms = 0; /* On error, stop trying */
6751 }
6752 }
6753 #endif /* DHD_DEBUG */
6754
6755 #ifdef SDTEST
6756 /* Generate packets if configured */
6757 if (bus->pktgen_count && (++bus->pktgen_tick >= bus->pktgen_freq)) {
6758 /* Make sure backplane clock is on */
6759 if (SLPAUTO_ENAB(bus))
6760 dhdsdio_bussleep(bus, FALSE);
6761 else
6762 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
6763 bus->pktgen_tick = 0;
6764 dhdsdio_pktgen(bus);
6765 }
6766 #endif
6767
6768 /* On idle timeout clear activity flag and/or turn off clock */
6769 #ifdef DHD_USE_IDLECOUNT
6770 if (bus->activity)
6771 bus->activity = FALSE;
6772 else {
6773 bus->idlecount++;
6774
6775 if ((bus->idletime > 0) && (bus->idlecount >= bus->idletime)) {
6776 DHD_TIMER(("%s: DHD Idle state!!\n", __FUNCTION__));
6777 if (SLPAUTO_ENAB(bus)) {
6778 if (dhdsdio_bussleep(bus, TRUE) != BCME_BUSY)
6779 dhd_os_wd_timer(bus->dhd, 0);
6780 } else
6781 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
6782
6783 bus->idlecount = 0;
6784 }
6785 }
6786 #else
6787 if ((bus->idletime > 0) && (bus->clkstate == CLK_AVAIL)) {
6788 if (++bus->idlecount > bus->idletime) {
6789 bus->idlecount = 0;
6790 if (bus->activity) {
6791 bus->activity = FALSE;
6792 if (SLPAUTO_ENAB(bus)) {
6793 if (!bus->readframes)
6794 dhdsdio_bussleep(bus, TRUE);
6795 else
6796 bus->reqbussleep = TRUE;
6797 }
6798 else
6799 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
6800 }
6801 }
6802 }
6803 #endif /* DHD_USE_IDLECOUNT */
6804
6805 return bus->ipend;
6806 }
6807
6808 #ifdef DHD_DEBUG
6809 extern int
dhd_bus_console_in(dhd_pub_t * dhdp,uchar * msg,uint msglen)6810 dhd_bus_console_in(dhd_pub_t *dhdp, uchar *msg, uint msglen)
6811 {
6812 dhd_bus_t *bus = dhdp->bus;
6813 uint32 addr, val;
6814 int rv;
6815 void *pkt;
6816
6817 /* Address could be zero if CONSOLE := 0 in dongle Makefile */
6818 if (bus->console_addr == 0)
6819 return BCME_UNSUPPORTED;
6820
6821 /* Exclusive bus access */
6822 dhd_os_sdlock(bus->dhd);
6823
6824 /* Don't allow input if dongle is in reset */
6825 if (bus->dhd->dongle_reset) {
6826 dhd_os_sdunlock(bus->dhd);
6827 return BCME_NOTREADY;
6828 }
6829
6830 /* Request clock to allow SDIO accesses */
6831 BUS_WAKE(bus);
6832 /* No pend allowed since txpkt is called later, ht clk has to be on */
6833 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
6834
6835 /* Zero cbuf_index */
6836 addr = bus->console_addr + OFFSETOF(hndrte_cons_t, cbuf_idx);
6837 val = htol32(0);
6838 if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0)
6839 goto done;
6840
6841 /* Write message into cbuf */
6842 addr = bus->console_addr + OFFSETOF(hndrte_cons_t, cbuf);
6843 if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)msg, msglen)) < 0)
6844 goto done;
6845
6846 /* Write length into vcons_in */
6847 addr = bus->console_addr + OFFSETOF(hndrte_cons_t, vcons_in);
6848 val = htol32(msglen);
6849 if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0)
6850 goto done;
6851
6852 /* Bump dongle by sending an empty packet on the event channel.
6853 * sdpcm_sendup (RX) checks for virtual console input.
6854 */
6855 if ((pkt = PKTGET(bus->dhd->osh, 4 + SDPCM_RESERVE, TRUE)) != NULL)
6856 dhdsdio_txpkt(bus, pkt, SDPCM_EVENT_CHANNEL, TRUE, FALSE);
6857
6858 done:
6859 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
6860 bus->activity = FALSE;
6861 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
6862 }
6863
6864 dhd_os_sdunlock(bus->dhd);
6865
6866 return rv;
6867 }
6868 #endif /* DHD_DEBUG */
6869
6870 #ifdef DHD_DEBUG
6871 static void
dhd_dump_cis(uint fn,uint8 * cis)6872 dhd_dump_cis(uint fn, uint8 *cis)
6873 {
6874 uint byte, tag, tdata;
6875 DHD_INFO(("Function %d CIS:\n", fn));
6876
6877 for (tdata = byte = 0; byte < SBSDIO_CIS_SIZE_LIMIT; byte++) {
6878 if ((byte % 16) == 0)
6879 DHD_INFO((" "));
6880 DHD_INFO(("%02x ", cis[byte]));
6881 if ((byte % 16) == 15)
6882 DHD_INFO(("\n"));
6883 if (!tdata--) {
6884 tag = cis[byte];
6885 if (tag == 0xff)
6886 break;
6887 else if (!tag)
6888 tdata = 0;
6889 else if ((byte + 1) < SBSDIO_CIS_SIZE_LIMIT)
6890 tdata = cis[byte + 1] + 1;
6891 else
6892 DHD_INFO(("]"));
6893 }
6894 }
6895 if ((byte % 16) != 15)
6896 DHD_INFO(("\n"));
6897 }
6898 #endif /* DHD_DEBUG */
6899
6900 static bool
dhdsdio_chipmatch(uint16 chipid)6901 dhdsdio_chipmatch(uint16 chipid)
6902 {
6903 if (chipid == BCM4325_CHIP_ID)
6904 return TRUE;
6905 if (chipid == BCM4329_CHIP_ID)
6906 return TRUE;
6907 if (chipid == BCM4315_CHIP_ID)
6908 return TRUE;
6909 if (chipid == BCM4319_CHIP_ID)
6910 return TRUE;
6911 if (chipid == BCM4336_CHIP_ID)
6912 return TRUE;
6913 if (chipid == BCM4330_CHIP_ID)
6914 return TRUE;
6915 if (chipid == BCM43237_CHIP_ID)
6916 return TRUE;
6917 if (chipid == BCM43362_CHIP_ID)
6918 return TRUE;
6919 if (chipid == BCM4314_CHIP_ID)
6920 return TRUE;
6921 if (chipid == BCM43242_CHIP_ID)
6922 return TRUE;
6923 if (chipid == BCM43340_CHIP_ID)
6924 return TRUE;
6925 if (chipid == BCM43341_CHIP_ID)
6926 return TRUE;
6927 if (chipid == BCM43143_CHIP_ID)
6928 return TRUE;
6929 if (chipid == BCM43342_CHIP_ID)
6930 return TRUE;
6931 if (chipid == BCM4334_CHIP_ID)
6932 return TRUE;
6933 if (chipid == BCM43239_CHIP_ID)
6934 return TRUE;
6935 if (chipid == BCM4324_CHIP_ID)
6936 return TRUE;
6937 if (chipid == BCM4335_CHIP_ID)
6938 return TRUE;
6939 if (chipid == BCM4339_CHIP_ID)
6940 return TRUE;
6941 if (chipid == BCM4350_CHIP_ID)
6942 return TRUE;
6943 return FALSE;
6944 }
6945
6946 static void *
dhdsdio_probe(uint16 venid,uint16 devid,uint16 bus_no,uint16 slot,uint16 func,uint bustype,void * regsva,osl_t * osh,void * sdh)6947 dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot,
6948 uint16 func, uint bustype, void *regsva, osl_t * osh, void *sdh)
6949 {
6950 int ret;
6951 dhd_bus_t *bus;
6952 #ifdef GET_CUSTOM_MAC_ENABLE
6953 struct ether_addr ea_addr;
6954 #endif /* GET_CUSTOM_MAC_ENABLE */
6955
6956
6957 /* Init global variables at run-time, not as part of the declaration.
6958 * This is required to support init/de-init of the driver. Initialization
6959 * of globals as part of the declaration results in non-deterministic
6960 * behavior since the value of the globals may be different on the
6961 * first time that the driver is initialized vs subsequent initializations.
6962 */
6963 dhd_txbound = DHD_TXBOUND;
6964 dhd_rxbound = DHD_RXBOUND;
6965 dhd_alignctl = TRUE;
6966 sd1idle = TRUE;
6967 dhd_readahead = TRUE;
6968 retrydata = FALSE;
6969 dhd_doflow = TRUE;
6970 dhd_dongle_ramsize = 0;
6971 dhd_txminmax = DHD_TXMINMAX;
6972
6973 forcealign = TRUE;
6974
6975 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
6976 DHD_INFO(("%s: venid 0x%04x devid 0x%04x\n", __FUNCTION__, venid, devid));
6977
6978 /* We make assumptions about address window mappings */
6979 ASSERT((uintptr)regsva == SI_ENUM_BASE);
6980
6981 /* BCMSDH passes venid and devid based on CIS parsing -- but low-power start
6982 * means early parse could fail, so here we should get either an ID
6983 * we recognize OR (-1) indicating we must request power first.
6984 */
6985 /* Check the Vendor ID */
6986 switch (venid) {
6987 case 0x0000:
6988 case VENDOR_BROADCOM:
6989 break;
6990 default:
6991 DHD_ERROR(("%s: unknown vendor: 0x%04x\n",
6992 __FUNCTION__, venid));
6993 goto forcereturn;
6994 }
6995
6996 /* Check the Device ID and make sure it's one that we support */
6997 switch (devid) {
6998 case BCM4325_D11DUAL_ID: /* 4325 802.11a/g id */
6999 case BCM4325_D11G_ID: /* 4325 802.11g 2.4Ghz band id */
7000 case BCM4325_D11A_ID: /* 4325 802.11a 5Ghz band id */
7001 DHD_INFO(("%s: found 4325 Dongle\n", __FUNCTION__));
7002 break;
7003 case BCM4329_D11N_ID: /* 4329 802.11n dualband device */
7004 case BCM4329_D11N2G_ID: /* 4329 802.11n 2.4G device */
7005 case BCM4329_D11N5G_ID: /* 4329 802.11n 5G device */
7006 case 0x4329:
7007 DHD_INFO(("%s: found 4329 Dongle\n", __FUNCTION__));
7008 break;
7009 case BCM4315_D11DUAL_ID: /* 4315 802.11a/g id */
7010 case BCM4315_D11G_ID: /* 4315 802.11g id */
7011 case BCM4315_D11A_ID: /* 4315 802.11a id */
7012 DHD_INFO(("%s: found 4315 Dongle\n", __FUNCTION__));
7013 break;
7014 case BCM4319_D11N_ID: /* 4319 802.11n id */
7015 case BCM4319_D11N2G_ID: /* 4319 802.11n2g id */
7016 case BCM4319_D11N5G_ID: /* 4319 802.11n5g id */
7017 DHD_INFO(("%s: found 4319 Dongle\n", __FUNCTION__));
7018 break;
7019 case 0:
7020 DHD_INFO(("%s: allow device id 0, will check chip internals\n",
7021 __FUNCTION__));
7022 break;
7023
7024 default:
7025 DHD_ERROR(("%s: skipping 0x%04x/0x%04x, not a dongle\n",
7026 __FUNCTION__, venid, devid));
7027 goto forcereturn;
7028 }
7029
7030 if (osh == NULL) {
7031 /* Ask the OS interface part for an OSL handle */
7032 if (!(osh = dhd_osl_attach(sdh, DHD_BUS))) {
7033 DHD_ERROR(("%s: osl_attach failed!\n", __FUNCTION__));
7034 goto forcereturn;
7035 }
7036 }
7037
7038 /* Allocate private bus interface state */
7039 if (!(bus = MALLOC(osh, sizeof(dhd_bus_t)))) {
7040 DHD_ERROR(("%s: MALLOC of dhd_bus_t failed\n", __FUNCTION__));
7041 goto fail;
7042 }
7043 bzero(bus, sizeof(dhd_bus_t));
7044 bus->sdh = sdh;
7045 bus->cl_devid = (uint16)devid;
7046 bus->bus = DHD_BUS;
7047 bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1;
7048 bus->usebufpool = FALSE; /* Use bufpool if allocated, else use locally malloced rxbuf */
7049
7050 /* attach the common module */
7051 dhd_common_init(osh);
7052
7053 /* attempt to attach to the dongle */
7054 if (!(dhdsdio_probe_attach(bus, osh, sdh, regsva, devid))) {
7055 DHD_ERROR(("%s: dhdsdio_probe_attach failed\n", __FUNCTION__));
7056 goto fail;
7057 }
7058
7059 /* Attach to the dhd/OS/network interface */
7060 if (!(bus->dhd = dhd_attach(osh, bus, SDPCM_RESERVE))) {
7061 DHD_ERROR(("%s: dhd_attach failed\n", __FUNCTION__));
7062 goto fail;
7063 }
7064
7065 /* Allocate buffers */
7066 if (!(dhdsdio_probe_malloc(bus, osh, sdh))) {
7067 DHD_ERROR(("%s: dhdsdio_probe_malloc failed\n", __FUNCTION__));
7068 goto fail;
7069 }
7070
7071 if (!(dhdsdio_probe_init(bus, osh, sdh))) {
7072 DHD_ERROR(("%s: dhdsdio_probe_init failed\n", __FUNCTION__));
7073 goto fail;
7074 }
7075
7076 if (bus->intr) {
7077 /* Register interrupt callback, but mask it (not operational yet). */
7078 DHD_INTR(("%s: disable SDIO interrupts (not interested yet)\n", __FUNCTION__));
7079 bcmsdh_intr_disable(sdh);
7080 if ((ret = bcmsdh_intr_reg(sdh, dhdsdio_isr, bus)) != 0) {
7081 DHD_ERROR(("%s: FAILED: bcmsdh_intr_reg returned %d\n",
7082 __FUNCTION__, ret));
7083 goto fail;
7084 }
7085 DHD_INTR(("%s: registered SDIO interrupt function ok\n", __FUNCTION__));
7086 } else {
7087 DHD_INFO(("%s: SDIO interrupt function is NOT registered due to polling mode\n",
7088 __FUNCTION__));
7089 }
7090
7091 DHD_INFO(("%s: completed!!\n", __FUNCTION__));
7092
7093 #ifdef GET_CUSTOM_MAC_ENABLE
7094 /* Read MAC address from external customer place */
7095 memset(&ea_addr, 0, sizeof(ea_addr));
7096 ret = dhd_custom_get_mac_address(ea_addr.octet);
7097 if (!ret) {
7098 memcpy(bus->dhd->mac.octet, (void *)&ea_addr, ETHER_ADDR_LEN);
7099 }
7100 #endif /* GET_CUSTOM_MAC_ENABLE */
7101
7102 /* if firmware path present try to download and bring up bus */
7103 bus->dhd->hang_report = TRUE;
7104 if (dhd_download_fw_on_driverload) {
7105 if ((ret = dhd_bus_start(bus->dhd)) != 0) {
7106 DHD_ERROR(("%s: dhd_bus_start failed\n", __FUNCTION__));
7107 goto fail;
7108 }
7109 }
7110 /* Ok, have the per-port tell the stack we're open for business */
7111 if (dhd_net_attach(bus->dhd, 0) != 0) {
7112 DHD_ERROR(("%s: Net attach failed!!\n", __FUNCTION__));
7113 goto fail;
7114 }
7115
7116
7117
7118 return bus;
7119
7120 fail:
7121 dhdsdio_release(bus, osh);
7122
7123 forcereturn:
7124
7125 return NULL;
7126 }
7127
7128 static bool
dhdsdio_probe_attach(struct dhd_bus * bus,osl_t * osh,void * sdh,void * regsva,uint16 devid)7129 dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva,
7130 uint16 devid)
7131 {
7132 int err = 0;
7133 uint8 clkctl = 0;
7134
7135 bus->alp_only = TRUE;
7136 bus->sih = NULL;
7137
7138 /* Return the window to backplane enumeration space for core access */
7139 if (dhdsdio_set_siaddr_window(bus, SI_ENUM_BASE)) {
7140 DHD_ERROR(("%s: FAILED to return to SI_ENUM_BASE\n", __FUNCTION__));
7141 }
7142
7143
7144 /* Force PLL off until si_attach() programs PLL control regs */
7145
7146
7147
7148 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, DHD_INIT_CLKCTL1, &err);
7149 if (!err)
7150 clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
7151
7152 if (err || ((clkctl & ~SBSDIO_AVBITS) != DHD_INIT_CLKCTL1)) {
7153 DHD_ERROR(("dhdsdio_probe: ChipClkCSR access: err %d wrote 0x%02x read 0x%02x\n",
7154 err, DHD_INIT_CLKCTL1, clkctl));
7155 goto fail;
7156 }
7157
7158 #ifdef DHD_DEBUG
7159 if (DHD_INFO_ON()) {
7160 uint fn, numfn;
7161 uint8 *cis[SDIOD_MAX_IOFUNCS];
7162 int err = 0;
7163
7164 numfn = bcmsdh_query_iofnum(sdh);
7165 ASSERT(numfn <= SDIOD_MAX_IOFUNCS);
7166
7167 /* Make sure ALP is available before trying to read CIS */
7168 SPINWAIT(((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
7169 SBSDIO_FUNC1_CHIPCLKCSR, NULL)),
7170 !SBSDIO_ALPAV(clkctl)), PMU_MAX_TRANSITION_DLY);
7171
7172 /* Now request ALP be put on the bus */
7173 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
7174 DHD_INIT_CLKCTL2, &err);
7175 OSL_DELAY(65);
7176
7177 for (fn = 0; fn <= numfn; fn++) {
7178 if (!(cis[fn] = MALLOC(osh, SBSDIO_CIS_SIZE_LIMIT))) {
7179 DHD_INFO(("dhdsdio_probe: fn %d cis malloc failed\n", fn));
7180 break;
7181 }
7182 bzero(cis[fn], SBSDIO_CIS_SIZE_LIMIT);
7183
7184 if ((err = bcmsdh_cis_read(sdh, fn, cis[fn], SBSDIO_CIS_SIZE_LIMIT))) {
7185 DHD_INFO(("dhdsdio_probe: fn %d cis read err %d\n", fn, err));
7186 MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT);
7187 break;
7188 }
7189 dhd_dump_cis(fn, cis[fn]);
7190 }
7191
7192 while (fn-- > 0) {
7193 ASSERT(cis[fn]);
7194 MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT);
7195 }
7196
7197 if (err) {
7198 DHD_ERROR(("dhdsdio_probe: failure reading or parsing CIS\n"));
7199 goto fail;
7200 }
7201 }
7202 #endif /* DHD_DEBUG */
7203
7204 /* si_attach() will provide an SI handle and scan the backplane */
7205 if (!(bus->sih = si_attach((uint)devid, osh, regsva, DHD_BUS, sdh,
7206 &bus->vars, &bus->varsz))) {
7207 DHD_ERROR(("%s: si_attach failed!\n", __FUNCTION__));
7208 goto fail;
7209 }
7210
7211
7212 #ifdef DHD_DEBUG
7213 DHD_ERROR(("F1 signature OK, socitype:0x%x chip:0x%4x rev:0x%x pkg:0x%x\n",
7214 bus->sih->socitype, bus->sih->chip, bus->sih->chiprev,
7215 bus->sih->chippkg));
7216 #endif /* DHD_DEBUG */
7217
7218
7219 bcmsdh_chipinfo(sdh, bus->sih->chip, bus->sih->chiprev);
7220
7221 if (!dhdsdio_chipmatch((uint16)bus->sih->chip)) {
7222 DHD_ERROR(("%s: unsupported chip: 0x%04x\n",
7223 __FUNCTION__, bus->sih->chip));
7224 goto fail;
7225 }
7226
7227 if (bus->sih->buscorerev >= 12)
7228 dhdsdio_clk_kso_init(bus);
7229 else
7230 bus->kso = TRUE;
7231
7232 if (CST4330_CHIPMODE_SDIOD(bus->sih->chipst)) {
7233 }
7234
7235 si_sdiod_drive_strength_init(bus->sih, osh, dhd_sdiod_drive_strength);
7236
7237
7238 /* Get info on the ARM and SOCRAM cores... */
7239 if (!DHD_NOPMU(bus)) {
7240 if ((si_setcore(bus->sih, ARM7S_CORE_ID, 0)) ||
7241 (si_setcore(bus->sih, ARMCM3_CORE_ID, 0)) ||
7242 (si_setcore(bus->sih, ARMCR4_CORE_ID, 0))) {
7243 bus->armrev = si_corerev(bus->sih);
7244 } else {
7245 DHD_ERROR(("%s: failed to find ARM core!\n", __FUNCTION__));
7246 goto fail;
7247 }
7248
7249 if (!si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
7250 if (!(bus->orig_ramsize = si_socram_size(bus->sih))) {
7251 DHD_ERROR(("%s: failed to find SOCRAM memory!\n", __FUNCTION__));
7252 goto fail;
7253 }
7254 } else {
7255 /* cr4 has a different way to find the RAM size from TCM's */
7256 if (!(bus->orig_ramsize = si_tcm_size(bus->sih))) {
7257 DHD_ERROR(("%s: failed to find CR4-TCM memory!\n", __FUNCTION__));
7258 goto fail;
7259 }
7260 /* also populate base address */
7261 switch ((uint16)bus->sih->chip) {
7262 case BCM4335_CHIP_ID:
7263 case BCM4339_CHIP_ID:
7264 bus->dongle_ram_base = CR4_4335_RAM_BASE;
7265 break;
7266 case BCM4350_CHIP_ID:
7267 bus->dongle_ram_base = CR4_4350_RAM_BASE;
7268 break;
7269 case BCM4360_CHIP_ID:
7270 bus->dongle_ram_base = CR4_4360_RAM_BASE;
7271 break;
7272 default:
7273 bus->dongle_ram_base = 0;
7274 DHD_ERROR(("%s: WARNING: Using default ram base at 0x%x\n",
7275 __FUNCTION__, bus->dongle_ram_base));
7276 }
7277 }
7278 bus->ramsize = bus->orig_ramsize;
7279 if (dhd_dongle_ramsize)
7280 dhd_dongle_setramsize(bus, dhd_dongle_ramsize);
7281
7282 DHD_ERROR(("DHD: dongle ram size is set to %d(orig %d) at 0x%x\n",
7283 bus->ramsize, bus->orig_ramsize, bus->dongle_ram_base));
7284
7285 bus->srmemsize = si_socram_srmem_size(bus->sih);
7286 }
7287
7288 /* ...but normally deal with the SDPCMDEV core */
7289 if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0)) &&
7290 !(bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0))) {
7291 DHD_ERROR(("%s: failed to find SDIODEV core!\n", __FUNCTION__));
7292 goto fail;
7293 }
7294 bus->sdpcmrev = si_corerev(bus->sih);
7295
7296 /* Set core control so an SDIO reset does a backplane reset */
7297 OR_REG(osh, &bus->regs->corecontrol, CC_BPRESEN);
7298 bus->rxint_mode = SDIO_DEVICE_HMB_RXINT;
7299
7300 if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev >= 4) &&
7301 (bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_1))
7302 {
7303 uint32 val;
7304
7305 val = R_REG(osh, &bus->regs->corecontrol);
7306 val &= ~CC_XMTDATAAVAIL_MODE;
7307 val |= CC_XMTDATAAVAIL_CTRL;
7308 W_REG(osh, &bus->regs->corecontrol, val);
7309 }
7310
7311
7312 pktq_init(&bus->txq, (PRIOMASK + 1), QLEN);
7313
7314 /* Locate an appropriately-aligned portion of hdrbuf */
7315 bus->rxhdr = (uint8 *)ROUNDUP((uintptr)&bus->hdrbuf[0], DHD_SDALIGN);
7316
7317 /* Set the poll and/or interrupt flags */
7318 bus->intr = (bool)dhd_intr;
7319 if ((bus->poll = (bool)dhd_poll))
7320 bus->pollrate = 1;
7321
7322 #ifdef BCMSDIOH_TXGLOM
7323 /* Setting default Glom mode */
7324 bus->glom_mode = bcmsdh_set_mode(bus->sdh, SDPCM_DEFGLOM_MODE);
7325 /* Setting default Glom size */
7326 bus->glomsize = SDPCM_DEFGLOM_SIZE;
7327 #endif
7328
7329 return TRUE;
7330
7331 fail:
7332 if (bus->sih != NULL) {
7333 si_detach(bus->sih);
7334 bus->sih = NULL;
7335 }
7336 return FALSE;
7337 }
7338
7339 static bool
dhdsdio_probe_malloc(dhd_bus_t * bus,osl_t * osh,void * sdh)7340 dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh)
7341 {
7342 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7343
7344 if (bus->dhd->maxctl) {
7345 bus->rxblen = ROUNDUP((bus->dhd->maxctl + SDPCM_HDRLEN), ALIGNMENT) + DHD_SDALIGN;
7346 if (!(bus->rxbuf = DHD_OS_PREALLOC(osh, DHD_PREALLOC_RXBUF, bus->rxblen))) {
7347 DHD_ERROR(("%s: MALLOC of %d-byte rxbuf failed\n",
7348 __FUNCTION__, bus->rxblen));
7349 goto fail;
7350 }
7351 }
7352 /* Allocate buffer to receive glomed packet */
7353 if (!(bus->databuf = DHD_OS_PREALLOC(osh, DHD_PREALLOC_DATABUF, MAX_DATA_BUF))) {
7354 DHD_ERROR(("%s: MALLOC of %d-byte databuf failed\n",
7355 __FUNCTION__, MAX_DATA_BUF));
7356 /* release rxbuf which was already located as above */
7357 if (!bus->rxblen)
7358 DHD_OS_PREFREE(osh, bus->rxbuf, bus->rxblen);
7359 goto fail;
7360 }
7361
7362 /* Align the buffer */
7363 if ((uintptr)bus->databuf % DHD_SDALIGN)
7364 bus->dataptr = bus->databuf + (DHD_SDALIGN - ((uintptr)bus->databuf % DHD_SDALIGN));
7365 else
7366 bus->dataptr = bus->databuf;
7367
7368 return TRUE;
7369
7370 fail:
7371 return FALSE;
7372 }
7373
7374 static bool
dhdsdio_probe_init(dhd_bus_t * bus,osl_t * osh,void * sdh)7375 dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh)
7376 {
7377 int32 fnum;
7378
7379 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7380
7381 #ifdef SDTEST
7382 dhdsdio_pktgen_init(bus);
7383 #endif /* SDTEST */
7384
7385 /* Disable F2 to clear any intermediate frame state on the dongle */
7386 bcmsdh_cfg_write(sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL);
7387
7388 bus->dhd->busstate = DHD_BUS_DOWN;
7389 bus->sleeping = FALSE;
7390 bus->rxflow = FALSE;
7391 bus->prev_rxlim_hit = 0;
7392
7393 /* Done with backplane-dependent accesses, can drop clock... */
7394 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
7395
7396 /* ...and initialize clock/power states */
7397 bus->clkstate = CLK_SDONLY;
7398 bus->idletime = (int32)dhd_idletime;
7399 bus->idleclock = DHD_IDLE_ACTIVE;
7400
7401 /* Query the SD clock speed */
7402 if (bcmsdh_iovar_op(sdh, "sd_divisor", NULL, 0,
7403 &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) {
7404 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_divisor"));
7405 bus->sd_divisor = -1;
7406 } else {
7407 DHD_INFO(("%s: Initial value for %s is %d\n",
7408 __FUNCTION__, "sd_divisor", bus->sd_divisor));
7409 }
7410
7411 /* Query the SD bus mode */
7412 if (bcmsdh_iovar_op(sdh, "sd_mode", NULL, 0,
7413 &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) {
7414 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_mode"));
7415 bus->sd_mode = -1;
7416 } else {
7417 DHD_INFO(("%s: Initial value for %s is %d\n",
7418 __FUNCTION__, "sd_mode", bus->sd_mode));
7419 }
7420
7421 /* Query the F2 block size, set roundup accordingly */
7422 fnum = 2;
7423 if (bcmsdh_iovar_op(sdh, "sd_blocksize", &fnum, sizeof(int32),
7424 &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) {
7425 bus->blocksize = 0;
7426 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize"));
7427 } else {
7428 DHD_INFO(("%s: Initial value for %s is %d\n",
7429 __FUNCTION__, "sd_blocksize", bus->blocksize));
7430
7431 if ((bus->sih->chip == BCM4335_CHIP_ID) ||
7432 (bus->sih->chip == BCM4339_CHIP_ID))
7433 dhd_overflow_war(bus);
7434 }
7435 bus->roundup = MIN(max_roundup, bus->blocksize);
7436
7437 /* Query if bus module supports packet chaining, default to use if supported */
7438 if (bcmsdh_iovar_op(sdh, "sd_rxchain", NULL, 0,
7439 &bus->sd_rxchain, sizeof(int32), FALSE) != BCME_OK) {
7440 bus->sd_rxchain = FALSE;
7441 } else {
7442 DHD_INFO(("%s: bus module (through bcmsdh API) %s chaining\n",
7443 __FUNCTION__, (bus->sd_rxchain ? "supports" : "does not support")));
7444 }
7445 bus->use_rxchain = (bool)bus->sd_rxchain;
7446
7447 return TRUE;
7448 }
7449
7450 bool
dhd_bus_download_firmware(struct dhd_bus * bus,osl_t * osh,char * pfw_path,char * pnv_path)7451 dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh,
7452 char *pfw_path, char *pnv_path)
7453 {
7454 bool ret;
7455 bus->fw_path = pfw_path;
7456 bus->nv_path = pnv_path;
7457
7458 ret = dhdsdio_download_firmware(bus, osh, bus->sdh);
7459
7460
7461 return ret;
7462 }
7463
7464 static bool
dhdsdio_download_firmware(struct dhd_bus * bus,osl_t * osh,void * sdh)7465 dhdsdio_download_firmware(struct dhd_bus *bus, osl_t *osh, void *sdh)
7466 {
7467 bool ret;
7468
7469 DHD_OS_WAKE_LOCK(bus->dhd);
7470
7471 /* Download the firmware */
7472 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
7473
7474 ret = _dhdsdio_download_firmware(bus) == 0;
7475
7476 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
7477
7478 DHD_OS_WAKE_UNLOCK(bus->dhd);
7479 return ret;
7480 }
7481
7482 /* Detach and free everything */
7483 static void
dhdsdio_release(dhd_bus_t * bus,osl_t * osh)7484 dhdsdio_release(dhd_bus_t *bus, osl_t *osh)
7485 {
7486 bool dongle_isolation = FALSE;
7487 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7488
7489 if (bus) {
7490 ASSERT(osh);
7491
7492 if (bus->dhd) {
7493 dongle_isolation = bus->dhd->dongle_isolation;
7494 dhd_detach(bus->dhd);
7495 }
7496
7497 /* De-register interrupt handler */
7498 bcmsdh_intr_disable(bus->sdh);
7499 bcmsdh_intr_dereg(bus->sdh);
7500
7501 if (bus->dhd) {
7502 dhdsdio_release_dongle(bus, osh, dongle_isolation, TRUE);
7503 dhd_free(bus->dhd);
7504 bus->dhd = NULL;
7505 }
7506
7507 dhdsdio_release_malloc(bus, osh);
7508
7509 #ifdef DHD_DEBUG
7510 if (bus->console.buf != NULL)
7511 MFREE(osh, bus->console.buf, bus->console.bufsize);
7512 #endif
7513
7514 MFREE(osh, bus, sizeof(dhd_bus_t));
7515 }
7516
7517 if (osh)
7518 dhd_osl_detach(osh);
7519
7520 DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
7521 }
7522
7523 static void
dhdsdio_release_malloc(dhd_bus_t * bus,osl_t * osh)7524 dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh)
7525 {
7526 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7527
7528 if (bus->dhd && bus->dhd->dongle_reset)
7529 return;
7530
7531 if (bus->rxbuf) {
7532 #ifndef CONFIG_DHD_USE_STATIC_BUF
7533 MFREE(osh, bus->rxbuf, bus->rxblen);
7534 #endif
7535 bus->rxctl = bus->rxbuf = NULL;
7536 bus->rxlen = 0;
7537 }
7538
7539 if (bus->databuf) {
7540 #ifndef CONFIG_DHD_USE_STATIC_BUF
7541 MFREE(osh, bus->databuf, MAX_DATA_BUF);
7542 #endif
7543 bus->databuf = NULL;
7544 }
7545
7546 if (bus->vars && bus->varsz) {
7547 MFREE(osh, bus->vars, bus->varsz);
7548 bus->vars = NULL;
7549 }
7550
7551 }
7552
7553
7554 static void
dhdsdio_release_dongle(dhd_bus_t * bus,osl_t * osh,bool dongle_isolation,bool reset_flag)7555 dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation, bool reset_flag)
7556 {
7557 DHD_TRACE(("%s: Enter bus->dhd %p bus->dhd->dongle_reset %d \n", __FUNCTION__,
7558 bus->dhd, bus->dhd->dongle_reset));
7559
7560 if ((bus->dhd && bus->dhd->dongle_reset) && reset_flag)
7561 return;
7562
7563 if (bus->sih) {
7564 #if !defined(BCMLXSDMMC)
7565 if (bus->dhd) {
7566 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
7567 }
7568 if (KSO_ENAB(bus) && (dongle_isolation == FALSE))
7569 si_watchdog(bus->sih, 4);
7570 #endif /* !defined(BCMLXSDMMC) */
7571 if (bus->dhd) {
7572 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
7573 }
7574 si_detach(bus->sih);
7575 bus->sih = NULL;
7576 if (bus->vars && bus->varsz)
7577 MFREE(osh, bus->vars, bus->varsz);
7578 bus->vars = NULL;
7579 }
7580
7581 DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
7582 }
7583
7584 static void
dhdsdio_disconnect(void * ptr)7585 dhdsdio_disconnect(void *ptr)
7586 {
7587 dhd_bus_t *bus = (dhd_bus_t *)ptr;
7588
7589 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7590
7591
7592
7593 if (bus) {
7594 ASSERT(bus->dhd);
7595 dhdsdio_release(bus, bus->dhd->osh);
7596 }
7597
7598
7599
7600 DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
7601 }
7602
7603
7604 /* Register/Unregister functions are called by the main DHD entry
7605 * point (e.g. module insertion) to link with the bus driver, in
7606 * order to look for or await the device.
7607 */
7608
7609 static bcmsdh_driver_t dhd_sdio = {
7610 dhdsdio_probe,
7611 dhdsdio_disconnect
7612 };
7613
7614 int
dhd_bus_register(void)7615 dhd_bus_register(void)
7616 {
7617 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7618
7619 return bcmsdh_register(&dhd_sdio);
7620 }
7621
7622 void
dhd_bus_unregister(void)7623 dhd_bus_unregister(void)
7624 {
7625 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
7626
7627 bcmsdh_unregister();
7628 }
7629
7630 #if defined(BCMLXSDMMC)
7631 /* Register a dummy SDIO client driver in order to be notified of new SDIO device */
dhd_bus_reg_sdio_notify(void * semaphore)7632 int dhd_bus_reg_sdio_notify(void* semaphore)
7633 {
7634 return bcmsdh_reg_sdio_notify(semaphore);
7635 }
7636
dhd_bus_unreg_sdio_notify(void)7637 void dhd_bus_unreg_sdio_notify(void)
7638 {
7639 bcmsdh_unreg_sdio_notify();
7640 }
7641 #endif /* defined(BCMLXSDMMC) */
7642
7643 #ifdef BCMEMBEDIMAGE
7644 static int
dhdsdio_download_code_array(struct dhd_bus * bus)7645 dhdsdio_download_code_array(struct dhd_bus *bus)
7646 {
7647 int bcmerror = -1;
7648 int offset = 0;
7649 unsigned char *ularray = NULL;
7650
7651 DHD_INFO(("%s: download embedded firmware...\n", __FUNCTION__));
7652
7653 /* Download image */
7654 while ((offset + MEMBLOCK) < sizeof(dlarray)) {
7655 /* check if CR4 */
7656 if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
7657 /* if address is 0, store the reset instruction to be written in 0 */
7658
7659 if (offset == 0) {
7660 bus->resetinstr = *(((uint32*)dlarray));
7661 /* Add start of RAM address to the address given by user */
7662 offset += bus->dongle_ram_base;
7663 }
7664 }
7665
7666 bcmerror = dhdsdio_membytes(bus, TRUE, offset,
7667 (uint8 *) (dlarray + offset), MEMBLOCK);
7668 if (bcmerror) {
7669 DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
7670 __FUNCTION__, bcmerror, MEMBLOCK, offset));
7671 goto err;
7672 }
7673
7674 offset += MEMBLOCK;
7675 }
7676
7677 if (offset < sizeof(dlarray)) {
7678 bcmerror = dhdsdio_membytes(bus, TRUE, offset,
7679 (uint8 *) (dlarray + offset), sizeof(dlarray) - offset);
7680 if (bcmerror) {
7681 DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
7682 __FUNCTION__, bcmerror, sizeof(dlarray) - offset, offset));
7683 goto err;
7684 }
7685 }
7686
7687 #ifdef DHD_DEBUG
7688 /* Upload and compare the downloaded code */
7689 {
7690 ularray = MALLOC(bus->dhd->osh, bus->ramsize);
7691 /* Upload image to verify downloaded contents. */
7692 offset = 0;
7693 memset(ularray, 0xaa, bus->ramsize);
7694 while ((offset + MEMBLOCK) < sizeof(dlarray)) {
7695 bcmerror = dhdsdio_membytes(bus, FALSE, offset, ularray + offset, MEMBLOCK);
7696 if (bcmerror) {
7697 DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n",
7698 __FUNCTION__, bcmerror, MEMBLOCK, offset));
7699 goto err;
7700 }
7701
7702 offset += MEMBLOCK;
7703 }
7704
7705 if (offset < sizeof(dlarray)) {
7706 bcmerror = dhdsdio_membytes(bus, FALSE, offset,
7707 ularray + offset, sizeof(dlarray) - offset);
7708 if (bcmerror) {
7709 DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n",
7710 __FUNCTION__, bcmerror, sizeof(dlarray) - offset, offset));
7711 goto err;
7712 }
7713 }
7714
7715 if (memcmp(dlarray, ularray, sizeof(dlarray))) {
7716 DHD_ERROR(("%s: Downloaded image is corrupted (%s, %s, %s).\n",
7717 __FUNCTION__, dlimagename, dlimagever, dlimagedate));
7718 goto err;
7719 } else
7720 DHD_ERROR(("%s: Download, Upload and compare succeeded (%s, %s, %s).\n",
7721 __FUNCTION__, dlimagename, dlimagever, dlimagedate));
7722
7723 }
7724 #endif /* DHD_DEBUG */
7725
7726 err:
7727 if (ularray)
7728 MFREE(bus->dhd->osh, ularray, bus->ramsize);
7729 return bcmerror;
7730 }
7731 #endif /* BCMEMBEDIMAGE */
7732
7733 static int
dhdsdio_download_code_file(struct dhd_bus * bus,char * pfw_path)7734 dhdsdio_download_code_file(struct dhd_bus *bus, char *pfw_path)
7735 {
7736 int bcmerror = -1;
7737 int offset = 0;
7738 int len;
7739 void *image = NULL;
7740 uint8 *memblock = NULL, *memptr;
7741
7742 DHD_INFO(("%s: download firmware %s\n", __FUNCTION__, pfw_path));
7743
7744 image = dhd_os_open_image(pfw_path);
7745 if (image == NULL)
7746 goto err;
7747
7748 memptr = memblock = MALLOC(bus->dhd->osh, MEMBLOCK + DHD_SDALIGN);
7749 if (memblock == NULL) {
7750 DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, MEMBLOCK));
7751 goto err;
7752 }
7753 if ((uint32)(uintptr)memblock % DHD_SDALIGN)
7754 memptr += (DHD_SDALIGN - ((uint32)(uintptr)memblock % DHD_SDALIGN));
7755
7756 /* Download image */
7757 while ((len = dhd_os_get_image_block((char*)memptr, MEMBLOCK, image))) {
7758 if (len < 0) {
7759 DHD_ERROR(("%s: dhd_os_get_image_block failed (%d)\n", __FUNCTION__, len));
7760 bcmerror = BCME_ERROR;
7761 goto err;
7762 }
7763 /* check if CR4 */
7764 if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
7765 /* if address is 0, store the reset instruction to be written in 0 */
7766
7767 if (offset == 0) {
7768 bus->resetinstr = *(((uint32*)memptr));
7769 /* Add start of RAM address to the address given by user */
7770 offset += bus->dongle_ram_base;
7771 }
7772 }
7773
7774 bcmerror = dhdsdio_membytes(bus, TRUE, offset, memptr, len);
7775 if (bcmerror) {
7776 DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
7777 __FUNCTION__, bcmerror, MEMBLOCK, offset));
7778 goto err;
7779 }
7780
7781 offset += MEMBLOCK;
7782 }
7783
7784 err:
7785 if (memblock)
7786 MFREE(bus->dhd->osh, memblock, MEMBLOCK + DHD_SDALIGN);
7787
7788 if (image)
7789 dhd_os_close_image(image);
7790
7791 return bcmerror;
7792 }
7793
7794 /*
7795 EXAMPLE: nvram_array
7796 nvram_arry format:
7797 name=value
7798 Use carriage return at the end of each assignment, and an empty string with
7799 carriage return at the end of array.
7800
7801 For example:
7802 unsigned char nvram_array[] = {"name1=value1\n", "name2=value2\n", "\n"};
7803 Hex values start with 0x, and mac addr format: xx:xx:xx:xx:xx:xx.
7804
7805 Search "EXAMPLE: nvram_array" to see how the array is activated.
7806 */
7807
7808 void
dhd_bus_set_nvram_params(struct dhd_bus * bus,const char * nvram_params)7809 dhd_bus_set_nvram_params(struct dhd_bus * bus, const char *nvram_params)
7810 {
7811 bus->nvram_params = nvram_params;
7812 }
7813
7814 static int
dhdsdio_download_nvram(struct dhd_bus * bus)7815 dhdsdio_download_nvram(struct dhd_bus *bus)
7816 {
7817 int bcmerror = -1;
7818 uint len;
7819 void * image = NULL;
7820 char * memblock = NULL;
7821 char *bufp;
7822 char *pnv_path;
7823 bool nvram_file_exists;
7824
7825 pnv_path = bus->nv_path;
7826
7827 nvram_file_exists = ((pnv_path != NULL) && (pnv_path[0] != '\0'));
7828 if (!nvram_file_exists && (bus->nvram_params == NULL))
7829 return (0);
7830
7831 if (nvram_file_exists) {
7832 image = dhd_os_open_image(pnv_path);
7833 if (image == NULL)
7834 goto err;
7835 }
7836
7837 memblock = MALLOC(bus->dhd->osh, MAX_NVRAMBUF_SIZE);
7838 if (memblock == NULL) {
7839 DHD_ERROR(("%s: Failed to allocate memory %d bytes\n",
7840 __FUNCTION__, MAX_NVRAMBUF_SIZE));
7841 goto err;
7842 }
7843
7844 /* Download variables */
7845 if (nvram_file_exists) {
7846 len = dhd_os_get_image_block(memblock, MAX_NVRAMBUF_SIZE, image);
7847 }
7848 else {
7849 len = strlen(bus->nvram_params);
7850 ASSERT(len <= MAX_NVRAMBUF_SIZE);
7851 memcpy(memblock, bus->nvram_params, len);
7852 }
7853 if (len > 0 && len < MAX_NVRAMBUF_SIZE) {
7854 bufp = (char *)memblock;
7855 bufp[len] = 0;
7856 len = process_nvram_vars(bufp, len);
7857 if (len % 4) {
7858 len += 4 - (len % 4);
7859 }
7860 bufp += len;
7861 *bufp++ = 0;
7862 if (len)
7863 bcmerror = dhdsdio_downloadvars(bus, memblock, len + 1);
7864 if (bcmerror) {
7865 DHD_ERROR(("%s: error downloading vars: %d\n",
7866 __FUNCTION__, bcmerror));
7867 }
7868 }
7869 else {
7870 DHD_ERROR(("%s: error reading nvram file: %d\n",
7871 __FUNCTION__, len));
7872 bcmerror = BCME_SDIO_ERROR;
7873 }
7874
7875 err:
7876 if (memblock)
7877 MFREE(bus->dhd->osh, memblock, MAX_NVRAMBUF_SIZE);
7878
7879 if (image)
7880 dhd_os_close_image(image);
7881
7882 return bcmerror;
7883 }
7884
7885 static int
_dhdsdio_download_firmware(struct dhd_bus * bus)7886 _dhdsdio_download_firmware(struct dhd_bus *bus)
7887 {
7888 int bcmerror = -1;
7889
7890 bool embed = FALSE; /* download embedded firmware */
7891 bool dlok = FALSE; /* download firmware succeeded */
7892
7893 /* Out immediately if no image to download */
7894 if ((bus->fw_path == NULL) || (bus->fw_path[0] == '\0')) {
7895 #ifdef BCMEMBEDIMAGE
7896 embed = TRUE;
7897 #else
7898 return 0;
7899 #endif
7900 }
7901
7902 /* Keep arm in reset */
7903 if (dhdsdio_download_state(bus, TRUE)) {
7904 DHD_ERROR(("%s: error placing ARM core in reset\n", __FUNCTION__));
7905 goto err;
7906 }
7907
7908 /* External image takes precedence if specified */
7909 if ((bus->fw_path != NULL) && (bus->fw_path[0] != '\0')) {
7910 if (dhdsdio_download_code_file(bus, bus->fw_path)) {
7911 DHD_ERROR(("%s: dongle image file download failed\n", __FUNCTION__));
7912 #ifdef BCMEMBEDIMAGE
7913 embed = TRUE;
7914 #else
7915 goto err;
7916 #endif
7917 }
7918 else {
7919 embed = FALSE;
7920 dlok = TRUE;
7921 }
7922 }
7923
7924 #ifdef BCMEMBEDIMAGE
7925 if (embed) {
7926 if (dhdsdio_download_code_array(bus)) {
7927 DHD_ERROR(("%s: dongle image array download failed\n", __FUNCTION__));
7928 goto err;
7929 }
7930 else {
7931 dlok = TRUE;
7932 }
7933 }
7934 #else
7935 BCM_REFERENCE(embed);
7936 #endif
7937 if (!dlok) {
7938 DHD_ERROR(("%s: dongle image download failed\n", __FUNCTION__));
7939 goto err;
7940 }
7941
7942 /* EXAMPLE: nvram_array */
7943 /* If a valid nvram_arry is specified as above, it can be passed down to dongle */
7944 /* dhd_bus_set_nvram_params(bus, (char *)&nvram_array); */
7945
7946 /* External nvram takes precedence if specified */
7947 if (dhdsdio_download_nvram(bus)) {
7948 DHD_ERROR(("%s: dongle nvram file download failed\n", __FUNCTION__));
7949 goto err;
7950 }
7951
7952 /* Take arm out of reset */
7953 if (dhdsdio_download_state(bus, FALSE)) {
7954 DHD_ERROR(("%s: error getting out of ARM core reset\n", __FUNCTION__));
7955 goto err;
7956 }
7957
7958 bcmerror = 0;
7959
7960 err:
7961 return bcmerror;
7962 }
7963
7964 static int
dhd_bcmsdh_recv_buf(dhd_bus_t * bus,uint32 addr,uint fn,uint flags,uint8 * buf,uint nbytes,void * pkt,bcmsdh_cmplt_fn_t complete,void * handle)7965 dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes,
7966 void *pkt, bcmsdh_cmplt_fn_t complete, void *handle)
7967 {
7968 int status;
7969
7970 if (!KSO_ENAB(bus)) {
7971 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
7972 return BCME_NODEVICE;
7973 }
7974
7975 status = bcmsdh_recv_buf(bus->sdh, addr, fn, flags, buf, nbytes, pkt, complete, handle);
7976
7977 return status;
7978 }
7979
7980 static int
dhd_bcmsdh_send_buf(dhd_bus_t * bus,uint32 addr,uint fn,uint flags,uint8 * buf,uint nbytes,void * pkt,bcmsdh_cmplt_fn_t complete,void * handle)7981 dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes,
7982 void *pkt, bcmsdh_cmplt_fn_t complete, void *handle)
7983 {
7984 if (!KSO_ENAB(bus)) {
7985 DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
7986 return BCME_NODEVICE;
7987 }
7988
7989 return (bcmsdh_send_buf(bus->sdh, addr, fn, flags, buf, nbytes, pkt, complete, handle));
7990 }
7991
7992 #ifdef BCMSDIOH_TXGLOM
7993 static void
dhd_bcmsdh_glom_post(dhd_bus_t * bus,uint8 * frame,void * pkt,uint len)7994 dhd_bcmsdh_glom_post(dhd_bus_t *bus, uint8 *frame, void *pkt, uint len)
7995 {
7996 bcmsdh_glom_post(bus->sdh, frame, pkt, len);
7997 }
7998
7999 static void
dhd_bcmsdh_glom_clear(dhd_bus_t * bus)8000 dhd_bcmsdh_glom_clear(dhd_bus_t *bus)
8001 {
8002 bcmsdh_glom_clear(bus->sdh);
8003 }
8004 #endif
8005
8006 uint
dhd_bus_chip(struct dhd_bus * bus)8007 dhd_bus_chip(struct dhd_bus *bus)
8008 {
8009 ASSERT(bus->sih != NULL);
8010 return bus->sih->chip;
8011 }
8012
8013 void *
dhd_bus_pub(struct dhd_bus * bus)8014 dhd_bus_pub(struct dhd_bus *bus)
8015 {
8016 return bus->dhd;
8017 }
8018
8019 void *
dhd_bus_txq(struct dhd_bus * bus)8020 dhd_bus_txq(struct dhd_bus *bus)
8021 {
8022 return &bus->txq;
8023 }
8024
8025 uint
dhd_bus_hdrlen(struct dhd_bus * bus)8026 dhd_bus_hdrlen(struct dhd_bus *bus)
8027 {
8028 return SDPCM_HDRLEN;
8029 }
8030
8031 int
dhd_bus_devreset(dhd_pub_t * dhdp,uint8 flag)8032 dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag)
8033 {
8034 int bcmerror = 0;
8035 dhd_bus_t *bus;
8036
8037 bus = dhdp->bus;
8038
8039 if (flag == TRUE) {
8040 if (!bus->dhd->dongle_reset) {
8041 dhd_os_sdlock(dhdp);
8042 dhd_os_wd_timer(dhdp, 0);
8043 #if !defined(IGNORE_ETH0_DOWN)
8044 /* Force flow control as protection when stop come before ifconfig_down */
8045 dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON);
8046 #endif /* !defined(IGNORE_ETH0_DOWN) */
8047 /* Expect app to have torn down any connection before calling */
8048 /* Stop the bus, disable F2 */
8049 dhd_bus_stop(bus, FALSE);
8050
8051 #if defined(OOB_INTR_ONLY)
8052 /* Clean up any pending IRQ */
8053 dhd_enable_oob_intr(bus, FALSE);
8054 bcmsdh_set_irq(FALSE);
8055 bcmsdh_unregister_oob_intr();
8056 #endif
8057
8058 /* Clean tx/rx buffer pointers, detach from the dongle */
8059 dhdsdio_release_dongle(bus, bus->dhd->osh, TRUE, TRUE);
8060
8061 bus->dhd->dongle_reset = TRUE;
8062 bus->dhd->up = FALSE;
8063 #ifdef BCMSDIOH_TXGLOM
8064 dhd_txglom_enable(dhdp, FALSE);
8065 #endif
8066 dhd_os_sdunlock(dhdp);
8067
8068 DHD_TRACE(("%s: WLAN OFF DONE\n", __FUNCTION__));
8069 /* App can now remove power from device */
8070 } else
8071 bcmerror = BCME_SDIO_ERROR;
8072 } else {
8073 /* App must have restored power to device before calling */
8074
8075 DHD_TRACE(("\n\n%s: == WLAN ON ==\n", __FUNCTION__));
8076
8077 if (bus->dhd->dongle_reset) {
8078 /* Turn on WLAN */
8079 #ifdef DHDTHREAD
8080 dhd_os_sdlock(dhdp);
8081 #endif /* DHDTHREAD */
8082 /* Reset SD client */
8083 bcmsdh_reset(bus->sdh);
8084
8085 /* Attempt to re-attach & download */
8086 if (dhdsdio_probe_attach(bus, bus->dhd->osh, bus->sdh,
8087 (uint32 *)SI_ENUM_BASE,
8088 bus->cl_devid)) {
8089 /* Attempt to download binary to the dongle */
8090 if (dhdsdio_probe_init(bus, bus->dhd->osh, bus->sdh) &&
8091 dhdsdio_download_firmware(bus, bus->dhd->osh, bus->sdh)) {
8092
8093 /* Re-init bus, enable F2 transfer */
8094 bcmerror = dhd_bus_init((dhd_pub_t *) bus->dhd, FALSE);
8095 if (bcmerror == BCME_OK) {
8096 #if defined(OOB_INTR_ONLY)
8097 /* make sure oob intr get registered */
8098 if (!bcmsdh_is_oob_intr_registered()) {
8099 sdioh_start(NULL, 1);
8100 bcmsdh_register_oob_intr(dhdp);
8101 dhdp->iswl = TRUE;
8102 }
8103
8104 bcmsdh_set_irq(TRUE);
8105 dhd_enable_oob_intr(bus, TRUE);
8106 #endif
8107
8108 bus->dhd->dongle_reset = FALSE;
8109 bus->dhd->up = TRUE;
8110
8111 #if !defined(IGNORE_ETH0_DOWN)
8112 /* Restore flow control */
8113 dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF);
8114 #endif
8115 dhd_os_wd_timer(dhdp, dhd_watchdog_ms);
8116 DHD_TRACE(("%s: WLAN ON DONE\n", __FUNCTION__));
8117 } else {
8118 dhd_bus_stop(bus, FALSE);
8119 dhdsdio_release_dongle(bus, bus->dhd->osh,
8120 TRUE, FALSE);
8121 }
8122 } else
8123 bcmerror = BCME_SDIO_ERROR;
8124 } else
8125 bcmerror = BCME_SDIO_ERROR;
8126
8127 #ifdef DHDTHREAD
8128 dhd_os_sdunlock(dhdp);
8129 #endif /* DHDTHREAD */
8130 } else {
8131 bcmerror = BCME_SDIO_ERROR;
8132 DHD_INFO(("%s called when dongle is not in reset\n",
8133 __FUNCTION__));
8134 DHD_INFO(("Will call dhd_bus_start instead\n"));
8135 sdioh_start(NULL, 1);
8136 if ((bcmerror = dhd_bus_start(dhdp)) != 0)
8137 DHD_ERROR(("%s: dhd_bus_start fail with %d\n",
8138 __FUNCTION__, bcmerror));
8139 }
8140 }
8141 return bcmerror;
8142 }
8143
8144 /* Get Chip ID version */
dhd_bus_chip_id(dhd_pub_t * dhdp)8145 uint dhd_bus_chip_id(dhd_pub_t *dhdp)
8146 {
8147 dhd_bus_t *bus = dhdp->bus;
8148
8149 return bus->sih->chip;
8150 }
8151
8152 /* Get Chip Rev ID version */
dhd_bus_chiprev_id(dhd_pub_t * dhdp)8153 uint dhd_bus_chiprev_id(dhd_pub_t *dhdp)
8154 {
8155 dhd_bus_t *bus = dhdp->bus;
8156
8157 return bus->sih->chiprev;
8158 }
8159
8160 /* Get Chip Pkg ID version */
dhd_bus_chippkg_id(dhd_pub_t * dhdp)8161 uint dhd_bus_chippkg_id(dhd_pub_t *dhdp)
8162 {
8163 dhd_bus_t *bus = dhdp->bus;
8164
8165 return bus->sih->chippkg;
8166 }
8167
8168 int
dhd_bus_membytes(dhd_pub_t * dhdp,bool set,uint32 address,uint8 * data,uint size)8169 dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint size)
8170 {
8171 dhd_bus_t *bus;
8172
8173 bus = dhdp->bus;
8174 return dhdsdio_membytes(bus, set, address, data, size);
8175 }
8176
8177 int
dhd_enableOOB(dhd_pub_t * dhd,bool sleep)8178 dhd_enableOOB(dhd_pub_t *dhd, bool sleep)
8179 {
8180 dhd_bus_t *bus = dhd->bus;
8181 sdpcmd_regs_t *regs = bus->regs;
8182 uint retries = 0;
8183
8184 if (sleep) {
8185 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
8186 /* Tell device to start using OOB wakeup */
8187 W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries);
8188 if (retries > retry_limit) {
8189 DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
8190 return BCME_BUSY;
8191 }
8192 /* Turn off our contribution to the HT clock request */
8193 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
8194 } else {
8195 /* Make sure the controller has the bus up */
8196 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
8197
8198 /* Send misc interrupt to indicate OOB not needed */
8199 W_SDREG(0, ®s->tosbmailboxdata, retries);
8200 if (retries <= retry_limit)
8201 W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries);
8202
8203 if (retries > retry_limit)
8204 DHD_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n"));
8205
8206 /* Make sure we have SD bus access */
8207 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
8208 }
8209 return BCME_OK;
8210 }
8211
8212 void
dhd_bus_pktq_flush(dhd_pub_t * dhdp)8213 dhd_bus_pktq_flush(dhd_pub_t *dhdp)
8214 {
8215 dhd_bus_t *bus = dhdp->bus;
8216 /* Clear the data packet queues */
8217 pktq_flush(dhdp->osh, &bus->txq, TRUE, NULL, 0);
8218 }
8219
8220 int
dhd_sr_config(dhd_pub_t * dhd,bool on)8221 dhd_sr_config(dhd_pub_t *dhd, bool on)
8222 {
8223 dhd_bus_t *bus = dhd->bus;
8224
8225 if (!bus->_srenab)
8226 return -1;
8227
8228 return dhdsdio_clk_devsleep_iovar(bus, on);
8229 }
8230
8231 uint16
dhd_get_chipid(dhd_pub_t * dhd)8232 dhd_get_chipid(dhd_pub_t *dhd)
8233 {
8234 dhd_bus_t *bus = dhd->bus;
8235
8236 if (bus && bus->sih)
8237 return (uint16)bus->sih->chip;
8238 else
8239 return 0;
8240 }
8241