2 * Copyright (c) 2010 Broadcom Corporation
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.
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.
17 #include <linux/types.h>
18 #include <linux/kernel.h>
19 #include <linux/printk.h>
20 #include <linux/pci_ids.h>
21 #include <linux/netdevice.h>
22 #include <linux/sched.h>
23 #include <linux/mmc/sdio.h>
24 #include <asm/unaligned.h>
26 #include <brcmu_wifi.h>
27 #include <brcmu_utils.h>
28 #include <brcm_hw_ids.h>
30 #include "sdio_host.h"
32 /* register access macros */
36 bcmsdh_reg_read(NULL, (unsigned long)(r), sizeof(*(r)))
40 __typeof(*(r)) __osl_v; \
41 __asm__ __volatile__("sync"); \
42 __osl_v = bcmsdh_reg_read(NULL, (unsigned long)(r),\
44 __asm__ __volatile__("sync"); \
49 #define W_REG(r, v) do { \
50 bcmsdh_reg_write(NULL, (unsigned long)(r), sizeof(*(r)), (v)); \
52 #else /* __BIG_ENDIAN */
54 bcmsdh_reg_read(NULL, (unsigned long)(r), sizeof(*(r)))
55 #define W_REG(r, v) do { \
56 bcmsdh_reg_write(NULL, (unsigned long)(r), sizeof(*(r)), (v)); \
58 #endif /* __BIG_ENDIAN */
60 #define AND_REG(r, v) W_REG((r), R_REG(r) & (v))
61 #define OR_REG(r, v) W_REG((r), R_REG(r) | (v))
63 #define SET_REG(r, mask, val) \
64 W_REG((r), ((R_REG(r) & ~(mask)) | (val)))
68 /* ARM trap handling */
70 /* Trap types defined by ARM (see arminc.h) */
72 /* Trap locations in lo memory */
74 #define FIRST_TRAP TR_RST
75 #define LAST_TRAP (TR_FIQ * TRAP_STRIDE)
77 #if defined(__ARM_ARCH_4T__)
78 #define MAX_TRAP_TYPE (TR_FIQ + 1)
79 #elif defined(__ARM_ARCH_7M__)
80 #define MAX_TRAP_TYPE (TR_ISR + ARMCM3_NUMINTS)
81 #endif /* __ARM_ARCH_7M__ */
83 /* The trap structure is defined here as offsets for assembly */
89 #define TR_REG(n) (TR_REGS + (n) * 4)
90 #define TR_SP TR_REG(13)
91 #define TR_LR TR_REG(14)
92 #define TR_PC TR_REG(15)
94 #define TRAP_T_SIZE 80
96 typedef struct _trap_struct
{
119 #define CBUF_LEN (128)
121 #define LOG_BUF_LEN 1024
124 u32 buf
; /* Can't be pointer on (64-bit) hosts */
127 char *_buf_compat
; /* Redundant pointer for backward compat. */
132 * When there is no UART (e.g. Quickturn),
133 * the host should write a complete
134 * input line directly into cbuf and then write
135 * the length into vcons_in.
136 * This may also be used when there is a real UART
137 * (at risk of conflicting with
138 * the real UART). vcons_out is currently unused.
140 volatile uint vcons_in
;
141 volatile uint vcons_out
;
143 /* Output (logging) buffer
144 * Console output is written to a ring buffer log_buf at index log_idx.
145 * The host may read the output when it sees log_idx advance.
146 * Output will be lost if the output wraps around faster than the host
151 /* Console input line buffer
152 * Characters are read one at a time into cbuf
153 * until <CR> is received, then
154 * the buffer is processed as a command line.
155 * Also used for virtual UART.
161 #endif /* DHD_DEBUG */
162 #include <chipcommon.h>
166 #include "dngl_stats.h"
169 #include "dhd_proto.h"
174 #ifndef DHDSDIO_MEM_DUMP_FNAME
175 #define DHDSDIO_MEM_DUMP_FNAME "mem_dump"
178 #define TXQLEN 2048 /* bulk tx queue length */
179 #define TXHI (TXQLEN - 256) /* turn on flow control above TXHI */
180 #define TXLOW (TXHI - 256) /* turn off flow control below TXLOW */
183 #define TXRETRIES 2 /* # of retries for tx frames */
185 #if defined(CONFIG_MACH_SANDGATE2G)
186 #define DHD_RXBOUND 250 /* Default for max rx frames in
189 #define DHD_RXBOUND 50 /* Default for max rx frames in
191 #endif /* defined(CONFIG_MACH_SANDGATE2G) */
193 #define DHD_TXBOUND 20 /* Default for max tx frames in
196 #define DHD_TXMINMAX 1 /* Max tx frames if rx still pending */
198 #define MEMBLOCK 2048 /* Block size used for downloading
200 #define MAX_DATA_BUF (32 * 1024) /* Must be large enough to hold
201 biggest possible glom */
203 /* Packet alignment for most efficient SDIO (can change based on platform) */
205 #define DHD_SDALIGN 32
207 #if !ISPOWEROF2(DHD_SDALIGN)
208 #error DHD_SDALIGN is not a power of 2!
211 #ifndef DHD_FIRSTREAD
212 #define DHD_FIRSTREAD 32
214 #if !ISPOWEROF2(DHD_FIRSTREAD)
215 #error DHD_FIRSTREAD is not a power of 2!
218 /* Total length of frame header for dongle protocol */
219 #define SDPCM_HDRLEN (SDPCM_FRAMETAG_LEN + SDPCM_SWHEADER_LEN)
221 #define SDPCM_RESERVE (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN)
223 #define SDPCM_RESERVE (SDPCM_HDRLEN + DHD_SDALIGN)
227 * Software allocation of To SB Mailbox resources
230 /* tosbmailbox bits corresponding to intstatus bits */
231 #define SMB_NAK (1 << 0) /* Frame NAK */
232 #define SMB_INT_ACK (1 << 1) /* Host Interrupt ACK */
233 #define SMB_USE_OOB (1 << 2) /* Use OOB Wakeup */
234 #define SMB_DEV_INT (1 << 3) /* Miscellaneous Interrupt */
236 /* tosbmailboxdata */
237 #define SMB_DATA_VERSION_SHIFT 16 /* host protocol version */
240 * Software allocation of To Host Mailbox resources
244 #define I_HMB_FC_STATE I_HMB_SW0 /* Flow Control State */
245 #define I_HMB_FC_CHANGE I_HMB_SW1 /* Flow Control State Changed */
246 #define I_HMB_FRAME_IND I_HMB_SW2 /* Frame Indication */
247 #define I_HMB_HOST_INT I_HMB_SW3 /* Miscellaneous Interrupt */
249 /* tohostmailboxdata */
250 #define HMB_DATA_NAKHANDLED 1 /* retransmit NAK'd frame */
251 #define HMB_DATA_DEVREADY 2 /* talk to host after enable */
252 #define HMB_DATA_FC 4 /* per prio flowcontrol update flag */
253 #define HMB_DATA_FWREADY 8 /* fw ready for protocol activity */
255 #define HMB_DATA_FCDATA_MASK 0xff000000
256 #define HMB_DATA_FCDATA_SHIFT 24
258 #define HMB_DATA_VERSION_MASK 0x00ff0000
259 #define HMB_DATA_VERSION_SHIFT 16
262 * Software-defined protocol header
265 /* Current protocol version */
266 #define SDPCM_PROT_VERSION 4
268 /* SW frame header */
269 #define SDPCM_PACKET_SEQUENCE(p) (((u8 *)p)[0] & 0xff)
271 #define SDPCM_CHANNEL_MASK 0x00000f00
272 #define SDPCM_CHANNEL_SHIFT 8
273 #define SDPCM_PACKET_CHANNEL(p) (((u8 *)p)[1] & 0x0f)
275 #define SDPCM_NEXTLEN_OFFSET 2
277 /* Data Offset from SOF (HW Tag, SW Tag, Pad) */
278 #define SDPCM_DOFFSET_OFFSET 3 /* Data Offset */
279 #define SDPCM_DOFFSET_VALUE(p) (((u8 *)p)[SDPCM_DOFFSET_OFFSET] & 0xff)
280 #define SDPCM_DOFFSET_MASK 0xff000000
281 #define SDPCM_DOFFSET_SHIFT 24
282 #define SDPCM_FCMASK_OFFSET 4 /* Flow control */
283 #define SDPCM_FCMASK_VALUE(p) (((u8 *)p)[SDPCM_FCMASK_OFFSET] & 0xff)
284 #define SDPCM_WINDOW_OFFSET 5 /* Credit based fc */
285 #define SDPCM_WINDOW_VALUE(p) (((u8 *)p)[SDPCM_WINDOW_OFFSET] & 0xff)
287 #define SDPCM_SWHEADER_LEN 8 /* SW header is 64 bits */
289 /* logical channel numbers */
290 #define SDPCM_CONTROL_CHANNEL 0 /* Control channel Id */
291 #define SDPCM_EVENT_CHANNEL 1 /* Asyc Event Indication Channel Id */
292 #define SDPCM_DATA_CHANNEL 2 /* Data Xmit/Recv Channel Id */
293 #define SDPCM_GLOM_CHANNEL 3 /* For coalesced packets */
294 #define SDPCM_TEST_CHANNEL 15 /* Reserved for test/debug packets */
296 #define SDPCM_SEQUENCE_WRAP 256 /* wrap-around val for 8bit frame seq */
298 #define SDPCM_GLOMDESC(p) (((u8 *)p)[1] & 0x80)
300 /* For TEST_CHANNEL packets, define another 4-byte header */
301 #define SDPCM_TEST_HDRLEN 4 /*
302 * Generally: Cmd(1), Ext(1), Len(2);
303 * Semantics of Ext byte depend on
304 * command. Len is current or requested
305 * frame length, not including test
306 * header; sent little-endian.
308 #define SDPCM_TEST_DISCARD 0x01 /* Receiver discards. Ext:pattern id. */
309 #define SDPCM_TEST_ECHOREQ 0x02 /* Echo request. Ext:pattern id. */
310 #define SDPCM_TEST_ECHORSP 0x03 /* Echo response. Ext:pattern id. */
311 #define SDPCM_TEST_BURST 0x04 /*
312 * Receiver to send a burst.
313 * Ext is a frame count
315 #define SDPCM_TEST_SEND 0x05 /*
316 * Receiver sets send mode.
317 * Ext is boolean on/off
320 /* Handy macro for filling in datagen packets with a pattern */
321 #define SDPCM_TEST_FILL(byteno, id) ((u8)(id + byteno))
324 * Shared structure between dongle and the host.
325 * The structure contains pointers to trap or assert information.
327 #define SDPCM_SHARED_VERSION 0x0002
328 #define SDPCM_SHARED_VERSION_MASK 0x00FF
329 #define SDPCM_SHARED_ASSERT_BUILT 0x0100
330 #define SDPCM_SHARED_ASSERT 0x0200
331 #define SDPCM_SHARED_TRAP 0x0400
334 /* Space for header read, limit for data packets */
336 #define MAX_HDR_READ 32
338 #if !ISPOWEROF2(MAX_HDR_READ)
339 #error MAX_HDR_READ is not a power of 2!
342 #define MAX_RX_DATASZ 2048
344 /* Maximum milliseconds to wait for F2 to come up */
345 #define DHD_WAIT_F2RDY 3000
347 /* Bump up limit on waiting for HT to account for first startup;
348 * if the image is doing a CRC calculation before programming the PMU
349 * for HT availability, it could take a couple hundred ms more, so
350 * max out at a 1 second (1000000us).
352 #if (PMU_MAX_TRANSITION_DLY <= 1000000)
353 #undef PMU_MAX_TRANSITION_DLY
354 #define PMU_MAX_TRANSITION_DLY 1000000
357 /* Value for ChipClockCSR during initial setup */
358 #define DHD_INIT_CLKCTL1 (SBSDIO_FORCE_HW_CLKREQ_OFF | \
359 SBSDIO_ALP_AVAIL_REQ)
360 #define DHD_INIT_CLKCTL2 (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP)
362 /* Flags for SDH calls */
363 #define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED)
366 #define SBIM_IBE 0x20000 /* inbanderror */
367 #define SBIM_TO 0x40000 /* timeout */
368 #define SBIM_BY 0x01800000 /* busy (sonics >= 2.3) */
369 #define SBIM_RJ 0x02000000 /* reject (sonics >= 2.3) */
372 #define SBTML_RESET 0x0001 /* reset */
373 #define SBTML_REJ_MASK 0x0006 /* reject field */
374 #define SBTML_REJ 0x0002 /* reject */
375 #define SBTML_TMPREJ 0x0004 /* temporary reject, for error recovery */
377 #define SBTML_SICF_SHIFT 16 /* Shift to locate the SI control flags in sbtml */
380 #define SBTMH_SERR 0x0001 /* serror */
381 #define SBTMH_INT 0x0002 /* interrupt */
382 #define SBTMH_BUSY 0x0004 /* busy */
383 #define SBTMH_TO 0x0020 /* timeout (sonics >= 2.3) */
385 #define SBTMH_SISF_SHIFT 16 /* Shift to locate the SI status flags in sbtmh */
388 #define SBIDL_INIT 0x80 /* initiator */
391 #define SBIDH_RC_MASK 0x000f /* revision code */
392 #define SBIDH_RCE_MASK 0x7000 /* revision code extension field */
393 #define SBIDH_RCE_SHIFT 8
394 #define SBCOREREV(sbidh) \
395 ((((sbidh) & SBIDH_RCE_MASK) >> SBIDH_RCE_SHIFT) | ((sbidh) & SBIDH_RC_MASK))
396 #define SBIDH_CC_MASK 0x8ff0 /* core code */
397 #define SBIDH_CC_SHIFT 4
398 #define SBIDH_VC_MASK 0xffff0000 /* vendor code */
399 #define SBIDH_VC_SHIFT 16
402 * Conversion of 802.1D priority to precedence level
404 #define PRIO2PREC(prio) \
405 (((prio) == PRIO_8021D_NONE || (prio) == PRIO_8021D_BE) ? \
408 DHD_SPINWAIT_SLEEP_INIT(sdioh_spinwait_sleep
);
409 extern int dhdcdc_set_ioctl(dhd_pub_t
*dhd
, int ifidx
, uint cmd
, void *buf
,
412 /* Core reg address translation */
413 #define CORE_CC_REG(base, field) (base + offsetof(chipcregs_t, field))
414 #define CORE_BUS_REG(base, field) \
415 (base + offsetof(struct sdpcmd_regs, field))
416 #define CORE_SB(base, field) \
417 (base + SBCONFIGOFF + offsetof(sbconfig_t, field))
420 /* Device console log buffer state */
421 typedef struct dhd_console
{
422 uint count
; /* Poll interval msec counter */
423 uint log_addr
; /* Log struct address (fixed) */
424 rte_log_t log
; /* Log struct (host copy) */
425 uint bufsize
; /* Size of log buffer */
426 u8
*buf
; /* Log buffer (host copy) */
427 uint last
; /* Last buffer read index */
429 #endif /* DHD_DEBUG */
431 struct sdpcm_shared
{
435 u32 assert_file_addr
;
437 u32 console_addr
; /* Address of rte_cons_t */
443 /* misc chip info needed by some of the routines */
459 /* Private data for SDIO bus interaction */
460 typedef struct dhd_bus
{
463 bcmsdh_info_t
*sdh
; /* Handle for BCMSDH calls */
464 struct chip_info
*ci
; /* Chip info struct */
465 char *vars
; /* Variables (from CIS and/or other) */
466 uint varsz
; /* Size of variables buffer */
467 u32 sbaddr
; /* Current SB window pointer (-1, invalid) */
469 struct sdpcmd_regs
*regs
; /* SDIO core */
470 uint sdpcmrev
; /* SDIO core revision */
471 uint armrev
; /* CPU core revision */
472 uint ramrev
; /* SOCRAM core revision */
473 u32 ramsize
; /* Size of RAM in SOCRAM (bytes) */
474 u32 orig_ramsize
; /* Size of RAM in SOCRAM (bytes) */
476 u32 bus
; /* gSPI or SDIO bus */
477 u32 hostintmask
; /* Copy of Host Interrupt Mask */
478 u32 intstatus
; /* Intstatus bits (events) pending */
479 bool dpc_sched
; /* Indicates DPC schedule (intrpt rcvd) */
480 bool fcstate
; /* State of dongle flow-control */
482 u16 cl_devid
; /* cached devid for dhdsdio_probe_attach() */
483 char *fw_path
; /* module_param: path to firmware image */
484 char *nv_path
; /* module_param: path to nvram vars file */
485 const char *nvram_params
; /* user specified nvram params. */
487 uint blocksize
; /* Block size of SDIO transfers */
488 uint roundup
; /* Max roundup limit */
490 struct pktq txq
; /* Queue length used for flow-control */
491 u8 flowcontrol
; /* per prio flow control bitmask */
492 u8 tx_seq
; /* Transmit sequence number (next) */
493 u8 tx_max
; /* Maximum transmit sequence allowed */
495 u8 hdrbuf
[MAX_HDR_READ
+ DHD_SDALIGN
];
496 u8
*rxhdr
; /* Header of current rx frame (in hdrbuf) */
497 u16 nextlen
; /* Next Read Len from last header */
498 u8 rx_seq
; /* Receive sequence number (expected) */
499 bool rxskip
; /* Skip receive (awaiting NAK ACK) */
501 struct sk_buff
*glomd
; /* Packet containing glomming descriptor */
502 struct sk_buff
*glom
; /* Packet chain for glommed superframe */
503 uint glomerr
; /* Glom packet read errors */
505 u8
*rxbuf
; /* Buffer for receiving control packets */
506 uint rxblen
; /* Allocated length of rxbuf */
507 u8
*rxctl
; /* Aligned pointer into rxbuf */
508 u8
*databuf
; /* Buffer for receiving big glom packet */
509 u8
*dataptr
; /* Aligned pointer into databuf */
510 uint rxlen
; /* Length of valid data in buffer */
512 u8 sdpcm_ver
; /* Bus protocol reported by dongle */
514 bool intr
; /* Use interrupts */
515 bool poll
; /* Use polling */
516 bool ipend
; /* Device interrupt is pending */
517 bool intdis
; /* Interrupts disabled by isr */
518 uint intrcount
; /* Count of device interrupt callbacks */
519 uint lastintrs
; /* Count as of last watchdog timer */
520 uint spurious
; /* Count of spurious interrupts */
521 uint pollrate
; /* Ticks between device polls */
522 uint polltick
; /* Tick counter */
523 uint pollcnt
; /* Count of active polls */
526 dhd_console_t console
; /* Console output polling support */
527 uint console_addr
; /* Console address from shared struct */
528 #endif /* DHD_DEBUG */
530 uint regfails
; /* Count of R_REG/W_REG failures */
532 uint clkstate
; /* State of sd and backplane clock(s) */
533 bool activity
; /* Activity flag for clock down */
534 s32 idletime
; /* Control for activity timeout */
535 s32 idlecount
; /* Activity timeout counter */
536 s32 idleclock
; /* How to set bus driver when idle */
537 s32 sd_rxchain
; /* If bcmsdh api accepts PKT chains */
538 bool use_rxchain
; /* If dhd should use PKT chains */
539 bool sleeping
; /* Is SDIO bus sleeping? */
540 bool rxflow_mode
; /* Rx flow control mode */
541 bool rxflow
; /* Is rx flow control on */
542 uint prev_rxlim_hit
; /* Is prev rx limit exceeded
543 (per dpc schedule) */
544 bool alp_only
; /* Don't use HT clock (ALP only) */
545 /* Field to decide if rx of control frames happen in rxbuf or lb-pool */
549 /* external loopback */
553 /* pktgen configuration */
554 uint pktgen_freq
; /* Ticks between bursts */
555 uint pktgen_count
; /* Packets to send each burst */
556 uint pktgen_print
; /* Bursts between count displays */
557 uint pktgen_total
; /* Stop after this many */
558 uint pktgen_minlen
; /* Minimum packet data len */
559 uint pktgen_maxlen
; /* Maximum packet data len */
560 uint pktgen_mode
; /* Configured mode: tx, rx, or echo */
561 uint pktgen_stop
; /* Number of tx failures causing stop */
563 /* active pktgen fields */
564 uint pktgen_tick
; /* Tick counter for bursts */
565 uint pktgen_ptick
; /* Burst counter for printing */
566 uint pktgen_sent
; /* Number of test packets generated */
567 uint pktgen_rcvd
; /* Number of test packets received */
568 uint pktgen_fail
; /* Number of failed send attempts */
569 u16 pktgen_len
; /* Length of next packet to send */
572 /* Some additional counters */
573 uint tx_sderrs
; /* Count of tx attempts with sd errors */
574 uint fcqueued
; /* Tx packets that got queued */
575 uint rxrtx
; /* Count of rtx requests (NAK to dongle) */
576 uint rx_toolong
; /* Receive frames too long to receive */
577 uint rxc_errors
; /* SDIO errors when reading control frames */
578 uint rx_hdrfail
; /* SDIO errors on header reads */
579 uint rx_badhdr
; /* Bad received headers (roosync?) */
580 uint rx_badseq
; /* Mismatched rx sequence number */
581 uint fc_rcvd
; /* Number of flow-control events received */
582 uint fc_xoff
; /* Number which turned on flow-control */
583 uint fc_xon
; /* Number which turned off flow-control */
584 uint rxglomfail
; /* Failed deglom attempts */
585 uint rxglomframes
; /* Number of glom frames (superframes) */
586 uint rxglompkts
; /* Number of packets from glom frames */
587 uint f2rxhdrs
; /* Number of header reads */
588 uint f2rxdata
; /* Number of frame data reads */
589 uint f2txdata
; /* Number of f2 frame writes */
590 uint f1regdata
; /* Number of f1 register accesses */
594 bool ctrl_frame_stat
;
597 typedef volatile struct _sbconfig
{
599 u32 sbipsflag
; /* initiator port ocp slave flag */
601 u32 sbtpsflag
; /* target port ocp slave flag */
603 u32 sbtmerrloga
; /* (sonics >= 2.3) */
605 u32 sbtmerrlog
; /* (sonics >= 2.3) */
607 u32 sbadmatch3
; /* address match3 */
609 u32 sbadmatch2
; /* address match2 */
611 u32 sbadmatch1
; /* address match1 */
613 u32 sbimstate
; /* initiator agent state */
614 u32 sbintvec
; /* interrupt mask */
615 u32 sbtmstatelow
; /* target state */
616 u32 sbtmstatehigh
; /* target state */
617 u32 sbbwa0
; /* bandwidth allocation table0 */
619 u32 sbimconfiglow
; /* initiator configuration */
620 u32 sbimconfighigh
; /* initiator configuration */
621 u32 sbadmatch0
; /* address match0 */
623 u32 sbtmconfiglow
; /* target configuration */
624 u32 sbtmconfighigh
; /* target configuration */
625 u32 sbbconfig
; /* broadcast configuration */
627 u32 sbbstate
; /* broadcast state */
629 u32 sbactcnfg
; /* activate configuration */
631 u32 sbflagst
; /* current sbflags */
633 u32 sbidlow
; /* identification */
634 u32 sbidhigh
; /* identification */
640 #define CLK_PENDING 2 /* Not used yet */
643 #define DHD_NOPMU(dhd) (false)
646 static int qcount
[NUMPRIO
];
647 static int tx_packets
[NUMPRIO
];
648 #endif /* DHD_DEBUG */
650 /* Deferred transmit */
651 const uint dhd_deferred_tx
= 1;
653 extern uint dhd_watchdog_ms
;
654 extern void dhd_os_wd_timer(void *bus
, uint wdtick
);
661 /* override the RAM size if possible */
662 #define DONGLE_MIN_MEMSIZE (128 * 1024)
663 int dhd_dongle_memsize
;
665 static bool dhd_alignctl
;
669 static bool retrydata
;
670 #define RETRYCHAN(chan) (((chan) == SDPCM_EVENT_CHANNEL) || retrydata)
672 static const uint watermark
= 8;
673 static const uint firstread
= DHD_FIRSTREAD
;
675 #define HDATLEN (firstread - (SDPCM_HDRLEN))
677 /* Retry count for register access failures */
678 static const uint retry_limit
= 2;
680 /* Force even SD lengths (some host controllers mess up on odd bytes) */
681 static bool forcealign
;
685 #if defined(OOB_INTR_ONLY) && defined(HW_OOB)
686 extern void bcmsdh_enable_hw_oob_intr(void *sdh
, bool enable
);
689 #if defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD)
690 #error OOB_INTR_ONLY is NOT working with SDIO_ISR_THREAD
691 #endif /* defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD) */
692 #define PKTALIGN(_p, _len, _align) \
695 datalign = (unsigned long)((_p)->data); \
696 datalign = roundup(datalign, (_align)) - datalign; \
697 ASSERT(datalign < (_align)); \
698 ASSERT((_p)->len >= ((_len) + datalign)); \
700 skb_pull((_p), datalign); \
701 __skb_trim((_p), (_len)); \
704 /* Limit on rounding up frames */
705 static const uint max_roundup
= 512;
707 /* Try doing readahead */
708 static bool dhd_readahead
;
710 /* To check if there's window offered */
711 #define DATAOK(bus) \
712 (((u8)(bus->tx_max - bus->tx_seq) != 0) && \
713 (((u8)(bus->tx_max - bus->tx_seq) & 0x80) == 0))
715 /* Macros to get register read/write status */
716 /* NOTE: these assume a local dhdsdio_bus_t *bus! */
717 #define R_SDREG(regvar, regaddr, retryvar) \
721 regvar = R_REG(regaddr); \
722 } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \
724 bus->regfails += (retryvar-1); \
725 if (retryvar > retry_limit) { \
726 DHD_ERROR(("%s: FAILED" #regvar "READ, LINE %d\n", \
727 __func__, __LINE__)); \
733 #define W_SDREG(regval, regaddr, retryvar) \
737 W_REG(regaddr, regval); \
738 } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \
740 bus->regfails += (retryvar-1); \
741 if (retryvar > retry_limit) \
742 DHD_ERROR(("%s: FAILED REGISTER WRITE, LINE %d\n", \
743 __func__, __LINE__)); \
747 #define DHD_BUS SDIO_BUS
749 #define PKT_AVAILABLE() (intstatus & I_HMB_FRAME_IND)
751 #define HOSTINTMASK (I_HMB_SW_MASK | I_CHIPACTIVE)
754 static void dhdsdio_testrcv(dhd_bus_t
*bus
, void *pkt
, uint seq
);
755 static void dhdsdio_sdtest_set(dhd_bus_t
*bus
, bool start
);
759 static int dhdsdio_checkdied(dhd_bus_t
*bus
, u8
*data
, uint size
);
760 static int dhdsdio_mem_dump(dhd_bus_t
*bus
);
761 #endif /* DHD_DEBUG */
762 static int dhdsdio_download_state(dhd_bus_t
*bus
, bool enter
);
764 static void dhdsdio_release(dhd_bus_t
*bus
);
765 static void dhdsdio_release_malloc(dhd_bus_t
*bus
);
766 static void dhdsdio_disconnect(void *ptr
);
767 static bool dhdsdio_chipmatch(u16 chipid
);
768 static bool dhdsdio_probe_attach(dhd_bus_t
*bus
, void *sdh
,
769 void *regsva
, u16 devid
);
770 static bool dhdsdio_probe_malloc(dhd_bus_t
*bus
, void *sdh
);
771 static bool dhdsdio_probe_init(dhd_bus_t
*bus
, void *sdh
);
772 static void dhdsdio_release_dongle(dhd_bus_t
*bus
);
774 static uint
process_nvram_vars(char *varbuf
, uint len
);
776 static void dhd_dongle_setmemsize(struct dhd_bus
*bus
, int mem_size
);
777 static int dhd_bcmsdh_send_buf(dhd_bus_t
*bus
, u32 addr
, uint fn
,
778 uint flags
, u8
*buf
, uint nbytes
,
779 struct sk_buff
*pkt
, bcmsdh_cmplt_fn_t complete
,
782 static bool dhdsdio_download_firmware(struct dhd_bus
*bus
, void *sdh
);
783 static int _dhdsdio_download_firmware(struct dhd_bus
*bus
);
785 static int dhdsdio_download_code_file(struct dhd_bus
*bus
, char *image_path
);
786 static int dhdsdio_download_nvram(struct dhd_bus
*bus
);
787 static void dhdsdio_chip_disablecore(bcmsdh_info_t
*sdh
, u32 corebase
);
788 static int dhdsdio_chip_attach(struct dhd_bus
*bus
, void *regs
);
789 static void dhdsdio_chip_resetcore(bcmsdh_info_t
*sdh
, u32 corebase
);
790 static void dhdsdio_sdiod_drive_strength_init(struct dhd_bus
*bus
,
792 static void dhdsdio_chip_detach(struct dhd_bus
*bus
);
794 /* Packet free applicable unconditionally for sdio and sdspi.
795 * Conditional if bufpool was present for gspi bus.
797 static void dhdsdio_pktfree2(dhd_bus_t
*bus
, struct sk_buff
*pkt
)
799 dhd_os_sdlock_rxq(bus
->dhd
);
800 if ((bus
->bus
!= SPI_BUS
) || bus
->usebufpool
)
801 brcmu_pkt_buf_free_skb(pkt
);
802 dhd_os_sdunlock_rxq(bus
->dhd
);
805 static void dhd_dongle_setmemsize(struct dhd_bus
*bus
, int mem_size
)
807 s32 min_size
= DONGLE_MIN_MEMSIZE
;
808 /* Restrict the memsize to user specified limit */
809 DHD_ERROR(("user: Restrict the dongle ram size to %d, min %d\n",
810 dhd_dongle_memsize
, min_size
));
811 if ((dhd_dongle_memsize
> min_size
) &&
812 (dhd_dongle_memsize
< (s32
) bus
->orig_ramsize
))
813 bus
->ramsize
= dhd_dongle_memsize
;
816 static int dhdsdio_set_siaddr_window(dhd_bus_t
*bus
, u32 address
)
819 bcmsdh_cfg_write(bus
->sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_SBADDRLOW
,
820 (address
>> 8) & SBSDIO_SBADDRLOW_MASK
, &err
);
822 bcmsdh_cfg_write(bus
->sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_SBADDRMID
,
823 (address
>> 16) & SBSDIO_SBADDRMID_MASK
, &err
);
825 bcmsdh_cfg_write(bus
->sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_SBADDRHIGH
,
826 (address
>> 24) & SBSDIO_SBADDRHIGH_MASK
,
831 /* Turn backplane clock on or off */
832 static int dhdsdio_htclk(dhd_bus_t
*bus
, bool on
, bool pendok
)
835 u8 clkctl
, clkreq
, devctl
;
838 DHD_TRACE(("%s: Enter\n", __func__
));
840 #if defined(OOB_INTR_ONLY)
847 /* Request HT Avail */
849 bus
->alp_only
? SBSDIO_ALP_AVAIL_REQ
: SBSDIO_HT_AVAIL_REQ
;
851 if ((bus
->ci
->chip
== BCM4329_CHIP_ID
)
852 && (bus
->ci
->chiprev
== 0))
853 clkreq
|= SBSDIO_FORCE_ALP
;
855 bcmsdh_cfg_write(sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_CHIPCLKCSR
,
858 DHD_ERROR(("%s: HT Avail request error: %d\n",
863 if (pendok
&& ((bus
->ci
->buscoretype
== PCMCIA_CORE_ID
)
864 && (bus
->ci
->buscorerev
== 9))) {
866 R_SDREG(dummy
, &bus
->regs
->clockctlstatus
, retries
);
869 /* Check current status */
871 bcmsdh_cfg_read(sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_CHIPCLKCSR
,
874 DHD_ERROR(("%s: HT Avail read error: %d\n",
879 /* Go to pending and await interrupt if appropriate */
880 if (!SBSDIO_CLKAV(clkctl
, bus
->alp_only
) && pendok
) {
881 /* Allow only clock-available interrupt */
883 bcmsdh_cfg_read(sdh
, SDIO_FUNC_1
, SBSDIO_DEVICE_CTL
,
886 DHD_ERROR(("%s: Devctl error setting CA: %d\n",
891 devctl
|= SBSDIO_DEVCTL_CA_INT_ONLY
;
892 bcmsdh_cfg_write(sdh
, SDIO_FUNC_1
, SBSDIO_DEVICE_CTL
,
894 DHD_INFO(("CLKCTL: set PENDING\n"));
895 bus
->clkstate
= CLK_PENDING
;
898 } else if (bus
->clkstate
== CLK_PENDING
) {
899 /* Cancel CA-only interrupt filter */
901 bcmsdh_cfg_read(sdh
, SDIO_FUNC_1
, SBSDIO_DEVICE_CTL
,
903 devctl
&= ~SBSDIO_DEVCTL_CA_INT_ONLY
;
904 bcmsdh_cfg_write(sdh
, SDIO_FUNC_1
, SBSDIO_DEVICE_CTL
,
908 /* Otherwise, wait here (polling) for HT Avail */
909 if (!SBSDIO_CLKAV(clkctl
, bus
->alp_only
)) {
910 SPINWAIT_SLEEP(sdioh_spinwait_sleep
,
912 bcmsdh_cfg_read(sdh
, SDIO_FUNC_1
,
913 SBSDIO_FUNC1_CHIPCLKCSR
,
915 !SBSDIO_CLKAV(clkctl
, bus
->alp_only
)),
916 PMU_MAX_TRANSITION_DLY
);
919 DHD_ERROR(("%s: HT Avail request error: %d\n",
923 if (!SBSDIO_CLKAV(clkctl
, bus
->alp_only
)) {
924 DHD_ERROR(("%s: HT Avail timeout (%d): clkctl 0x%02x\n",
925 __func__
, PMU_MAX_TRANSITION_DLY
, clkctl
));
929 /* Mark clock available */
930 bus
->clkstate
= CLK_AVAIL
;
931 DHD_INFO(("CLKCTL: turned ON\n"));
933 #if defined(DHD_DEBUG)
934 if (bus
->alp_only
== true) {
935 #if !defined(BCMLXSDMMC)
936 if (!SBSDIO_ALPONLY(clkctl
)) {
937 DHD_ERROR(("%s: HT Clock, when ALP Only\n",
940 #endif /* !defined(BCMLXSDMMC) */
942 if (SBSDIO_ALPONLY(clkctl
)) {
943 DHD_ERROR(("%s: HT Clock should be on.\n",
947 #endif /* defined (DHD_DEBUG) */
949 bus
->activity
= true;
953 if (bus
->clkstate
== CLK_PENDING
) {
954 /* Cancel CA-only interrupt filter */
956 bcmsdh_cfg_read(sdh
, SDIO_FUNC_1
, SBSDIO_DEVICE_CTL
,
958 devctl
&= ~SBSDIO_DEVCTL_CA_INT_ONLY
;
959 bcmsdh_cfg_write(sdh
, SDIO_FUNC_1
, SBSDIO_DEVICE_CTL
,
963 bus
->clkstate
= CLK_SDONLY
;
964 bcmsdh_cfg_write(sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_CHIPCLKCSR
,
966 DHD_INFO(("CLKCTL: turned OFF\n"));
968 DHD_ERROR(("%s: Failed access turning clock off: %d\n",
976 /* Change idle/active SD state */
977 static int dhdsdio_sdclk(dhd_bus_t
*bus
, bool on
)
979 DHD_TRACE(("%s: Enter\n", __func__
));
982 bus
->clkstate
= CLK_SDONLY
;
984 bus
->clkstate
= CLK_NONE
;
989 /* Transition SD and backplane clock readiness */
990 static int dhdsdio_clkctl(dhd_bus_t
*bus
, uint target
, bool pendok
)
993 uint oldstate
= bus
->clkstate
;
994 #endif /* DHD_DEBUG */
996 DHD_TRACE(("%s: Enter\n", __func__
));
998 /* Early exit if we're already there */
999 if (bus
->clkstate
== target
) {
1000 if (target
== CLK_AVAIL
) {
1001 dhd_os_wd_timer(bus
->dhd
, dhd_watchdog_ms
);
1002 bus
->activity
= true;
1009 /* Make sure SD clock is available */
1010 if (bus
->clkstate
== CLK_NONE
)
1011 dhdsdio_sdclk(bus
, true);
1012 /* Now request HT Avail on the backplane */
1013 dhdsdio_htclk(bus
, true, pendok
);
1014 dhd_os_wd_timer(bus
->dhd
, dhd_watchdog_ms
);
1015 bus
->activity
= true;
1019 /* Remove HT request, or bring up SD clock */
1020 if (bus
->clkstate
== CLK_NONE
)
1021 dhdsdio_sdclk(bus
, true);
1022 else if (bus
->clkstate
== CLK_AVAIL
)
1023 dhdsdio_htclk(bus
, false, false);
1025 DHD_ERROR(("dhdsdio_clkctl: request for %d -> %d\n",
1026 bus
->clkstate
, target
));
1027 dhd_os_wd_timer(bus
->dhd
, dhd_watchdog_ms
);
1031 /* Make sure to remove HT request */
1032 if (bus
->clkstate
== CLK_AVAIL
)
1033 dhdsdio_htclk(bus
, false, false);
1034 /* Now remove the SD clock */
1035 dhdsdio_sdclk(bus
, false);
1036 dhd_os_wd_timer(bus
->dhd
, 0);
1040 DHD_INFO(("dhdsdio_clkctl: %d -> %d\n", oldstate
, bus
->clkstate
));
1041 #endif /* DHD_DEBUG */
1046 int dhdsdio_bussleep(dhd_bus_t
*bus
, bool sleep
)
1048 bcmsdh_info_t
*sdh
= bus
->sdh
;
1049 struct sdpcmd_regs
*regs
= bus
->regs
;
1052 DHD_INFO(("dhdsdio_bussleep: request %s (currently %s)\n",
1053 (sleep
? "SLEEP" : "WAKE"),
1054 (bus
->sleeping
? "SLEEP" : "WAKE")));
1056 /* Done if we're already in the requested state */
1057 if (sleep
== bus
->sleeping
)
1060 /* Going to sleep: set the alarm and turn off the lights... */
1062 /* Don't sleep if something is pending */
1063 if (bus
->dpc_sched
|| bus
->rxskip
|| pktq_len(&bus
->txq
))
1066 /* Disable SDIO interrupts (no longer interested) */
1067 bcmsdh_intr_disable(bus
->sdh
);
1069 /* Make sure the controller has the bus up */
1070 dhdsdio_clkctl(bus
, CLK_AVAIL
, false);
1072 /* Tell device to start using OOB wakeup */
1073 W_SDREG(SMB_USE_OOB
, ®s
->tosbmailbox
, retries
);
1074 if (retries
> retry_limit
)
1075 DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
1077 /* Turn off our contribution to the HT clock request */
1078 dhdsdio_clkctl(bus
, CLK_SDONLY
, false);
1080 bcmsdh_cfg_write(sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_CHIPCLKCSR
,
1081 SBSDIO_FORCE_HW_CLKREQ_OFF
, NULL
);
1083 /* Isolate the bus */
1084 if (bus
->ci
->chip
!= BCM4329_CHIP_ID
1085 && bus
->ci
->chip
!= BCM4319_CHIP_ID
) {
1086 bcmsdh_cfg_write(sdh
, SDIO_FUNC_1
, SBSDIO_DEVICE_CTL
,
1087 SBSDIO_DEVCTL_PADS_ISO
, NULL
);
1091 bus
->sleeping
= true;
1094 /* Waking up: bus power up is ok, set local state */
1096 bcmsdh_cfg_write(sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_CHIPCLKCSR
,
1099 /* Force pad isolation off if possible
1100 (in case power never toggled) */
1101 if ((bus
->ci
->buscoretype
== PCMCIA_CORE_ID
)
1102 && (bus
->ci
->buscorerev
>= 10))
1103 bcmsdh_cfg_write(sdh
, SDIO_FUNC_1
, SBSDIO_DEVICE_CTL
, 0,
1106 /* Make sure the controller has the bus up */
1107 dhdsdio_clkctl(bus
, CLK_AVAIL
, false);
1109 /* Send misc interrupt to indicate OOB not needed */
1110 W_SDREG(0, ®s
->tosbmailboxdata
, retries
);
1111 if (retries
<= retry_limit
)
1112 W_SDREG(SMB_DEV_INT
, ®s
->tosbmailbox
, retries
);
1114 if (retries
> retry_limit
)
1115 DHD_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n"));
1117 /* Make sure we have SD bus access */
1118 dhdsdio_clkctl(bus
, CLK_SDONLY
, false);
1121 bus
->sleeping
= false;
1123 /* Enable interrupts again */
1124 if (bus
->intr
&& (bus
->dhd
->busstate
== DHD_BUS_DATA
)) {
1125 bus
->intdis
= false;
1126 bcmsdh_intr_enable(bus
->sdh
);
1133 #if defined(OOB_INTR_ONLY)
1134 void dhd_enable_oob_intr(struct dhd_bus
*bus
, bool enable
)
1137 bcmsdh_enable_hw_oob_intr(bus
->sdh
, enable
);
1139 sdpcmd_regs_t
*regs
= bus
->regs
;
1142 dhdsdio_clkctl(bus
, CLK_AVAIL
, false);
1143 if (enable
== true) {
1145 /* Tell device to start using OOB wakeup */
1146 W_SDREG(SMB_USE_OOB
, ®s
->tosbmailbox
, retries
);
1147 if (retries
> retry_limit
)
1148 DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
1151 /* Send misc interrupt to indicate OOB not needed */
1152 W_SDREG(0, ®s
->tosbmailboxdata
, retries
);
1153 if (retries
<= retry_limit
)
1154 W_SDREG(SMB_DEV_INT
, ®s
->tosbmailbox
, retries
);
1157 /* Turn off our contribution to the HT clock request */
1158 dhdsdio_clkctl(bus
, CLK_SDONLY
, false);
1159 #endif /* !defined(HW_OOB) */
1161 #endif /* defined(OOB_INTR_ONLY) */
1163 #define BUS_WAKE(bus) \
1165 if ((bus)->sleeping) \
1166 dhdsdio_bussleep((bus), false); \
1169 /* Writes a HW/SW header into the packet and sends it. */
1170 /* Assumes: (a) header space already there, (b) caller holds lock */
1171 static int dhdsdio_txpkt(dhd_bus_t
*bus
, struct sk_buff
*pkt
, uint chan
,
1180 struct sk_buff
*new;
1183 DHD_TRACE(("%s: Enter\n", __func__
));
1187 if (bus
->dhd
->dongle_reset
) {
1192 frame
= (u8
*) (pkt
->data
);
1194 /* Add alignment padding, allocate new packet if needed */
1195 pad
= ((unsigned long)frame
% DHD_SDALIGN
);
1197 if (skb_headroom(pkt
) < pad
) {
1198 DHD_INFO(("%s: insufficient headroom %d for %d pad\n",
1199 __func__
, skb_headroom(pkt
), pad
));
1200 bus
->dhd
->tx_realloc
++;
1201 new = brcmu_pkt_buf_get_skb(pkt
->len
+ DHD_SDALIGN
);
1203 DHD_ERROR(("%s: couldn't allocate new %d-byte "
1205 __func__
, pkt
->len
+ DHD_SDALIGN
));
1210 PKTALIGN(new, pkt
->len
, DHD_SDALIGN
);
1211 memcpy(new->data
, pkt
->data
, pkt
->len
);
1213 brcmu_pkt_buf_free_skb(pkt
);
1214 /* free the pkt if canned one is not used */
1217 frame
= (u8
*) (pkt
->data
);
1218 ASSERT(((unsigned long)frame
% DHD_SDALIGN
) == 0);
1222 frame
= (u8
*) (pkt
->data
);
1224 ASSERT((pad
+ SDPCM_HDRLEN
) <= (int)(pkt
->len
));
1225 memset(frame
, 0, pad
+ SDPCM_HDRLEN
);
1228 ASSERT(pad
< DHD_SDALIGN
);
1230 /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
1231 len
= (u16
) (pkt
->len
);
1232 *(u16
*) frame
= cpu_to_le16(len
);
1233 *(((u16
*) frame
) + 1) = cpu_to_le16(~len
);
1235 /* Software tag: channel, sequence number, data offset */
1237 ((chan
<< SDPCM_CHANNEL_SHIFT
) & SDPCM_CHANNEL_MASK
) | bus
->tx_seq
|
1239 SDPCM_HDRLEN
) << SDPCM_DOFFSET_SHIFT
) & SDPCM_DOFFSET_MASK
);
1241 put_unaligned_le32(swheader
, frame
+ SDPCM_FRAMETAG_LEN
);
1242 put_unaligned_le32(0, frame
+ SDPCM_FRAMETAG_LEN
+ sizeof(swheader
));
1245 tx_packets
[pkt
->priority
]++;
1246 if (DHD_BYTES_ON() &&
1247 (((DHD_CTL_ON() && (chan
== SDPCM_CONTROL_CHANNEL
)) ||
1248 (DHD_DATA_ON() && (chan
!= SDPCM_CONTROL_CHANNEL
))))) {
1249 printk(KERN_DEBUG
"Tx Frame:\n");
1250 print_hex_dump_bytes("", DUMP_PREFIX_OFFSET
, frame
, len
);
1251 } else if (DHD_HDRS_ON()) {
1252 printk(KERN_DEBUG
"TxHdr:\n");
1253 print_hex_dump_bytes("", DUMP_PREFIX_OFFSET
,
1254 frame
, min_t(u16
, len
, 16));
1258 /* Raise len to next SDIO block to eliminate tail command */
1259 if (bus
->roundup
&& bus
->blocksize
&& (len
> bus
->blocksize
)) {
1260 u16 pad
= bus
->blocksize
- (len
% bus
->blocksize
);
1261 if ((pad
<= bus
->roundup
) && (pad
< bus
->blocksize
))
1263 if (pad
<= skb_tailroom(pkt
))
1264 #endif /* NOTUSED */
1266 } else if (len
% DHD_SDALIGN
) {
1267 len
+= DHD_SDALIGN
- (len
% DHD_SDALIGN
);
1270 /* Some controllers have trouble with odd bytes -- round to even */
1271 if (forcealign
&& (len
& (ALIGNMENT
- 1))) {
1273 if (skb_tailroom(pkt
))
1275 len
= roundup(len
, ALIGNMENT
);
1278 DHD_ERROR(("%s: sending unrounded %d-byte packet\n",
1285 dhd_bcmsdh_send_buf(bus
, bcmsdh_cur_sbwad(sdh
), SDIO_FUNC_2
,
1286 F2SYNC
, frame
, len
, pkt
, NULL
, NULL
);
1288 ASSERT(ret
!= -BCME_PENDING
);
1291 /* On failure, abort the command
1292 and terminate the frame */
1293 DHD_INFO(("%s: sdio error %d, abort command and "
1294 "terminate frame.\n", __func__
, ret
));
1297 bcmsdh_abort(sdh
, SDIO_FUNC_2
);
1298 bcmsdh_cfg_write(sdh
, SDIO_FUNC_1
,
1299 SBSDIO_FUNC1_FRAMECTRL
, SFC_WF_TERM
,
1303 for (i
= 0; i
< 3; i
++) {
1305 hi
= bcmsdh_cfg_read(sdh
, SDIO_FUNC_1
,
1306 SBSDIO_FUNC1_WFRAMEBCHI
,
1308 lo
= bcmsdh_cfg_read(sdh
, SDIO_FUNC_1
,
1309 SBSDIO_FUNC1_WFRAMEBCLO
,
1311 bus
->f1regdata
+= 2;
1312 if ((hi
== 0) && (lo
== 0))
1318 bus
->tx_seq
= (bus
->tx_seq
+ 1) % SDPCM_SEQUENCE_WRAP
;
1320 } while ((ret
< 0) && retrydata
&& retries
++ < TXRETRIES
);
1323 /* restore pkt buffer pointer before calling tx complete routine */
1324 skb_pull(pkt
, SDPCM_HDRLEN
+ pad
);
1325 dhd_os_sdunlock(bus
->dhd
);
1326 dhd_txcomplete(bus
->dhd
, pkt
, ret
!= 0);
1327 dhd_os_sdlock(bus
->dhd
);
1330 brcmu_pkt_buf_free_skb(pkt
);
1335 int dhd_bus_txdata(struct dhd_bus
*bus
, struct sk_buff
*pkt
)
1340 DHD_TRACE(("%s: Enter\n", __func__
));
1345 /* Push the test header if doing loopback */
1346 if (bus
->ext_loop
) {
1348 skb_push(pkt
, SDPCM_TEST_HDRLEN
);
1350 *data
++ = SDPCM_TEST_ECHOREQ
;
1351 *data
++ = (u8
) bus
->loopid
++;
1352 *data
++ = (datalen
>> 0);
1353 *data
++ = (datalen
>> 8);
1354 datalen
+= SDPCM_TEST_HDRLEN
;
1358 /* Add space for the header */
1359 skb_push(pkt
, SDPCM_HDRLEN
);
1360 ASSERT(IS_ALIGNED((unsigned long)(pkt
->data
), 2));
1362 prec
= PRIO2PREC((pkt
->priority
& PRIOMASK
));
1364 /* Check for existing queue, current flow-control,
1365 pending event, or pending clock */
1366 if (dhd_deferred_tx
|| bus
->fcstate
|| pktq_len(&bus
->txq
)
1367 || bus
->dpc_sched
|| (!DATAOK(bus
))
1368 || (bus
->flowcontrol
& NBITVAL(prec
))
1369 || (bus
->clkstate
!= CLK_AVAIL
)) {
1370 DHD_TRACE(("%s: deferring pktq len %d\n", __func__
,
1371 pktq_len(&bus
->txq
)));
1374 /* Priority based enq */
1375 dhd_os_sdlock_txq(bus
->dhd
);
1376 if (dhd_prec_enq(bus
->dhd
, &bus
->txq
, pkt
, prec
) == false) {
1377 skb_pull(pkt
, SDPCM_HDRLEN
);
1378 dhd_txcomplete(bus
->dhd
, pkt
, false);
1379 brcmu_pkt_buf_free_skb(pkt
);
1380 DHD_ERROR(("%s: out of bus->txq !!!\n", __func__
));
1385 dhd_os_sdunlock_txq(bus
->dhd
);
1387 if (pktq_len(&bus
->txq
) >= TXHI
)
1388 dhd_txflowcontrol(bus
->dhd
, 0, ON
);
1391 if (pktq_plen(&bus
->txq
, prec
) > qcount
[prec
])
1392 qcount
[prec
] = pktq_plen(&bus
->txq
, prec
);
1394 /* Schedule DPC if needed to send queued packet(s) */
1395 if (dhd_deferred_tx
&& !bus
->dpc_sched
) {
1396 bus
->dpc_sched
= true;
1397 dhd_sched_dpc(bus
->dhd
);
1400 /* Lock: we're about to use shared data/code (and SDIO) */
1401 dhd_os_sdlock(bus
->dhd
);
1403 /* Otherwise, send it now */
1405 /* Make sure back plane ht clk is on, no pending allowed */
1406 dhdsdio_clkctl(bus
, CLK_AVAIL
, true);
1409 DHD_TRACE(("%s: calling txpkt\n", __func__
));
1410 ret
= dhdsdio_txpkt(bus
, pkt
, SDPCM_DATA_CHANNEL
, true);
1412 ret
= dhdsdio_txpkt(bus
, pkt
,
1413 (bus
->ext_loop
? SDPCM_TEST_CHANNEL
:
1414 SDPCM_DATA_CHANNEL
), true);
1417 bus
->dhd
->tx_errors
++;
1419 bus
->dhd
->dstats
.tx_bytes
+= datalen
;
1421 if ((bus
->idletime
== DHD_IDLE_IMMEDIATE
) && !bus
->dpc_sched
) {
1422 bus
->activity
= false;
1423 dhdsdio_clkctl(bus
, CLK_NONE
, true);
1426 dhd_os_sdunlock(bus
->dhd
);
1432 static uint
dhdsdio_sendfromq(dhd_bus_t
*bus
, uint maxframes
)
1434 struct sk_buff
*pkt
;
1437 int ret
= 0, prec_out
;
1442 dhd_pub_t
*dhd
= bus
->dhd
;
1443 struct sdpcmd_regs
*regs
= bus
->regs
;
1445 DHD_TRACE(("%s: Enter\n", __func__
));
1447 tx_prec_map
= ~bus
->flowcontrol
;
1449 /* Send frames until the limit or some other event */
1450 for (cnt
= 0; (cnt
< maxframes
) && DATAOK(bus
); cnt
++) {
1451 dhd_os_sdlock_txq(bus
->dhd
);
1452 pkt
= brcmu_pktq_mdeq(&bus
->txq
, tx_prec_map
, &prec_out
);
1454 dhd_os_sdunlock_txq(bus
->dhd
);
1457 dhd_os_sdunlock_txq(bus
->dhd
);
1458 datalen
= pkt
->len
- SDPCM_HDRLEN
;
1461 ret
= dhdsdio_txpkt(bus
, pkt
, SDPCM_DATA_CHANNEL
, true);
1463 ret
= dhdsdio_txpkt(bus
, pkt
,
1464 (bus
->ext_loop
? SDPCM_TEST_CHANNEL
:
1465 SDPCM_DATA_CHANNEL
), true);
1468 bus
->dhd
->tx_errors
++;
1470 bus
->dhd
->dstats
.tx_bytes
+= datalen
;
1472 /* In poll mode, need to check for other events */
1473 if (!bus
->intr
&& cnt
) {
1474 /* Check device status, signal pending interrupt */
1475 R_SDREG(intstatus
, ®s
->intstatus
, retries
);
1477 if (bcmsdh_regfail(bus
->sdh
))
1479 if (intstatus
& bus
->hostintmask
)
1484 /* Deflow-control stack if needed */
1485 if (dhd
->up
&& (dhd
->busstate
== DHD_BUS_DATA
) &&
1486 dhd
->txoff
&& (pktq_len(&bus
->txq
) < TXLOW
))
1487 dhd_txflowcontrol(dhd
, 0, OFF
);
1492 int dhd_bus_txctl(struct dhd_bus
*bus
, unsigned char *msg
, uint msglen
)
1498 bcmsdh_info_t
*sdh
= bus
->sdh
;
1503 DHD_TRACE(("%s: Enter\n", __func__
));
1505 if (bus
->dhd
->dongle_reset
)
1508 /* Back the pointer to make a room for bus header */
1509 frame
= msg
- SDPCM_HDRLEN
;
1510 len
= (msglen
+= SDPCM_HDRLEN
);
1512 /* Add alignment padding (optional for ctl frames) */
1514 doff
= ((unsigned long)frame
% DHD_SDALIGN
);
1519 memset(frame
, 0, doff
+ SDPCM_HDRLEN
);
1521 ASSERT(doff
< DHD_SDALIGN
);
1523 doff
+= SDPCM_HDRLEN
;
1525 /* Round send length to next SDIO block */
1526 if (bus
->roundup
&& bus
->blocksize
&& (len
> bus
->blocksize
)) {
1527 u16 pad
= bus
->blocksize
- (len
% bus
->blocksize
);
1528 if ((pad
<= bus
->roundup
) && (pad
< bus
->blocksize
))
1530 } else if (len
% DHD_SDALIGN
) {
1531 len
+= DHD_SDALIGN
- (len
% DHD_SDALIGN
);
1534 /* Satisfy length-alignment requirements */
1535 if (forcealign
&& (len
& (ALIGNMENT
- 1)))
1536 len
= roundup(len
, ALIGNMENT
);
1538 ASSERT(IS_ALIGNED((unsigned long)frame
, 2));
1540 /* Need to lock here to protect txseq and SDIO tx calls */
1541 dhd_os_sdlock(bus
->dhd
);
1545 /* Make sure backplane clock is on */
1546 dhdsdio_clkctl(bus
, CLK_AVAIL
, false);
1548 /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
1549 *(u16
*) frame
= cpu_to_le16((u16
) msglen
);
1550 *(((u16
*) frame
) + 1) = cpu_to_le16(~msglen
);
1552 /* Software tag: channel, sequence number, data offset */
1554 ((SDPCM_CONTROL_CHANNEL
<< SDPCM_CHANNEL_SHIFT
) &
1556 | bus
->tx_seq
| ((doff
<< SDPCM_DOFFSET_SHIFT
) &
1557 SDPCM_DOFFSET_MASK
);
1558 put_unaligned_le32(swheader
, frame
+ SDPCM_FRAMETAG_LEN
);
1559 put_unaligned_le32(0, frame
+ SDPCM_FRAMETAG_LEN
+ sizeof(swheader
));
1562 DHD_INFO(("%s: No bus credit bus->tx_max %d, bus->tx_seq %d\n",
1563 __func__
, bus
->tx_max
, bus
->tx_seq
));
1564 bus
->ctrl_frame_stat
= true;
1566 bus
->ctrl_frame_buf
= frame
;
1567 bus
->ctrl_frame_len
= len
;
1569 dhd_wait_for_event(bus
->dhd
, &bus
->ctrl_frame_stat
);
1571 if (bus
->ctrl_frame_stat
== false) {
1572 DHD_INFO(("%s: ctrl_frame_stat == false\n", __func__
));
1575 DHD_INFO(("%s: ctrl_frame_stat == true\n", __func__
));
1582 if (DHD_BYTES_ON() && DHD_CTL_ON()) {
1583 printk(KERN_DEBUG
"Tx Frame:\n");
1584 print_hex_dump_bytes("", DUMP_PREFIX_OFFSET
,
1586 } else if (DHD_HDRS_ON()) {
1587 printk(KERN_DEBUG
"TxHdr:\n");
1588 print_hex_dump_bytes("", DUMP_PREFIX_OFFSET
,
1589 frame
, min_t(u16
, len
, 16));
1594 bus
->ctrl_frame_stat
= false;
1596 dhd_bcmsdh_send_buf(bus
, bcmsdh_cur_sbwad(sdh
),
1597 SDIO_FUNC_2
, F2SYNC
, frame
, len
,
1600 ASSERT(ret
!= -BCME_PENDING
);
1603 /* On failure, abort the command and
1604 terminate the frame */
1605 DHD_INFO(("%s: sdio error %d, abort command and terminate frame.\n",
1609 bcmsdh_abort(sdh
, SDIO_FUNC_2
);
1611 bcmsdh_cfg_write(sdh
, SDIO_FUNC_1
,
1612 SBSDIO_FUNC1_FRAMECTRL
,
1616 for (i
= 0; i
< 3; i
++) {
1618 hi
= bcmsdh_cfg_read(sdh
, SDIO_FUNC_1
,
1619 SBSDIO_FUNC1_WFRAMEBCHI
,
1621 lo
= bcmsdh_cfg_read(sdh
, SDIO_FUNC_1
,
1622 SBSDIO_FUNC1_WFRAMEBCLO
,
1624 bus
->f1regdata
+= 2;
1625 if ((hi
== 0) && (lo
== 0))
1632 (bus
->tx_seq
+ 1) % SDPCM_SEQUENCE_WRAP
;
1634 } while ((ret
< 0) && retries
++ < TXRETRIES
);
1637 if ((bus
->idletime
== DHD_IDLE_IMMEDIATE
) && !bus
->dpc_sched
) {
1638 bus
->activity
= false;
1639 dhdsdio_clkctl(bus
, CLK_NONE
, true);
1642 dhd_os_sdunlock(bus
->dhd
);
1645 bus
->dhd
->tx_ctlerrs
++;
1647 bus
->dhd
->tx_ctlpkts
++;
1649 return ret
? -EIO
: 0;
1652 int dhd_bus_rxctl(struct dhd_bus
*bus
, unsigned char *msg
, uint msglen
)
1658 DHD_TRACE(("%s: Enter\n", __func__
));
1660 if (bus
->dhd
->dongle_reset
)
1663 /* Wait until control frame is available */
1664 timeleft
= dhd_os_ioctl_resp_wait(bus
->dhd
, &bus
->rxlen
, &pending
);
1666 dhd_os_sdlock(bus
->dhd
);
1668 memcpy(msg
, bus
->rxctl
, min(msglen
, rxlen
));
1670 dhd_os_sdunlock(bus
->dhd
);
1673 DHD_CTL(("%s: resumed on rxctl frame, got %d expected %d\n",
1674 __func__
, rxlen
, msglen
));
1675 } else if (timeleft
== 0) {
1676 DHD_ERROR(("%s: resumed on timeout\n", __func__
));
1678 dhd_os_sdlock(bus
->dhd
);
1679 dhdsdio_checkdied(bus
, NULL
, 0);
1680 dhd_os_sdunlock(bus
->dhd
);
1681 #endif /* DHD_DEBUG */
1682 } else if (pending
== true) {
1683 DHD_CTL(("%s: cancelled\n", __func__
));
1684 return -ERESTARTSYS
;
1686 DHD_CTL(("%s: resumed for unknown reason?\n", __func__
));
1688 dhd_os_sdlock(bus
->dhd
);
1689 dhdsdio_checkdied(bus
, NULL
, 0);
1690 dhd_os_sdunlock(bus
->dhd
);
1691 #endif /* DHD_DEBUG */
1695 bus
->dhd
->rx_ctlpkts
++;
1697 bus
->dhd
->rx_ctlerrs
++;
1699 return rxlen
? (int)rxlen
: -ETIMEDOUT
;
1738 const struct brcmu_iovar dhdsdio_iovars
[] = {
1739 {"intr", IOV_INTR
, 0, IOVT_BOOL
, 0},
1740 {"sleep", IOV_SLEEP
, 0, IOVT_BOOL
, 0},
1741 {"pollrate", IOV_POLLRATE
, 0, IOVT_UINT32
, 0},
1742 {"idletime", IOV_IDLETIME
, 0, IOVT_INT32
, 0},
1743 {"idleclock", IOV_IDLECLOCK
, 0, IOVT_INT32
, 0},
1744 {"sd1idle", IOV_SD1IDLE
, 0, IOVT_BOOL
, 0},
1745 {"membytes", IOV_MEMBYTES
, 0, IOVT_BUFFER
, 2 * sizeof(int)},
1746 {"memsize", IOV_MEMSIZE
, 0, IOVT_UINT32
, 0},
1747 {"download", IOV_DOWNLOAD
, 0, IOVT_BOOL
, 0},
1748 {"vars", IOV_VARS
, 0, IOVT_BUFFER
, 0},
1749 {"sdiod_drive", IOV_SDIOD_DRIVE
, 0, IOVT_UINT32
, 0},
1750 {"readahead", IOV_READAHEAD
, 0, IOVT_BOOL
, 0},
1751 {"sdrxchain", IOV_SDRXCHAIN
, 0, IOVT_BOOL
, 0},
1752 {"alignctl", IOV_ALIGNCTL
, 0, IOVT_BOOL
, 0},
1753 {"sdalign", IOV_SDALIGN
, 0, IOVT_BOOL
, 0},
1754 {"devreset", IOV_DEVRESET
, 0, IOVT_BOOL
, 0},
1756 {"sdreg", IOV_SDREG
, 0, IOVT_BUFFER
, sizeof(sdreg_t
)}
1758 {"sbreg", IOV_SBREG
, 0, IOVT_BUFFER
, sizeof(sdreg_t
)}
1760 {"sd_cis", IOV_SDCIS
, 0, IOVT_BUFFER
, DHD_IOCTL_MAXLEN
}
1762 {"forcealign", IOV_FORCEEVEN
, 0, IOVT_BOOL
, 0}
1764 {"txbound", IOV_TXBOUND
, 0, IOVT_UINT32
, 0}
1766 {"rxbound", IOV_RXBOUND
, 0, IOVT_UINT32
, 0}
1768 {"txminmax", IOV_TXMINMAX
, 0, IOVT_UINT32
, 0}
1770 {"cpu", IOV_CPU
, 0, IOVT_BOOL
, 0}
1773 {"checkdied", IOV_CHECKDIED
, 0, IOVT_BUFFER
, 0}
1775 #endif /* DHD_DEBUG */
1776 #endif /* DHD_DEBUG */
1778 {"extloop", IOV_EXTLOOP
, 0, IOVT_BOOL
, 0}
1780 {"pktgen", IOV_PKTGEN
, 0, IOVT_BUFFER
, sizeof(dhd_pktgen_t
)}
1788 dhd_dump_pct(struct brcmu_strbuf
*strbuf
, char *desc
, uint num
, uint div
)
1793 brcmu_bprintf(strbuf
, "%s N/A", desc
);
1796 q2
= (100 * (num
- (q1
* div
))) / div
;
1797 brcmu_bprintf(strbuf
, "%s %d.%02d", desc
, q1
, q2
);
1801 void dhd_bus_dump(dhd_pub_t
*dhdp
, struct brcmu_strbuf
*strbuf
)
1803 dhd_bus_t
*bus
= dhdp
->bus
;
1805 brcmu_bprintf(strbuf
, "Bus SDIO structure:\n");
1806 brcmu_bprintf(strbuf
,
1807 "hostintmask 0x%08x intstatus 0x%08x sdpcm_ver %d\n",
1808 bus
->hostintmask
, bus
->intstatus
, bus
->sdpcm_ver
);
1809 brcmu_bprintf(strbuf
,
1810 "fcstate %d qlen %d tx_seq %d, max %d, rxskip %d rxlen %d rx_seq %d\n",
1811 bus
->fcstate
, pktq_len(&bus
->txq
), bus
->tx_seq
, bus
->tx_max
,
1812 bus
->rxskip
, bus
->rxlen
, bus
->rx_seq
);
1813 brcmu_bprintf(strbuf
, "intr %d intrcount %d lastintrs %d spurious %d\n",
1814 bus
->intr
, bus
->intrcount
, bus
->lastintrs
, bus
->spurious
);
1815 brcmu_bprintf(strbuf
, "pollrate %d pollcnt %d regfails %d\n",
1816 bus
->pollrate
, bus
->pollcnt
, bus
->regfails
);
1818 brcmu_bprintf(strbuf
, "\nAdditional counters:\n");
1819 brcmu_bprintf(strbuf
,
1820 "tx_sderrs %d fcqueued %d rxrtx %d rx_toolong %d rxc_errors %d\n",
1821 bus
->tx_sderrs
, bus
->fcqueued
, bus
->rxrtx
, bus
->rx_toolong
,
1823 brcmu_bprintf(strbuf
, "rx_hdrfail %d badhdr %d badseq %d\n",
1824 bus
->rx_hdrfail
, bus
->rx_badhdr
, bus
->rx_badseq
);
1825 brcmu_bprintf(strbuf
, "fc_rcvd %d, fc_xoff %d, fc_xon %d\n",
1826 bus
->fc_rcvd
, bus
->fc_xoff
, bus
->fc_xon
);
1827 brcmu_bprintf(strbuf
, "rxglomfail %d, rxglomframes %d, rxglompkts %d\n",
1828 bus
->rxglomfail
, bus
->rxglomframes
, bus
->rxglompkts
);
1829 brcmu_bprintf(strbuf
, "f2rx (hdrs/data) %d (%d/%d), f2tx %d f1regs"
1831 (bus
->f2rxhdrs
+ bus
->f2rxdata
), bus
->f2rxhdrs
,
1832 bus
->f2rxdata
, bus
->f2txdata
, bus
->f1regdata
);
1834 dhd_dump_pct(strbuf
, "\nRx: pkts/f2rd", bus
->dhd
->rx_packets
,
1835 (bus
->f2rxhdrs
+ bus
->f2rxdata
));
1836 dhd_dump_pct(strbuf
, ", pkts/f1sd", bus
->dhd
->rx_packets
,
1838 dhd_dump_pct(strbuf
, ", pkts/sd", bus
->dhd
->rx_packets
,
1839 (bus
->f2rxhdrs
+ bus
->f2rxdata
+ bus
->f1regdata
));
1840 dhd_dump_pct(strbuf
, ", pkts/int", bus
->dhd
->rx_packets
,
1842 brcmu_bprintf(strbuf
, "\n");
1844 dhd_dump_pct(strbuf
, "Rx: glom pct", (100 * bus
->rxglompkts
),
1845 bus
->dhd
->rx_packets
);
1846 dhd_dump_pct(strbuf
, ", pkts/glom", bus
->rxglompkts
,
1848 brcmu_bprintf(strbuf
, "\n");
1850 dhd_dump_pct(strbuf
, "Tx: pkts/f2wr", bus
->dhd
->tx_packets
,
1852 dhd_dump_pct(strbuf
, ", pkts/f1sd", bus
->dhd
->tx_packets
,
1854 dhd_dump_pct(strbuf
, ", pkts/sd", bus
->dhd
->tx_packets
,
1855 (bus
->f2txdata
+ bus
->f1regdata
));
1856 dhd_dump_pct(strbuf
, ", pkts/int", bus
->dhd
->tx_packets
,
1858 brcmu_bprintf(strbuf
, "\n");
1860 dhd_dump_pct(strbuf
, "Total: pkts/f2rw",
1861 (bus
->dhd
->tx_packets
+ bus
->dhd
->rx_packets
),
1862 (bus
->f2txdata
+ bus
->f2rxhdrs
+ bus
->f2rxdata
));
1863 dhd_dump_pct(strbuf
, ", pkts/f1sd",
1864 (bus
->dhd
->tx_packets
+ bus
->dhd
->rx_packets
),
1866 dhd_dump_pct(strbuf
, ", pkts/sd",
1867 (bus
->dhd
->tx_packets
+ bus
->dhd
->rx_packets
),
1868 (bus
->f2txdata
+ bus
->f2rxhdrs
+ bus
->f2rxdata
+
1870 dhd_dump_pct(strbuf
, ", pkts/int",
1871 (bus
->dhd
->tx_packets
+ bus
->dhd
->rx_packets
),
1873 brcmu_bprintf(strbuf
, "\n\n");
1877 if (bus
->pktgen_count
) {
1878 brcmu_bprintf(strbuf
, "pktgen config and count:\n");
1879 brcmu_bprintf(strbuf
,
1880 "freq %d count %d print %d total %d min %d len %d\n",
1881 bus
->pktgen_freq
, bus
->pktgen_count
,
1882 bus
->pktgen_print
, bus
->pktgen_total
,
1883 bus
->pktgen_minlen
, bus
->pktgen_maxlen
);
1884 brcmu_bprintf(strbuf
, "send attempts %d rcvd %d fail %d\n",
1885 bus
->pktgen_sent
, bus
->pktgen_rcvd
,
1890 brcmu_bprintf(strbuf
, "dpc_sched %d host interrupt%spending\n",
1892 (bcmsdh_intr_pending(bus
->sdh
) ? " " : " not "));
1893 brcmu_bprintf(strbuf
, "blocksize %d roundup %d\n", bus
->blocksize
,
1895 #endif /* DHD_DEBUG */
1896 brcmu_bprintf(strbuf
,
1897 "clkstate %d activity %d idletime %d idlecount %d sleeping %d\n",
1898 bus
->clkstate
, bus
->activity
, bus
->idletime
, bus
->idlecount
,
1902 void dhd_bus_clearcounts(dhd_pub_t
*dhdp
)
1904 dhd_bus_t
*bus
= (dhd_bus_t
*) dhdp
->bus
;
1906 bus
->intrcount
= bus
->lastintrs
= bus
->spurious
= bus
->regfails
= 0;
1907 bus
->rxrtx
= bus
->rx_toolong
= bus
->rxc_errors
= 0;
1908 bus
->rx_hdrfail
= bus
->rx_badhdr
= bus
->rx_badseq
= 0;
1909 bus
->tx_sderrs
= bus
->fc_rcvd
= bus
->fc_xoff
= bus
->fc_xon
= 0;
1910 bus
->rxglomfail
= bus
->rxglomframes
= bus
->rxglompkts
= 0;
1911 bus
->f2rxhdrs
= bus
->f2rxdata
= bus
->f2txdata
= bus
->f1regdata
= 0;
1915 static int dhdsdio_pktgen_get(dhd_bus_t
*bus
, u8
*arg
)
1917 dhd_pktgen_t pktgen
;
1919 pktgen
.version
= DHD_PKTGEN_VERSION
;
1920 pktgen
.freq
= bus
->pktgen_freq
;
1921 pktgen
.count
= bus
->pktgen_count
;
1922 pktgen
.print
= bus
->pktgen_print
;
1923 pktgen
.total
= bus
->pktgen_total
;
1924 pktgen
.minlen
= bus
->pktgen_minlen
;
1925 pktgen
.maxlen
= bus
->pktgen_maxlen
;
1926 pktgen
.numsent
= bus
->pktgen_sent
;
1927 pktgen
.numrcvd
= bus
->pktgen_rcvd
;
1928 pktgen
.numfail
= bus
->pktgen_fail
;
1929 pktgen
.mode
= bus
->pktgen_mode
;
1930 pktgen
.stop
= bus
->pktgen_stop
;
1932 memcpy(arg
, &pktgen
, sizeof(pktgen
));
1937 static int dhdsdio_pktgen_set(dhd_bus_t
*bus
, u8
*arg
)
1939 dhd_pktgen_t pktgen
;
1940 uint oldcnt
, oldmode
;
1942 memcpy(&pktgen
, arg
, sizeof(pktgen
));
1943 if (pktgen
.version
!= DHD_PKTGEN_VERSION
)
1946 oldcnt
= bus
->pktgen_count
;
1947 oldmode
= bus
->pktgen_mode
;
1949 bus
->pktgen_freq
= pktgen
.freq
;
1950 bus
->pktgen_count
= pktgen
.count
;
1951 bus
->pktgen_print
= pktgen
.print
;
1952 bus
->pktgen_total
= pktgen
.total
;
1953 bus
->pktgen_minlen
= pktgen
.minlen
;
1954 bus
->pktgen_maxlen
= pktgen
.maxlen
;
1955 bus
->pktgen_mode
= pktgen
.mode
;
1956 bus
->pktgen_stop
= pktgen
.stop
;
1958 bus
->pktgen_tick
= bus
->pktgen_ptick
= 0;
1959 bus
->pktgen_len
= max(bus
->pktgen_len
, bus
->pktgen_minlen
);
1960 bus
->pktgen_len
= min(bus
->pktgen_len
, bus
->pktgen_maxlen
);
1962 /* Clear counts for a new pktgen (mode change, or was stopped) */
1963 if (bus
->pktgen_count
&& (!oldcnt
|| oldmode
!= bus
->pktgen_mode
))
1964 bus
->pktgen_sent
= bus
->pktgen_rcvd
= bus
->pktgen_fail
= 0;
1971 dhdsdio_membytes(dhd_bus_t
*bus
, bool write
, u32 address
, u8
*data
,
1978 /* Determine initial transfer parameters */
1979 sdaddr
= address
& SBSDIO_SB_OFT_ADDR_MASK
;
1980 if ((sdaddr
+ size
) & SBSDIO_SBWINDOW_MASK
)
1981 dsize
= (SBSDIO_SB_OFT_ADDR_LIMIT
- sdaddr
);
1985 /* Set the backplane window to include the start address */
1986 bcmerror
= dhdsdio_set_siaddr_window(bus
, address
);
1988 DHD_ERROR(("%s: window change failed\n", __func__
));
1992 /* Do the transfer(s) */
1994 DHD_INFO(("%s: %s %d bytes at offset 0x%08x in window 0x%08x\n",
1995 __func__
, (write
? "write" : "read"), dsize
,
1996 sdaddr
, (address
& SBSDIO_SBWINDOW_MASK
)));
1998 bcmsdh_rwdata(bus
->sdh
, write
, sdaddr
, data
, dsize
);
2000 DHD_ERROR(("%s: membytes transfer failed\n", __func__
));
2004 /* Adjust for next transfer (if any) */
2009 bcmerror
= dhdsdio_set_siaddr_window(bus
, address
);
2011 DHD_ERROR(("%s: window change failed\n",
2016 dsize
= min_t(uint
, SBSDIO_SB_OFT_ADDR_LIMIT
, size
);
2021 /* Return the window to backplane enumeration space for core access */
2022 if (dhdsdio_set_siaddr_window(bus
, bcmsdh_cur_sbwad(bus
->sdh
))) {
2023 DHD_ERROR(("%s: FAILED to set window back to 0x%x\n",
2024 __func__
, bcmsdh_cur_sbwad(bus
->sdh
)));
2031 static int dhdsdio_readshared(dhd_bus_t
*bus
, struct sdpcm_shared
*sh
)
2036 /* Read last word in memory to determine address of
2037 sdpcm_shared structure */
2038 rv
= dhdsdio_membytes(bus
, false, bus
->ramsize
- 4, (u8
*)&addr
, 4);
2042 addr
= le32_to_cpu(addr
);
2044 DHD_INFO(("sdpcm_shared address 0x%08X\n", addr
));
2047 * Check if addr is valid.
2048 * NVRAM length at the end of memory should have been overwritten.
2050 if (addr
== 0 || ((~addr
>> 16) & 0xffff) == (addr
& 0xffff)) {
2051 DHD_ERROR(("%s: address (0x%08x) of sdpcm_shared invalid\n",
2056 /* Read rte_shared structure */
2057 rv
= dhdsdio_membytes(bus
, false, addr
, (u8
*) sh
,
2058 sizeof(struct sdpcm_shared
));
2063 sh
->flags
= le32_to_cpu(sh
->flags
);
2064 sh
->trap_addr
= le32_to_cpu(sh
->trap_addr
);
2065 sh
->assert_exp_addr
= le32_to_cpu(sh
->assert_exp_addr
);
2066 sh
->assert_file_addr
= le32_to_cpu(sh
->assert_file_addr
);
2067 sh
->assert_line
= le32_to_cpu(sh
->assert_line
);
2068 sh
->console_addr
= le32_to_cpu(sh
->console_addr
);
2069 sh
->msgtrace_addr
= le32_to_cpu(sh
->msgtrace_addr
);
2071 if ((sh
->flags
& SDPCM_SHARED_VERSION_MASK
) != SDPCM_SHARED_VERSION
) {
2072 DHD_ERROR(("%s: sdpcm_shared version %d in dhd "
2073 "is different than sdpcm_shared version %d in dongle\n",
2074 __func__
, SDPCM_SHARED_VERSION
,
2075 sh
->flags
& SDPCM_SHARED_VERSION_MASK
));
2082 static int dhdsdio_checkdied(dhd_bus_t
*bus
, u8
*data
, uint size
)
2086 char *mbuffer
= NULL
;
2087 uint maxstrlen
= 256;
2090 struct sdpcm_shared sdpcm_shared
;
2091 struct brcmu_strbuf strbuf
;
2093 DHD_TRACE(("%s: Enter\n", __func__
));
2097 * Called after a rx ctrl timeout. "data" is NULL.
2098 * allocate memory to trace the trap or assert.
2101 mbuffer
= data
= kmalloc(msize
, GFP_ATOMIC
);
2102 if (mbuffer
== NULL
) {
2103 DHD_ERROR(("%s: kmalloc(%d) failed\n", __func__
,
2110 str
= kmalloc(maxstrlen
, GFP_ATOMIC
);
2112 DHD_ERROR(("%s: kmalloc(%d) failed\n", __func__
, maxstrlen
));
2117 bcmerror
= dhdsdio_readshared(bus
, &sdpcm_shared
);
2121 brcmu_binit(&strbuf
, data
, size
);
2123 brcmu_bprintf(&strbuf
,
2124 "msgtrace address : 0x%08X\nconsole address : 0x%08X\n",
2125 sdpcm_shared
.msgtrace_addr
, sdpcm_shared
.console_addr
);
2127 if ((sdpcm_shared
.flags
& SDPCM_SHARED_ASSERT_BUILT
) == 0) {
2128 /* NOTE: Misspelled assert is intentional - DO NOT FIX.
2129 * (Avoids conflict with real asserts for programmatic
2130 * parsing of output.)
2132 brcmu_bprintf(&strbuf
, "Assrt not built in dongle\n");
2135 if ((sdpcm_shared
.flags
& (SDPCM_SHARED_ASSERT
| SDPCM_SHARED_TRAP
)) ==
2137 /* NOTE: Misspelled assert is intentional - DO NOT FIX.
2138 * (Avoids conflict with real asserts for programmatic
2139 * parsing of output.)
2141 brcmu_bprintf(&strbuf
, "No trap%s in dongle",
2142 (sdpcm_shared
.flags
& SDPCM_SHARED_ASSERT_BUILT
)
2145 if (sdpcm_shared
.flags
& SDPCM_SHARED_ASSERT
) {
2146 /* Download assert */
2147 brcmu_bprintf(&strbuf
, "Dongle assert");
2148 if (sdpcm_shared
.assert_exp_addr
!= 0) {
2150 bcmerror
= dhdsdio_membytes(bus
, false,
2151 sdpcm_shared
.assert_exp_addr
,
2152 (u8
*) str
, maxstrlen
);
2156 str
[maxstrlen
- 1] = '\0';
2157 brcmu_bprintf(&strbuf
, " expr \"%s\"", str
);
2160 if (sdpcm_shared
.assert_file_addr
!= 0) {
2162 bcmerror
= dhdsdio_membytes(bus
, false,
2163 sdpcm_shared
.assert_file_addr
,
2164 (u8
*) str
, maxstrlen
);
2168 str
[maxstrlen
- 1] = '\0';
2169 brcmu_bprintf(&strbuf
, " file \"%s\"", str
);
2172 brcmu_bprintf(&strbuf
, " line %d ",
2173 sdpcm_shared
.assert_line
);
2176 if (sdpcm_shared
.flags
& SDPCM_SHARED_TRAP
) {
2177 bcmerror
= dhdsdio_membytes(bus
, false,
2178 sdpcm_shared
.trap_addr
, (u8
*)&tr
,
2183 brcmu_bprintf(&strbuf
,
2184 "Dongle trap type 0x%x @ epc 0x%x, cpsr 0x%x, spsr 0x%x, sp 0x%x,"
2185 "lp 0x%x, rpc 0x%x Trap offset 0x%x, "
2186 "r0 0x%x, r1 0x%x, r2 0x%x, r3 0x%x, r4 0x%x, r5 0x%x, r6 0x%x, r7 0x%x\n",
2187 tr
.type
, tr
.epc
, tr
.cpsr
, tr
.spsr
, tr
.r13
,
2188 tr
.r14
, tr
.pc
, sdpcm_shared
.trap_addr
,
2189 tr
.r0
, tr
.r1
, tr
.r2
, tr
.r3
, tr
.r4
, tr
.r5
,
2194 if (sdpcm_shared
.flags
& (SDPCM_SHARED_ASSERT
| SDPCM_SHARED_TRAP
))
2195 DHD_ERROR(("%s: %s\n", __func__
, strbuf
.origbuf
));
2198 if (sdpcm_shared
.flags
& SDPCM_SHARED_TRAP
) {
2199 /* Mem dump to a file on device */
2200 dhdsdio_mem_dump(bus
);
2202 #endif /* DHD_DEBUG */
2211 static int dhdsdio_mem_dump(dhd_bus_t
*bus
)
2214 int size
; /* Full mem size */
2215 int start
= 0; /* Start address */
2216 int read_size
= 0; /* Read size of each iteration */
2217 u8
*buf
= NULL
, *databuf
= NULL
;
2219 /* Get full mem size */
2220 size
= bus
->ramsize
;
2221 buf
= kmalloc(size
, GFP_ATOMIC
);
2223 DHD_ERROR(("%s: Out of memory (%d bytes)\n", __func__
, size
));
2227 /* Read mem content */
2228 printk(KERN_DEBUG
"Dump dongle memory");
2231 read_size
= min(MEMBLOCK
, size
);
2232 ret
= dhdsdio_membytes(bus
, false, start
, databuf
, read_size
);
2234 DHD_ERROR(("%s: Error membytes %d\n", __func__
, ret
));
2240 /* Decrement size and increment start address */
2243 databuf
+= read_size
;
2245 printk(KERN_DEBUG
"Done\n");
2247 /* free buf before return !!! */
2248 if (write_to_file(bus
->dhd
, buf
, bus
->ramsize
)) {
2249 DHD_ERROR(("%s: Error writing to files\n", __func__
));
2253 /* buf free handled in write_to_file, not here */
2257 #define CONSOLE_LINE_MAX 192
2259 static int dhdsdio_readconsole(dhd_bus_t
*bus
)
2261 dhd_console_t
*c
= &bus
->console
;
2262 u8 line
[CONSOLE_LINE_MAX
], ch
;
2266 /* Don't do anything until FWREADY updates console address */
2267 if (bus
->console_addr
== 0)
2270 /* Read console log struct */
2271 addr
= bus
->console_addr
+ offsetof(rte_cons_t
, log
);
2272 rv
= dhdsdio_membytes(bus
, false, addr
, (u8
*)&c
->log
,
2277 /* Allocate console buffer (one time only) */
2278 if (c
->buf
== NULL
) {
2279 c
->bufsize
= le32_to_cpu(c
->log
.buf_size
);
2280 c
->buf
= kmalloc(c
->bufsize
, GFP_ATOMIC
);
2285 idx
= le32_to_cpu(c
->log
.idx
);
2287 /* Protect against corrupt value */
2288 if (idx
> c
->bufsize
)
2291 /* Skip reading the console buffer if the index pointer
2296 /* Read the console buffer */
2297 addr
= le32_to_cpu(c
->log
.buf
);
2298 rv
= dhdsdio_membytes(bus
, false, addr
, c
->buf
, c
->bufsize
);
2302 while (c
->last
!= idx
) {
2303 for (n
= 0; n
< CONSOLE_LINE_MAX
- 2; n
++) {
2304 if (c
->last
== idx
) {
2305 /* This would output a partial line.
2307 * the buffer pointer and output this
2308 * line next time around.
2313 c
->last
= c
->bufsize
- n
;
2316 ch
= c
->buf
[c
->last
];
2317 c
->last
= (c
->last
+ 1) % c
->bufsize
;
2324 if (line
[n
- 1] == '\r')
2327 printk(KERN_DEBUG
"CONSOLE: %s\n", line
);
2334 #endif /* DHD_DEBUG */
2336 int dhdsdio_downloadvars(dhd_bus_t
*bus
, void *arg
, int len
)
2340 DHD_TRACE(("%s: Enter\n", __func__
));
2342 /* Basic sanity checks */
2344 bcmerror
= -EISCONN
;
2348 bcmerror
= -EOVERFLOW
;
2352 /* Free the old ones and replace with passed variables */
2355 bus
->vars
= kmalloc(len
, GFP_ATOMIC
);
2356 bus
->varsz
= bus
->vars
? len
: 0;
2357 if (bus
->vars
== NULL
) {
2362 /* Copy the passed variables, which should include the
2363 terminating double-null */
2364 memcpy(bus
->vars
, arg
, bus
->varsz
);
2370 dhdsdio_doiovar(dhd_bus_t
*bus
, const struct brcmu_iovar
*vi
, u32 actionid
,
2371 const char *name
, void *params
, int plen
, void *arg
, int len
,
2378 DHD_TRACE(("%s: Enter, action %d name %s params %p plen %d arg %p "
2379 "len %d val_size %d\n",
2380 __func__
, actionid
, name
, params
, plen
, arg
, len
, val_size
));
2382 bcmerror
= brcmu_iovar_lencheck(vi
, arg
, len
, IOV_ISSET(actionid
));
2386 if (plen
>= (int)sizeof(int_val
))
2387 memcpy(&int_val
, params
, sizeof(int_val
));
2389 bool_val
= (int_val
!= 0) ? true : false;
2391 /* Some ioctls use the bus */
2392 dhd_os_sdlock(bus
->dhd
);
2394 /* Check if dongle is in reset. If so, only allow DEVRESET iovars */
2395 if (bus
->dhd
->dongle_reset
&& !(actionid
== IOV_SVAL(IOV_DEVRESET
) ||
2396 actionid
== IOV_GVAL(IOV_DEVRESET
))) {
2401 /* Handle sleep stuff before any clock mucking */
2402 if (vi
->varid
== IOV_SLEEP
) {
2403 if (IOV_ISSET(actionid
)) {
2404 bcmerror
= dhdsdio_bussleep(bus
, bool_val
);
2406 int_val
= (s32
) bus
->sleeping
;
2407 memcpy(arg
, &int_val
, val_size
);
2412 /* Request clock to allow SDIO accesses */
2413 if (!bus
->dhd
->dongle_reset
) {
2415 dhdsdio_clkctl(bus
, CLK_AVAIL
, false);
2419 case IOV_GVAL(IOV_INTR
):
2420 int_val
= (s32
) bus
->intr
;
2421 memcpy(arg
, &int_val
, val_size
);
2424 case IOV_SVAL(IOV_INTR
):
2425 bus
->intr
= bool_val
;
2426 bus
->intdis
= false;
2429 DHD_INTR(("%s: enable SDIO device interrupts\n",
2431 bcmsdh_intr_enable(bus
->sdh
);
2433 DHD_INTR(("%s: disable SDIO interrupts\n",
2435 bcmsdh_intr_disable(bus
->sdh
);
2440 case IOV_GVAL(IOV_POLLRATE
):
2441 int_val
= (s32
) bus
->pollrate
;
2442 memcpy(arg
, &int_val
, val_size
);
2445 case IOV_SVAL(IOV_POLLRATE
):
2446 bus
->pollrate
= (uint
) int_val
;
2447 bus
->poll
= (bus
->pollrate
!= 0);
2450 case IOV_GVAL(IOV_IDLETIME
):
2451 int_val
= bus
->idletime
;
2452 memcpy(arg
, &int_val
, val_size
);
2455 case IOV_SVAL(IOV_IDLETIME
):
2456 if ((int_val
< 0) && (int_val
!= DHD_IDLE_IMMEDIATE
))
2459 bus
->idletime
= int_val
;
2462 case IOV_GVAL(IOV_IDLECLOCK
):
2463 int_val
= (s32
) bus
->idleclock
;
2464 memcpy(arg
, &int_val
, val_size
);
2467 case IOV_SVAL(IOV_IDLECLOCK
):
2468 bus
->idleclock
= int_val
;
2471 case IOV_GVAL(IOV_SD1IDLE
):
2472 int_val
= (s32
) sd1idle
;
2473 memcpy(arg
, &int_val
, val_size
);
2476 case IOV_SVAL(IOV_SD1IDLE
):
2480 case IOV_SVAL(IOV_MEMBYTES
):
2481 case IOV_GVAL(IOV_MEMBYTES
):
2487 bool set
= (actionid
== IOV_SVAL(IOV_MEMBYTES
));
2489 ASSERT(plen
>= 2 * sizeof(int));
2491 address
= (u32
) int_val
;
2492 memcpy(&int_val
, (char *)params
+ sizeof(int_val
),
2494 size
= (uint
) int_val
;
2496 /* Do some validation */
2497 dsize
= set
? plen
- (2 * sizeof(int)) : len
;
2499 DHD_ERROR(("%s: error on %s membytes, addr "
2500 "0x%08x size %d dsize %d\n",
2501 __func__
, (set
? "set" : "get"),
2502 address
, size
, dsize
));
2507 DHD_INFO(("%s: Request to %s %d bytes at address "
2509 __func__
, (set
? "write" : "read"), size
, address
));
2511 /* If we know about SOCRAM, check for a fit */
2512 if ((bus
->orig_ramsize
) &&
2513 ((address
> bus
->orig_ramsize
)
2514 || (address
+ size
> bus
->orig_ramsize
))) {
2515 DHD_ERROR(("%s: ramsize 0x%08x doesn't have %d "
2516 "bytes at 0x%08x\n",
2517 __func__
, bus
->orig_ramsize
, size
, address
));
2522 /* Generate the actual data pointer */
2524 set
? (u8
*) params
+
2525 2 * sizeof(int) : (u8
*) arg
;
2527 /* Call to do the transfer */
2529 dhdsdio_membytes(bus
, set
, address
, data
, size
);
2534 case IOV_GVAL(IOV_MEMSIZE
):
2535 int_val
= (s32
) bus
->ramsize
;
2536 memcpy(arg
, &int_val
, val_size
);
2539 case IOV_GVAL(IOV_SDIOD_DRIVE
):
2540 int_val
= (s32
) dhd_sdiod_drive_strength
;
2541 memcpy(arg
, &int_val
, val_size
);
2544 case IOV_SVAL(IOV_SDIOD_DRIVE
):
2545 dhd_sdiod_drive_strength
= int_val
;
2546 dhdsdio_sdiod_drive_strength_init(bus
,
2547 dhd_sdiod_drive_strength
);
2550 case IOV_SVAL(IOV_DOWNLOAD
):
2551 bcmerror
= dhdsdio_download_state(bus
, bool_val
);
2554 case IOV_SVAL(IOV_VARS
):
2555 bcmerror
= dhdsdio_downloadvars(bus
, arg
, len
);
2558 case IOV_GVAL(IOV_READAHEAD
):
2559 int_val
= (s32
) dhd_readahead
;
2560 memcpy(arg
, &int_val
, val_size
);
2563 case IOV_SVAL(IOV_READAHEAD
):
2564 if (bool_val
&& !dhd_readahead
)
2566 dhd_readahead
= bool_val
;
2569 case IOV_GVAL(IOV_SDRXCHAIN
):
2570 int_val
= (s32
) bus
->use_rxchain
;
2571 memcpy(arg
, &int_val
, val_size
);
2574 case IOV_SVAL(IOV_SDRXCHAIN
):
2575 if (bool_val
&& !bus
->sd_rxchain
)
2576 bcmerror
= -ENOTSUPP
;
2578 bus
->use_rxchain
= bool_val
;
2580 case IOV_GVAL(IOV_ALIGNCTL
):
2581 int_val
= (s32
) dhd_alignctl
;
2582 memcpy(arg
, &int_val
, val_size
);
2585 case IOV_SVAL(IOV_ALIGNCTL
):
2586 dhd_alignctl
= bool_val
;
2589 case IOV_GVAL(IOV_SDALIGN
):
2590 int_val
= DHD_SDALIGN
;
2591 memcpy(arg
, &int_val
, val_size
);
2595 case IOV_GVAL(IOV_VARS
):
2596 if (bus
->varsz
< (uint
) len
)
2597 memcpy(arg
, bus
->vars
, bus
->varsz
);
2599 bcmerror
= -EOVERFLOW
;
2601 #endif /* DHD_DEBUG */
2604 case IOV_GVAL(IOV_SDREG
):
2609 sd_ptr
= (sdreg_t
*) params
;
2611 addr
= (unsigned long)bus
->regs
+ sd_ptr
->offset
;
2612 size
= sd_ptr
->func
;
2613 int_val
= (s32
) bcmsdh_reg_read(bus
->sdh
, addr
, size
);
2614 if (bcmsdh_regfail(bus
->sdh
))
2616 memcpy(arg
, &int_val
, sizeof(s32
));
2620 case IOV_SVAL(IOV_SDREG
):
2625 sd_ptr
= (sdreg_t
*) params
;
2627 addr
= (unsigned long)bus
->regs
+ sd_ptr
->offset
;
2628 size
= sd_ptr
->func
;
2629 bcmsdh_reg_write(bus
->sdh
, addr
, size
, sd_ptr
->value
);
2630 if (bcmsdh_regfail(bus
->sdh
))
2635 /* Same as above, but offset is not backplane
2637 case IOV_GVAL(IOV_SBREG
):
2642 memcpy(&sdreg
, params
, sizeof(sdreg
));
2644 addr
= SI_ENUM_BASE
+ sdreg
.offset
;
2646 int_val
= (s32
) bcmsdh_reg_read(bus
->sdh
, addr
, size
);
2647 if (bcmsdh_regfail(bus
->sdh
))
2649 memcpy(arg
, &int_val
, sizeof(s32
));
2653 case IOV_SVAL(IOV_SBREG
):
2658 memcpy(&sdreg
, params
, sizeof(sdreg
));
2660 addr
= SI_ENUM_BASE
+ sdreg
.offset
;
2662 bcmsdh_reg_write(bus
->sdh
, addr
, size
, sdreg
.value
);
2663 if (bcmsdh_regfail(bus
->sdh
))
2668 case IOV_GVAL(IOV_SDCIS
):
2672 strcat(arg
, "\nFunc 0\n");
2673 bcmsdh_cis_read(bus
->sdh
, 0x10,
2674 (u8
*) arg
+ strlen(arg
),
2675 SBSDIO_CIS_SIZE_LIMIT
);
2676 strcat(arg
, "\nFunc 1\n");
2677 bcmsdh_cis_read(bus
->sdh
, 0x11,
2678 (u8
*) arg
+ strlen(arg
),
2679 SBSDIO_CIS_SIZE_LIMIT
);
2680 strcat(arg
, "\nFunc 2\n");
2681 bcmsdh_cis_read(bus
->sdh
, 0x12,
2682 (u8
*) arg
+ strlen(arg
),
2683 SBSDIO_CIS_SIZE_LIMIT
);
2687 case IOV_GVAL(IOV_FORCEEVEN
):
2688 int_val
= (s32
) forcealign
;
2689 memcpy(arg
, &int_val
, val_size
);
2692 case IOV_SVAL(IOV_FORCEEVEN
):
2693 forcealign
= bool_val
;
2696 case IOV_GVAL(IOV_TXBOUND
):
2697 int_val
= (s32
) dhd_txbound
;
2698 memcpy(arg
, &int_val
, val_size
);
2701 case IOV_SVAL(IOV_TXBOUND
):
2702 dhd_txbound
= (uint
) int_val
;
2705 case IOV_GVAL(IOV_RXBOUND
):
2706 int_val
= (s32
) dhd_rxbound
;
2707 memcpy(arg
, &int_val
, val_size
);
2710 case IOV_SVAL(IOV_RXBOUND
):
2711 dhd_rxbound
= (uint
) int_val
;
2714 case IOV_GVAL(IOV_TXMINMAX
):
2715 int_val
= (s32
) dhd_txminmax
;
2716 memcpy(arg
, &int_val
, val_size
);
2719 case IOV_SVAL(IOV_TXMINMAX
):
2720 dhd_txminmax
= (uint
) int_val
;
2722 #endif /* DHD_DEBUG */
2725 case IOV_GVAL(IOV_EXTLOOP
):
2726 int_val
= (s32
) bus
->ext_loop
;
2727 memcpy(arg
, &int_val
, val_size
);
2730 case IOV_SVAL(IOV_EXTLOOP
):
2731 bus
->ext_loop
= bool_val
;
2734 case IOV_GVAL(IOV_PKTGEN
):
2735 bcmerror
= dhdsdio_pktgen_get(bus
, arg
);
2738 case IOV_SVAL(IOV_PKTGEN
):
2739 bcmerror
= dhdsdio_pktgen_set(bus
, arg
);
2743 case IOV_SVAL(IOV_DEVRESET
):
2744 DHD_TRACE(("%s: Called set IOV_DEVRESET=%d dongle_reset=%d "
2746 __func__
, bool_val
, bus
->dhd
->dongle_reset
,
2747 bus
->dhd
->busstate
));
2749 dhd_bus_devreset(bus
->dhd
, (u8
) bool_val
);
2753 case IOV_GVAL(IOV_DEVRESET
):
2754 DHD_TRACE(("%s: Called get IOV_DEVRESET\n", __func__
));
2756 /* Get its status */
2757 int_val
= (bool) bus
->dhd
->dongle_reset
;
2758 memcpy(arg
, &int_val
, val_size
);
2763 bcmerror
= -ENOTSUPP
;
2768 if ((bus
->idletime
== DHD_IDLE_IMMEDIATE
) && !bus
->dpc_sched
) {
2769 bus
->activity
= false;
2770 dhdsdio_clkctl(bus
, CLK_NONE
, true);
2773 dhd_os_sdunlock(bus
->dhd
);
2775 if (actionid
== IOV_SVAL(IOV_DEVRESET
) && bool_val
== false)
2776 dhd_preinit_ioctls((dhd_pub_t
*) bus
->dhd
);
2781 static int dhdsdio_write_vars(dhd_bus_t
*bus
)
2789 char *nvram_ularray
;
2790 #endif /* DHD_DEBUG */
2792 /* Even if there are no vars are to be written, we still
2793 need to set the ramsize. */
2794 varsize
= bus
->varsz
? roundup(bus
->varsz
, 4) : 0;
2795 varaddr
= (bus
->ramsize
- 4) - varsize
;
2798 vbuffer
= kzalloc(varsize
, GFP_ATOMIC
);
2802 memcpy(vbuffer
, bus
->vars
, bus
->varsz
);
2804 /* Write the vars list */
2806 dhdsdio_membytes(bus
, true, varaddr
, vbuffer
, varsize
);
2808 /* Verify NVRAM bytes */
2809 DHD_INFO(("Compare NVRAM dl & ul; varsize=%d\n", varsize
));
2810 nvram_ularray
= kmalloc(varsize
, GFP_ATOMIC
);
2814 /* Upload image to verify downloaded contents. */
2815 memset(nvram_ularray
, 0xaa, varsize
);
2817 /* Read the vars list to temp buffer for comparison */
2819 dhdsdio_membytes(bus
, false, varaddr
, nvram_ularray
,
2822 DHD_ERROR(("%s: error %d on reading %d nvram bytes at "
2823 "0x%08x\n", __func__
, bcmerror
, varsize
, varaddr
));
2825 /* Compare the org NVRAM with the one read from RAM */
2826 if (memcmp(vbuffer
, nvram_ularray
, varsize
)) {
2827 DHD_ERROR(("%s: Downloaded NVRAM image is corrupted.\n",
2830 DHD_ERROR(("%s: Download/Upload/Compare of NVRAM ok.\n",
2833 kfree(nvram_ularray
);
2834 #endif /* DHD_DEBUG */
2839 /* adjust to the user specified RAM */
2840 DHD_INFO(("Physical memory size: %d, usable memory size: %d\n",
2841 bus
->orig_ramsize
, bus
->ramsize
));
2842 DHD_INFO(("Vars are at %d, orig varsize is %d\n", varaddr
, varsize
));
2843 varsize
= ((bus
->orig_ramsize
- 4) - varaddr
);
2846 * Determine the length token:
2847 * Varsize, converted to words, in lower 16-bits, checksum
2853 varsizew
= varsize
/ 4;
2854 varsizew
= (~varsizew
<< 16) | (varsizew
& 0x0000FFFF);
2855 varsizew
= cpu_to_le32(varsizew
);
2858 DHD_INFO(("New varsize is %d, length token=0x%08x\n", varsize
,
2861 /* Write the length token to the last word */
2862 bcmerror
= dhdsdio_membytes(bus
, true, (bus
->orig_ramsize
- 4),
2863 (u8
*)&varsizew
, 4);
2868 static int dhdsdio_download_state(dhd_bus_t
*bus
, bool enter
)
2874 /* To enter download state, disable ARM and reset SOCRAM.
2875 * To exit download state, simply reset ARM (default is RAM boot).
2878 bus
->alp_only
= true;
2880 dhdsdio_chip_disablecore(bus
->sdh
, bus
->ci
->armcorebase
);
2882 dhdsdio_chip_resetcore(bus
->sdh
, bus
->ci
->ramcorebase
);
2884 /* Clear the top bit of memory */
2887 dhdsdio_membytes(bus
, true, bus
->ramsize
- 4,
2891 regdata
= bcmsdh_reg_read(bus
->sdh
,
2892 CORE_SB(bus
->ci
->ramcorebase
, sbtmstatelow
), 4);
2893 regdata
&= (SBTML_RESET
| SBTML_REJ_MASK
|
2894 (SICF_CLOCK_EN
<< SBTML_SICF_SHIFT
));
2895 if ((SICF_CLOCK_EN
<< SBTML_SICF_SHIFT
) != regdata
) {
2896 DHD_ERROR(("%s: SOCRAM core is down after reset?\n",
2902 bcmerror
= dhdsdio_write_vars(bus
);
2904 DHD_ERROR(("%s: no vars written to RAM\n", __func__
));
2908 W_SDREG(0xFFFFFFFF, &bus
->regs
->intstatus
, retries
);
2910 dhdsdio_chip_resetcore(bus
->sdh
, bus
->ci
->armcorebase
);
2912 /* Allow HT Clock now that the ARM is running. */
2913 bus
->alp_only
= false;
2915 bus
->dhd
->busstate
= DHD_BUS_LOAD
;
2922 dhd_bus_iovar_op(dhd_pub_t
*dhdp
, const char *name
,
2923 void *params
, int plen
, void *arg
, int len
, bool set
)
2925 dhd_bus_t
*bus
= dhdp
->bus
;
2926 const struct brcmu_iovar
*vi
= NULL
;
2931 DHD_TRACE(("%s: Enter\n", __func__
));
2936 /* Get MUST have return space */
2937 ASSERT(set
|| (arg
&& len
));
2939 /* Set does NOT take qualifiers */
2940 ASSERT(!set
|| (!params
&& !plen
));
2942 /* Look up var locally; if not found pass to host driver */
2943 vi
= brcmu_iovar_lookup(dhdsdio_iovars
, name
);
2945 dhd_os_sdlock(bus
->dhd
);
2949 /* Turn on clock in case SD command needs backplane */
2950 dhdsdio_clkctl(bus
, CLK_AVAIL
, false);
2953 bcmsdh_iovar_op(bus
->sdh
, name
, params
, plen
, arg
, len
,
2956 /* Similar check for blocksize change */
2957 if (set
&& strcmp(name
, "sd_blocksize") == 0) {
2960 (bus
->sdh
, "sd_blocksize", &fnum
, sizeof(s32
),
2961 &bus
->blocksize
, sizeof(s32
),
2964 DHD_ERROR(("%s: fail on %s get\n", __func__
,
2967 DHD_INFO(("%s: noted %s update, value now %d\n",
2968 __func__
, "sd_blocksize",
2972 bus
->roundup
= min(max_roundup
, bus
->blocksize
);
2974 if ((bus
->idletime
== DHD_IDLE_IMMEDIATE
) && !bus
->dpc_sched
) {
2975 bus
->activity
= false;
2976 dhdsdio_clkctl(bus
, CLK_NONE
, true);
2979 dhd_os_sdunlock(bus
->dhd
);
2983 DHD_CTL(("%s: %s %s, len %d plen %d\n", __func__
,
2984 name
, (set
? "set" : "get"), len
, plen
));
2986 /* set up 'params' pointer in case this is a set command so that
2987 * the convenience int and bool code can be common to set and get
2989 if (params
== NULL
) {
2994 if (vi
->type
== IOVT_VOID
)
2996 else if (vi
->type
== IOVT_BUFFER
)
2999 /* all other types are integer sized */
3000 val_size
= sizeof(int);
3002 actionid
= set
? IOV_SVAL(vi
->varid
) : IOV_GVAL(vi
->varid
);
3004 dhdsdio_doiovar(bus
, vi
, actionid
, name
, params
, plen
, arg
, len
,
3011 void dhd_bus_stop(struct dhd_bus
*bus
, bool enforce_mutex
)
3013 u32 local_hostintmask
;
3018 DHD_TRACE(("%s: Enter\n", __func__
));
3021 dhd_os_sdlock(bus
->dhd
);
3025 /* Enable clock for device interrupts */
3026 dhdsdio_clkctl(bus
, CLK_AVAIL
, false);
3028 /* Disable and clear interrupts at the chip level also */
3029 W_SDREG(0, &bus
->regs
->hostintmask
, retries
);
3030 local_hostintmask
= bus
->hostintmask
;
3031 bus
->hostintmask
= 0;
3033 /* Change our idea of bus state */
3034 bus
->dhd
->busstate
= DHD_BUS_DOWN
;
3036 /* Force clocks on backplane to be sure F2 interrupt propagates */
3038 bcmsdh_cfg_read(bus
->sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_CHIPCLKCSR
,
3041 bcmsdh_cfg_write(bus
->sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_CHIPCLKCSR
,
3042 (saveclk
| SBSDIO_FORCE_HT
), &err
);
3045 DHD_ERROR(("%s: Failed to force clock for F2: err %d\n",
3049 /* Turn off the bus (F2), free any pending packets */
3050 DHD_INTR(("%s: disable SDIO interrupts\n", __func__
));
3051 bcmsdh_intr_disable(bus
->sdh
);
3052 bcmsdh_cfg_write(bus
->sdh
, SDIO_FUNC_0
, SDIO_CCCR_IOEx
,
3053 SDIO_FUNC_ENABLE_1
, NULL
);
3055 /* Clear any pending interrupts now that F2 is disabled */
3056 W_SDREG(local_hostintmask
, &bus
->regs
->intstatus
, retries
);
3058 /* Turn off the backplane clock (only) */
3059 dhdsdio_clkctl(bus
, CLK_SDONLY
, false);
3061 /* Clear the data packet queues */
3062 brcmu_pktq_flush(&bus
->txq
, true, NULL
, NULL
);
3064 /* Clear any held glomming stuff */
3066 brcmu_pkt_buf_free_skb(bus
->glomd
);
3069 brcmu_pkt_buf_free_skb(bus
->glom
);
3071 bus
->glom
= bus
->glomd
= NULL
;
3073 /* Clear rx control and wake any waiters */
3075 dhd_os_ioctl_resp_wake(bus
->dhd
);
3077 /* Reset some F2 state stuff */
3078 bus
->rxskip
= false;
3079 bus
->tx_seq
= bus
->rx_seq
= 0;
3082 dhd_os_sdunlock(bus
->dhd
);
3085 int dhd_bus_init(dhd_pub_t
*dhdp
, bool enforce_mutex
)
3087 dhd_bus_t
*bus
= dhdp
->bus
;
3094 DHD_TRACE(("%s: Enter\n", __func__
));
3101 dhd_os_sdlock(bus
->dhd
);
3103 /* Make sure backplane clock is on, needed to generate F2 interrupt */
3104 dhdsdio_clkctl(bus
, CLK_AVAIL
, false);
3105 if (bus
->clkstate
!= CLK_AVAIL
)
3108 /* Force clocks on backplane to be sure F2 interrupt propagates */
3110 bcmsdh_cfg_read(bus
->sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_CHIPCLKCSR
,
3113 bcmsdh_cfg_write(bus
->sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_CHIPCLKCSR
,
3114 (saveclk
| SBSDIO_FORCE_HT
), &err
);
3117 DHD_ERROR(("%s: Failed to force clock for F2: err %d\n",
3122 /* Enable function 2 (frame transfers) */
3123 W_SDREG((SDPCM_PROT_VERSION
<< SMB_DATA_VERSION_SHIFT
),
3124 &bus
->regs
->tosbmailboxdata
, retries
);
3125 enable
= (SDIO_FUNC_ENABLE_1
| SDIO_FUNC_ENABLE_2
);
3127 bcmsdh_cfg_write(bus
->sdh
, SDIO_FUNC_0
, SDIO_CCCR_IOEx
, enable
, NULL
);
3129 /* Give the dongle some time to do its thing and set IOR2 */
3130 dhd_timeout_start(&tmo
, DHD_WAIT_F2RDY
* 1000);
3133 while (ready
!= enable
&& !dhd_timeout_expired(&tmo
))
3135 bcmsdh_cfg_read(bus
->sdh
, SDIO_FUNC_0
, SDIO_CCCR_IORx
,
3138 DHD_INFO(("%s: enable 0x%02x, ready 0x%02x (waited %uus)\n",
3139 __func__
, enable
, ready
, tmo
.elapsed
));
3141 /* If F2 successfully enabled, set core and enable interrupts */
3142 if (ready
== enable
) {
3143 /* Set up the interrupt mask and enable interrupts */
3144 bus
->hostintmask
= HOSTINTMASK
;
3145 W_SDREG(bus
->hostintmask
,
3146 (unsigned int *)CORE_BUS_REG(bus
->ci
->buscorebase
,
3147 hostintmask
), retries
);
3149 bcmsdh_cfg_write(bus
->sdh
, SDIO_FUNC_1
, SBSDIO_WATERMARK
,
3150 (u8
) watermark
, &err
);
3152 /* Set bus state according to enable result */
3153 dhdp
->busstate
= DHD_BUS_DATA
;
3155 /* bcmsdh_intr_unmask(bus->sdh); */
3157 bus
->intdis
= false;
3159 DHD_INTR(("%s: enable SDIO device interrupts\n",
3161 bcmsdh_intr_enable(bus
->sdh
);
3163 DHD_INTR(("%s: disable SDIO interrupts\n", __func__
));
3164 bcmsdh_intr_disable(bus
->sdh
);
3170 /* Disable F2 again */
3171 enable
= SDIO_FUNC_ENABLE_1
;
3172 bcmsdh_cfg_write(bus
->sdh
, SDIO_FUNC_0
, SDIO_CCCR_IOEx
, enable
,
3176 /* Restore previous clock setting */
3177 bcmsdh_cfg_write(bus
->sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_CHIPCLKCSR
,
3180 /* If we didn't come up, turn off backplane clock */
3181 if (dhdp
->busstate
!= DHD_BUS_DATA
)
3182 dhdsdio_clkctl(bus
, CLK_NONE
, false);
3186 dhd_os_sdunlock(bus
->dhd
);
3191 static void dhdsdio_rxfail(dhd_bus_t
*bus
, bool abort
, bool rtx
)
3193 bcmsdh_info_t
*sdh
= bus
->sdh
;
3194 struct sdpcmd_regs
*regs
= bus
->regs
;
3200 DHD_ERROR(("%s: %sterminate frame%s\n", __func__
,
3201 (abort
? "abort command, " : ""),
3202 (rtx
? ", send NAK" : "")));
3205 bcmsdh_abort(sdh
, SDIO_FUNC_2
);
3207 bcmsdh_cfg_write(sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_FRAMECTRL
, SFC_RF_TERM
,
3211 /* Wait until the packet has been flushed (device/FIFO stable) */
3212 for (lastrbc
= retries
= 0xffff; retries
> 0; retries
--) {
3213 hi
= bcmsdh_cfg_read(sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_RFRAMEBCHI
,
3215 lo
= bcmsdh_cfg_read(sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_RFRAMEBCLO
,
3217 bus
->f1regdata
+= 2;
3219 if ((hi
== 0) && (lo
== 0))
3222 if ((hi
> (lastrbc
>> 8)) && (lo
> (lastrbc
& 0x00ff))) {
3223 DHD_ERROR(("%s: count growing: last 0x%04x now "
3225 __func__
, lastrbc
, ((hi
<< 8) + lo
)));
3227 lastrbc
= (hi
<< 8) + lo
;
3231 DHD_ERROR(("%s: count never zeroed: last 0x%04x\n",
3232 __func__
, lastrbc
));
3234 DHD_INFO(("%s: flush took %d iterations\n", __func__
,
3235 (0xffff - retries
)));
3240 W_SDREG(SMB_NAK
, ®s
->tosbmailbox
, retries
);
3242 if (retries
<= retry_limit
)
3246 /* Clear partial in any case */
3249 /* If we can't reach the device, signal failure */
3250 if (err
|| bcmsdh_regfail(sdh
))
3251 bus
->dhd
->busstate
= DHD_BUS_DOWN
;
3255 dhdsdio_read_control(dhd_bus_t
*bus
, u8
*hdr
, uint len
, uint doff
)
3257 bcmsdh_info_t
*sdh
= bus
->sdh
;
3262 DHD_TRACE(("%s: Enter\n", __func__
));
3264 /* Control data already received in aligned rxctl */
3265 if ((bus
->bus
== SPI_BUS
) && (!bus
->usebufpool
))
3269 /* Set rxctl for frame (w/optional alignment) */
3270 bus
->rxctl
= bus
->rxbuf
;
3272 bus
->rxctl
+= firstread
;
3273 pad
= ((unsigned long)bus
->rxctl
% DHD_SDALIGN
);
3275 bus
->rxctl
+= (DHD_SDALIGN
- pad
);
3276 bus
->rxctl
-= firstread
;
3278 ASSERT(bus
->rxctl
>= bus
->rxbuf
);
3280 /* Copy the already-read portion over */
3281 memcpy(bus
->rxctl
, hdr
, firstread
);
3282 if (len
<= firstread
)
3285 /* Copy the full data pkt in gSPI case and process ioctl. */
3286 if (bus
->bus
== SPI_BUS
) {
3287 memcpy(bus
->rxctl
, hdr
, len
);
3291 /* Raise rdlen to next SDIO block to avoid tail command */
3292 rdlen
= len
- firstread
;
3293 if (bus
->roundup
&& bus
->blocksize
&& (rdlen
> bus
->blocksize
)) {
3294 pad
= bus
->blocksize
- (rdlen
% bus
->blocksize
);
3295 if ((pad
<= bus
->roundup
) && (pad
< bus
->blocksize
) &&
3296 ((len
+ pad
) < bus
->dhd
->maxctl
))
3298 } else if (rdlen
% DHD_SDALIGN
) {
3299 rdlen
+= DHD_SDALIGN
- (rdlen
% DHD_SDALIGN
);
3302 /* Satisfy length-alignment requirements */
3303 if (forcealign
&& (rdlen
& (ALIGNMENT
- 1)))
3304 rdlen
= roundup(rdlen
, ALIGNMENT
);
3306 /* Drop if the read is too big or it exceeds our maximum */
3307 if ((rdlen
+ firstread
) > bus
->dhd
->maxctl
) {
3308 DHD_ERROR(("%s: %d-byte control read exceeds %d-byte buffer\n",
3309 __func__
, rdlen
, bus
->dhd
->maxctl
));
3310 bus
->dhd
->rx_errors
++;
3311 dhdsdio_rxfail(bus
, false, false);
3315 if ((len
- doff
) > bus
->dhd
->maxctl
) {
3316 DHD_ERROR(("%s: %d-byte ctl frame (%d-byte ctl data) exceeds "
3318 __func__
, len
, (len
- doff
), bus
->dhd
->maxctl
));
3319 bus
->dhd
->rx_errors
++;
3321 dhdsdio_rxfail(bus
, false, false);
3325 /* Read remainder of frame body into the rxctl buffer */
3326 sdret
= bcmsdh_recv_buf(bus
, bcmsdh_cur_sbwad(sdh
), SDIO_FUNC_2
,
3327 F2SYNC
, (bus
->rxctl
+ firstread
), rdlen
,
3330 ASSERT(sdret
!= -BCME_PENDING
);
3332 /* Control frame failures need retransmission */
3334 DHD_ERROR(("%s: read %d control bytes failed: %d\n",
3335 __func__
, rdlen
, sdret
));
3336 bus
->rxc_errors
++; /* dhd.rx_ctlerrs is higher level */
3337 dhdsdio_rxfail(bus
, true, true);
3344 if (DHD_BYTES_ON() && DHD_CTL_ON()) {
3345 printk(KERN_DEBUG
"RxCtrl:\n");
3346 print_hex_dump_bytes("", DUMP_PREFIX_OFFSET
, bus
->rxctl
, len
);
3350 /* Point to valid data and indicate its length */
3352 bus
->rxlen
= len
- doff
;
3355 /* Awake any waiters */
3356 dhd_os_ioctl_resp_wake(bus
->dhd
);
3359 static u8
dhdsdio_rxglom(dhd_bus_t
*bus
, u8 rxseq
)
3365 struct sk_buff
*pfirst
, *plast
, *pnext
, *save_pfirst
;
3368 u8 chan
, seq
, doff
, sfdoff
;
3372 bool usechain
= bus
->use_rxchain
;
3374 /* If packets, issue read(s) and send up packet chain */
3375 /* Return sequence numbers consumed? */
3377 DHD_TRACE(("dhdsdio_rxglom: start: glomd %p glom %p\n", bus
->glomd
,
3380 /* If there's a descriptor, generate the packet chain */
3382 dhd_os_sdlock_rxq(bus
->dhd
);
3384 pfirst
= plast
= pnext
= NULL
;
3385 dlen
= (u16
) (bus
->glomd
->len
);
3386 dptr
= bus
->glomd
->data
;
3387 if (!dlen
|| (dlen
& 1)) {
3388 DHD_ERROR(("%s: bad glomd len(%d), ignore descriptor\n",
3393 for (totlen
= num
= 0; dlen
; num
++) {
3394 /* Get (and move past) next length */
3395 sublen
= get_unaligned_le16(dptr
);
3396 dlen
-= sizeof(u16
);
3397 dptr
+= sizeof(u16
);
3398 if ((sublen
< SDPCM_HDRLEN
) ||
3399 ((num
== 0) && (sublen
< (2 * SDPCM_HDRLEN
)))) {
3400 DHD_ERROR(("%s: descriptor len %d bad: %d\n",
3401 __func__
, num
, sublen
));
3405 if (sublen
% DHD_SDALIGN
) {
3406 DHD_ERROR(("%s: sublen %d not multiple of %d\n",
3407 __func__
, sublen
, DHD_SDALIGN
));
3412 /* For last frame, adjust read len so total
3413 is a block multiple */
3416 (roundup(totlen
, bus
->blocksize
) - totlen
);
3417 totlen
= roundup(totlen
, bus
->blocksize
);
3420 /* Allocate/chain packet for next subframe */
3421 pnext
= brcmu_pkt_buf_get_skb(sublen
+ DHD_SDALIGN
);
3422 if (pnext
== NULL
) {
3423 DHD_ERROR(("%s: bcm_pkt_buf_get_skb failed, "
3424 "num %d len %d\n", __func__
,
3428 ASSERT(!(pnext
->prev
));
3431 pfirst
= plast
= pnext
;
3434 plast
->next
= pnext
;
3438 /* Adhere to start alignment requirements */
3439 PKTALIGN(pnext
, sublen
, DHD_SDALIGN
);
3442 /* If all allocations succeeded, save packet chain
3445 DHD_GLOM(("%s: allocated %d-byte packet chain for %d "
3446 "subframes\n", __func__
, totlen
, num
));
3447 if (DHD_GLOM_ON() && bus
->nextlen
) {
3448 if (totlen
!= bus
->nextlen
) {
3449 DHD_GLOM(("%s: glomdesc mismatch: nextlen %d glomdesc %d " "rxseq %d\n",
3450 __func__
, bus
->nextlen
,
3455 pfirst
= pnext
= NULL
;
3458 brcmu_pkt_buf_free_skb(pfirst
);
3463 /* Done with descriptor packet */
3464 brcmu_pkt_buf_free_skb(bus
->glomd
);
3468 dhd_os_sdunlock_rxq(bus
->dhd
);
3471 /* Ok -- either we just generated a packet chain,
3472 or had one from before */
3474 if (DHD_GLOM_ON()) {
3475 DHD_GLOM(("%s: try superframe read, packet chain:\n",
3477 for (pnext
= bus
->glom
; pnext
; pnext
= pnext
->next
) {
3478 DHD_GLOM((" %p: %p len 0x%04x (%d)\n",
3479 pnext
, (u8
*) (pnext
->data
),
3480 pnext
->len
, pnext
->len
));
3485 dlen
= (u16
) brcmu_pkttotlen(pfirst
);
3487 /* Do an SDIO read for the superframe. Configurable iovar to
3488 * read directly into the chained packet, or allocate a large
3489 * packet and and copy into the chain.
3492 errcode
= bcmsdh_recv_buf(bus
,
3493 bcmsdh_cur_sbwad(bus
->sdh
), SDIO_FUNC_2
,
3494 F2SYNC
, (u8
*) pfirst
->data
, dlen
,
3495 pfirst
, NULL
, NULL
);
3496 } else if (bus
->dataptr
) {
3497 errcode
= bcmsdh_recv_buf(bus
,
3498 bcmsdh_cur_sbwad(bus
->sdh
), SDIO_FUNC_2
,
3499 F2SYNC
, bus
->dataptr
, dlen
,
3501 sublen
= (u16
) brcmu_pktfrombuf(pfirst
, 0, dlen
,
3503 if (sublen
!= dlen
) {
3504 DHD_ERROR(("%s: FAILED TO COPY, dlen %d sublen %d\n",
3505 __func__
, dlen
, sublen
));
3510 DHD_ERROR(("COULDN'T ALLOC %d-BYTE GLOM, FORCE FAILURE\n",
3515 ASSERT(errcode
!= -BCME_PENDING
);
3517 /* On failure, kill the superframe, allow a couple retries */
3519 DHD_ERROR(("%s: glom read of %d bytes failed: %d\n",
3520 __func__
, dlen
, errcode
));
3521 bus
->dhd
->rx_errors
++;
3523 if (bus
->glomerr
++ < 3) {
3524 dhdsdio_rxfail(bus
, true, true);
3527 dhdsdio_rxfail(bus
, true, false);
3528 dhd_os_sdlock_rxq(bus
->dhd
);
3529 brcmu_pkt_buf_free_skb(bus
->glom
);
3530 dhd_os_sdunlock_rxq(bus
->dhd
);
3537 if (DHD_GLOM_ON()) {
3538 printk(KERN_DEBUG
"SUPERFRAME:\n");
3539 print_hex_dump_bytes("", DUMP_PREFIX_OFFSET
,
3540 pfirst
->data
, min_t(int, pfirst
->len
, 48));
3544 /* Validate the superframe header */
3545 dptr
= (u8
*) (pfirst
->data
);
3546 sublen
= get_unaligned_le16(dptr
);
3547 check
= get_unaligned_le16(dptr
+ sizeof(u16
));
3549 chan
= SDPCM_PACKET_CHANNEL(&dptr
[SDPCM_FRAMETAG_LEN
]);
3550 seq
= SDPCM_PACKET_SEQUENCE(&dptr
[SDPCM_FRAMETAG_LEN
]);
3551 bus
->nextlen
= dptr
[SDPCM_FRAMETAG_LEN
+ SDPCM_NEXTLEN_OFFSET
];
3552 if ((bus
->nextlen
<< 4) > MAX_RX_DATASZ
) {
3553 DHD_INFO(("%s: nextlen too large (%d) seq %d\n",
3554 __func__
, bus
->nextlen
, seq
));
3557 doff
= SDPCM_DOFFSET_VALUE(&dptr
[SDPCM_FRAMETAG_LEN
]);
3558 txmax
= SDPCM_WINDOW_VALUE(&dptr
[SDPCM_FRAMETAG_LEN
]);
3561 if ((u16
)~(sublen
^ check
)) {
3562 DHD_ERROR(("%s (superframe): HW hdr error: len/check "
3563 "0x%04x/0x%04x\n", __func__
, sublen
, check
));
3565 } else if (roundup(sublen
, bus
->blocksize
) != dlen
) {
3566 DHD_ERROR(("%s (superframe): len 0x%04x, rounded "
3567 "0x%04x, expect 0x%04x\n",
3569 roundup(sublen
, bus
->blocksize
), dlen
));
3571 } else if (SDPCM_PACKET_CHANNEL(&dptr
[SDPCM_FRAMETAG_LEN
]) !=
3572 SDPCM_GLOM_CHANNEL
) {
3573 DHD_ERROR(("%s (superframe): bad channel %d\n",
3575 SDPCM_PACKET_CHANNEL(&dptr
3576 [SDPCM_FRAMETAG_LEN
])));
3578 } else if (SDPCM_GLOMDESC(&dptr
[SDPCM_FRAMETAG_LEN
])) {
3579 DHD_ERROR(("%s (superframe): got second descriptor?\n",
3582 } else if ((doff
< SDPCM_HDRLEN
) ||
3583 (doff
> (pfirst
->len
- SDPCM_HDRLEN
))) {
3584 DHD_ERROR(("%s (superframe): Bad data offset %d: HW %d "
3586 __func__
, doff
, sublen
,
3587 pfirst
->len
, SDPCM_HDRLEN
));
3591 /* Check sequence number of superframe SW header */
3593 DHD_INFO(("%s: (superframe) rx_seq %d, expected %d\n",
3594 __func__
, seq
, rxseq
));
3599 /* Check window for sanity */
3600 if ((u8
) (txmax
- bus
->tx_seq
) > 0x40) {
3601 DHD_ERROR(("%s: unlikely tx max %d with tx_seq %d\n",
3602 __func__
, txmax
, bus
->tx_seq
));
3603 txmax
= bus
->tx_seq
+ 2;
3605 bus
->tx_max
= txmax
;
3607 /* Remove superframe header, remember offset */
3608 skb_pull(pfirst
, doff
);
3611 /* Validate all the subframe headers */
3612 for (num
= 0, pnext
= pfirst
; pnext
&& !errcode
;
3613 num
++, pnext
= pnext
->next
) {
3614 dptr
= (u8
*) (pnext
->data
);
3615 dlen
= (u16
) (pnext
->len
);
3616 sublen
= get_unaligned_le16(dptr
);
3617 check
= get_unaligned_le16(dptr
+ sizeof(u16
));
3618 chan
= SDPCM_PACKET_CHANNEL(&dptr
[SDPCM_FRAMETAG_LEN
]);
3619 doff
= SDPCM_DOFFSET_VALUE(&dptr
[SDPCM_FRAMETAG_LEN
]);
3621 if (DHD_GLOM_ON()) {
3622 printk(KERN_DEBUG
"subframe:\n");
3623 print_hex_dump_bytes("", DUMP_PREFIX_OFFSET
,
3628 if ((u16
)~(sublen
^ check
)) {
3629 DHD_ERROR(("%s (subframe %d): HW hdr error: "
3630 "len/check 0x%04x/0x%04x\n",
3631 __func__
, num
, sublen
, check
));
3633 } else if ((sublen
> dlen
) || (sublen
< SDPCM_HDRLEN
)) {
3634 DHD_ERROR(("%s (subframe %d): length mismatch: "
3635 "len 0x%04x, expect 0x%04x\n",
3636 __func__
, num
, sublen
, dlen
));
3638 } else if ((chan
!= SDPCM_DATA_CHANNEL
) &&
3639 (chan
!= SDPCM_EVENT_CHANNEL
)) {
3640 DHD_ERROR(("%s (subframe %d): bad channel %d\n",
3641 __func__
, num
, chan
));
3643 } else if ((doff
< SDPCM_HDRLEN
) || (doff
> sublen
)) {
3644 DHD_ERROR(("%s (subframe %d): Bad data offset %d: HW %d min %d\n",
3645 __func__
, num
, doff
, sublen
,
3652 /* Terminate frame on error, request
3654 if (bus
->glomerr
++ < 3) {
3655 /* Restore superframe header space */
3656 skb_push(pfirst
, sfdoff
);
3657 dhdsdio_rxfail(bus
, true, true);
3660 dhdsdio_rxfail(bus
, true, false);
3661 dhd_os_sdlock_rxq(bus
->dhd
);
3662 brcmu_pkt_buf_free_skb(bus
->glom
);
3663 dhd_os_sdunlock_rxq(bus
->dhd
);
3671 /* Basic SD framing looks ok - process each packet (header) */
3672 save_pfirst
= pfirst
;
3676 dhd_os_sdlock_rxq(bus
->dhd
);
3677 for (num
= 0; pfirst
; rxseq
++, pfirst
= pnext
) {
3678 pnext
= pfirst
->next
;
3679 pfirst
->next
= NULL
;
3681 dptr
= (u8
*) (pfirst
->data
);
3682 sublen
= get_unaligned_le16(dptr
);
3683 chan
= SDPCM_PACKET_CHANNEL(&dptr
[SDPCM_FRAMETAG_LEN
]);
3684 seq
= SDPCM_PACKET_SEQUENCE(&dptr
[SDPCM_FRAMETAG_LEN
]);
3685 doff
= SDPCM_DOFFSET_VALUE(&dptr
[SDPCM_FRAMETAG_LEN
]);
3687 DHD_GLOM(("%s: Get subframe %d, %p(%p/%d), sublen %d "
3689 __func__
, num
, pfirst
, pfirst
->data
,
3690 pfirst
->len
, sublen
, chan
, seq
));
3692 ASSERT((chan
== SDPCM_DATA_CHANNEL
)
3693 || (chan
== SDPCM_EVENT_CHANNEL
));
3696 DHD_GLOM(("%s: rx_seq %d, expected %d\n",
3697 __func__
, seq
, rxseq
));
3702 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
3703 printk(KERN_DEBUG
"Rx Subframe Data:\n");
3704 print_hex_dump_bytes("", DUMP_PREFIX_OFFSET
,
3709 __skb_trim(pfirst
, sublen
);
3710 skb_pull(pfirst
, doff
);
3712 if (pfirst
->len
== 0) {
3713 brcmu_pkt_buf_free_skb(pfirst
);
3715 plast
->next
= pnext
;
3717 ASSERT(save_pfirst
== pfirst
);
3718 save_pfirst
= pnext
;
3721 } else if (dhd_prot_hdrpull(bus
->dhd
, &ifidx
, pfirst
) !=
3723 DHD_ERROR(("%s: rx protocol error\n",
3725 bus
->dhd
->rx_errors
++;
3726 brcmu_pkt_buf_free_skb(pfirst
);
3728 plast
->next
= pnext
;
3730 ASSERT(save_pfirst
== pfirst
);
3731 save_pfirst
= pnext
;
3736 /* this packet will go up, link back into
3737 chain and count it */
3738 pfirst
->next
= pnext
;
3743 if (DHD_GLOM_ON()) {
3744 DHD_GLOM(("%s subframe %d to stack, %p(%p/%d) "
3746 __func__
, num
, pfirst
, pfirst
->data
,
3747 pfirst
->len
, pfirst
->next
,
3749 print_hex_dump_bytes("", DUMP_PREFIX_OFFSET
,
3751 min_t(int, pfirst
->len
, 32));
3753 #endif /* DHD_DEBUG */
3755 dhd_os_sdunlock_rxq(bus
->dhd
);
3757 dhd_os_sdunlock(bus
->dhd
);
3758 dhd_rx_frame(bus
->dhd
, ifidx
, save_pfirst
, num
);
3759 dhd_os_sdlock(bus
->dhd
);
3762 bus
->rxglomframes
++;
3763 bus
->rxglompkts
+= num
;
3768 /* Return true if there may be more frames to read */
3769 static uint
dhdsdio_readframes(dhd_bus_t
*bus
, uint maxframes
, bool *finished
)
3771 bcmsdh_info_t
*sdh
= bus
->sdh
;
3773 u16 len
, check
; /* Extracted hardware header fields */
3774 u8 chan
, seq
, doff
; /* Extracted software header fields */
3775 u8 fcbits
; /* Extracted fcbits from software header */
3777 struct sk_buff
*pkt
; /* Packet for event or data frames */
3778 u16 pad
; /* Number of pad bytes to read */
3779 u16 rdlen
; /* Total number of bytes to read */
3780 u8 rxseq
; /* Next sequence number to expect */
3781 uint rxleft
= 0; /* Remaining number of frames allowed */
3782 int sdret
; /* Return code from bcmsdh calls */
3783 u8 txmax
; /* Maximum tx sequence offered */
3784 bool len_consistent
; /* Result of comparing readahead len and
3788 uint rxcount
= 0; /* Total frames read */
3790 #if defined(DHD_DEBUG) || defined(SDTEST)
3791 bool sdtest
= false; /* To limit message spew from test mode */
3794 DHD_TRACE(("%s: Enter\n", __func__
));
3799 /* Allow pktgen to override maxframes */
3800 if (bus
->pktgen_count
&& (bus
->pktgen_mode
== DHD_PKTGEN_RECV
)) {
3801 maxframes
= bus
->pktgen_count
;
3806 /* Not finished unless we encounter no more frames indication */
3809 for (rxseq
= bus
->rx_seq
, rxleft
= maxframes
;
3810 !bus
->rxskip
&& rxleft
&& bus
->dhd
->busstate
!= DHD_BUS_DOWN
;
3811 rxseq
++, rxleft
--) {
3813 /* Handle glomming separately */
3814 if (bus
->glom
|| bus
->glomd
) {
3816 DHD_GLOM(("%s: calling rxglom: glomd %p, glom %p\n",
3817 __func__
, bus
->glomd
, bus
->glom
));
3818 cnt
= dhdsdio_rxglom(bus
, rxseq
);
3819 DHD_GLOM(("%s: rxglom returned %d\n", __func__
, cnt
));
3821 rxleft
= (rxleft
> cnt
) ? (rxleft
- cnt
) : 1;
3825 /* Try doing single read if we can */
3826 if (dhd_readahead
&& bus
->nextlen
) {
3827 u16 nextlen
= bus
->nextlen
;
3830 if (bus
->bus
== SPI_BUS
) {
3831 rdlen
= len
= nextlen
;
3833 rdlen
= len
= nextlen
<< 4;
3835 /* Pad read to blocksize for efficiency */
3836 if (bus
->roundup
&& bus
->blocksize
3837 && (rdlen
> bus
->blocksize
)) {
3840 (rdlen
% bus
->blocksize
);
3841 if ((pad
<= bus
->roundup
)
3842 && (pad
< bus
->blocksize
)
3843 && ((rdlen
+ pad
+ firstread
) <
3846 } else if (rdlen
% DHD_SDALIGN
) {
3848 DHD_SDALIGN
- (rdlen
% DHD_SDALIGN
);
3852 /* We use bus->rxctl buffer in WinXP for initial
3853 * control pkt receives.
3854 * Later we use buffer-poll for data as well
3855 * as control packets.
3856 * This is required because dhd receives full
3857 * frame in gSPI unlike SDIO.
3858 * After the frame is received we have to
3859 * distinguish whether it is data
3860 * or non-data frame.
3862 /* Allocate a packet buffer */
3863 dhd_os_sdlock_rxq(bus
->dhd
);
3864 pkt
= brcmu_pkt_buf_get_skb(rdlen
+ DHD_SDALIGN
);
3866 if (bus
->bus
== SPI_BUS
) {
3867 bus
->usebufpool
= false;
3868 bus
->rxctl
= bus
->rxbuf
;
3870 bus
->rxctl
+= firstread
;
3871 pad
= ((unsigned long)bus
->rxctl
%
3875 (DHD_SDALIGN
- pad
);
3876 bus
->rxctl
-= firstread
;
3878 ASSERT(bus
->rxctl
>= bus
->rxbuf
);
3880 /* Read the entire frame */
3881 sdret
= bcmsdh_recv_buf(bus
,
3882 bcmsdh_cur_sbwad(sdh
),
3883 SDIO_FUNC_2
, F2SYNC
,
3887 ASSERT(sdret
!= -BCME_PENDING
);
3889 /* Control frame failures need
3892 DHD_ERROR(("%s: read %d control bytes failed: %d\n",
3895 /* dhd.rx_ctlerrs is higher */
3897 dhd_os_sdunlock_rxq(bus
->dhd
);
3898 dhdsdio_rxfail(bus
, true,
3906 request rtx of events */
3907 DHD_ERROR(("%s (nextlen): "
3908 "brcmu_pkt_buf_get_skb "
3910 " len %d rdlen %d expected"
3911 " rxseq %d\n", __func__
,
3912 len
, rdlen
, rxseq
));
3913 /* Just go try again w/normal
3915 dhd_os_sdunlock_rxq(bus
->dhd
);
3919 if (bus
->bus
== SPI_BUS
)
3920 bus
->usebufpool
= true;
3922 ASSERT(!(pkt
->prev
));
3923 PKTALIGN(pkt
, rdlen
, DHD_SDALIGN
);
3924 rxbuf
= (u8
*) (pkt
->data
);
3925 /* Read the entire frame */
3926 sdret
= bcmsdh_recv_buf(bus
,
3927 bcmsdh_cur_sbwad(sdh
),
3928 SDIO_FUNC_2
, F2SYNC
,
3932 ASSERT(sdret
!= -BCME_PENDING
);
3935 DHD_ERROR(("%s (nextlen): read %d bytes failed: %d\n",
3936 __func__
, rdlen
, sdret
));
3937 brcmu_pkt_buf_free_skb(pkt
);
3938 bus
->dhd
->rx_errors
++;
3939 dhd_os_sdunlock_rxq(bus
->dhd
);
3940 /* Force retry w/normal header read.
3941 * Don't attempt NAK for
3944 dhdsdio_rxfail(bus
, true,
3951 dhd_os_sdunlock_rxq(bus
->dhd
);
3953 /* Now check the header */
3954 memcpy(bus
->rxhdr
, rxbuf
, SDPCM_HDRLEN
);
3956 /* Extract hardware header fields */
3957 len
= get_unaligned_le16(bus
->rxhdr
);
3958 check
= get_unaligned_le16(bus
->rxhdr
+ sizeof(u16
));
3960 /* All zeros means readahead info was bad */
3961 if (!(len
| check
)) {
3962 DHD_INFO(("%s (nextlen): read zeros in HW "
3963 "header???\n", __func__
));
3964 dhdsdio_pktfree2(bus
, pkt
);
3968 /* Validate check bytes */
3969 if ((u16
)~(len
^ check
)) {
3970 DHD_ERROR(("%s (nextlen): HW hdr error:"
3971 " nextlen/len/check"
3972 " 0x%04x/0x%04x/0x%04x\n",
3973 __func__
, nextlen
, len
, check
));
3975 dhdsdio_rxfail(bus
, false, false);
3976 dhdsdio_pktfree2(bus
, pkt
);
3980 /* Validate frame length */
3981 if (len
< SDPCM_HDRLEN
) {
3982 DHD_ERROR(("%s (nextlen): HW hdr length "
3983 "invalid: %d\n", __func__
, len
));
3984 dhdsdio_pktfree2(bus
, pkt
);
3988 /* Check for consistency withreadahead info */
3989 len_consistent
= (nextlen
!= (roundup(len
, 16) >> 4));
3990 if (len_consistent
) {
3991 /* Mismatch, force retry w/normal
3992 header (may be >4K) */
3993 DHD_ERROR(("%s (nextlen): mismatch, "
3994 "nextlen %d len %d rnd %d; "
3995 "expected rxseq %d\n",
3997 len
, roundup(len
, 16), rxseq
));
3998 dhdsdio_rxfail(bus
, true, (bus
->bus
!= SPI_BUS
));
3999 dhdsdio_pktfree2(bus
, pkt
);
4003 /* Extract software header fields */
4004 chan
= SDPCM_PACKET_CHANNEL(
4005 &bus
->rxhdr
[SDPCM_FRAMETAG_LEN
]);
4006 seq
= SDPCM_PACKET_SEQUENCE(
4007 &bus
->rxhdr
[SDPCM_FRAMETAG_LEN
]);
4008 doff
= SDPCM_DOFFSET_VALUE(
4009 &bus
->rxhdr
[SDPCM_FRAMETAG_LEN
]);
4010 txmax
= SDPCM_WINDOW_VALUE(
4011 &bus
->rxhdr
[SDPCM_FRAMETAG_LEN
]);
4014 bus
->rxhdr
[SDPCM_FRAMETAG_LEN
+
4015 SDPCM_NEXTLEN_OFFSET
];
4016 if ((bus
->nextlen
<< 4) > MAX_RX_DATASZ
) {
4017 DHD_INFO(("%s (nextlen): got frame w/nextlen too large" " (%d), seq %d\n",
4018 __func__
, bus
->nextlen
, seq
));
4022 bus
->dhd
->rx_readahead_cnt
++;
4024 /* Handle Flow Control */
4025 fcbits
= SDPCM_FCMASK_VALUE(
4026 &bus
->rxhdr
[SDPCM_FRAMETAG_LEN
]);
4028 if (bus
->flowcontrol
!= fcbits
) {
4029 if (~bus
->flowcontrol
& fcbits
)
4032 if (bus
->flowcontrol
& ~fcbits
)
4036 bus
->flowcontrol
= fcbits
;
4039 /* Check and update sequence number */
4041 DHD_INFO(("%s (nextlen): rx_seq %d, expected "
4042 "%d\n", __func__
, seq
, rxseq
));
4047 /* Check window for sanity */
4048 if ((u8
) (txmax
- bus
->tx_seq
) > 0x40) {
4049 DHD_ERROR(("%s: got unlikely tx max %d with "
4051 __func__
, txmax
, bus
->tx_seq
));
4052 txmax
= bus
->tx_seq
+ 2;
4054 bus
->tx_max
= txmax
;
4057 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
4058 printk(KERN_DEBUG
"Rx Data:\n");
4059 print_hex_dump_bytes("", DUMP_PREFIX_OFFSET
,
4061 } else if (DHD_HDRS_ON()) {
4062 printk(KERN_DEBUG
"RxHdr:\n");
4063 print_hex_dump_bytes("", DUMP_PREFIX_OFFSET
,
4064 bus
->rxhdr
, SDPCM_HDRLEN
);
4068 if (chan
== SDPCM_CONTROL_CHANNEL
) {
4069 if (bus
->bus
== SPI_BUS
) {
4070 dhdsdio_read_control(bus
, rxbuf
, len
,
4073 DHD_ERROR(("%s (nextlen): readahead on control" " packet %d?\n",
4075 /* Force retry w/normal header read */
4077 dhdsdio_rxfail(bus
, false, true);
4079 dhdsdio_pktfree2(bus
, pkt
);
4083 if ((bus
->bus
== SPI_BUS
) && !bus
->usebufpool
) {
4084 DHD_ERROR(("Received %d bytes on %d channel. Running out of " "rx pktbuf's or not yet malloced.\n",
4089 /* Validate data offset */
4090 if ((doff
< SDPCM_HDRLEN
) || (doff
> len
)) {
4091 DHD_ERROR(("%s (nextlen): bad data offset %d: HW len %d min %d\n",
4092 __func__
, doff
, len
, SDPCM_HDRLEN
));
4093 dhdsdio_rxfail(bus
, false, false);
4094 dhdsdio_pktfree2(bus
, pkt
);
4098 /* All done with this one -- now deliver the packet */
4101 /* gSPI frames should not be handled in fractions */
4102 if (bus
->bus
== SPI_BUS
)
4105 /* Read frame header (hardware and software) */
4106 sdret
= bcmsdh_recv_buf(bus
, bcmsdh_cur_sbwad(sdh
),
4107 SDIO_FUNC_2
, F2SYNC
, bus
->rxhdr
, firstread
,
4110 ASSERT(sdret
!= -BCME_PENDING
);
4113 DHD_ERROR(("%s: RXHEADER FAILED: %d\n", __func__
,
4116 dhdsdio_rxfail(bus
, true, true);
4120 if (DHD_BYTES_ON() || DHD_HDRS_ON()) {
4121 printk(KERN_DEBUG
"RxHdr:\n");
4122 print_hex_dump_bytes("", DUMP_PREFIX_OFFSET
,
4123 bus
->rxhdr
, SDPCM_HDRLEN
);
4127 /* Extract hardware header fields */
4128 len
= get_unaligned_le16(bus
->rxhdr
);
4129 check
= get_unaligned_le16(bus
->rxhdr
+ sizeof(u16
));
4131 /* All zeros means no more frames */
4132 if (!(len
| check
)) {
4137 /* Validate check bytes */
4138 if ((u16
) ~(len
^ check
)) {
4139 DHD_ERROR(("%s: HW hdr err: len/check 0x%04x/0x%04x\n",
4140 __func__
, len
, check
));
4142 dhdsdio_rxfail(bus
, false, false);
4146 /* Validate frame length */
4147 if (len
< SDPCM_HDRLEN
) {
4148 DHD_ERROR(("%s: HW hdr length invalid: %d\n",
4153 /* Extract software header fields */
4154 chan
= SDPCM_PACKET_CHANNEL(&bus
->rxhdr
[SDPCM_FRAMETAG_LEN
]);
4155 seq
= SDPCM_PACKET_SEQUENCE(&bus
->rxhdr
[SDPCM_FRAMETAG_LEN
]);
4156 doff
= SDPCM_DOFFSET_VALUE(&bus
->rxhdr
[SDPCM_FRAMETAG_LEN
]);
4157 txmax
= SDPCM_WINDOW_VALUE(&bus
->rxhdr
[SDPCM_FRAMETAG_LEN
]);
4159 /* Validate data offset */
4160 if ((doff
< SDPCM_HDRLEN
) || (doff
> len
)) {
4161 DHD_ERROR(("%s: Bad data offset %d: HW len %d, min %d "
4163 __func__
, doff
, len
, SDPCM_HDRLEN
, seq
));
4166 dhdsdio_rxfail(bus
, false, false);
4170 /* Save the readahead length if there is one */
4172 bus
->rxhdr
[SDPCM_FRAMETAG_LEN
+ SDPCM_NEXTLEN_OFFSET
];
4173 if ((bus
->nextlen
<< 4) > MAX_RX_DATASZ
) {
4174 DHD_INFO(("%s (nextlen): got frame w/nextlen too large "
4176 __func__
, bus
->nextlen
, seq
));
4180 /* Handle Flow Control */
4181 fcbits
= SDPCM_FCMASK_VALUE(&bus
->rxhdr
[SDPCM_FRAMETAG_LEN
]);
4183 if (bus
->flowcontrol
!= fcbits
) {
4184 if (~bus
->flowcontrol
& fcbits
)
4187 if (bus
->flowcontrol
& ~fcbits
)
4191 bus
->flowcontrol
= fcbits
;
4194 /* Check and update sequence number */
4196 DHD_INFO(("%s: rx_seq %d, expected %d\n", __func__
,
4202 /* Check window for sanity */
4203 if ((u8
) (txmax
- bus
->tx_seq
) > 0x40) {
4204 DHD_ERROR(("%s: unlikely tx max %d with tx_seq %d\n",
4205 __func__
, txmax
, bus
->tx_seq
));
4206 txmax
= bus
->tx_seq
+ 2;
4208 bus
->tx_max
= txmax
;
4210 /* Call a separate function for control frames */
4211 if (chan
== SDPCM_CONTROL_CHANNEL
) {
4212 dhdsdio_read_control(bus
, bus
->rxhdr
, len
, doff
);
4216 ASSERT((chan
== SDPCM_DATA_CHANNEL
)
4217 || (chan
== SDPCM_EVENT_CHANNEL
)
4218 || (chan
== SDPCM_TEST_CHANNEL
)
4219 || (chan
== SDPCM_GLOM_CHANNEL
));
4221 /* Length to read */
4222 rdlen
= (len
> firstread
) ? (len
- firstread
) : 0;
4224 /* May pad read to blocksize for efficiency */
4225 if (bus
->roundup
&& bus
->blocksize
&&
4226 (rdlen
> bus
->blocksize
)) {
4227 pad
= bus
->blocksize
- (rdlen
% bus
->blocksize
);
4228 if ((pad
<= bus
->roundup
) && (pad
< bus
->blocksize
) &&
4229 ((rdlen
+ pad
+ firstread
) < MAX_RX_DATASZ
))
4231 } else if (rdlen
% DHD_SDALIGN
) {
4232 rdlen
+= DHD_SDALIGN
- (rdlen
% DHD_SDALIGN
);
4235 /* Satisfy length-alignment requirements */
4236 if (forcealign
&& (rdlen
& (ALIGNMENT
- 1)))
4237 rdlen
= roundup(rdlen
, ALIGNMENT
);
4239 if ((rdlen
+ firstread
) > MAX_RX_DATASZ
) {
4240 /* Too long -- skip this frame */
4241 DHD_ERROR(("%s: too long: len %d rdlen %d\n",
4242 __func__
, len
, rdlen
));
4243 bus
->dhd
->rx_errors
++;
4245 dhdsdio_rxfail(bus
, false, false);
4249 dhd_os_sdlock_rxq(bus
->dhd
);
4250 pkt
= brcmu_pkt_buf_get_skb(rdlen
+ firstread
+ DHD_SDALIGN
);
4252 /* Give up on data, request rtx of events */
4253 DHD_ERROR(("%s: brcmu_pkt_buf_get_skb failed: rdlen %d"
4254 " chan %d\n", __func__
, rdlen
, chan
));
4255 bus
->dhd
->rx_dropped
++;
4256 dhd_os_sdunlock_rxq(bus
->dhd
);
4257 dhdsdio_rxfail(bus
, false, RETRYCHAN(chan
));
4260 dhd_os_sdunlock_rxq(bus
->dhd
);
4262 ASSERT(!(pkt
->prev
));
4264 /* Leave room for what we already read, and align remainder */
4265 ASSERT(firstread
< pkt
->len
);
4266 skb_pull(pkt
, firstread
);
4267 PKTALIGN(pkt
, rdlen
, DHD_SDALIGN
);
4269 /* Read the remaining frame data */
4270 sdret
= bcmsdh_recv_buf(bus
, bcmsdh_cur_sbwad(sdh
), SDIO_FUNC_2
,
4271 F2SYNC
, ((u8
*) (pkt
->data
)), rdlen
,
4274 ASSERT(sdret
!= -BCME_PENDING
);
4277 DHD_ERROR(("%s: read %d %s bytes failed: %d\n",
4280 SDPCM_EVENT_CHANNEL
) ? "event" : ((chan
==
4282 ? "data" : "test")),
4284 dhd_os_sdlock_rxq(bus
->dhd
);
4285 brcmu_pkt_buf_free_skb(pkt
);
4286 dhd_os_sdunlock_rxq(bus
->dhd
);
4287 bus
->dhd
->rx_errors
++;
4288 dhdsdio_rxfail(bus
, true, RETRYCHAN(chan
));
4292 /* Copy the already-read portion */
4293 skb_push(pkt
, firstread
);
4294 memcpy(pkt
->data
, bus
->rxhdr
, firstread
);
4297 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
4298 printk(KERN_DEBUG
"Rx Data:\n");
4299 print_hex_dump_bytes("", DUMP_PREFIX_OFFSET
,
4305 /* Save superframe descriptor and allocate packet frame */
4306 if (chan
== SDPCM_GLOM_CHANNEL
) {
4307 if (SDPCM_GLOMDESC(&bus
->rxhdr
[SDPCM_FRAMETAG_LEN
])) {
4308 DHD_GLOM(("%s: glom descriptor, %d bytes:\n",
4311 if (DHD_GLOM_ON()) {
4312 printk(KERN_DEBUG
"Glom Data:\n");
4313 print_hex_dump_bytes("",
4318 __skb_trim(pkt
, len
);
4319 ASSERT(doff
== SDPCM_HDRLEN
);
4320 skb_pull(pkt
, SDPCM_HDRLEN
);
4323 DHD_ERROR(("%s: glom superframe w/o "
4324 "descriptor!\n", __func__
));
4325 dhdsdio_rxfail(bus
, false, false);
4330 /* Fill in packet len and prio, deliver upward */
4331 __skb_trim(pkt
, len
);
4332 skb_pull(pkt
, doff
);
4335 /* Test channel packets are processed separately */
4336 if (chan
== SDPCM_TEST_CHANNEL
) {
4337 dhdsdio_testrcv(bus
, pkt
, seq
);
4342 if (pkt
->len
== 0) {
4343 dhd_os_sdlock_rxq(bus
->dhd
);
4344 brcmu_pkt_buf_free_skb(pkt
);
4345 dhd_os_sdunlock_rxq(bus
->dhd
);
4347 } else if (dhd_prot_hdrpull(bus
->dhd
, &ifidx
, pkt
) != 0) {
4348 DHD_ERROR(("%s: rx protocol error\n", __func__
));
4349 dhd_os_sdlock_rxq(bus
->dhd
);
4350 brcmu_pkt_buf_free_skb(pkt
);
4351 dhd_os_sdunlock_rxq(bus
->dhd
);
4352 bus
->dhd
->rx_errors
++;
4356 /* Unlock during rx call */
4357 dhd_os_sdunlock(bus
->dhd
);
4358 dhd_rx_frame(bus
->dhd
, ifidx
, pkt
, 1);
4359 dhd_os_sdlock(bus
->dhd
);
4361 rxcount
= maxframes
- rxleft
;
4363 /* Message if we hit the limit */
4364 if (!rxleft
&& !sdtest
)
4365 DHD_DATA(("%s: hit rx limit of %d frames\n", __func__
,
4368 #endif /* DHD_DEBUG */
4369 DHD_DATA(("%s: processed %d frames\n", __func__
, rxcount
));
4370 /* Back off rxseq if awaiting rtx, update rx_seq */
4373 bus
->rx_seq
= rxseq
;
4378 static u32
dhdsdio_hostmail(dhd_bus_t
*bus
)
4380 struct sdpcmd_regs
*regs
= bus
->regs
;
4386 DHD_TRACE(("%s: Enter\n", __func__
));
4388 /* Read mailbox data and ack that we did so */
4389 R_SDREG(hmb_data
, ®s
->tohostmailboxdata
, retries
);
4390 if (retries
<= retry_limit
)
4391 W_SDREG(SMB_INT_ACK
, ®s
->tosbmailbox
, retries
);
4392 bus
->f1regdata
+= 2;
4394 /* Dongle recomposed rx frames, accept them again */
4395 if (hmb_data
& HMB_DATA_NAKHANDLED
) {
4396 DHD_INFO(("Dongle reports NAK handled, expect rtx of %d\n",
4399 DHD_ERROR(("%s: unexpected NAKHANDLED!\n", __func__
));
4401 bus
->rxskip
= false;
4402 intstatus
|= I_HMB_FRAME_IND
;
4406 * DEVREADY does not occur with gSPI.
4408 if (hmb_data
& (HMB_DATA_DEVREADY
| HMB_DATA_FWREADY
)) {
4410 (hmb_data
& HMB_DATA_VERSION_MASK
) >>
4411 HMB_DATA_VERSION_SHIFT
;
4412 if (bus
->sdpcm_ver
!= SDPCM_PROT_VERSION
)
4413 DHD_ERROR(("Version mismatch, dongle reports %d, "
4415 bus
->sdpcm_ver
, SDPCM_PROT_VERSION
));
4417 DHD_INFO(("Dongle ready, protocol version %d\n",
4422 * Flow Control has been moved into the RX headers and this out of band
4423 * method isn't used any more.
4424 * remaining backward compatible with older dongles.
4426 if (hmb_data
& HMB_DATA_FC
) {
4427 fcbits
= (hmb_data
& HMB_DATA_FCDATA_MASK
) >>
4428 HMB_DATA_FCDATA_SHIFT
;
4430 if (fcbits
& ~bus
->flowcontrol
)
4433 if (bus
->flowcontrol
& ~fcbits
)
4437 bus
->flowcontrol
= fcbits
;
4440 /* Shouldn't be any others */
4441 if (hmb_data
& ~(HMB_DATA_DEVREADY
|
4442 HMB_DATA_NAKHANDLED
|
4445 HMB_DATA_FCDATA_MASK
| HMB_DATA_VERSION_MASK
)) {
4446 DHD_ERROR(("Unknown mailbox data content: 0x%02x\n", hmb_data
));
4452 bool dhdsdio_dpc(dhd_bus_t
*bus
)
4454 bcmsdh_info_t
*sdh
= bus
->sdh
;
4455 struct sdpcmd_regs
*regs
= bus
->regs
;
4456 u32 intstatus
, newstatus
= 0;
4458 uint rxlimit
= dhd_rxbound
; /* Rx frames to read before resched */
4459 uint txlimit
= dhd_txbound
; /* Tx frames to send before resched */
4460 uint framecnt
= 0; /* Temporary counter of tx/rx frames */
4461 bool rxdone
= true; /* Flag for no more read data */
4462 bool resched
= false; /* Flag indicating resched wanted */
4464 DHD_TRACE(("%s: Enter\n", __func__
));
4466 /* Start with leftover status bits */
4467 intstatus
= bus
->intstatus
;
4469 dhd_os_sdlock(bus
->dhd
);
4471 /* If waiting for HTAVAIL, check status */
4472 if (bus
->clkstate
== CLK_PENDING
) {
4474 u8 clkctl
, devctl
= 0;
4477 /* Check for inconsistent device control */
4479 bcmsdh_cfg_read(sdh
, SDIO_FUNC_1
, SBSDIO_DEVICE_CTL
, &err
);
4481 DHD_ERROR(("%s: error reading DEVCTL: %d\n",
4483 bus
->dhd
->busstate
= DHD_BUS_DOWN
;
4485 ASSERT(devctl
& SBSDIO_DEVCTL_CA_INT_ONLY
);
4487 #endif /* DHD_DEBUG */
4489 /* Read CSR, if clock on switch to AVAIL, else ignore */
4491 bcmsdh_cfg_read(sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_CHIPCLKCSR
,
4494 DHD_ERROR(("%s: error reading CSR: %d\n", __func__
,
4496 bus
->dhd
->busstate
= DHD_BUS_DOWN
;
4499 DHD_INFO(("DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n", devctl
,
4502 if (SBSDIO_HTAV(clkctl
)) {
4504 bcmsdh_cfg_read(sdh
, SDIO_FUNC_1
, SBSDIO_DEVICE_CTL
,
4507 DHD_ERROR(("%s: error reading DEVCTL: %d\n",
4509 bus
->dhd
->busstate
= DHD_BUS_DOWN
;
4511 devctl
&= ~SBSDIO_DEVCTL_CA_INT_ONLY
;
4512 bcmsdh_cfg_write(sdh
, SDIO_FUNC_1
, SBSDIO_DEVICE_CTL
,
4515 DHD_ERROR(("%s: error writing DEVCTL: %d\n",
4517 bus
->dhd
->busstate
= DHD_BUS_DOWN
;
4519 bus
->clkstate
= CLK_AVAIL
;
4527 /* Make sure backplane clock is on */
4528 dhdsdio_clkctl(bus
, CLK_AVAIL
, true);
4529 if (bus
->clkstate
== CLK_PENDING
)
4532 /* Pending interrupt indicates new device status */
4535 R_SDREG(newstatus
, ®s
->intstatus
, retries
);
4537 if (bcmsdh_regfail(bus
->sdh
))
4539 newstatus
&= bus
->hostintmask
;
4540 bus
->fcstate
= !!(newstatus
& I_HMB_FC_STATE
);
4542 W_SDREG(newstatus
, ®s
->intstatus
, retries
);
4547 /* Merge new bits with previous */
4548 intstatus
|= newstatus
;
4551 /* Handle flow-control change: read new state in case our ack
4552 * crossed another change interrupt. If change still set, assume
4553 * FC ON for safety, let next loop through do the debounce.
4555 if (intstatus
& I_HMB_FC_CHANGE
) {
4556 intstatus
&= ~I_HMB_FC_CHANGE
;
4557 W_SDREG(I_HMB_FC_CHANGE
, ®s
->intstatus
, retries
);
4558 R_SDREG(newstatus
, ®s
->intstatus
, retries
);
4559 bus
->f1regdata
+= 2;
4561 !!(newstatus
& (I_HMB_FC_STATE
| I_HMB_FC_CHANGE
));
4562 intstatus
|= (newstatus
& bus
->hostintmask
);
4565 /* Handle host mailbox indication */
4566 if (intstatus
& I_HMB_HOST_INT
) {
4567 intstatus
&= ~I_HMB_HOST_INT
;
4568 intstatus
|= dhdsdio_hostmail(bus
);
4571 /* Generally don't ask for these, can get CRC errors... */
4572 if (intstatus
& I_WR_OOSYNC
) {
4573 DHD_ERROR(("Dongle reports WR_OOSYNC\n"));
4574 intstatus
&= ~I_WR_OOSYNC
;
4577 if (intstatus
& I_RD_OOSYNC
) {
4578 DHD_ERROR(("Dongle reports RD_OOSYNC\n"));
4579 intstatus
&= ~I_RD_OOSYNC
;
4582 if (intstatus
& I_SBINT
) {
4583 DHD_ERROR(("Dongle reports SBINT\n"));
4584 intstatus
&= ~I_SBINT
;
4587 /* Would be active due to wake-wlan in gSPI */
4588 if (intstatus
& I_CHIPACTIVE
) {
4589 DHD_INFO(("Dongle reports CHIPACTIVE\n"));
4590 intstatus
&= ~I_CHIPACTIVE
;
4593 /* Ignore frame indications if rxskip is set */
4595 intstatus
&= ~I_HMB_FRAME_IND
;
4597 /* On frame indication, read available frames */
4598 if (PKT_AVAILABLE()) {
4599 framecnt
= dhdsdio_readframes(bus
, rxlimit
, &rxdone
);
4600 if (rxdone
|| bus
->rxskip
)
4601 intstatus
&= ~I_HMB_FRAME_IND
;
4602 rxlimit
-= min(framecnt
, rxlimit
);
4605 /* Keep still-pending events for next scheduling */
4606 bus
->intstatus
= intstatus
;
4609 #if defined(OOB_INTR_ONLY)
4610 bcmsdh_oob_intr_set(1);
4611 #endif /* (OOB_INTR_ONLY) */
4612 /* Re-enable interrupts to detect new device events (mailbox, rx frame)
4613 * or clock availability. (Allows tx loop to check ipend if desired.)
4614 * (Unless register access seems hosed, as we may not be able to ACK...)
4616 if (bus
->intr
&& bus
->intdis
&& !bcmsdh_regfail(sdh
)) {
4617 DHD_INTR(("%s: enable SDIO interrupts, rxdone %d framecnt %d\n",
4618 __func__
, rxdone
, framecnt
));
4619 bus
->intdis
= false;
4620 bcmsdh_intr_enable(sdh
);
4623 if (DATAOK(bus
) && bus
->ctrl_frame_stat
&&
4624 (bus
->clkstate
== CLK_AVAIL
)) {
4628 dhd_bcmsdh_send_buf(bus
, bcmsdh_cur_sbwad(sdh
), SDIO_FUNC_2
,
4629 F2SYNC
, (u8
*) bus
->ctrl_frame_buf
,
4630 (u32
) bus
->ctrl_frame_len
, NULL
,
4632 ASSERT(ret
!= -BCME_PENDING
);
4635 /* On failure, abort the command and
4636 terminate the frame */
4637 DHD_INFO(("%s: sdio error %d, abort command and "
4638 "terminate frame.\n", __func__
, ret
));
4641 bcmsdh_abort(sdh
, SDIO_FUNC_2
);
4643 bcmsdh_cfg_write(sdh
, SDIO_FUNC_1
,
4644 SBSDIO_FUNC1_FRAMECTRL
, SFC_WF_TERM
,
4648 for (i
= 0; i
< 3; i
++) {
4650 hi
= bcmsdh_cfg_read(sdh
, SDIO_FUNC_1
,
4651 SBSDIO_FUNC1_WFRAMEBCHI
,
4653 lo
= bcmsdh_cfg_read(sdh
, SDIO_FUNC_1
,
4654 SBSDIO_FUNC1_WFRAMEBCLO
,
4656 bus
->f1regdata
+= 2;
4657 if ((hi
== 0) && (lo
== 0))
4663 bus
->tx_seq
= (bus
->tx_seq
+ 1) % SDPCM_SEQUENCE_WRAP
;
4665 DHD_INFO(("Return_dpc value is : %d\n", ret
));
4666 bus
->ctrl_frame_stat
= false;
4667 dhd_wait_event_wakeup(bus
->dhd
);
4669 /* Send queued frames (limit 1 if rx may still be pending) */
4670 else if ((bus
->clkstate
== CLK_AVAIL
) && !bus
->fcstate
&&
4671 brcmu_pktq_mlen(&bus
->txq
, ~bus
->flowcontrol
) && txlimit
4673 framecnt
= rxdone
? txlimit
: min(txlimit
, dhd_txminmax
);
4674 framecnt
= dhdsdio_sendfromq(bus
, framecnt
);
4675 txlimit
-= framecnt
;
4678 /* Resched if events or tx frames are pending,
4679 else await next interrupt */
4680 /* On failed register access, all bets are off:
4681 no resched or interrupts */
4682 if ((bus
->dhd
->busstate
== DHD_BUS_DOWN
) || bcmsdh_regfail(sdh
)) {
4683 DHD_ERROR(("%s: failed backplane access over SDIO, halting "
4684 "operation %d\n", __func__
, bcmsdh_regfail(sdh
)));
4685 bus
->dhd
->busstate
= DHD_BUS_DOWN
;
4687 } else if (bus
->clkstate
== CLK_PENDING
) {
4688 DHD_INFO(("%s: rescheduled due to CLK_PENDING awaiting "
4689 "I_CHIPACTIVE interrupt\n", __func__
));
4691 } else if (bus
->intstatus
|| bus
->ipend
||
4692 (!bus
->fcstate
&& brcmu_pktq_mlen(&bus
->txq
, ~bus
->flowcontrol
)
4693 && DATAOK(bus
)) || PKT_AVAILABLE()) {
4697 bus
->dpc_sched
= resched
;
4699 /* If we're done for now, turn off clock request. */
4700 if ((bus
->clkstate
!= CLK_PENDING
)
4701 && bus
->idletime
== DHD_IDLE_IMMEDIATE
) {
4702 bus
->activity
= false;
4703 dhdsdio_clkctl(bus
, CLK_NONE
, false);
4706 dhd_os_sdunlock(bus
->dhd
);
4711 bool dhd_bus_dpc(struct dhd_bus
*bus
)
4715 /* Call the DPC directly. */
4716 DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __func__
));
4717 resched
= dhdsdio_dpc(bus
);
4722 void dhdsdio_isr(void *arg
)
4724 dhd_bus_t
*bus
= (dhd_bus_t
*) arg
;
4727 DHD_TRACE(("%s: Enter\n", __func__
));
4730 DHD_ERROR(("%s : bus is null pointer , exit\n", __func__
));
4735 if (bus
->dhd
->busstate
== DHD_BUS_DOWN
) {
4736 DHD_ERROR(("%s : bus is down. we have nothing to do\n",
4740 /* Count the interrupt call */
4744 /* Shouldn't get this interrupt if we're sleeping? */
4745 if (bus
->sleeping
) {
4746 DHD_ERROR(("INTERRUPT WHILE SLEEPING??\n"));
4750 /* Disable additional interrupts (is this needed now)? */
4752 DHD_INTR(("%s: disable SDIO interrupts\n", __func__
));
4754 DHD_ERROR(("dhdsdio_isr() w/o interrupt configured!\n"));
4756 bcmsdh_intr_disable(sdh
);
4759 #if defined(SDIO_ISR_THREAD)
4760 DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __func__
));
4761 while (dhdsdio_dpc(bus
))
4764 bus
->dpc_sched
= true;
4765 dhd_sched_dpc(bus
->dhd
);
4771 static void dhdsdio_pktgen_init(dhd_bus_t
*bus
)
4773 /* Default to specified length, or full range */
4774 if (dhd_pktgen_len
) {
4775 bus
->pktgen_maxlen
= min(dhd_pktgen_len
, MAX_PKTGEN_LEN
);
4776 bus
->pktgen_minlen
= bus
->pktgen_maxlen
;
4778 bus
->pktgen_maxlen
= MAX_PKTGEN_LEN
;
4779 bus
->pktgen_minlen
= 0;
4781 bus
->pktgen_len
= (u16
) bus
->pktgen_minlen
;
4783 /* Default to per-watchdog burst with 10s print time */
4784 bus
->pktgen_freq
= 1;
4785 bus
->pktgen_print
= 10000 / dhd_watchdog_ms
;
4786 bus
->pktgen_count
= (dhd_pktgen
* dhd_watchdog_ms
+ 999) / 1000;
4788 /* Default to echo mode */
4789 bus
->pktgen_mode
= DHD_PKTGEN_ECHO
;
4790 bus
->pktgen_stop
= 1;
4793 static void dhdsdio_pktgen(dhd_bus_t
*bus
)
4795 struct sk_buff
*pkt
;
4801 /* Display current count if appropriate */
4802 if (bus
->pktgen_print
&& (++bus
->pktgen_ptick
>= bus
->pktgen_print
)) {
4803 bus
->pktgen_ptick
= 0;
4804 printk(KERN_DEBUG
"%s: send attempts %d rcvd %d\n",
4805 __func__
, bus
->pktgen_sent
, bus
->pktgen_rcvd
);
4808 /* For recv mode, just make sure dongle has started sending */
4809 if (bus
->pktgen_mode
== DHD_PKTGEN_RECV
) {
4810 if (!bus
->pktgen_rcvd
)
4811 dhdsdio_sdtest_set(bus
, true);
4815 /* Otherwise, generate or request the specified number of packets */
4816 for (pktcount
= 0; pktcount
< bus
->pktgen_count
; pktcount
++) {
4817 /* Stop if total has been reached */
4818 if (bus
->pktgen_total
4819 && (bus
->pktgen_sent
>= bus
->pktgen_total
)) {
4820 bus
->pktgen_count
= 0;
4824 /* Allocate an appropriate-sized packet */
4825 len
= bus
->pktgen_len
;
4826 pkt
= brcmu_pkt_buf_get_skb(
4827 (len
+ SDPCM_HDRLEN
+ SDPCM_TEST_HDRLEN
+ DHD_SDALIGN
),
4830 DHD_ERROR(("%s: brcmu_pkt_buf_get_skb failed!\n",
4834 PKTALIGN(pkt
, (len
+ SDPCM_HDRLEN
+ SDPCM_TEST_HDRLEN
),
4836 data
= (u8
*) (pkt
->data
) + SDPCM_HDRLEN
;
4838 /* Write test header cmd and extra based on mode */
4839 switch (bus
->pktgen_mode
) {
4840 case DHD_PKTGEN_ECHO
:
4841 *data
++ = SDPCM_TEST_ECHOREQ
;
4842 *data
++ = (u8
) bus
->pktgen_sent
;
4845 case DHD_PKTGEN_SEND
:
4846 *data
++ = SDPCM_TEST_DISCARD
;
4847 *data
++ = (u8
) bus
->pktgen_sent
;
4850 case DHD_PKTGEN_RXBURST
:
4851 *data
++ = SDPCM_TEST_BURST
;
4852 *data
++ = (u8
) bus
->pktgen_count
;
4856 DHD_ERROR(("Unrecognized pktgen mode %d\n",
4858 brcmu_pkt_buf_free_skb(pkt
, true);
4859 bus
->pktgen_count
= 0;
4863 /* Write test header length field */
4864 *data
++ = (len
>> 0);
4865 *data
++ = (len
>> 8);
4867 /* Then fill in the remainder -- N/A for burst,
4869 for (fillbyte
= 0; fillbyte
< len
; fillbyte
++)
4871 SDPCM_TEST_FILL(fillbyte
, (u8
) bus
->pktgen_sent
);
4874 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
4875 data
= (u8
*) (pkt
->data
) + SDPCM_HDRLEN
;
4876 printk(KERN_DEBUG
"dhdsdio_pktgen: Tx Data:\n");
4877 print_hex_dump_bytes("", DUMP_PREFIX_OFFSET
, data
,
4878 pkt
->len
- SDPCM_HDRLEN
);
4883 if (dhdsdio_txpkt(bus
, pkt
, SDPCM_TEST_CHANNEL
, true)) {
4885 if (bus
->pktgen_stop
4886 && bus
->pktgen_stop
== bus
->pktgen_fail
)
4887 bus
->pktgen_count
= 0;
4891 /* Bump length if not fixed, wrap at max */
4892 if (++bus
->pktgen_len
> bus
->pktgen_maxlen
)
4893 bus
->pktgen_len
= (u16
) bus
->pktgen_minlen
;
4895 /* Special case for burst mode: just send one request! */
4896 if (bus
->pktgen_mode
== DHD_PKTGEN_RXBURST
)
4901 static void dhdsdio_sdtest_set(dhd_bus_t
*bus
, bool start
)
4903 struct sk_buff
*pkt
;
4906 /* Allocate the packet */
4907 pkt
= brcmu_pkt_buf_get_skb(SDPCM_HDRLEN
+ SDPCM_TEST_HDRLEN
+
4910 DHD_ERROR(("%s: brcmu_pkt_buf_get_skb failed!\n", __func__
));
4913 PKTALIGN(pkt
, (SDPCM_HDRLEN
+ SDPCM_TEST_HDRLEN
), DHD_SDALIGN
);
4914 data
= (u8
*) (pkt
->data
) + SDPCM_HDRLEN
;
4916 /* Fill in the test header */
4917 *data
++ = SDPCM_TEST_SEND
;
4919 *data
++ = (bus
->pktgen_maxlen
>> 0);
4920 *data
++ = (bus
->pktgen_maxlen
>> 8);
4923 if (dhdsdio_txpkt(bus
, pkt
, SDPCM_TEST_CHANNEL
, true))
4927 static void dhdsdio_testrcv(dhd_bus_t
*bus
, struct sk_buff
*pkt
, uint seq
)
4937 /* Check for min length */
4939 if (pktlen
< SDPCM_TEST_HDRLEN
) {
4940 DHD_ERROR(("dhdsdio_restrcv: toss runt frame, pktlen %d\n",
4942 brcmu_pkt_buf_free_skb(pkt
, false);
4946 /* Extract header fields */
4951 len
+= *data
++ << 8;
4953 /* Check length for relevant commands */
4954 if (cmd
== SDPCM_TEST_DISCARD
|| cmd
== SDPCM_TEST_ECHOREQ
4955 || cmd
== SDPCM_TEST_ECHORSP
) {
4956 if (pktlen
!= len
+ SDPCM_TEST_HDRLEN
) {
4957 DHD_ERROR(("dhdsdio_testrcv: frame length mismatch, "
4958 "pktlen %d seq %d" " cmd %d extra %d len %d\n",
4959 pktlen
, seq
, cmd
, extra
, len
));
4960 brcmu_pkt_buf_free_skb(pkt
, false);
4965 /* Process as per command */
4967 case SDPCM_TEST_ECHOREQ
:
4968 /* Rx->Tx turnaround ok (even on NDIS w/current
4970 *(u8
*) (pkt
->data
) = SDPCM_TEST_ECHORSP
;
4971 if (dhdsdio_txpkt(bus
, pkt
, SDPCM_TEST_CHANNEL
, true) == 0) {
4975 brcmu_pkt_buf_free_skb(pkt
, false);
4980 case SDPCM_TEST_ECHORSP
:
4981 if (bus
->ext_loop
) {
4982 brcmu_pkt_buf_free_skb(pkt
, false);
4987 for (offset
= 0; offset
< len
; offset
++, data
++) {
4988 if (*data
!= SDPCM_TEST_FILL(offset
, extra
)) {
4989 DHD_ERROR(("dhdsdio_testrcv: echo data mismatch: " "offset %d (len %d) expect 0x%02x rcvd 0x%02x\n",
4991 SDPCM_TEST_FILL(offset
, extra
), *data
));
4995 brcmu_pkt_buf_free_skb(pkt
, false);
4999 case SDPCM_TEST_DISCARD
:
5000 brcmu_pkt_buf_free_skb(pkt
, false);
5004 case SDPCM_TEST_BURST
:
5005 case SDPCM_TEST_SEND
:
5007 DHD_INFO(("dhdsdio_testrcv: unsupported or unknown command, "
5008 "pktlen %d seq %d" " cmd %d extra %d len %d\n",
5009 pktlen
, seq
, cmd
, extra
, len
));
5010 brcmu_pkt_buf_free_skb(pkt
, false);
5014 /* For recv mode, stop at limie (and tell dongle to stop sending) */
5015 if (bus
->pktgen_mode
== DHD_PKTGEN_RECV
) {
5016 if (bus
->pktgen_total
5017 && (bus
->pktgen_rcvd
>= bus
->pktgen_total
)) {
5018 bus
->pktgen_count
= 0;
5019 dhdsdio_sdtest_set(bus
, false);
5025 extern bool dhd_bus_watchdog(dhd_pub_t
*dhdp
)
5029 DHD_TIMER(("%s: Enter\n", __func__
));
5033 if (bus
->dhd
->dongle_reset
)
5036 /* Ignore the timer if simulating bus down */
5040 dhd_os_sdlock(bus
->dhd
);
5042 /* Poll period: check device if appropriate. */
5043 if (bus
->poll
&& (++bus
->polltick
>= bus
->pollrate
)) {
5046 /* Reset poll tick */
5049 /* Check device if no interrupts */
5050 if (!bus
->intr
|| (bus
->intrcount
== bus
->lastintrs
)) {
5052 if (!bus
->dpc_sched
) {
5054 devpend
= bcmsdh_cfg_read(bus
->sdh
, SDIO_FUNC_0
,
5058 devpend
& (INTR_STATUS_FUNC1
|
5062 /* If there is something, make like the ISR and
5068 bcmsdh_intr_disable(bus
->sdh
);
5070 bus
->dpc_sched
= true;
5071 dhd_sched_dpc(bus
->dhd
);
5076 /* Update interrupt tracking */
5077 bus
->lastintrs
= bus
->intrcount
;
5080 /* Poll for console output periodically */
5081 if (dhdp
->busstate
== DHD_BUS_DATA
&& dhd_console_ms
!= 0) {
5082 bus
->console
.count
+= dhd_watchdog_ms
;
5083 if (bus
->console
.count
>= dhd_console_ms
) {
5084 bus
->console
.count
-= dhd_console_ms
;
5085 /* Make sure backplane clock is on */
5086 dhdsdio_clkctl(bus
, CLK_AVAIL
, false);
5087 if (dhdsdio_readconsole(bus
) < 0)
5088 dhd_console_ms
= 0; /* On error,
5092 #endif /* DHD_DEBUG */
5095 /* Generate packets if configured */
5096 if (bus
->pktgen_count
&& (++bus
->pktgen_tick
>= bus
->pktgen_freq
)) {
5097 /* Make sure backplane clock is on */
5098 dhdsdio_clkctl(bus
, CLK_AVAIL
, false);
5099 bus
->pktgen_tick
= 0;
5100 dhdsdio_pktgen(bus
);
5104 /* On idle timeout clear activity flag and/or turn off clock */
5105 if ((bus
->idletime
> 0) && (bus
->clkstate
== CLK_AVAIL
)) {
5106 if (++bus
->idlecount
>= bus
->idletime
) {
5108 if (bus
->activity
) {
5109 bus
->activity
= false;
5110 dhd_os_wd_timer(bus
->dhd
, dhd_watchdog_ms
);
5112 dhdsdio_clkctl(bus
, CLK_NONE
, false);
5117 dhd_os_sdunlock(bus
->dhd
);
5123 extern int dhd_bus_console_in(dhd_pub_t
*dhdp
, unsigned char *msg
, uint msglen
)
5125 dhd_bus_t
*bus
= dhdp
->bus
;
5128 struct sk_buff
*pkt
;
5130 /* Address could be zero if CONSOLE := 0 in dongle Makefile */
5131 if (bus
->console_addr
== 0)
5134 /* Exclusive bus access */
5135 dhd_os_sdlock(bus
->dhd
);
5137 /* Don't allow input if dongle is in reset */
5138 if (bus
->dhd
->dongle_reset
) {
5139 dhd_os_sdunlock(bus
->dhd
);
5143 /* Request clock to allow SDIO accesses */
5145 /* No pend allowed since txpkt is called later, ht clk has to be on */
5146 dhdsdio_clkctl(bus
, CLK_AVAIL
, false);
5148 /* Zero cbuf_index */
5149 addr
= bus
->console_addr
+ offsetof(rte_cons_t
, cbuf_idx
);
5150 val
= cpu_to_le32(0);
5151 rv
= dhdsdio_membytes(bus
, true, addr
, (u8
*)&val
, sizeof(val
));
5155 /* Write message into cbuf */
5156 addr
= bus
->console_addr
+ offsetof(rte_cons_t
, cbuf
);
5157 rv
= dhdsdio_membytes(bus
, true, addr
, (u8
*)msg
, msglen
);
5161 /* Write length into vcons_in */
5162 addr
= bus
->console_addr
+ offsetof(rte_cons_t
, vcons_in
);
5163 val
= cpu_to_le32(msglen
);
5164 rv
= dhdsdio_membytes(bus
, true, addr
, (u8
*)&val
, sizeof(val
));
5168 /* Bump dongle by sending an empty event pkt.
5169 * sdpcm_sendup (RX) checks for virtual console input.
5171 pkt
= brcmu_pkt_buf_get_skb(4 + SDPCM_RESERVE
);
5172 if ((pkt
!= NULL
) && bus
->clkstate
== CLK_AVAIL
)
5173 dhdsdio_txpkt(bus
, pkt
, SDPCM_EVENT_CHANNEL
, true);
5176 if ((bus
->idletime
== DHD_IDLE_IMMEDIATE
) && !bus
->dpc_sched
) {
5177 bus
->activity
= false;
5178 dhdsdio_clkctl(bus
, CLK_NONE
, true);
5181 dhd_os_sdunlock(bus
->dhd
);
5185 #endif /* DHD_DEBUG */
5187 static bool dhdsdio_chipmatch(u16 chipid
)
5189 if (chipid
== BCM4325_CHIP_ID
)
5191 if (chipid
== BCM4329_CHIP_ID
)
5193 if (chipid
== BCM4319_CHIP_ID
)
5198 static void *dhdsdio_probe(u16 venid
, u16 devid
, u16 bus_no
,
5199 u16 slot
, u16 func
, uint bustype
, void *regsva
,
5205 /* Init global variables at run-time, not as part of the declaration.
5206 * This is required to support init/de-init of the driver.
5208 * of globals as part of the declaration results in non-deterministic
5209 * behavior since the value of the globals may be different on the
5210 * first time that the driver is initialized vs subsequent
5213 dhd_txbound
= DHD_TXBOUND
;
5214 dhd_rxbound
= DHD_RXBOUND
;
5215 dhd_alignctl
= true;
5217 dhd_readahead
= true;
5219 dhd_dongle_memsize
= 0;
5220 dhd_txminmax
= DHD_TXMINMAX
;
5226 DHD_TRACE(("%s: Enter\n", __func__
));
5227 DHD_INFO(("%s: venid 0x%04x devid 0x%04x\n", __func__
, venid
, devid
));
5229 /* We make assumptions about address window mappings */
5230 ASSERT((unsigned long)regsva
== SI_ENUM_BASE
);
5232 /* BCMSDH passes venid and devid based on CIS parsing -- but
5234 * means early parse could fail, so here we should get either an ID
5235 * we recognize OR (-1) indicating we must request power first.
5237 /* Check the Vendor ID */
5240 case PCI_VENDOR_ID_BROADCOM
:
5243 DHD_ERROR(("%s: unknown vendor: 0x%04x\n", __func__
, venid
));
5247 /* Check the Device ID and make sure it's one that we support */
5249 case BCM4325_D11DUAL_ID
: /* 4325 802.11a/g id */
5250 case BCM4325_D11G_ID
: /* 4325 802.11g 2.4Ghz band id */
5251 case BCM4325_D11A_ID
: /* 4325 802.11a 5Ghz band id */
5252 DHD_INFO(("%s: found 4325 Dongle\n", __func__
));
5254 case BCM4329_D11NDUAL_ID
: /* 4329 802.11n dualband device */
5255 case BCM4329_D11N2G_ID
: /* 4329 802.11n 2.4G device */
5256 case BCM4329_D11N5G_ID
: /* 4329 802.11n 5G device */
5258 DHD_INFO(("%s: found 4329 Dongle\n", __func__
));
5260 case BCM4319_D11N_ID
: /* 4319 802.11n id */
5261 case BCM4319_D11N2G_ID
: /* 4319 802.11n2g id */
5262 case BCM4319_D11N5G_ID
: /* 4319 802.11n5g id */
5263 DHD_INFO(("%s: found 4319 Dongle\n", __func__
));
5266 DHD_INFO(("%s: allow device id 0, will check chip internals\n",
5271 DHD_ERROR(("%s: skipping 0x%04x/0x%04x, not a dongle\n",
5272 __func__
, venid
, devid
));
5276 /* Allocate private bus interface state */
5277 bus
= kzalloc(sizeof(dhd_bus_t
), GFP_ATOMIC
);
5279 DHD_ERROR(("%s: kmalloc of dhd_bus_t failed\n", __func__
));
5283 bus
->cl_devid
= (u16
) devid
;
5285 bus
->tx_seq
= SDPCM_SEQUENCE_WRAP
- 1;
5286 bus
->usebufpool
= false; /* Use bufpool if allocated,
5287 else use locally malloced rxbuf */
5289 /* attempt to attach to the dongle */
5290 if (!(dhdsdio_probe_attach(bus
, sdh
, regsva
, devid
))) {
5291 DHD_ERROR(("%s: dhdsdio_probe_attach failed\n", __func__
));
5295 /* Attach to the dhd/OS/network interface */
5296 bus
->dhd
= dhd_attach(bus
, SDPCM_RESERVE
);
5298 DHD_ERROR(("%s: dhd_attach failed\n", __func__
));
5302 /* Allocate buffers */
5303 if (!(dhdsdio_probe_malloc(bus
, sdh
))) {
5304 DHD_ERROR(("%s: dhdsdio_probe_malloc failed\n", __func__
));
5308 if (!(dhdsdio_probe_init(bus
, sdh
))) {
5309 DHD_ERROR(("%s: dhdsdio_probe_init failed\n", __func__
));
5313 /* Register interrupt callback, but mask it (not operational yet). */
5314 DHD_INTR(("%s: disable SDIO interrupts (not interested yet)\n",
5316 bcmsdh_intr_disable(sdh
);
5317 ret
= bcmsdh_intr_reg(sdh
, dhdsdio_isr
, bus
);
5319 DHD_ERROR(("%s: FAILED: bcmsdh_intr_reg returned %d\n",
5323 DHD_INTR(("%s: registered SDIO interrupt function ok\n", __func__
));
5325 DHD_INFO(("%s: completed!!\n", __func__
));
5327 /* if firmware path present try to download and bring up bus */
5328 ret
= dhd_bus_start(bus
->dhd
);
5330 if (ret
== -ENOLINK
) {
5331 DHD_ERROR(("%s: dongle is not responding\n", __func__
));
5335 /* Ok, have the per-port tell the stack we're open for business */
5336 if (dhd_net_attach(bus
->dhd
, 0) != 0) {
5337 DHD_ERROR(("%s: Net attach failed!!\n", __func__
));
5344 dhdsdio_release(bus
);
5349 dhdsdio_probe_attach(struct dhd_bus
*bus
, void *sdh
, void *regsva
, u16 devid
)
5354 bus
->alp_only
= true;
5356 /* Return the window to backplane enumeration space for core access */
5357 if (dhdsdio_set_siaddr_window(bus
, SI_ENUM_BASE
))
5358 DHD_ERROR(("%s: FAILED to return to SI_ENUM_BASE\n", __func__
));
5361 printk(KERN_DEBUG
"F1 signature read @0x18000000=0x%4x\n",
5362 bcmsdh_reg_read(bus
->sdh
, SI_ENUM_BASE
, 4));
5364 #endif /* DHD_DEBUG */
5367 * Force PLL off until dhdsdio_chip_attach()
5368 * programs PLL control regs
5371 bcmsdh_cfg_write(sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_CHIPCLKCSR
,
5372 DHD_INIT_CLKCTL1
, &err
);
5375 bcmsdh_cfg_read(sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_CHIPCLKCSR
,
5378 if (err
|| ((clkctl
& ~SBSDIO_AVBITS
) != DHD_INIT_CLKCTL1
)) {
5379 DHD_ERROR(("dhdsdio_probe: ChipClkCSR access: err %d wrote "
5380 "0x%02x read 0x%02x\n",
5381 err
, DHD_INIT_CLKCTL1
, clkctl
));
5385 if (dhdsdio_chip_attach(bus
, regsva
)) {
5386 DHD_ERROR(("%s: dhdsdio_chip_attach failed!\n", __func__
));
5390 bcmsdh_chipinfo(sdh
, bus
->ci
->chip
, bus
->ci
->chiprev
);
5392 if (!dhdsdio_chipmatch((u16
) bus
->ci
->chip
)) {
5393 DHD_ERROR(("%s: unsupported chip: 0x%04x\n",
5394 __func__
, bus
->ci
->chip
));
5398 dhdsdio_sdiod_drive_strength_init(bus
, dhd_sdiod_drive_strength
);
5400 /* Get info on the ARM and SOCRAM cores... */
5401 if (!DHD_NOPMU(bus
)) {
5402 bus
->armrev
= SBCOREREV(bcmsdh_reg_read(bus
->sdh
,
5403 CORE_SB(bus
->ci
->armcorebase
, sbidhigh
), 4));
5404 bus
->orig_ramsize
= bus
->ci
->ramsize
;
5405 if (!(bus
->orig_ramsize
)) {
5406 DHD_ERROR(("%s: failed to find SOCRAM memory!\n",
5410 bus
->ramsize
= bus
->orig_ramsize
;
5411 if (dhd_dongle_memsize
)
5412 dhd_dongle_setmemsize(bus
, dhd_dongle_memsize
);
5414 DHD_ERROR(("DHD: dongle ram size is set to %d(orig %d)\n",
5415 bus
->ramsize
, bus
->orig_ramsize
));
5418 bus
->regs
= (void *)bus
->ci
->buscorebase
;
5420 /* Set core control so an SDIO reset does a backplane reset */
5421 OR_REG(&bus
->regs
->corecontrol
, CC_BPRESEN
);
5423 brcmu_pktq_init(&bus
->txq
, (PRIOMASK
+ 1), TXQLEN
);
5425 /* Locate an appropriately-aligned portion of hdrbuf */
5426 bus
->rxhdr
= (u8
*) roundup((unsigned long)&bus
->hdrbuf
[0], DHD_SDALIGN
);
5428 /* Set the poll and/or interrupt flags */
5429 bus
->intr
= (bool) dhd_intr
;
5430 bus
->poll
= (bool) dhd_poll
;
5440 static bool dhdsdio_probe_malloc(dhd_bus_t
*bus
, void *sdh
)
5442 DHD_TRACE(("%s: Enter\n", __func__
));
5444 if (bus
->dhd
->maxctl
) {
5446 roundup((bus
->dhd
->maxctl
+ SDPCM_HDRLEN
),
5447 ALIGNMENT
) + DHD_SDALIGN
;
5448 bus
->rxbuf
= kmalloc(bus
->rxblen
, GFP_ATOMIC
);
5449 if (!(bus
->rxbuf
)) {
5450 DHD_ERROR(("%s: kmalloc of %d-byte rxbuf failed\n",
5451 __func__
, bus
->rxblen
));
5456 /* Allocate buffer to receive glomed packet */
5457 bus
->databuf
= kmalloc(MAX_DATA_BUF
, GFP_ATOMIC
);
5458 if (!(bus
->databuf
)) {
5459 DHD_ERROR(("%s: kmalloc of %d-byte databuf failed\n",
5460 __func__
, MAX_DATA_BUF
));
5461 /* release rxbuf which was already located as above */
5467 /* Align the buffer */
5468 if ((unsigned long)bus
->databuf
% DHD_SDALIGN
)
5470 bus
->databuf
+ (DHD_SDALIGN
-
5471 ((unsigned long)bus
->databuf
% DHD_SDALIGN
));
5473 bus
->dataptr
= bus
->databuf
;
5481 static bool dhdsdio_probe_init(dhd_bus_t
*bus
, void *sdh
)
5485 DHD_TRACE(("%s: Enter\n", __func__
));
5488 dhdsdio_pktgen_init(bus
);
5491 /* Disable F2 to clear any intermediate frame state on the dongle */
5492 bcmsdh_cfg_write(sdh
, SDIO_FUNC_0
, SDIO_CCCR_IOEx
, SDIO_FUNC_ENABLE_1
,
5495 bus
->dhd
->busstate
= DHD_BUS_DOWN
;
5496 bus
->sleeping
= false;
5497 bus
->rxflow
= false;
5498 bus
->prev_rxlim_hit
= 0;
5500 /* Done with backplane-dependent accesses, can drop clock... */
5501 bcmsdh_cfg_write(sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_CHIPCLKCSR
, 0, NULL
);
5503 /* ...and initialize clock/power states */
5504 bus
->clkstate
= CLK_SDONLY
;
5505 bus
->idletime
= (s32
) dhd_idletime
;
5506 bus
->idleclock
= DHD_IDLE_ACTIVE
;
5508 /* Query the F2 block size, set roundup accordingly */
5510 if (bcmsdh_iovar_op(sdh
, "sd_blocksize", &fnum
, sizeof(s32
),
5511 &bus
->blocksize
, sizeof(s32
), false) != 0) {
5513 DHD_ERROR(("%s: fail on %s get\n", __func__
, "sd_blocksize"));
5515 DHD_INFO(("%s: Initial value for %s is %d\n",
5516 __func__
, "sd_blocksize", bus
->blocksize
));
5518 bus
->roundup
= min(max_roundup
, bus
->blocksize
);
5520 /* Query if bus module supports packet chaining,
5521 default to use if supported */
5522 if (bcmsdh_iovar_op(sdh
, "sd_rxchain", NULL
, 0,
5523 &bus
->sd_rxchain
, sizeof(s32
),
5525 bus
->sd_rxchain
= false;
5527 DHD_INFO(("%s: bus module (through bcmsdh API) %s chaining\n",
5529 (bus
->sd_rxchain
? "supports" : "does not support")));
5531 bus
->use_rxchain
= (bool) bus
->sd_rxchain
;
5537 dhd_bus_download_firmware(struct dhd_bus
*bus
, char *fw_path
, char *nv_path
)
5540 bus
->fw_path
= fw_path
;
5541 bus
->nv_path
= nv_path
;
5543 ret
= dhdsdio_download_firmware(bus
, bus
->sdh
);
5549 dhdsdio_download_firmware(struct dhd_bus
*bus
, void *sdh
)
5553 /* Download the firmware */
5554 dhdsdio_clkctl(bus
, CLK_AVAIL
, false);
5556 ret
= _dhdsdio_download_firmware(bus
) == 0;
5558 dhdsdio_clkctl(bus
, CLK_SDONLY
, false);
5563 /* Detach and free everything */
5564 static void dhdsdio_release(dhd_bus_t
*bus
)
5566 DHD_TRACE(("%s: Enter\n", __func__
));
5569 /* De-register interrupt handler */
5570 bcmsdh_intr_disable(bus
->sdh
);
5571 bcmsdh_intr_dereg(bus
->sdh
);
5574 dhd_detach(bus
->dhd
);
5575 dhdsdio_release_dongle(bus
);
5579 dhdsdio_release_malloc(bus
);
5584 DHD_TRACE(("%s: Disconnected\n", __func__
));
5587 static void dhdsdio_release_malloc(dhd_bus_t
*bus
)
5589 DHD_TRACE(("%s: Enter\n", __func__
));
5591 if (bus
->dhd
&& bus
->dhd
->dongle_reset
)
5596 bus
->rxctl
= bus
->rxbuf
= NULL
;
5600 kfree(bus
->databuf
);
5601 bus
->databuf
= NULL
;
5604 static void dhdsdio_release_dongle(dhd_bus_t
*bus
)
5606 DHD_TRACE(("%s: Enter\n", __func__
));
5608 if (bus
->dhd
&& bus
->dhd
->dongle_reset
)
5612 dhdsdio_clkctl(bus
, CLK_AVAIL
, false);
5613 dhdsdio_clkctl(bus
, CLK_NONE
, false);
5614 dhdsdio_chip_detach(bus
);
5615 if (bus
->vars
&& bus
->varsz
)
5620 DHD_TRACE(("%s: Disconnected\n", __func__
));
5623 static void dhdsdio_disconnect(void *ptr
)
5625 dhd_bus_t
*bus
= (dhd_bus_t
*)ptr
;
5627 DHD_TRACE(("%s: Enter\n", __func__
));
5631 dhdsdio_release(bus
);
5634 DHD_TRACE(("%s: Disconnected\n", __func__
));
5637 /* Register/Unregister functions are called by the main DHD entry
5638 * point (e.g. module insertion) to link with the bus driver, in
5639 * order to look for or await the device.
5642 static bcmsdh_driver_t dhd_sdio
= {
5647 int dhd_bus_register(void)
5649 DHD_TRACE(("%s: Enter\n", __func__
));
5651 return bcmsdh_register(&dhd_sdio
);
5654 void dhd_bus_unregister(void)
5656 DHD_TRACE(("%s: Enter\n", __func__
));
5658 bcmsdh_unregister();
5661 static int dhdsdio_download_code_file(struct dhd_bus
*bus
, char *fw_path
)
5667 u8
*memblock
= NULL
, *memptr
;
5669 DHD_INFO(("%s: download firmware %s\n", __func__
, fw_path
));
5671 image
= dhd_os_open_image(fw_path
);
5675 memptr
= memblock
= kmalloc(MEMBLOCK
+ DHD_SDALIGN
, GFP_ATOMIC
);
5676 if (memblock
== NULL
) {
5677 DHD_ERROR(("%s: Failed to allocate memory %d bytes\n",
5678 __func__
, MEMBLOCK
));
5681 if ((u32
)(unsigned long)memblock
% DHD_SDALIGN
)
5683 (DHD_SDALIGN
- ((u32
)(unsigned long)memblock
% DHD_SDALIGN
));
5685 /* Download image */
5687 dhd_os_get_image_block((char *)memptr
, MEMBLOCK
, image
))) {
5688 bcmerror
= dhdsdio_membytes(bus
, true, offset
, memptr
, len
);
5690 DHD_ERROR(("%s: error %d on writing %d membytes at "
5691 "0x%08x\n", __func__
, bcmerror
, MEMBLOCK
, offset
));
5702 dhd_os_close_image(image
);
5708 * ProcessVars:Takes a buffer of "<var>=<value>\n" lines read from a file
5709 * and ending in a NUL.
5710 * Removes carriage returns, empty lines, comment lines, and converts
5712 * Shortens buffer as needed and pads with NULs. End of buffer is marked
5716 static uint
process_nvram_vars(char *varbuf
, uint len
)
5725 findNewline
= false;
5728 for (n
= 0; n
< len
; n
++) {
5731 if (varbuf
[n
] == '\r')
5733 if (findNewline
&& varbuf
[n
] != '\n')
5735 findNewline
= false;
5736 if (varbuf
[n
] == '#') {
5740 if (varbuf
[n
] == '\n') {
5750 buf_len
= dp
- varbuf
;
5752 while (dp
< varbuf
+ n
)
5759 EXAMPLE: nvram_array
5762 Use carriage return at the end of each assignment,
5763 and an empty string with
5764 carriage return at the end of array.
5767 unsigned char nvram_array[] = {"name1=value1\n",
5768 "name2=value2\n", "\n"};
5769 Hex values start with 0x, and mac addr format: xx:xx:xx:xx:xx:xx.
5771 Search "EXAMPLE: nvram_array" to see how the array is activated.
5774 void dhd_bus_set_nvram_params(struct dhd_bus
*bus
, const char *nvram_params
)
5776 bus
->nvram_params
= nvram_params
;
5779 static int dhdsdio_download_nvram(struct dhd_bus
*bus
)
5784 char *memblock
= NULL
;
5787 bool nvram_file_exists
;
5789 nv_path
= bus
->nv_path
;
5791 nvram_file_exists
= ((nv_path
!= NULL
) && (nv_path
[0] != '\0'));
5792 if (!nvram_file_exists
&& (bus
->nvram_params
== NULL
))
5795 if (nvram_file_exists
) {
5796 image
= dhd_os_open_image(nv_path
);
5801 memblock
= kmalloc(MEMBLOCK
, GFP_ATOMIC
);
5802 if (memblock
== NULL
) {
5803 DHD_ERROR(("%s: Failed to allocate memory %d bytes\n",
5804 __func__
, MEMBLOCK
));
5808 /* Download variables */
5809 if (nvram_file_exists
) {
5810 len
= dhd_os_get_image_block(memblock
, MEMBLOCK
, image
);
5812 len
= strlen(bus
->nvram_params
);
5813 ASSERT(len
<= MEMBLOCK
);
5816 memcpy(memblock
, bus
->nvram_params
, len
);
5819 if (len
> 0 && len
< MEMBLOCK
) {
5820 bufp
= (char *)memblock
;
5822 len
= process_nvram_vars(bufp
, len
);
5826 bcmerror
= dhdsdio_downloadvars(bus
, memblock
, len
+ 1);
5828 DHD_ERROR(("%s: error downloading vars: %d\n",
5829 __func__
, bcmerror
));
5832 DHD_ERROR(("%s: error reading nvram file: %d\n",
5841 dhd_os_close_image(image
);
5846 static int _dhdsdio_download_firmware(struct dhd_bus
*bus
)
5850 bool embed
= false; /* download embedded firmware */
5851 bool dlok
= false; /* download firmware succeeded */
5853 /* Out immediately if no image to download */
5854 if ((bus
->fw_path
== NULL
) || (bus
->fw_path
[0] == '\0'))
5857 /* Keep arm in reset */
5858 if (dhdsdio_download_state(bus
, true)) {
5859 DHD_ERROR(("%s: error placing ARM core in reset\n", __func__
));
5863 /* External image takes precedence if specified */
5864 if ((bus
->fw_path
!= NULL
) && (bus
->fw_path
[0] != '\0')) {
5865 if (dhdsdio_download_code_file(bus
, bus
->fw_path
)) {
5866 DHD_ERROR(("%s: dongle image file download failed\n",
5875 DHD_ERROR(("%s: dongle image download failed\n", __func__
));
5879 /* EXAMPLE: nvram_array */
5880 /* If a valid nvram_arry is specified as above, it can be passed
5882 /* dhd_bus_set_nvram_params(bus, (char *)&nvram_array); */
5884 /* External nvram takes precedence if specified */
5885 if (dhdsdio_download_nvram(bus
)) {
5886 DHD_ERROR(("%s: dongle nvram file download failed\n",
5890 /* Take arm out of reset */
5891 if (dhdsdio_download_state(bus
, false)) {
5892 DHD_ERROR(("%s: error getting out of ARM core reset\n",
5905 dhd_bcmsdh_send_buf(dhd_bus_t
*bus
, u32 addr
, uint fn
, uint flags
,
5906 u8
*buf
, uint nbytes
, struct sk_buff
*pkt
,
5907 bcmsdh_cmplt_fn_t complete
, void *handle
)
5909 return bcmsdh_send_buf
5910 (bus
->sdh
, addr
, fn
, flags
, buf
, nbytes
, pkt
, complete
,
5914 uint
dhd_bus_chip(struct dhd_bus
*bus
)
5916 ASSERT(bus
->ci
!= NULL
);
5917 return bus
->ci
->chip
;
5920 void *dhd_bus_pub(struct dhd_bus
*bus
)
5925 void *dhd_bus_txq(struct dhd_bus
*bus
)
5930 uint
dhd_bus_hdrlen(struct dhd_bus
*bus
)
5932 return SDPCM_HDRLEN
;
5935 int dhd_bus_devreset(dhd_pub_t
*dhdp
, u8 flag
)
5943 if (!bus
->dhd
->dongle_reset
) {
5944 /* Expect app to have torn down any
5945 connection before calling */
5946 /* Stop the bus, disable F2 */
5947 dhd_bus_stop(bus
, false);
5949 /* Clean tx/rx buffer pointers,
5950 detach from the dongle */
5951 dhdsdio_release_dongle(bus
);
5953 bus
->dhd
->dongle_reset
= true;
5954 bus
->dhd
->up
= false;
5956 DHD_TRACE(("%s: WLAN OFF DONE\n", __func__
));
5957 /* App can now remove power from device */
5961 /* App must have restored power to device before calling */
5963 DHD_TRACE(("\n\n%s: == WLAN ON ==\n", __func__
));
5965 if (bus
->dhd
->dongle_reset
) {
5967 /* Reset SD client */
5968 bcmsdh_reset(bus
->sdh
);
5970 /* Attempt to re-attach & download */
5971 if (dhdsdio_probe_attach(bus
, bus
->sdh
,
5972 (u32
*) SI_ENUM_BASE
,
5974 /* Attempt to download binary to the dongle */
5975 if (dhdsdio_probe_init
5977 && dhdsdio_download_firmware(bus
,
5980 /* Re-init bus, enable F2 transfer */
5981 dhd_bus_init((dhd_pub_t
*) bus
->dhd
,
5984 #if defined(OOB_INTR_ONLY)
5985 dhd_enable_oob_intr(bus
, true);
5986 #endif /* defined(OOB_INTR_ONLY) */
5988 bus
->dhd
->dongle_reset
= false;
5989 bus
->dhd
->up
= true;
5991 DHD_TRACE(("%s: WLAN ON DONE\n",
5998 bcmerror
= -EISCONN
;
5999 DHD_ERROR(("%s: Set DEVRESET=false invoked when device "
6000 "is on\n", __func__
));
6008 dhdsdio_chip_recognition(bcmsdh_info_t
*sdh
, struct chip_info
*ci
, void *regs
)
6014 * Chipid is assume to be at offset 0 from regs arg
6015 * For different chiptypes or old sdio hosts w/o chipcommon,
6016 * other ways of recognition should be added here.
6018 ci
->cccorebase
= (u32
)regs
;
6019 regdata
= bcmsdh_reg_read(sdh
, CORE_CC_REG(ci
->cccorebase
, chipid
), 4);
6020 ci
->chip
= regdata
& CID_ID_MASK
;
6021 ci
->chiprev
= (regdata
& CID_REV_MASK
) >> CID_REV_SHIFT
;
6023 DHD_INFO(("%s: chipid=0x%x chiprev=%d\n",
6024 __func__
, ci
->chip
, ci
->chiprev
));
6026 /* Address of cores for new chips should be added here */
6028 case BCM4329_CHIP_ID
:
6029 ci
->buscorebase
= BCM4329_CORE_BUS_BASE
;
6030 ci
->ramcorebase
= BCM4329_CORE_SOCRAM_BASE
;
6031 ci
->armcorebase
= BCM4329_CORE_ARM_BASE
;
6032 ci
->ramsize
= BCM4329_RAMSIZE
;
6035 DHD_ERROR(("%s: chipid 0x%x is not supported\n",
6036 __func__
, ci
->chip
));
6040 regdata
= bcmsdh_reg_read(sdh
,
6041 CORE_SB(ci
->cccorebase
, sbidhigh
), 4);
6042 ci
->ccrev
= SBCOREREV(regdata
);
6044 regdata
= bcmsdh_reg_read(sdh
,
6045 CORE_CC_REG(ci
->cccorebase
, pmucapabilities
), 4);
6046 ci
->pmurev
= regdata
& PCAP_REV_MASK
;
6048 regdata
= bcmsdh_reg_read(sdh
, CORE_SB(ci
->buscorebase
, sbidhigh
), 4);
6049 ci
->buscorerev
= SBCOREREV(regdata
);
6050 ci
->buscoretype
= (regdata
& SBIDH_CC_MASK
) >> SBIDH_CC_SHIFT
;
6052 DHD_INFO(("%s: ccrev=%d, pmurev=%d, buscore rev/type=%d/0x%x\n",
6053 __func__
, ci
->ccrev
, ci
->pmurev
,
6054 ci
->buscorerev
, ci
->buscoretype
));
6056 /* get chipcommon capabilites */
6057 ci
->cccaps
= bcmsdh_reg_read(sdh
,
6058 CORE_CC_REG(ci
->cccorebase
, capabilities
), 4);
6064 dhdsdio_chip_disablecore(bcmsdh_info_t
*sdh
, u32 corebase
)
6068 regdata
= bcmsdh_reg_read(sdh
,
6069 CORE_SB(corebase
, sbtmstatelow
), 4);
6070 if (regdata
& SBTML_RESET
)
6073 regdata
= bcmsdh_reg_read(sdh
,
6074 CORE_SB(corebase
, sbtmstatelow
), 4);
6075 if ((regdata
& (SICF_CLOCK_EN
<< SBTML_SICF_SHIFT
)) != 0) {
6077 * set target reject and spin until busy is clear
6078 * (preserve core-specific bits)
6080 regdata
= bcmsdh_reg_read(sdh
,
6081 CORE_SB(corebase
, sbtmstatelow
), 4);
6082 bcmsdh_reg_write(sdh
, CORE_SB(corebase
, sbtmstatelow
), 4,
6083 regdata
| SBTML_REJ
);
6085 regdata
= bcmsdh_reg_read(sdh
,
6086 CORE_SB(corebase
, sbtmstatelow
), 4);
6088 SPINWAIT((bcmsdh_reg_read(sdh
,
6089 CORE_SB(corebase
, sbtmstatehigh
), 4) &
6090 SBTMH_BUSY
), 100000);
6092 regdata
= bcmsdh_reg_read(sdh
,
6093 CORE_SB(corebase
, sbtmstatehigh
), 4);
6094 if (regdata
& SBTMH_BUSY
)
6095 DHD_ERROR(("%s: ARM core still busy\n", __func__
));
6097 regdata
= bcmsdh_reg_read(sdh
,
6098 CORE_SB(corebase
, sbidlow
), 4);
6099 if (regdata
& SBIDL_INIT
) {
6100 regdata
= bcmsdh_reg_read(sdh
,
6101 CORE_SB(corebase
, sbimstate
), 4) |
6103 bcmsdh_reg_write(sdh
,
6104 CORE_SB(corebase
, sbimstate
), 4,
6106 regdata
= bcmsdh_reg_read(sdh
,
6107 CORE_SB(corebase
, sbimstate
), 4);
6109 SPINWAIT((bcmsdh_reg_read(sdh
,
6110 CORE_SB(corebase
, sbimstate
), 4) &
6114 /* set reset and reject while enabling the clocks */
6115 bcmsdh_reg_write(sdh
,
6116 CORE_SB(corebase
, sbtmstatelow
), 4,
6117 (((SICF_FGC
| SICF_CLOCK_EN
) << SBTML_SICF_SHIFT
) |
6118 SBTML_REJ
| SBTML_RESET
));
6119 regdata
= bcmsdh_reg_read(sdh
,
6120 CORE_SB(corebase
, sbtmstatelow
), 4);
6123 /* clear the initiator reject bit */
6124 regdata
= bcmsdh_reg_read(sdh
,
6125 CORE_SB(corebase
, sbidlow
), 4);
6126 if (regdata
& SBIDL_INIT
) {
6127 regdata
= bcmsdh_reg_read(sdh
,
6128 CORE_SB(corebase
, sbimstate
), 4) &
6130 bcmsdh_reg_write(sdh
,
6131 CORE_SB(corebase
, sbimstate
), 4,
6136 /* leave reset and reject asserted */
6137 bcmsdh_reg_write(sdh
, CORE_SB(corebase
, sbtmstatelow
), 4,
6138 (SBTML_REJ
| SBTML_RESET
));
6143 dhdsdio_chip_attach(struct dhd_bus
*bus
, void *regs
)
6145 struct chip_info
*ci
;
6149 DHD_TRACE(("%s: Enter\n", __func__
));
6151 /* alloc chip_info_t */
6152 ci
= kmalloc(sizeof(struct chip_info
), GFP_ATOMIC
);
6154 DHD_ERROR(("%s: malloc failed!\n", __func__
));
6158 memset((unsigned char *)ci
, 0, sizeof(struct chip_info
));
6160 /* bus/core/clk setup for register access */
6161 /* Try forcing SDIO core to do ALPAvail request only */
6162 clkset
= SBSDIO_FORCE_HW_CLKREQ_OFF
| SBSDIO_ALP_AVAIL_REQ
;
6163 bcmsdh_cfg_write(bus
->sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_CHIPCLKCSR
,
6166 DHD_ERROR(("%s: error writing for HT off\n", __func__
));
6170 /* If register supported, wait for ALPAvail and then force ALP */
6171 /* This may take up to 15 milliseconds */
6172 clkval
= bcmsdh_cfg_read(bus
->sdh
, SDIO_FUNC_1
,
6173 SBSDIO_FUNC1_CHIPCLKCSR
, NULL
);
6174 if ((clkval
& ~SBSDIO_AVBITS
) == clkset
) {
6176 bcmsdh_cfg_read(bus
->sdh
, SDIO_FUNC_1
,
6177 SBSDIO_FUNC1_CHIPCLKCSR
,
6179 !SBSDIO_ALPAV(clkval
)),
6180 PMU_MAX_TRANSITION_DLY
);
6181 if (!SBSDIO_ALPAV(clkval
)) {
6182 DHD_ERROR(("%s: timeout on ALPAV wait, clkval 0x%02x\n",
6187 clkset
= SBSDIO_FORCE_HW_CLKREQ_OFF
|
6189 bcmsdh_cfg_write(bus
->sdh
, SDIO_FUNC_1
,
6190 SBSDIO_FUNC1_CHIPCLKCSR
,
6194 DHD_ERROR(("%s: ChipClkCSR access: wrote 0x%02x read 0x%02x\n",
6195 __func__
, clkset
, clkval
));
6200 /* Also, disable the extra SDIO pull-ups */
6201 bcmsdh_cfg_write(bus
->sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_SDIOPULLUP
, 0,
6204 err
= dhdsdio_chip_recognition(bus
->sdh
, ci
, regs
);
6209 * Make sure any on-chip ARM is off (in case strapping is wrong),
6210 * or downloaded code was already running.
6212 dhdsdio_chip_disablecore(bus
->sdh
, ci
->armcorebase
);
6214 bcmsdh_reg_write(bus
->sdh
,
6215 CORE_CC_REG(ci
->cccorebase
, gpiopullup
), 4, 0);
6216 bcmsdh_reg_write(bus
->sdh
,
6217 CORE_CC_REG(ci
->cccorebase
, gpiopulldown
), 4, 0);
6219 /* Disable F2 to clear any intermediate frame state on the dongle */
6220 bcmsdh_cfg_write(bus
->sdh
, SDIO_FUNC_0
, SDIO_CCCR_IOEx
,
6221 SDIO_FUNC_ENABLE_1
, NULL
);
6223 /* WAR: cmd52 backplane read so core HW will drop ALPReq */
6224 clkval
= bcmsdh_cfg_read(bus
->sdh
, SDIO_FUNC_1
,
6227 /* Done with backplane-dependent accesses, can drop clock... */
6228 bcmsdh_cfg_write(bus
->sdh
, SDIO_FUNC_1
, SBSDIO_FUNC1_CHIPCLKCSR
, 0,
6240 dhdsdio_chip_resetcore(bcmsdh_info_t
*sdh
, u32 corebase
)
6245 * Must do the disable sequence first to work for
6246 * arbitrary current core state.
6248 dhdsdio_chip_disablecore(sdh
, corebase
);
6251 * Now do the initialization sequence.
6252 * set reset while enabling the clock and
6253 * forcing them on throughout the core
6255 bcmsdh_reg_write(sdh
, CORE_SB(corebase
, sbtmstatelow
), 4,
6256 ((SICF_FGC
| SICF_CLOCK_EN
) << SBTML_SICF_SHIFT
) |
6260 regdata
= bcmsdh_reg_read(sdh
, CORE_SB(corebase
, sbtmstatehigh
), 4);
6261 if (regdata
& SBTMH_SERR
)
6262 bcmsdh_reg_write(sdh
, CORE_SB(corebase
, sbtmstatehigh
), 4, 0);
6264 regdata
= bcmsdh_reg_read(sdh
, CORE_SB(corebase
, sbimstate
), 4);
6265 if (regdata
& (SBIM_IBE
| SBIM_TO
))
6266 bcmsdh_reg_write(sdh
, CORE_SB(corebase
, sbimstate
), 4,
6267 regdata
& ~(SBIM_IBE
| SBIM_TO
));
6269 /* clear reset and allow it to propagate throughout the core */
6270 bcmsdh_reg_write(sdh
, CORE_SB(corebase
, sbtmstatelow
), 4,
6271 (SICF_FGC
<< SBTML_SICF_SHIFT
) |
6272 (SICF_CLOCK_EN
<< SBTML_SICF_SHIFT
));
6275 /* leave clock enabled */
6276 bcmsdh_reg_write(sdh
, CORE_SB(corebase
, sbtmstatelow
), 4,
6277 (SICF_CLOCK_EN
<< SBTML_SICF_SHIFT
));
6281 /* SDIO Pad drive strength to select value mappings */
6282 struct sdiod_drive_str
{
6283 u8 strength
; /* Pad Drive Strength in mA */
6284 u8 sel
; /* Chip-specific select value */
6287 /* SDIO Drive Strength to sel value table for PMU Rev 1 */
6288 static const struct sdiod_drive_str sdiod_drive_strength_tab1
[] = {
6296 /* SDIO Drive Strength to sel value table for PMU Rev 2, 3 */
6297 static const struct sdiod_drive_str sdiod_drive_strength_tab2
[] = {
6308 /* SDIO Drive Strength to sel value table for PMU Rev 8 (1.8V) */
6309 static const struct sdiod_drive_str sdiod_drive_strength_tab3
[] = {
6321 #define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu))
6324 dhdsdio_sdiod_drive_strength_init(struct dhd_bus
*bus
, u32 drivestrength
) {
6325 struct sdiod_drive_str
*str_tab
= NULL
;
6330 if (!(bus
->ci
->cccaps
& CC_CAP_PMU
))
6333 switch (SDIOD_DRVSTR_KEY(bus
->ci
->chip
, bus
->ci
->pmurev
)) {
6334 case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID
, 1):
6335 str_tab
= (struct sdiod_drive_str
*)&sdiod_drive_strength_tab1
;
6336 str_mask
= 0x30000000;
6339 case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID
, 2):
6340 case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID
, 3):
6341 str_tab
= (struct sdiod_drive_str
*)&sdiod_drive_strength_tab2
;
6342 str_mask
= 0x00003800;
6345 case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID
, 8):
6346 str_tab
= (struct sdiod_drive_str
*)&sdiod_drive_strength_tab3
;
6347 str_mask
= 0x00003800;
6351 DHD_ERROR(("No SDIO Drive strength init"
6352 "done for chip %s rev %d pmurev %d\n",
6353 brcmu_chipname(bus
->ci
->chip
, chn
, 8),
6354 bus
->ci
->chiprev
, bus
->ci
->pmurev
));
6358 if (str_tab
!= NULL
) {
6359 u32 drivestrength_sel
= 0;
6363 for (i
= 0; str_tab
[i
].strength
!= 0; i
++) {
6364 if (drivestrength
>= str_tab
[i
].strength
) {
6365 drivestrength_sel
= str_tab
[i
].sel
;
6370 bcmsdh_reg_write(bus
->sdh
,
6371 CORE_CC_REG(bus
->ci
->cccorebase
, chipcontrol_addr
),
6373 cc_data_temp
= bcmsdh_reg_read(bus
->sdh
,
6374 CORE_CC_REG(bus
->ci
->cccorebase
, chipcontrol_addr
), 4);
6375 cc_data_temp
&= ~str_mask
;
6376 drivestrength_sel
<<= str_shift
;
6377 cc_data_temp
|= drivestrength_sel
;
6378 bcmsdh_reg_write(bus
->sdh
,
6379 CORE_CC_REG(bus
->ci
->cccorebase
, chipcontrol_addr
),
6382 DHD_INFO(("SDIO: %dmA drive strength selected, set to 0x%08x\n",
6383 drivestrength
, cc_data_temp
));
6388 dhdsdio_chip_detach(struct dhd_bus
*bus
)
6390 DHD_TRACE(("%s: Enter\n", __func__
));