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