/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c
https://bitbucket.org/cyanogenmod/android_kernel_asus_tf300t · C · 6772 lines · 5051 code · 1015 blank · 706 comment · 946 complexity · 02856cd1f5dfd7e3cc5f432120f1cff0 MD5 · raw file
Large files are truncated click here to view the full file
- /*
- * Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
- #include <linux/types.h>
- #include <linux/kernel.h>
- #include <linux/kthread.h>
- #include <linux/printk.h>
- #include <linux/pci_ids.h>
- #include <linux/netdevice.h>
- #include <linux/interrupt.h>
- #include <linux/sched.h>
- #include <linux/mmc/sdio.h>
- #include <linux/mmc/sdio_func.h>
- #include <linux/semaphore.h>
- #include <linux/firmware.h>
- #include <asm/unaligned.h>
- #include <defs.h>
- #include <brcmu_wifi.h>
- #include <brcmu_utils.h>
- #include <brcm_hw_ids.h>
- #include <soc.h>
- #include "sdio_host.h"
- /* register access macros */
- #ifndef __BIG_ENDIAN
- #ifndef __mips__
- #define R_REG(r, typ) \
- brcmf_sdcard_reg_read(NULL, (r), sizeof(typ))
- #else /* __mips__ */
- #define R_REG(r, typ) \
- ({ \
- __typeof(*(r)) __osl_v; \
- __asm__ __volatile__("sync"); \
- __osl_v = brcmf_sdcard_reg_read(NULL, (r),\
- sizeof(typ)); \
- __asm__ __volatile__("sync"); \
- __osl_v; \
- })
- #endif /* __mips__ */
- #else /* __BIG_ENDIAN */
- #define R_REG(r, typ) \
- brcmf_sdcard_reg_read(NULL, (r), sizeof(typ))
- #endif /* __BIG_ENDIAN */
- #define OR_REG(r, v, typ) \
- brcmf_sdcard_reg_write(NULL, (r), sizeof(typ), R_REG(r, typ) | (v))
- #ifdef BCMDBG
- /* ARM trap handling */
- /* Trap types defined by ARM (see arminc.h) */
- #if defined(__ARM_ARCH_4T__)
- #define MAX_TRAP_TYPE (TR_FIQ + 1)
- #elif defined(__ARM_ARCH_7M__)
- #define MAX_TRAP_TYPE (TR_ISR + ARMCM3_NUMINTS)
- #endif /* __ARM_ARCH_7M__ */
- /* The trap structure is defined here as offsets for assembly */
- #define TR_TYPE 0x00
- #define TR_EPC 0x04
- #define TR_CPSR 0x08
- #define TR_SPSR 0x0c
- #define TR_REGS 0x10
- #define TR_REG(n) (TR_REGS + (n) * 4)
- #define TR_SP TR_REG(13)
- #define TR_LR TR_REG(14)
- #define TR_PC TR_REG(15)
- #define TRAP_T_SIZE 80
- struct brcmf_trap {
- u32 type;
- u32 epc;
- u32 cpsr;
- u32 spsr;
- u32 r0;
- u32 r1;
- u32 r2;
- u32 r3;
- u32 r4;
- u32 r5;
- u32 r6;
- u32 r7;
- u32 r8;
- u32 r9;
- u32 r10;
- u32 r11;
- u32 r12;
- u32 r13;
- u32 r14;
- u32 pc;
- };
- #define CBUF_LEN (128)
- struct rte_log {
- u32 buf; /* Can't be pointer on (64-bit) hosts */
- uint buf_size;
- uint idx;
- char *_buf_compat; /* Redundant pointer for backward compat. */
- };
- struct rte_console {
- /* Virtual UART
- * When there is no UART (e.g. Quickturn),
- * the host should write a complete
- * input line directly into cbuf and then write
- * the length into vcons_in.
- * This may also be used when there is a real UART
- * (at risk of conflicting with
- * the real UART). vcons_out is currently unused.
- */
- volatile uint vcons_in;
- volatile uint vcons_out;
- /* Output (logging) buffer
- * Console output is written to a ring buffer log_buf at index log_idx.
- * The host may read the output when it sees log_idx advance.
- * Output will be lost if the output wraps around faster than the host
- * polls.
- */
- struct rte_log log;
- /* Console input line buffer
- * Characters are read one at a time into cbuf
- * until <CR> is received, then
- * the buffer is processed as a command line.
- * Also used for virtual UART.
- */
- uint cbuf_idx;
- char cbuf[CBUF_LEN];
- };
- #endif /* BCMDBG */
- #include <chipcommon.h>
- #include "dhd.h"
- #include "dhd_bus.h"
- #include "dhd_proto.h"
- #include "dhd_dbg.h"
- #include <bcmchip.h>
- #define TXQLEN 2048 /* bulk tx queue length */
- #define TXHI (TXQLEN - 256) /* turn on flow control above TXHI */
- #define TXLOW (TXHI - 256) /* turn off flow control below TXLOW */
- #define PRIOMASK 7
- #define TXRETRIES 2 /* # of retries for tx frames */
- #define BRCMF_RXBOUND 50 /* Default for max rx frames in
- one scheduling */
- #define BRCMF_TXBOUND 20 /* Default for max tx frames in
- one scheduling */
- #define BRCMF_TXMINMAX 1 /* Max tx frames if rx still pending */
- #define MEMBLOCK 2048 /* Block size used for downloading
- of dongle image */
- #define MAX_DATA_BUF (32 * 1024) /* Must be large enough to hold
- biggest possible glom */
- #ifndef BRCMF_FIRSTREAD
- #define BRCMF_FIRSTREAD 32
- #endif
- #if !ISPOWEROF2(BRCMF_FIRSTREAD)
- #error BRCMF_FIRSTREAD is not a power of 2!
- #endif
- /* SBSDIO_DEVICE_CTL */
- #define SBSDIO_DEVCTL_SETBUSY 0x01 /* 1: device will assert busy signal when
- * receiving CMD53
- */
- #define SBSDIO_DEVCTL_SPI_INTR_SYNC 0x02 /* 1: assertion of sdio interrupt is
- * synchronous to the sdio clock
- */
- #define SBSDIO_DEVCTL_CA_INT_ONLY 0x04 /* 1: mask all interrupts to host
- * except the chipActive (rev 8)
- */
- #define SBSDIO_DEVCTL_PADS_ISO 0x08 /* 1: isolate internal sdio signals, put
- * external pads in tri-state; requires
- * sdio bus power cycle to clear (rev 9)
- */
- #define SBSDIO_DEVCTL_SB_RST_CTL 0x30 /* Force SD->SB reset mapping (rev 11) */
- #define SBSDIO_DEVCTL_RST_CORECTL 0x00 /* Determined by CoreControl bit */
- #define SBSDIO_DEVCTL_RST_BPRESET 0x10 /* Force backplane reset */
- #define SBSDIO_DEVCTL_RST_NOBPRESET 0x20 /* Force no backplane reset */
- /* SBSDIO_FUNC1_CHIPCLKCSR */
- #define SBSDIO_FORCE_ALP 0x01 /* Force ALP request to backplane */
- #define SBSDIO_FORCE_HT 0x02 /* Force HT request to backplane */
- #define SBSDIO_FORCE_ILP 0x04 /* Force ILP request to backplane */
- #define SBSDIO_ALP_AVAIL_REQ 0x08 /* Make ALP ready (power up xtal) */
- #define SBSDIO_HT_AVAIL_REQ 0x10 /* Make HT ready (power up PLL) */
- #define SBSDIO_FORCE_HW_CLKREQ_OFF 0x20 /* Squelch clock requests from HW */
- #define SBSDIO_ALP_AVAIL 0x40 /* Status: ALP is ready */
- #define SBSDIO_HT_AVAIL 0x80 /* Status: HT is ready */
- #define SBSDIO_AVBITS (SBSDIO_HT_AVAIL | SBSDIO_ALP_AVAIL)
- #define SBSDIO_ALPAV(regval) ((regval) & SBSDIO_AVBITS)
- #define SBSDIO_HTAV(regval) (((regval) & SBSDIO_AVBITS) == SBSDIO_AVBITS)
- #define SBSDIO_ALPONLY(regval) (SBSDIO_ALPAV(regval) && !SBSDIO_HTAV(regval))
- #define SBSDIO_CLKAV(regval, alponly) (SBSDIO_ALPAV(regval) && \
- (alponly ? 1 : SBSDIO_HTAV(regval)))
- /* direct(mapped) cis space */
- #define SBSDIO_CIS_BASE_COMMON 0x1000 /* MAPPED common CIS address */
- #define SBSDIO_CIS_SIZE_LIMIT 0x200 /* maximum bytes in one CIS */
- #define SBSDIO_CIS_OFT_ADDR_MASK 0x1FFFF /* cis offset addr is < 17 bits */
- #define SBSDIO_CIS_MANFID_TUPLE_LEN 6 /* manfid tuple length, include tuple,
- * link bytes
- */
- /* intstatus */
- #define I_SMB_SW0 (1 << 0) /* To SB Mail S/W interrupt 0 */
- #define I_SMB_SW1 (1 << 1) /* To SB Mail S/W interrupt 1 */
- #define I_SMB_SW2 (1 << 2) /* To SB Mail S/W interrupt 2 */
- #define I_SMB_SW3 (1 << 3) /* To SB Mail S/W interrupt 3 */
- #define I_SMB_SW_MASK 0x0000000f /* To SB Mail S/W interrupts mask */
- #define I_SMB_SW_SHIFT 0 /* To SB Mail S/W interrupts shift */
- #define I_HMB_SW0 (1 << 4) /* To Host Mail S/W interrupt 0 */
- #define I_HMB_SW1 (1 << 5) /* To Host Mail S/W interrupt 1 */
- #define I_HMB_SW2 (1 << 6) /* To Host Mail S/W interrupt 2 */
- #define I_HMB_SW3 (1 << 7) /* To Host Mail S/W interrupt 3 */
- #define I_HMB_SW_MASK 0x000000f0 /* To Host Mail S/W interrupts mask */
- #define I_HMB_SW_SHIFT 4 /* To Host Mail S/W interrupts shift */
- #define I_WR_OOSYNC (1 << 8) /* Write Frame Out Of Sync */
- #define I_RD_OOSYNC (1 << 9) /* Read Frame Out Of Sync */
- #define I_PC (1 << 10) /* descriptor error */
- #define I_PD (1 << 11) /* data error */
- #define I_DE (1 << 12) /* Descriptor protocol Error */
- #define I_RU (1 << 13) /* Receive descriptor Underflow */
- #define I_RO (1 << 14) /* Receive fifo Overflow */
- #define I_XU (1 << 15) /* Transmit fifo Underflow */
- #define I_RI (1 << 16) /* Receive Interrupt */
- #define I_BUSPWR (1 << 17) /* SDIO Bus Power Change (rev 9) */
- #define I_XMTDATA_AVAIL (1 << 23) /* bits in fifo */
- #define I_XI (1 << 24) /* Transmit Interrupt */
- #define I_RF_TERM (1 << 25) /* Read Frame Terminate */
- #define I_WF_TERM (1 << 26) /* Write Frame Terminate */
- #define I_PCMCIA_XU (1 << 27) /* PCMCIA Transmit FIFO Underflow */
- #define I_SBINT (1 << 28) /* sbintstatus Interrupt */
- #define I_CHIPACTIVE (1 << 29) /* chip from doze to active state */
- #define I_SRESET (1 << 30) /* CCCR RES interrupt */
- #define I_IOE2 (1U << 31) /* CCCR IOE2 Bit Changed */
- #define I_ERRORS (I_PC | I_PD | I_DE | I_RU | I_RO | I_XU)
- #define I_DMA (I_RI | I_XI | I_ERRORS)
- /* corecontrol */
- #define CC_CISRDY (1 << 0) /* CIS Ready */
- #define CC_BPRESEN (1 << 1) /* CCCR RES signal */
- #define CC_F2RDY (1 << 2) /* set CCCR IOR2 bit */
- #define CC_CLRPADSISO (1 << 3) /* clear SDIO pads isolation */
- #define CC_XMTDATAAVAIL_MODE (1 << 4)
- #define CC_XMTDATAAVAIL_CTRL (1 << 5)
- /* SDA_FRAMECTRL */
- #define SFC_RF_TERM (1 << 0) /* Read Frame Terminate */
- #define SFC_WF_TERM (1 << 1) /* Write Frame Terminate */
- #define SFC_CRC4WOOS (1 << 2) /* CRC error for write out of sync */
- #define SFC_ABORTALL (1 << 3) /* Abort all in-progress frames */
- /* HW frame tag */
- #define SDPCM_FRAMETAG_LEN 4 /* 2 bytes len, 2 bytes check val */
- /* Total length of frame header for dongle protocol */
- #define SDPCM_HDRLEN (SDPCM_FRAMETAG_LEN + SDPCM_SWHEADER_LEN)
- #ifdef SDTEST
- #define SDPCM_RESERVE (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + BRCMF_SDALIGN)
- #else
- #define SDPCM_RESERVE (SDPCM_HDRLEN + BRCMF_SDALIGN)
- #endif
- /*
- * Software allocation of To SB Mailbox resources
- */
- /* tosbmailbox bits corresponding to intstatus bits */
- #define SMB_NAK (1 << 0) /* Frame NAK */
- #define SMB_INT_ACK (1 << 1) /* Host Interrupt ACK */
- #define SMB_USE_OOB (1 << 2) /* Use OOB Wakeup */
- #define SMB_DEV_INT (1 << 3) /* Miscellaneous Interrupt */
- /* tosbmailboxdata */
- #define SMB_DATA_VERSION_SHIFT 16 /* host protocol version */
- /*
- * Software allocation of To Host Mailbox resources
- */
- /* intstatus bits */
- #define I_HMB_FC_STATE I_HMB_SW0 /* Flow Control State */
- #define I_HMB_FC_CHANGE I_HMB_SW1 /* Flow Control State Changed */
- #define I_HMB_FRAME_IND I_HMB_SW2 /* Frame Indication */
- #define I_HMB_HOST_INT I_HMB_SW3 /* Miscellaneous Interrupt */
- /* tohostmailboxdata */
- #define HMB_DATA_NAKHANDLED 1 /* retransmit NAK'd frame */
- #define HMB_DATA_DEVREADY 2 /* talk to host after enable */
- #define HMB_DATA_FC 4 /* per prio flowcontrol update flag */
- #define HMB_DATA_FWREADY 8 /* fw ready for protocol activity */
- #define HMB_DATA_FCDATA_MASK 0xff000000
- #define HMB_DATA_FCDATA_SHIFT 24
- #define HMB_DATA_VERSION_MASK 0x00ff0000
- #define HMB_DATA_VERSION_SHIFT 16
- /*
- * Software-defined protocol header
- */
- /* Current protocol version */
- #define SDPCM_PROT_VERSION 4
- /* SW frame header */
- #define SDPCM_PACKET_SEQUENCE(p) (((u8 *)p)[0] & 0xff)
- #define SDPCM_CHANNEL_MASK 0x00000f00
- #define SDPCM_CHANNEL_SHIFT 8
- #define SDPCM_PACKET_CHANNEL(p) (((u8 *)p)[1] & 0x0f)
- #define SDPCM_NEXTLEN_OFFSET 2
- /* Data Offset from SOF (HW Tag, SW Tag, Pad) */
- #define SDPCM_DOFFSET_OFFSET 3 /* Data Offset */
- #define SDPCM_DOFFSET_VALUE(p) (((u8 *)p)[SDPCM_DOFFSET_OFFSET] & 0xff)
- #define SDPCM_DOFFSET_MASK 0xff000000
- #define SDPCM_DOFFSET_SHIFT 24
- #define SDPCM_FCMASK_OFFSET 4 /* Flow control */
- #define SDPCM_FCMASK_VALUE(p) (((u8 *)p)[SDPCM_FCMASK_OFFSET] & 0xff)
- #define SDPCM_WINDOW_OFFSET 5 /* Credit based fc */
- #define SDPCM_WINDOW_VALUE(p) (((u8 *)p)[SDPCM_WINDOW_OFFSET] & 0xff)
- #define SDPCM_SWHEADER_LEN 8 /* SW header is 64 bits */
- /* logical channel numbers */
- #define SDPCM_CONTROL_CHANNEL 0 /* Control channel Id */
- #define SDPCM_EVENT_CHANNEL 1 /* Asyc Event Indication Channel Id */
- #define SDPCM_DATA_CHANNEL 2 /* Data Xmit/Recv Channel Id */
- #define SDPCM_GLOM_CHANNEL 3 /* For coalesced packets */
- #define SDPCM_TEST_CHANNEL 15 /* Reserved for test/debug packets */
- #define SDPCM_SEQUENCE_WRAP 256 /* wrap-around val for 8bit frame seq */
- #define SDPCM_GLOMDESC(p) (((u8 *)p)[1] & 0x80)
- /* For TEST_CHANNEL packets, define another 4-byte header */
- #define SDPCM_TEST_HDRLEN 4 /*
- * Generally: Cmd(1), Ext(1), Len(2);
- * Semantics of Ext byte depend on
- * command. Len is current or requested
- * frame length, not including test
- * header; sent little-endian.
- */
- #define SDPCM_TEST_DISCARD 0x01 /* Receiver discards. Ext:pattern id. */
- #define SDPCM_TEST_ECHOREQ 0x02 /* Echo request. Ext:pattern id. */
- #define SDPCM_TEST_ECHORSP 0x03 /* Echo response. Ext:pattern id. */
- #define SDPCM_TEST_BURST 0x04 /*
- * Receiver to send a burst.
- * Ext is a frame count
- */
- #define SDPCM_TEST_SEND 0x05 /*
- * Receiver sets send mode.
- * Ext is boolean on/off
- */
- /* Handy macro for filling in datagen packets with a pattern */
- #define SDPCM_TEST_FILL(byteno, id) ((u8)(id + byteno))
- /*
- * Shared structure between dongle and the host.
- * The structure contains pointers to trap or assert information.
- */
- #define SDPCM_SHARED_VERSION 0x0002
- #define SDPCM_SHARED_VERSION_MASK 0x00FF
- #define SDPCM_SHARED_ASSERT_BUILT 0x0100
- #define SDPCM_SHARED_ASSERT 0x0200
- #define SDPCM_SHARED_TRAP 0x0400
- /* Space for header read, limit for data packets */
- #ifndef MAX_HDR_READ
- #define MAX_HDR_READ 32
- #endif
- #if !ISPOWEROF2(MAX_HDR_READ)
- #error MAX_HDR_READ is not a power of 2!
- #endif
- #define MAX_RX_DATASZ 2048
- /* Maximum milliseconds to wait for F2 to come up */
- #define BRCMF_WAIT_F2RDY 3000
- /* Bump up limit on waiting for HT to account for first startup;
- * if the image is doing a CRC calculation before programming the PMU
- * for HT availability, it could take a couple hundred ms more, so
- * max out at a 1 second (1000000us).
- */
- #if (PMU_MAX_TRANSITION_DLY <= 1000000)
- #undef PMU_MAX_TRANSITION_DLY
- #define PMU_MAX_TRANSITION_DLY 1000000
- #endif
- /* Value for ChipClockCSR during initial setup */
- #define BRCMF_INIT_CLKCTL1 (SBSDIO_FORCE_HW_CLKREQ_OFF | \
- SBSDIO_ALP_AVAIL_REQ)
- /* Flags for SDH calls */
- #define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED)
- /* sbimstate */
- #define SBIM_IBE 0x20000 /* inbanderror */
- #define SBIM_TO 0x40000 /* timeout */
- #define SBIM_BY 0x01800000 /* busy (sonics >= 2.3) */
- #define SBIM_RJ 0x02000000 /* reject (sonics >= 2.3) */
- /* sbtmstatelow */
- #define SBTML_RESET 0x0001 /* reset */
- #define SBTML_REJ_MASK 0x0006 /* reject field */
- #define SBTML_REJ 0x0002 /* reject */
- #define SBTML_TMPREJ 0x0004 /* temporary reject, for error recovery */
- #define SBTML_SICF_SHIFT 16 /* Shift to locate the SI control flags in sbtml */
- /* sbtmstatehigh */
- #define SBTMH_SERR 0x0001 /* serror */
- #define SBTMH_INT 0x0002 /* interrupt */
- #define SBTMH_BUSY 0x0004 /* busy */
- #define SBTMH_TO 0x0020 /* timeout (sonics >= 2.3) */
- #define SBTMH_SISF_SHIFT 16 /* Shift to locate the SI status flags in sbtmh */
- /* sbidlow */
- #define SBIDL_INIT 0x80 /* initiator */
- /* sbidhigh */
- #define SBIDH_RC_MASK 0x000f /* revision code */
- #define SBIDH_RCE_MASK 0x7000 /* revision code extension field */
- #define SBIDH_RCE_SHIFT 8
- #define SBCOREREV(sbidh) \
- ((((sbidh) & SBIDH_RCE_MASK) >> SBIDH_RCE_SHIFT) | ((sbidh) & SBIDH_RC_MASK))
- #define SBIDH_CC_MASK 0x8ff0 /* core code */
- #define SBIDH_CC_SHIFT 4
- #define SBIDH_VC_MASK 0xffff0000 /* vendor code */
- #define SBIDH_VC_SHIFT 16
- /*
- * Conversion of 802.1D priority to precedence level
- */
- #define PRIO2PREC(prio) \
- (((prio) == PRIO_8021D_NONE || (prio) == PRIO_8021D_BE) ? \
- ((prio^2)) : (prio))
- BRCMF_SPINWAIT_SLEEP_INIT(sdioh_spinwait_sleep);
- /*
- * Core reg address translation.
- * Both macro's returns a 32 bits byte address on the backplane bus.
- */
- #define CORE_CC_REG(base, field) (base + offsetof(chipcregs_t, field))
- #define CORE_BUS_REG(base, field) \
- (base + offsetof(struct sdpcmd_regs, field))
- #define CORE_SB(base, field) \
- (base + SBCONFIGOFF + offsetof(struct sbconfig, field))
- /* core registers */
- struct sdpcmd_regs {
- u32 corecontrol; /* 0x00, rev8 */
- u32 corestatus; /* rev8 */
- u32 PAD[1];
- u32 biststatus; /* rev8 */
- /* PCMCIA access */
- u16 pcmciamesportaladdr; /* 0x010, rev8 */
- u16 PAD[1];
- u16 pcmciamesportalmask; /* rev8 */
- u16 PAD[1];
- u16 pcmciawrframebc; /* rev8 */
- u16 PAD[1];
- u16 pcmciaunderflowtimer; /* rev8 */
- u16 PAD[1];
- /* interrupt */
- u32 intstatus; /* 0x020, rev8 */
- u32 hostintmask; /* rev8 */
- u32 intmask; /* rev8 */
- u32 sbintstatus; /* rev8 */
- u32 sbintmask; /* rev8 */
- u32 funcintmask; /* rev4 */
- u32 PAD[2];
- u32 tosbmailbox; /* 0x040, rev8 */
- u32 tohostmailbox; /* rev8 */
- u32 tosbmailboxdata; /* rev8 */
- u32 tohostmailboxdata; /* rev8 */
- /* synchronized access to registers in SDIO clock domain */
- u32 sdioaccess; /* 0x050, rev8 */
- u32 PAD[3];
- /* PCMCIA frame control */
- u8 pcmciaframectrl; /* 0x060, rev8 */
- u8 PAD[3];
- u8 pcmciawatermark; /* rev8 */
- u8 PAD[155];
- /* interrupt batching control */
- u32 intrcvlazy; /* 0x100, rev8 */
- u32 PAD[3];
- /* counters */
- u32 cmd52rd; /* 0x110, rev8 */
- u32 cmd52wr; /* rev8 */
- u32 cmd53rd; /* rev8 */
- u32 cmd53wr; /* rev8 */
- u32 abort; /* rev8 */
- u32 datacrcerror; /* rev8 */
- u32 rdoutofsync; /* rev8 */
- u32 wroutofsync; /* rev8 */
- u32 writebusy; /* rev8 */
- u32 readwait; /* rev8 */
- u32 readterm; /* rev8 */
- u32 writeterm; /* rev8 */
- u32 PAD[40];
- u32 clockctlstatus; /* rev8 */
- u32 PAD[7];
- u32 PAD[128]; /* DMA engines */
- /* SDIO/PCMCIA CIS region */
- char cis[512]; /* 0x400-0x5ff, rev6 */
- /* PCMCIA function control registers */
- char pcmciafcr[256]; /* 0x600-6ff, rev6 */
- u16 PAD[55];
- /* PCMCIA backplane access */
- u16 backplanecsr; /* 0x76E, rev6 */
- u16 backplaneaddr0; /* rev6 */
- u16 backplaneaddr1; /* rev6 */
- u16 backplaneaddr2; /* rev6 */
- u16 backplaneaddr3; /* rev6 */
- u16 backplanedata0; /* rev6 */
- u16 backplanedata1; /* rev6 */
- u16 backplanedata2; /* rev6 */
- u16 backplanedata3; /* rev6 */
- u16 PAD[31];
- /* sprom "size" & "blank" info */
- u16 spromstatus; /* 0x7BE, rev2 */
- u32 PAD[464];
- u16 PAD[0x80];
- };
- #ifdef BCMDBG
- /* Device console log buffer state */
- struct brcmf_console {
- uint count; /* Poll interval msec counter */
- uint log_addr; /* Log struct address (fixed) */
- struct rte_log log; /* Log struct (host copy) */
- uint bufsize; /* Size of log buffer */
- u8 *buf; /* Log buffer (host copy) */
- uint last; /* Last buffer read index */
- };
- #endif /* BCMDBG */
- struct sdpcm_shared {
- u32 flags;
- u32 trap_addr;
- u32 assert_exp_addr;
- u32 assert_file_addr;
- u32 assert_line;
- u32 console_addr; /* Address of struct rte_console */
- u32 msgtrace_addr;
- u8 tag[32];
- };
- /* misc chip info needed by some of the routines */
- struct chip_info {
- u32 chip;
- u32 chiprev;
- u32 cccorebase;
- u32 ccrev;
- u32 cccaps;
- u32 buscorebase; /* 32 bits backplane bus address */
- u32 buscorerev;
- u32 buscoretype;
- u32 ramcorebase;
- u32 armcorebase;
- u32 pmurev;
- u32 ramsize;
- };
- /* Private data for SDIO bus interaction */
- struct brcmf_bus {
- struct brcmf_pub *drvr;
- struct brcmf_sdio_card *card; /* Handle for sdio card calls */
- struct chip_info *ci; /* Chip info struct */
- char *vars; /* Variables (from CIS and/or other) */
- uint varsz; /* Size of variables buffer */
- u32 ramsize; /* Size of RAM in SOCRAM (bytes) */
- u32 orig_ramsize; /* Size of RAM in SOCRAM (bytes) */
- u32 bus; /* gSPI or SDIO bus */
- u32 hostintmask; /* Copy of Host Interrupt Mask */
- u32 intstatus; /* Intstatus bits (events) pending */
- bool dpc_sched; /* Indicates DPC schedule (intrpt rcvd) */
- bool fcstate; /* State of dongle flow-control */
- u16 cl_devid; /* cached devid for brcmf_sdio_probe_attach() */
- uint blocksize; /* Block size of SDIO transfers */
- uint roundup; /* Max roundup limit */
- struct pktq txq; /* Queue length used for flow-control */
- u8 flowcontrol; /* per prio flow control bitmask */
- u8 tx_seq; /* Transmit sequence number (next) */
- u8 tx_max; /* Maximum transmit sequence allowed */
- u8 hdrbuf[MAX_HDR_READ + BRCMF_SDALIGN];
- u8 *rxhdr; /* Header of current rx frame (in hdrbuf) */
- u16 nextlen; /* Next Read Len from last header */
- u8 rx_seq; /* Receive sequence number (expected) */
- bool rxskip; /* Skip receive (awaiting NAK ACK) */
- struct sk_buff *glomd; /* Packet containing glomming descriptor */
- struct sk_buff *glom; /* Packet chain for glommed superframe */
- uint glomerr; /* Glom packet read errors */
- u8 *rxbuf; /* Buffer for receiving control packets */
- uint rxblen; /* Allocated length of rxbuf */
- u8 *rxctl; /* Aligned pointer into rxbuf */
- u8 *databuf; /* Buffer for receiving big glom packet */
- u8 *dataptr; /* Aligned pointer into databuf */
- uint rxlen; /* Length of valid data in buffer */
- u8 sdpcm_ver; /* Bus protocol reported by dongle */
- bool intr; /* Use interrupts */
- bool poll; /* Use polling */
- bool ipend; /* Device interrupt is pending */
- bool intdis; /* Interrupts disabled by isr */
- uint intrcount; /* Count of device interrupt callbacks */
- uint lastintrs; /* Count as of last watchdog timer */
- uint spurious; /* Count of spurious interrupts */
- uint pollrate; /* Ticks between device polls */
- uint polltick; /* Tick counter */
- uint pollcnt; /* Count of active polls */
- #ifdef BCMDBG
- struct brcmf_console console; /* Console output polling support */
- uint console_addr; /* Console address from shared struct */
- #endif /* BCMDBG */
- uint regfails; /* Count of R_REG failures */
- uint clkstate; /* State of sd and backplane clock(s) */
- bool activity; /* Activity flag for clock down */
- s32 idletime; /* Control for activity timeout */
- s32 idlecount; /* Activity timeout counter */
- s32 idleclock; /* How to set bus driver when idle */
- s32 sd_rxchain;
- bool use_rxchain; /* If brcmf should use PKT chains */
- bool sleeping; /* Is SDIO bus sleeping? */
- bool rxflow_mode; /* Rx flow control mode */
- bool rxflow; /* Is rx flow control on */
- bool alp_only; /* Don't use HT clock (ALP only) */
- /* Field to decide if rx of control frames happen in rxbuf or lb-pool */
- bool usebufpool;
- #ifdef SDTEST
- /* external loopback */
- bool ext_loop;
- u8 loopid;
- /* pktgen configuration */
- uint pktgen_freq; /* Ticks between bursts */
- uint pktgen_count; /* Packets to send each burst */
- uint pktgen_print; /* Bursts between count displays */
- uint pktgen_total; /* Stop after this many */
- uint pktgen_minlen; /* Minimum packet data len */
- uint pktgen_maxlen; /* Maximum packet data len */
- uint pktgen_mode; /* Configured mode: tx, rx, or echo */
- uint pktgen_stop; /* Number of tx failures causing stop */
- /* active pktgen fields */
- uint pktgen_tick; /* Tick counter for bursts */
- uint pktgen_ptick; /* Burst counter for printing */
- uint pktgen_sent; /* Number of test packets generated */
- uint pktgen_rcvd; /* Number of test packets received */
- uint pktgen_fail; /* Number of failed send attempts */
- u16 pktgen_len; /* Length of next packet to send */
- #endif /* SDTEST */
- /* Some additional counters */
- uint tx_sderrs; /* Count of tx attempts with sd errors */
- uint fcqueued; /* Tx packets that got queued */
- uint rxrtx; /* Count of rtx requests (NAK to dongle) */
- uint rx_toolong; /* Receive frames too long to receive */
- uint rxc_errors; /* SDIO errors when reading control frames */
- uint rx_hdrfail; /* SDIO errors on header reads */
- uint rx_badhdr; /* Bad received headers (roosync?) */
- uint rx_badseq; /* Mismatched rx sequence number */
- uint fc_rcvd; /* Number of flow-control events received */
- uint fc_xoff; /* Number which turned on flow-control */
- uint fc_xon; /* Number which turned off flow-control */
- uint rxglomfail; /* Failed deglom attempts */
- uint rxglomframes; /* Number of glom frames (superframes) */
- uint rxglompkts; /* Number of packets from glom frames */
- uint f2rxhdrs; /* Number of header reads */
- uint f2rxdata; /* Number of frame data reads */
- uint f2txdata; /* Number of f2 frame writes */
- uint f1regdata; /* Number of f1 register accesses */
- u8 *ctrl_frame_buf;
- u32 ctrl_frame_len;
- bool ctrl_frame_stat;
- spinlock_t txqlock;
- wait_queue_head_t ctrl_wait;
- struct timer_list timer;
- struct completion watchdog_wait;
- struct task_struct *watchdog_tsk;
- bool wd_timer_valid;
- struct tasklet_struct tasklet;
- struct task_struct *dpc_tsk;
- struct completion dpc_wait;
- bool threads_only;
- struct semaphore sdsem;
- spinlock_t sdlock;
- const char *fw_name;
- const struct firmware *firmware;
- const char *nv_name;
- u32 fw_ptr;
- };
- struct sbconfig {
- u32 PAD[2];
- u32 sbipsflag; /* initiator port ocp slave flag */
- u32 PAD[3];
- u32 sbtpsflag; /* target port ocp slave flag */
- u32 PAD[11];
- u32 sbtmerrloga; /* (sonics >= 2.3) */
- u32 PAD;
- u32 sbtmerrlog; /* (sonics >= 2.3) */
- u32 PAD[3];
- u32 sbadmatch3; /* address match3 */
- u32 PAD;
- u32 sbadmatch2; /* address match2 */
- u32 PAD;
- u32 sbadmatch1; /* address match1 */
- u32 PAD[7];
- u32 sbimstate; /* initiator agent state */
- u32 sbintvec; /* interrupt mask */
- u32 sbtmstatelow; /* target state */
- u32 sbtmstatehigh; /* target state */
- u32 sbbwa0; /* bandwidth allocation table0 */
- u32 PAD;
- u32 sbimconfiglow; /* initiator configuration */
- u32 sbimconfighigh; /* initiator configuration */
- u32 sbadmatch0; /* address match0 */
- u32 PAD;
- u32 sbtmconfiglow; /* target configuration */
- u32 sbtmconfighigh; /* target configuration */
- u32 sbbconfig; /* broadcast configuration */
- u32 PAD;
- u32 sbbstate; /* broadcast state */
- u32 PAD[3];
- u32 sbactcnfg; /* activate configuration */
- u32 PAD[3];
- u32 sbflagst; /* current sbflags */
- u32 PAD[3];
- u32 sbidlow; /* identification */
- u32 sbidhigh; /* identification */
- };
- /* clkstate */
- #define CLK_NONE 0
- #define CLK_SDONLY 1
- #define CLK_PENDING 2 /* Not used yet */
- #define CLK_AVAIL 3
- #define BRCMF_NOPMU(brcmf) (false)
- #ifdef BCMDBG
- static int qcount[NUMPRIO];
- static int tx_packets[NUMPRIO];
- #endif /* BCMDBG */
- /* Deferred transmit */
- uint brcmf_deferred_tx = 1;
- module_param(brcmf_deferred_tx, uint, 0);
- /* Watchdog thread priority, -1 to use kernel timer */
- int brcmf_watchdog_prio = 97;
- module_param(brcmf_watchdog_prio, int, 0);
- /* Watchdog interval */
- uint brcmf_watchdog_ms = 10;
- module_param(brcmf_watchdog_ms, uint, 0);
- /* DPC thread priority, -1 to use tasklet */
- int brcmf_dpc_prio = 98;
- module_param(brcmf_dpc_prio, int, 0);
- #ifdef BCMDBG
- /* Console poll interval */
- uint brcmf_console_ms;
- module_param(brcmf_console_ms, uint, 0);
- #endif /* BCMDBG */
- /* Tx/Rx bounds */
- uint brcmf_txbound;
- uint brcmf_rxbound;
- uint brcmf_txminmax;
- /* override the RAM size if possible */
- #define DONGLE_MIN_MEMSIZE (128 * 1024)
- int brcmf_dongle_memsize;
- static bool brcmf_alignctl;
- static bool sd1idle;
- static bool retrydata;
- #define RETRYCHAN(chan) (((chan) == SDPCM_EVENT_CHANNEL) || retrydata)
- static const uint watermark = 8;
- static const uint firstread = BRCMF_FIRSTREAD;
- /* Retry count for register access failures */
- static const uint retry_limit = 2;
- /* Force even SD lengths (some host controllers mess up on odd bytes) */
- static bool forcealign;
- #define ALIGNMENT 4
- #define PKTALIGN(_p, _len, _align) \
- do { \
- uint datalign; \
- datalign = (unsigned long)((_p)->data); \
- datalign = roundup(datalign, (_align)) - datalign; \
- if (datalign) \
- skb_pull((_p), datalign); \
- __skb_trim((_p), (_len)); \
- } while (0)
- /* Limit on rounding up frames */
- static const uint max_roundup = 512;
- /* Try doing readahead */
- static bool brcmf_readahead;
- /* To check if there's window offered */
- #define DATAOK(bus) \
- (((u8)(bus->tx_max - bus->tx_seq) != 0) && \
- (((u8)(bus->tx_max - bus->tx_seq) & 0x80) == 0))
- /*
- * Reads a register in the SDIO hardware block. This block occupies a series of
- * adresses on the 32 bit backplane bus.
- */
- static void
- r_sdreg32(struct brcmf_bus *bus, u32 *regvar, u32 reg_offset, u32 *retryvar)
- {
- *retryvar = 0;
- do {
- *regvar = R_REG(bus->ci->buscorebase + reg_offset, u32);
- } while (brcmf_sdcard_regfail(bus->card) &&
- (++(*retryvar) <= retry_limit));
- if (*retryvar) {
- bus->regfails += (*retryvar-1);
- if (*retryvar > retry_limit) {
- BRCMF_ERROR(("FAILED READ %Xh\n", reg_offset));
- *regvar = 0;
- }
- }
- }
- static void
- w_sdreg32(struct brcmf_bus *bus, u32 regval, u32 reg_offset, u32 *retryvar)
- {
- *retryvar = 0;
- do {
- brcmf_sdcard_reg_write(NULL, bus->ci->buscorebase + reg_offset,
- sizeof(u32), regval);
- } while (brcmf_sdcard_regfail(bus->card) &&
- (++(*retryvar) <= retry_limit));
- if (*retryvar) {
- bus->regfails += (*retryvar-1);
- if (*retryvar > retry_limit)
- BRCMF_ERROR(("FAILED REGISTER WRITE"
- " %Xh\n", reg_offset));
- }
- }
- #define BRCMF_BUS SDIO_BUS
- #define PKT_AVAILABLE() (intstatus & I_HMB_FRAME_IND)
- #define HOSTINTMASK (I_HMB_SW_MASK | I_CHIPACTIVE)
- #ifdef SDTEST
- static void brcmf_sdbrcm_checkdied(struct brcmf_bus *bus, void *pkt, uint seq);
- static void brcmf_sdbrcm_sdtest_set(struct brcmf_bus *bus, bool start);
- #endif
- #ifdef BCMDBG
- static int brcmf_sdbrcm_bus_console_in(struct brcmf_pub *drvr,
- unsigned char *msg, uint msglen);
- static int brcmf_sdbrcm_checkdied(struct brcmf_bus *bus, u8 *data, uint size);
- static int brcmf_sdbrcm_mem_dump(struct brcmf_bus *bus);
- #endif /* BCMDBG */
- static int brcmf_sdbrcm_download_state(struct brcmf_bus *bus, bool enter);
- static void brcmf_sdbrcm_release(struct brcmf_bus *bus);
- static void brcmf_sdbrcm_release_malloc(struct brcmf_bus *bus);
- static void brcmf_sdbrcm_disconnect(void *ptr);
- static bool brcmf_sdbrcm_chipmatch(u16 chipid);
- static bool brcmf_sdbrcm_probe_attach(struct brcmf_bus *bus, void *card,
- u32 regsva, u16 devid);
- static bool brcmf_sdbrcm_probe_malloc(struct brcmf_bus *bus, void *card);
- static bool brcmf_sdbrcm_probe_init(struct brcmf_bus *bus, void *card);
- static void brcmf_sdbrcm_release_dongle(struct brcmf_bus *bus);
- static uint brcmf_process_nvram_vars(char *varbuf, uint len);
- static void brcmf_sdbrcm_setmemsize(struct brcmf_bus *bus, int mem_size);
- static int brcmf_sdbrcm_send_buf(struct brcmf_bus *bus, u32 addr, uint fn,
- uint flags, u8 *buf, uint nbytes,
- struct sk_buff *pkt,
- void (*complete)(void *handle, int status,
- bool sync_waiting),
- void *handle);
- static bool brcmf_sdbrcm_download_firmware(struct brcmf_bus *bus, void *card);
- static int _brcmf_sdbrcm_download_firmware(struct brcmf_bus *bus);
- static int brcmf_sdbrcm_download_code_file(struct brcmf_bus *bus);
- static int brcmf_sdbrcm_download_nvram(struct brcmf_bus *bus);
- static void
- brcmf_sdbrcm_chip_disablecore(struct brcmf_sdio_card *card, u32 corebase);
- static int brcmf_sdbrcm_chip_attach(struct brcmf_bus *bus, u32 regs);
- static void
- brcmf_sdbrcm_chip_resetcore(struct brcmf_sdio_card *card, u32 corebase);
- static void brcmf_sdbrcm_sdiod_drive_strength_init(struct brcmf_bus *bus,
- u32 drivestrength);
- static void brcmf_sdbrcm_chip_detach(struct brcmf_bus *bus);
- static void brcmf_sdbrcm_wait_for_event(struct brcmf_bus *bus, bool *lockvar);
- static void brcmf_sdbrcm_wait_event_wakeup(struct brcmf_bus *bus);
- static void brcmf_sdbrcm_watchdog(unsigned long data);
- static int brcmf_sdbrcm_watchdog_thread(void *data);
- static int brcmf_sdbrcm_dpc_thread(void *data);
- static void brcmf_sdbrcm_dpc_tasklet(unsigned long data);
- static void brcmf_sdbrcm_sched_dpc(struct brcmf_bus *bus);
- static void brcmf_sdbrcm_sdlock(struct brcmf_bus *bus);
- static void brcmf_sdbrcm_sdunlock(struct brcmf_bus *bus);
- static int brcmf_sdbrcm_get_image(char *buf, int len, struct brcmf_bus *bus);
- /* Packet free applicable unconditionally for sdio and sdspi.
- * Conditional if bufpool was present for gspi bus.
- */
- static void brcmf_sdbrcm_pktfree2(struct brcmf_bus *bus, struct sk_buff *pkt)
- {
- if ((bus->bus != SPI_BUS) || bus->usebufpool)
- brcmu_pkt_buf_free_skb(pkt);
- }
- static void brcmf_sdbrcm_setmemsize(struct brcmf_bus *bus, int mem_size)
- {
- s32 min_size = DONGLE_MIN_MEMSIZE;
- /* Restrict the memsize to user specified limit */
- BRCMF_ERROR(("user: Restrict the dongle ram size to %d, min %d\n",
- brcmf_dongle_memsize, min_size));
- if ((brcmf_dongle_memsize > min_size) &&
- (brcmf_dongle_memsize < (s32) bus->orig_ramsize))
- bus->ramsize = brcmf_dongle_memsize;
- }
- static int brcmf_sdbrcm_set_siaddr_window(struct brcmf_bus *bus, u32 address)
- {
- int err = 0;
- brcmf_sdcard_cfg_write(bus->card, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW,
- (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err);
- if (!err)
- brcmf_sdcard_cfg_write(bus->card, SDIO_FUNC_1,
- SBSDIO_FUNC1_SBADDRMID,
- (address >> 16) & SBSDIO_SBADDRMID_MASK, &err);
- if (!err)
- brcmf_sdcard_cfg_write(bus->card, SDIO_FUNC_1,
- SBSDIO_FUNC1_SBADDRHIGH,
- (address >> 24) & SBSDIO_SBADDRHIGH_MASK,
- &err);
- return err;
- }
- /* Turn backplane clock on or off */
- static int brcmf_sdbrcm_htclk(struct brcmf_bus *bus, bool on, bool pendok)
- {
- int err;
- u8 clkctl, clkreq, devctl;
- struct brcmf_sdio_card *card;
- BRCMF_TRACE(("%s: Enter\n", __func__));
- clkctl = 0;
- card = bus->card;
- if (on) {
- /* Request HT Avail */
- clkreq =
- bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ;
- if ((bus->ci->chip == BCM4329_CHIP_ID)
- && (bus->ci->chiprev == 0))
- clkreq |= SBSDIO_FORCE_ALP;
- brcmf_sdcard_cfg_write(card, SDIO_FUNC_1,
- SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
- if (err) {
- BRCMF_ERROR(("%s: HT Avail request error: %d\n",
- __func__, err));
- return -EBADE;
- }
- if (pendok && ((bus->ci->buscoretype == PCMCIA_CORE_ID)
- && (bus->ci->buscorerev == 9))) {
- u32 dummy, retries;
- r_sdreg32(bus, &dummy,
- offsetof(struct sdpcmd_regs, clockctlstatus),
- &retries);
- }
- /* Check current status */
- clkctl = brcmf_sdcard_cfg_read(card, SDIO_FUNC_1,
- SBSDIO_FUNC1_CHIPCLKCSR, &err);
- if (err) {
- BRCMF_ERROR(("%s: HT Avail read error: %d\n",
- __func__, err));
- return -EBADE;
- }
- /* Go to pending and await interrupt if appropriate */
- if (!SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) {
- /* Allow only clock-available interrupt */
- devctl = brcmf_sdcard_cfg_read(card, SDIO_FUNC_1,
- SBSDIO_DEVICE_CTL, &err);
- if (err) {
- BRCMF_ERROR(("%s: Devctl error setting CA:"
- " %d\n", __func__, err));
- return -EBADE;
- }
- devctl |= SBSDIO_DEVCTL_CA_INT_ONLY;
- brcmf_sdcard_cfg_write(card, SDIO_FUNC_1,
- SBSDIO_DEVICE_CTL, devctl, &err);
- BRCMF_INFO(("CLKCTL: set PENDING\n"));
- bus->clkstate = CLK_PENDING;
- return 0;
- } else if (bus->clkstate == CLK_PENDING) {
- /* Cancel CA-only interrupt filter */
- devctl =
- brcmf_sdcard_cfg_read(card, SDIO_FUNC_1,
- SBSDIO_DEVICE_CTL, &err);
- devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
- brcmf_sdcard_cfg_write(card, SDIO_FUNC_1,
- SBSDIO_DEVICE_CTL, devctl, &err);
- }
- /* Otherwise, wait here (polling) for HT Avail */
- if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
- BRCMF_SPINWAIT_SLEEP(sdioh_spinwait_sleep,
- ((clkctl =
- brcmf_sdcard_cfg_read(card, SDIO_FUNC_1,
- SBSDIO_FUNC1_CHIPCLKCSR,
- &err)),
- !SBSDIO_CLKAV(clkctl, bus->alp_only)),
- PMU_MAX_TRANSITION_DLY);
- }
- if (err) {
- BRCMF_ERROR(("%s: HT Avail request error: %d\n",
- __func__, err));
- return -EBADE;
- }
- if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
- BRCMF_ERROR(("%s: HT Avail timeout (%d): "
- "clkctl 0x%02x\n", __func__,
- PMU_MAX_TRANSITION_DLY, clkctl));
- return -EBADE;
- }
- /* Mark clock available */
- bus->clkstate = CLK_AVAIL;
- BRCMF_INFO(("CLKCTL: turned ON\n"));
- #if defined(BCMDBG)
- if (bus->alp_only != true) {
- if (SBSDIO_ALPONLY(clkctl)) {
- BRCMF_ERROR(("%s: HT Clock should be on.\n",
- __func__));
- }
- }
- #endif /* defined (BCMDBG) */
- bus->activity = true;
- } else {
- clkreq = 0;
- if (bus->clkstate == CLK_PENDING) {
- /* Cancel CA-only interrupt filter */
- devctl = brcmf_sdcard_cfg_read(card, SDIO_FUNC_1,
- SBSDIO_DEVICE_CTL, &err);
- devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
- brcmf_sdcard_cfg_write(card, SDIO_FUNC_1,
- SBSDIO_DEVICE_CTL, devctl, &err);
- }
- bus->clkstate = CLK_SDONLY;
- brcmf_sdcard_cfg_write(card, SDIO_FUNC_1,
- SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
- BRCMF_INFO(("CLKCTL: turned OFF\n"));
- if (err) {
- BRCMF_ERROR(("%s: Failed access turning clock off:"
- " %d\n", __func__, err));
- return -EBADE;
- }
- }
- return 0;
- }
- /* Change idle/active SD state */
- static int brcmf_sdbrcm_sdclk(struct brcmf_bus *bus, bool on)
- {
- BRCMF_TRACE(("%s: Enter\n", __func__));
- if (on)
- bus->clkstate = CLK_SDONLY;
- else
- bus->clkstate = CLK_NONE;
- return 0;
- }
- /* Transition SD and backplane clock readiness */
- static int brcmf_sdbrcm_clkctl(struct brcmf_bus *bus, uint target, bool pendok)
- {
- #ifdef BCMDBG
- uint oldstate = bus->clkstate;
- #endif /* BCMDBG */
- BRCMF_TRACE(("%s: Enter\n", __func__));
- /* Early exit if we're already there */
- if (bus->clkstate == target) {
- if (target == CLK_AVAIL) {
- brcmf_sdbrcm_wd_timer(bus, brcmf_watchdog_ms);
- bus->activity = true;
- }
- return 0;
- }
- switch (target) {
- case CLK_AVAIL:
- /* Make sure SD clock is available */
- if (bus->clkstate == CLK_NONE)
- brcmf_sdbrcm_sdclk(bus, true);
- /* Now request HT Avail on the backplane */
- brcmf_sdbrcm_htclk(bus, true, pendok);
- brcmf_sdbrcm_wd_timer(bus, brcmf_watchdog_ms);
- bus->activity = true;
- break;
- case CLK_SDONLY:
- /* Remove HT request, or bring up SD clock */
- if (bus->clkstate == CLK_NONE)
- brcmf_sdbrcm_sdclk(bus, true);
- else if (bus->clkstate == CLK_AVAIL)
- brcmf_sdbrcm_htclk(bus, false, false);
- else
- BRCMF_ERROR(("brcmf_sdbrcm_clkctl: request for %d -> %d"
- "\n", bus->clkstate, target));
- brcmf_sdbrcm_wd_timer(bus, brcmf_watchdog_ms);
- break;
- case CLK_NONE:
- /* Make sure to remove HT request */
- if (bus->clkstate == CLK_AVAIL)
- brcmf_sdbrcm_htclk(bus, false, false);
- /* Now remove the SD clock */
- brcmf_sdbrcm_sdclk(bus, false);
- brcmf_sdbrcm_wd_timer(bus, 0);
- break;
- }
- #ifdef BCMDBG
- BRCMF_INFO(("brcmf_sdbrcm_clkctl: %d -> %d\n",
- oldstate, bus->clkstate));
- #endif /* BCMDBG */
- return 0;
- }
- int brcmf_sdbrcm_bussleep(struct brcmf_bus *bus, bool sleep)
- {
- struct brcmf_sdio_card *card = bus->card;
- uint retries = 0;
- BRCMF_INFO(("brcmf_sdbrcm_bussleep: request %s (currently %s)\n",
- (sleep ? "SLEEP" : "WAKE"),
- (bus->sleeping ? "SLEEP" : "WAKE")));
- /* Done if we're already in the requested state */
- if (sleep == bus->sleeping)
- return 0;
- /* Going to sleep: set the alarm and turn off the lights... */
- if (sleep) {
- /* Don't sleep if something is pending */
- if (bus->dpc_sched || bus->rxskip || pktq_len(&bus->txq))
- return -EBUSY;
- /* Disable SDIO interrupts (no longer interested) */
- brcmf_sdcard_intr_disable(bus->card);
- /* Make sure the controller has the bus up */
- brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
- /* Tell device to start using OOB wakeup */
- w_sdreg32(bus, SMB_USE_OOB,
- offsetof(struct sdpcmd_regs, tosbmailbox), &retries);
- if (retries > retry_limit)
- BRCMF_ERROR(("CANNOT SIGNAL CHIP, "
- "WILL NOT WAKE UP!!\n"));
- /* Turn off our contribution to the HT clock request */
- brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false);
- brcmf_sdcard_cfg_write(card, SDIO_FUNC_1,
- SBSDIO_FUNC1_CHIPCLKCSR,
- SBSDIO_FORCE_HW_CLKREQ_OFF, NULL);
- /* Isolate the bus */
- if (bus->ci->chip != BCM4329_CHIP_ID
- && bus->ci->chip != BCM4319_CHIP_ID) {
- brcmf_sdcard_cfg_write(card, SDIO_FUNC_1,
- SBSDIO_DEVICE_CTL,
- SBSDIO_DEVCTL_PADS_ISO, NULL);
- }
- /* Change state */
- bus->sleeping = true;
- } else {
- /* Waking up: bus power up is ok, set local state */
- brcmf_sdcard_cfg_write(card, SDIO_FUNC_1,
- SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
- /* Force pad isolation off if possible
- (in case power never toggled) */
- if ((bus->ci->buscoretype == PCMCIA_CORE_ID)
- && (bus->ci->buscorerev >= 10))
- brcmf_sdcard_cfg_write(card, SDIO_FUNC_1,
- SBSDIO_DEVICE_CTL, 0, NULL);
- /* Make sure the controller has the bus up */
- brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
- /* Send misc interrupt to indicate OOB not needed */
- w_sdreg32(bus, 0, offsetof(struct sdpcmd_regs, tosbmailboxdata),
- &retries);
- if (retries <= retry_limit)
- w_sdreg32(bus, SMB_DEV_INT,
- offsetof(struct sdpcmd_regs, tosbmailbox),
- &retries);
- if (retries > retry_limit)
- BRCMF_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n"));
- /* Make sure we have SD bus access */
- brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false);
- /* Change state */
- bus->sleeping = false;
- /* Enable interrupts again */
- if (bus->intr && (bus->drvr->busstate == BRCMF_BUS_DATA)) {
- bus->intdis = false;
- brcmf_sdcard_intr_enable(bus->card);
- }
- }
- return 0;
- }
- #define BUS_WAKE(bus) \
- do { \
- if ((bus)->sleeping) \
- brcmf_sdbrcm_bussleep((bus), false); \
- } while (0);
- /* Writes a HW/SW header into the packet and sends it. */
- /* Assumes: (a) header space already there, (b) caller holds lock */
- static int brcmf_sdbrcm_txpkt(struct brcmf_bus *bus, struct sk_buff *pkt, uint chan,
- bool free_pkt)
- {
- int ret;
- u8 *frame;
- u16 len, pad = 0;
- u32 swheader;
- uint retries = 0;
- struct brcmf_sdio_card *card;
- struct sk_buff *new;
- int i;
- BRCMF_TRACE(("%s: Enter\n", __func__));
- card = bus->card;
- if (bus->drvr->dongle_reset) {
- ret = -EPERM;
- goto done;
- }
- frame = (u8 *) (pkt->data);
- /* Add alignment padding, allocate new packet if needed */
- pad = ((unsigned long)frame % BRCMF_SDALIGN);
- if (pad) {
- if (skb_headroom(pkt) < pad) {
- BRCMF_INFO(("%s: insufficient headroom %d for %d pad\n",
- __func__, skb_headroom(pkt), pad));
- bus->drvr->tx_realloc++;
- new = brcmu_pkt_buf_get_skb(pkt->len + BRCMF_SDALIGN);
- if (!new) {
- BRCMF_ERROR(("%s: couldn't allocate new "
- "%d-byte packet\n", __func__,
- pkt->len + BRCMF_SDALIGN));
- ret = -ENOMEM;
- goto done;
- }
- PKTALIGN(new, pkt->len, BRCMF_SDALIGN);
- memcpy(new->data, pkt->data, pkt->len);
- if (free_pkt)
- brcmu_pkt_buf_free_skb(pkt);
- /* free the pkt if canned one is not used */
- free_pkt = true;
- pkt = new;
- frame = (u8 *) (pkt->data);
- /* precondition: (frame % BRCMF_SDALIGN) == 0) */
- pad = 0;
- } else {
- skb_push(pkt, pad);
- frame = (u8 *) (pkt->data);
- /* precondition: pad + SDPCM_HDRLEN <= pkt->len */
- memset(frame, 0, pad + SDPCM_HDRLEN);
- }
- }
- /* precondition: pad < BRCMF_SDALIGN */
- /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
- len = (u16) (pkt->len);
- *(u16 *) frame = cpu_to_le16(len);
- *(((u16 *) frame) + 1) = cpu_to_le16(~len);
- /* Software tag: channel, sequence number, data offset */
- swheader =
- ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) | bus->tx_seq |
- (((pad +
- SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
- put_unaligned_le32(swheader, frame + SDPCM_FRAMETAG_LEN);
- put_unaligned_le32(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
- #ifdef BCMDBG
- tx_packets[pkt->priority]++;
- if (BRCMF_BYTES_ON() &&
- (((BRCMF_CTL_ON() && (chan == SDPCM_CONTROL_CHANNEL)) ||
- (BRCMF_DATA_ON() && (chan != SDPCM_CONTROL_CHANNEL))))) {
- printk(KERN_DEBUG "Tx Frame:\n");
- print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, frame, len);
- } else if (BRCMF_HDRS_ON()) {
- printk(KERN_DEBUG "TxHdr:\n");
- print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
- frame, min_t(u16, len, 16));
- }
- #endif
- /* Raise len to next SDIO block to eliminate tail command */
- if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
- u16 pad = bus->blocksize - (len % bus->blocksize);
- if ((pad <= bus->roundup) && (pad < bus->blocksize))
- len += pad;
- } else if (len % BRCMF_SDALIGN) {
- len += BRCMF_SDALIGN - (len % BRCMF_SDALIGN);
- }
- /* Some controllers have trouble with odd bytes -- round to even */
- if (forcealign && (len & (ALIGNMENT - 1))) {
- len = roundup(len, ALIGNMENT);
- }
- do {
- ret = brcmf_sdbrcm_send_buf(bus, brcmf_sdcard_cur_sbwad(card),
- SDIO_FUNC_2, F2SYNC, frame, len, pkt, NULL, NULL);
- bus->f2txdata++;
- if (ret < 0) {
- /* On failure, abort the command
- and terminate the frame */
- BRCMF_INFO(("%s: sdio error %d, abort command and "
- "terminate frame.\n", __func__, ret));
- bus->tx_sderrs++;
- brcmf_sdcard_abort(card, SDIO_FUNC_2);
- brcmf_sdcard_cfg_write(card, SDIO_FUNC_1,
- SBSDIO_FUNC1_FRAMECTRL, SFC_WF_TERM,
- NULL);
- bus->f1regdata++;
- for (i = 0; i < 3; i++) {
- u8 hi, lo;
- hi = brcmf_sdcard_cfg_read(card, SDIO_FUNC_1,
- SBSDIO_FUNC1_WFRAMEBCHI,
- NULL);
- lo = brcmf_sdcard_cfg_read(card, SDIO_FUNC_1,
- SBSDIO_FUNC1_WFRAMEBCLO,
- NULL);
- bus->f1regdata += 2;
- if ((hi == 0) && (lo == 0))
- break;
- }
- }
- if (ret == 0)
- bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
- } while ((ret < 0) && retrydata && retries++ < TXRETRIES);
- done:
- /* restore pkt buffer pointer before calling tx complete routine */
- skb_pull(pkt, SDPCM_HDRLEN + pad);
- brcmf_sdbrcm_sdunlock(bus);
- brcmf_txcomplete(bus->drvr, pkt, ret != 0);
- brcmf_sdbrcm_sdlock(bus);
- if (free_pkt)
- brcmu_pkt_buf_free_skb(pkt);
- return ret;
- }
- int brcmf_sdbrcm_bus_txdata(struct brcmf_bus *bus, struct sk_buff *pkt)
- {
- int ret = -EBADE;
- uint datalen, prec;
- BRCMF_TRACE(("%s: Enter\n", __func__));
- datalen = pkt->len;
- #ifdef SDTEST
- /* Push the test header if doing loopback */
- if (bus->ext_loop) {
- u8 *data;
- skb_push(pkt, SDPCM_TEST_HDRLEN);
- data = pkt->data;
- *data++ = SDPCM_TEST_ECHOREQ;
- *data++ = (u8) bus->loopid++;
- *data++ = (datalen >> 0);
- *data++ = (datalen >> 8);
- datalen += SDPCM_TEST_HDRLEN;
- }
- #endif /* SDTEST */
- /* Add space for the header */
- skb_push(pkt, SDPCM_HDRLEN);
- /* precondition: IS_ALIGNED((unsigned long)(pkt->data), 2) */
- prec = PRIO2PREC((pkt->priority & PRIOMASK));
- /* Check for existing queue, current flow-control,
- pending event, or pending clock */
- if (brcmf_deferred_tx || bus->fcstate || pktq_len(&bus->txq)
- || bus->dpc_sched || (!DATAOK(bus))
- || (bus->flowcontrol & NBITVAL(prec))
- || (bus->clkstate != CLK_AVAIL)) {
- BRCMF_TRACE(("%s: deferring pktq len %d\n", __func__,
- pktq_len(&bus->txq)));
- bus->fcqueued++;
- /* Priority based enq */
- spin_lock_bh(&bus->txqlock);
- if (brcmf_c_prec_enq(bus->drvr, &bus->txq, pkt, prec) == false) {
- skb_pull(pkt, SDPCM_HDRLEN);
- brcmf_txcomplete(bus->drvr, pkt, false);
- brcmu_pkt_buf_free_skb(pkt);
- BRCMF_ERROR(("%s: out of bus->txq !!!\n", __func__));
- ret = -ENOSR;
- } else {
- ret = 0;
- }
- spin_unlock_bh(&bus->txqlock);
- if (pktq_len(&bus->txq) >= TXHI)
- brcmf_txflowcontrol(bus->drvr, 0, ON);
- #ifdef BCMDBG
- if (pktq_plen(&bus->txq, prec) > qcount[prec])
- qcount[prec] = pktq_plen(&bus->txq, prec);
- #endif
- /* Schedule DPC if needed to send queued packet(s) */
- if (brcmf_deferred_tx && !bus->dpc_sched) {
- bus->dpc_sched = true;
- brcmf_sdbrcm_sched_dpc(bus);
- }
- } else {
- /* Lock: we're about to use shared data/code (and SDIO) */
- brcmf_sdbrcm_sdlock(bus);
- /* Otherwise, send it now */
- BUS_WAKE(bus);
- /* Make sure back plane ht clk is on, no pending allowed */
- brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, true);
- #ifndef SDTEST
- BRCMF_TRACE(("%s: calling txpkt\n", __func__));
- ret = brcmf_sdbrcm_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, true);
- #else
- ret = brcmf_sdbrcm_txpkt(bus, pkt,
- (bus->ext_loop ? SDPCM_TEST_CHANNEL :
- SDPCM_DATA_CHANNEL), true);
- #endif
- if (ret)
- bus->drvr->tx_errors++;
- else
- bus->drvr->dstats.tx_bytes += datalen;
- if (bus->idletime == BRCMF_IDLE_IMMEDIATE &&
- !bus->dpc_sched) {
- bus->activity = false;
- brcmf_sdbrcm_clkctl(bus, CLK_NONE, true);
- }
- brcmf_sdbrcm_sdunlock(bus);
- }
- return ret;
- }
- static uint brcmf_sdbrcm_sendfromq(struct brcmf_bus *bus, uint maxframes)
- {
- struct sk_buff *pkt;
- u32 intstatus = 0;
- uint retries = 0;
- int ret = 0, prec_out;
- uint cnt = 0;
- uint datalen;
- u8 tx_prec_map;
- struct brcmf_pub *drvr = bus->drvr;
- BRCMF_TRACE(("%s: Enter\n", __func__));
- tx_prec_map = ~bus->flowcontrol;
- /* Send frames until the limit or some other event */
- for (cnt = 0; (cnt < maxframes) && DATAOK(bus); cnt++) {
- spin_lock_bh(&bus->txqlock);
- pkt = brcmu_pktq_mdeq(&bus->txq, tx_prec_map, &prec_out);
- if (pkt == NULL) {
- spin_unlock_bh(&bus->txqlock);
- break;
- }
- spin_unlock_bh(&bus->txqlock);
- datalen = pkt->len - SDPCM_HDRLEN;
- #ifndef SDTEST
- ret = brcmf_sdbrcm_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, true);
- #else
- ret = brcmf_sdbrcm_txpkt(bus, pkt,
- (bus->ext_loop ? SDPCM_TEST_CHANNEL :
- SDPCM_DATA_CHANNEL), true);
- #endif
- if (ret)
- bus->drvr->tx_errors++;
- else
- bus->drvr->dstats.tx_bytes += datalen;
- /* In poll mode, need to check for other events */
- if (!bus->intr && cnt) {
- /* Check device status, signal pending interrupt */
- r_sdreg32(bus, &intstatus,
- offsetof(struct sdpcmd_regs, intstatus),
- &retries);
- bus->f2txdata++;
- if (brcmf_sdcard_regfail(bus->card))
- break;
- if (intstatus & bus->hostintmask)
- bus->ipend = true;
- }
- }
- /* Deflow-control stack if needed */
- if (drvr->up && (drvr->busstate == BRCMF_BUS_DATA) &&
- drvr->txoff && (pktq_len(&bus->txq) < TXLOW))
- brcmf_txflowcontrol(drvr, 0, OFF);
- return cnt;
- }
- int
- brcmf_sdbrcm_bus_txctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen)
- {
- u8 *frame;
- u16 len;
- u32 swheader;
- uint retries = 0;
- struct brcmf_sdio_card *card = bus->card;
- u8 doff = 0;
- int ret = -1;
- int i;
- BRCMF_TRACE(("%s: Enter\n", __func__));
- if (bus->drvr->dongle_reset)
- return -EIO;
- /* Back the pointer to make a room for bus header */
- frame = msg - SDPCM_HDRLEN;
- len = (msglen += SDPCM_HDRLEN);
- /* Add alignme…