blob: c1cab4034958dcb108d2ef78f251416898be2578 [file] [log] [blame]
Arend van Spriel5b435de2011-10-05 13:19:03 +02001/*
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
17#include <linux/types.h>
18#include <linux/kernel.h>
19#include <linux/kthread.h>
20#include <linux/printk.h>
21#include <linux/pci_ids.h>
22#include <linux/netdevice.h>
23#include <linux/interrupt.h>
24#include <linux/sched.h>
25#include <linux/mmc/sdio.h>
26#include <linux/mmc/sdio_func.h>
27#include <linux/mmc/card.h>
28#include <linux/semaphore.h>
29#include <linux/firmware.h>
Stephen Rothwellb7a57e72011-10-12 21:35:07 +020030#include <linux/module.h>
Franky Lin99ba15c2011-11-04 22:23:42 +010031#include <linux/bcma/bcma.h>
Arend van Spriel4fc0d012012-06-14 12:16:57 +020032#include <linux/debugfs.h>
Arend van Spriel8dc01812012-06-21 11:33:32 +020033#include <linux/vmalloc.h>
Arend van Spriel5b435de2011-10-05 13:19:03 +020034#include <asm/unaligned.h>
35#include <defs.h>
36#include <brcmu_wifi.h>
37#include <brcmu_utils.h>
38#include <brcm_hw_ids.h>
39#include <soc.h>
40#include "sdio_host.h"
Franky Lina83369b2011-11-04 22:23:28 +010041#include "sdio_chip.h"
Arend van Spriel5b435de2011-10-05 13:19:03 +020042
43#define DCMD_RESP_TIMEOUT 2000 /* In milli second */
44
Joe Perches8ae74652012-01-15 00:38:38 -080045#ifdef DEBUG
Arend van Spriel5b435de2011-10-05 13:19:03 +020046
47#define BRCMF_TRAP_INFO_SIZE 80
48
49#define CBUF_LEN (128)
50
Arend van Spriel4fc0d012012-06-14 12:16:57 +020051/* Device console log buffer state */
52#define CONSOLE_BUFFER_MAX 2024
53
Arend van Spriel5b435de2011-10-05 13:19:03 +020054struct rte_log_le {
55 __le32 buf; /* Can't be pointer on (64-bit) hosts */
56 __le32 buf_size;
57 __le32 idx;
58 char *_buf_compat; /* Redundant pointer for backward compat. */
59};
60
61struct rte_console {
62 /* Virtual UART
63 * When there is no UART (e.g. Quickturn),
64 * the host should write a complete
65 * input line directly into cbuf and then write
66 * the length into vcons_in.
67 * This may also be used when there is a real UART
68 * (at risk of conflicting with
69 * the real UART). vcons_out is currently unused.
70 */
71 uint vcons_in;
72 uint vcons_out;
73
74 /* Output (logging) buffer
75 * Console output is written to a ring buffer log_buf at index log_idx.
76 * The host may read the output when it sees log_idx advance.
77 * Output will be lost if the output wraps around faster than the host
78 * polls.
79 */
80 struct rte_log_le log_le;
81
82 /* Console input line buffer
83 * Characters are read one at a time into cbuf
84 * until <CR> is received, then
85 * the buffer is processed as a command line.
86 * Also used for virtual UART.
87 */
88 uint cbuf_idx;
89 char cbuf[CBUF_LEN];
90};
91
Joe Perches8ae74652012-01-15 00:38:38 -080092#endif /* DEBUG */
Arend van Spriel5b435de2011-10-05 13:19:03 +020093#include <chipcommon.h>
94
Arend van Spriel5b435de2011-10-05 13:19:03 +020095#include "dhd_bus.h"
Arend van Spriel5b435de2011-10-05 13:19:03 +020096#include "dhd_dbg.h"
Arend van Spriel40c1c242013-04-05 10:57:44 +020097#include "tracepoint.h"
Arend van Spriel5b435de2011-10-05 13:19:03 +020098
99#define TXQLEN 2048 /* bulk tx queue length */
100#define TXHI (TXQLEN - 256) /* turn on flow control above TXHI */
101#define TXLOW (TXHI - 256) /* turn off flow control below TXLOW */
102#define PRIOMASK 7
103
104#define TXRETRIES 2 /* # of retries for tx frames */
105
106#define BRCMF_RXBOUND 50 /* Default for max rx frames in
107 one scheduling */
108
109#define BRCMF_TXBOUND 20 /* Default for max tx frames in
110 one scheduling */
111
112#define BRCMF_TXMINMAX 1 /* Max tx frames if rx still pending */
113
114#define MEMBLOCK 2048 /* Block size used for downloading
115 of dongle image */
116#define MAX_DATA_BUF (32 * 1024) /* Must be large enough to hold
117 biggest possible glom */
118
119#define BRCMF_FIRSTREAD (1 << 6)
120
121
122/* SBSDIO_DEVICE_CTL */
123
124/* 1: device will assert busy signal when receiving CMD53 */
125#define SBSDIO_DEVCTL_SETBUSY 0x01
126/* 1: assertion of sdio interrupt is synchronous to the sdio clock */
127#define SBSDIO_DEVCTL_SPI_INTR_SYNC 0x02
128/* 1: mask all interrupts to host except the chipActive (rev 8) */
129#define SBSDIO_DEVCTL_CA_INT_ONLY 0x04
130/* 1: isolate internal sdio signals, put external pads in tri-state; requires
131 * sdio bus power cycle to clear (rev 9) */
132#define SBSDIO_DEVCTL_PADS_ISO 0x08
133/* Force SD->SB reset mapping (rev 11) */
134#define SBSDIO_DEVCTL_SB_RST_CTL 0x30
135/* Determined by CoreControl bit */
136#define SBSDIO_DEVCTL_RST_CORECTL 0x00
137/* Force backplane reset */
138#define SBSDIO_DEVCTL_RST_BPRESET 0x10
139/* Force no backplane reset */
140#define SBSDIO_DEVCTL_RST_NOBPRESET 0x20
141
Arend van Spriel5b435de2011-10-05 13:19:03 +0200142/* direct(mapped) cis space */
143
144/* MAPPED common CIS address */
145#define SBSDIO_CIS_BASE_COMMON 0x1000
146/* maximum bytes in one CIS */
147#define SBSDIO_CIS_SIZE_LIMIT 0x200
148/* cis offset addr is < 17 bits */
149#define SBSDIO_CIS_OFT_ADDR_MASK 0x1FFFF
150
151/* manfid tuple length, include tuple, link bytes */
152#define SBSDIO_CIS_MANFID_TUPLE_LEN 6
153
154/* intstatus */
155#define I_SMB_SW0 (1 << 0) /* To SB Mail S/W interrupt 0 */
156#define I_SMB_SW1 (1 << 1) /* To SB Mail S/W interrupt 1 */
157#define I_SMB_SW2 (1 << 2) /* To SB Mail S/W interrupt 2 */
158#define I_SMB_SW3 (1 << 3) /* To SB Mail S/W interrupt 3 */
159#define I_SMB_SW_MASK 0x0000000f /* To SB Mail S/W interrupts mask */
160#define I_SMB_SW_SHIFT 0 /* To SB Mail S/W interrupts shift */
161#define I_HMB_SW0 (1 << 4) /* To Host Mail S/W interrupt 0 */
162#define I_HMB_SW1 (1 << 5) /* To Host Mail S/W interrupt 1 */
163#define I_HMB_SW2 (1 << 6) /* To Host Mail S/W interrupt 2 */
164#define I_HMB_SW3 (1 << 7) /* To Host Mail S/W interrupt 3 */
165#define I_HMB_SW_MASK 0x000000f0 /* To Host Mail S/W interrupts mask */
166#define I_HMB_SW_SHIFT 4 /* To Host Mail S/W interrupts shift */
167#define I_WR_OOSYNC (1 << 8) /* Write Frame Out Of Sync */
168#define I_RD_OOSYNC (1 << 9) /* Read Frame Out Of Sync */
169#define I_PC (1 << 10) /* descriptor error */
170#define I_PD (1 << 11) /* data error */
171#define I_DE (1 << 12) /* Descriptor protocol Error */
172#define I_RU (1 << 13) /* Receive descriptor Underflow */
173#define I_RO (1 << 14) /* Receive fifo Overflow */
174#define I_XU (1 << 15) /* Transmit fifo Underflow */
175#define I_RI (1 << 16) /* Receive Interrupt */
176#define I_BUSPWR (1 << 17) /* SDIO Bus Power Change (rev 9) */
177#define I_XMTDATA_AVAIL (1 << 23) /* bits in fifo */
178#define I_XI (1 << 24) /* Transmit Interrupt */
179#define I_RF_TERM (1 << 25) /* Read Frame Terminate */
180#define I_WF_TERM (1 << 26) /* Write Frame Terminate */
181#define I_PCMCIA_XU (1 << 27) /* PCMCIA Transmit FIFO Underflow */
182#define I_SBINT (1 << 28) /* sbintstatus Interrupt */
183#define I_CHIPACTIVE (1 << 29) /* chip from doze to active state */
184#define I_SRESET (1 << 30) /* CCCR RES interrupt */
185#define I_IOE2 (1U << 31) /* CCCR IOE2 Bit Changed */
186#define I_ERRORS (I_PC | I_PD | I_DE | I_RU | I_RO | I_XU)
187#define I_DMA (I_RI | I_XI | I_ERRORS)
188
189/* corecontrol */
190#define CC_CISRDY (1 << 0) /* CIS Ready */
191#define CC_BPRESEN (1 << 1) /* CCCR RES signal */
192#define CC_F2RDY (1 << 2) /* set CCCR IOR2 bit */
193#define CC_CLRPADSISO (1 << 3) /* clear SDIO pads isolation */
194#define CC_XMTDATAAVAIL_MODE (1 << 4)
195#define CC_XMTDATAAVAIL_CTRL (1 << 5)
196
197/* SDA_FRAMECTRL */
198#define SFC_RF_TERM (1 << 0) /* Read Frame Terminate */
199#define SFC_WF_TERM (1 << 1) /* Write Frame Terminate */
200#define SFC_CRC4WOOS (1 << 2) /* CRC error for write out of sync */
201#define SFC_ABORTALL (1 << 3) /* Abort all in-progress frames */
202
203/* HW frame tag */
204#define SDPCM_FRAMETAG_LEN 4 /* 2 bytes len, 2 bytes check val */
205
206/* Total length of frame header for dongle protocol */
207#define SDPCM_HDRLEN (SDPCM_FRAMETAG_LEN + SDPCM_SWHEADER_LEN)
208#define SDPCM_RESERVE (SDPCM_HDRLEN + BRCMF_SDALIGN)
209
210/*
211 * Software allocation of To SB Mailbox resources
212 */
213
214/* tosbmailbox bits corresponding to intstatus bits */
215#define SMB_NAK (1 << 0) /* Frame NAK */
216#define SMB_INT_ACK (1 << 1) /* Host Interrupt ACK */
217#define SMB_USE_OOB (1 << 2) /* Use OOB Wakeup */
218#define SMB_DEV_INT (1 << 3) /* Miscellaneous Interrupt */
219
220/* tosbmailboxdata */
221#define SMB_DATA_VERSION_SHIFT 16 /* host protocol version */
222
223/*
224 * Software allocation of To Host Mailbox resources
225 */
226
227/* intstatus bits */
228#define I_HMB_FC_STATE I_HMB_SW0 /* Flow Control State */
229#define I_HMB_FC_CHANGE I_HMB_SW1 /* Flow Control State Changed */
230#define I_HMB_FRAME_IND I_HMB_SW2 /* Frame Indication */
231#define I_HMB_HOST_INT I_HMB_SW3 /* Miscellaneous Interrupt */
232
233/* tohostmailboxdata */
234#define HMB_DATA_NAKHANDLED 1 /* retransmit NAK'd frame */
235#define HMB_DATA_DEVREADY 2 /* talk to host after enable */
236#define HMB_DATA_FC 4 /* per prio flowcontrol update flag */
237#define HMB_DATA_FWREADY 8 /* fw ready for protocol activity */
238
239#define HMB_DATA_FCDATA_MASK 0xff000000
240#define HMB_DATA_FCDATA_SHIFT 24
241
242#define HMB_DATA_VERSION_MASK 0x00ff0000
243#define HMB_DATA_VERSION_SHIFT 16
244
245/*
246 * Software-defined protocol header
247 */
248
249/* Current protocol version */
250#define SDPCM_PROT_VERSION 4
251
252/* SW frame header */
253#define SDPCM_PACKET_SEQUENCE(p) (((u8 *)p)[0] & 0xff)
254
255#define SDPCM_CHANNEL_MASK 0x00000f00
256#define SDPCM_CHANNEL_SHIFT 8
257#define SDPCM_PACKET_CHANNEL(p) (((u8 *)p)[1] & 0x0f)
258
259#define SDPCM_NEXTLEN_OFFSET 2
260
261/* Data Offset from SOF (HW Tag, SW Tag, Pad) */
262#define SDPCM_DOFFSET_OFFSET 3 /* Data Offset */
263#define SDPCM_DOFFSET_VALUE(p) (((u8 *)p)[SDPCM_DOFFSET_OFFSET] & 0xff)
264#define SDPCM_DOFFSET_MASK 0xff000000
265#define SDPCM_DOFFSET_SHIFT 24
266#define SDPCM_FCMASK_OFFSET 4 /* Flow control */
267#define SDPCM_FCMASK_VALUE(p) (((u8 *)p)[SDPCM_FCMASK_OFFSET] & 0xff)
268#define SDPCM_WINDOW_OFFSET 5 /* Credit based fc */
269#define SDPCM_WINDOW_VALUE(p) (((u8 *)p)[SDPCM_WINDOW_OFFSET] & 0xff)
270
271#define SDPCM_SWHEADER_LEN 8 /* SW header is 64 bits */
272
273/* logical channel numbers */
274#define SDPCM_CONTROL_CHANNEL 0 /* Control channel Id */
275#define SDPCM_EVENT_CHANNEL 1 /* Asyc Event Indication Channel Id */
276#define SDPCM_DATA_CHANNEL 2 /* Data Xmit/Recv Channel Id */
277#define SDPCM_GLOM_CHANNEL 3 /* For coalesced packets */
278#define SDPCM_TEST_CHANNEL 15 /* Reserved for test/debug packets */
279
280#define SDPCM_SEQUENCE_WRAP 256 /* wrap-around val for 8bit frame seq */
281
282#define SDPCM_GLOMDESC(p) (((u8 *)p)[1] & 0x80)
283
284/*
285 * Shared structure between dongle and the host.
286 * The structure contains pointers to trap or assert information.
287 */
Arend van Spriel4fc0d012012-06-14 12:16:57 +0200288#define SDPCM_SHARED_VERSION 0x0003
Arend van Spriel5b435de2011-10-05 13:19:03 +0200289#define SDPCM_SHARED_VERSION_MASK 0x00FF
290#define SDPCM_SHARED_ASSERT_BUILT 0x0100
291#define SDPCM_SHARED_ASSERT 0x0200
292#define SDPCM_SHARED_TRAP 0x0400
293
294/* Space for header read, limit for data packets */
295#define MAX_HDR_READ (1 << 6)
296#define MAX_RX_DATASZ 2048
297
298/* Maximum milliseconds to wait for F2 to come up */
299#define BRCMF_WAIT_F2RDY 3000
300
301/* Bump up limit on waiting for HT to account for first startup;
302 * if the image is doing a CRC calculation before programming the PMU
303 * for HT availability, it could take a couple hundred ms more, so
304 * max out at a 1 second (1000000us).
305 */
306#undef PMU_MAX_TRANSITION_DLY
307#define PMU_MAX_TRANSITION_DLY 1000000
308
309/* Value for ChipClockCSR during initial setup */
310#define BRCMF_INIT_CLKCTL1 (SBSDIO_FORCE_HW_CLKREQ_OFF | \
311 SBSDIO_ALP_AVAIL_REQ)
312
313/* Flags for SDH calls */
314#define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED)
315
Arend van Spriel52e14092012-02-09 21:09:09 +0100316#define BRCMF_SDIO_FW_NAME "brcm/brcmfmac-sdio.bin"
317#define BRCMF_SDIO_NV_NAME "brcm/brcmfmac-sdio.txt"
318MODULE_FIRMWARE(BRCMF_SDIO_FW_NAME);
319MODULE_FIRMWARE(BRCMF_SDIO_NV_NAME);
Franky Lin8dd939c2011-11-22 17:21:41 -0800320
Franky Lin382a9e02011-12-16 18:37:18 -0800321#define BRCMF_IDLE_IMMEDIATE (-1) /* Enter idle immediately */
322#define BRCMF_IDLE_ACTIVE 0 /* Do not request any SD clock change
323 * when idle
324 */
325#define BRCMF_IDLE_INTERVAL 1
326
Arend van Spriel5b435de2011-10-05 13:19:03 +0200327/*
328 * Conversion of 802.1D priority to precedence level
329 */
330static uint prio2prec(u32 prio)
331{
332 return (prio == PRIO_8021D_NONE || prio == PRIO_8021D_BE) ?
333 (prio^2) : prio;
334}
335
Arend van Spriel5b435de2011-10-05 13:19:03 +0200336/* core registers */
337struct sdpcmd_regs {
338 u32 corecontrol; /* 0x00, rev8 */
339 u32 corestatus; /* rev8 */
340 u32 PAD[1];
341 u32 biststatus; /* rev8 */
342
343 /* PCMCIA access */
344 u16 pcmciamesportaladdr; /* 0x010, rev8 */
345 u16 PAD[1];
346 u16 pcmciamesportalmask; /* rev8 */
347 u16 PAD[1];
348 u16 pcmciawrframebc; /* rev8 */
349 u16 PAD[1];
350 u16 pcmciaunderflowtimer; /* rev8 */
351 u16 PAD[1];
352
353 /* interrupt */
354 u32 intstatus; /* 0x020, rev8 */
355 u32 hostintmask; /* rev8 */
356 u32 intmask; /* rev8 */
357 u32 sbintstatus; /* rev8 */
358 u32 sbintmask; /* rev8 */
359 u32 funcintmask; /* rev4 */
360 u32 PAD[2];
361 u32 tosbmailbox; /* 0x040, rev8 */
362 u32 tohostmailbox; /* rev8 */
363 u32 tosbmailboxdata; /* rev8 */
364 u32 tohostmailboxdata; /* rev8 */
365
366 /* synchronized access to registers in SDIO clock domain */
367 u32 sdioaccess; /* 0x050, rev8 */
368 u32 PAD[3];
369
370 /* PCMCIA frame control */
371 u8 pcmciaframectrl; /* 0x060, rev8 */
372 u8 PAD[3];
373 u8 pcmciawatermark; /* rev8 */
374 u8 PAD[155];
375
376 /* interrupt batching control */
377 u32 intrcvlazy; /* 0x100, rev8 */
378 u32 PAD[3];
379
380 /* counters */
381 u32 cmd52rd; /* 0x110, rev8 */
382 u32 cmd52wr; /* rev8 */
383 u32 cmd53rd; /* rev8 */
384 u32 cmd53wr; /* rev8 */
385 u32 abort; /* rev8 */
386 u32 datacrcerror; /* rev8 */
387 u32 rdoutofsync; /* rev8 */
388 u32 wroutofsync; /* rev8 */
389 u32 writebusy; /* rev8 */
390 u32 readwait; /* rev8 */
391 u32 readterm; /* rev8 */
392 u32 writeterm; /* rev8 */
393 u32 PAD[40];
394 u32 clockctlstatus; /* rev8 */
395 u32 PAD[7];
396
397 u32 PAD[128]; /* DMA engines */
398
399 /* SDIO/PCMCIA CIS region */
400 char cis[512]; /* 0x400-0x5ff, rev6 */
401
402 /* PCMCIA function control registers */
403 char pcmciafcr[256]; /* 0x600-6ff, rev6 */
404 u16 PAD[55];
405
406 /* PCMCIA backplane access */
407 u16 backplanecsr; /* 0x76E, rev6 */
408 u16 backplaneaddr0; /* rev6 */
409 u16 backplaneaddr1; /* rev6 */
410 u16 backplaneaddr2; /* rev6 */
411 u16 backplaneaddr3; /* rev6 */
412 u16 backplanedata0; /* rev6 */
413 u16 backplanedata1; /* rev6 */
414 u16 backplanedata2; /* rev6 */
415 u16 backplanedata3; /* rev6 */
416 u16 PAD[31];
417
418 /* sprom "size" & "blank" info */
419 u16 spromstatus; /* 0x7BE, rev2 */
420 u32 PAD[464];
421
422 u16 PAD[0x80];
423};
424
Joe Perches8ae74652012-01-15 00:38:38 -0800425#ifdef DEBUG
Arend van Spriel5b435de2011-10-05 13:19:03 +0200426/* Device console log buffer state */
427struct brcmf_console {
428 uint count; /* Poll interval msec counter */
429 uint log_addr; /* Log struct address (fixed) */
430 struct rte_log_le log_le; /* Log struct (host copy) */
431 uint bufsize; /* Size of log buffer */
432 u8 *buf; /* Log buffer (host copy) */
433 uint last; /* Last buffer read index */
434};
Arend van Spriel4fc0d012012-06-14 12:16:57 +0200435
436struct brcmf_trap_info {
437 __le32 type;
438 __le32 epc;
439 __le32 cpsr;
440 __le32 spsr;
441 __le32 r0; /* a1 */
442 __le32 r1; /* a2 */
443 __le32 r2; /* a3 */
444 __le32 r3; /* a4 */
445 __le32 r4; /* v1 */
446 __le32 r5; /* v2 */
447 __le32 r6; /* v3 */
448 __le32 r7; /* v4 */
449 __le32 r8; /* v5 */
450 __le32 r9; /* sb/v6 */
451 __le32 r10; /* sl/v7 */
452 __le32 r11; /* fp/v8 */
453 __le32 r12; /* ip */
454 __le32 r13; /* sp */
455 __le32 r14; /* lr */
456 __le32 pc; /* r15 */
457};
Joe Perches8ae74652012-01-15 00:38:38 -0800458#endif /* DEBUG */
Arend van Spriel5b435de2011-10-05 13:19:03 +0200459
460struct sdpcm_shared {
461 u32 flags;
462 u32 trap_addr;
463 u32 assert_exp_addr;
464 u32 assert_file_addr;
465 u32 assert_line;
466 u32 console_addr; /* Address of struct rte_console */
467 u32 msgtrace_addr;
468 u8 tag[32];
Arend van Spriel4fc0d012012-06-14 12:16:57 +0200469 u32 brpt_addr;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200470};
471
472struct sdpcm_shared_le {
473 __le32 flags;
474 __le32 trap_addr;
475 __le32 assert_exp_addr;
476 __le32 assert_file_addr;
477 __le32 assert_line;
478 __le32 console_addr; /* Address of struct rte_console */
479 __le32 msgtrace_addr;
480 u8 tag[32];
Arend van Spriel4fc0d012012-06-14 12:16:57 +0200481 __le32 brpt_addr;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200482};
483
Franky Lin4754fce2012-09-19 22:21:11 +0200484/* SDIO read frame info */
485struct brcmf_sdio_read {
486 u8 seq_num;
487 u8 channel;
488 u16 len;
489 u16 len_left;
490 u16 len_nxtfrm;
491 u8 dat_offset;
492};
Arend van Spriel5b435de2011-10-05 13:19:03 +0200493
494/* misc chip info needed by some of the routines */
Arend van Spriel5b435de2011-10-05 13:19:03 +0200495/* Private data for SDIO bus interaction */
Franky Line92eedf2011-11-22 17:21:50 -0800496struct brcmf_sdio {
Arend van Spriel5b435de2011-10-05 13:19:03 +0200497 struct brcmf_sdio_dev *sdiodev; /* sdio device handler */
498 struct chip_info *ci; /* Chip info struct */
499 char *vars; /* Variables (from CIS and/or other) */
500 uint varsz; /* Size of variables buffer */
501
502 u32 ramsize; /* Size of RAM in SOCRAM (bytes) */
503
504 u32 hostintmask; /* Copy of Host Interrupt Mask */
Franky Lin45316032012-09-13 21:12:03 +0200505 atomic_t intstatus; /* Intstatus bits (events) pending */
506 atomic_t fcstate; /* State of dongle flow-control */
Arend van Spriel5b435de2011-10-05 13:19:03 +0200507
508 uint blocksize; /* Block size of SDIO transfers */
509 uint roundup; /* Max roundup limit */
510
511 struct pktq txq; /* Queue length used for flow-control */
512 u8 flowcontrol; /* per prio flow control bitmask */
513 u8 tx_seq; /* Transmit sequence number (next) */
514 u8 tx_max; /* Maximum transmit sequence allowed */
515
516 u8 hdrbuf[MAX_HDR_READ + BRCMF_SDALIGN];
517 u8 *rxhdr; /* Header of current rx frame (in hdrbuf) */
Arend van Spriel5b435de2011-10-05 13:19:03 +0200518 u8 rx_seq; /* Receive sequence number (expected) */
Franky Lin4754fce2012-09-19 22:21:11 +0200519 struct brcmf_sdio_read cur_read;
520 /* info of current read frame */
Arend van Spriel5b435de2011-10-05 13:19:03 +0200521 bool rxskip; /* Skip receive (awaiting NAK ACK) */
Franky Lin4754fce2012-09-19 22:21:11 +0200522 bool rxpending; /* Data frame pending in dongle */
Arend van Spriel5b435de2011-10-05 13:19:03 +0200523
524 uint rxbound; /* Rx frames to read before resched */
525 uint txbound; /* Tx frames to send before resched */
526 uint txminmax;
527
528 struct sk_buff *glomd; /* Packet containing glomming descriptor */
Arend van Sprielb83db862011-10-19 12:51:09 +0200529 struct sk_buff_head glom; /* Packet list for glommed superframe */
Arend van Spriel5b435de2011-10-05 13:19:03 +0200530 uint glomerr; /* Glom packet read errors */
531
532 u8 *rxbuf; /* Buffer for receiving control packets */
533 uint rxblen; /* Allocated length of rxbuf */
534 u8 *rxctl; /* Aligned pointer into rxbuf */
Franky Lindd43a012012-11-05 16:22:22 -0800535 u8 *rxctl_orig; /* pointer for freeing rxctl */
Arend van Spriel5b435de2011-10-05 13:19:03 +0200536 u8 *databuf; /* Buffer for receiving big glom packet */
537 u8 *dataptr; /* Aligned pointer into databuf */
538 uint rxlen; /* Length of valid data in buffer */
Franky Lindd43a012012-11-05 16:22:22 -0800539 spinlock_t rxctl_lock; /* protection lock for ctrl frame resources */
Arend van Spriel5b435de2011-10-05 13:19:03 +0200540
541 u8 sdpcm_ver; /* Bus protocol reported by dongle */
542
543 bool intr; /* Use interrupts */
544 bool poll; /* Use polling */
Franky Lin1d382272012-09-13 21:11:59 +0200545 atomic_t ipend; /* Device interrupt is pending */
Arend van Spriel5b435de2011-10-05 13:19:03 +0200546 uint spurious; /* Count of spurious interrupts */
547 uint pollrate; /* Ticks between device polls */
548 uint polltick; /* Tick counter */
Arend van Spriel5b435de2011-10-05 13:19:03 +0200549
Joe Perches8ae74652012-01-15 00:38:38 -0800550#ifdef DEBUG
Arend van Spriel5b435de2011-10-05 13:19:03 +0200551 uint console_interval;
552 struct brcmf_console console; /* Console output polling support */
553 uint console_addr; /* Console address from shared struct */
Joe Perches8ae74652012-01-15 00:38:38 -0800554#endif /* DEBUG */
Arend van Spriel5b435de2011-10-05 13:19:03 +0200555
Arend van Spriel5b435de2011-10-05 13:19:03 +0200556 uint clkstate; /* State of sd and backplane clock(s) */
557 bool activity; /* Activity flag for clock down */
558 s32 idletime; /* Control for activity timeout */
559 s32 idlecount; /* Activity timeout counter */
560 s32 idleclock; /* How to set bus driver when idle */
561 s32 sd_rxchain;
562 bool use_rxchain; /* If brcmf should use PKT chains */
Arend van Spriel5b435de2011-10-05 13:19:03 +0200563 bool rxflow_mode; /* Rx flow control mode */
564 bool rxflow; /* Is rx flow control on */
565 bool alp_only; /* Don't use HT clock (ALP only) */
Arend van Spriel5b435de2011-10-05 13:19:03 +0200566
Arend van Spriel5b435de2011-10-05 13:19:03 +0200567 u8 *ctrl_frame_buf;
568 u32 ctrl_frame_len;
569 bool ctrl_frame_stat;
570
571 spinlock_t txqlock;
572 wait_queue_head_t ctrl_wait;
573 wait_queue_head_t dcmd_resp_wait;
574
575 struct timer_list timer;
576 struct completion watchdog_wait;
577 struct task_struct *watchdog_tsk;
578 bool wd_timer_valid;
579 uint save_ms;
580
Franky Linf1e68c22012-09-13 21:12:00 +0200581 struct workqueue_struct *brcmf_wq;
582 struct work_struct datawork;
Franky Linb948a852012-04-23 14:24:53 -0700583 struct list_head dpc_tsklst;
584 spinlock_t dpc_tl_lock;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200585
Arend van Spriel5b435de2011-10-05 13:19:03 +0200586 const struct firmware *firmware;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200587 u32 fw_ptr;
Franky Linc8bf3482011-12-16 18:37:08 -0800588
589 bool txoff; /* Transmit flow-controlled */
Arend van Spriel80969832012-06-09 22:51:44 +0200590 struct brcmf_sdio_count sdcnt;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200591};
592
Arend van Spriel5b435de2011-10-05 13:19:03 +0200593/* clkstate */
594#define CLK_NONE 0
595#define CLK_SDONLY 1
596#define CLK_PENDING 2 /* Not used yet */
597#define CLK_AVAIL 3
598
Joe Perches8ae74652012-01-15 00:38:38 -0800599#ifdef DEBUG
Arend van Spriel5b435de2011-10-05 13:19:03 +0200600static int qcount[NUMPRIO];
601static int tx_packets[NUMPRIO];
Joe Perches8ae74652012-01-15 00:38:38 -0800602#endif /* DEBUG */
Arend van Spriel5b435de2011-10-05 13:19:03 +0200603
604#define SDIO_DRIVE_STRENGTH 6 /* in milliamps */
605
606#define RETRYCHAN(chan) ((chan) == SDPCM_EVENT_CHANNEL)
607
608/* Retry count for register access failures */
609static const uint retry_limit = 2;
610
611/* Limit on rounding up frames */
612static const uint max_roundup = 512;
613
614#define ALIGNMENT 4
615
Franky Lin9d7d6f92012-10-22 10:36:24 -0700616enum brcmf_sdio_frmtype {
617 BRCMF_SDIO_FT_NORMAL,
618 BRCMF_SDIO_FT_SUPER,
619 BRCMF_SDIO_FT_SUB,
620};
621
Arend van Spriel5b435de2011-10-05 13:19:03 +0200622static void pkt_align(struct sk_buff *p, int len, int align)
623{
624 uint datalign;
625 datalign = (unsigned long)(p->data);
626 datalign = roundup(datalign, (align)) - datalign;
627 if (datalign)
628 skb_pull(p, datalign);
629 __skb_trim(p, len);
630}
631
632/* To check if there's window offered */
Franky Line92eedf2011-11-22 17:21:50 -0800633static bool data_ok(struct brcmf_sdio *bus)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200634{
635 return (u8)(bus->tx_max - bus->tx_seq) != 0 &&
636 ((u8)(bus->tx_max - bus->tx_seq) & 0x80) == 0;
637}
638
639/*
640 * Reads a register in the SDIO hardware block. This block occupies a series of
641 * adresses on the 32 bit backplane bus.
642 */
Franky Lin58692752012-05-04 18:27:36 -0700643static int
644r_sdreg32(struct brcmf_sdio *bus, u32 *regvar, u32 offset)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200645{
Franky Lin99ba15c2011-11-04 22:23:42 +0100646 u8 idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV);
Franky Lin79ae3952012-05-04 18:27:34 -0700647 int ret;
Franky Lin58692752012-05-04 18:27:36 -0700648
649 *regvar = brcmf_sdio_regrl(bus->sdiodev,
650 bus->ci->c_inf[idx].base + offset, &ret);
651
652 return ret;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200653}
654
Franky Lin58692752012-05-04 18:27:36 -0700655static int
656w_sdreg32(struct brcmf_sdio *bus, u32 regval, u32 reg_offset)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200657{
Franky Lin99ba15c2011-11-04 22:23:42 +0100658 u8 idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV);
Franky Line13ce262012-05-04 18:27:35 -0700659 int ret;
Franky Lin58692752012-05-04 18:27:36 -0700660
661 brcmf_sdio_regwl(bus->sdiodev,
662 bus->ci->c_inf[idx].base + reg_offset,
663 regval, &ret);
664
665 return ret;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200666}
667
668#define PKT_AVAILABLE() (intstatus & I_HMB_FRAME_IND)
669
670#define HOSTINTMASK (I_HMB_SW_MASK | I_CHIPACTIVE)
671
Arend van Spriel5b435de2011-10-05 13:19:03 +0200672/* Turn backplane clock on or off */
Franky Line92eedf2011-11-22 17:21:50 -0800673static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200674{
675 int err;
676 u8 clkctl, clkreq, devctl;
677 unsigned long timeout;
678
Arend van Sprielc3203372013-04-03 12:40:44 +0200679 brcmf_dbg(SDIO, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200680
681 clkctl = 0;
682
683 if (on) {
684 /* Request HT Avail */
685 clkreq =
686 bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ;
687
Franky Lin3bba8292012-05-04 18:27:33 -0700688 brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
689 clkreq, &err);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200690 if (err) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +0100691 brcmf_err("HT Avail request error: %d\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200692 return -EBADE;
693 }
694
Arend van Spriel5b435de2011-10-05 13:19:03 +0200695 /* Check current status */
Franky Lin45db3392012-05-04 18:27:32 -0700696 clkctl = brcmf_sdio_regrb(bus->sdiodev,
697 SBSDIO_FUNC1_CHIPCLKCSR, &err);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200698 if (err) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +0100699 brcmf_err("HT Avail read error: %d\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200700 return -EBADE;
701 }
702
703 /* Go to pending and await interrupt if appropriate */
704 if (!SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) {
705 /* Allow only clock-available interrupt */
Franky Lin45db3392012-05-04 18:27:32 -0700706 devctl = brcmf_sdio_regrb(bus->sdiodev,
707 SBSDIO_DEVICE_CTL, &err);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200708 if (err) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +0100709 brcmf_err("Devctl error setting CA: %d\n",
Arend van Spriel5b435de2011-10-05 13:19:03 +0200710 err);
711 return -EBADE;
712 }
713
714 devctl |= SBSDIO_DEVCTL_CA_INT_ONLY;
Franky Lin3bba8292012-05-04 18:27:33 -0700715 brcmf_sdio_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL,
716 devctl, &err);
Arend van Sprielc3203372013-04-03 12:40:44 +0200717 brcmf_dbg(SDIO, "CLKCTL: set PENDING\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200718 bus->clkstate = CLK_PENDING;
719
720 return 0;
721 } else if (bus->clkstate == CLK_PENDING) {
722 /* Cancel CA-only interrupt filter */
Franky Lin45db3392012-05-04 18:27:32 -0700723 devctl = brcmf_sdio_regrb(bus->sdiodev,
Arend van Spriel5b435de2011-10-05 13:19:03 +0200724 SBSDIO_DEVICE_CTL, &err);
725 devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
Franky Lin3bba8292012-05-04 18:27:33 -0700726 brcmf_sdio_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL,
727 devctl, &err);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200728 }
729
730 /* Otherwise, wait here (polling) for HT Avail */
731 timeout = jiffies +
732 msecs_to_jiffies(PMU_MAX_TRANSITION_DLY/1000);
733 while (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
Franky Lin45db3392012-05-04 18:27:32 -0700734 clkctl = brcmf_sdio_regrb(bus->sdiodev,
735 SBSDIO_FUNC1_CHIPCLKCSR,
736 &err);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200737 if (time_after(jiffies, timeout))
738 break;
739 else
740 usleep_range(5000, 10000);
741 }
742 if (err) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +0100743 brcmf_err("HT Avail request error: %d\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200744 return -EBADE;
745 }
746 if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +0100747 brcmf_err("HT Avail timeout (%d): clkctl 0x%02x\n",
Arend van Spriel5b435de2011-10-05 13:19:03 +0200748 PMU_MAX_TRANSITION_DLY, clkctl);
749 return -EBADE;
750 }
751
752 /* Mark clock available */
753 bus->clkstate = CLK_AVAIL;
Arend van Sprielc3203372013-04-03 12:40:44 +0200754 brcmf_dbg(SDIO, "CLKCTL: turned ON\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200755
Joe Perches8ae74652012-01-15 00:38:38 -0800756#if defined(DEBUG)
Joe Perches23677ce2012-02-09 11:17:23 +0000757 if (!bus->alp_only) {
Arend van Spriel5b435de2011-10-05 13:19:03 +0200758 if (SBSDIO_ALPONLY(clkctl))
Arend van Spriel5e8149f2012-12-07 10:49:57 +0100759 brcmf_err("HT Clock should be on\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200760 }
Joe Perches8ae74652012-01-15 00:38:38 -0800761#endif /* defined (DEBUG) */
Arend van Spriel5b435de2011-10-05 13:19:03 +0200762
763 bus->activity = true;
764 } else {
765 clkreq = 0;
766
767 if (bus->clkstate == CLK_PENDING) {
768 /* Cancel CA-only interrupt filter */
Franky Lin45db3392012-05-04 18:27:32 -0700769 devctl = brcmf_sdio_regrb(bus->sdiodev,
770 SBSDIO_DEVICE_CTL, &err);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200771 devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
Franky Lin3bba8292012-05-04 18:27:33 -0700772 brcmf_sdio_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL,
773 devctl, &err);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200774 }
775
776 bus->clkstate = CLK_SDONLY;
Franky Lin3bba8292012-05-04 18:27:33 -0700777 brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
778 clkreq, &err);
Arend van Sprielc3203372013-04-03 12:40:44 +0200779 brcmf_dbg(SDIO, "CLKCTL: turned OFF\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200780 if (err) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +0100781 brcmf_err("Failed access turning clock off: %d\n",
Arend van Spriel5b435de2011-10-05 13:19:03 +0200782 err);
783 return -EBADE;
784 }
785 }
786 return 0;
787}
788
789/* Change idle/active SD state */
Franky Line92eedf2011-11-22 17:21:50 -0800790static int brcmf_sdbrcm_sdclk(struct brcmf_sdio *bus, bool on)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200791{
Arend van Sprielc3203372013-04-03 12:40:44 +0200792 brcmf_dbg(SDIO, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200793
794 if (on)
795 bus->clkstate = CLK_SDONLY;
796 else
797 bus->clkstate = CLK_NONE;
798
799 return 0;
800}
801
802/* Transition SD and backplane clock readiness */
Franky Line92eedf2011-11-22 17:21:50 -0800803static int brcmf_sdbrcm_clkctl(struct brcmf_sdio *bus, uint target, bool pendok)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200804{
Joe Perches8ae74652012-01-15 00:38:38 -0800805#ifdef DEBUG
Arend van Spriel5b435de2011-10-05 13:19:03 +0200806 uint oldstate = bus->clkstate;
Joe Perches8ae74652012-01-15 00:38:38 -0800807#endif /* DEBUG */
Arend van Spriel5b435de2011-10-05 13:19:03 +0200808
Arend van Sprielc3203372013-04-03 12:40:44 +0200809 brcmf_dbg(SDIO, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200810
811 /* Early exit if we're already there */
812 if (bus->clkstate == target) {
813 if (target == CLK_AVAIL) {
814 brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS);
815 bus->activity = true;
816 }
817 return 0;
818 }
819
820 switch (target) {
821 case CLK_AVAIL:
822 /* Make sure SD clock is available */
823 if (bus->clkstate == CLK_NONE)
824 brcmf_sdbrcm_sdclk(bus, true);
825 /* Now request HT Avail on the backplane */
826 brcmf_sdbrcm_htclk(bus, true, pendok);
827 brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS);
828 bus->activity = true;
829 break;
830
831 case CLK_SDONLY:
832 /* Remove HT request, or bring up SD clock */
833 if (bus->clkstate == CLK_NONE)
834 brcmf_sdbrcm_sdclk(bus, true);
835 else if (bus->clkstate == CLK_AVAIL)
836 brcmf_sdbrcm_htclk(bus, false, false);
837 else
Arend van Spriel5e8149f2012-12-07 10:49:57 +0100838 brcmf_err("request for %d -> %d\n",
Arend van Spriel5b435de2011-10-05 13:19:03 +0200839 bus->clkstate, target);
840 brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS);
841 break;
842
843 case CLK_NONE:
844 /* Make sure to remove HT request */
845 if (bus->clkstate == CLK_AVAIL)
846 brcmf_sdbrcm_htclk(bus, false, false);
847 /* Now remove the SD clock */
848 brcmf_sdbrcm_sdclk(bus, false);
849 brcmf_sdbrcm_wd_timer(bus, 0);
850 break;
851 }
Joe Perches8ae74652012-01-15 00:38:38 -0800852#ifdef DEBUG
Arend van Sprielc3203372013-04-03 12:40:44 +0200853 brcmf_dbg(SDIO, "%d -> %d\n", oldstate, bus->clkstate);
Joe Perches8ae74652012-01-15 00:38:38 -0800854#endif /* DEBUG */
Arend van Spriel5b435de2011-10-05 13:19:03 +0200855
856 return 0;
857}
858
Franky Line92eedf2011-11-22 17:21:50 -0800859static u32 brcmf_sdbrcm_hostmail(struct brcmf_sdio *bus)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200860{
861 u32 intstatus = 0;
862 u32 hmb_data;
863 u8 fcbits;
Franky Lin58692752012-05-04 18:27:36 -0700864 int ret;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200865
Arend van Sprielc3203372013-04-03 12:40:44 +0200866 brcmf_dbg(SDIO, "Enter\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200867
868 /* Read mailbox data and ack that we did so */
Franky Lin58692752012-05-04 18:27:36 -0700869 ret = r_sdreg32(bus, &hmb_data,
870 offsetof(struct sdpcmd_regs, tohostmailboxdata));
Arend van Spriel5b435de2011-10-05 13:19:03 +0200871
Franky Lin58692752012-05-04 18:27:36 -0700872 if (ret == 0)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200873 w_sdreg32(bus, SMB_INT_ACK,
Franky Lin58692752012-05-04 18:27:36 -0700874 offsetof(struct sdpcmd_regs, tosbmailbox));
Arend van Spriel80969832012-06-09 22:51:44 +0200875 bus->sdcnt.f1regdata += 2;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200876
877 /* Dongle recomposed rx frames, accept them again */
878 if (hmb_data & HMB_DATA_NAKHANDLED) {
Arend van Sprielc3203372013-04-03 12:40:44 +0200879 brcmf_dbg(SDIO, "Dongle reports NAK handled, expect rtx of %d\n",
Arend van Spriel5b435de2011-10-05 13:19:03 +0200880 bus->rx_seq);
881 if (!bus->rxskip)
Arend van Spriel5e8149f2012-12-07 10:49:57 +0100882 brcmf_err("unexpected NAKHANDLED!\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +0200883
884 bus->rxskip = false;
885 intstatus |= I_HMB_FRAME_IND;
886 }
887
888 /*
889 * DEVREADY does not occur with gSPI.
890 */
891 if (hmb_data & (HMB_DATA_DEVREADY | HMB_DATA_FWREADY)) {
892 bus->sdpcm_ver =
893 (hmb_data & HMB_DATA_VERSION_MASK) >>
894 HMB_DATA_VERSION_SHIFT;
895 if (bus->sdpcm_ver != SDPCM_PROT_VERSION)
Arend van Spriel5e8149f2012-12-07 10:49:57 +0100896 brcmf_err("Version mismatch, dongle reports %d, "
Arend van Spriel5b435de2011-10-05 13:19:03 +0200897 "expecting %d\n",
898 bus->sdpcm_ver, SDPCM_PROT_VERSION);
899 else
Arend van Sprielc3203372013-04-03 12:40:44 +0200900 brcmf_dbg(SDIO, "Dongle ready, protocol version %d\n",
Arend van Spriel5b435de2011-10-05 13:19:03 +0200901 bus->sdpcm_ver);
902 }
903
904 /*
905 * Flow Control has been moved into the RX headers and this out of band
906 * method isn't used any more.
907 * remaining backward compatible with older dongles.
908 */
909 if (hmb_data & HMB_DATA_FC) {
910 fcbits = (hmb_data & HMB_DATA_FCDATA_MASK) >>
911 HMB_DATA_FCDATA_SHIFT;
912
913 if (fcbits & ~bus->flowcontrol)
Arend van Spriel80969832012-06-09 22:51:44 +0200914 bus->sdcnt.fc_xoff++;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200915
916 if (bus->flowcontrol & ~fcbits)
Arend van Spriel80969832012-06-09 22:51:44 +0200917 bus->sdcnt.fc_xon++;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200918
Arend van Spriel80969832012-06-09 22:51:44 +0200919 bus->sdcnt.fc_rcvd++;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200920 bus->flowcontrol = fcbits;
921 }
922
923 /* Shouldn't be any others */
924 if (hmb_data & ~(HMB_DATA_DEVREADY |
925 HMB_DATA_NAKHANDLED |
926 HMB_DATA_FC |
927 HMB_DATA_FWREADY |
928 HMB_DATA_FCDATA_MASK | HMB_DATA_VERSION_MASK))
Arend van Spriel5e8149f2012-12-07 10:49:57 +0100929 brcmf_err("Unknown mailbox data content: 0x%02x\n",
Arend van Spriel5b435de2011-10-05 13:19:03 +0200930 hmb_data);
931
932 return intstatus;
933}
934
Franky Line92eedf2011-11-22 17:21:50 -0800935static void brcmf_sdbrcm_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200936{
937 uint retries = 0;
938 u16 lastrbc;
939 u8 hi, lo;
940 int err;
941
Arend van Spriel5e8149f2012-12-07 10:49:57 +0100942 brcmf_err("%sterminate frame%s\n",
Arend van Spriel5b435de2011-10-05 13:19:03 +0200943 abort ? "abort command, " : "",
944 rtx ? ", send NAK" : "");
945
946 if (abort)
947 brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2);
948
Franky Lin3bba8292012-05-04 18:27:33 -0700949 brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
950 SFC_RF_TERM, &err);
Arend van Spriel80969832012-06-09 22:51:44 +0200951 bus->sdcnt.f1regdata++;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200952
953 /* Wait until the packet has been flushed (device/FIFO stable) */
954 for (lastrbc = retries = 0xffff; retries > 0; retries--) {
Franky Lin45db3392012-05-04 18:27:32 -0700955 hi = brcmf_sdio_regrb(bus->sdiodev,
Franky Lin5c15c232012-05-04 18:27:37 -0700956 SBSDIO_FUNC1_RFRAMEBCHI, &err);
Franky Lin45db3392012-05-04 18:27:32 -0700957 lo = brcmf_sdio_regrb(bus->sdiodev,
Franky Lin5c15c232012-05-04 18:27:37 -0700958 SBSDIO_FUNC1_RFRAMEBCLO, &err);
Arend van Spriel80969832012-06-09 22:51:44 +0200959 bus->sdcnt.f1regdata += 2;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200960
961 if ((hi == 0) && (lo == 0))
962 break;
963
964 if ((hi > (lastrbc >> 8)) && (lo > (lastrbc & 0x00ff))) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +0100965 brcmf_err("count growing: last 0x%04x now 0x%04x\n",
Arend van Spriel5b435de2011-10-05 13:19:03 +0200966 lastrbc, (hi << 8) + lo);
967 }
968 lastrbc = (hi << 8) + lo;
969 }
970
971 if (!retries)
Arend van Spriel5e8149f2012-12-07 10:49:57 +0100972 brcmf_err("count never zeroed: last 0x%04x\n", lastrbc);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200973 else
Arend van Sprielc3203372013-04-03 12:40:44 +0200974 brcmf_dbg(SDIO, "flush took %d iterations\n", 0xffff - retries);
Arend van Spriel5b435de2011-10-05 13:19:03 +0200975
976 if (rtx) {
Arend van Spriel80969832012-06-09 22:51:44 +0200977 bus->sdcnt.rxrtx++;
Franky Lin58692752012-05-04 18:27:36 -0700978 err = w_sdreg32(bus, SMB_NAK,
979 offsetof(struct sdpcmd_regs, tosbmailbox));
Arend van Spriel5b435de2011-10-05 13:19:03 +0200980
Arend van Spriel80969832012-06-09 22:51:44 +0200981 bus->sdcnt.f1regdata++;
Franky Lin58692752012-05-04 18:27:36 -0700982 if (err == 0)
Arend van Spriel5b435de2011-10-05 13:19:03 +0200983 bus->rxskip = true;
984 }
985
986 /* Clear partial in any case */
Franky Lin4754fce2012-09-19 22:21:11 +0200987 bus->cur_read.len = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200988
989 /* If we can't reach the device, signal failure */
Franky Lin5c15c232012-05-04 18:27:37 -0700990 if (err)
Franky Lin712ac5b2011-12-16 18:37:09 -0800991 bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
Arend van Spriel5b435de2011-10-05 13:19:03 +0200992}
993
Arend van Spriel20e5ca12011-10-18 14:03:09 +0200994/* copy a buffer into a pkt buffer chain */
Franky Line92eedf2011-11-22 17:21:50 -0800995static uint brcmf_sdbrcm_glom_from_buf(struct brcmf_sdio *bus, uint len)
Arend van Spriel20e5ca12011-10-18 14:03:09 +0200996{
997 uint n, ret = 0;
998 struct sk_buff *p;
999 u8 *buf;
1000
Arend van Spriel20e5ca12011-10-18 14:03:09 +02001001 buf = bus->dataptr;
1002
1003 /* copy the data */
Arend van Sprielb83db862011-10-19 12:51:09 +02001004 skb_queue_walk(&bus->glom, p) {
Arend van Spriel20e5ca12011-10-18 14:03:09 +02001005 n = min_t(uint, p->len, len);
1006 memcpy(p->data, buf, n);
1007 buf += n;
1008 len -= n;
1009 ret += n;
Arend van Sprielb83db862011-10-19 12:51:09 +02001010 if (!len)
1011 break;
Arend van Spriel20e5ca12011-10-18 14:03:09 +02001012 }
1013
1014 return ret;
1015}
1016
Arend van Spriel9a95e602011-11-10 20:30:29 +01001017/* return total length of buffer chain */
Franky Line92eedf2011-11-22 17:21:50 -08001018static uint brcmf_sdbrcm_glom_len(struct brcmf_sdio *bus)
Arend van Spriel9a95e602011-11-10 20:30:29 +01001019{
1020 struct sk_buff *p;
1021 uint total;
1022
1023 total = 0;
1024 skb_queue_walk(&bus->glom, p)
1025 total += p->len;
1026 return total;
1027}
1028
Franky Line92eedf2011-11-22 17:21:50 -08001029static void brcmf_sdbrcm_free_glom(struct brcmf_sdio *bus)
Arend van Spriel046808d2011-11-10 20:30:31 +01001030{
1031 struct sk_buff *cur, *next;
1032
1033 skb_queue_walk_safe(&bus->glom, cur, next) {
1034 skb_unlink(cur, &bus->glom);
1035 brcmu_pkt_buf_free_skb(cur);
1036 }
1037}
1038
Franky Lin10510582012-11-05 16:22:26 -08001039static int brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header,
1040 struct brcmf_sdio_read *rd,
1041 enum brcmf_sdio_frmtype type)
Franky Lin4754fce2012-09-19 22:21:11 +02001042{
1043 u16 len, checksum;
1044 u8 rx_seq, fc, tx_seq_max;
1045
1046 /*
1047 * 4 bytes hardware header (frame tag)
1048 * Byte 0~1: Frame length
1049 * Byte 2~3: Checksum, bit-wise inverse of frame length
1050 */
1051 len = get_unaligned_le16(header);
1052 checksum = get_unaligned_le16(header + sizeof(u16));
1053 /* All zero means no more to read */
1054 if (!(len | checksum)) {
1055 bus->rxpending = false;
Franky Lin10510582012-11-05 16:22:26 -08001056 return -ENODATA;
Franky Lin4754fce2012-09-19 22:21:11 +02001057 }
1058 if ((u16)(~(len ^ checksum))) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01001059 brcmf_err("HW header checksum error\n");
Franky Lin4754fce2012-09-19 22:21:11 +02001060 bus->sdcnt.rx_badhdr++;
1061 brcmf_sdbrcm_rxfail(bus, false, false);
Franky Lin10510582012-11-05 16:22:26 -08001062 return -EIO;
Franky Lin4754fce2012-09-19 22:21:11 +02001063 }
1064 if (len < SDPCM_HDRLEN) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01001065 brcmf_err("HW header length error\n");
Franky Lin10510582012-11-05 16:22:26 -08001066 return -EPROTO;
Franky Lin4754fce2012-09-19 22:21:11 +02001067 }
Franky Lin9d7d6f92012-10-22 10:36:24 -07001068 if (type == BRCMF_SDIO_FT_SUPER &&
1069 (roundup(len, bus->blocksize) != rd->len)) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01001070 brcmf_err("HW superframe header length error\n");
Franky Lin10510582012-11-05 16:22:26 -08001071 return -EPROTO;
Franky Lin9d7d6f92012-10-22 10:36:24 -07001072 }
1073 if (type == BRCMF_SDIO_FT_SUB && len > rd->len) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01001074 brcmf_err("HW subframe header length error\n");
Franky Lin10510582012-11-05 16:22:26 -08001075 return -EPROTO;
Franky Lin9d7d6f92012-10-22 10:36:24 -07001076 }
Franky Lin4754fce2012-09-19 22:21:11 +02001077 rd->len = len;
1078
1079 /*
1080 * 8 bytes hardware header
1081 * Byte 0: Rx sequence number
1082 * Byte 1: 4 MSB Channel number, 4 LSB arbitrary flag
1083 * Byte 2: Length of next data frame
1084 * Byte 3: Data offset
1085 * Byte 4: Flow control bits
1086 * Byte 5: Maximum Sequence number allow for Tx
1087 * Byte 6~7: Reserved
1088 */
Franky Lin9d7d6f92012-10-22 10:36:24 -07001089 if (type == BRCMF_SDIO_FT_SUPER &&
1090 SDPCM_GLOMDESC(&header[SDPCM_FRAMETAG_LEN])) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01001091 brcmf_err("Glom descriptor found in superframe head\n");
Franky Lin9d7d6f92012-10-22 10:36:24 -07001092 rd->len = 0;
Franky Lin10510582012-11-05 16:22:26 -08001093 return -EINVAL;
Franky Lin9d7d6f92012-10-22 10:36:24 -07001094 }
Franky Lin4754fce2012-09-19 22:21:11 +02001095 rx_seq = SDPCM_PACKET_SEQUENCE(&header[SDPCM_FRAMETAG_LEN]);
1096 rd->channel = SDPCM_PACKET_CHANNEL(&header[SDPCM_FRAMETAG_LEN]);
Franky Lin9d7d6f92012-10-22 10:36:24 -07001097 if (len > MAX_RX_DATASZ && rd->channel != SDPCM_CONTROL_CHANNEL &&
1098 type != BRCMF_SDIO_FT_SUPER) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01001099 brcmf_err("HW header length too long\n");
Franky Lin4754fce2012-09-19 22:21:11 +02001100 bus->sdcnt.rx_toolong++;
1101 brcmf_sdbrcm_rxfail(bus, false, false);
1102 rd->len = 0;
Franky Lin10510582012-11-05 16:22:26 -08001103 return -EPROTO;
Franky Lin4754fce2012-09-19 22:21:11 +02001104 }
Franky Lin9d7d6f92012-10-22 10:36:24 -07001105 if (type == BRCMF_SDIO_FT_SUPER && rd->channel != SDPCM_GLOM_CHANNEL) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01001106 brcmf_err("Wrong channel for superframe\n");
Franky Lin9d7d6f92012-10-22 10:36:24 -07001107 rd->len = 0;
Franky Lin10510582012-11-05 16:22:26 -08001108 return -EINVAL;
Franky Lin9d7d6f92012-10-22 10:36:24 -07001109 }
1110 if (type == BRCMF_SDIO_FT_SUB && rd->channel != SDPCM_DATA_CHANNEL &&
1111 rd->channel != SDPCM_EVENT_CHANNEL) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01001112 brcmf_err("Wrong channel for subframe\n");
Franky Lin9d7d6f92012-10-22 10:36:24 -07001113 rd->len = 0;
Franky Lin10510582012-11-05 16:22:26 -08001114 return -EINVAL;
Franky Lin9d7d6f92012-10-22 10:36:24 -07001115 }
Franky Lin4754fce2012-09-19 22:21:11 +02001116 rd->dat_offset = SDPCM_DOFFSET_VALUE(&header[SDPCM_FRAMETAG_LEN]);
1117 if (rd->dat_offset < SDPCM_HDRLEN || rd->dat_offset > rd->len) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01001118 brcmf_err("seq %d: bad data offset\n", rx_seq);
Franky Lin4754fce2012-09-19 22:21:11 +02001119 bus->sdcnt.rx_badhdr++;
1120 brcmf_sdbrcm_rxfail(bus, false, false);
1121 rd->len = 0;
Franky Lin10510582012-11-05 16:22:26 -08001122 return -ENXIO;
Franky Lin4754fce2012-09-19 22:21:11 +02001123 }
1124 if (rd->seq_num != rx_seq) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01001125 brcmf_err("seq %d: sequence number error, expect %d\n",
Franky Lin4754fce2012-09-19 22:21:11 +02001126 rx_seq, rd->seq_num);
1127 bus->sdcnt.rx_badseq++;
1128 rd->seq_num = rx_seq;
1129 }
Franky Lin9d7d6f92012-10-22 10:36:24 -07001130 /* no need to check the reset for subframe */
1131 if (type == BRCMF_SDIO_FT_SUB)
Franky Lin10510582012-11-05 16:22:26 -08001132 return 0;
Franky Lin4754fce2012-09-19 22:21:11 +02001133 rd->len_nxtfrm = header[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
1134 if (rd->len_nxtfrm << 4 > MAX_RX_DATASZ) {
1135 /* only warm for NON glom packet */
1136 if (rd->channel != SDPCM_GLOM_CHANNEL)
Arend van Spriel5e8149f2012-12-07 10:49:57 +01001137 brcmf_err("seq %d: next length error\n", rx_seq);
Franky Lin4754fce2012-09-19 22:21:11 +02001138 rd->len_nxtfrm = 0;
1139 }
1140 fc = SDPCM_FCMASK_VALUE(&header[SDPCM_FRAMETAG_LEN]);
1141 if (bus->flowcontrol != fc) {
1142 if (~bus->flowcontrol & fc)
1143 bus->sdcnt.fc_xoff++;
1144 if (bus->flowcontrol & ~fc)
1145 bus->sdcnt.fc_xon++;
1146 bus->sdcnt.fc_rcvd++;
1147 bus->flowcontrol = fc;
1148 }
1149 tx_seq_max = SDPCM_WINDOW_VALUE(&header[SDPCM_FRAMETAG_LEN]);
1150 if ((u8)(tx_seq_max - bus->tx_seq) > 0x40) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01001151 brcmf_err("seq %d: max tx seq number error\n", rx_seq);
Franky Lin4754fce2012-09-19 22:21:11 +02001152 tx_seq_max = bus->tx_seq + 2;
1153 }
1154 bus->tx_max = tx_seq_max;
1155
Franky Lin10510582012-11-05 16:22:26 -08001156 return 0;
Franky Lin4754fce2012-09-19 22:21:11 +02001157}
1158
Franky Line92eedf2011-11-22 17:21:50 -08001159static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001160{
1161 u16 dlen, totlen;
1162 u8 *dptr, num = 0;
1163
Franky Lin9d7d6f92012-10-22 10:36:24 -07001164 u16 sublen;
Arend van Spriel0b45bf72011-11-22 17:21:36 -08001165 struct sk_buff *pfirst, *pnext;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001166
1167 int errcode;
Franky Lin9d7d6f92012-10-22 10:36:24 -07001168 u8 doff, sfdoff;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001169
Arend van Spriel5b435de2011-10-05 13:19:03 +02001170 bool usechain = bus->use_rxchain;
Franky Lin9d7d6f92012-10-22 10:36:24 -07001171
1172 struct brcmf_sdio_read rd_new;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001173
1174 /* If packets, issue read(s) and send up packet chain */
1175 /* Return sequence numbers consumed? */
1176
Arend van Sprielc3203372013-04-03 12:40:44 +02001177 brcmf_dbg(SDIO, "start: glomd %p glom %p\n",
Arend van Sprielb83db862011-10-19 12:51:09 +02001178 bus->glomd, skb_peek(&bus->glom));
Arend van Spriel5b435de2011-10-05 13:19:03 +02001179
1180 /* If there's a descriptor, generate the packet chain */
1181 if (bus->glomd) {
Arend van Spriel0b45bf72011-11-22 17:21:36 -08001182 pfirst = pnext = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001183 dlen = (u16) (bus->glomd->len);
1184 dptr = bus->glomd->data;
1185 if (!dlen || (dlen & 1)) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01001186 brcmf_err("bad glomd len(%d), ignore descriptor\n",
Arend van Spriel5b435de2011-10-05 13:19:03 +02001187 dlen);
1188 dlen = 0;
1189 }
1190
1191 for (totlen = num = 0; dlen; num++) {
1192 /* Get (and move past) next length */
1193 sublen = get_unaligned_le16(dptr);
1194 dlen -= sizeof(u16);
1195 dptr += sizeof(u16);
1196 if ((sublen < SDPCM_HDRLEN) ||
1197 ((num == 0) && (sublen < (2 * SDPCM_HDRLEN)))) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01001198 brcmf_err("descriptor len %d bad: %d\n",
Arend van Spriel5b435de2011-10-05 13:19:03 +02001199 num, sublen);
1200 pnext = NULL;
1201 break;
1202 }
1203 if (sublen % BRCMF_SDALIGN) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01001204 brcmf_err("sublen %d not multiple of %d\n",
Arend van Spriel5b435de2011-10-05 13:19:03 +02001205 sublen, BRCMF_SDALIGN);
1206 usechain = false;
1207 }
1208 totlen += sublen;
1209
1210 /* For last frame, adjust read len so total
1211 is a block multiple */
1212 if (!dlen) {
1213 sublen +=
1214 (roundup(totlen, bus->blocksize) - totlen);
1215 totlen = roundup(totlen, bus->blocksize);
1216 }
1217
1218 /* Allocate/chain packet for next subframe */
1219 pnext = brcmu_pkt_buf_get_skb(sublen + BRCMF_SDALIGN);
1220 if (pnext == NULL) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01001221 brcmf_err("bcm_pkt_buf_get_skb failed, num %d len %d\n",
Arend van Spriel5b435de2011-10-05 13:19:03 +02001222 num, sublen);
1223 break;
1224 }
Arend van Sprielb83db862011-10-19 12:51:09 +02001225 skb_queue_tail(&bus->glom, pnext);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001226
1227 /* Adhere to start alignment requirements */
1228 pkt_align(pnext, sublen, BRCMF_SDALIGN);
1229 }
1230
1231 /* If all allocations succeeded, save packet chain
1232 in bus structure */
1233 if (pnext) {
1234 brcmf_dbg(GLOM, "allocated %d-byte packet chain for %d subframes\n",
1235 totlen, num);
Franky Lin4754fce2012-09-19 22:21:11 +02001236 if (BRCMF_GLOM_ON() && bus->cur_read.len &&
1237 totlen != bus->cur_read.len) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02001238 brcmf_dbg(GLOM, "glomdesc mismatch: nextlen %d glomdesc %d rxseq %d\n",
Franky Lin4754fce2012-09-19 22:21:11 +02001239 bus->cur_read.len, totlen, rxseq);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001240 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001241 pfirst = pnext = NULL;
1242 } else {
Arend van Spriel046808d2011-11-10 20:30:31 +01001243 brcmf_sdbrcm_free_glom(bus);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001244 num = 0;
1245 }
1246
1247 /* Done with descriptor packet */
1248 brcmu_pkt_buf_free_skb(bus->glomd);
1249 bus->glomd = NULL;
Franky Lin4754fce2012-09-19 22:21:11 +02001250 bus->cur_read.len = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001251 }
1252
1253 /* Ok -- either we just generated a packet chain,
1254 or had one from before */
Arend van Sprielb83db862011-10-19 12:51:09 +02001255 if (!skb_queue_empty(&bus->glom)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02001256 if (BRCMF_GLOM_ON()) {
1257 brcmf_dbg(GLOM, "try superframe read, packet chain:\n");
Arend van Sprielb83db862011-10-19 12:51:09 +02001258 skb_queue_walk(&bus->glom, pnext) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02001259 brcmf_dbg(GLOM, " %p: %p len 0x%04x (%d)\n",
1260 pnext, (u8 *) (pnext->data),
1261 pnext->len, pnext->len);
1262 }
1263 }
1264
Arend van Sprielb83db862011-10-19 12:51:09 +02001265 pfirst = skb_peek(&bus->glom);
Arend van Spriel9a95e602011-11-10 20:30:29 +01001266 dlen = (u16) brcmf_sdbrcm_glom_len(bus);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001267
1268 /* Do an SDIO read for the superframe. Configurable iovar to
1269 * read directly into the chained packet, or allocate a large
1270 * packet and and copy into the chain.
1271 */
Franky Lin38b0b0d2012-11-05 16:22:24 -08001272 sdio_claim_host(bus->sdiodev->func[1]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001273 if (usechain) {
Arend van Spriel5adfeb62011-11-22 17:21:38 -08001274 errcode = brcmf_sdcard_recv_chain(bus->sdiodev,
Arend van Spriel5b435de2011-10-05 13:19:03 +02001275 bus->sdiodev->sbwad,
Arend van Spriel5adfeb62011-11-22 17:21:38 -08001276 SDIO_FUNC_2, F2SYNC, &bus->glom);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001277 } else if (bus->dataptr) {
1278 errcode = brcmf_sdcard_recv_buf(bus->sdiodev,
1279 bus->sdiodev->sbwad,
Arend van Spriel5adfeb62011-11-22 17:21:38 -08001280 SDIO_FUNC_2, F2SYNC,
1281 bus->dataptr, dlen);
Arend van Spriel20e5ca12011-10-18 14:03:09 +02001282 sublen = (u16) brcmf_sdbrcm_glom_from_buf(bus, dlen);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001283 if (sublen != dlen) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01001284 brcmf_err("FAILED TO COPY, dlen %d sublen %d\n",
Arend van Spriel5b435de2011-10-05 13:19:03 +02001285 dlen, sublen);
1286 errcode = -1;
1287 }
1288 pnext = NULL;
1289 } else {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01001290 brcmf_err("COULDN'T ALLOC %d-BYTE GLOM, FORCE FAILURE\n",
Arend van Spriel5b435de2011-10-05 13:19:03 +02001291 dlen);
1292 errcode = -1;
1293 }
Franky Lin38b0b0d2012-11-05 16:22:24 -08001294 sdio_release_host(bus->sdiodev->func[1]);
Arend van Spriel80969832012-06-09 22:51:44 +02001295 bus->sdcnt.f2rxdata++;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001296
1297 /* On failure, kill the superframe, allow a couple retries */
1298 if (errcode < 0) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01001299 brcmf_err("glom read of %d bytes failed: %d\n",
Arend van Spriel5b435de2011-10-05 13:19:03 +02001300 dlen, errcode);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001301
Franky Lin38b0b0d2012-11-05 16:22:24 -08001302 sdio_claim_host(bus->sdiodev->func[1]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001303 if (bus->glomerr++ < 3) {
1304 brcmf_sdbrcm_rxfail(bus, true, true);
1305 } else {
1306 bus->glomerr = 0;
1307 brcmf_sdbrcm_rxfail(bus, true, false);
Arend van Spriel80969832012-06-09 22:51:44 +02001308 bus->sdcnt.rxglomfail++;
Arend van Spriel046808d2011-11-10 20:30:31 +01001309 brcmf_sdbrcm_free_glom(bus);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001310 }
Franky Lin38b0b0d2012-11-05 16:22:24 -08001311 sdio_release_host(bus->sdiodev->func[1]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001312 return 0;
1313 }
Joe Perches1e023822012-01-15 00:38:40 -08001314
1315 brcmf_dbg_hex_dump(BRCMF_GLOM_ON(),
1316 pfirst->data, min_t(int, pfirst->len, 48),
1317 "SUPERFRAME:\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001318
Franky Lin9d7d6f92012-10-22 10:36:24 -07001319 rd_new.seq_num = rxseq;
1320 rd_new.len = dlen;
Franky Lin38b0b0d2012-11-05 16:22:24 -08001321 sdio_claim_host(bus->sdiodev->func[1]);
Franky Lin10510582012-11-05 16:22:26 -08001322 errcode = brcmf_sdio_hdparser(bus, pfirst->data, &rd_new,
1323 BRCMF_SDIO_FT_SUPER);
Franky Lin38b0b0d2012-11-05 16:22:24 -08001324 sdio_release_host(bus->sdiodev->func[1]);
Franky Lin9d7d6f92012-10-22 10:36:24 -07001325 bus->cur_read.len = rd_new.len_nxtfrm << 4;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001326
1327 /* Remove superframe header, remember offset */
Franky Lin9d7d6f92012-10-22 10:36:24 -07001328 skb_pull(pfirst, rd_new.dat_offset);
1329 sfdoff = rd_new.dat_offset;
Arend van Spriel0b45bf72011-11-22 17:21:36 -08001330 num = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001331
1332 /* Validate all the subframe headers */
Arend van Spriel0b45bf72011-11-22 17:21:36 -08001333 skb_queue_walk(&bus->glom, pnext) {
1334 /* leave when invalid subframe is found */
1335 if (errcode)
1336 break;
1337
Franky Lin9d7d6f92012-10-22 10:36:24 -07001338 rd_new.len = pnext->len;
1339 rd_new.seq_num = rxseq++;
Franky Lin38b0b0d2012-11-05 16:22:24 -08001340 sdio_claim_host(bus->sdiodev->func[1]);
Franky Lin10510582012-11-05 16:22:26 -08001341 errcode = brcmf_sdio_hdparser(bus, pnext->data, &rd_new,
1342 BRCMF_SDIO_FT_SUB);
Franky Lin38b0b0d2012-11-05 16:22:24 -08001343 sdio_release_host(bus->sdiodev->func[1]);
Joe Perches1e023822012-01-15 00:38:40 -08001344 brcmf_dbg_hex_dump(BRCMF_GLOM_ON(),
Franky Lin9d7d6f92012-10-22 10:36:24 -07001345 pnext->data, 32, "subframe:\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001346
Arend van Spriel0b45bf72011-11-22 17:21:36 -08001347 num++;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001348 }
1349
1350 if (errcode) {
1351 /* Terminate frame on error, request
1352 a couple retries */
Franky Lin38b0b0d2012-11-05 16:22:24 -08001353 sdio_claim_host(bus->sdiodev->func[1]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001354 if (bus->glomerr++ < 3) {
1355 /* Restore superframe header space */
1356 skb_push(pfirst, sfdoff);
1357 brcmf_sdbrcm_rxfail(bus, true, true);
1358 } else {
1359 bus->glomerr = 0;
1360 brcmf_sdbrcm_rxfail(bus, true, false);
Arend van Spriel80969832012-06-09 22:51:44 +02001361 bus->sdcnt.rxglomfail++;
Arend van Spriel046808d2011-11-10 20:30:31 +01001362 brcmf_sdbrcm_free_glom(bus);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001363 }
Franky Lin38b0b0d2012-11-05 16:22:24 -08001364 sdio_release_host(bus->sdiodev->func[1]);
Franky Lin4754fce2012-09-19 22:21:11 +02001365 bus->cur_read.len = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001366 return 0;
1367 }
1368
1369 /* Basic SD framing looks ok - process each packet (header) */
Arend van Spriel5b435de2011-10-05 13:19:03 +02001370
Arend van Spriel0b45bf72011-11-22 17:21:36 -08001371 skb_queue_walk_safe(&bus->glom, pfirst, pnext) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02001372 dptr = (u8 *) (pfirst->data);
1373 sublen = get_unaligned_le16(dptr);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001374 doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
1375
Joe Perches1e023822012-01-15 00:38:40 -08001376 brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && BRCMF_DATA_ON(),
Franky Lin9d7d6f92012-10-22 10:36:24 -07001377 dptr, pfirst->len,
1378 "Rx Subframe Data:\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001379
1380 __skb_trim(pfirst, sublen);
1381 skb_pull(pfirst, doff);
1382
1383 if (pfirst->len == 0) {
Arend van Spriel0b45bf72011-11-22 17:21:36 -08001384 skb_unlink(pfirst, &bus->glom);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001385 brcmu_pkt_buf_free_skb(pfirst);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001386 continue;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001387 }
1388
Joe Perches1e023822012-01-15 00:38:40 -08001389 brcmf_dbg_hex_dump(BRCMF_GLOM_ON(),
1390 pfirst->data,
1391 min_t(int, pfirst->len, 32),
1392 "subframe %d to stack, %p (%p/%d) nxt/lnk %p/%p\n",
1393 bus->glom.qlen, pfirst, pfirst->data,
1394 pfirst->len, pfirst->next,
1395 pfirst->prev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001396 }
Arend van Spriel0b45bf72011-11-22 17:21:36 -08001397 /* sent any remaining packets up */
Franky Lin7cdf57d2012-11-05 16:22:23 -08001398 if (bus->glom.qlen)
Arend van Spriela43af512013-01-02 15:22:43 +01001399 brcmf_rx_frames(bus->sdiodev->dev, &bus->glom);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001400
Arend van Spriel80969832012-06-09 22:51:44 +02001401 bus->sdcnt.rxglomframes++;
1402 bus->sdcnt.rxglompkts += bus->glom.qlen;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001403 }
1404 return num;
1405}
1406
Franky Line92eedf2011-11-22 17:21:50 -08001407static int brcmf_sdbrcm_dcmd_resp_wait(struct brcmf_sdio *bus, uint *condition,
Arend van Spriel5b435de2011-10-05 13:19:03 +02001408 bool *pending)
1409{
1410 DECLARE_WAITQUEUE(wait, current);
1411 int timeout = msecs_to_jiffies(DCMD_RESP_TIMEOUT);
1412
1413 /* Wait until control frame is available */
1414 add_wait_queue(&bus->dcmd_resp_wait, &wait);
1415 set_current_state(TASK_INTERRUPTIBLE);
1416
1417 while (!(*condition) && (!signal_pending(current) && timeout))
1418 timeout = schedule_timeout(timeout);
1419
1420 if (signal_pending(current))
1421 *pending = true;
1422
1423 set_current_state(TASK_RUNNING);
1424 remove_wait_queue(&bus->dcmd_resp_wait, &wait);
1425
1426 return timeout;
1427}
1428
Franky Line92eedf2011-11-22 17:21:50 -08001429static int brcmf_sdbrcm_dcmd_resp_wake(struct brcmf_sdio *bus)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001430{
1431 if (waitqueue_active(&bus->dcmd_resp_wait))
1432 wake_up_interruptible(&bus->dcmd_resp_wait);
1433
1434 return 0;
1435}
1436static void
Franky Line92eedf2011-11-22 17:21:50 -08001437brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001438{
1439 uint rdlen, pad;
Franky Lindd43a012012-11-05 16:22:22 -08001440 u8 *buf = NULL, *rbuf;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001441 int sdret;
1442
1443 brcmf_dbg(TRACE, "Enter\n");
1444
Franky Lindd43a012012-11-05 16:22:22 -08001445 if (bus->rxblen)
1446 buf = vzalloc(bus->rxblen);
Joe Perches14f8dc42013-02-07 11:46:27 +00001447 if (!buf)
Franky Lindd43a012012-11-05 16:22:22 -08001448 goto done;
Joe Perches14f8dc42013-02-07 11:46:27 +00001449
Franky Lindd43a012012-11-05 16:22:22 -08001450 rbuf = bus->rxbuf;
1451 pad = ((unsigned long)rbuf % BRCMF_SDALIGN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001452 if (pad)
Franky Lindd43a012012-11-05 16:22:22 -08001453 rbuf += (BRCMF_SDALIGN - pad);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001454
1455 /* Copy the already-read portion over */
Franky Lindd43a012012-11-05 16:22:22 -08001456 memcpy(buf, hdr, BRCMF_FIRSTREAD);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001457 if (len <= BRCMF_FIRSTREAD)
1458 goto gotpkt;
1459
1460 /* Raise rdlen to next SDIO block to avoid tail command */
1461 rdlen = len - BRCMF_FIRSTREAD;
1462 if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
1463 pad = bus->blocksize - (rdlen % bus->blocksize);
1464 if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
Franky Linb01a6b32011-12-16 18:37:03 -08001465 ((len + pad) < bus->sdiodev->bus_if->maxctl))
Arend van Spriel5b435de2011-10-05 13:19:03 +02001466 rdlen += pad;
1467 } else if (rdlen % BRCMF_SDALIGN) {
1468 rdlen += BRCMF_SDALIGN - (rdlen % BRCMF_SDALIGN);
1469 }
1470
1471 /* Satisfy length-alignment requirements */
1472 if (rdlen & (ALIGNMENT - 1))
1473 rdlen = roundup(rdlen, ALIGNMENT);
1474
1475 /* Drop if the read is too big or it exceeds our maximum */
Franky Linb01a6b32011-12-16 18:37:03 -08001476 if ((rdlen + BRCMF_FIRSTREAD) > bus->sdiodev->bus_if->maxctl) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01001477 brcmf_err("%d-byte control read exceeds %d-byte buffer\n",
Franky Linb01a6b32011-12-16 18:37:03 -08001478 rdlen, bus->sdiodev->bus_if->maxctl);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001479 brcmf_sdbrcm_rxfail(bus, false, false);
1480 goto done;
1481 }
1482
Franky Linb01a6b32011-12-16 18:37:03 -08001483 if ((len - doff) > bus->sdiodev->bus_if->maxctl) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01001484 brcmf_err("%d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n",
Franky Linb01a6b32011-12-16 18:37:03 -08001485 len, len - doff, bus->sdiodev->bus_if->maxctl);
Arend van Spriel80969832012-06-09 22:51:44 +02001486 bus->sdcnt.rx_toolong++;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001487 brcmf_sdbrcm_rxfail(bus, false, false);
1488 goto done;
1489 }
1490
Franky Lindd43a012012-11-05 16:22:22 -08001491 /* Read remain of frame body */
Arend van Spriel5b435de2011-10-05 13:19:03 +02001492 sdret = brcmf_sdcard_recv_buf(bus->sdiodev,
1493 bus->sdiodev->sbwad,
1494 SDIO_FUNC_2,
Franky Lindd43a012012-11-05 16:22:22 -08001495 F2SYNC, rbuf, rdlen);
Arend van Spriel80969832012-06-09 22:51:44 +02001496 bus->sdcnt.f2rxdata++;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001497
1498 /* Control frame failures need retransmission */
1499 if (sdret < 0) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01001500 brcmf_err("read %d control bytes failed: %d\n",
Arend van Spriel5b435de2011-10-05 13:19:03 +02001501 rdlen, sdret);
Arend van Spriel80969832012-06-09 22:51:44 +02001502 bus->sdcnt.rxc_errors++;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001503 brcmf_sdbrcm_rxfail(bus, true, true);
1504 goto done;
Franky Lindd43a012012-11-05 16:22:22 -08001505 } else
1506 memcpy(buf + BRCMF_FIRSTREAD, rbuf, rdlen);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001507
1508gotpkt:
1509
Joe Perches1e023822012-01-15 00:38:40 -08001510 brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && BRCMF_CTL_ON(),
Franky Lindd43a012012-11-05 16:22:22 -08001511 buf, len, "RxCtrl:\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001512
1513 /* Point to valid data and indicate its length */
Franky Lindd43a012012-11-05 16:22:22 -08001514 spin_lock_bh(&bus->rxctl_lock);
1515 if (bus->rxctl) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01001516 brcmf_err("last control frame is being processed.\n");
Franky Lindd43a012012-11-05 16:22:22 -08001517 spin_unlock_bh(&bus->rxctl_lock);
1518 vfree(buf);
1519 goto done;
1520 }
1521 bus->rxctl = buf + doff;
1522 bus->rxctl_orig = buf;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001523 bus->rxlen = len - doff;
Franky Lindd43a012012-11-05 16:22:22 -08001524 spin_unlock_bh(&bus->rxctl_lock);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001525
1526done:
1527 /* Awake any waiters */
1528 brcmf_sdbrcm_dcmd_resp_wake(bus);
1529}
1530
1531/* Pad read to blocksize for efficiency */
Franky Line92eedf2011-11-22 17:21:50 -08001532static void brcmf_pad(struct brcmf_sdio *bus, u16 *pad, u16 *rdlen)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001533{
1534 if (bus->roundup && bus->blocksize && *rdlen > bus->blocksize) {
1535 *pad = bus->blocksize - (*rdlen % bus->blocksize);
1536 if (*pad <= bus->roundup && *pad < bus->blocksize &&
1537 *rdlen + *pad + BRCMF_FIRSTREAD < MAX_RX_DATASZ)
1538 *rdlen += *pad;
1539 } else if (*rdlen % BRCMF_SDALIGN) {
1540 *rdlen += BRCMF_SDALIGN - (*rdlen % BRCMF_SDALIGN);
1541 }
1542}
1543
Franky Lin4754fce2012-09-19 22:21:11 +02001544static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001545{
Arend van Spriel5b435de2011-10-05 13:19:03 +02001546 struct sk_buff *pkt; /* Packet for event or data frames */
Arend van Spriel3aa7aad2013-01-02 15:22:42 +01001547 struct sk_buff_head pktlist; /* needed for bus interface */
Arend van Spriel5b435de2011-10-05 13:19:03 +02001548 u16 pad; /* Number of pad bytes to read */
Arend van Spriel5b435de2011-10-05 13:19:03 +02001549 uint rxleft = 0; /* Remaining number of frames allowed */
Arend van Spriel349e7102013-03-03 12:45:28 +01001550 int ret; /* Return code from calls */
Arend van Spriel5b435de2011-10-05 13:19:03 +02001551 uint rxcount = 0; /* Total frames read */
Franky Lin4754fce2012-09-19 22:21:11 +02001552 struct brcmf_sdio_read *rd = &bus->cur_read, rd_new;
1553 u8 head_read = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001554
1555 brcmf_dbg(TRACE, "Enter\n");
1556
1557 /* Not finished unless we encounter no more frames indication */
Franky Lin4754fce2012-09-19 22:21:11 +02001558 bus->rxpending = true;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001559
Franky Lin4754fce2012-09-19 22:21:11 +02001560 for (rd->seq_num = bus->rx_seq, rxleft = maxframes;
Franky Lin8d169aa2011-11-22 17:21:52 -08001561 !bus->rxskip && rxleft &&
Franky Lin712ac5b2011-12-16 18:37:09 -08001562 bus->sdiodev->bus_if->state != BRCMF_BUS_DOWN;
Franky Lin4754fce2012-09-19 22:21:11 +02001563 rd->seq_num++, rxleft--) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02001564
1565 /* Handle glomming separately */
Arend van Sprielb83db862011-10-19 12:51:09 +02001566 if (bus->glomd || !skb_queue_empty(&bus->glom)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02001567 u8 cnt;
1568 brcmf_dbg(GLOM, "calling rxglom: glomd %p, glom %p\n",
Arend van Sprielb83db862011-10-19 12:51:09 +02001569 bus->glomd, skb_peek(&bus->glom));
Franky Lin4754fce2012-09-19 22:21:11 +02001570 cnt = brcmf_sdbrcm_rxglom(bus, rd->seq_num);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001571 brcmf_dbg(GLOM, "rxglom returned %d\n", cnt);
Franky Lin4754fce2012-09-19 22:21:11 +02001572 rd->seq_num += cnt - 1;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001573 rxleft = (rxleft > cnt) ? (rxleft - cnt) : 1;
1574 continue;
1575 }
1576
Franky Lin4754fce2012-09-19 22:21:11 +02001577 rd->len_left = rd->len;
1578 /* read header first for unknow frame length */
Franky Lin38b0b0d2012-11-05 16:22:24 -08001579 sdio_claim_host(bus->sdiodev->func[1]);
Franky Lin4754fce2012-09-19 22:21:11 +02001580 if (!rd->len) {
Arend van Spriel349e7102013-03-03 12:45:28 +01001581 ret = brcmf_sdcard_recv_buf(bus->sdiodev,
Franky Lin4754fce2012-09-19 22:21:11 +02001582 bus->sdiodev->sbwad,
1583 SDIO_FUNC_2, F2SYNC,
1584 bus->rxhdr,
1585 BRCMF_FIRSTREAD);
1586 bus->sdcnt.f2rxhdrs++;
Arend van Spriel349e7102013-03-03 12:45:28 +01001587 if (ret < 0) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01001588 brcmf_err("RXHEADER FAILED: %d\n",
Arend van Spriel349e7102013-03-03 12:45:28 +01001589 ret);
Franky Lin4754fce2012-09-19 22:21:11 +02001590 bus->sdcnt.rx_hdrfail++;
1591 brcmf_sdbrcm_rxfail(bus, true, true);
Franky Lin38b0b0d2012-11-05 16:22:24 -08001592 sdio_release_host(bus->sdiodev->func[1]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001593 continue;
1594 }
1595
Franky Lin4754fce2012-09-19 22:21:11 +02001596 brcmf_dbg_hex_dump(BRCMF_BYTES_ON() || BRCMF_HDRS_ON(),
1597 bus->rxhdr, SDPCM_HDRLEN,
1598 "RxHdr:\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001599
Franky Lin10510582012-11-05 16:22:26 -08001600 if (brcmf_sdio_hdparser(bus, bus->rxhdr, rd,
1601 BRCMF_SDIO_FT_NORMAL)) {
Franky Lin38b0b0d2012-11-05 16:22:24 -08001602 sdio_release_host(bus->sdiodev->func[1]);
Franky Lin4754fce2012-09-19 22:21:11 +02001603 if (!bus->rxpending)
1604 break;
1605 else
1606 continue;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001607 }
1608
Franky Lin4754fce2012-09-19 22:21:11 +02001609 if (rd->channel == SDPCM_CONTROL_CHANNEL) {
1610 brcmf_sdbrcm_read_control(bus, bus->rxhdr,
1611 rd->len,
1612 rd->dat_offset);
1613 /* prepare the descriptor for the next read */
1614 rd->len = rd->len_nxtfrm << 4;
1615 rd->len_nxtfrm = 0;
1616 /* treat all packet as event if we don't know */
1617 rd->channel = SDPCM_EVENT_CHANNEL;
Franky Lin38b0b0d2012-11-05 16:22:24 -08001618 sdio_release_host(bus->sdiodev->func[1]);
Franky Lin4754fce2012-09-19 22:21:11 +02001619 continue;
1620 }
1621 rd->len_left = rd->len > BRCMF_FIRSTREAD ?
1622 rd->len - BRCMF_FIRSTREAD : 0;
1623 head_read = BRCMF_FIRSTREAD;
1624 }
1625
1626 brcmf_pad(bus, &pad, &rd->len_left);
1627
1628 pkt = brcmu_pkt_buf_get_skb(rd->len_left + head_read +
1629 BRCMF_SDALIGN);
1630 if (!pkt) {
1631 /* Give up on data, request rtx of events */
Arend van Spriel5e8149f2012-12-07 10:49:57 +01001632 brcmf_err("brcmu_pkt_buf_get_skb failed\n");
Franky Lin4754fce2012-09-19 22:21:11 +02001633 brcmf_sdbrcm_rxfail(bus, false,
1634 RETRYCHAN(rd->channel));
Franky Lin38b0b0d2012-11-05 16:22:24 -08001635 sdio_release_host(bus->sdiodev->func[1]);
Franky Lin4754fce2012-09-19 22:21:11 +02001636 continue;
1637 }
1638 skb_pull(pkt, head_read);
1639 pkt_align(pkt, rd->len_left, BRCMF_SDALIGN);
1640
Arend van Spriel349e7102013-03-03 12:45:28 +01001641 ret = brcmf_sdcard_recv_pkt(bus->sdiodev, bus->sdiodev->sbwad,
Franky Lin4754fce2012-09-19 22:21:11 +02001642 SDIO_FUNC_2, F2SYNC, pkt);
1643 bus->sdcnt.f2rxdata++;
Franky Lin38b0b0d2012-11-05 16:22:24 -08001644 sdio_release_host(bus->sdiodev->func[1]);
Franky Lin4754fce2012-09-19 22:21:11 +02001645
Arend van Spriel349e7102013-03-03 12:45:28 +01001646 if (ret < 0) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01001647 brcmf_err("read %d bytes from channel %d failed: %d\n",
Arend van Spriel349e7102013-03-03 12:45:28 +01001648 rd->len, rd->channel, ret);
Franky Lin4754fce2012-09-19 22:21:11 +02001649 brcmu_pkt_buf_free_skb(pkt);
Franky Lin38b0b0d2012-11-05 16:22:24 -08001650 sdio_claim_host(bus->sdiodev->func[1]);
Franky Lin4754fce2012-09-19 22:21:11 +02001651 brcmf_sdbrcm_rxfail(bus, true,
1652 RETRYCHAN(rd->channel));
Franky Lin38b0b0d2012-11-05 16:22:24 -08001653 sdio_release_host(bus->sdiodev->func[1]);
Franky Lin4754fce2012-09-19 22:21:11 +02001654 continue;
1655 }
1656
1657 if (head_read) {
1658 skb_push(pkt, head_read);
1659 memcpy(pkt->data, bus->rxhdr, head_read);
1660 head_read = 0;
1661 } else {
1662 memcpy(bus->rxhdr, pkt->data, SDPCM_HDRLEN);
1663 rd_new.seq_num = rd->seq_num;
Franky Lin38b0b0d2012-11-05 16:22:24 -08001664 sdio_claim_host(bus->sdiodev->func[1]);
Franky Lin10510582012-11-05 16:22:26 -08001665 if (brcmf_sdio_hdparser(bus, bus->rxhdr, &rd_new,
1666 BRCMF_SDIO_FT_NORMAL)) {
Franky Lin4754fce2012-09-19 22:21:11 +02001667 rd->len = 0;
1668 brcmu_pkt_buf_free_skb(pkt);
1669 }
Arend van Spriel80969832012-06-09 22:51:44 +02001670 bus->sdcnt.rx_readahead_cnt++;
Franky Lin4754fce2012-09-19 22:21:11 +02001671 if (rd->len != roundup(rd_new.len, 16)) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01001672 brcmf_err("frame length mismatch:read %d, should be %d\n",
Franky Lin4754fce2012-09-19 22:21:11 +02001673 rd->len,
1674 roundup(rd_new.len, 16) >> 4);
1675 rd->len = 0;
1676 brcmf_sdbrcm_rxfail(bus, true, true);
Franky Lin38b0b0d2012-11-05 16:22:24 -08001677 sdio_release_host(bus->sdiodev->func[1]);
Franky Lin4754fce2012-09-19 22:21:11 +02001678 brcmu_pkt_buf_free_skb(pkt);
1679 continue;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001680 }
Franky Lin38b0b0d2012-11-05 16:22:24 -08001681 sdio_release_host(bus->sdiodev->func[1]);
Franky Lin4754fce2012-09-19 22:21:11 +02001682 rd->len_nxtfrm = rd_new.len_nxtfrm;
1683 rd->channel = rd_new.channel;
1684 rd->dat_offset = rd_new.dat_offset;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001685
Joe Perches1e023822012-01-15 00:38:40 -08001686 brcmf_dbg_hex_dump(!(BRCMF_BYTES_ON() &&
1687 BRCMF_DATA_ON()) &&
1688 BRCMF_HDRS_ON(),
1689 bus->rxhdr, SDPCM_HDRLEN,
1690 "RxHdr:\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001691
Franky Lin4754fce2012-09-19 22:21:11 +02001692 if (rd_new.channel == SDPCM_CONTROL_CHANNEL) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01001693 brcmf_err("readahead on control packet %d?\n",
Franky Lin4754fce2012-09-19 22:21:11 +02001694 rd_new.seq_num);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001695 /* Force retry w/normal header read */
Franky Lin4754fce2012-09-19 22:21:11 +02001696 rd->len = 0;
Franky Lin38b0b0d2012-11-05 16:22:24 -08001697 sdio_claim_host(bus->sdiodev->func[1]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001698 brcmf_sdbrcm_rxfail(bus, false, true);
Franky Lin38b0b0d2012-11-05 16:22:24 -08001699 sdio_release_host(bus->sdiodev->func[1]);
Franky Lin4754fce2012-09-19 22:21:11 +02001700 brcmu_pkt_buf_free_skb(pkt);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001701 continue;
1702 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001703 }
1704
Joe Perches1e023822012-01-15 00:38:40 -08001705 brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && BRCMF_DATA_ON(),
Franky Lin4754fce2012-09-19 22:21:11 +02001706 pkt->data, rd->len, "Rx Data:\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001707
Arend van Spriel5b435de2011-10-05 13:19:03 +02001708 /* Save superframe descriptor and allocate packet frame */
Franky Lin4754fce2012-09-19 22:21:11 +02001709 if (rd->channel == SDPCM_GLOM_CHANNEL) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02001710 if (SDPCM_GLOMDESC(&bus->rxhdr[SDPCM_FRAMETAG_LEN])) {
1711 brcmf_dbg(GLOM, "glom descriptor, %d bytes:\n",
Franky Lin4754fce2012-09-19 22:21:11 +02001712 rd->len);
Joe Perches1e023822012-01-15 00:38:40 -08001713 brcmf_dbg_hex_dump(BRCMF_GLOM_ON(),
Franky Lin4754fce2012-09-19 22:21:11 +02001714 pkt->data, rd->len,
Joe Perches1e023822012-01-15 00:38:40 -08001715 "Glom Data:\n");
Franky Lin4754fce2012-09-19 22:21:11 +02001716 __skb_trim(pkt, rd->len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001717 skb_pull(pkt, SDPCM_HDRLEN);
1718 bus->glomd = pkt;
1719 } else {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01001720 brcmf_err("%s: glom superframe w/o "
Arend van Spriel5b435de2011-10-05 13:19:03 +02001721 "descriptor!\n", __func__);
Franky Lin38b0b0d2012-11-05 16:22:24 -08001722 sdio_claim_host(bus->sdiodev->func[1]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001723 brcmf_sdbrcm_rxfail(bus, false, false);
Franky Lin38b0b0d2012-11-05 16:22:24 -08001724 sdio_release_host(bus->sdiodev->func[1]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001725 }
Franky Lin4754fce2012-09-19 22:21:11 +02001726 /* prepare the descriptor for the next read */
1727 rd->len = rd->len_nxtfrm << 4;
1728 rd->len_nxtfrm = 0;
1729 /* treat all packet as event if we don't know */
1730 rd->channel = SDPCM_EVENT_CHANNEL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001731 continue;
1732 }
1733
1734 /* Fill in packet len and prio, deliver upward */
Franky Lin4754fce2012-09-19 22:21:11 +02001735 __skb_trim(pkt, rd->len);
1736 skb_pull(pkt, rd->dat_offset);
1737
1738 /* prepare the descriptor for the next read */
1739 rd->len = rd->len_nxtfrm << 4;
1740 rd->len_nxtfrm = 0;
1741 /* treat all packet as event if we don't know */
1742 rd->channel = SDPCM_EVENT_CHANNEL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001743
1744 if (pkt->len == 0) {
1745 brcmu_pkt_buf_free_skb(pkt);
1746 continue;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001747 }
1748
Arend van Spriel3aa7aad2013-01-02 15:22:42 +01001749 skb_queue_head_init(&pktlist);
1750 skb_queue_tail(&pktlist, pkt);
Arend van Spriela43af512013-01-02 15:22:43 +01001751 brcmf_rx_frames(bus->sdiodev->dev, &pktlist);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001752 }
Franky Lin4754fce2012-09-19 22:21:11 +02001753
Arend van Spriel5b435de2011-10-05 13:19:03 +02001754 rxcount = maxframes - rxleft;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001755 /* Message if we hit the limit */
1756 if (!rxleft)
Franky Lin4754fce2012-09-19 22:21:11 +02001757 brcmf_dbg(DATA, "hit rx limit of %d frames\n", maxframes);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001758 else
Arend van Spriel5b435de2011-10-05 13:19:03 +02001759 brcmf_dbg(DATA, "processed %d frames\n", rxcount);
1760 /* Back off rxseq if awaiting rtx, update rx_seq */
1761 if (bus->rxskip)
Franky Lin4754fce2012-09-19 22:21:11 +02001762 rd->seq_num--;
1763 bus->rx_seq = rd->seq_num;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001764
1765 return rxcount;
1766}
1767
Arend van Spriel5b435de2011-10-05 13:19:03 +02001768static void
Franky Line92eedf2011-11-22 17:21:50 -08001769brcmf_sdbrcm_wait_event_wakeup(struct brcmf_sdio *bus)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001770{
1771 if (waitqueue_active(&bus->ctrl_wait))
1772 wake_up_interruptible(&bus->ctrl_wait);
1773 return;
1774}
1775
1776/* Writes a HW/SW header into the packet and sends it. */
1777/* Assumes: (a) header space already there, (b) caller holds lock */
Franky Line92eedf2011-11-22 17:21:50 -08001778static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt,
Arend van Spriel7f4bcee2013-03-03 12:45:29 +01001779 uint chan)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001780{
1781 int ret;
1782 u8 *frame;
1783 u16 len, pad = 0;
1784 u32 swheader;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001785 int i;
1786
1787 brcmf_dbg(TRACE, "Enter\n");
1788
1789 frame = (u8 *) (pkt->data);
1790
1791 /* Add alignment padding, allocate new packet if needed */
1792 pad = ((unsigned long)frame % BRCMF_SDALIGN);
1793 if (pad) {
1794 if (skb_headroom(pkt) < pad) {
1795 brcmf_dbg(INFO, "insufficient headroom %d for %d pad\n",
1796 skb_headroom(pkt), pad);
Franky Lin9c1a0432011-12-16 18:37:07 -08001797 bus->sdiodev->bus_if->tx_realloc++;
Arend van Sprielaeecc5742013-04-03 12:40:28 +02001798 ret = skb_cow(pkt, BRCMF_SDALIGN);
1799 if (ret)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001800 goto done;
Arend van Sprielaeecc5742013-04-03 12:40:28 +02001801 pad = ((unsigned long)frame % BRCMF_SDALIGN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001802 }
Arend van Sprielaeecc5742013-04-03 12:40:28 +02001803 skb_push(pkt, pad);
1804 frame = (u8 *) (pkt->data);
1805 memset(frame, 0, pad + SDPCM_HDRLEN);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001806 }
1807 /* precondition: pad < BRCMF_SDALIGN */
1808
1809 /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
1810 len = (u16) (pkt->len);
1811 *(__le16 *) frame = cpu_to_le16(len);
1812 *(((__le16 *) frame) + 1) = cpu_to_le16(~len);
1813
1814 /* Software tag: channel, sequence number, data offset */
1815 swheader =
1816 ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) | bus->tx_seq |
1817 (((pad +
1818 SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
1819
Arend van Spriela0427802013-04-03 12:40:27 +02001820 *(((__le32 *) frame) + 1) = cpu_to_le32(swheader);
1821 *(((__le32 *) frame) + 2) = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001822
Joe Perches8ae74652012-01-15 00:38:38 -08001823#ifdef DEBUG
Arend van Spriel5b435de2011-10-05 13:19:03 +02001824 tx_packets[pkt->priority]++;
Joe Perches18aad4f2012-01-15 00:38:42 -08001825#endif
Joe Perches1e023822012-01-15 00:38:40 -08001826
1827 brcmf_dbg_hex_dump(BRCMF_BYTES_ON() &&
1828 ((BRCMF_CTL_ON() && chan == SDPCM_CONTROL_CHANNEL) ||
1829 (BRCMF_DATA_ON() && chan != SDPCM_CONTROL_CHANNEL)),
1830 frame, len, "Tx Frame:\n");
1831 brcmf_dbg_hex_dump(!(BRCMF_BYTES_ON() &&
1832 ((BRCMF_CTL_ON() &&
1833 chan == SDPCM_CONTROL_CHANNEL) ||
1834 (BRCMF_DATA_ON() &&
1835 chan != SDPCM_CONTROL_CHANNEL))) &&
1836 BRCMF_HDRS_ON(),
1837 frame, min_t(u16, len, 16), "TxHdr:\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02001838
1839 /* Raise len to next SDIO block to eliminate tail command */
1840 if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
1841 u16 pad = bus->blocksize - (len % bus->blocksize);
1842 if ((pad <= bus->roundup) && (pad < bus->blocksize))
1843 len += pad;
1844 } else if (len % BRCMF_SDALIGN) {
1845 len += BRCMF_SDALIGN - (len % BRCMF_SDALIGN);
1846 }
1847
1848 /* Some controllers have trouble with odd bytes -- round to even */
1849 if (len & (ALIGNMENT - 1))
1850 len = roundup(len, ALIGNMENT);
1851
Franky Lin38b0b0d2012-11-05 16:22:24 -08001852 sdio_claim_host(bus->sdiodev->func[1]);
Arend van Spriel5adfeb62011-11-22 17:21:38 -08001853 ret = brcmf_sdcard_send_pkt(bus->sdiodev, bus->sdiodev->sbwad,
1854 SDIO_FUNC_2, F2SYNC, pkt);
Arend van Spriel80969832012-06-09 22:51:44 +02001855 bus->sdcnt.f2txdata++;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001856
1857 if (ret < 0) {
1858 /* On failure, abort the command and terminate the frame */
1859 brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n",
1860 ret);
Arend van Spriel80969832012-06-09 22:51:44 +02001861 bus->sdcnt.tx_sderrs++;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001862
1863 brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2);
Franky Lin3bba8292012-05-04 18:27:33 -07001864 brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
1865 SFC_WF_TERM, NULL);
Arend van Spriel80969832012-06-09 22:51:44 +02001866 bus->sdcnt.f1regdata++;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001867
1868 for (i = 0; i < 3; i++) {
1869 u8 hi, lo;
Franky Lin45db3392012-05-04 18:27:32 -07001870 hi = brcmf_sdio_regrb(bus->sdiodev,
1871 SBSDIO_FUNC1_WFRAMEBCHI, NULL);
1872 lo = brcmf_sdio_regrb(bus->sdiodev,
1873 SBSDIO_FUNC1_WFRAMEBCLO, NULL);
Arend van Spriel80969832012-06-09 22:51:44 +02001874 bus->sdcnt.f1regdata += 2;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001875 if ((hi == 0) && (lo == 0))
1876 break;
1877 }
1878
1879 }
Franky Lin38b0b0d2012-11-05 16:22:24 -08001880 sdio_release_host(bus->sdiodev->func[1]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001881 if (ret == 0)
1882 bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
1883
1884done:
1885 /* restore pkt buffer pointer before calling tx complete routine */
1886 skb_pull(pkt, SDPCM_HDRLEN + pad);
Arend van Spriela886f7f2013-04-03 12:40:26 +02001887 brcmf_txcomplete(bus->sdiodev->dev, pkt, ret == 0);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001888 return ret;
1889}
1890
Franky Line92eedf2011-11-22 17:21:50 -08001891static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001892{
1893 struct sk_buff *pkt;
1894 u32 intstatus = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02001895 int ret = 0, prec_out;
1896 uint cnt = 0;
1897 uint datalen;
1898 u8 tx_prec_map;
1899
Arend van Spriel5b435de2011-10-05 13:19:03 +02001900 brcmf_dbg(TRACE, "Enter\n");
1901
1902 tx_prec_map = ~bus->flowcontrol;
1903
1904 /* Send frames until the limit or some other event */
1905 for (cnt = 0; (cnt < maxframes) && data_ok(bus); cnt++) {
1906 spin_lock_bh(&bus->txqlock);
1907 pkt = brcmu_pktq_mdeq(&bus->txq, tx_prec_map, &prec_out);
1908 if (pkt == NULL) {
1909 spin_unlock_bh(&bus->txqlock);
1910 break;
1911 }
1912 spin_unlock_bh(&bus->txqlock);
1913 datalen = pkt->len - SDPCM_HDRLEN;
1914
Arend van Spriel7f4bcee2013-03-03 12:45:29 +01001915 ret = brcmf_sdbrcm_txpkt(bus, pkt, SDPCM_DATA_CHANNEL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001916
1917 /* In poll mode, need to check for other events */
1918 if (!bus->intr && cnt) {
1919 /* Check device status, signal pending interrupt */
Franky Lin38b0b0d2012-11-05 16:22:24 -08001920 sdio_claim_host(bus->sdiodev->func[1]);
Franky Lin5c15c232012-05-04 18:27:37 -07001921 ret = r_sdreg32(bus, &intstatus,
1922 offsetof(struct sdpcmd_regs,
1923 intstatus));
Franky Lin38b0b0d2012-11-05 16:22:24 -08001924 sdio_release_host(bus->sdiodev->func[1]);
Arend van Spriel80969832012-06-09 22:51:44 +02001925 bus->sdcnt.f2txdata++;
Franky Lin5c15c232012-05-04 18:27:37 -07001926 if (ret != 0)
Arend van Spriel5b435de2011-10-05 13:19:03 +02001927 break;
1928 if (intstatus & bus->hostintmask)
Franky Lin1d382272012-09-13 21:11:59 +02001929 atomic_set(&bus->ipend, 1);
Arend van Spriel5b435de2011-10-05 13:19:03 +02001930 }
1931 }
1932
1933 /* Deflow-control stack if needed */
Hante Meuleman05dde972013-02-06 18:40:36 +01001934 if ((bus->sdiodev->bus_if->state == BRCMF_BUS_DATA) &&
Franky Linc8bf3482011-12-16 18:37:08 -08001935 bus->txoff && (pktq_len(&bus->txq) < TXLOW)) {
Hante Meuleman90d03ff2012-09-11 21:18:46 +02001936 bus->txoff = false;
1937 brcmf_txflowblock(bus->sdiodev->dev, false);
Franky Linc8bf3482011-12-16 18:37:08 -08001938 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02001939
1940 return cnt;
1941}
1942
Franky Lina9ffda82011-12-16 18:37:12 -08001943static void brcmf_sdbrcm_bus_stop(struct device *dev)
1944{
1945 u32 local_hostintmask;
1946 u8 saveclk;
Franky Lina9ffda82011-12-16 18:37:12 -08001947 int err;
1948 struct brcmf_bus *bus_if = dev_get_drvdata(dev);
Arend van Spriel0a332e42012-02-09 21:09:02 +01001949 struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
Franky Lina9ffda82011-12-16 18:37:12 -08001950 struct brcmf_sdio *bus = sdiodev->bus;
1951
1952 brcmf_dbg(TRACE, "Enter\n");
1953
1954 if (bus->watchdog_tsk) {
1955 send_sig(SIGTERM, bus->watchdog_tsk, 1);
1956 kthread_stop(bus->watchdog_tsk);
1957 bus->watchdog_tsk = NULL;
1958 }
1959
Franky Lin38b0b0d2012-11-05 16:22:24 -08001960 sdio_claim_host(bus->sdiodev->func[1]);
Franky Lina9ffda82011-12-16 18:37:12 -08001961
Franky Lina9ffda82011-12-16 18:37:12 -08001962 /* Enable clock for device interrupts */
1963 brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
1964
1965 /* Disable and clear interrupts at the chip level also */
Franky Lin58692752012-05-04 18:27:36 -07001966 w_sdreg32(bus, 0, offsetof(struct sdpcmd_regs, hostintmask));
Franky Lina9ffda82011-12-16 18:37:12 -08001967 local_hostintmask = bus->hostintmask;
1968 bus->hostintmask = 0;
1969
1970 /* Change our idea of bus state */
1971 bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
1972
1973 /* Force clocks on backplane to be sure F2 interrupt propagates */
Franky Lin45db3392012-05-04 18:27:32 -07001974 saveclk = brcmf_sdio_regrb(bus->sdiodev,
1975 SBSDIO_FUNC1_CHIPCLKCSR, &err);
Franky Lina9ffda82011-12-16 18:37:12 -08001976 if (!err) {
Franky Lin3bba8292012-05-04 18:27:33 -07001977 brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
1978 (saveclk | SBSDIO_FORCE_HT), &err);
Franky Lina9ffda82011-12-16 18:37:12 -08001979 }
1980 if (err)
Arend van Spriel5e8149f2012-12-07 10:49:57 +01001981 brcmf_err("Failed to force clock for F2: err %d\n", err);
Franky Lina9ffda82011-12-16 18:37:12 -08001982
1983 /* Turn off the bus (F2), free any pending packets */
1984 brcmf_dbg(INTR, "disable SDIO interrupts\n");
Franky Lin3bba8292012-05-04 18:27:33 -07001985 brcmf_sdio_regwb(bus->sdiodev, SDIO_CCCR_IOEx, SDIO_FUNC_ENABLE_1,
1986 NULL);
Franky Lina9ffda82011-12-16 18:37:12 -08001987
1988 /* Clear any pending interrupts now that F2 is disabled */
1989 w_sdreg32(bus, local_hostintmask,
Franky Lin58692752012-05-04 18:27:36 -07001990 offsetof(struct sdpcmd_regs, intstatus));
Franky Lina9ffda82011-12-16 18:37:12 -08001991
1992 /* Turn off the backplane clock (only) */
1993 brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false);
Franky Lin38b0b0d2012-11-05 16:22:24 -08001994 sdio_release_host(bus->sdiodev->func[1]);
Franky Lina9ffda82011-12-16 18:37:12 -08001995
1996 /* Clear the data packet queues */
1997 brcmu_pktq_flush(&bus->txq, true, NULL, NULL);
1998
1999 /* Clear any held glomming stuff */
2000 if (bus->glomd)
2001 brcmu_pkt_buf_free_skb(bus->glomd);
2002 brcmf_sdbrcm_free_glom(bus);
2003
2004 /* Clear rx control and wake any waiters */
Franky Lindd43a012012-11-05 16:22:22 -08002005 spin_lock_bh(&bus->rxctl_lock);
Franky Lina9ffda82011-12-16 18:37:12 -08002006 bus->rxlen = 0;
Franky Lindd43a012012-11-05 16:22:22 -08002007 spin_unlock_bh(&bus->rxctl_lock);
Franky Lina9ffda82011-12-16 18:37:12 -08002008 brcmf_sdbrcm_dcmd_resp_wake(bus);
2009
2010 /* Reset some F2 state stuff */
2011 bus->rxskip = false;
2012 bus->tx_seq = bus->rx_seq = 0;
Franky Lina9ffda82011-12-16 18:37:12 -08002013}
2014
Franky Linba89bf12012-04-27 18:56:59 -07002015#ifdef CONFIG_BRCMFMAC_SDIO_OOB
2016static inline void brcmf_sdbrcm_clrintr(struct brcmf_sdio *bus)
2017{
2018 unsigned long flags;
2019
2020 spin_lock_irqsave(&bus->sdiodev->irq_en_lock, flags);
Franky Lin1d382272012-09-13 21:11:59 +02002021 if (!bus->sdiodev->irq_en && !atomic_read(&bus->ipend)) {
Franky Linba89bf12012-04-27 18:56:59 -07002022 enable_irq(bus->sdiodev->irq);
2023 bus->sdiodev->irq_en = true;
2024 }
2025 spin_unlock_irqrestore(&bus->sdiodev->irq_en_lock, flags);
2026}
2027#else
2028static inline void brcmf_sdbrcm_clrintr(struct brcmf_sdio *bus)
2029{
2030}
2031#endif /* CONFIG_BRCMFMAC_SDIO_OOB */
2032
Franky Linf1e68c22012-09-13 21:12:00 +02002033static inline void brcmf_sdbrcm_adddpctsk(struct brcmf_sdio *bus)
2034{
2035 struct list_head *new_hd;
2036 unsigned long flags;
2037
2038 if (in_interrupt())
2039 new_hd = kzalloc(sizeof(struct list_head), GFP_ATOMIC);
2040 else
2041 new_hd = kzalloc(sizeof(struct list_head), GFP_KERNEL);
2042 if (new_hd == NULL)
2043 return;
2044
2045 spin_lock_irqsave(&bus->dpc_tl_lock, flags);
2046 list_add_tail(new_hd, &bus->dpc_tsklst);
2047 spin_unlock_irqrestore(&bus->dpc_tl_lock, flags);
2048}
2049
Franky Lin45316032012-09-13 21:12:03 +02002050static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus)
2051{
2052 u8 idx;
2053 u32 addr;
2054 unsigned long val;
2055 int n, ret;
2056
2057 idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV);
2058 addr = bus->ci->c_inf[idx].base +
2059 offsetof(struct sdpcmd_regs, intstatus);
2060
2061 ret = brcmf_sdio_regrw_helper(bus->sdiodev, addr, &val, false);
2062 bus->sdcnt.f1regdata++;
2063 if (ret != 0)
2064 val = 0;
2065
2066 val &= bus->hostintmask;
2067 atomic_set(&bus->fcstate, !!(val & I_HMB_FC_STATE));
2068
2069 /* Clear interrupts */
2070 if (val) {
2071 ret = brcmf_sdio_regrw_helper(bus->sdiodev, addr, &val, true);
2072 bus->sdcnt.f1regdata++;
2073 }
2074
2075 if (ret) {
2076 atomic_set(&bus->intstatus, 0);
2077 } else if (val) {
2078 for_each_set_bit(n, &val, 32)
2079 set_bit(n, (unsigned long *)&bus->intstatus.counter);
2080 }
2081
2082 return ret;
2083}
2084
Franky Linf1e68c22012-09-13 21:12:00 +02002085static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002086{
Franky Lin45316032012-09-13 21:12:03 +02002087 u32 newstatus = 0;
2088 unsigned long intstatus;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002089 uint rxlimit = bus->rxbound; /* Rx frames to read before resched */
2090 uint txlimit = bus->txbound; /* Tx frames to send before resched */
2091 uint framecnt = 0; /* Temporary counter of tx/rx frames */
Franky Lin45316032012-09-13 21:12:03 +02002092 int err = 0, n;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002093
2094 brcmf_dbg(TRACE, "Enter\n");
2095
Franky Lin38b0b0d2012-11-05 16:22:24 -08002096 sdio_claim_host(bus->sdiodev->func[1]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002097
2098 /* If waiting for HTAVAIL, check status */
2099 if (bus->clkstate == CLK_PENDING) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002100 u8 clkctl, devctl = 0;
2101
Joe Perches8ae74652012-01-15 00:38:38 -08002102#ifdef DEBUG
Arend van Spriel5b435de2011-10-05 13:19:03 +02002103 /* Check for inconsistent device control */
Franky Lin45db3392012-05-04 18:27:32 -07002104 devctl = brcmf_sdio_regrb(bus->sdiodev,
2105 SBSDIO_DEVICE_CTL, &err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002106 if (err) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01002107 brcmf_err("error reading DEVCTL: %d\n", err);
Franky Lin712ac5b2011-12-16 18:37:09 -08002108 bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002109 }
Joe Perches8ae74652012-01-15 00:38:38 -08002110#endif /* DEBUG */
Arend van Spriel5b435de2011-10-05 13:19:03 +02002111
2112 /* Read CSR, if clock on switch to AVAIL, else ignore */
Franky Lin45db3392012-05-04 18:27:32 -07002113 clkctl = brcmf_sdio_regrb(bus->sdiodev,
2114 SBSDIO_FUNC1_CHIPCLKCSR, &err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002115 if (err) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01002116 brcmf_err("error reading CSR: %d\n",
Arend van Spriel5b435de2011-10-05 13:19:03 +02002117 err);
Franky Lin712ac5b2011-12-16 18:37:09 -08002118 bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002119 }
2120
Arend van Sprielc3203372013-04-03 12:40:44 +02002121 brcmf_dbg(SDIO, "DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n",
Arend van Spriel5b435de2011-10-05 13:19:03 +02002122 devctl, clkctl);
2123
2124 if (SBSDIO_HTAV(clkctl)) {
Franky Lin45db3392012-05-04 18:27:32 -07002125 devctl = brcmf_sdio_regrb(bus->sdiodev,
2126 SBSDIO_DEVICE_CTL, &err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002127 if (err) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01002128 brcmf_err("error reading DEVCTL: %d\n",
Arend van Spriel5b435de2011-10-05 13:19:03 +02002129 err);
Franky Lin712ac5b2011-12-16 18:37:09 -08002130 bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002131 }
2132 devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
Franky Lin3bba8292012-05-04 18:27:33 -07002133 brcmf_sdio_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL,
2134 devctl, &err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002135 if (err) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01002136 brcmf_err("error writing DEVCTL: %d\n",
Arend van Spriel5b435de2011-10-05 13:19:03 +02002137 err);
Franky Lin712ac5b2011-12-16 18:37:09 -08002138 bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002139 }
2140 bus->clkstate = CLK_AVAIL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002141 }
2142 }
2143
Arend van Spriel5b435de2011-10-05 13:19:03 +02002144 /* Make sure backplane clock is on */
2145 brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, true);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002146
2147 /* Pending interrupt indicates new device status */
Franky Lin1d382272012-09-13 21:11:59 +02002148 if (atomic_read(&bus->ipend) > 0) {
2149 atomic_set(&bus->ipend, 0);
Franky Lin45316032012-09-13 21:12:03 +02002150 err = brcmf_sdio_intr_rstatus(bus);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002151 }
2152
Franky Lin45316032012-09-13 21:12:03 +02002153 /* Start with leftover status bits */
2154 intstatus = atomic_xchg(&bus->intstatus, 0);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002155
2156 /* Handle flow-control change: read new state in case our ack
2157 * crossed another change interrupt. If change still set, assume
2158 * FC ON for safety, let next loop through do the debounce.
2159 */
2160 if (intstatus & I_HMB_FC_CHANGE) {
2161 intstatus &= ~I_HMB_FC_CHANGE;
Franky Lin5c15c232012-05-04 18:27:37 -07002162 err = w_sdreg32(bus, I_HMB_FC_CHANGE,
2163 offsetof(struct sdpcmd_regs, intstatus));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002164
Franky Lin5c15c232012-05-04 18:27:37 -07002165 err = r_sdreg32(bus, &newstatus,
2166 offsetof(struct sdpcmd_regs, intstatus));
Arend van Spriel80969832012-06-09 22:51:44 +02002167 bus->sdcnt.f1regdata += 2;
Franky Lin45316032012-09-13 21:12:03 +02002168 atomic_set(&bus->fcstate,
2169 !!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE)));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002170 intstatus |= (newstatus & bus->hostintmask);
2171 }
2172
2173 /* Handle host mailbox indication */
2174 if (intstatus & I_HMB_HOST_INT) {
2175 intstatus &= ~I_HMB_HOST_INT;
2176 intstatus |= brcmf_sdbrcm_hostmail(bus);
2177 }
2178
Franky Lin38b0b0d2012-11-05 16:22:24 -08002179 sdio_release_host(bus->sdiodev->func[1]);
Franky Lin7cdf57d2012-11-05 16:22:23 -08002180
Arend van Spriel5b435de2011-10-05 13:19:03 +02002181 /* Generally don't ask for these, can get CRC errors... */
2182 if (intstatus & I_WR_OOSYNC) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01002183 brcmf_err("Dongle reports WR_OOSYNC\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002184 intstatus &= ~I_WR_OOSYNC;
2185 }
2186
2187 if (intstatus & I_RD_OOSYNC) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01002188 brcmf_err("Dongle reports RD_OOSYNC\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002189 intstatus &= ~I_RD_OOSYNC;
2190 }
2191
2192 if (intstatus & I_SBINT) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01002193 brcmf_err("Dongle reports SBINT\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002194 intstatus &= ~I_SBINT;
2195 }
2196
2197 /* Would be active due to wake-wlan in gSPI */
2198 if (intstatus & I_CHIPACTIVE) {
2199 brcmf_dbg(INFO, "Dongle reports CHIPACTIVE\n");
2200 intstatus &= ~I_CHIPACTIVE;
2201 }
2202
2203 /* Ignore frame indications if rxskip is set */
2204 if (bus->rxskip)
2205 intstatus &= ~I_HMB_FRAME_IND;
2206
2207 /* On frame indication, read available frames */
Franky Lin03d5c362012-09-13 21:12:01 +02002208 if (PKT_AVAILABLE() && bus->clkstate == CLK_AVAIL) {
Franky Lin4754fce2012-09-19 22:21:11 +02002209 framecnt = brcmf_sdio_readframes(bus, rxlimit);
2210 if (!bus->rxpending)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002211 intstatus &= ~I_HMB_FRAME_IND;
2212 rxlimit -= min(framecnt, rxlimit);
2213 }
2214
2215 /* Keep still-pending events for next scheduling */
Franky Lin45316032012-09-13 21:12:03 +02002216 if (intstatus) {
2217 for_each_set_bit(n, &intstatus, 32)
2218 set_bit(n, (unsigned long *)&bus->intstatus.counter);
2219 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002220
Franky Linba89bf12012-04-27 18:56:59 -07002221 brcmf_sdbrcm_clrintr(bus);
2222
Arend van Spriel5b435de2011-10-05 13:19:03 +02002223 if (data_ok(bus) && bus->ctrl_frame_stat &&
2224 (bus->clkstate == CLK_AVAIL)) {
Franky Lin03d5c362012-09-13 21:12:01 +02002225 int i;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002226
Franky Lin38b0b0d2012-11-05 16:22:24 -08002227 sdio_claim_host(bus->sdiodev->func[1]);
Franky Lin03d5c362012-09-13 21:12:01 +02002228 err = brcmf_sdcard_send_buf(bus->sdiodev, bus->sdiodev->sbwad,
Joe Perches2c208892012-06-04 12:44:17 +00002229 SDIO_FUNC_2, F2SYNC, bus->ctrl_frame_buf,
Arend van Spriel5adfeb62011-11-22 17:21:38 -08002230 (u32) bus->ctrl_frame_len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002231
Franky Lin03d5c362012-09-13 21:12:01 +02002232 if (err < 0) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002233 /* On failure, abort the command and
2234 terminate the frame */
2235 brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n",
Franky Lin03d5c362012-09-13 21:12:01 +02002236 err);
Arend van Spriel80969832012-06-09 22:51:44 +02002237 bus->sdcnt.tx_sderrs++;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002238
2239 brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2);
2240
Franky Lin3bba8292012-05-04 18:27:33 -07002241 brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
Franky Lin5c15c232012-05-04 18:27:37 -07002242 SFC_WF_TERM, &err);
Arend van Spriel80969832012-06-09 22:51:44 +02002243 bus->sdcnt.f1regdata++;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002244
2245 for (i = 0; i < 3; i++) {
2246 u8 hi, lo;
Franky Lin45db3392012-05-04 18:27:32 -07002247 hi = brcmf_sdio_regrb(bus->sdiodev,
2248 SBSDIO_FUNC1_WFRAMEBCHI,
Franky Lin5c15c232012-05-04 18:27:37 -07002249 &err);
Franky Lin45db3392012-05-04 18:27:32 -07002250 lo = brcmf_sdio_regrb(bus->sdiodev,
2251 SBSDIO_FUNC1_WFRAMEBCLO,
Franky Lin5c15c232012-05-04 18:27:37 -07002252 &err);
Arend van Spriel80969832012-06-09 22:51:44 +02002253 bus->sdcnt.f1regdata += 2;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002254 if ((hi == 0) && (lo == 0))
2255 break;
2256 }
2257
Franky Lin03d5c362012-09-13 21:12:01 +02002258 } else {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002259 bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
Franky Lin03d5c362012-09-13 21:12:01 +02002260 }
Franky Lin38b0b0d2012-11-05 16:22:24 -08002261 sdio_release_host(bus->sdiodev->func[1]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002262 bus->ctrl_frame_stat = false;
2263 brcmf_sdbrcm_wait_event_wakeup(bus);
2264 }
2265 /* Send queued frames (limit 1 if rx may still be pending) */
Franky Lin45316032012-09-13 21:12:03 +02002266 else if ((bus->clkstate == CLK_AVAIL) && !atomic_read(&bus->fcstate) &&
Arend van Spriel5b435de2011-10-05 13:19:03 +02002267 brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit
2268 && data_ok(bus)) {
Franky Lin4754fce2012-09-19 22:21:11 +02002269 framecnt = bus->rxpending ? min(txlimit, bus->txminmax) :
2270 txlimit;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002271 framecnt = brcmf_sdbrcm_sendfromq(bus, framecnt);
2272 txlimit -= framecnt;
2273 }
2274
Franky Lin5c15c232012-05-04 18:27:37 -07002275 if ((bus->sdiodev->bus_if->state == BRCMF_BUS_DOWN) || (err != 0)) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01002276 brcmf_err("failed backplane access over SDIO, halting operation\n");
Franky Lin712ac5b2011-12-16 18:37:09 -08002277 bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
Franky Lin45316032012-09-13 21:12:03 +02002278 atomic_set(&bus->intstatus, 0);
2279 } else if (atomic_read(&bus->intstatus) ||
2280 atomic_read(&bus->ipend) > 0 ||
2281 (!atomic_read(&bus->fcstate) &&
2282 brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) &&
2283 data_ok(bus)) || PKT_AVAILABLE()) {
Franky Linf1e68c22012-09-13 21:12:00 +02002284 brcmf_sdbrcm_adddpctsk(bus);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002285 }
2286
Arend van Spriel5b435de2011-10-05 13:19:03 +02002287 /* If we're done for now, turn off clock request. */
2288 if ((bus->clkstate != CLK_PENDING)
2289 && bus->idletime == BRCMF_IDLE_IMMEDIATE) {
2290 bus->activity = false;
Franky Lin38b0b0d2012-11-05 16:22:24 -08002291 sdio_claim_host(bus->sdiodev->func[1]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002292 brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
Franky Lin38b0b0d2012-11-05 16:22:24 -08002293 sdio_release_host(bus->sdiodev->func[1]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002294 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002295}
2296
Arend van Spriele2432b62013-04-03 12:40:38 +02002297static struct pktq *brcmf_sdbrcm_bus_gettxq(struct device *dev)
2298{
2299 struct brcmf_bus *bus_if = dev_get_drvdata(dev);
2300 struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
2301 struct brcmf_sdio *bus = sdiodev->bus;
2302
2303 return &bus->txq;
2304}
2305
Franky Linb9692d12011-12-16 18:37:15 -08002306static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002307{
2308 int ret = -EBADE;
2309 uint datalen, prec;
Franky Linbf347bb2011-11-22 17:21:56 -08002310 struct brcmf_bus *bus_if = dev_get_drvdata(dev);
Arend van Spriel0a332e42012-02-09 21:09:02 +01002311 struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
Franky Linbf347bb2011-11-22 17:21:56 -08002312 struct brcmf_sdio *bus = sdiodev->bus;
Franky Linf1e68c22012-09-13 21:12:00 +02002313 unsigned long flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002314
2315 brcmf_dbg(TRACE, "Enter\n");
2316
2317 datalen = pkt->len;
2318
2319 /* Add space for the header */
2320 skb_push(pkt, SDPCM_HDRLEN);
2321 /* precondition: IS_ALIGNED((unsigned long)(pkt->data), 2) */
2322
2323 prec = prio2prec((pkt->priority & PRIOMASK));
2324
2325 /* Check for existing queue, current flow-control,
2326 pending event, or pending clock */
2327 brcmf_dbg(TRACE, "deferring pktq len %d\n", pktq_len(&bus->txq));
Arend van Spriel80969832012-06-09 22:51:44 +02002328 bus->sdcnt.fcqueued++;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002329
2330 /* Priority based enq */
2331 spin_lock_bh(&bus->txqlock);
Joe Perches23677ce2012-02-09 11:17:23 +00002332 if (!brcmf_c_prec_enq(bus->sdiodev->dev, &bus->txq, pkt, prec)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02002333 skb_pull(pkt, SDPCM_HDRLEN);
Franky Linc9957882011-12-16 18:36:58 -08002334 brcmf_txcomplete(bus->sdiodev->dev, pkt, false);
Arend van Spriel5e8149f2012-12-07 10:49:57 +01002335 brcmf_err("out of bus->txq !!!\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002336 ret = -ENOSR;
2337 } else {
2338 ret = 0;
2339 }
2340 spin_unlock_bh(&bus->txqlock);
2341
Franky Linc8bf3482011-12-16 18:37:08 -08002342 if (pktq_len(&bus->txq) >= TXHI) {
Hante Meuleman90d03ff2012-09-11 21:18:46 +02002343 bus->txoff = true;
2344 brcmf_txflowblock(bus->sdiodev->dev, true);
Franky Linc8bf3482011-12-16 18:37:08 -08002345 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02002346
Joe Perches8ae74652012-01-15 00:38:38 -08002347#ifdef DEBUG
Arend van Spriel5b435de2011-10-05 13:19:03 +02002348 if (pktq_plen(&bus->txq, prec) > qcount[prec])
2349 qcount[prec] = pktq_plen(&bus->txq, prec);
2350#endif
Franky Linf1e68c22012-09-13 21:12:00 +02002351
2352 spin_lock_irqsave(&bus->dpc_tl_lock, flags);
2353 if (list_empty(&bus->dpc_tsklst)) {
2354 spin_unlock_irqrestore(&bus->dpc_tl_lock, flags);
2355
2356 brcmf_sdbrcm_adddpctsk(bus);
2357 queue_work(bus->brcmf_wq, &bus->datawork);
2358 } else {
2359 spin_unlock_irqrestore(&bus->dpc_tl_lock, flags);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002360 }
2361
2362 return ret;
2363}
2364
2365static int
Franky Line92eedf2011-11-22 17:21:50 -08002366brcmf_sdbrcm_membytes(struct brcmf_sdio *bus, bool write, u32 address, u8 *data,
Arend van Spriel5b435de2011-10-05 13:19:03 +02002367 uint size)
2368{
2369 int bcmerror = 0;
2370 u32 sdaddr;
2371 uint dsize;
2372
2373 /* Determine initial transfer parameters */
2374 sdaddr = address & SBSDIO_SB_OFT_ADDR_MASK;
2375 if ((sdaddr + size) & SBSDIO_SBWINDOW_MASK)
2376 dsize = (SBSDIO_SB_OFT_ADDR_LIMIT - sdaddr);
2377 else
2378 dsize = size;
2379
Franky Lin7057fd02012-09-13 21:12:02 +02002380 sdio_claim_host(bus->sdiodev->func[1]);
2381
Arend van Spriel5b435de2011-10-05 13:19:03 +02002382 /* Set the backplane window to include the start address */
2383 bcmerror = brcmf_sdcard_set_sbaddr_window(bus->sdiodev, address);
2384 if (bcmerror) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01002385 brcmf_err("window change failed\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002386 goto xfer_done;
2387 }
2388
2389 /* Do the transfer(s) */
2390 while (size) {
Arend van Sprielc3203372013-04-03 12:40:44 +02002391 brcmf_dbg(SDIO, "%s %d bytes at offset 0x%08x in window 0x%08x\n",
Arend van Spriel5b435de2011-10-05 13:19:03 +02002392 write ? "write" : "read", dsize,
2393 sdaddr, address & SBSDIO_SBWINDOW_MASK);
2394 bcmerror = brcmf_sdcard_rwdata(bus->sdiodev, write,
2395 sdaddr, data, dsize);
2396 if (bcmerror) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01002397 brcmf_err("membytes transfer failed\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002398 break;
2399 }
2400
2401 /* Adjust for next transfer (if any) */
2402 size -= dsize;
2403 if (size) {
2404 data += dsize;
2405 address += dsize;
2406 bcmerror = brcmf_sdcard_set_sbaddr_window(bus->sdiodev,
2407 address);
2408 if (bcmerror) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01002409 brcmf_err("window change failed\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002410 break;
2411 }
2412 sdaddr = 0;
2413 dsize = min_t(uint, SBSDIO_SB_OFT_ADDR_LIMIT, size);
2414 }
2415 }
2416
2417xfer_done:
2418 /* Return the window to backplane enumeration space for core access */
2419 if (brcmf_sdcard_set_sbaddr_window(bus->sdiodev, bus->sdiodev->sbwad))
Arend van Spriel5e8149f2012-12-07 10:49:57 +01002420 brcmf_err("FAILED to set window back to 0x%x\n",
Arend van Spriel5b435de2011-10-05 13:19:03 +02002421 bus->sdiodev->sbwad);
2422
Franky Lin7057fd02012-09-13 21:12:02 +02002423 sdio_release_host(bus->sdiodev->func[1]);
2424
Arend van Spriel5b435de2011-10-05 13:19:03 +02002425 return bcmerror;
2426}
2427
Joe Perches8ae74652012-01-15 00:38:38 -08002428#ifdef DEBUG
Arend van Spriel5b435de2011-10-05 13:19:03 +02002429#define CONSOLE_LINE_MAX 192
2430
Franky Line92eedf2011-11-22 17:21:50 -08002431static int brcmf_sdbrcm_readconsole(struct brcmf_sdio *bus)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002432{
2433 struct brcmf_console *c = &bus->console;
2434 u8 line[CONSOLE_LINE_MAX], ch;
2435 u32 n, idx, addr;
2436 int rv;
2437
2438 /* Don't do anything until FWREADY updates console address */
2439 if (bus->console_addr == 0)
2440 return 0;
2441
2442 /* Read console log struct */
2443 addr = bus->console_addr + offsetof(struct rte_console, log_le);
2444 rv = brcmf_sdbrcm_membytes(bus, false, addr, (u8 *)&c->log_le,
2445 sizeof(c->log_le));
2446 if (rv < 0)
2447 return rv;
2448
2449 /* Allocate console buffer (one time only) */
2450 if (c->buf == NULL) {
2451 c->bufsize = le32_to_cpu(c->log_le.buf_size);
2452 c->buf = kmalloc(c->bufsize, GFP_ATOMIC);
2453 if (c->buf == NULL)
2454 return -ENOMEM;
2455 }
2456
2457 idx = le32_to_cpu(c->log_le.idx);
2458
2459 /* Protect against corrupt value */
2460 if (idx > c->bufsize)
2461 return -EBADE;
2462
2463 /* Skip reading the console buffer if the index pointer
2464 has not moved */
2465 if (idx == c->last)
2466 return 0;
2467
2468 /* Read the console buffer */
2469 addr = le32_to_cpu(c->log_le.buf);
2470 rv = brcmf_sdbrcm_membytes(bus, false, addr, c->buf, c->bufsize);
2471 if (rv < 0)
2472 return rv;
2473
2474 while (c->last != idx) {
2475 for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) {
2476 if (c->last == idx) {
2477 /* This would output a partial line.
2478 * Instead, back up
2479 * the buffer pointer and output this
2480 * line next time around.
2481 */
2482 if (c->last >= n)
2483 c->last -= n;
2484 else
2485 c->last = c->bufsize - n;
2486 goto break2;
2487 }
2488 ch = c->buf[c->last];
2489 c->last = (c->last + 1) % c->bufsize;
2490 if (ch == '\n')
2491 break;
2492 line[n] = ch;
2493 }
2494
2495 if (n > 0) {
2496 if (line[n - 1] == '\r')
2497 n--;
2498 line[n] = 0;
Joe Perches18aad4f2012-01-15 00:38:42 -08002499 pr_debug("CONSOLE: %s\n", line);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002500 }
2501 }
2502break2:
2503
2504 return 0;
2505}
Joe Perches8ae74652012-01-15 00:38:38 -08002506#endif /* DEBUG */
Arend van Spriel5b435de2011-10-05 13:19:03 +02002507
Franky Line92eedf2011-11-22 17:21:50 -08002508static int brcmf_tx_frame(struct brcmf_sdio *bus, u8 *frame, u16 len)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002509{
2510 int i;
2511 int ret;
2512
2513 bus->ctrl_frame_stat = false;
Arend van Spriel5adfeb62011-11-22 17:21:38 -08002514 ret = brcmf_sdcard_send_buf(bus->sdiodev, bus->sdiodev->sbwad,
2515 SDIO_FUNC_2, F2SYNC, frame, len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002516
2517 if (ret < 0) {
2518 /* On failure, abort the command and terminate the frame */
2519 brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n",
2520 ret);
Arend van Spriel80969832012-06-09 22:51:44 +02002521 bus->sdcnt.tx_sderrs++;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002522
2523 brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2);
2524
Franky Lin3bba8292012-05-04 18:27:33 -07002525 brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
2526 SFC_WF_TERM, NULL);
Arend van Spriel80969832012-06-09 22:51:44 +02002527 bus->sdcnt.f1regdata++;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002528
2529 for (i = 0; i < 3; i++) {
2530 u8 hi, lo;
Franky Lin45db3392012-05-04 18:27:32 -07002531 hi = brcmf_sdio_regrb(bus->sdiodev,
2532 SBSDIO_FUNC1_WFRAMEBCHI, NULL);
2533 lo = brcmf_sdio_regrb(bus->sdiodev,
2534 SBSDIO_FUNC1_WFRAMEBCLO, NULL);
Arend van Spriel80969832012-06-09 22:51:44 +02002535 bus->sdcnt.f1regdata += 2;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002536 if (hi == 0 && lo == 0)
2537 break;
2538 }
2539 return ret;
2540 }
2541
2542 bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
2543
2544 return ret;
2545}
2546
Franky Linfcf094f2011-12-16 18:37:16 -08002547static int
Franky Lin47a1ce72011-11-22 17:21:55 -08002548brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002549{
2550 u8 *frame;
2551 u16 len;
2552 u32 swheader;
2553 uint retries = 0;
2554 u8 doff = 0;
2555 int ret = -1;
Franky Lin47a1ce72011-11-22 17:21:55 -08002556 struct brcmf_bus *bus_if = dev_get_drvdata(dev);
Arend van Spriel0a332e42012-02-09 21:09:02 +01002557 struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
Franky Lin47a1ce72011-11-22 17:21:55 -08002558 struct brcmf_sdio *bus = sdiodev->bus;
Franky Linf1e68c22012-09-13 21:12:00 +02002559 unsigned long flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002560
2561 brcmf_dbg(TRACE, "Enter\n");
2562
2563 /* Back the pointer to make a room for bus header */
2564 frame = msg - SDPCM_HDRLEN;
2565 len = (msglen += SDPCM_HDRLEN);
2566
2567 /* Add alignment padding (optional for ctl frames) */
2568 doff = ((unsigned long)frame % BRCMF_SDALIGN);
2569 if (doff) {
2570 frame -= doff;
2571 len += doff;
2572 msglen += doff;
2573 memset(frame, 0, doff + SDPCM_HDRLEN);
2574 }
2575 /* precondition: doff < BRCMF_SDALIGN */
2576 doff += SDPCM_HDRLEN;
2577
2578 /* Round send length to next SDIO block */
2579 if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
2580 u16 pad = bus->blocksize - (len % bus->blocksize);
2581 if ((pad <= bus->roundup) && (pad < bus->blocksize))
2582 len += pad;
2583 } else if (len % BRCMF_SDALIGN) {
2584 len += BRCMF_SDALIGN - (len % BRCMF_SDALIGN);
2585 }
2586
2587 /* Satisfy length-alignment requirements */
2588 if (len & (ALIGNMENT - 1))
2589 len = roundup(len, ALIGNMENT);
2590
2591 /* precondition: IS_ALIGNED((unsigned long)frame, 2) */
2592
Arend van Spriel5b435de2011-10-05 13:19:03 +02002593 /* Make sure backplane clock is on */
Franky Lin38b0b0d2012-11-05 16:22:24 -08002594 sdio_claim_host(bus->sdiodev->func[1]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002595 brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
Franky Lin38b0b0d2012-11-05 16:22:24 -08002596 sdio_release_host(bus->sdiodev->func[1]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002597
2598 /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
2599 *(__le16 *) frame = cpu_to_le16((u16) msglen);
2600 *(((__le16 *) frame) + 1) = cpu_to_le16(~msglen);
2601
2602 /* Software tag: channel, sequence number, data offset */
2603 swheader =
2604 ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) &
2605 SDPCM_CHANNEL_MASK)
2606 | bus->tx_seq | ((doff << SDPCM_DOFFSET_SHIFT) &
2607 SDPCM_DOFFSET_MASK);
2608 put_unaligned_le32(swheader, frame + SDPCM_FRAMETAG_LEN);
2609 put_unaligned_le32(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
2610
2611 if (!data_ok(bus)) {
2612 brcmf_dbg(INFO, "No bus credit bus->tx_max %d, bus->tx_seq %d\n",
2613 bus->tx_max, bus->tx_seq);
2614 bus->ctrl_frame_stat = true;
2615 /* Send from dpc */
2616 bus->ctrl_frame_buf = frame;
2617 bus->ctrl_frame_len = len;
2618
Franky Linfd67dc82012-11-05 16:22:25 -08002619 wait_event_interruptible_timeout(bus->ctrl_wait,
2620 !bus->ctrl_frame_stat,
2621 msecs_to_jiffies(2000));
Arend van Spriel5b435de2011-10-05 13:19:03 +02002622
Joe Perches23677ce2012-02-09 11:17:23 +00002623 if (!bus->ctrl_frame_stat) {
Arend van Sprielc3203372013-04-03 12:40:44 +02002624 brcmf_dbg(SDIO, "ctrl_frame_stat == false\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002625 ret = 0;
2626 } else {
Arend van Sprielc3203372013-04-03 12:40:44 +02002627 brcmf_dbg(SDIO, "ctrl_frame_stat == true\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002628 ret = -1;
2629 }
2630 }
2631
2632 if (ret == -1) {
Joe Perches1e023822012-01-15 00:38:40 -08002633 brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && BRCMF_CTL_ON(),
2634 frame, len, "Tx Frame:\n");
2635 brcmf_dbg_hex_dump(!(BRCMF_BYTES_ON() && BRCMF_CTL_ON()) &&
2636 BRCMF_HDRS_ON(),
2637 frame, min_t(u16, len, 16), "TxHdr:\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02002638
2639 do {
Franky Lin38b0b0d2012-11-05 16:22:24 -08002640 sdio_claim_host(bus->sdiodev->func[1]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002641 ret = brcmf_tx_frame(bus, frame, len);
Franky Lin38b0b0d2012-11-05 16:22:24 -08002642 sdio_release_host(bus->sdiodev->func[1]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002643 } while (ret < 0 && retries++ < TXRETRIES);
2644 }
2645
Franky Linf1e68c22012-09-13 21:12:00 +02002646 spin_lock_irqsave(&bus->dpc_tl_lock, flags);
2647 if ((bus->idletime == BRCMF_IDLE_IMMEDIATE) &&
2648 list_empty(&bus->dpc_tsklst)) {
2649 spin_unlock_irqrestore(&bus->dpc_tl_lock, flags);
2650
Arend van Spriel5b435de2011-10-05 13:19:03 +02002651 bus->activity = false;
Franky Lin38b0b0d2012-11-05 16:22:24 -08002652 sdio_claim_host(bus->sdiodev->func[1]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002653 brcmf_sdbrcm_clkctl(bus, CLK_NONE, true);
Franky Lin38b0b0d2012-11-05 16:22:24 -08002654 sdio_release_host(bus->sdiodev->func[1]);
Franky Linf1e68c22012-09-13 21:12:00 +02002655 } else {
2656 spin_unlock_irqrestore(&bus->dpc_tl_lock, flags);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002657 }
2658
Arend van Spriel5b435de2011-10-05 13:19:03 +02002659 if (ret)
Arend van Spriel80969832012-06-09 22:51:44 +02002660 bus->sdcnt.tx_ctlerrs++;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002661 else
Arend van Spriel80969832012-06-09 22:51:44 +02002662 bus->sdcnt.tx_ctlpkts++;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002663
2664 return ret ? -EIO : 0;
2665}
2666
Arend van Spriel80969832012-06-09 22:51:44 +02002667#ifdef DEBUG
Arend van Spriel4fc0d012012-06-14 12:16:57 +02002668static inline bool brcmf_sdio_valid_shared_address(u32 addr)
2669{
2670 return !(addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff));
2671}
2672
2673static int brcmf_sdio_readshared(struct brcmf_sdio *bus,
2674 struct sdpcm_shared *sh)
2675{
2676 u32 addr;
2677 int rv;
2678 u32 shaddr = 0;
2679 struct sdpcm_shared_le sh_le;
2680 __le32 addr_le;
2681
2682 shaddr = bus->ramsize - 4;
2683
2684 /*
2685 * Read last word in socram to determine
2686 * address of sdpcm_shared structure
2687 */
Franky Lin38b0b0d2012-11-05 16:22:24 -08002688 sdio_claim_host(bus->sdiodev->func[1]);
Piotr Haberbd16e352013-02-08 12:06:34 +01002689 brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
Arend van Spriel4fc0d012012-06-14 12:16:57 +02002690 rv = brcmf_sdbrcm_membytes(bus, false, shaddr,
2691 (u8 *)&addr_le, 4);
Piotr Haberb55de972013-02-08 12:06:33 +01002692 sdio_release_host(bus->sdiodev->func[1]);
Arend van Spriel4fc0d012012-06-14 12:16:57 +02002693 if (rv < 0)
2694 return rv;
2695
2696 addr = le32_to_cpu(addr_le);
2697
Arend van Sprielc3203372013-04-03 12:40:44 +02002698 brcmf_dbg(SDIO, "sdpcm_shared address 0x%08X\n", addr);
Arend van Spriel4fc0d012012-06-14 12:16:57 +02002699
2700 /*
2701 * Check if addr is valid.
2702 * NVRAM length at the end of memory should have been overwritten.
2703 */
2704 if (!brcmf_sdio_valid_shared_address(addr)) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01002705 brcmf_err("invalid sdpcm_shared address 0x%08X\n",
Arend van Spriel4fc0d012012-06-14 12:16:57 +02002706 addr);
2707 return -EINVAL;
2708 }
2709
2710 /* Read hndrte_shared structure */
2711 rv = brcmf_sdbrcm_membytes(bus, false, addr, (u8 *)&sh_le,
2712 sizeof(struct sdpcm_shared_le));
2713 if (rv < 0)
2714 return rv;
2715
2716 /* Endianness */
2717 sh->flags = le32_to_cpu(sh_le.flags);
2718 sh->trap_addr = le32_to_cpu(sh_le.trap_addr);
2719 sh->assert_exp_addr = le32_to_cpu(sh_le.assert_exp_addr);
2720 sh->assert_file_addr = le32_to_cpu(sh_le.assert_file_addr);
2721 sh->assert_line = le32_to_cpu(sh_le.assert_line);
2722 sh->console_addr = le32_to_cpu(sh_le.console_addr);
2723 sh->msgtrace_addr = le32_to_cpu(sh_le.msgtrace_addr);
2724
Piotr Haber86dcd932013-04-05 10:57:43 +02002725 if ((sh->flags & SDPCM_SHARED_VERSION_MASK) > SDPCM_SHARED_VERSION) {
2726 brcmf_err("sdpcm shared version unsupported: dhd %d dongle %d\n",
Arend van Spriel4fc0d012012-06-14 12:16:57 +02002727 SDPCM_SHARED_VERSION,
2728 sh->flags & SDPCM_SHARED_VERSION_MASK);
2729 return -EPROTO;
2730 }
2731
2732 return 0;
2733}
2734
2735static int brcmf_sdio_dump_console(struct brcmf_sdio *bus,
2736 struct sdpcm_shared *sh, char __user *data,
2737 size_t count)
2738{
2739 u32 addr, console_ptr, console_size, console_index;
2740 char *conbuf = NULL;
2741 __le32 sh_val;
2742 int rv;
2743 loff_t pos = 0;
2744 int nbytes = 0;
2745
2746 /* obtain console information from device memory */
2747 addr = sh->console_addr + offsetof(struct rte_console, log_le);
2748 rv = brcmf_sdbrcm_membytes(bus, false, addr,
2749 (u8 *)&sh_val, sizeof(u32));
2750 if (rv < 0)
2751 return rv;
2752 console_ptr = le32_to_cpu(sh_val);
2753
2754 addr = sh->console_addr + offsetof(struct rte_console, log_le.buf_size);
2755 rv = brcmf_sdbrcm_membytes(bus, false, addr,
2756 (u8 *)&sh_val, sizeof(u32));
2757 if (rv < 0)
2758 return rv;
2759 console_size = le32_to_cpu(sh_val);
2760
2761 addr = sh->console_addr + offsetof(struct rte_console, log_le.idx);
2762 rv = brcmf_sdbrcm_membytes(bus, false, addr,
2763 (u8 *)&sh_val, sizeof(u32));
2764 if (rv < 0)
2765 return rv;
2766 console_index = le32_to_cpu(sh_val);
2767
2768 /* allocate buffer for console data */
2769 if (console_size <= CONSOLE_BUFFER_MAX)
2770 conbuf = vzalloc(console_size+1);
2771
2772 if (!conbuf)
2773 return -ENOMEM;
2774
2775 /* obtain the console data from device */
2776 conbuf[console_size] = '\0';
2777 rv = brcmf_sdbrcm_membytes(bus, false, console_ptr, (u8 *)conbuf,
2778 console_size);
2779 if (rv < 0)
2780 goto done;
2781
2782 rv = simple_read_from_buffer(data, count, &pos,
2783 conbuf + console_index,
2784 console_size - console_index);
2785 if (rv < 0)
2786 goto done;
2787
2788 nbytes = rv;
2789 if (console_index > 0) {
2790 pos = 0;
2791 rv = simple_read_from_buffer(data+nbytes, count, &pos,
2792 conbuf, console_index - 1);
2793 if (rv < 0)
2794 goto done;
2795 rv += nbytes;
2796 }
2797done:
2798 vfree(conbuf);
2799 return rv;
2800}
2801
2802static int brcmf_sdio_trap_info(struct brcmf_sdio *bus, struct sdpcm_shared *sh,
2803 char __user *data, size_t count)
2804{
2805 int error, res;
2806 char buf[350];
2807 struct brcmf_trap_info tr;
Arend van Spriel4fc0d012012-06-14 12:16:57 +02002808 loff_t pos = 0;
2809
Piotr Haberbaa9e602013-04-05 10:57:42 +02002810 if ((sh->flags & SDPCM_SHARED_TRAP) == 0) {
2811 brcmf_dbg(INFO, "no trap in firmware\n");
Arend van Spriel4fc0d012012-06-14 12:16:57 +02002812 return 0;
Piotr Haberbaa9e602013-04-05 10:57:42 +02002813 }
Arend van Spriel4fc0d012012-06-14 12:16:57 +02002814
2815 error = brcmf_sdbrcm_membytes(bus, false, sh->trap_addr, (u8 *)&tr,
2816 sizeof(struct brcmf_trap_info));
2817 if (error < 0)
2818 return error;
2819
Arend van Spriel4fc0d012012-06-14 12:16:57 +02002820 res = scnprintf(buf, sizeof(buf),
2821 "dongle trap info: type 0x%x @ epc 0x%08x\n"
2822 " cpsr 0x%08x spsr 0x%08x sp 0x%08x\n"
2823 " lr 0x%08x pc 0x%08x offset 0x%x\n"
2824 " r0 0x%08x r1 0x%08x r2 0x%08x r3 0x%08x\n"
2825 " r4 0x%08x r5 0x%08x r6 0x%08x r7 0x%08x\n",
2826 le32_to_cpu(tr.type), le32_to_cpu(tr.epc),
2827 le32_to_cpu(tr.cpsr), le32_to_cpu(tr.spsr),
2828 le32_to_cpu(tr.r13), le32_to_cpu(tr.r14),
Arend van Spriel9bd02c62012-06-26 21:26:40 +02002829 le32_to_cpu(tr.pc), sh->trap_addr,
Arend van Spriel4fc0d012012-06-14 12:16:57 +02002830 le32_to_cpu(tr.r0), le32_to_cpu(tr.r1),
2831 le32_to_cpu(tr.r2), le32_to_cpu(tr.r3),
2832 le32_to_cpu(tr.r4), le32_to_cpu(tr.r5),
2833 le32_to_cpu(tr.r6), le32_to_cpu(tr.r7));
2834
Piotr Haberbaa9e602013-04-05 10:57:42 +02002835 return simple_read_from_buffer(data, count, &pos, buf, res);
Arend van Spriel4fc0d012012-06-14 12:16:57 +02002836}
2837
2838static int brcmf_sdio_assert_info(struct brcmf_sdio *bus,
2839 struct sdpcm_shared *sh, char __user *data,
2840 size_t count)
2841{
2842 int error = 0;
2843 char buf[200];
2844 char file[80] = "?";
2845 char expr[80] = "<???>";
2846 int res;
2847 loff_t pos = 0;
2848
2849 if ((sh->flags & SDPCM_SHARED_ASSERT_BUILT) == 0) {
2850 brcmf_dbg(INFO, "firmware not built with -assert\n");
2851 return 0;
2852 } else if ((sh->flags & SDPCM_SHARED_ASSERT) == 0) {
2853 brcmf_dbg(INFO, "no assert in dongle\n");
2854 return 0;
2855 }
2856
Franky Lin38b0b0d2012-11-05 16:22:24 -08002857 sdio_claim_host(bus->sdiodev->func[1]);
Arend van Spriel4fc0d012012-06-14 12:16:57 +02002858 if (sh->assert_file_addr != 0) {
2859 error = brcmf_sdbrcm_membytes(bus, false, sh->assert_file_addr,
2860 (u8 *)file, 80);
2861 if (error < 0)
2862 return error;
2863 }
2864 if (sh->assert_exp_addr != 0) {
2865 error = brcmf_sdbrcm_membytes(bus, false, sh->assert_exp_addr,
2866 (u8 *)expr, 80);
2867 if (error < 0)
2868 return error;
2869 }
Franky Lin38b0b0d2012-11-05 16:22:24 -08002870 sdio_release_host(bus->sdiodev->func[1]);
Arend van Spriel4fc0d012012-06-14 12:16:57 +02002871
2872 res = scnprintf(buf, sizeof(buf),
2873 "dongle assert: %s:%d: assert(%s)\n",
2874 file, sh->assert_line, expr);
2875 return simple_read_from_buffer(data, count, &pos, buf, res);
2876}
2877
2878static int brcmf_sdbrcm_checkdied(struct brcmf_sdio *bus)
2879{
2880 int error;
2881 struct sdpcm_shared sh;
2882
Arend van Spriel4fc0d012012-06-14 12:16:57 +02002883 error = brcmf_sdio_readshared(bus, &sh);
Arend van Spriel4fc0d012012-06-14 12:16:57 +02002884
2885 if (error < 0)
2886 return error;
2887
2888 if ((sh.flags & SDPCM_SHARED_ASSERT_BUILT) == 0)
2889 brcmf_dbg(INFO, "firmware not built with -assert\n");
2890 else if (sh.flags & SDPCM_SHARED_ASSERT)
Arend van Spriel5e8149f2012-12-07 10:49:57 +01002891 brcmf_err("assertion in dongle\n");
Arend van Spriel4fc0d012012-06-14 12:16:57 +02002892
2893 if (sh.flags & SDPCM_SHARED_TRAP)
Arend van Spriel5e8149f2012-12-07 10:49:57 +01002894 brcmf_err("firmware trap in dongle\n");
Arend van Spriel4fc0d012012-06-14 12:16:57 +02002895
2896 return 0;
2897}
2898
2899static int brcmf_sdbrcm_died_dump(struct brcmf_sdio *bus, char __user *data,
2900 size_t count, loff_t *ppos)
2901{
2902 int error = 0;
2903 struct sdpcm_shared sh;
2904 int nbytes = 0;
2905 loff_t pos = *ppos;
2906
2907 if (pos != 0)
2908 return 0;
2909
Arend van Spriel4fc0d012012-06-14 12:16:57 +02002910 error = brcmf_sdio_readshared(bus, &sh);
2911 if (error < 0)
2912 goto done;
2913
2914 error = brcmf_sdio_assert_info(bus, &sh, data, count);
2915 if (error < 0)
2916 goto done;
Arend van Spriel4fc0d012012-06-14 12:16:57 +02002917 nbytes = error;
Piotr Haberbaa9e602013-04-05 10:57:42 +02002918
2919 error = brcmf_sdio_trap_info(bus, &sh, data+nbytes, count);
Arend van Spriel4fc0d012012-06-14 12:16:57 +02002920 if (error < 0)
2921 goto done;
Piotr Haberbaa9e602013-04-05 10:57:42 +02002922 nbytes += error;
Arend van Spriel4fc0d012012-06-14 12:16:57 +02002923
Piotr Haberbaa9e602013-04-05 10:57:42 +02002924 error = brcmf_sdio_dump_console(bus, &sh, data+nbytes, count);
2925 if (error < 0)
2926 goto done;
2927 nbytes += error;
2928
2929 error = nbytes;
2930 *ppos += nbytes;
Arend van Spriel4fc0d012012-06-14 12:16:57 +02002931done:
Arend van Spriel4fc0d012012-06-14 12:16:57 +02002932 return error;
2933}
2934
2935static ssize_t brcmf_sdio_forensic_read(struct file *f, char __user *data,
2936 size_t count, loff_t *ppos)
2937{
2938 struct brcmf_sdio *bus = f->private_data;
2939 int res;
2940
2941 res = brcmf_sdbrcm_died_dump(bus, data, count, ppos);
2942 if (res > 0)
2943 *ppos += res;
2944 return (ssize_t)res;
2945}
2946
2947static const struct file_operations brcmf_sdio_forensic_ops = {
2948 .owner = THIS_MODULE,
2949 .open = simple_open,
2950 .read = brcmf_sdio_forensic_read
2951};
2952
Arend van Spriel80969832012-06-09 22:51:44 +02002953static void brcmf_sdio_debugfs_create(struct brcmf_sdio *bus)
2954{
2955 struct brcmf_pub *drvr = bus->sdiodev->bus_if->drvr;
Arend van Spriel4fc0d012012-06-14 12:16:57 +02002956 struct dentry *dentry = brcmf_debugfs_get_devdir(drvr);
Arend van Spriel80969832012-06-09 22:51:44 +02002957
Arend van Spriel4fc0d012012-06-14 12:16:57 +02002958 if (IS_ERR_OR_NULL(dentry))
2959 return;
2960
2961 debugfs_create_file("forensics", S_IRUGO, dentry, bus,
2962 &brcmf_sdio_forensic_ops);
Arend van Spriel80969832012-06-09 22:51:44 +02002963 brcmf_debugfs_create_sdio_count(drvr, &bus->sdcnt);
2964}
2965#else
Arend van Spriel4fc0d012012-06-14 12:16:57 +02002966static int brcmf_sdbrcm_checkdied(struct brcmf_sdio *bus)
2967{
2968 return 0;
2969}
2970
Arend van Spriel80969832012-06-09 22:51:44 +02002971static void brcmf_sdio_debugfs_create(struct brcmf_sdio *bus)
2972{
2973}
2974#endif /* DEBUG */
2975
Franky Linfcf094f2011-12-16 18:37:16 -08002976static int
Franky Lin532cdd32011-11-22 17:21:54 -08002977brcmf_sdbrcm_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen)
Arend van Spriel5b435de2011-10-05 13:19:03 +02002978{
2979 int timeleft;
2980 uint rxlen = 0;
2981 bool pending;
Franky Lindd43a012012-11-05 16:22:22 -08002982 u8 *buf;
Franky Lin532cdd32011-11-22 17:21:54 -08002983 struct brcmf_bus *bus_if = dev_get_drvdata(dev);
Arend van Spriel0a332e42012-02-09 21:09:02 +01002984 struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
Franky Lin532cdd32011-11-22 17:21:54 -08002985 struct brcmf_sdio *bus = sdiodev->bus;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002986
2987 brcmf_dbg(TRACE, "Enter\n");
2988
2989 /* Wait until control frame is available */
2990 timeleft = brcmf_sdbrcm_dcmd_resp_wait(bus, &bus->rxlen, &pending);
2991
Franky Lindd43a012012-11-05 16:22:22 -08002992 spin_lock_bh(&bus->rxctl_lock);
Arend van Spriel5b435de2011-10-05 13:19:03 +02002993 rxlen = bus->rxlen;
2994 memcpy(msg, bus->rxctl, min(msglen, rxlen));
Franky Lindd43a012012-11-05 16:22:22 -08002995 bus->rxctl = NULL;
2996 buf = bus->rxctl_orig;
2997 bus->rxctl_orig = NULL;
Arend van Spriel5b435de2011-10-05 13:19:03 +02002998 bus->rxlen = 0;
Franky Lindd43a012012-11-05 16:22:22 -08002999 spin_unlock_bh(&bus->rxctl_lock);
3000 vfree(buf);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003001
3002 if (rxlen) {
3003 brcmf_dbg(CTL, "resumed on rxctl frame, got %d expected %d\n",
3004 rxlen, msglen);
3005 } else if (timeleft == 0) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01003006 brcmf_err("resumed on timeout\n");
Arend van Spriel4fc0d012012-06-14 12:16:57 +02003007 brcmf_sdbrcm_checkdied(bus);
Joe Perches23677ce2012-02-09 11:17:23 +00003008 } else if (pending) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02003009 brcmf_dbg(CTL, "cancelled\n");
3010 return -ERESTARTSYS;
3011 } else {
3012 brcmf_dbg(CTL, "resumed for unknown reason?\n");
Arend van Spriel4fc0d012012-06-14 12:16:57 +02003013 brcmf_sdbrcm_checkdied(bus);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003014 }
3015
3016 if (rxlen)
Arend van Spriel80969832012-06-09 22:51:44 +02003017 bus->sdcnt.rx_ctlpkts++;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003018 else
Arend van Spriel80969832012-06-09 22:51:44 +02003019 bus->sdcnt.rx_ctlerrs++;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003020
3021 return rxlen ? (int)rxlen : -ETIMEDOUT;
3022}
3023
Franky Line92eedf2011-11-22 17:21:50 -08003024static int brcmf_sdbrcm_write_vars(struct brcmf_sdio *bus)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003025{
3026 int bcmerror = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003027 u32 varaddr;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003028 u32 varsizew;
3029 __le32 varsizew_le;
Joe Perches8ae74652012-01-15 00:38:38 -08003030#ifdef DEBUG
Arend van Spriel5b435de2011-10-05 13:19:03 +02003031 char *nvram_ularray;
Joe Perches8ae74652012-01-15 00:38:38 -08003032#endif /* DEBUG */
Arend van Spriel5b435de2011-10-05 13:19:03 +02003033
3034 /* Even if there are no vars are to be written, we still
3035 need to set the ramsize. */
Arend van Spriel6d4ef682012-06-26 21:26:38 +02003036 varaddr = (bus->ramsize - 4) - bus->varsz;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003037
3038 if (bus->vars) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02003039 /* Write the vars list */
Arend van Spriel6d4ef682012-06-26 21:26:38 +02003040 bcmerror = brcmf_sdbrcm_membytes(bus, true, varaddr,
3041 bus->vars, bus->varsz);
Joe Perches8ae74652012-01-15 00:38:38 -08003042#ifdef DEBUG
Arend van Spriel5b435de2011-10-05 13:19:03 +02003043 /* Verify NVRAM bytes */
Arend van Spriel6d4ef682012-06-26 21:26:38 +02003044 brcmf_dbg(INFO, "Compare NVRAM dl & ul; varsize=%d\n",
3045 bus->varsz);
3046 nvram_ularray = kmalloc(bus->varsz, GFP_ATOMIC);
3047 if (!nvram_ularray)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003048 return -ENOMEM;
3049
3050 /* Upload image to verify downloaded contents. */
Arend van Spriel6d4ef682012-06-26 21:26:38 +02003051 memset(nvram_ularray, 0xaa, bus->varsz);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003052
3053 /* Read the vars list to temp buffer for comparison */
Arend van Spriel6d4ef682012-06-26 21:26:38 +02003054 bcmerror = brcmf_sdbrcm_membytes(bus, false, varaddr,
3055 nvram_ularray, bus->varsz);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003056 if (bcmerror) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01003057 brcmf_err("error %d on reading %d nvram bytes at 0x%08x\n",
Arend van Spriel6d4ef682012-06-26 21:26:38 +02003058 bcmerror, bus->varsz, varaddr);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003059 }
3060 /* Compare the org NVRAM with the one read from RAM */
Arend van Spriel6d4ef682012-06-26 21:26:38 +02003061 if (memcmp(bus->vars, nvram_ularray, bus->varsz))
Arend van Spriel5e8149f2012-12-07 10:49:57 +01003062 brcmf_err("Downloaded NVRAM image is corrupted\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003063 else
Arend van Spriel5e8149f2012-12-07 10:49:57 +01003064 brcmf_err("Download/Upload/Compare of NVRAM ok\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003065
3066 kfree(nvram_ularray);
Joe Perches8ae74652012-01-15 00:38:38 -08003067#endif /* DEBUG */
Arend van Spriel5b435de2011-10-05 13:19:03 +02003068 }
3069
3070 /* adjust to the user specified RAM */
3071 brcmf_dbg(INFO, "Physical memory size: %d\n", bus->ramsize);
3072 brcmf_dbg(INFO, "Vars are at %d, orig varsize is %d\n",
Arend van Spriel6d4ef682012-06-26 21:26:38 +02003073 varaddr, bus->varsz);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003074
3075 /*
3076 * Determine the length token:
3077 * Varsize, converted to words, in lower 16-bits, checksum
3078 * in upper 16-bits.
3079 */
3080 if (bcmerror) {
3081 varsizew = 0;
3082 varsizew_le = cpu_to_le32(0);
3083 } else {
Arend van Spriel6d4ef682012-06-26 21:26:38 +02003084 varsizew = bus->varsz / 4;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003085 varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF);
3086 varsizew_le = cpu_to_le32(varsizew);
3087 }
3088
3089 brcmf_dbg(INFO, "New varsize is %d, length token=0x%08x\n",
Arend van Spriel6d4ef682012-06-26 21:26:38 +02003090 bus->varsz, varsizew);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003091
3092 /* Write the length token to the last word */
3093 bcmerror = brcmf_sdbrcm_membytes(bus, true, (bus->ramsize - 4),
3094 (u8 *)&varsizew_le, 4);
3095
3096 return bcmerror;
3097}
3098
Franky Line92eedf2011-11-22 17:21:50 -08003099static int brcmf_sdbrcm_download_state(struct brcmf_sdio *bus, bool enter)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003100{
Arend van Spriel5b435de2011-10-05 13:19:03 +02003101 int bcmerror = 0;
Franky Lin99ba15c2011-11-04 22:23:42 +01003102 struct chip_info *ci = bus->ci;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003103
3104 /* To enter download state, disable ARM and reset SOCRAM.
3105 * To exit download state, simply reset ARM (default is RAM boot).
3106 */
3107 if (enter) {
3108 bus->alp_only = true;
3109
Franky Lin086a2e02011-11-10 20:30:23 +01003110 ci->coredisable(bus->sdiodev, ci, BCMA_CORE_ARM_CM3);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003111
Franky Lind77e70f2011-11-10 20:30:24 +01003112 ci->resetcore(bus->sdiodev, ci, BCMA_CORE_INTERNAL_MEM);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003113
3114 /* Clear the top bit of memory */
3115 if (bus->ramsize) {
3116 u32 zeros = 0;
3117 brcmf_sdbrcm_membytes(bus, true, bus->ramsize - 4,
3118 (u8 *)&zeros, 4);
3119 }
3120 } else {
Franky Lin6ca687d2011-11-10 20:30:21 +01003121 if (!ci->iscoreup(bus->sdiodev, ci, BCMA_CORE_INTERNAL_MEM)) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01003122 brcmf_err("SOCRAM core is down after reset?\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003123 bcmerror = -EBADE;
3124 goto fail;
3125 }
3126
3127 bcmerror = brcmf_sdbrcm_write_vars(bus);
3128 if (bcmerror) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01003129 brcmf_err("no vars written to RAM\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003130 bcmerror = 0;
3131 }
3132
3133 w_sdreg32(bus, 0xFFFFFFFF,
Franky Lin58692752012-05-04 18:27:36 -07003134 offsetof(struct sdpcmd_regs, intstatus));
Arend van Spriel5b435de2011-10-05 13:19:03 +02003135
Franky Lind77e70f2011-11-10 20:30:24 +01003136 ci->resetcore(bus->sdiodev, ci, BCMA_CORE_ARM_CM3);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003137
3138 /* Allow HT Clock now that the ARM is running. */
3139 bus->alp_only = false;
3140
Franky Lin712ac5b2011-12-16 18:37:09 -08003141 bus->sdiodev->bus_if->state = BRCMF_BUS_LOAD;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003142 }
3143fail:
3144 return bcmerror;
3145}
3146
Franky Line92eedf2011-11-22 17:21:50 -08003147static int brcmf_sdbrcm_get_image(char *buf, int len, struct brcmf_sdio *bus)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003148{
3149 if (bus->firmware->size < bus->fw_ptr + len)
3150 len = bus->firmware->size - bus->fw_ptr;
3151
3152 memcpy(buf, &bus->firmware->data[bus->fw_ptr], len);
3153 bus->fw_ptr += len;
3154 return len;
3155}
3156
Franky Line92eedf2011-11-22 17:21:50 -08003157static int brcmf_sdbrcm_download_code_file(struct brcmf_sdio *bus)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003158{
3159 int offset = 0;
3160 uint len;
3161 u8 *memblock = NULL, *memptr;
3162 int ret;
3163
3164 brcmf_dbg(INFO, "Enter\n");
3165
Arend van Spriel52e14092012-02-09 21:09:09 +01003166 ret = request_firmware(&bus->firmware, BRCMF_SDIO_FW_NAME,
Arend van Spriel5b435de2011-10-05 13:19:03 +02003167 &bus->sdiodev->func[2]->dev);
3168 if (ret) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01003169 brcmf_err("Fail to request firmware %d\n", ret);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003170 return ret;
3171 }
3172 bus->fw_ptr = 0;
3173
3174 memptr = memblock = kmalloc(MEMBLOCK + BRCMF_SDALIGN, GFP_ATOMIC);
3175 if (memblock == NULL) {
3176 ret = -ENOMEM;
3177 goto err;
3178 }
3179 if ((u32)(unsigned long)memblock % BRCMF_SDALIGN)
3180 memptr += (BRCMF_SDALIGN -
3181 ((u32)(unsigned long)memblock % BRCMF_SDALIGN));
3182
3183 /* Download image */
3184 while ((len =
3185 brcmf_sdbrcm_get_image((char *)memptr, MEMBLOCK, bus))) {
3186 ret = brcmf_sdbrcm_membytes(bus, true, offset, memptr, len);
3187 if (ret) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01003188 brcmf_err("error %d on writing %d membytes at 0x%08x\n",
Arend van Spriel5b435de2011-10-05 13:19:03 +02003189 ret, MEMBLOCK, offset);
3190 goto err;
3191 }
3192
3193 offset += MEMBLOCK;
3194 }
3195
3196err:
3197 kfree(memblock);
3198
3199 release_firmware(bus->firmware);
3200 bus->fw_ptr = 0;
3201
3202 return ret;
3203}
3204
3205/*
3206 * ProcessVars:Takes a buffer of "<var>=<value>\n" lines read from a file
3207 * and ending in a NUL.
3208 * Removes carriage returns, empty lines, comment lines, and converts
3209 * newlines to NULs.
3210 * Shortens buffer as needed and pads with NULs. End of buffer is marked
3211 * by two NULs.
3212*/
3213
Franky Lind610cde2012-06-26 21:26:37 +02003214static int brcmf_process_nvram_vars(struct brcmf_sdio *bus)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003215{
Franky Lind610cde2012-06-26 21:26:37 +02003216 char *varbuf;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003217 char *dp;
3218 bool findNewline;
3219 int column;
Franky Lind610cde2012-06-26 21:26:37 +02003220 int ret = 0;
3221 uint buf_len, n, len;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003222
Franky Lind610cde2012-06-26 21:26:37 +02003223 len = bus->firmware->size;
3224 varbuf = vmalloc(len);
3225 if (!varbuf)
3226 return -ENOMEM;
3227
3228 memcpy(varbuf, bus->firmware->data, len);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003229 dp = varbuf;
3230
3231 findNewline = false;
3232 column = 0;
3233
3234 for (n = 0; n < len; n++) {
3235 if (varbuf[n] == 0)
3236 break;
3237 if (varbuf[n] == '\r')
3238 continue;
3239 if (findNewline && varbuf[n] != '\n')
3240 continue;
3241 findNewline = false;
3242 if (varbuf[n] == '#') {
3243 findNewline = true;
3244 continue;
3245 }
3246 if (varbuf[n] == '\n') {
3247 if (column == 0)
3248 continue;
3249 *dp++ = 0;
3250 column = 0;
3251 continue;
3252 }
3253 *dp++ = varbuf[n];
3254 column++;
3255 }
3256 buf_len = dp - varbuf;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003257 while (dp < varbuf + n)
3258 *dp++ = 0;
3259
Franky Lind610cde2012-06-26 21:26:37 +02003260 kfree(bus->vars);
Arend van Spriel6d4ef682012-06-26 21:26:38 +02003261 /* roundup needed for download to device */
3262 bus->varsz = roundup(buf_len + 1, 4);
Franky Lind610cde2012-06-26 21:26:37 +02003263 bus->vars = kmalloc(bus->varsz, GFP_KERNEL);
3264 if (bus->vars == NULL) {
3265 bus->varsz = 0;
3266 ret = -ENOMEM;
3267 goto err;
3268 }
3269
3270 /* copy the processed variables and add null termination */
3271 memcpy(bus->vars, varbuf, buf_len);
3272 bus->vars[buf_len] = 0;
3273err:
3274 vfree(varbuf);
3275 return ret;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003276}
3277
Franky Line92eedf2011-11-22 17:21:50 -08003278static int brcmf_sdbrcm_download_nvram(struct brcmf_sdio *bus)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003279{
Arend van Spriel5b435de2011-10-05 13:19:03 +02003280 int ret;
3281
Arend van Spriel52e14092012-02-09 21:09:09 +01003282 ret = request_firmware(&bus->firmware, BRCMF_SDIO_NV_NAME,
Arend van Spriel5b435de2011-10-05 13:19:03 +02003283 &bus->sdiodev->func[2]->dev);
3284 if (ret) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01003285 brcmf_err("Fail to request nvram %d\n", ret);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003286 return ret;
3287 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003288
Franky Lind610cde2012-06-26 21:26:37 +02003289 ret = brcmf_process_nvram_vars(bus);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003290
3291 release_firmware(bus->firmware);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003292
3293 return ret;
3294}
3295
Franky Line92eedf2011-11-22 17:21:50 -08003296static int _brcmf_sdbrcm_download_firmware(struct brcmf_sdio *bus)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003297{
3298 int bcmerror = -1;
3299
3300 /* Keep arm in reset */
3301 if (brcmf_sdbrcm_download_state(bus, true)) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01003302 brcmf_err("error placing ARM core in reset\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003303 goto err;
3304 }
3305
3306 /* External image takes precedence if specified */
3307 if (brcmf_sdbrcm_download_code_file(bus)) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01003308 brcmf_err("dongle image file download failed\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003309 goto err;
3310 }
3311
3312 /* External nvram takes precedence if specified */
3313 if (brcmf_sdbrcm_download_nvram(bus))
Arend van Spriel5e8149f2012-12-07 10:49:57 +01003314 brcmf_err("dongle nvram file download failed\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003315
3316 /* Take arm out of reset */
3317 if (brcmf_sdbrcm_download_state(bus, false)) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01003318 brcmf_err("error getting out of ARM core reset\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003319 goto err;
3320 }
3321
3322 bcmerror = 0;
3323
3324err:
3325 return bcmerror;
3326}
3327
3328static bool
Franky Line92eedf2011-11-22 17:21:50 -08003329brcmf_sdbrcm_download_firmware(struct brcmf_sdio *bus)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003330{
3331 bool ret;
3332
Franky Lin38b0b0d2012-11-05 16:22:24 -08003333 sdio_claim_host(bus->sdiodev->func[1]);
3334
Arend van Spriel5b435de2011-10-05 13:19:03 +02003335 brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
3336
3337 ret = _brcmf_sdbrcm_download_firmware(bus) == 0;
3338
3339 brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false);
3340
Franky Lin38b0b0d2012-11-05 16:22:24 -08003341 sdio_release_host(bus->sdiodev->func[1]);
3342
Arend van Spriel5b435de2011-10-05 13:19:03 +02003343 return ret;
3344}
3345
Franky Lin99a0b8f2011-12-16 18:37:14 -08003346static int brcmf_sdbrcm_bus_init(struct device *dev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003347{
Franky Linfa20b912011-11-22 17:21:57 -08003348 struct brcmf_bus *bus_if = dev_get_drvdata(dev);
Arend van Spriel0a332e42012-02-09 21:09:02 +01003349 struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
Franky Linfa20b912011-11-22 17:21:57 -08003350 struct brcmf_sdio *bus = sdiodev->bus;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003351 unsigned long timeout;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003352 u8 ready, enable;
3353 int err, ret = 0;
3354 u8 saveclk;
3355
3356 brcmf_dbg(TRACE, "Enter\n");
3357
3358 /* try to download image and nvram to the dongle */
Franky Linfa20b912011-11-22 17:21:57 -08003359 if (bus_if->state == BRCMF_BUS_DOWN) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02003360 if (!(brcmf_sdbrcm_download_firmware(bus)))
3361 return -1;
3362 }
3363
Franky Lin712ac5b2011-12-16 18:37:09 -08003364 if (!bus->sdiodev->bus_if->drvr)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003365 return 0;
3366
3367 /* Start the watchdog timer */
Arend van Spriel80969832012-06-09 22:51:44 +02003368 bus->sdcnt.tickcnt = 0;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003369 brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS);
3370
Franky Lin38b0b0d2012-11-05 16:22:24 -08003371 sdio_claim_host(bus->sdiodev->func[1]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003372
3373 /* Make sure backplane clock is on, needed to generate F2 interrupt */
3374 brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
3375 if (bus->clkstate != CLK_AVAIL)
3376 goto exit;
3377
3378 /* Force clocks on backplane to be sure F2 interrupt propagates */
Franky Lin45db3392012-05-04 18:27:32 -07003379 saveclk = brcmf_sdio_regrb(bus->sdiodev,
3380 SBSDIO_FUNC1_CHIPCLKCSR, &err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003381 if (!err) {
Franky Lin3bba8292012-05-04 18:27:33 -07003382 brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
3383 (saveclk | SBSDIO_FORCE_HT), &err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003384 }
3385 if (err) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01003386 brcmf_err("Failed to force clock for F2: err %d\n", err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003387 goto exit;
3388 }
3389
3390 /* Enable function 2 (frame transfers) */
3391 w_sdreg32(bus, SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT,
Franky Lin58692752012-05-04 18:27:36 -07003392 offsetof(struct sdpcmd_regs, tosbmailboxdata));
Arend van Spriel5b435de2011-10-05 13:19:03 +02003393 enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2);
3394
Franky Lin3bba8292012-05-04 18:27:33 -07003395 brcmf_sdio_regwb(bus->sdiodev, SDIO_CCCR_IOEx, enable, NULL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003396
3397 timeout = jiffies + msecs_to_jiffies(BRCMF_WAIT_F2RDY);
3398 ready = 0;
3399 while (enable != ready) {
Franky Lin45db3392012-05-04 18:27:32 -07003400 ready = brcmf_sdio_regrb(bus->sdiodev,
3401 SDIO_CCCR_IORx, NULL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003402 if (time_after(jiffies, timeout))
3403 break;
3404 else if (time_after(jiffies, timeout - BRCMF_WAIT_F2RDY + 50))
3405 /* prevent busy waiting if it takes too long */
3406 msleep_interruptible(20);
3407 }
3408
3409 brcmf_dbg(INFO, "enable 0x%02x, ready 0x%02x\n", enable, ready);
3410
3411 /* If F2 successfully enabled, set core and enable interrupts */
3412 if (ready == enable) {
3413 /* Set up the interrupt mask and enable interrupts */
3414 bus->hostintmask = HOSTINTMASK;
3415 w_sdreg32(bus, bus->hostintmask,
Franky Lin58692752012-05-04 18:27:36 -07003416 offsetof(struct sdpcmd_regs, hostintmask));
Arend van Spriel5b435de2011-10-05 13:19:03 +02003417
Franky Lin3bba8292012-05-04 18:27:33 -07003418 brcmf_sdio_regwb(bus->sdiodev, SBSDIO_WATERMARK, 8, &err);
Arend van Sprielc0e89f02012-02-09 21:09:04 +01003419 } else {
Arend van Spriel5b435de2011-10-05 13:19:03 +02003420 /* Disable F2 again */
3421 enable = SDIO_FUNC_ENABLE_1;
Franky Lin3bba8292012-05-04 18:27:33 -07003422 brcmf_sdio_regwb(bus->sdiodev, SDIO_CCCR_IOEx, enable, NULL);
Arend van Sprielc0e89f02012-02-09 21:09:04 +01003423 ret = -ENODEV;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003424 }
3425
3426 /* Restore previous clock setting */
Franky Lin3bba8292012-05-04 18:27:33 -07003427 brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003428
Franky Line2f93cc2012-04-27 18:56:58 -07003429 if (ret == 0) {
Franky Linba89bf12012-04-27 18:56:59 -07003430 ret = brcmf_sdio_intr_register(bus->sdiodev);
Franky Line2f93cc2012-04-27 18:56:58 -07003431 if (ret != 0)
Arend van Spriel5e8149f2012-12-07 10:49:57 +01003432 brcmf_err("intr register failed:%d\n", ret);
Franky Line2f93cc2012-04-27 18:56:58 -07003433 }
3434
Arend van Spriel5b435de2011-10-05 13:19:03 +02003435 /* If we didn't come up, turn off backplane clock */
Franky Lind9126e02012-04-27 18:56:57 -07003436 if (bus_if->state != BRCMF_BUS_DATA)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003437 brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
3438
3439exit:
Franky Lin38b0b0d2012-11-05 16:22:24 -08003440 sdio_release_host(bus->sdiodev->func[1]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003441
3442 return ret;
3443}
3444
3445void brcmf_sdbrcm_isr(void *arg)
3446{
Franky Line92eedf2011-11-22 17:21:50 -08003447 struct brcmf_sdio *bus = (struct brcmf_sdio *) arg;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003448
3449 brcmf_dbg(TRACE, "Enter\n");
3450
3451 if (!bus) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01003452 brcmf_err("bus is null pointer, exiting\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003453 return;
3454 }
3455
Franky Lin712ac5b2011-12-16 18:37:09 -08003456 if (bus->sdiodev->bus_if->state == BRCMF_BUS_DOWN) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01003457 brcmf_err("bus is down. we have nothing to do\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003458 return;
3459 }
3460 /* Count the interrupt call */
Arend van Spriel80969832012-06-09 22:51:44 +02003461 bus->sdcnt.intrcount++;
Franky Lin45316032012-09-13 21:12:03 +02003462 if (in_interrupt())
3463 atomic_set(&bus->ipend, 1);
3464 else
3465 if (brcmf_sdio_intr_rstatus(bus)) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01003466 brcmf_err("failed backplane access\n");
Franky Lin45316032012-09-13 21:12:03 +02003467 bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
3468 }
Arend van Spriel5b435de2011-10-05 13:19:03 +02003469
Arend van Spriel5b435de2011-10-05 13:19:03 +02003470 /* Disable additional interrupts (is this needed now)? */
3471 if (!bus->intr)
Arend van Spriel5e8149f2012-12-07 10:49:57 +01003472 brcmf_err("isr w/o interrupt configured!\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003473
Franky Linf1e68c22012-09-13 21:12:00 +02003474 brcmf_sdbrcm_adddpctsk(bus);
3475 queue_work(bus->brcmf_wq, &bus->datawork);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003476}
3477
Franky Lincad2b262011-11-22 17:21:53 -08003478static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003479{
Joe Perches8ae74652012-01-15 00:38:38 -08003480#ifdef DEBUG
Franky Lincad2b262011-11-22 17:21:53 -08003481 struct brcmf_bus *bus_if = dev_get_drvdata(bus->sdiodev->dev);
Joe Perches8ae74652012-01-15 00:38:38 -08003482#endif /* DEBUG */
Franky Linf1e68c22012-09-13 21:12:00 +02003483 unsigned long flags;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003484
3485 brcmf_dbg(TIMER, "Enter\n");
3486
Arend van Spriel5b435de2011-10-05 13:19:03 +02003487 /* Poll period: check device if appropriate. */
3488 if (bus->poll && (++bus->polltick >= bus->pollrate)) {
3489 u32 intstatus = 0;
3490
3491 /* Reset poll tick */
3492 bus->polltick = 0;
3493
3494 /* Check device if no interrupts */
Arend van Spriel80969832012-06-09 22:51:44 +02003495 if (!bus->intr ||
3496 (bus->sdcnt.intrcount == bus->sdcnt.lastintrs)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02003497
Franky Linf1e68c22012-09-13 21:12:00 +02003498 spin_lock_irqsave(&bus->dpc_tl_lock, flags);
3499 if (list_empty(&bus->dpc_tsklst)) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02003500 u8 devpend;
Franky Linf1e68c22012-09-13 21:12:00 +02003501 spin_unlock_irqrestore(&bus->dpc_tl_lock,
3502 flags);
Franky Lin38b0b0d2012-11-05 16:22:24 -08003503 sdio_claim_host(bus->sdiodev->func[1]);
Franky Lin45db3392012-05-04 18:27:32 -07003504 devpend = brcmf_sdio_regrb(bus->sdiodev,
3505 SDIO_CCCR_INTx,
3506 NULL);
Franky Lin38b0b0d2012-11-05 16:22:24 -08003507 sdio_release_host(bus->sdiodev->func[1]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003508 intstatus =
3509 devpend & (INTR_STATUS_FUNC1 |
3510 INTR_STATUS_FUNC2);
Franky Linf1e68c22012-09-13 21:12:00 +02003511 } else {
3512 spin_unlock_irqrestore(&bus->dpc_tl_lock,
3513 flags);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003514 }
3515
3516 /* If there is something, make like the ISR and
3517 schedule the DPC */
3518 if (intstatus) {
Arend van Spriel80969832012-06-09 22:51:44 +02003519 bus->sdcnt.pollcnt++;
Franky Lin1d382272012-09-13 21:11:59 +02003520 atomic_set(&bus->ipend, 1);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003521
Franky Linf1e68c22012-09-13 21:12:00 +02003522 brcmf_sdbrcm_adddpctsk(bus);
3523 queue_work(bus->brcmf_wq, &bus->datawork);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003524 }
3525 }
3526
3527 /* Update interrupt tracking */
Arend van Spriel80969832012-06-09 22:51:44 +02003528 bus->sdcnt.lastintrs = bus->sdcnt.intrcount;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003529 }
Joe Perches8ae74652012-01-15 00:38:38 -08003530#ifdef DEBUG
Arend van Spriel5b435de2011-10-05 13:19:03 +02003531 /* Poll for console output periodically */
Hante Meuleman2def5c12012-11-14 18:46:19 -08003532 if (bus_if && bus_if->state == BRCMF_BUS_DATA &&
Franky Lin8d169aa2011-11-22 17:21:52 -08003533 bus->console_interval != 0) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02003534 bus->console.count += BRCMF_WD_POLL_MS;
3535 if (bus->console.count >= bus->console_interval) {
3536 bus->console.count -= bus->console_interval;
Franky Lin38b0b0d2012-11-05 16:22:24 -08003537 sdio_claim_host(bus->sdiodev->func[1]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003538 /* Make sure backplane clock is on */
3539 brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
3540 if (brcmf_sdbrcm_readconsole(bus) < 0)
3541 /* stop on error */
3542 bus->console_interval = 0;
Franky Lin38b0b0d2012-11-05 16:22:24 -08003543 sdio_release_host(bus->sdiodev->func[1]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003544 }
3545 }
Joe Perches8ae74652012-01-15 00:38:38 -08003546#endif /* DEBUG */
Arend van Spriel5b435de2011-10-05 13:19:03 +02003547
3548 /* On idle timeout clear activity flag and/or turn off clock */
3549 if ((bus->idletime > 0) && (bus->clkstate == CLK_AVAIL)) {
3550 if (++bus->idlecount >= bus->idletime) {
3551 bus->idlecount = 0;
3552 if (bus->activity) {
3553 bus->activity = false;
3554 brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS);
3555 } else {
Franky Lin38b0b0d2012-11-05 16:22:24 -08003556 sdio_claim_host(bus->sdiodev->func[1]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003557 brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
Franky Lin38b0b0d2012-11-05 16:22:24 -08003558 sdio_release_host(bus->sdiodev->func[1]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003559 }
3560 }
3561 }
3562
Franky Lin1d382272012-09-13 21:11:59 +02003563 return (atomic_read(&bus->ipend) > 0);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003564}
3565
3566static bool brcmf_sdbrcm_chipmatch(u16 chipid)
3567{
Franky Lin4a1c02c2012-08-30 19:42:59 +02003568 if (chipid == BCM43241_CHIP_ID)
3569 return true;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003570 if (chipid == BCM4329_CHIP_ID)
3571 return true;
Franky Lince2d7d72011-12-08 15:06:39 -08003572 if (chipid == BCM4330_CHIP_ID)
3573 return true;
Franky Lin85a4a1c2012-06-26 21:26:39 +02003574 if (chipid == BCM4334_CHIP_ID)
3575 return true;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003576 return false;
3577}
3578
Franky Linf1e68c22012-09-13 21:12:00 +02003579static void brcmf_sdio_dataworker(struct work_struct *work)
3580{
3581 struct brcmf_sdio *bus = container_of(work, struct brcmf_sdio,
3582 datawork);
3583 struct list_head *cur_hd, *tmp_hd;
3584 unsigned long flags;
3585
3586 spin_lock_irqsave(&bus->dpc_tl_lock, flags);
3587 list_for_each_safe(cur_hd, tmp_hd, &bus->dpc_tsklst) {
3588 spin_unlock_irqrestore(&bus->dpc_tl_lock, flags);
3589
3590 brcmf_sdbrcm_dpc(bus);
3591
3592 spin_lock_irqsave(&bus->dpc_tl_lock, flags);
3593 list_del(cur_hd);
3594 kfree(cur_hd);
3595 }
3596 spin_unlock_irqrestore(&bus->dpc_tl_lock, flags);
3597}
3598
Franky Line92eedf2011-11-22 17:21:50 -08003599static void brcmf_sdbrcm_release_malloc(struct brcmf_sdio *bus)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003600{
3601 brcmf_dbg(TRACE, "Enter\n");
3602
3603 kfree(bus->rxbuf);
3604 bus->rxctl = bus->rxbuf = NULL;
3605 bus->rxlen = 0;
3606
3607 kfree(bus->databuf);
3608 bus->databuf = NULL;
3609}
3610
Franky Line92eedf2011-11-22 17:21:50 -08003611static bool brcmf_sdbrcm_probe_malloc(struct brcmf_sdio *bus)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003612{
3613 brcmf_dbg(TRACE, "Enter\n");
3614
Franky Linb01a6b32011-12-16 18:37:03 -08003615 if (bus->sdiodev->bus_if->maxctl) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02003616 bus->rxblen =
Franky Linb01a6b32011-12-16 18:37:03 -08003617 roundup((bus->sdiodev->bus_if->maxctl + SDPCM_HDRLEN),
Arend van Spriel5b435de2011-10-05 13:19:03 +02003618 ALIGNMENT) + BRCMF_SDALIGN;
3619 bus->rxbuf = kmalloc(bus->rxblen, GFP_ATOMIC);
3620 if (!(bus->rxbuf))
3621 goto fail;
3622 }
3623
3624 /* Allocate buffer to receive glomed packet */
3625 bus->databuf = kmalloc(MAX_DATA_BUF, GFP_ATOMIC);
3626 if (!(bus->databuf)) {
3627 /* release rxbuf which was already located as above */
3628 if (!bus->rxblen)
3629 kfree(bus->rxbuf);
3630 goto fail;
3631 }
3632
3633 /* Align the buffer */
3634 if ((unsigned long)bus->databuf % BRCMF_SDALIGN)
3635 bus->dataptr = bus->databuf + (BRCMF_SDALIGN -
3636 ((unsigned long)bus->databuf % BRCMF_SDALIGN));
3637 else
3638 bus->dataptr = bus->databuf;
3639
3640 return true;
3641
3642fail:
3643 return false;
3644}
3645
Arend van Spriel5b435de2011-10-05 13:19:03 +02003646static bool
Franky Line92eedf2011-11-22 17:21:50 -08003647brcmf_sdbrcm_probe_attach(struct brcmf_sdio *bus, u32 regsva)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003648{
3649 u8 clkctl = 0;
3650 int err = 0;
3651 int reg_addr;
3652 u32 reg_val;
Franky Lin99ba15c2011-11-04 22:23:42 +01003653 u8 idx;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003654
3655 bus->alp_only = true;
3656
Franky Lin38b0b0d2012-11-05 16:22:24 -08003657 sdio_claim_host(bus->sdiodev->func[1]);
3658
Joe Perches18aad4f2012-01-15 00:38:42 -08003659 pr_debug("F1 signature read @0x18000000=0x%4x\n",
Franky Lin79ae3952012-05-04 18:27:34 -07003660 brcmf_sdio_regrl(bus->sdiodev, SI_ENUM_BASE, NULL));
Arend van Spriel5b435de2011-10-05 13:19:03 +02003661
3662 /*
Franky Lina97e4fc2011-11-04 22:23:35 +01003663 * Force PLL off until brcmf_sdio_chip_attach()
Arend van Spriel5b435de2011-10-05 13:19:03 +02003664 * programs PLL control regs
3665 */
3666
Franky Lin3bba8292012-05-04 18:27:33 -07003667 brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
3668 BRCMF_INIT_CLKCTL1, &err);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003669 if (!err)
Franky Lin45db3392012-05-04 18:27:32 -07003670 clkctl = brcmf_sdio_regrb(bus->sdiodev,
Arend van Spriel5b435de2011-10-05 13:19:03 +02003671 SBSDIO_FUNC1_CHIPCLKCSR, &err);
3672
3673 if (err || ((clkctl & ~SBSDIO_AVBITS) != BRCMF_INIT_CLKCTL1)) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01003674 brcmf_err("ChipClkCSR access: err %d wrote 0x%02x read 0x%02x\n",
Arend van Spriel5b435de2011-10-05 13:19:03 +02003675 err, BRCMF_INIT_CLKCTL1, clkctl);
3676 goto fail;
3677 }
3678
Franky Lina97e4fc2011-11-04 22:23:35 +01003679 if (brcmf_sdio_chip_attach(bus->sdiodev, &bus->ci, regsva)) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01003680 brcmf_err("brcmf_sdio_chip_attach failed!\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003681 goto fail;
3682 }
3683
3684 if (!brcmf_sdbrcm_chipmatch((u16) bus->ci->chip)) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01003685 brcmf_err("unsupported chip: 0x%04x\n", bus->ci->chip);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003686 goto fail;
3687 }
3688
Franky Line12afb62011-11-04 22:23:40 +01003689 brcmf_sdio_chip_drivestrengthinit(bus->sdiodev, bus->ci,
3690 SDIO_DRIVE_STRENGTH);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003691
Franky Lin454d2a82011-11-04 22:23:37 +01003692 /* Get info on the SOCRAM cores... */
Arend van Spriel5b435de2011-10-05 13:19:03 +02003693 bus->ramsize = bus->ci->ramsize;
3694 if (!(bus->ramsize)) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01003695 brcmf_err("failed to find SOCRAM memory!\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003696 goto fail;
3697 }
3698
3699 /* Set core control so an SDIO reset does a backplane reset */
Franky Lin99ba15c2011-11-04 22:23:42 +01003700 idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV);
3701 reg_addr = bus->ci->c_inf[idx].base +
Arend van Spriel5b435de2011-10-05 13:19:03 +02003702 offsetof(struct sdpcmd_regs, corecontrol);
Franky Lin79ae3952012-05-04 18:27:34 -07003703 reg_val = brcmf_sdio_regrl(bus->sdiodev, reg_addr, NULL);
Franky Line13ce262012-05-04 18:27:35 -07003704 brcmf_sdio_regwl(bus->sdiodev, reg_addr, reg_val | CC_BPRESEN, NULL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003705
Franky Lin38b0b0d2012-11-05 16:22:24 -08003706 sdio_release_host(bus->sdiodev->func[1]);
3707
Arend van Spriel5b435de2011-10-05 13:19:03 +02003708 brcmu_pktq_init(&bus->txq, (PRIOMASK + 1), TXQLEN);
3709
3710 /* Locate an appropriately-aligned portion of hdrbuf */
3711 bus->rxhdr = (u8 *) roundup((unsigned long)&bus->hdrbuf[0],
3712 BRCMF_SDALIGN);
3713
3714 /* Set the poll and/or interrupt flags */
3715 bus->intr = true;
3716 bus->poll = false;
3717 if (bus->poll)
3718 bus->pollrate = 1;
3719
3720 return true;
3721
3722fail:
Franky Lin38b0b0d2012-11-05 16:22:24 -08003723 sdio_release_host(bus->sdiodev->func[1]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003724 return false;
3725}
3726
Franky Line92eedf2011-11-22 17:21:50 -08003727static bool brcmf_sdbrcm_probe_init(struct brcmf_sdio *bus)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003728{
3729 brcmf_dbg(TRACE, "Enter\n");
3730
Franky Lin38b0b0d2012-11-05 16:22:24 -08003731 sdio_claim_host(bus->sdiodev->func[1]);
3732
Arend van Spriel5b435de2011-10-05 13:19:03 +02003733 /* Disable F2 to clear any intermediate frame state on the dongle */
Franky Lin3bba8292012-05-04 18:27:33 -07003734 brcmf_sdio_regwb(bus->sdiodev, SDIO_CCCR_IOEx,
3735 SDIO_FUNC_ENABLE_1, NULL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003736
Franky Lin712ac5b2011-12-16 18:37:09 -08003737 bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003738 bus->rxflow = false;
3739
3740 /* Done with backplane-dependent accesses, can drop clock... */
Franky Lin3bba8292012-05-04 18:27:33 -07003741 brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003742
Franky Lin38b0b0d2012-11-05 16:22:24 -08003743 sdio_release_host(bus->sdiodev->func[1]);
3744
Arend van Spriel5b435de2011-10-05 13:19:03 +02003745 /* ...and initialize clock/power states */
3746 bus->clkstate = CLK_SDONLY;
3747 bus->idletime = BRCMF_IDLE_INTERVAL;
3748 bus->idleclock = BRCMF_IDLE_ACTIVE;
3749
3750 /* Query the F2 block size, set roundup accordingly */
3751 bus->blocksize = bus->sdiodev->func[2]->cur_blksize;
3752 bus->roundup = min(max_roundup, bus->blocksize);
3753
3754 /* bus module does not support packet chaining */
3755 bus->use_rxchain = false;
3756 bus->sd_rxchain = false;
3757
3758 return true;
3759}
3760
3761static int
3762brcmf_sdbrcm_watchdog_thread(void *data)
3763{
Franky Line92eedf2011-11-22 17:21:50 -08003764 struct brcmf_sdio *bus = (struct brcmf_sdio *)data;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003765
3766 allow_signal(SIGTERM);
3767 /* Run until signal received */
3768 while (1) {
3769 if (kthread_should_stop())
3770 break;
3771 if (!wait_for_completion_interruptible(&bus->watchdog_wait)) {
Franky Lincad2b262011-11-22 17:21:53 -08003772 brcmf_sdbrcm_bus_watchdog(bus);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003773 /* Count the tick for reference */
Arend van Spriel80969832012-06-09 22:51:44 +02003774 bus->sdcnt.tickcnt++;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003775 } else
3776 break;
3777 }
3778 return 0;
3779}
3780
3781static void
3782brcmf_sdbrcm_watchdog(unsigned long data)
3783{
Franky Line92eedf2011-11-22 17:21:50 -08003784 struct brcmf_sdio *bus = (struct brcmf_sdio *)data;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003785
3786 if (bus->watchdog_tsk) {
3787 complete(&bus->watchdog_wait);
3788 /* Reschedule the watchdog */
3789 if (bus->wd_timer_valid)
3790 mod_timer(&bus->timer,
3791 jiffies + BRCMF_WD_POLL_MS * HZ / 1000);
3792 }
3793}
3794
Franky Line92eedf2011-11-22 17:21:50 -08003795static void brcmf_sdbrcm_release_dongle(struct brcmf_sdio *bus)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003796{
3797 brcmf_dbg(TRACE, "Enter\n");
3798
3799 if (bus->ci) {
Franky Lin38b0b0d2012-11-05 16:22:24 -08003800 sdio_claim_host(bus->sdiodev->func[1]);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003801 brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
3802 brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
Franky Lin38b0b0d2012-11-05 16:22:24 -08003803 sdio_release_host(bus->sdiodev->func[1]);
Franky Lina8a6c042011-11-04 22:23:39 +01003804 brcmf_sdio_chip_detach(&bus->ci);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003805 if (bus->vars && bus->varsz)
3806 kfree(bus->vars);
3807 bus->vars = NULL;
3808 }
3809
3810 brcmf_dbg(TRACE, "Disconnected\n");
3811}
3812
3813/* Detach and free everything */
Franky Line92eedf2011-11-22 17:21:50 -08003814static void brcmf_sdbrcm_release(struct brcmf_sdio *bus)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003815{
3816 brcmf_dbg(TRACE, "Enter\n");
Arend van Spriel4fc0d012012-06-14 12:16:57 +02003817
Arend van Spriel5b435de2011-10-05 13:19:03 +02003818 if (bus) {
3819 /* De-register interrupt handler */
Franky Linba89bf12012-04-27 18:56:59 -07003820 brcmf_sdio_intr_unregister(bus->sdiodev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003821
Franky Linf1e68c22012-09-13 21:12:00 +02003822 cancel_work_sync(&bus->datawork);
Hante Meuleman37ac5782012-11-14 18:46:18 -08003823 if (bus->brcmf_wq)
3824 destroy_workqueue(bus->brcmf_wq);
Franky Linf1e68c22012-09-13 21:12:00 +02003825
Franky Lin5f947ad2011-12-16 18:36:56 -08003826 if (bus->sdiodev->bus_if->drvr) {
3827 brcmf_detach(bus->sdiodev->dev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003828 brcmf_sdbrcm_release_dongle(bus);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003829 }
3830
3831 brcmf_sdbrcm_release_malloc(bus);
3832
3833 kfree(bus);
3834 }
3835
3836 brcmf_dbg(TRACE, "Disconnected\n");
3837}
3838
Arend van Sprield9cb2592012-12-05 15:25:54 +01003839static struct brcmf_bus_ops brcmf_sdio_bus_ops = {
3840 .stop = brcmf_sdbrcm_bus_stop,
3841 .init = brcmf_sdbrcm_bus_init,
3842 .txdata = brcmf_sdbrcm_bus_txdata,
3843 .txctl = brcmf_sdbrcm_bus_txctl,
3844 .rxctl = brcmf_sdbrcm_bus_rxctl,
Arend van Spriele2432b62013-04-03 12:40:38 +02003845 .gettxq = brcmf_sdbrcm_bus_gettxq,
Arend van Sprield9cb2592012-12-05 15:25:54 +01003846};
3847
Franky Lin4175b882011-11-22 17:21:49 -08003848void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003849{
3850 int ret;
Franky Line92eedf2011-11-22 17:21:50 -08003851 struct brcmf_sdio *bus;
Franky Linbbfd6a62012-06-26 21:26:35 +02003852 struct brcmf_bus_dcmd *dlst;
3853 u32 dngl_txglom;
Franky Linc3d2bc32012-06-26 21:26:36 +02003854 u32 dngl_txglomalign;
Franky Linbbfd6a62012-06-26 21:26:35 +02003855 u8 idx;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003856
Arend van Spriel5b435de2011-10-05 13:19:03 +02003857 brcmf_dbg(TRACE, "Enter\n");
3858
3859 /* We make an assumption about address window mappings:
3860 * regsva == SI_ENUM_BASE*/
3861
3862 /* Allocate private bus interface state */
Franky Line92eedf2011-11-22 17:21:50 -08003863 bus = kzalloc(sizeof(struct brcmf_sdio), GFP_ATOMIC);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003864 if (!bus)
3865 goto fail;
3866
3867 bus->sdiodev = sdiodev;
3868 sdiodev->bus = bus;
Arend van Sprielb83db862011-10-19 12:51:09 +02003869 skb_queue_head_init(&bus->glom);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003870 bus->txbound = BRCMF_TXBOUND;
3871 bus->rxbound = BRCMF_RXBOUND;
3872 bus->txminmax = BRCMF_TXMINMAX;
3873 bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003874
Hante Meuleman37ac5782012-11-14 18:46:18 -08003875 INIT_WORK(&bus->datawork, brcmf_sdio_dataworker);
3876 bus->brcmf_wq = create_singlethread_workqueue("brcmf_wq");
3877 if (bus->brcmf_wq == NULL) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01003878 brcmf_err("insufficient memory to create txworkqueue\n");
Hante Meuleman37ac5782012-11-14 18:46:18 -08003879 goto fail;
3880 }
3881
Arend van Spriel5b435de2011-10-05 13:19:03 +02003882 /* attempt to attach to the dongle */
3883 if (!(brcmf_sdbrcm_probe_attach(bus, regsva))) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01003884 brcmf_err("brcmf_sdbrcm_probe_attach failed\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003885 goto fail;
3886 }
3887
Franky Lindd43a012012-11-05 16:22:22 -08003888 spin_lock_init(&bus->rxctl_lock);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003889 spin_lock_init(&bus->txqlock);
3890 init_waitqueue_head(&bus->ctrl_wait);
3891 init_waitqueue_head(&bus->dcmd_resp_wait);
3892
3893 /* Set up the watchdog timer */
3894 init_timer(&bus->timer);
3895 bus->timer.data = (unsigned long)bus;
3896 bus->timer.function = brcmf_sdbrcm_watchdog;
3897
Arend van Spriel5b435de2011-10-05 13:19:03 +02003898 /* Initialize watchdog thread */
3899 init_completion(&bus->watchdog_wait);
3900 bus->watchdog_tsk = kthread_run(brcmf_sdbrcm_watchdog_thread,
3901 bus, "brcmf_watchdog");
3902 if (IS_ERR(bus->watchdog_tsk)) {
Joe Perches02f77192012-01-15 00:38:44 -08003903 pr_warn("brcmf_watchdog thread failed to start\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003904 bus->watchdog_tsk = NULL;
3905 }
3906 /* Initialize DPC thread */
Franky Linb948a852012-04-23 14:24:53 -07003907 INIT_LIST_HEAD(&bus->dpc_tsklst);
3908 spin_lock_init(&bus->dpc_tl_lock);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003909
Franky Lina9ffda82011-12-16 18:37:12 -08003910 /* Assign bus interface call back */
Arend van Sprield9cb2592012-12-05 15:25:54 +01003911 bus->sdiodev->bus_if->dev = bus->sdiodev->dev;
3912 bus->sdiodev->bus_if->ops = &brcmf_sdio_bus_ops;
Arend van Spriel75d907d2013-02-06 18:40:45 +01003913 bus->sdiodev->bus_if->chip = bus->ci->chip;
3914 bus->sdiodev->bus_if->chiprev = bus->ci->chiprev;
Arend van Sprield9cb2592012-12-05 15:25:54 +01003915
Arend van Spriel5b435de2011-10-05 13:19:03 +02003916 /* Attach to the brcmf/OS/network interface */
Franky Lin2447ffb2011-12-16 18:37:10 -08003917 ret = brcmf_attach(SDPCM_RESERVE, bus->sdiodev->dev);
Franky Lin712ac5b2011-12-16 18:37:09 -08003918 if (ret != 0) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01003919 brcmf_err("brcmf_attach failed\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003920 goto fail;
3921 }
3922
3923 /* Allocate buffers */
3924 if (!(brcmf_sdbrcm_probe_malloc(bus))) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01003925 brcmf_err("brcmf_sdbrcm_probe_malloc failed\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003926 goto fail;
3927 }
3928
3929 if (!(brcmf_sdbrcm_probe_init(bus))) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01003930 brcmf_err("brcmf_sdbrcm_probe_init failed\n");
Arend van Spriel5b435de2011-10-05 13:19:03 +02003931 goto fail;
3932 }
3933
Arend van Spriel80969832012-06-09 22:51:44 +02003934 brcmf_sdio_debugfs_create(bus);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003935 brcmf_dbg(INFO, "completed!!\n");
3936
Franky Linbbfd6a62012-06-26 21:26:35 +02003937 /* sdio bus core specific dcmd */
3938 idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV);
3939 dlst = kzalloc(sizeof(struct brcmf_bus_dcmd), GFP_KERNEL);
Franky Linc3d2bc32012-06-26 21:26:36 +02003940 if (dlst) {
3941 if (bus->ci->c_inf[idx].rev < 12) {
3942 /* for sdio core rev < 12, disable txgloming */
3943 dngl_txglom = 0;
3944 dlst->name = "bus:txglom";
3945 dlst->param = (char *)&dngl_txglom;
3946 dlst->param_len = sizeof(u32);
3947 } else {
3948 /* otherwise, set txglomalign */
3949 dngl_txglomalign = bus->sdiodev->bus_if->align;
3950 dlst->name = "bus:txglomalign";
3951 dlst->param = (char *)&dngl_txglomalign;
3952 dlst->param_len = sizeof(u32);
3953 }
Franky Linbbfd6a62012-06-26 21:26:35 +02003954 list_add(&dlst->list, &bus->sdiodev->bus_if->dcmd_list);
3955 }
3956
Arend van Spriel5b435de2011-10-05 13:19:03 +02003957 /* if firmware path present try to download and bring up bus */
Franky Lined683c92011-12-16 18:36:55 -08003958 ret = brcmf_bus_start(bus->sdiodev->dev);
Arend van Spriel5b435de2011-10-05 13:19:03 +02003959 if (ret != 0) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +01003960 brcmf_err("dongle is not responding\n");
Hante Meuleman1799ddf2012-11-14 18:46:17 -08003961 goto fail;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003962 }
Franky Lin15d45b62011-10-21 16:16:32 +02003963
Arend van Spriel5b435de2011-10-05 13:19:03 +02003964 return bus;
3965
3966fail:
3967 brcmf_sdbrcm_release(bus);
3968 return NULL;
3969}
3970
3971void brcmf_sdbrcm_disconnect(void *ptr)
3972{
Franky Line92eedf2011-11-22 17:21:50 -08003973 struct brcmf_sdio *bus = (struct brcmf_sdio *)ptr;
Arend van Spriel5b435de2011-10-05 13:19:03 +02003974
3975 brcmf_dbg(TRACE, "Enter\n");
3976
3977 if (bus)
3978 brcmf_sdbrcm_release(bus);
3979
3980 brcmf_dbg(TRACE, "Disconnected\n");
3981}
3982
Arend van Spriel5b435de2011-10-05 13:19:03 +02003983void
Franky Line92eedf2011-11-22 17:21:50 -08003984brcmf_sdbrcm_wd_timer(struct brcmf_sdio *bus, uint wdtick)
Arend van Spriel5b435de2011-10-05 13:19:03 +02003985{
Arend van Spriel5b435de2011-10-05 13:19:03 +02003986 /* Totally stop the timer */
Joe Perches23677ce2012-02-09 11:17:23 +00003987 if (!wdtick && bus->wd_timer_valid) {
Arend van Spriel5b435de2011-10-05 13:19:03 +02003988 del_timer_sync(&bus->timer);
3989 bus->wd_timer_valid = false;
3990 bus->save_ms = wdtick;
3991 return;
3992 }
3993
Franky Linece960e2011-10-21 16:16:19 +02003994 /* don't start the wd until fw is loaded */
Franky Lin712ac5b2011-12-16 18:37:09 -08003995 if (bus->sdiodev->bus_if->state == BRCMF_BUS_DOWN)
Franky Linece960e2011-10-21 16:16:19 +02003996 return;
3997
Arend van Spriel5b435de2011-10-05 13:19:03 +02003998 if (wdtick) {
3999 if (bus->save_ms != BRCMF_WD_POLL_MS) {
Joe Perches23677ce2012-02-09 11:17:23 +00004000 if (bus->wd_timer_valid)
Arend van Spriel5b435de2011-10-05 13:19:03 +02004001 /* Stop timer and restart at new value */
4002 del_timer_sync(&bus->timer);
4003
4004 /* Create timer again when watchdog period is
4005 dynamically changed or in the first instance
4006 */
4007 bus->timer.expires =
4008 jiffies + BRCMF_WD_POLL_MS * HZ / 1000;
4009 add_timer(&bus->timer);
4010
4011 } else {
4012 /* Re arm the timer, at last watchdog period */
4013 mod_timer(&bus->timer,
4014 jiffies + BRCMF_WD_POLL_MS * HZ / 1000);
4015 }
4016
4017 bus->wd_timer_valid = true;
4018 bus->save_ms = wdtick;
4019 }
4020}