dhd_sdio.c revision fcf094f414f9e9c088f6c2aa9e19a59f7b41e1f5
15b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/*
25b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * Copyright (c) 2010 Broadcom Corporation
35b435de0d786869c95d1962121af0d7df2542009Arend van Spriel *
45b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * Permission to use, copy, modify, and/or distribute this software for any
55b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * purpose with or without fee is hereby granted, provided that the above
65b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * copyright notice and this permission notice appear in all copies.
75b435de0d786869c95d1962121af0d7df2542009Arend van Spriel *
85b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
95b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */
165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include <linux/types.h>
185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include <linux/kernel.h>
195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include <linux/kthread.h>
205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include <linux/printk.h>
215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include <linux/pci_ids.h>
225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include <linux/netdevice.h>
235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include <linux/interrupt.h>
245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include <linux/sched.h>
255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include <linux/mmc/sdio.h>
265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include <linux/mmc/sdio_func.h>
275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include <linux/mmc/card.h>
285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include <linux/semaphore.h>
295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include <linux/firmware.h>
30b7a57e762ecf5d9971549ab3f9eb66b559840e72Stephen Rothwell#include <linux/module.h>
3199ba15cd75ed22e4ae86804ca2982a724e8102c2Franky Lin#include <linux/bcma/bcma.h>
325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include <asm/unaligned.h>
335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include <defs.h>
345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include <brcmu_wifi.h>
355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include <brcmu_utils.h>
365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include <brcm_hw_ids.h>
375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include <soc.h>
385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include "sdio_host.h"
39a83369b6e1e7285edd5217601a0618b9a43bdc4bFranky Lin#include "sdio_chip.h"
405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define DCMD_RESP_TIMEOUT  2000	/* In milli second */
425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#ifdef BCMDBG
445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define BRCMF_TRAP_INFO_SIZE	80
465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define CBUF_LEN	(128)
485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
495b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstruct rte_log_le {
505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	__le32 buf;		/* Can't be pointer on (64-bit) hosts */
515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	__le32 buf_size;
525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	__le32 idx;
535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	char *_buf_compat;	/* Redundant pointer for backward compat. */
545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel};
555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
565b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstruct rte_console {
575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Virtual UART
585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	 * When there is no UART (e.g. Quickturn),
595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	 * the host should write a complete
605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	 * input line directly into cbuf and then write
615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	 * the length into vcons_in.
625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	 * This may also be used when there is a real UART
635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	 * (at risk of conflicting with
645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	 * the real UART).  vcons_out is currently unused.
655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	 */
665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint vcons_in;
675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint vcons_out;
685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Output (logging) buffer
705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	 * Console output is written to a ring buffer log_buf at index log_idx.
715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	 * The host may read the output when it sees log_idx advance.
725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	 * Output will be lost if the output wraps around faster than the host
735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	 * polls.
745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	 */
755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	struct rte_log_le log_le;
765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Console input line buffer
785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	 * Characters are read one at a time into cbuf
795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	 * until <CR> is received, then
805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	 * the buffer is processed as a command line.
815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	 * Also used for virtual UART.
825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	 */
835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint cbuf_idx;
845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	char cbuf[CBUF_LEN];
855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel};
865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#endif				/* BCMDBG */
885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include <chipcommon.h>
895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include "dhd.h"
915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include "dhd_bus.h"
925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include "dhd_proto.h"
935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include "dhd_dbg.h"
945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define TXQLEN		2048	/* bulk tx queue length */
965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define TXHI		(TXQLEN - 256)	/* turn on flow control above TXHI */
975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define TXLOW		(TXHI - 256)	/* turn off flow control below TXLOW */
985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define PRIOMASK	7
995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
1005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define TXRETRIES	2	/* # of retries for tx frames */
1015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
1025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define BRCMF_RXBOUND	50	/* Default for max rx frames in
1035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				 one scheduling */
1045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
1055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define BRCMF_TXBOUND	20	/* Default for max tx frames in
1065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				 one scheduling */
1075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
1085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define BRCMF_TXMINMAX	1	/* Max tx frames if rx still pending */
1095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
1105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define MEMBLOCK	2048	/* Block size used for downloading
1115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				 of dongle image */
1125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define MAX_DATA_BUF	(32 * 1024)	/* Must be large enough to hold
1135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				 biggest possible glom */
1145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
1155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define BRCMF_FIRSTREAD	(1 << 6)
1165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
1175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
1185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* SBSDIO_DEVICE_CTL */
1195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
1205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* 1: device will assert busy signal when receiving CMD53 */
1215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SBSDIO_DEVCTL_SETBUSY		0x01
1225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* 1: assertion of sdio interrupt is synchronous to the sdio clock */
1235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SBSDIO_DEVCTL_SPI_INTR_SYNC	0x02
1245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* 1: mask all interrupts to host except the chipActive (rev 8) */
1255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SBSDIO_DEVCTL_CA_INT_ONLY	0x04
1265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* 1: isolate internal sdio signals, put external pads in tri-state; requires
1275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * sdio bus power cycle to clear (rev 9) */
1285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SBSDIO_DEVCTL_PADS_ISO		0x08
1295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* Force SD->SB reset mapping (rev 11) */
1305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SBSDIO_DEVCTL_SB_RST_CTL	0x30
1315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/*   Determined by CoreControl bit */
1325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SBSDIO_DEVCTL_RST_CORECTL	0x00
1335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/*   Force backplane reset */
1345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SBSDIO_DEVCTL_RST_BPRESET	0x10
1355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/*   Force no backplane reset */
1365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SBSDIO_DEVCTL_RST_NOBPRESET	0x20
1375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
1385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* direct(mapped) cis space */
1395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
1405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* MAPPED common CIS address */
1415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SBSDIO_CIS_BASE_COMMON		0x1000
1425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* maximum bytes in one CIS */
1435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SBSDIO_CIS_SIZE_LIMIT		0x200
1445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* cis offset addr is < 17 bits */
1455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SBSDIO_CIS_OFT_ADDR_MASK	0x1FFFF
1465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
1475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* manfid tuple length, include tuple, link bytes */
1485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SBSDIO_CIS_MANFID_TUPLE_LEN	6
1495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
1505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* intstatus */
1515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define I_SMB_SW0	(1 << 0)	/* To SB Mail S/W interrupt 0 */
1525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define I_SMB_SW1	(1 << 1)	/* To SB Mail S/W interrupt 1 */
1535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define I_SMB_SW2	(1 << 2)	/* To SB Mail S/W interrupt 2 */
1545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define I_SMB_SW3	(1 << 3)	/* To SB Mail S/W interrupt 3 */
1555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define I_SMB_SW_MASK	0x0000000f	/* To SB Mail S/W interrupts mask */
1565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define I_SMB_SW_SHIFT	0	/* To SB Mail S/W interrupts shift */
1575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define I_HMB_SW0	(1 << 4)	/* To Host Mail S/W interrupt 0 */
1585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define I_HMB_SW1	(1 << 5)	/* To Host Mail S/W interrupt 1 */
1595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define I_HMB_SW2	(1 << 6)	/* To Host Mail S/W interrupt 2 */
1605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define I_HMB_SW3	(1 << 7)	/* To Host Mail S/W interrupt 3 */
1615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define I_HMB_SW_MASK	0x000000f0	/* To Host Mail S/W interrupts mask */
1625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define I_HMB_SW_SHIFT	4	/* To Host Mail S/W interrupts shift */
1635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define I_WR_OOSYNC	(1 << 8)	/* Write Frame Out Of Sync */
1645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define I_RD_OOSYNC	(1 << 9)	/* Read Frame Out Of Sync */
1655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define	I_PC		(1 << 10)	/* descriptor error */
1665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define	I_PD		(1 << 11)	/* data error */
1675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define	I_DE		(1 << 12)	/* Descriptor protocol Error */
1685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define	I_RU		(1 << 13)	/* Receive descriptor Underflow */
1695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define	I_RO		(1 << 14)	/* Receive fifo Overflow */
1705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define	I_XU		(1 << 15)	/* Transmit fifo Underflow */
1715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define	I_RI		(1 << 16)	/* Receive Interrupt */
1725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define I_BUSPWR	(1 << 17)	/* SDIO Bus Power Change (rev 9) */
1735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define I_XMTDATA_AVAIL (1 << 23)	/* bits in fifo */
1745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define	I_XI		(1 << 24)	/* Transmit Interrupt */
1755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define I_RF_TERM	(1 << 25)	/* Read Frame Terminate */
1765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define I_WF_TERM	(1 << 26)	/* Write Frame Terminate */
1775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define I_PCMCIA_XU	(1 << 27)	/* PCMCIA Transmit FIFO Underflow */
1785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define I_SBINT		(1 << 28)	/* sbintstatus Interrupt */
1795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define I_CHIPACTIVE	(1 << 29)	/* chip from doze to active state */
1805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define I_SRESET	(1 << 30)	/* CCCR RES interrupt */
1815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define I_IOE2		(1U << 31)	/* CCCR IOE2 Bit Changed */
1825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define	I_ERRORS	(I_PC | I_PD | I_DE | I_RU | I_RO | I_XU)
1835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define I_DMA		(I_RI | I_XI | I_ERRORS)
1845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
1855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* corecontrol */
1865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define CC_CISRDY		(1 << 0)	/* CIS Ready */
1875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define CC_BPRESEN		(1 << 1)	/* CCCR RES signal */
1885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define CC_F2RDY		(1 << 2)	/* set CCCR IOR2 bit */
1895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define CC_CLRPADSISO		(1 << 3)	/* clear SDIO pads isolation */
1905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define CC_XMTDATAAVAIL_MODE	(1 << 4)
1915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define CC_XMTDATAAVAIL_CTRL	(1 << 5)
1925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
1935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* SDA_FRAMECTRL */
1945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SFC_RF_TERM	(1 << 0)	/* Read Frame Terminate */
1955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SFC_WF_TERM	(1 << 1)	/* Write Frame Terminate */
1965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SFC_CRC4WOOS	(1 << 2)	/* CRC error for write out of sync */
1975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SFC_ABORTALL	(1 << 3)	/* Abort all in-progress frames */
1985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
1995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* HW frame tag */
2005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SDPCM_FRAMETAG_LEN	4	/* 2 bytes len, 2 bytes check val */
2015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
2025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* Total length of frame header for dongle protocol */
2035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SDPCM_HDRLEN	(SDPCM_FRAMETAG_LEN + SDPCM_SWHEADER_LEN)
2045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SDPCM_RESERVE	(SDPCM_HDRLEN + BRCMF_SDALIGN)
2055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
2065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/*
2075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * Software allocation of To SB Mailbox resources
2085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */
2095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
2105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* tosbmailbox bits corresponding to intstatus bits */
2115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SMB_NAK		(1 << 0)	/* Frame NAK */
2125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SMB_INT_ACK	(1 << 1)	/* Host Interrupt ACK */
2135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SMB_USE_OOB	(1 << 2)	/* Use OOB Wakeup */
2145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SMB_DEV_INT	(1 << 3)	/* Miscellaneous Interrupt */
2155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
2165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* tosbmailboxdata */
2175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SMB_DATA_VERSION_SHIFT	16	/* host protocol version */
2185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
2195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/*
2205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * Software allocation of To Host Mailbox resources
2215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */
2225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
2235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* intstatus bits */
2245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define I_HMB_FC_STATE	I_HMB_SW0	/* Flow Control State */
2255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define I_HMB_FC_CHANGE	I_HMB_SW1	/* Flow Control State Changed */
2265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define I_HMB_FRAME_IND	I_HMB_SW2	/* Frame Indication */
2275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define I_HMB_HOST_INT	I_HMB_SW3	/* Miscellaneous Interrupt */
2285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
2295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* tohostmailboxdata */
2305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define HMB_DATA_NAKHANDLED	1	/* retransmit NAK'd frame */
2315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define HMB_DATA_DEVREADY	2	/* talk to host after enable */
2325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define HMB_DATA_FC		4	/* per prio flowcontrol update flag */
2335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define HMB_DATA_FWREADY	8	/* fw ready for protocol activity */
2345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
2355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define HMB_DATA_FCDATA_MASK	0xff000000
2365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define HMB_DATA_FCDATA_SHIFT	24
2375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
2385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define HMB_DATA_VERSION_MASK	0x00ff0000
2395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define HMB_DATA_VERSION_SHIFT	16
2405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
2415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/*
2425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * Software-defined protocol header
2435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */
2445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
2455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* Current protocol version */
2465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SDPCM_PROT_VERSION	4
2475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
2485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* SW frame header */
2495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SDPCM_PACKET_SEQUENCE(p)	(((u8 *)p)[0] & 0xff)
2505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
2515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SDPCM_CHANNEL_MASK		0x00000f00
2525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SDPCM_CHANNEL_SHIFT		8
2535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SDPCM_PACKET_CHANNEL(p)		(((u8 *)p)[1] & 0x0f)
2545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
2555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SDPCM_NEXTLEN_OFFSET		2
2565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
2575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* Data Offset from SOF (HW Tag, SW Tag, Pad) */
2585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SDPCM_DOFFSET_OFFSET		3	/* Data Offset */
2595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SDPCM_DOFFSET_VALUE(p)		(((u8 *)p)[SDPCM_DOFFSET_OFFSET] & 0xff)
2605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SDPCM_DOFFSET_MASK		0xff000000
2615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SDPCM_DOFFSET_SHIFT		24
2625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SDPCM_FCMASK_OFFSET		4	/* Flow control */
2635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SDPCM_FCMASK_VALUE(p)		(((u8 *)p)[SDPCM_FCMASK_OFFSET] & 0xff)
2645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SDPCM_WINDOW_OFFSET		5	/* Credit based fc */
2655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SDPCM_WINDOW_VALUE(p)		(((u8 *)p)[SDPCM_WINDOW_OFFSET] & 0xff)
2665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
2675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SDPCM_SWHEADER_LEN	8	/* SW header is 64 bits */
2685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
2695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* logical channel numbers */
2705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SDPCM_CONTROL_CHANNEL	0	/* Control channel Id */
2715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SDPCM_EVENT_CHANNEL	1	/* Asyc Event Indication Channel Id */
2725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SDPCM_DATA_CHANNEL	2	/* Data Xmit/Recv Channel Id */
2735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SDPCM_GLOM_CHANNEL	3	/* For coalesced packets */
2745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SDPCM_TEST_CHANNEL	15	/* Reserved for test/debug packets */
2755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
2765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SDPCM_SEQUENCE_WRAP	256	/* wrap-around val for 8bit frame seq */
2775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
2785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SDPCM_GLOMDESC(p)	(((u8 *)p)[1] & 0x80)
2795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
2805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/*
2815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * Shared structure between dongle and the host.
2825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * The structure contains pointers to trap or assert information.
2835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */
2845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SDPCM_SHARED_VERSION       0x0002
2855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SDPCM_SHARED_VERSION_MASK  0x00FF
2865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SDPCM_SHARED_ASSERT_BUILT  0x0100
2875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SDPCM_SHARED_ASSERT        0x0200
2885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SDPCM_SHARED_TRAP          0x0400
2895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
2905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* Space for header read, limit for data packets */
2915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define MAX_HDR_READ	(1 << 6)
2925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define MAX_RX_DATASZ	2048
2935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
2945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* Maximum milliseconds to wait for F2 to come up */
2955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define BRCMF_WAIT_F2RDY	3000
2965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
2975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* Bump up limit on waiting for HT to account for first startup;
2985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * if the image is doing a CRC calculation before programming the PMU
2995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * for HT availability, it could take a couple hundred ms more, so
3005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * max out at a 1 second (1000000us).
3015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */
3025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#undef PMU_MAX_TRANSITION_DLY
3035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define PMU_MAX_TRANSITION_DLY 1000000
3045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
3055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* Value for ChipClockCSR during initial setup */
3065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define BRCMF_INIT_CLKCTL1	(SBSDIO_FORCE_HW_CLKREQ_OFF |	\
3075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					SBSDIO_ALP_AVAIL_REQ)
3085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
3095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* Flags for SDH calls */
3105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define F2SYNC	(SDIO_REQ_4BYTE | SDIO_REQ_FIXED)
3115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
3128dd939cade92647a7c87db5ae895a6e120258320Franky Lin#define BRCMFMAC_FW_NAME	"brcm/brcmfmac.bin"
3138dd939cade92647a7c87db5ae895a6e120258320Franky Lin#define BRCMFMAC_NV_NAME	"brcm/brcmfmac.txt"
3148dd939cade92647a7c87db5ae895a6e120258320Franky LinMODULE_FIRMWARE(BRCMFMAC_FW_NAME);
3158dd939cade92647a7c87db5ae895a6e120258320Franky LinMODULE_FIRMWARE(BRCMFMAC_NV_NAME);
3168dd939cade92647a7c87db5ae895a6e120258320Franky Lin
3175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/*
3185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * Conversion of 802.1D priority to precedence level
3195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */
3205b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic uint prio2prec(u32 prio)
3215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
3225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	return (prio == PRIO_8021D_NONE || prio == PRIO_8021D_BE) ?
3235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	       (prio^2) : prio;
3245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
3255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
3265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* core registers */
3275b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstruct sdpcmd_regs {
3285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 corecontrol;		/* 0x00, rev8 */
3295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 corestatus;			/* rev8 */
3305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 PAD[1];
3315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 biststatus;			/* rev8 */
3325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
3335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* PCMCIA access */
3345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u16 pcmciamesportaladdr;	/* 0x010, rev8 */
3355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u16 PAD[1];
3365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u16 pcmciamesportalmask;	/* rev8 */
3375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u16 PAD[1];
3385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u16 pcmciawrframebc;		/* rev8 */
3395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u16 PAD[1];
3405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u16 pcmciaunderflowtimer;	/* rev8 */
3415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u16 PAD[1];
3425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
3435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* interrupt */
3445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 intstatus;			/* 0x020, rev8 */
3455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 hostintmask;		/* rev8 */
3465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 intmask;			/* rev8 */
3475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 sbintstatus;		/* rev8 */
3485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 sbintmask;			/* rev8 */
3495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 funcintmask;		/* rev4 */
3505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 PAD[2];
3515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 tosbmailbox;		/* 0x040, rev8 */
3525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 tohostmailbox;		/* rev8 */
3535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 tosbmailboxdata;		/* rev8 */
3545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 tohostmailboxdata;		/* rev8 */
3555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
3565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* synchronized access to registers in SDIO clock domain */
3575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 sdioaccess;			/* 0x050, rev8 */
3585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 PAD[3];
3595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
3605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* PCMCIA frame control */
3615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u8 pcmciaframectrl;		/* 0x060, rev8 */
3625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u8 PAD[3];
3635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u8 pcmciawatermark;		/* rev8 */
3645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u8 PAD[155];
3655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
3665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* interrupt batching control */
3675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 intrcvlazy;			/* 0x100, rev8 */
3685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 PAD[3];
3695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
3705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* counters */
3715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 cmd52rd;			/* 0x110, rev8 */
3725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 cmd52wr;			/* rev8 */
3735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 cmd53rd;			/* rev8 */
3745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 cmd53wr;			/* rev8 */
3755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 abort;			/* rev8 */
3765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 datacrcerror;		/* rev8 */
3775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 rdoutofsync;		/* rev8 */
3785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 wroutofsync;		/* rev8 */
3795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 writebusy;			/* rev8 */
3805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 readwait;			/* rev8 */
3815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 readterm;			/* rev8 */
3825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 writeterm;			/* rev8 */
3835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 PAD[40];
3845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 clockctlstatus;		/* rev8 */
3855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 PAD[7];
3865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
3875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 PAD[128];			/* DMA engines */
3885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
3895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* SDIO/PCMCIA CIS region */
3905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	char cis[512];			/* 0x400-0x5ff, rev6 */
3915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
3925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* PCMCIA function control registers */
3935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	char pcmciafcr[256];		/* 0x600-6ff, rev6 */
3945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u16 PAD[55];
3955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
3965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* PCMCIA backplane access */
3975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u16 backplanecsr;		/* 0x76E, rev6 */
3985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u16 backplaneaddr0;		/* rev6 */
3995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u16 backplaneaddr1;		/* rev6 */
4005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u16 backplaneaddr2;		/* rev6 */
4015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u16 backplaneaddr3;		/* rev6 */
4025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u16 backplanedata0;		/* rev6 */
4035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u16 backplanedata1;		/* rev6 */
4045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u16 backplanedata2;		/* rev6 */
4055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u16 backplanedata3;		/* rev6 */
4065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u16 PAD[31];
4075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
4085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* sprom "size" & "blank" info */
4095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u16 spromstatus;		/* 0x7BE, rev2 */
4105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 PAD[464];
4115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
4125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u16 PAD[0x80];
4135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel};
4145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
4155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#ifdef BCMDBG
4165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* Device console log buffer state */
4175b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstruct brcmf_console {
4185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint count;		/* Poll interval msec counter */
4195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint log_addr;		/* Log struct address (fixed) */
4205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	struct rte_log_le log_le;	/* Log struct (host copy) */
4215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint bufsize;		/* Size of log buffer */
4225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u8 *buf;		/* Log buffer (host copy) */
4235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint last;		/* Last buffer read index */
4245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel};
4255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#endif				/* BCMDBG */
4265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
4275b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstruct sdpcm_shared {
4285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 flags;
4295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 trap_addr;
4305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 assert_exp_addr;
4315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 assert_file_addr;
4325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 assert_line;
4335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 console_addr;	/* Address of struct rte_console */
4345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 msgtrace_addr;
4355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u8 tag[32];
4365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel};
4375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
4385b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstruct sdpcm_shared_le {
4395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	__le32 flags;
4405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	__le32 trap_addr;
4415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	__le32 assert_exp_addr;
4425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	__le32 assert_file_addr;
4435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	__le32 assert_line;
4445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	__le32 console_addr;	/* Address of struct rte_console */
4455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	__le32 msgtrace_addr;
4465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u8 tag[32];
4475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel};
4485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
4495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
4505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* misc chip info needed by some of the routines */
4515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* Private data for SDIO bus interaction */
452e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstruct brcmf_sdio {
4535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	struct brcmf_sdio_dev *sdiodev;	/* sdio device handler */
4545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	struct chip_info *ci;	/* Chip info struct */
4555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	char *vars;		/* Variables (from CIS and/or other) */
4565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint varsz;		/* Size of variables buffer */
4575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
4585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 ramsize;		/* Size of RAM in SOCRAM (bytes) */
4595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
4605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 hostintmask;	/* Copy of Host Interrupt Mask */
4615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 intstatus;	/* Intstatus bits (events) pending */
4625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bool dpc_sched;		/* Indicates DPC schedule (intrpt rcvd) */
4635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bool fcstate;		/* State of dongle flow-control */
4645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
4655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint blocksize;		/* Block size of SDIO transfers */
4665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint roundup;		/* Max roundup limit */
4675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
4685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	struct pktq txq;	/* Queue length used for flow-control */
4695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u8 flowcontrol;	/* per prio flow control bitmask */
4705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u8 tx_seq;		/* Transmit sequence number (next) */
4715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u8 tx_max;		/* Maximum transmit sequence allowed */
4725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
4735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u8 hdrbuf[MAX_HDR_READ + BRCMF_SDALIGN];
4745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u8 *rxhdr;		/* Header of current rx frame (in hdrbuf) */
4755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u16 nextlen;		/* Next Read Len from last header */
4765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u8 rx_seq;		/* Receive sequence number (expected) */
4775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bool rxskip;		/* Skip receive (awaiting NAK ACK) */
4785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
4795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint rxbound;		/* Rx frames to read before resched */
4805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint txbound;		/* Tx frames to send before resched */
4815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint txminmax;
4825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
4835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	struct sk_buff *glomd;	/* Packet containing glomming descriptor */
484b83db862ffb871e3131e5d2160c741b288eea9aaArend van Spriel	struct sk_buff_head glom; /* Packet list for glommed superframe */
4855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint glomerr;		/* Glom packet read errors */
4865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
4875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u8 *rxbuf;		/* Buffer for receiving control packets */
4885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint rxblen;		/* Allocated length of rxbuf */
4895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u8 *rxctl;		/* Aligned pointer into rxbuf */
4905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u8 *databuf;		/* Buffer for receiving big glom packet */
4915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u8 *dataptr;		/* Aligned pointer into databuf */
4925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint rxlen;		/* Length of valid data in buffer */
4935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
4945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u8 sdpcm_ver;	/* Bus protocol reported by dongle */
4955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
4965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bool intr;		/* Use interrupts */
4975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bool poll;		/* Use polling */
4985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bool ipend;		/* Device interrupt is pending */
4995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint intrcount;		/* Count of device interrupt callbacks */
5005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint lastintrs;		/* Count as of last watchdog timer */
5015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint spurious;		/* Count of spurious interrupts */
5025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint pollrate;		/* Ticks between device polls */
5035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint polltick;		/* Tick counter */
5045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint pollcnt;		/* Count of active polls */
5055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
5065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#ifdef BCMDBG
5075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint console_interval;
5085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	struct brcmf_console console;	/* Console output polling support */
5095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint console_addr;	/* Console address from shared struct */
5105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#endif				/* BCMDBG */
5115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
5125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint regfails;		/* Count of R_REG failures */
5135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
5145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint clkstate;		/* State of sd and backplane clock(s) */
5155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bool activity;		/* Activity flag for clock down */
5165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	s32 idletime;		/* Control for activity timeout */
5175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	s32 idlecount;	/* Activity timeout counter */
5185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	s32 idleclock;	/* How to set bus driver when idle */
5195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	s32 sd_rxchain;
5205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bool use_rxchain;	/* If brcmf should use PKT chains */
5215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bool sleeping;		/* Is SDIO bus sleeping? */
5225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bool rxflow_mode;	/* Rx flow control mode */
5235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bool rxflow;		/* Is rx flow control on */
5245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bool alp_only;		/* Don't use HT clock (ALP only) */
5255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* Field to decide if rx of control frames happen in rxbuf or lb-pool */
5265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bool usebufpool;
5275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
5285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Some additional counters */
5295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint tx_sderrs;		/* Count of tx attempts with sd errors */
5305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint fcqueued;		/* Tx packets that got queued */
5315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint rxrtx;		/* Count of rtx requests (NAK to dongle) */
5325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint rx_toolong;	/* Receive frames too long to receive */
5335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint rxc_errors;	/* SDIO errors when reading control frames */
5345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint rx_hdrfail;	/* SDIO errors on header reads */
5355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint rx_badhdr;		/* Bad received headers (roosync?) */
5365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint rx_badseq;		/* Mismatched rx sequence number */
5375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint fc_rcvd;		/* Number of flow-control events received */
5385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint fc_xoff;		/* Number which turned on flow-control */
5395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint fc_xon;		/* Number which turned off flow-control */
5405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint rxglomfail;	/* Failed deglom attempts */
5415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint rxglomframes;	/* Number of glom frames (superframes) */
5425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint rxglompkts;	/* Number of packets from glom frames */
5435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint f2rxhdrs;		/* Number of header reads */
5445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint f2rxdata;		/* Number of frame data reads */
5455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint f2txdata;		/* Number of f2 frame writes */
5465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint f1regdata;		/* Number of f1 register accesses */
54728a1a3bdaf4cce5ee8e473c332e2f371888341bbFranky Lin	uint tickcnt;		/* Number of watchdog been schedule */
54828a1a3bdaf4cce5ee8e473c332e2f371888341bbFranky Lin	unsigned long tx_ctlerrs;	/* Err of sending ctrl frames */
54928a1a3bdaf4cce5ee8e473c332e2f371888341bbFranky Lin	unsigned long tx_ctlpkts;	/* Ctrl frames sent to dongle */
55028a1a3bdaf4cce5ee8e473c332e2f371888341bbFranky Lin	unsigned long rx_ctlerrs;	/* Err of processing rx ctrl frames */
55128a1a3bdaf4cce5ee8e473c332e2f371888341bbFranky Lin	unsigned long rx_ctlpkts;	/* Ctrl frames processed from dongle */
55228a1a3bdaf4cce5ee8e473c332e2f371888341bbFranky Lin	unsigned long rx_readahead_cnt;	/* Number of packets where header
55328a1a3bdaf4cce5ee8e473c332e2f371888341bbFranky Lin					 * read-ahead was used. */
5545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
5555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u8 *ctrl_frame_buf;
5565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 ctrl_frame_len;
5575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bool ctrl_frame_stat;
5585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
5595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	spinlock_t txqlock;
5605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	wait_queue_head_t ctrl_wait;
5615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	wait_queue_head_t dcmd_resp_wait;
5625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
5635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	struct timer_list timer;
5645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	struct completion watchdog_wait;
5655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	struct task_struct *watchdog_tsk;
5665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bool wd_timer_valid;
5675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint save_ms;
5685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
5695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	struct task_struct *dpc_tsk;
5705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	struct completion dpc_wait;
5715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
5725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	struct semaphore sdsem;
5735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
5745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	const struct firmware *firmware;
5755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 fw_ptr;
576c8bf34849f92c5894a3d7e12573d3789d7851f23Franky Lin
577c8bf34849f92c5894a3d7e12573d3789d7851f23Franky Lin	bool txoff;		/* Transmit flow-controlled */
5785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel};
5795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
5805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* clkstate */
5815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define CLK_NONE	0
5825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define CLK_SDONLY	1
5835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define CLK_PENDING	2	/* Not used yet */
5845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define CLK_AVAIL	3
5855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
5865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#ifdef BCMDBG
5875b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic int qcount[NUMPRIO];
5885b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic int tx_packets[NUMPRIO];
5895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#endif				/* BCMDBG */
5905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
5915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SDIO_DRIVE_STRENGTH	6	/* in milliamps */
5925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
5935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define RETRYCHAN(chan) ((chan) == SDPCM_EVENT_CHANNEL)
5945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
5955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* Retry count for register access failures */
5965b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic const uint retry_limit = 2;
5975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
5985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* Limit on rounding up frames */
5995b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic const uint max_roundup = 512;
6005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
6015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define ALIGNMENT  4
6025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
6035b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic void pkt_align(struct sk_buff *p, int len, int align)
6045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
6055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint datalign;
6065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	datalign = (unsigned long)(p->data);
6075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	datalign = roundup(datalign, (align)) - datalign;
6085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (datalign)
6095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		skb_pull(p, datalign);
6105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	__skb_trim(p, len);
6115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
6125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
6135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* To check if there's window offered */
614e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic bool data_ok(struct brcmf_sdio *bus)
6155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
6165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	return (u8)(bus->tx_max - bus->tx_seq) != 0 &&
6175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	       ((u8)(bus->tx_max - bus->tx_seq) & 0x80) == 0;
6185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
6195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
6205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/*
6215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * Reads a register in the SDIO hardware block. This block occupies a series of
6225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * adresses on the 32 bit backplane bus.
6235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */
6245b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic void
625e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linr_sdreg32(struct brcmf_sdio *bus, u32 *regvar, u32 reg_offset, u32 *retryvar)
6265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
62799ba15cd75ed22e4ae86804ca2982a724e8102c2Franky Lin	u8 idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV);
6285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	*retryvar = 0;
6295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	do {
6305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		*regvar = brcmf_sdcard_reg_read(bus->sdiodev,
63199ba15cd75ed22e4ae86804ca2982a724e8102c2Franky Lin				bus->ci->c_inf[idx].base + reg_offset,
63299ba15cd75ed22e4ae86804ca2982a724e8102c2Franky Lin				sizeof(u32));
6335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	} while (brcmf_sdcard_regfail(bus->sdiodev) &&
6345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		 (++(*retryvar) <= retry_limit));
6355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (*retryvar) {
6365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->regfails += (*retryvar-1);
6375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (*retryvar > retry_limit) {
6385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(ERROR, "FAILED READ %Xh\n", reg_offset);
6395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			*regvar = 0;
6405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
6415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
6425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
6435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
6445b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic void
645e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linw_sdreg32(struct brcmf_sdio *bus, u32 regval, u32 reg_offset, u32 *retryvar)
6465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
64799ba15cd75ed22e4ae86804ca2982a724e8102c2Franky Lin	u8 idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV);
6485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	*retryvar = 0;
6495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	do {
6505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_sdcard_reg_write(bus->sdiodev,
65199ba15cd75ed22e4ae86804ca2982a724e8102c2Franky Lin				       bus->ci->c_inf[idx].base + reg_offset,
6525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				       sizeof(u32), regval);
6535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	} while (brcmf_sdcard_regfail(bus->sdiodev) &&
6545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		 (++(*retryvar) <= retry_limit));
6555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (*retryvar) {
6565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->regfails += (*retryvar-1);
6575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (*retryvar > retry_limit)
6585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(ERROR, "FAILED REGISTER WRITE %Xh\n",
6595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				  reg_offset);
6605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
6615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
6625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
6635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define PKT_AVAILABLE()		(intstatus & I_HMB_FRAME_IND)
6645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
6655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define HOSTINTMASK		(I_HMB_SW_MASK | I_CHIPACTIVE)
6665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
6675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* Packet free applicable unconditionally for sdio and sdspi.
6685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * Conditional if bufpool was present for gspi bus.
6695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */
670e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic void brcmf_sdbrcm_pktfree2(struct brcmf_sdio *bus, struct sk_buff *pkt)
6715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
6725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (bus->usebufpool)
6735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmu_pkt_buf_free_skb(pkt);
6745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
6755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
6765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* Turn backplane clock on or off */
677e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok)
6785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
6795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	int err;
6805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u8 clkctl, clkreq, devctl;
6815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	unsigned long timeout;
6825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
6835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_dbg(TRACE, "Enter\n");
6845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
6855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	clkctl = 0;
6865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
6875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (on) {
6885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Request HT Avail */
6895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		clkreq =
6905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		    bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ;
6915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
6925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
6935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				       SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
6945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (err) {
6955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(ERROR, "HT Avail request error: %d\n", err);
6965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			return -EBADE;
6975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
6985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
6995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Check current status */
7005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		clkctl = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
7015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					       SBSDIO_FUNC1_CHIPCLKCSR, &err);
7025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (err) {
7035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(ERROR, "HT Avail read error: %d\n", err);
7045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			return -EBADE;
7055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
7065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
7075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Go to pending and await interrupt if appropriate */
7085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (!SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) {
7095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			/* Allow only clock-available interrupt */
7105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			devctl = brcmf_sdcard_cfg_read(bus->sdiodev,
7115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					SDIO_FUNC_1,
7125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					SBSDIO_DEVICE_CTL, &err);
7135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			if (err) {
7145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				brcmf_dbg(ERROR, "Devctl error setting CA: %d\n",
7155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					  err);
7165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				return -EBADE;
7175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			}
7185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
7195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			devctl |= SBSDIO_DEVCTL_CA_INT_ONLY;
7205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
7215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					       SBSDIO_DEVICE_CTL, devctl, &err);
7225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(INFO, "CLKCTL: set PENDING\n");
7235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			bus->clkstate = CLK_PENDING;
7245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
7255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			return 0;
7265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		} else if (bus->clkstate == CLK_PENDING) {
7275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			/* Cancel CA-only interrupt filter */
7285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			devctl =
7295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			    brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
7305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel						  SBSDIO_DEVICE_CTL, &err);
7315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
7325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
7335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				SBSDIO_DEVICE_CTL, devctl, &err);
7345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
7355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
7365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Otherwise, wait here (polling) for HT Avail */
7375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		timeout = jiffies +
7385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			  msecs_to_jiffies(PMU_MAX_TRANSITION_DLY/1000);
7395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		while (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
7405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			clkctl = brcmf_sdcard_cfg_read(bus->sdiodev,
7415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel						       SDIO_FUNC_1,
7425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel						       SBSDIO_FUNC1_CHIPCLKCSR,
7435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel						       &err);
7445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			if (time_after(jiffies, timeout))
7455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				break;
7465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			else
7475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				usleep_range(5000, 10000);
7485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
7495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (err) {
7505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(ERROR, "HT Avail request error: %d\n", err);
7515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			return -EBADE;
7525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
7535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
7545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(ERROR, "HT Avail timeout (%d): clkctl 0x%02x\n",
7555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				  PMU_MAX_TRANSITION_DLY, clkctl);
7565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			return -EBADE;
7575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
7585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
7595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Mark clock available */
7605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->clkstate = CLK_AVAIL;
7615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(INFO, "CLKCTL: turned ON\n");
7625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
7635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#if defined(BCMDBG)
7645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (bus->alp_only != true) {
7655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			if (SBSDIO_ALPONLY(clkctl))
7665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				brcmf_dbg(ERROR, "HT Clock should be on\n");
7675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
7685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#endif				/* defined (BCMDBG) */
7695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
7705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->activity = true;
7715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	} else {
7725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		clkreq = 0;
7735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
7745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (bus->clkstate == CLK_PENDING) {
7755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			/* Cancel CA-only interrupt filter */
7765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			devctl = brcmf_sdcard_cfg_read(bus->sdiodev,
7775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					SDIO_FUNC_1,
7785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					SBSDIO_DEVICE_CTL, &err);
7795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
7805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
7815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				SBSDIO_DEVICE_CTL, devctl, &err);
7825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
7835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
7845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->clkstate = CLK_SDONLY;
7855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
7865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
7875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(INFO, "CLKCTL: turned OFF\n");
7885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (err) {
7895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(ERROR, "Failed access turning clock off: %d\n",
7905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				  err);
7915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			return -EBADE;
7925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
7935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
7945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	return 0;
7955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
7965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
7975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* Change idle/active SD state */
798e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic int brcmf_sdbrcm_sdclk(struct brcmf_sdio *bus, bool on)
7995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
8005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_dbg(TRACE, "Enter\n");
8015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
8025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (on)
8035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->clkstate = CLK_SDONLY;
8045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	else
8055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->clkstate = CLK_NONE;
8065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
8075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	return 0;
8085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
8095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
8105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* Transition SD and backplane clock readiness */
811e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic int brcmf_sdbrcm_clkctl(struct brcmf_sdio *bus, uint target, bool pendok)
8125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
8135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#ifdef BCMDBG
8145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint oldstate = bus->clkstate;
8155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#endif				/* BCMDBG */
8165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
8175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_dbg(TRACE, "Enter\n");
8185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
8195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Early exit if we're already there */
8205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (bus->clkstate == target) {
8215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (target == CLK_AVAIL) {
8225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS);
8235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			bus->activity = true;
8245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
8255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		return 0;
8265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
8275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
8285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	switch (target) {
8295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	case CLK_AVAIL:
8305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Make sure SD clock is available */
8315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (bus->clkstate == CLK_NONE)
8325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_sdbrcm_sdclk(bus, true);
8335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Now request HT Avail on the backplane */
8345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_sdbrcm_htclk(bus, true, pendok);
8355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS);
8365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->activity = true;
8375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		break;
8385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
8395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	case CLK_SDONLY:
8405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Remove HT request, or bring up SD clock */
8415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (bus->clkstate == CLK_NONE)
8425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_sdbrcm_sdclk(bus, true);
8435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		else if (bus->clkstate == CLK_AVAIL)
8445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_sdbrcm_htclk(bus, false, false);
8455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		else
8465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(ERROR, "request for %d -> %d\n",
8475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				  bus->clkstate, target);
8485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS);
8495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		break;
8505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
8515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	case CLK_NONE:
8525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Make sure to remove HT request */
8535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (bus->clkstate == CLK_AVAIL)
8545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_sdbrcm_htclk(bus, false, false);
8555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Now remove the SD clock */
8565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_sdbrcm_sdclk(bus, false);
8575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_sdbrcm_wd_timer(bus, 0);
8585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		break;
8595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
8605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#ifdef BCMDBG
8615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_dbg(INFO, "%d -> %d\n", oldstate, bus->clkstate);
8625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#endif				/* BCMDBG */
8635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
8645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	return 0;
8655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
8665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
867e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic int brcmf_sdbrcm_bussleep(struct brcmf_sdio *bus, bool sleep)
8685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
8695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint retries = 0;
8705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
8715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_dbg(INFO, "request %s (currently %s)\n",
8725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		  sleep ? "SLEEP" : "WAKE",
8735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		  bus->sleeping ? "SLEEP" : "WAKE");
8745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
8755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Done if we're already in the requested state */
8765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (sleep == bus->sleeping)
8775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		return 0;
8785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
8795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Going to sleep: set the alarm and turn off the lights... */
8805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (sleep) {
8815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Don't sleep if something is pending */
8825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (bus->dpc_sched || bus->rxskip || pktq_len(&bus->txq))
8835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			return -EBUSY;
8845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
8855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Make sure the controller has the bus up */
8865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
8875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
8885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Tell device to start using OOB wakeup */
8895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		w_sdreg32(bus, SMB_USE_OOB,
8905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			  offsetof(struct sdpcmd_regs, tosbmailbox), &retries);
8915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (retries > retry_limit)
8925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(ERROR, "CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n");
8935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
8945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Turn off our contribution to the HT clock request */
8955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false);
8965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
8975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
8985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			SBSDIO_FUNC1_CHIPCLKCSR,
8995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			SBSDIO_FORCE_HW_CLKREQ_OFF, NULL);
9005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
9015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Isolate the bus */
902718897eb3f90a47a56acb504762d521388a3231cFranky Lin		brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
903718897eb3f90a47a56acb504762d521388a3231cFranky Lin			SBSDIO_DEVICE_CTL,
904718897eb3f90a47a56acb504762d521388a3231cFranky Lin			SBSDIO_DEVCTL_PADS_ISO, NULL);
9055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
9065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Change state */
9075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->sleeping = true;
9085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
9095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	} else {
9105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Waking up: bus power up is ok, set local state */
9115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
9125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
9135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
9145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
9155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Make sure the controller has the bus up */
9165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
9175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
9185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Send misc interrupt to indicate OOB not needed */
9195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		w_sdreg32(bus, 0, offsetof(struct sdpcmd_regs, tosbmailboxdata),
9205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			  &retries);
9215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (retries <= retry_limit)
9225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			w_sdreg32(bus, SMB_DEV_INT,
9235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				  offsetof(struct sdpcmd_regs, tosbmailbox),
9245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				  &retries);
9255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
9265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (retries > retry_limit)
9275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(ERROR, "CANNOT SIGNAL CHIP TO CLEAR OOB!!\n");
9285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
9295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Make sure we have SD bus access */
9305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false);
9315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
9325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Change state */
9335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->sleeping = false;
9345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
9355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
9365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	return 0;
9375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
9385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
939e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic void bus_wake(struct brcmf_sdio *bus)
9405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
9415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (bus->sleeping)
9425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_sdbrcm_bussleep(bus, false);
9435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
9445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
945e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic u32 brcmf_sdbrcm_hostmail(struct brcmf_sdio *bus)
9465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
9475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 intstatus = 0;
9485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 hmb_data;
9495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u8 fcbits;
9505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint retries = 0;
9515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
9525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_dbg(TRACE, "Enter\n");
9535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
9545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Read mailbox data and ack that we did so */
9555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	r_sdreg32(bus, &hmb_data,
9565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		  offsetof(struct sdpcmd_regs, tohostmailboxdata), &retries);
9575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
9585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (retries <= retry_limit)
9595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		w_sdreg32(bus, SMB_INT_ACK,
9605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			  offsetof(struct sdpcmd_regs, tosbmailbox), &retries);
9615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->f1regdata += 2;
9625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
9635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Dongle recomposed rx frames, accept them again */
9645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (hmb_data & HMB_DATA_NAKHANDLED) {
9655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(INFO, "Dongle reports NAK handled, expect rtx of %d\n",
9665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			  bus->rx_seq);
9675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (!bus->rxskip)
9685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(ERROR, "unexpected NAKHANDLED!\n");
9695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
9705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->rxskip = false;
9715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		intstatus |= I_HMB_FRAME_IND;
9725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
9735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
9745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/*
9755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	 * DEVREADY does not occur with gSPI.
9765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	 */
9775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (hmb_data & (HMB_DATA_DEVREADY | HMB_DATA_FWREADY)) {
9785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->sdpcm_ver =
9795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		    (hmb_data & HMB_DATA_VERSION_MASK) >>
9805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		    HMB_DATA_VERSION_SHIFT;
9815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (bus->sdpcm_ver != SDPCM_PROT_VERSION)
9825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(ERROR, "Version mismatch, dongle reports %d, "
9835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				  "expecting %d\n",
9845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				  bus->sdpcm_ver, SDPCM_PROT_VERSION);
9855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		else
9865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(INFO, "Dongle ready, protocol version %d\n",
9875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				  bus->sdpcm_ver);
9885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
9895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
9905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/*
9915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	 * Flow Control has been moved into the RX headers and this out of band
9925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	 * method isn't used any more.
9935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	 * remaining backward compatible with older dongles.
9945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	 */
9955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (hmb_data & HMB_DATA_FC) {
9965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		fcbits = (hmb_data & HMB_DATA_FCDATA_MASK) >>
9975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel							HMB_DATA_FCDATA_SHIFT;
9985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
9995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (fcbits & ~bus->flowcontrol)
10005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			bus->fc_xoff++;
10015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
10025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (bus->flowcontrol & ~fcbits)
10035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			bus->fc_xon++;
10045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
10055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->fc_rcvd++;
10065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->flowcontrol = fcbits;
10075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
10085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
10095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Shouldn't be any others */
10105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (hmb_data & ~(HMB_DATA_DEVREADY |
10115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			 HMB_DATA_NAKHANDLED |
10125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			 HMB_DATA_FC |
10135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			 HMB_DATA_FWREADY |
10145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			 HMB_DATA_FCDATA_MASK | HMB_DATA_VERSION_MASK))
10155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(ERROR, "Unknown mailbox data content: 0x%02x\n",
10165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			  hmb_data);
10175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
10185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	return intstatus;
10195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
10205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
1021e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic void brcmf_sdbrcm_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx)
10225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
10235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint retries = 0;
10245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u16 lastrbc;
10255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u8 hi, lo;
10265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	int err;
10275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
10285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_dbg(ERROR, "%sterminate frame%s\n",
10295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		  abort ? "abort command, " : "",
10305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		  rtx ? ", send NAK" : "");
10315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
10325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (abort)
10335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2);
10345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
10355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
10365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			       SBSDIO_FUNC1_FRAMECTRL,
10375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			       SFC_RF_TERM, &err);
10385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->f1regdata++;
10395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
10405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Wait until the packet has been flushed (device/FIFO stable) */
10415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	for (lastrbc = retries = 0xffff; retries > 0; retries--) {
10425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		hi = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
10435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					   SBSDIO_FUNC1_RFRAMEBCHI, NULL);
10445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		lo = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
10455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					   SBSDIO_FUNC1_RFRAMEBCLO, NULL);
10465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->f1regdata += 2;
10475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
10485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if ((hi == 0) && (lo == 0))
10495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			break;
10505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
10515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if ((hi > (lastrbc >> 8)) && (lo > (lastrbc & 0x00ff))) {
10525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(ERROR, "count growing: last 0x%04x now 0x%04x\n",
10535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				  lastrbc, (hi << 8) + lo);
10545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
10555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		lastrbc = (hi << 8) + lo;
10565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
10575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
10585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (!retries)
10595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(ERROR, "count never zeroed: last 0x%04x\n", lastrbc);
10605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	else
10615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(INFO, "flush took %d iterations\n", 0xffff - retries);
10625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
10635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (rtx) {
10645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->rxrtx++;
10655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		w_sdreg32(bus, SMB_NAK,
10665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			  offsetof(struct sdpcmd_regs, tosbmailbox), &retries);
10675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
10685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->f1regdata++;
10695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (retries <= retry_limit)
10705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			bus->rxskip = true;
10715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
10725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
10735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Clear partial in any case */
10745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->nextlen = 0;
10755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
10765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* If we can't reach the device, signal failure */
10775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (err || brcmf_sdcard_regfail(bus->sdiodev))
1078712ac5b37a3348cac4e040c551a6ca6186d33682Franky Lin		bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
10795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
10805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
108120e5ca16397648811a9e1ad531360c843e005a57Arend van Spriel/* copy a buffer into a pkt buffer chain */
1082e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic uint brcmf_sdbrcm_glom_from_buf(struct brcmf_sdio *bus, uint len)
108320e5ca16397648811a9e1ad531360c843e005a57Arend van Spriel{
108420e5ca16397648811a9e1ad531360c843e005a57Arend van Spriel	uint n, ret = 0;
108520e5ca16397648811a9e1ad531360c843e005a57Arend van Spriel	struct sk_buff *p;
108620e5ca16397648811a9e1ad531360c843e005a57Arend van Spriel	u8 *buf;
108720e5ca16397648811a9e1ad531360c843e005a57Arend van Spriel
108820e5ca16397648811a9e1ad531360c843e005a57Arend van Spriel	buf = bus->dataptr;
108920e5ca16397648811a9e1ad531360c843e005a57Arend van Spriel
109020e5ca16397648811a9e1ad531360c843e005a57Arend van Spriel	/* copy the data */
1091b83db862ffb871e3131e5d2160c741b288eea9aaArend van Spriel	skb_queue_walk(&bus->glom, p) {
109220e5ca16397648811a9e1ad531360c843e005a57Arend van Spriel		n = min_t(uint, p->len, len);
109320e5ca16397648811a9e1ad531360c843e005a57Arend van Spriel		memcpy(p->data, buf, n);
109420e5ca16397648811a9e1ad531360c843e005a57Arend van Spriel		buf += n;
109520e5ca16397648811a9e1ad531360c843e005a57Arend van Spriel		len -= n;
109620e5ca16397648811a9e1ad531360c843e005a57Arend van Spriel		ret += n;
1097b83db862ffb871e3131e5d2160c741b288eea9aaArend van Spriel		if (!len)
1098b83db862ffb871e3131e5d2160c741b288eea9aaArend van Spriel			break;
109920e5ca16397648811a9e1ad531360c843e005a57Arend van Spriel	}
110020e5ca16397648811a9e1ad531360c843e005a57Arend van Spriel
110120e5ca16397648811a9e1ad531360c843e005a57Arend van Spriel	return ret;
110220e5ca16397648811a9e1ad531360c843e005a57Arend van Spriel}
110320e5ca16397648811a9e1ad531360c843e005a57Arend van Spriel
11049a95e60e0610bb8ec39c74d2c8546514a76428dfArend van Spriel/* return total length of buffer chain */
1105e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic uint brcmf_sdbrcm_glom_len(struct brcmf_sdio *bus)
11069a95e60e0610bb8ec39c74d2c8546514a76428dfArend van Spriel{
11079a95e60e0610bb8ec39c74d2c8546514a76428dfArend van Spriel	struct sk_buff *p;
11089a95e60e0610bb8ec39c74d2c8546514a76428dfArend van Spriel	uint total;
11099a95e60e0610bb8ec39c74d2c8546514a76428dfArend van Spriel
11109a95e60e0610bb8ec39c74d2c8546514a76428dfArend van Spriel	total = 0;
11119a95e60e0610bb8ec39c74d2c8546514a76428dfArend van Spriel	skb_queue_walk(&bus->glom, p)
11129a95e60e0610bb8ec39c74d2c8546514a76428dfArend van Spriel		total += p->len;
11139a95e60e0610bb8ec39c74d2c8546514a76428dfArend van Spriel	return total;
11149a95e60e0610bb8ec39c74d2c8546514a76428dfArend van Spriel}
11159a95e60e0610bb8ec39c74d2c8546514a76428dfArend van Spriel
1116e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic void brcmf_sdbrcm_free_glom(struct brcmf_sdio *bus)
1117046808daf9f6b8c5275861330d4f8c2e6cfe3c31Arend van Spriel{
1118046808daf9f6b8c5275861330d4f8c2e6cfe3c31Arend van Spriel	struct sk_buff *cur, *next;
1119046808daf9f6b8c5275861330d4f8c2e6cfe3c31Arend van Spriel
1120046808daf9f6b8c5275861330d4f8c2e6cfe3c31Arend van Spriel	skb_queue_walk_safe(&bus->glom, cur, next) {
1121046808daf9f6b8c5275861330d4f8c2e6cfe3c31Arend van Spriel		skb_unlink(cur, &bus->glom);
1122046808daf9f6b8c5275861330d4f8c2e6cfe3c31Arend van Spriel		brcmu_pkt_buf_free_skb(cur);
1123046808daf9f6b8c5275861330d4f8c2e6cfe3c31Arend van Spriel	}
1124046808daf9f6b8c5275861330d4f8c2e6cfe3c31Arend van Spriel}
1125046808daf9f6b8c5275861330d4f8c2e6cfe3c31Arend van Spriel
1126e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
11275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
11285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u16 dlen, totlen;
11295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u8 *dptr, num = 0;
11305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
11315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u16 sublen, check;
11320b45bf74f91e781b74bfadb8bb08ef341b6befd3Arend van Spriel	struct sk_buff *pfirst, *pnext;
11335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
11345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	int errcode;
11355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u8 chan, seq, doff, sfdoff;
11365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u8 txmax;
11375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
11385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	int ifidx = 0;
11395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bool usechain = bus->use_rxchain;
11405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
11415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* If packets, issue read(s) and send up packet chain */
11425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Return sequence numbers consumed? */
11435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
1144b83db862ffb871e3131e5d2160c741b288eea9aaArend van Spriel	brcmf_dbg(TRACE, "start: glomd %p glom %p\n",
1145b83db862ffb871e3131e5d2160c741b288eea9aaArend van Spriel		  bus->glomd, skb_peek(&bus->glom));
11465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
11475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* If there's a descriptor, generate the packet chain */
11485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (bus->glomd) {
11490b45bf74f91e781b74bfadb8bb08ef341b6befd3Arend van Spriel		pfirst = pnext = NULL;
11505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		dlen = (u16) (bus->glomd->len);
11515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		dptr = bus->glomd->data;
11525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (!dlen || (dlen & 1)) {
11535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(ERROR, "bad glomd len(%d), ignore descriptor\n",
11545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				  dlen);
11555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			dlen = 0;
11565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
11575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
11585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		for (totlen = num = 0; dlen; num++) {
11595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			/* Get (and move past) next length */
11605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			sublen = get_unaligned_le16(dptr);
11615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			dlen -= sizeof(u16);
11625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			dptr += sizeof(u16);
11635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			if ((sublen < SDPCM_HDRLEN) ||
11645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			    ((num == 0) && (sublen < (2 * SDPCM_HDRLEN)))) {
11655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				brcmf_dbg(ERROR, "descriptor len %d bad: %d\n",
11665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					  num, sublen);
11675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				pnext = NULL;
11685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				break;
11695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			}
11705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			if (sublen % BRCMF_SDALIGN) {
11715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				brcmf_dbg(ERROR, "sublen %d not multiple of %d\n",
11725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					  sublen, BRCMF_SDALIGN);
11735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				usechain = false;
11745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			}
11755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			totlen += sublen;
11765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
11775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			/* For last frame, adjust read len so total
11785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				 is a block multiple */
11795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			if (!dlen) {
11805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				sublen +=
11815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				    (roundup(totlen, bus->blocksize) - totlen);
11825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				totlen = roundup(totlen, bus->blocksize);
11835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			}
11845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
11855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			/* Allocate/chain packet for next subframe */
11865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			pnext = brcmu_pkt_buf_get_skb(sublen + BRCMF_SDALIGN);
11875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			if (pnext == NULL) {
11885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				brcmf_dbg(ERROR, "bcm_pkt_buf_get_skb failed, num %d len %d\n",
11895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					  num, sublen);
11905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				break;
11915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			}
1192b83db862ffb871e3131e5d2160c741b288eea9aaArend van Spriel			skb_queue_tail(&bus->glom, pnext);
11935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
11945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			/* Adhere to start alignment requirements */
11955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			pkt_align(pnext, sublen, BRCMF_SDALIGN);
11965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
11975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
11985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* If all allocations succeeded, save packet chain
11995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			 in bus structure */
12005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (pnext) {
12015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(GLOM, "allocated %d-byte packet chain for %d subframes\n",
12025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				  totlen, num);
12035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			if (BRCMF_GLOM_ON() && bus->nextlen &&
12045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			    totlen != bus->nextlen) {
12055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				brcmf_dbg(GLOM, "glomdesc mismatch: nextlen %d glomdesc %d rxseq %d\n",
12065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					  bus->nextlen, totlen, rxseq);
12075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			}
12085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			pfirst = pnext = NULL;
12095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		} else {
1210046808daf9f6b8c5275861330d4f8c2e6cfe3c31Arend van Spriel			brcmf_sdbrcm_free_glom(bus);
12115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			num = 0;
12125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
12135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
12145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Done with descriptor packet */
12155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmu_pkt_buf_free_skb(bus->glomd);
12165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->glomd = NULL;
12175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->nextlen = 0;
12185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
12195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
12205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Ok -- either we just generated a packet chain,
12215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		 or had one from before */
1222b83db862ffb871e3131e5d2160c741b288eea9aaArend van Spriel	if (!skb_queue_empty(&bus->glom)) {
12235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (BRCMF_GLOM_ON()) {
12245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(GLOM, "try superframe read, packet chain:\n");
1225b83db862ffb871e3131e5d2160c741b288eea9aaArend van Spriel			skb_queue_walk(&bus->glom, pnext) {
12265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				brcmf_dbg(GLOM, "    %p: %p len 0x%04x (%d)\n",
12275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					  pnext, (u8 *) (pnext->data),
12285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					  pnext->len, pnext->len);
12295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			}
12305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
12315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
1232b83db862ffb871e3131e5d2160c741b288eea9aaArend van Spriel		pfirst = skb_peek(&bus->glom);
12339a95e60e0610bb8ec39c74d2c8546514a76428dfArend van Spriel		dlen = (u16) brcmf_sdbrcm_glom_len(bus);
12345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
12355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Do an SDIO read for the superframe.  Configurable iovar to
12365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		 * read directly into the chained packet, or allocate a large
12375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		 * packet and and copy into the chain.
12385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		 */
12395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (usechain) {
12405adfeb632c52a6c15e98fa6465bdade6fff915d9Arend van Spriel			errcode = brcmf_sdcard_recv_chain(bus->sdiodev,
12415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					bus->sdiodev->sbwad,
12425adfeb632c52a6c15e98fa6465bdade6fff915d9Arend van Spriel					SDIO_FUNC_2, F2SYNC, &bus->glom);
12435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		} else if (bus->dataptr) {
12445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			errcode = brcmf_sdcard_recv_buf(bus->sdiodev,
12455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					bus->sdiodev->sbwad,
12465adfeb632c52a6c15e98fa6465bdade6fff915d9Arend van Spriel					SDIO_FUNC_2, F2SYNC,
12475adfeb632c52a6c15e98fa6465bdade6fff915d9Arend van Spriel					bus->dataptr, dlen);
124820e5ca16397648811a9e1ad531360c843e005a57Arend van Spriel			sublen = (u16) brcmf_sdbrcm_glom_from_buf(bus, dlen);
12495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			if (sublen != dlen) {
12505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				brcmf_dbg(ERROR, "FAILED TO COPY, dlen %d sublen %d\n",
12515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					  dlen, sublen);
12525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				errcode = -1;
12535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			}
12545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			pnext = NULL;
12555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		} else {
12565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(ERROR, "COULDN'T ALLOC %d-BYTE GLOM, FORCE FAILURE\n",
12575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				  dlen);
12585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			errcode = -1;
12595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
12605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->f2rxdata++;
12615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
12625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* On failure, kill the superframe, allow a couple retries */
12635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (errcode < 0) {
12645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(ERROR, "glom read of %d bytes failed: %d\n",
12655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				  dlen, errcode);
1266719f2733baa1e6a6a782c5109bfe054431db4259Franky Lin			bus->sdiodev->bus_if->dstats.rx_errors++;
12675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
12685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			if (bus->glomerr++ < 3) {
12695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				brcmf_sdbrcm_rxfail(bus, true, true);
12705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			} else {
12715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				bus->glomerr = 0;
12725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				brcmf_sdbrcm_rxfail(bus, true, false);
12735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				bus->rxglomfail++;
1274046808daf9f6b8c5275861330d4f8c2e6cfe3c31Arend van Spriel				brcmf_sdbrcm_free_glom(bus);
12755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			}
12765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			return 0;
12775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
12785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#ifdef BCMDBG
12795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (BRCMF_GLOM_ON()) {
12805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			printk(KERN_DEBUG "SUPERFRAME:\n");
12815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
12825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				pfirst->data, min_t(int, pfirst->len, 48));
12835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
12845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#endif
12855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
12865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Validate the superframe header */
12875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		dptr = (u8 *) (pfirst->data);
12885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		sublen = get_unaligned_le16(dptr);
12895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		check = get_unaligned_le16(dptr + sizeof(u16));
12905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
12915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
12925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
12935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->nextlen = dptr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
12945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
12955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(INFO, "nextlen too large (%d) seq %d\n",
12965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				  bus->nextlen, seq);
12975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			bus->nextlen = 0;
12985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
12995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
13005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		txmax = SDPCM_WINDOW_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
13015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
13025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		errcode = 0;
13035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if ((u16)~(sublen ^ check)) {
13045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(ERROR, "(superframe): HW hdr error: len/check 0x%04x/0x%04x\n",
13055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				  sublen, check);
13065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			errcode = -1;
13075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		} else if (roundup(sublen, bus->blocksize) != dlen) {
13085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(ERROR, "(superframe): len 0x%04x, rounded 0x%04x, expect 0x%04x\n",
13095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				  sublen, roundup(sublen, bus->blocksize),
13105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				  dlen);
13115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			errcode = -1;
13125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		} else if (SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]) !=
13135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			   SDPCM_GLOM_CHANNEL) {
13145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(ERROR, "(superframe): bad channel %d\n",
13155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				  SDPCM_PACKET_CHANNEL(
13165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					  &dptr[SDPCM_FRAMETAG_LEN]));
13175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			errcode = -1;
13185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		} else if (SDPCM_GLOMDESC(&dptr[SDPCM_FRAMETAG_LEN])) {
13195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(ERROR, "(superframe): got 2nd descriptor?\n");
13205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			errcode = -1;
13215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		} else if ((doff < SDPCM_HDRLEN) ||
13225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			   (doff > (pfirst->len - SDPCM_HDRLEN))) {
13235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(ERROR, "(superframe): Bad data offset %d: HW %d pkt %d min %d\n",
13245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				  doff, sublen, pfirst->len, SDPCM_HDRLEN);
13255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			errcode = -1;
13265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
13275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
13285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Check sequence number of superframe SW header */
13295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (rxseq != seq) {
13305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(INFO, "(superframe) rx_seq %d, expected %d\n",
13315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				  seq, rxseq);
13325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			bus->rx_badseq++;
13335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			rxseq = seq;
13345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
13355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
13365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Check window for sanity */
13375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if ((u8) (txmax - bus->tx_seq) > 0x40) {
13385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(ERROR, "unlikely tx max %d with tx_seq %d\n",
13395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				  txmax, bus->tx_seq);
13405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			txmax = bus->tx_seq + 2;
13415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
13425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->tx_max = txmax;
13435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
13445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Remove superframe header, remember offset */
13455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		skb_pull(pfirst, doff);
13465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		sfdoff = doff;
13470b45bf74f91e781b74bfadb8bb08ef341b6befd3Arend van Spriel		num = 0;
13485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
13495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Validate all the subframe headers */
13500b45bf74f91e781b74bfadb8bb08ef341b6befd3Arend van Spriel		skb_queue_walk(&bus->glom, pnext) {
13510b45bf74f91e781b74bfadb8bb08ef341b6befd3Arend van Spriel			/* leave when invalid subframe is found */
13520b45bf74f91e781b74bfadb8bb08ef341b6befd3Arend van Spriel			if (errcode)
13530b45bf74f91e781b74bfadb8bb08ef341b6befd3Arend van Spriel				break;
13540b45bf74f91e781b74bfadb8bb08ef341b6befd3Arend van Spriel
13555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			dptr = (u8 *) (pnext->data);
13565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			dlen = (u16) (pnext->len);
13575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			sublen = get_unaligned_le16(dptr);
13585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			check = get_unaligned_le16(dptr + sizeof(u16));
13595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
13605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
13615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#ifdef BCMDBG
13625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			if (BRCMF_GLOM_ON()) {
13635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				printk(KERN_DEBUG "subframe:\n");
13645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
13655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel						     dptr, 32);
13665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			}
13675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#endif
13685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
13695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			if ((u16)~(sublen ^ check)) {
13705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				brcmf_dbg(ERROR, "(subframe %d): HW hdr error: len/check 0x%04x/0x%04x\n",
13715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					  num, sublen, check);
13725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				errcode = -1;
13735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			} else if ((sublen > dlen) || (sublen < SDPCM_HDRLEN)) {
13745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				brcmf_dbg(ERROR, "(subframe %d): length mismatch: len 0x%04x, expect 0x%04x\n",
13755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					  num, sublen, dlen);
13765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				errcode = -1;
13775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			} else if ((chan != SDPCM_DATA_CHANNEL) &&
13785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				   (chan != SDPCM_EVENT_CHANNEL)) {
13795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				brcmf_dbg(ERROR, "(subframe %d): bad channel %d\n",
13805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					  num, chan);
13815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				errcode = -1;
13825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			} else if ((doff < SDPCM_HDRLEN) || (doff > sublen)) {
13835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				brcmf_dbg(ERROR, "(subframe %d): Bad data offset %d: HW %d min %d\n",
13845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					  num, doff, sublen, SDPCM_HDRLEN);
13855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				errcode = -1;
13865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			}
13870b45bf74f91e781b74bfadb8bb08ef341b6befd3Arend van Spriel			/* increase the subframe count */
13880b45bf74f91e781b74bfadb8bb08ef341b6befd3Arend van Spriel			num++;
13895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
13905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
13915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (errcode) {
13925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			/* Terminate frame on error, request
13935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				 a couple retries */
13945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			if (bus->glomerr++ < 3) {
13955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				/* Restore superframe header space */
13965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				skb_push(pfirst, sfdoff);
13975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				brcmf_sdbrcm_rxfail(bus, true, true);
13985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			} else {
13995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				bus->glomerr = 0;
14005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				brcmf_sdbrcm_rxfail(bus, true, false);
14015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				bus->rxglomfail++;
1402046808daf9f6b8c5275861330d4f8c2e6cfe3c31Arend van Spriel				brcmf_sdbrcm_free_glom(bus);
14035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			}
14045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			bus->nextlen = 0;
14055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			return 0;
14065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
14075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
14085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Basic SD framing looks ok - process each packet (header) */
14095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
14100b45bf74f91e781b74bfadb8bb08ef341b6befd3Arend van Spriel		skb_queue_walk_safe(&bus->glom, pfirst, pnext) {
14115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			dptr = (u8 *) (pfirst->data);
14125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			sublen = get_unaligned_le16(dptr);
14135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
14145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
14155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
14165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
14175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(GLOM, "Get subframe %d, %p(%p/%d), sublen %d chan %d seq %d\n",
14185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				  num, pfirst, pfirst->data,
14195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				  pfirst->len, sublen, chan, seq);
14205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
14215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			/* precondition: chan == SDPCM_DATA_CHANNEL ||
14225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					 chan == SDPCM_EVENT_CHANNEL */
14235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
14245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			if (rxseq != seq) {
14255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				brcmf_dbg(GLOM, "rx_seq %d, expected %d\n",
14265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					  seq, rxseq);
14275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				bus->rx_badseq++;
14285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				rxseq = seq;
14295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			}
14300b45bf74f91e781b74bfadb8bb08ef341b6befd3Arend van Spriel			rxseq++;
14310b45bf74f91e781b74bfadb8bb08ef341b6befd3Arend van Spriel
14325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#ifdef BCMDBG
14335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			if (BRCMF_BYTES_ON() && BRCMF_DATA_ON()) {
14345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				printk(KERN_DEBUG "Rx Subframe Data:\n");
14355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
14365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel						     dptr, dlen);
14375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			}
14385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#endif
14395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
14405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			__skb_trim(pfirst, sublen);
14415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			skb_pull(pfirst, doff);
14425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
14435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			if (pfirst->len == 0) {
14440b45bf74f91e781b74bfadb8bb08ef341b6befd3Arend van Spriel				skb_unlink(pfirst, &bus->glom);
14455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				brcmu_pkt_buf_free_skb(pfirst);
14465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				continue;
1447d5625ee66f82162acb7189c1974e688ebc178cf3Franky Lin			} else if (brcmf_proto_hdrpull(bus->sdiodev->dev,
1448d5625ee66f82162acb7189c1974e688ebc178cf3Franky Lin						       &ifidx, pfirst) != 0) {
14495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				brcmf_dbg(ERROR, "rx protocol error\n");
1450719f2733baa1e6a6a782c5109bfe054431db4259Franky Lin				bus->sdiodev->bus_if->dstats.rx_errors++;
14510b45bf74f91e781b74bfadb8bb08ef341b6befd3Arend van Spriel				skb_unlink(pfirst, &bus->glom);
14525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				brcmu_pkt_buf_free_skb(pfirst);
14535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				continue;
14545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			}
14555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
14565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#ifdef BCMDBG
14575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			if (BRCMF_GLOM_ON()) {
14585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				brcmf_dbg(GLOM, "subframe %d to stack, %p (%p/%d) nxt/lnk %p/%p\n",
14590b45bf74f91e781b74bfadb8bb08ef341b6befd3Arend van Spriel					  bus->glom.qlen, pfirst, pfirst->data,
14605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					  pfirst->len, pfirst->next,
14615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					  pfirst->prev);
14625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
14635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel						pfirst->data,
14645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel						min_t(int, pfirst->len, 32));
14655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			}
14665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#endif				/* BCMDBG */
14675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
14680b45bf74f91e781b74bfadb8bb08ef341b6befd3Arend van Spriel		/* sent any remaining packets up */
14690b45bf74f91e781b74bfadb8bb08ef341b6befd3Arend van Spriel		if (bus->glom.qlen) {
14705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			up(&bus->sdsem);
1471228bb43d5d82549c43eee29e12d7632d4df4e4dfFranky Lin			brcmf_rx_frame(bus->sdiodev->dev, ifidx, &bus->glom);
14725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			down(&bus->sdsem);
14735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
14745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
14755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->rxglomframes++;
14760b45bf74f91e781b74bfadb8bb08ef341b6befd3Arend van Spriel		bus->rxglompkts += bus->glom.qlen;
14775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
14785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	return num;
14795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
14805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
1481e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic int brcmf_sdbrcm_dcmd_resp_wait(struct brcmf_sdio *bus, uint *condition,
14825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					bool *pending)
14835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
14845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	DECLARE_WAITQUEUE(wait, current);
14855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	int timeout = msecs_to_jiffies(DCMD_RESP_TIMEOUT);
14865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
14875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Wait until control frame is available */
14885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	add_wait_queue(&bus->dcmd_resp_wait, &wait);
14895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	set_current_state(TASK_INTERRUPTIBLE);
14905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
14915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	while (!(*condition) && (!signal_pending(current) && timeout))
14925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		timeout = schedule_timeout(timeout);
14935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
14945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (signal_pending(current))
14955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		*pending = true;
14965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
14975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	set_current_state(TASK_RUNNING);
14985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	remove_wait_queue(&bus->dcmd_resp_wait, &wait);
14995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
15005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	return timeout;
15015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
15025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
1503e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic int brcmf_sdbrcm_dcmd_resp_wake(struct brcmf_sdio *bus)
15045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
15055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (waitqueue_active(&bus->dcmd_resp_wait))
15065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		wake_up_interruptible(&bus->dcmd_resp_wait);
15075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
15085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	return 0;
15095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
15105b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic void
1511e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linbrcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff)
15125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
15135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint rdlen, pad;
15145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
15155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	int sdret;
15165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
15175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_dbg(TRACE, "Enter\n");
15185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
15195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Set rxctl for frame (w/optional alignment) */
15205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->rxctl = bus->rxbuf;
15215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->rxctl += BRCMF_FIRSTREAD;
15225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	pad = ((unsigned long)bus->rxctl % BRCMF_SDALIGN);
15235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (pad)
15245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->rxctl += (BRCMF_SDALIGN - pad);
15255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->rxctl -= BRCMF_FIRSTREAD;
15265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
15275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Copy the already-read portion over */
15285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	memcpy(bus->rxctl, hdr, BRCMF_FIRSTREAD);
15295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (len <= BRCMF_FIRSTREAD)
15305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		goto gotpkt;
15315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
15325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Raise rdlen to next SDIO block to avoid tail command */
15335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	rdlen = len - BRCMF_FIRSTREAD;
15345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
15355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		pad = bus->blocksize - (rdlen % bus->blocksize);
15365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
1537b01a6b3ca714e2bb86ee387aee487c7360363c93Franky Lin		    ((len + pad) < bus->sdiodev->bus_if->maxctl))
15385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			rdlen += pad;
15395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	} else if (rdlen % BRCMF_SDALIGN) {
15405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		rdlen += BRCMF_SDALIGN - (rdlen % BRCMF_SDALIGN);
15415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
15425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
15435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Satisfy length-alignment requirements */
15445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (rdlen & (ALIGNMENT - 1))
15455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		rdlen = roundup(rdlen, ALIGNMENT);
15465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
15475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Drop if the read is too big or it exceeds our maximum */
1548b01a6b3ca714e2bb86ee387aee487c7360363c93Franky Lin	if ((rdlen + BRCMF_FIRSTREAD) > bus->sdiodev->bus_if->maxctl) {
15495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(ERROR, "%d-byte control read exceeds %d-byte buffer\n",
1550b01a6b3ca714e2bb86ee387aee487c7360363c93Franky Lin			  rdlen, bus->sdiodev->bus_if->maxctl);
1551719f2733baa1e6a6a782c5109bfe054431db4259Franky Lin		bus->sdiodev->bus_if->dstats.rx_errors++;
15525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_sdbrcm_rxfail(bus, false, false);
15535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		goto done;
15545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
15555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
1556b01a6b3ca714e2bb86ee387aee487c7360363c93Franky Lin	if ((len - doff) > bus->sdiodev->bus_if->maxctl) {
15575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(ERROR, "%d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n",
1558b01a6b3ca714e2bb86ee387aee487c7360363c93Franky Lin			  len, len - doff, bus->sdiodev->bus_if->maxctl);
1559719f2733baa1e6a6a782c5109bfe054431db4259Franky Lin		bus->sdiodev->bus_if->dstats.rx_errors++;
15605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->rx_toolong++;
15615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_sdbrcm_rxfail(bus, false, false);
15625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		goto done;
15635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
15645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
15655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Read remainder of frame body into the rxctl buffer */
15665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	sdret = brcmf_sdcard_recv_buf(bus->sdiodev,
15675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				bus->sdiodev->sbwad,
15685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				SDIO_FUNC_2,
15695adfeb632c52a6c15e98fa6465bdade6fff915d9Arend van Spriel				F2SYNC, (bus->rxctl + BRCMF_FIRSTREAD), rdlen);
15705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->f2rxdata++;
15715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
15725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Control frame failures need retransmission */
15735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (sdret < 0) {
15745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(ERROR, "read %d control bytes failed: %d\n",
15755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			  rdlen, sdret);
15765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->rxc_errors++;
15775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_sdbrcm_rxfail(bus, true, true);
15785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		goto done;
15795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
15805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
15815b435de0d786869c95d1962121af0d7df2542009Arend van Sprielgotpkt:
15825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
15835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#ifdef BCMDBG
15845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (BRCMF_BYTES_ON() && BRCMF_CTL_ON()) {
15855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		printk(KERN_DEBUG "RxCtrl:\n");
15865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, bus->rxctl, len);
15875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
15885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#endif
15895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
15905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Point to valid data and indicate its length */
15915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->rxctl += doff;
15925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->rxlen = len - doff;
15935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
15945b435de0d786869c95d1962121af0d7df2542009Arend van Sprieldone:
15955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Awake any waiters */
15965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_sdbrcm_dcmd_resp_wake(bus);
15975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
15985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
15995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* Pad read to blocksize for efficiency */
1600e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic void brcmf_pad(struct brcmf_sdio *bus, u16 *pad, u16 *rdlen)
16015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
16025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (bus->roundup && bus->blocksize && *rdlen > bus->blocksize) {
16035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		*pad = bus->blocksize - (*rdlen % bus->blocksize);
16045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (*pad <= bus->roundup && *pad < bus->blocksize &&
16055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		    *rdlen + *pad + BRCMF_FIRSTREAD < MAX_RX_DATASZ)
16065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			*rdlen += *pad;
16075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	} else if (*rdlen % BRCMF_SDALIGN) {
16085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		*rdlen += BRCMF_SDALIGN - (*rdlen % BRCMF_SDALIGN);
16095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
16105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
16115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
16125b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic void
1613e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linbrcmf_alloc_pkt_and_read(struct brcmf_sdio *bus, u16 rdlen,
16145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			 struct sk_buff **pkt, u8 **rxbuf)
16155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
16165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	int sdret;		/* Return code from calls */
16175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
16185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	*pkt = brcmu_pkt_buf_get_skb(rdlen + BRCMF_SDALIGN);
16195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (*pkt == NULL)
16205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		return;
16215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
16225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	pkt_align(*pkt, rdlen, BRCMF_SDALIGN);
16235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	*rxbuf = (u8 *) ((*pkt)->data);
16245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Read the entire frame */
16255adfeb632c52a6c15e98fa6465bdade6fff915d9Arend van Spriel	sdret = brcmf_sdcard_recv_pkt(bus->sdiodev, bus->sdiodev->sbwad,
16265adfeb632c52a6c15e98fa6465bdade6fff915d9Arend van Spriel				      SDIO_FUNC_2, F2SYNC, *pkt);
16275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->f2rxdata++;
16285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
16295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (sdret < 0) {
16305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(ERROR, "(nextlen): read %d bytes failed: %d\n",
16315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			  rdlen, sdret);
16325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmu_pkt_buf_free_skb(*pkt);
1633719f2733baa1e6a6a782c5109bfe054431db4259Franky Lin		bus->sdiodev->bus_if->dstats.rx_errors++;
16345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Force retry w/normal header read.
16355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		 * Don't attempt NAK for
16365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		 * gSPI
16375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		 */
16385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_sdbrcm_rxfail(bus, true, true);
16395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		*pkt = NULL;
16405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
16415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
16425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
16435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* Checks the header */
16445b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic int
1645e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linbrcmf_check_rxbuf(struct brcmf_sdio *bus, struct sk_buff *pkt, u8 *rxbuf,
16465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		  u8 rxseq, u16 nextlen, u16 *len)
16475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
16485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u16 check;
16495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bool len_consistent;	/* Result of comparing readahead len and
16505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				   len from hw-hdr */
16515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
16525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	memcpy(bus->rxhdr, rxbuf, SDPCM_HDRLEN);
16535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
16545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Extract hardware header fields */
16555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	*len = get_unaligned_le16(bus->rxhdr);
16565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	check = get_unaligned_le16(bus->rxhdr + sizeof(u16));
16575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
16585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* All zeros means readahead info was bad */
16595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (!(*len | check)) {
16605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(INFO, "(nextlen): read zeros in HW header???\n");
16615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		goto fail;
16625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
16635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
16645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Validate check bytes */
16655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if ((u16)~(*len ^ check)) {
16665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(ERROR, "(nextlen): HW hdr error: nextlen/len/check 0x%04x/0x%04x/0x%04x\n",
16675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			  nextlen, *len, check);
16685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->rx_badhdr++;
16695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_sdbrcm_rxfail(bus, false, false);
16705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		goto fail;
16715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
16725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
16735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Validate frame length */
16745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (*len < SDPCM_HDRLEN) {
16755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(ERROR, "(nextlen): HW hdr length invalid: %d\n",
16765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			  *len);
16775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		goto fail;
16785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
16795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
16805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Check for consistency with readahead info */
16815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	len_consistent = (nextlen != (roundup(*len, 16) >> 4));
16825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (len_consistent) {
16835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Mismatch, force retry w/normal
16845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			header (may be >4K) */
16855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(ERROR, "(nextlen): mismatch, nextlen %d len %d rnd %d; expected rxseq %d\n",
16865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			  nextlen, *len, roundup(*len, 16),
16875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			  rxseq);
16885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_sdbrcm_rxfail(bus, true, true);
16895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		goto fail;
16905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
16915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
16925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	return 0;
16935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
16945b435de0d786869c95d1962121af0d7df2542009Arend van Sprielfail:
16955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_sdbrcm_pktfree2(bus, pkt);
16965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	return -EINVAL;
16975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
16985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
16995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* Return true if there may be more frames to read */
17005b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic uint
1701e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linbrcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished)
17025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
17035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u16 len, check;	/* Extracted hardware header fields */
17045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u8 chan, seq, doff;	/* Extracted software header fields */
17055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u8 fcbits;		/* Extracted fcbits from software header */
17065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
17075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	struct sk_buff *pkt;		/* Packet for event or data frames */
17085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u16 pad;		/* Number of pad bytes to read */
17095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u16 rdlen;		/* Total number of bytes to read */
17105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u8 rxseq;		/* Next sequence number to expect */
17115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint rxleft = 0;	/* Remaining number of frames allowed */
17125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	int sdret;		/* Return code from calls */
17135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u8 txmax;		/* Maximum tx sequence offered */
17145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u8 *rxbuf;
17155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	int ifidx = 0;
17165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint rxcount = 0;	/* Total frames read */
17175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
17185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_dbg(TRACE, "Enter\n");
17195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
17205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Not finished unless we encounter no more frames indication */
17215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	*finished = false;
17225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
17235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	for (rxseq = bus->rx_seq, rxleft = maxframes;
17248d169aa00d0356f915e84dbdf6c9be381cce34a4Franky Lin	     !bus->rxskip && rxleft &&
1725712ac5b37a3348cac4e040c551a6ca6186d33682Franky Lin	     bus->sdiodev->bus_if->state != BRCMF_BUS_DOWN;
17265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	     rxseq++, rxleft--) {
17275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
17285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Handle glomming separately */
1729b83db862ffb871e3131e5d2160c741b288eea9aaArend van Spriel		if (bus->glomd || !skb_queue_empty(&bus->glom)) {
17305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			u8 cnt;
17315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(GLOM, "calling rxglom: glomd %p, glom %p\n",
1732b83db862ffb871e3131e5d2160c741b288eea9aaArend van Spriel				  bus->glomd, skb_peek(&bus->glom));
17335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			cnt = brcmf_sdbrcm_rxglom(bus, rxseq);
17345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(GLOM, "rxglom returned %d\n", cnt);
17355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			rxseq += cnt - 1;
17365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			rxleft = (rxleft > cnt) ? (rxleft - cnt) : 1;
17375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			continue;
17385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
17395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
17405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Try doing single read if we can */
17415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (bus->nextlen) {
17425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			u16 nextlen = bus->nextlen;
17435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			bus->nextlen = 0;
17445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
17455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			rdlen = len = nextlen << 4;
17465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_pad(bus, &pad, &rdlen);
17475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
17485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			/*
17495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			 * After the frame is received we have to
17505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			 * distinguish whether it is data
17515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			 * or non-data frame.
17525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			 */
17535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_alloc_pkt_and_read(bus, rdlen, &pkt, &rxbuf);
17545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			if (pkt == NULL) {
17555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				/* Give up on data, request rtx of events */
17565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				brcmf_dbg(ERROR, "(nextlen): brcmf_alloc_pkt_and_read failed: len %d rdlen %d expected rxseq %d\n",
17575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					  len, rdlen, rxseq);
17585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				continue;
17595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			}
17605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
17615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			if (brcmf_check_rxbuf(bus, pkt, rxbuf, rxseq, nextlen,
17625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					      &len) < 0)
17635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				continue;
17645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
17655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			/* Extract software header fields */
17665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			chan = SDPCM_PACKET_CHANNEL(
17675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
17685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			seq = SDPCM_PACKET_SEQUENCE(
17695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
17705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			doff = SDPCM_DOFFSET_VALUE(
17715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
17725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			txmax = SDPCM_WINDOW_VALUE(
17735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
17745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
17755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			bus->nextlen =
17765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			    bus->rxhdr[SDPCM_FRAMETAG_LEN +
17775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				       SDPCM_NEXTLEN_OFFSET];
17785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
17795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				brcmf_dbg(INFO, "(nextlen): got frame w/nextlen too large (%d), seq %d\n",
17805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					  bus->nextlen, seq);
17815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				bus->nextlen = 0;
17825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			}
17835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
178428a1a3bdaf4cce5ee8e473c332e2f371888341bbFranky Lin			bus->rx_readahead_cnt++;
17855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
17865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			/* Handle Flow Control */
17875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			fcbits = SDPCM_FCMASK_VALUE(
17885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
17895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
17905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			if (bus->flowcontrol != fcbits) {
17915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				if (~bus->flowcontrol & fcbits)
17925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					bus->fc_xoff++;
17935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
17945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				if (bus->flowcontrol & ~fcbits)
17955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					bus->fc_xon++;
17965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
17975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				bus->fc_rcvd++;
17985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				bus->flowcontrol = fcbits;
17995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			}
18005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
18015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			/* Check and update sequence number */
18025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			if (rxseq != seq) {
18035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				brcmf_dbg(INFO, "(nextlen): rx_seq %d, expected %d\n",
18045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					  seq, rxseq);
18055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				bus->rx_badseq++;
18065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				rxseq = seq;
18075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			}
18085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
18095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			/* Check window for sanity */
18105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			if ((u8) (txmax - bus->tx_seq) > 0x40) {
18115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				brcmf_dbg(ERROR, "got unlikely tx max %d with tx_seq %d\n",
18125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					  txmax, bus->tx_seq);
18135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				txmax = bus->tx_seq + 2;
18145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			}
18155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			bus->tx_max = txmax;
18165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
18175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#ifdef BCMDBG
18185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			if (BRCMF_BYTES_ON() && BRCMF_DATA_ON()) {
18195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				printk(KERN_DEBUG "Rx Data:\n");
18205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
18215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel						     rxbuf, len);
18225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			} else if (BRCMF_HDRS_ON()) {
18235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				printk(KERN_DEBUG "RxHdr:\n");
18245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
18255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel						     bus->rxhdr, SDPCM_HDRLEN);
18265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			}
18275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#endif
18285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
18295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			if (chan == SDPCM_CONTROL_CHANNEL) {
18305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				brcmf_dbg(ERROR, "(nextlen): readahead on control packet %d?\n",
18315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					  seq);
18325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				/* Force retry w/normal header read */
18335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				bus->nextlen = 0;
18345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				brcmf_sdbrcm_rxfail(bus, false, true);
18355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				brcmf_sdbrcm_pktfree2(bus, pkt);
18365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				continue;
18375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			}
18385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
18395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			/* Validate data offset */
18405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			if ((doff < SDPCM_HDRLEN) || (doff > len)) {
18415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				brcmf_dbg(ERROR, "(nextlen): bad data offset %d: HW len %d min %d\n",
18425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					  doff, len, SDPCM_HDRLEN);
18435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				brcmf_sdbrcm_rxfail(bus, false, false);
18445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				brcmf_sdbrcm_pktfree2(bus, pkt);
18455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				continue;
18465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			}
18475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
18485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			/* All done with this one -- now deliver the packet */
18495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			goto deliver;
18505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
18515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
18525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Read frame header (hardware and software) */
18535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		sdret = brcmf_sdcard_recv_buf(bus->sdiodev, bus->sdiodev->sbwad,
18545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					      SDIO_FUNC_2, F2SYNC, bus->rxhdr,
18555adfeb632c52a6c15e98fa6465bdade6fff915d9Arend van Spriel					      BRCMF_FIRSTREAD);
18565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->f2rxhdrs++;
18575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
18585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (sdret < 0) {
18595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(ERROR, "RXHEADER FAILED: %d\n", sdret);
18605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			bus->rx_hdrfail++;
18615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_sdbrcm_rxfail(bus, true, true);
18625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			continue;
18635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
18645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#ifdef BCMDBG
18655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (BRCMF_BYTES_ON() || BRCMF_HDRS_ON()) {
18665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			printk(KERN_DEBUG "RxHdr:\n");
18675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
18685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					     bus->rxhdr, SDPCM_HDRLEN);
18695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
18705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#endif
18715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
18725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Extract hardware header fields */
18735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		len = get_unaligned_le16(bus->rxhdr);
18745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		check = get_unaligned_le16(bus->rxhdr + sizeof(u16));
18755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
18765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* All zeros means no more frames */
18775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (!(len | check)) {
18785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			*finished = true;
18795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			break;
18805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
18815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
18825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Validate check bytes */
18835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if ((u16) ~(len ^ check)) {
18845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(ERROR, "HW hdr err: len/check 0x%04x/0x%04x\n",
18855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				  len, check);
18865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			bus->rx_badhdr++;
18875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_sdbrcm_rxfail(bus, false, false);
18885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			continue;
18895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
18905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
18915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Validate frame length */
18925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (len < SDPCM_HDRLEN) {
18935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(ERROR, "HW hdr length invalid: %d\n", len);
18945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			continue;
18955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
18965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
18975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Extract software header fields */
18985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
18995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
19005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
19015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
19025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
19035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Validate data offset */
19045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if ((doff < SDPCM_HDRLEN) || (doff > len)) {
19055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(ERROR, "Bad data offset %d: HW len %d, min %d seq %d\n",
19065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				  doff, len, SDPCM_HDRLEN, seq);
19075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			bus->rx_badhdr++;
19085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_sdbrcm_rxfail(bus, false, false);
19095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			continue;
19105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
19115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
19125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Save the readahead length if there is one */
19135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->nextlen =
19145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		    bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
19155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
19165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(INFO, "(nextlen): got frame w/nextlen too large (%d), seq %d\n",
19175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				  bus->nextlen, seq);
19185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			bus->nextlen = 0;
19195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
19205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
19215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Handle Flow Control */
19225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
19235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
19245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (bus->flowcontrol != fcbits) {
19255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			if (~bus->flowcontrol & fcbits)
19265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				bus->fc_xoff++;
19275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
19285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			if (bus->flowcontrol & ~fcbits)
19295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				bus->fc_xon++;
19305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
19315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			bus->fc_rcvd++;
19325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			bus->flowcontrol = fcbits;
19335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
19345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
19355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Check and update sequence number */
19365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (rxseq != seq) {
19375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(INFO, "rx_seq %d, expected %d\n", seq, rxseq);
19385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			bus->rx_badseq++;
19395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			rxseq = seq;
19405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
19415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
19425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Check window for sanity */
19435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if ((u8) (txmax - bus->tx_seq) > 0x40) {
19445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(ERROR, "unlikely tx max %d with tx_seq %d\n",
19455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				  txmax, bus->tx_seq);
19465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			txmax = bus->tx_seq + 2;
19475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
19485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->tx_max = txmax;
19495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
19505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Call a separate function for control frames */
19515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (chan == SDPCM_CONTROL_CHANNEL) {
19525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_sdbrcm_read_control(bus, bus->rxhdr, len, doff);
19535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			continue;
19545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
19555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
19565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* precondition: chan is either SDPCM_DATA_CHANNEL,
19575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		   SDPCM_EVENT_CHANNEL, SDPCM_TEST_CHANNEL or
19585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		   SDPCM_GLOM_CHANNEL */
19595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
19605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Length to read */
19615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		rdlen = (len > BRCMF_FIRSTREAD) ? (len - BRCMF_FIRSTREAD) : 0;
19625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
19635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* May pad read to blocksize for efficiency */
19645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (bus->roundup && bus->blocksize &&
19655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			(rdlen > bus->blocksize)) {
19665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			pad = bus->blocksize - (rdlen % bus->blocksize);
19675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
19685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			    ((rdlen + pad + BRCMF_FIRSTREAD) < MAX_RX_DATASZ))
19695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				rdlen += pad;
19705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		} else if (rdlen % BRCMF_SDALIGN) {
19715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			rdlen += BRCMF_SDALIGN - (rdlen % BRCMF_SDALIGN);
19725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
19735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
19745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Satisfy length-alignment requirements */
19755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (rdlen & (ALIGNMENT - 1))
19765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			rdlen = roundup(rdlen, ALIGNMENT);
19775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
19785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if ((rdlen + BRCMF_FIRSTREAD) > MAX_RX_DATASZ) {
19795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			/* Too long -- skip this frame */
19805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(ERROR, "too long: len %d rdlen %d\n",
19815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				  len, rdlen);
1982719f2733baa1e6a6a782c5109bfe054431db4259Franky Lin			bus->sdiodev->bus_if->dstats.rx_errors++;
19835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			bus->rx_toolong++;
19845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_sdbrcm_rxfail(bus, false, false);
19855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			continue;
19865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
19875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
19885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		pkt = brcmu_pkt_buf_get_skb(rdlen +
19895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					    BRCMF_FIRSTREAD + BRCMF_SDALIGN);
19905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (!pkt) {
19915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			/* Give up on data, request rtx of events */
19925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: rdlen %d chan %d\n",
19935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				  rdlen, chan);
1994719f2733baa1e6a6a782c5109bfe054431db4259Franky Lin			bus->sdiodev->bus_if->dstats.rx_dropped++;
19955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_sdbrcm_rxfail(bus, false, RETRYCHAN(chan));
19965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			continue;
19975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
19985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
19995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Leave room for what we already read, and align remainder */
20005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		skb_pull(pkt, BRCMF_FIRSTREAD);
20015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		pkt_align(pkt, rdlen, BRCMF_SDALIGN);
20025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
20035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Read the remaining frame data */
20045adfeb632c52a6c15e98fa6465bdade6fff915d9Arend van Spriel		sdret = brcmf_sdcard_recv_pkt(bus->sdiodev, bus->sdiodev->sbwad,
20055adfeb632c52a6c15e98fa6465bdade6fff915d9Arend van Spriel					      SDIO_FUNC_2, F2SYNC, pkt);
20065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->f2rxdata++;
20075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
20085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (sdret < 0) {
20095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(ERROR, "read %d %s bytes failed: %d\n", rdlen,
20105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				  ((chan == SDPCM_EVENT_CHANNEL) ? "event"
20115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				   : ((chan == SDPCM_DATA_CHANNEL) ? "data"
20125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				      : "test")), sdret);
20135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmu_pkt_buf_free_skb(pkt);
2014719f2733baa1e6a6a782c5109bfe054431db4259Franky Lin			bus->sdiodev->bus_if->dstats.rx_errors++;
20155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_sdbrcm_rxfail(bus, true, RETRYCHAN(chan));
20165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			continue;
20175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
20185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
20195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Copy the already-read portion */
20205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		skb_push(pkt, BRCMF_FIRSTREAD);
20215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		memcpy(pkt->data, bus->rxhdr, BRCMF_FIRSTREAD);
20225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
20235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#ifdef BCMDBG
20245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (BRCMF_BYTES_ON() && BRCMF_DATA_ON()) {
20255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			printk(KERN_DEBUG "Rx Data:\n");
20265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
20275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					     pkt->data, len);
20285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
20295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#endif
20305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
20315b435de0d786869c95d1962121af0d7df2542009Arend van Sprieldeliver:
20325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Save superframe descriptor and allocate packet frame */
20335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (chan == SDPCM_GLOM_CHANNEL) {
20345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			if (SDPCM_GLOMDESC(&bus->rxhdr[SDPCM_FRAMETAG_LEN])) {
20355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				brcmf_dbg(GLOM, "glom descriptor, %d bytes:\n",
20365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					  len);
20375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#ifdef BCMDBG
20385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				if (BRCMF_GLOM_ON()) {
20395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					printk(KERN_DEBUG "Glom Data:\n");
20405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					print_hex_dump_bytes("",
20415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel							     DUMP_PREFIX_OFFSET,
20425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel							     pkt->data, len);
20435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				}
20445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#endif
20455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				__skb_trim(pkt, len);
20465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				skb_pull(pkt, SDPCM_HDRLEN);
20475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				bus->glomd = pkt;
20485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			} else {
20495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				brcmf_dbg(ERROR, "%s: glom superframe w/o "
20505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					  "descriptor!\n", __func__);
20515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				brcmf_sdbrcm_rxfail(bus, false, false);
20525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			}
20535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			continue;
20545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
20555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
20565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Fill in packet len and prio, deliver upward */
20575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		__skb_trim(pkt, len);
20585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		skb_pull(pkt, doff);
20595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
20605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (pkt->len == 0) {
20615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmu_pkt_buf_free_skb(pkt);
20625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			continue;
2063d5625ee66f82162acb7189c1974e688ebc178cf3Franky Lin		} else if (brcmf_proto_hdrpull(bus->sdiodev->dev, &ifidx,
2064d5625ee66f82162acb7189c1974e688ebc178cf3Franky Lin			   pkt) != 0) {
20655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(ERROR, "rx protocol error\n");
20665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmu_pkt_buf_free_skb(pkt);
2067719f2733baa1e6a6a782c5109bfe054431db4259Franky Lin			bus->sdiodev->bus_if->dstats.rx_errors++;
20685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			continue;
20695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
20705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
20715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Unlock during rx call */
20725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		up(&bus->sdsem);
2073228bb43d5d82549c43eee29e12d7632d4df4e4dfFranky Lin		brcmf_rx_packet(bus->sdiodev->dev, ifidx, pkt);
20745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		down(&bus->sdsem);
20755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
20765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	rxcount = maxframes - rxleft;
20775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#ifdef BCMDBG
20785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Message if we hit the limit */
20795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (!rxleft)
20805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(DATA, "hit rx limit of %d frames\n",
20815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			  maxframes);
20825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	else
20835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#endif				/* BCMDBG */
20845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(DATA, "processed %d frames\n", rxcount);
20855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Back off rxseq if awaiting rtx, update rx_seq */
20865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (bus->rxskip)
20875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		rxseq--;
20885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->rx_seq = rxseq;
20895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
20905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	return rxcount;
20915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
20925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
20935b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic void
2094e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linbrcmf_sdbrcm_wait_for_event(struct brcmf_sdio *bus, bool *lockvar)
20955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
20965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	up(&bus->sdsem);
20975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	wait_event_interruptible_timeout(bus->ctrl_wait,
20985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					 (*lockvar == false), HZ * 2);
20995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	down(&bus->sdsem);
21005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	return;
21015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
21025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
21035b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic void
2104e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linbrcmf_sdbrcm_wait_event_wakeup(struct brcmf_sdio *bus)
21055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
21065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (waitqueue_active(&bus->ctrl_wait))
21075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		wake_up_interruptible(&bus->ctrl_wait);
21085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	return;
21095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
21105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
21115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* Writes a HW/SW header into the packet and sends it. */
21125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* Assumes: (a) header space already there, (b) caller holds lock */
2113e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt,
21145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			      uint chan, bool free_pkt)
21155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
21165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	int ret;
21175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u8 *frame;
21185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u16 len, pad = 0;
21195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 swheader;
21205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	struct sk_buff *new;
21215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	int i;
21225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
21235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_dbg(TRACE, "Enter\n");
21245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
21255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	frame = (u8 *) (pkt->data);
21265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
21275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Add alignment padding, allocate new packet if needed */
21285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	pad = ((unsigned long)frame % BRCMF_SDALIGN);
21295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (pad) {
21305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (skb_headroom(pkt) < pad) {
21315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(INFO, "insufficient headroom %d for %d pad\n",
21325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				  skb_headroom(pkt), pad);
21339c1a043ae688151444578f15208233143526bb88Franky Lin			bus->sdiodev->bus_if->tx_realloc++;
21345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			new = brcmu_pkt_buf_get_skb(pkt->len + BRCMF_SDALIGN);
21355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			if (!new) {
21365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				brcmf_dbg(ERROR, "couldn't allocate new %d-byte packet\n",
21375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					  pkt->len + BRCMF_SDALIGN);
21385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				ret = -ENOMEM;
21395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				goto done;
21405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			}
21415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
21425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			pkt_align(new, pkt->len, BRCMF_SDALIGN);
21435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			memcpy(new->data, pkt->data, pkt->len);
21445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			if (free_pkt)
21455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				brcmu_pkt_buf_free_skb(pkt);
21465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			/* free the pkt if canned one is not used */
21475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			free_pkt = true;
21485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			pkt = new;
21495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			frame = (u8 *) (pkt->data);
21505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			/* precondition: (frame % BRCMF_SDALIGN) == 0) */
21515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			pad = 0;
21525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		} else {
21535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			skb_push(pkt, pad);
21545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			frame = (u8 *) (pkt->data);
21555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			/* precondition: pad + SDPCM_HDRLEN <= pkt->len */
21565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			memset(frame, 0, pad + SDPCM_HDRLEN);
21575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
21585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
21595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* precondition: pad < BRCMF_SDALIGN */
21605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
21615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
21625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	len = (u16) (pkt->len);
21635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	*(__le16 *) frame = cpu_to_le16(len);
21645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	*(((__le16 *) frame) + 1) = cpu_to_le16(~len);
21655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
21665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Software tag: channel, sequence number, data offset */
21675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	swheader =
21685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	    ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) | bus->tx_seq |
21695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	    (((pad +
21705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	       SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
21715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
21725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	put_unaligned_le32(swheader, frame + SDPCM_FRAMETAG_LEN);
21735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	put_unaligned_le32(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
21745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
21755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#ifdef BCMDBG
21765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	tx_packets[pkt->priority]++;
21775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (BRCMF_BYTES_ON() &&
21785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	    (((BRCMF_CTL_ON() && (chan == SDPCM_CONTROL_CHANNEL)) ||
21795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	      (BRCMF_DATA_ON() && (chan != SDPCM_CONTROL_CHANNEL))))) {
21805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		printk(KERN_DEBUG "Tx Frame:\n");
21815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, frame, len);
21825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	} else if (BRCMF_HDRS_ON()) {
21835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		printk(KERN_DEBUG "TxHdr:\n");
21845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
21855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				     frame, min_t(u16, len, 16));
21865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
21875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#endif
21885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
21895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Raise len to next SDIO block to eliminate tail command */
21905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
21915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		u16 pad = bus->blocksize - (len % bus->blocksize);
21925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if ((pad <= bus->roundup) && (pad < bus->blocksize))
21935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				len += pad;
21945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	} else if (len % BRCMF_SDALIGN) {
21955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		len += BRCMF_SDALIGN - (len % BRCMF_SDALIGN);
21965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
21975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
21985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Some controllers have trouble with odd bytes -- round to even */
21995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (len & (ALIGNMENT - 1))
22005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			len = roundup(len, ALIGNMENT);
22015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
22025adfeb632c52a6c15e98fa6465bdade6fff915d9Arend van Spriel	ret = brcmf_sdcard_send_pkt(bus->sdiodev, bus->sdiodev->sbwad,
22035adfeb632c52a6c15e98fa6465bdade6fff915d9Arend van Spriel				    SDIO_FUNC_2, F2SYNC, pkt);
22045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->f2txdata++;
22055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
22065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (ret < 0) {
22075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* On failure, abort the command and terminate the frame */
22085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n",
22095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			  ret);
22105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->tx_sderrs++;
22115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
22125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2);
22135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
22145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				 SBSDIO_FUNC1_FRAMECTRL, SFC_WF_TERM,
22155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				 NULL);
22165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->f1regdata++;
22175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
22185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		for (i = 0; i < 3; i++) {
22195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			u8 hi, lo;
22205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			hi = brcmf_sdcard_cfg_read(bus->sdiodev,
22215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					     SDIO_FUNC_1,
22225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					     SBSDIO_FUNC1_WFRAMEBCHI,
22235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					     NULL);
22245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			lo = brcmf_sdcard_cfg_read(bus->sdiodev,
22255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					     SDIO_FUNC_1,
22265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					     SBSDIO_FUNC1_WFRAMEBCLO,
22275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					     NULL);
22285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			bus->f1regdata += 2;
22295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			if ((hi == 0) && (lo == 0))
22305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				break;
22315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
22325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
22335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
22345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (ret == 0)
22355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
22365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
22375b435de0d786869c95d1962121af0d7df2542009Arend van Sprieldone:
22385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* restore pkt buffer pointer before calling tx complete routine */
22395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	skb_pull(pkt, SDPCM_HDRLEN + pad);
22405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	up(&bus->sdsem);
2241c995788f4761f175f811cbeabb2f88ab8565ec1eFranky Lin	brcmf_txcomplete(bus->sdiodev->dev, pkt, ret != 0);
22425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	down(&bus->sdsem);
22435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
22445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (free_pkt)
22455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmu_pkt_buf_free_skb(pkt);
22465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
22475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	return ret;
22485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
22495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
2250e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes)
22515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
22525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	struct sk_buff *pkt;
22535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 intstatus = 0;
22545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint retries = 0;
22555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	int ret = 0, prec_out;
22565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint cnt = 0;
22575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint datalen;
22585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u8 tx_prec_map;
22595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
22605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_dbg(TRACE, "Enter\n");
22615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
22625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	tx_prec_map = ~bus->flowcontrol;
22635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
22645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Send frames until the limit or some other event */
22655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	for (cnt = 0; (cnt < maxframes) && data_ok(bus); cnt++) {
22665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		spin_lock_bh(&bus->txqlock);
22675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		pkt = brcmu_pktq_mdeq(&bus->txq, tx_prec_map, &prec_out);
22685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (pkt == NULL) {
22695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			spin_unlock_bh(&bus->txqlock);
22705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			break;
22715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
22725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		spin_unlock_bh(&bus->txqlock);
22735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		datalen = pkt->len - SDPCM_HDRLEN;
22745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
22755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		ret = brcmf_sdbrcm_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, true);
22765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (ret)
2277719f2733baa1e6a6a782c5109bfe054431db4259Franky Lin			bus->sdiodev->bus_if->dstats.tx_errors++;
22785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		else
2279719f2733baa1e6a6a782c5109bfe054431db4259Franky Lin			bus->sdiodev->bus_if->dstats.tx_bytes += datalen;
22805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
22815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* In poll mode, need to check for other events */
22825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (!bus->intr && cnt) {
22835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			/* Check device status, signal pending interrupt */
22845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			r_sdreg32(bus, &intstatus,
22855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				  offsetof(struct sdpcmd_regs, intstatus),
22865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				  &retries);
22875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			bus->f2txdata++;
22885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			if (brcmf_sdcard_regfail(bus->sdiodev))
22895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				break;
22905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			if (intstatus & bus->hostintmask)
22915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				bus->ipend = true;
22925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
22935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
22945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
22955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Deflow-control stack if needed */
2296712ac5b37a3348cac4e040c551a6ca6186d33682Franky Lin	if (bus->sdiodev->bus_if->drvr_up &&
2297712ac5b37a3348cac4e040c551a6ca6186d33682Franky Lin	    (bus->sdiodev->bus_if->state == BRCMF_BUS_DATA) &&
2298c8bf34849f92c5894a3d7e12573d3789d7851f23Franky Lin	    bus->txoff && (pktq_len(&bus->txq) < TXLOW)) {
2299c8bf34849f92c5894a3d7e12573d3789d7851f23Franky Lin		bus->txoff = OFF;
23002b4590569ead15fb88a83c1d8a07e3ca5507f4c6Franky Lin		brcmf_txflowcontrol(bus->sdiodev->dev, 0, OFF);
2301c8bf34849f92c5894a3d7e12573d3789d7851f23Franky Lin	}
23025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
23035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	return cnt;
23045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
23055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
2306a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Linstatic void brcmf_sdbrcm_bus_stop(struct device *dev)
2307a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin{
2308a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin	u32 local_hostintmask;
2309a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin	u8 saveclk;
2310a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin	uint retries;
2311a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin	int err;
2312a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
2313a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin	struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv;
2314a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin	struct brcmf_sdio *bus = sdiodev->bus;
2315a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin
2316a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin	brcmf_dbg(TRACE, "Enter\n");
2317a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin
2318a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin	if (bus->watchdog_tsk) {
2319a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin		send_sig(SIGTERM, bus->watchdog_tsk, 1);
2320a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin		kthread_stop(bus->watchdog_tsk);
2321a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin		bus->watchdog_tsk = NULL;
2322a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin	}
2323a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin
2324a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin	if (bus->dpc_tsk && bus->dpc_tsk != current) {
2325a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin		send_sig(SIGTERM, bus->dpc_tsk, 1);
2326a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin		kthread_stop(bus->dpc_tsk);
2327a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin		bus->dpc_tsk = NULL;
2328a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin	}
2329a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin
2330a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin	down(&bus->sdsem);
2331a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin
2332a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin	bus_wake(bus);
2333a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin
2334a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin	/* Enable clock for device interrupts */
2335a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin	brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
2336a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin
2337a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin	/* Disable and clear interrupts at the chip level also */
2338a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin	w_sdreg32(bus, 0, offsetof(struct sdpcmd_regs, hostintmask), &retries);
2339a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin	local_hostintmask = bus->hostintmask;
2340a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin	bus->hostintmask = 0;
2341a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin
2342a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin	/* Change our idea of bus state */
2343a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin	bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
2344a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin
2345a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin	/* Force clocks on backplane to be sure F2 interrupt propagates */
2346a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin	saveclk = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
2347a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin					SBSDIO_FUNC1_CHIPCLKCSR, &err);
2348a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin	if (!err) {
2349a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin		brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
2350a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin				       SBSDIO_FUNC1_CHIPCLKCSR,
2351a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin				       (saveclk | SBSDIO_FORCE_HT), &err);
2352a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin	}
2353a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin	if (err)
2354a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin		brcmf_dbg(ERROR, "Failed to force clock for F2: err %d\n", err);
2355a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin
2356a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin	/* Turn off the bus (F2), free any pending packets */
2357a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin	brcmf_dbg(INTR, "disable SDIO interrupts\n");
2358a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin	brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx,
2359a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin			 SDIO_FUNC_ENABLE_1, NULL);
2360a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin
2361a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin	/* Clear any pending interrupts now that F2 is disabled */
2362a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin	w_sdreg32(bus, local_hostintmask,
2363a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin		  offsetof(struct sdpcmd_regs, intstatus), &retries);
2364a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin
2365a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin	/* Turn off the backplane clock (only) */
2366a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin	brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false);
2367a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin
2368a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin	/* Clear the data packet queues */
2369a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin	brcmu_pktq_flush(&bus->txq, true, NULL, NULL);
2370a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin
2371a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin	/* Clear any held glomming stuff */
2372a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin	if (bus->glomd)
2373a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin		brcmu_pkt_buf_free_skb(bus->glomd);
2374a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin	brcmf_sdbrcm_free_glom(bus);
2375a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin
2376a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin	/* Clear rx control and wake any waiters */
2377a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin	bus->rxlen = 0;
2378a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin	brcmf_sdbrcm_dcmd_resp_wake(bus);
2379a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin
2380a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin	/* Reset some F2 state stuff */
2381a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin	bus->rxskip = false;
2382a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin	bus->tx_seq = bus->rx_seq = 0;
2383a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin
2384a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin	up(&bus->sdsem);
2385a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin}
2386a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin
2387e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
23885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
23895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 intstatus, newstatus = 0;
23905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint retries = 0;
23915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint rxlimit = bus->rxbound;	/* Rx frames to read before resched */
23925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint txlimit = bus->txbound;	/* Tx frames to send before resched */
23935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint framecnt = 0;	/* Temporary counter of tx/rx frames */
23945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bool rxdone = true;	/* Flag for no more read data */
23955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bool resched = false;	/* Flag indicating resched wanted */
23965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
23975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_dbg(TRACE, "Enter\n");
23985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
23995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Start with leftover status bits */
24005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	intstatus = bus->intstatus;
24015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
24025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	down(&bus->sdsem);
24035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
24045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* If waiting for HTAVAIL, check status */
24055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (bus->clkstate == CLK_PENDING) {
24065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		int err;
24075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		u8 clkctl, devctl = 0;
24085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
24095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#ifdef BCMDBG
24105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Check for inconsistent device control */
24115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		devctl = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
24125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					       SBSDIO_DEVICE_CTL, &err);
24135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (err) {
24145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(ERROR, "error reading DEVCTL: %d\n", err);
2415712ac5b37a3348cac4e040c551a6ca6186d33682Franky Lin			bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
24165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
24175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#endif				/* BCMDBG */
24185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
24195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Read CSR, if clock on switch to AVAIL, else ignore */
24205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		clkctl = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
24215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					       SBSDIO_FUNC1_CHIPCLKCSR, &err);
24225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (err) {
24235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(ERROR, "error reading CSR: %d\n",
24245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				  err);
2425712ac5b37a3348cac4e040c551a6ca6186d33682Franky Lin			bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
24265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
24275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
24285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(INFO, "DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n",
24295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			  devctl, clkctl);
24305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
24315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (SBSDIO_HTAV(clkctl)) {
24325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			devctl = brcmf_sdcard_cfg_read(bus->sdiodev,
24335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel						       SDIO_FUNC_1,
24345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel						       SBSDIO_DEVICE_CTL, &err);
24355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			if (err) {
24365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				brcmf_dbg(ERROR, "error reading DEVCTL: %d\n",
24375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					  err);
2438712ac5b37a3348cac4e040c551a6ca6186d33682Franky Lin				bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
24395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			}
24405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
24415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
24425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				SBSDIO_DEVICE_CTL, devctl, &err);
24435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			if (err) {
24445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				brcmf_dbg(ERROR, "error writing DEVCTL: %d\n",
24455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					  err);
2446712ac5b37a3348cac4e040c551a6ca6186d33682Franky Lin				bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
24475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			}
24485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			bus->clkstate = CLK_AVAIL;
24495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		} else {
24505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			goto clkwait;
24515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
24525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
24535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
24545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus_wake(bus);
24555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
24565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Make sure backplane clock is on */
24575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, true);
24585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (bus->clkstate == CLK_PENDING)
24595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		goto clkwait;
24605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
24615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Pending interrupt indicates new device status */
24625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (bus->ipend) {
24635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->ipend = false;
24645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		r_sdreg32(bus, &newstatus,
24655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			  offsetof(struct sdpcmd_regs, intstatus), &retries);
24665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->f1regdata++;
24675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (brcmf_sdcard_regfail(bus->sdiodev))
24685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			newstatus = 0;
24695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		newstatus &= bus->hostintmask;
24705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->fcstate = !!(newstatus & I_HMB_FC_STATE);
24715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (newstatus) {
24725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			w_sdreg32(bus, newstatus,
24735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				  offsetof(struct sdpcmd_regs, intstatus),
24745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				  &retries);
24755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			bus->f1regdata++;
24765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
24775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
24785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
24795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Merge new bits with previous */
24805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	intstatus |= newstatus;
24815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->intstatus = 0;
24825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
24835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Handle flow-control change: read new state in case our ack
24845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	 * crossed another change interrupt.  If change still set, assume
24855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	 * FC ON for safety, let next loop through do the debounce.
24865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	 */
24875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (intstatus & I_HMB_FC_CHANGE) {
24885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		intstatus &= ~I_HMB_FC_CHANGE;
24895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		w_sdreg32(bus, I_HMB_FC_CHANGE,
24905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			  offsetof(struct sdpcmd_regs, intstatus), &retries);
24915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
24925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		r_sdreg32(bus, &newstatus,
24935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			  offsetof(struct sdpcmd_regs, intstatus), &retries);
24945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->f1regdata += 2;
24955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->fcstate =
24965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		    !!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE));
24975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		intstatus |= (newstatus & bus->hostintmask);
24985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
24995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
25005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Handle host mailbox indication */
25015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (intstatus & I_HMB_HOST_INT) {
25025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		intstatus &= ~I_HMB_HOST_INT;
25035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		intstatus |= brcmf_sdbrcm_hostmail(bus);
25045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
25055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
25065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Generally don't ask for these, can get CRC errors... */
25075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (intstatus & I_WR_OOSYNC) {
25085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(ERROR, "Dongle reports WR_OOSYNC\n");
25095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		intstatus &= ~I_WR_OOSYNC;
25105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
25115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
25125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (intstatus & I_RD_OOSYNC) {
25135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(ERROR, "Dongle reports RD_OOSYNC\n");
25145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		intstatus &= ~I_RD_OOSYNC;
25155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
25165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
25175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (intstatus & I_SBINT) {
25185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(ERROR, "Dongle reports SBINT\n");
25195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		intstatus &= ~I_SBINT;
25205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
25215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
25225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Would be active due to wake-wlan in gSPI */
25235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (intstatus & I_CHIPACTIVE) {
25245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(INFO, "Dongle reports CHIPACTIVE\n");
25255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		intstatus &= ~I_CHIPACTIVE;
25265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
25275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
25285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Ignore frame indications if rxskip is set */
25295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (bus->rxskip)
25305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		intstatus &= ~I_HMB_FRAME_IND;
25315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
25325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* On frame indication, read available frames */
25335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (PKT_AVAILABLE()) {
25345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		framecnt = brcmf_sdbrcm_readframes(bus, rxlimit, &rxdone);
25355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (rxdone || bus->rxskip)
25365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			intstatus &= ~I_HMB_FRAME_IND;
25375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		rxlimit -= min(framecnt, rxlimit);
25385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
25395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
25405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Keep still-pending events for next scheduling */
25415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->intstatus = intstatus;
25425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
25435b435de0d786869c95d1962121af0d7df2542009Arend van Sprielclkwait:
25445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (data_ok(bus) && bus->ctrl_frame_stat &&
25455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		(bus->clkstate == CLK_AVAIL)) {
25465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		int ret, i;
25475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
25485adfeb632c52a6c15e98fa6465bdade6fff915d9Arend van Spriel		ret = brcmf_sdcard_send_buf(bus->sdiodev, bus->sdiodev->sbwad,
25495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			SDIO_FUNC_2, F2SYNC, (u8 *) bus->ctrl_frame_buf,
25505adfeb632c52a6c15e98fa6465bdade6fff915d9Arend van Spriel			(u32) bus->ctrl_frame_len);
25515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
25525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (ret < 0) {
25535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			/* On failure, abort the command and
25545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				terminate the frame */
25555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n",
25565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				  ret);
25575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			bus->tx_sderrs++;
25585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
25595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2);
25605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
25615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
25625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					 SBSDIO_FUNC1_FRAMECTRL, SFC_WF_TERM,
25635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					 NULL);
25645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			bus->f1regdata++;
25655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
25665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			for (i = 0; i < 3; i++) {
25675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				u8 hi, lo;
25685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				hi = brcmf_sdcard_cfg_read(bus->sdiodev,
25695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel						     SDIO_FUNC_1,
25705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel						     SBSDIO_FUNC1_WFRAMEBCHI,
25715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel						     NULL);
25725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				lo = brcmf_sdcard_cfg_read(bus->sdiodev,
25735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel						     SDIO_FUNC_1,
25745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel						     SBSDIO_FUNC1_WFRAMEBCLO,
25755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel						     NULL);
25765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				bus->f1regdata += 2;
25775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				if ((hi == 0) && (lo == 0))
25785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					break;
25795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			}
25805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
25815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
25825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (ret == 0)
25835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
25845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
25855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(INFO, "Return_dpc value is : %d\n", ret);
25865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->ctrl_frame_stat = false;
25875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_sdbrcm_wait_event_wakeup(bus);
25885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
25895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Send queued frames (limit 1 if rx may still be pending) */
25905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate &&
25915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		 brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit
25925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		 && data_ok(bus)) {
25935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		framecnt = rxdone ? txlimit : min(txlimit, bus->txminmax);
25945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		framecnt = brcmf_sdbrcm_sendfromq(bus, framecnt);
25955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		txlimit -= framecnt;
25965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
25975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
25985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Resched if events or tx frames are pending,
25995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		 else await next interrupt */
26005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* On failed register access, all bets are off:
26015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		 no resched or interrupts */
2602712ac5b37a3348cac4e040c551a6ca6186d33682Franky Lin	if ((bus->sdiodev->bus_if->state == BRCMF_BUS_DOWN) ||
26035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	    brcmf_sdcard_regfail(bus->sdiodev)) {
26045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(ERROR, "failed backplane access over SDIO, halting operation %d\n",
26055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			  brcmf_sdcard_regfail(bus->sdiodev));
2606712ac5b37a3348cac4e040c551a6ca6186d33682Franky Lin		bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
26075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->intstatus = 0;
26085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	} else if (bus->clkstate == CLK_PENDING) {
26095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(INFO, "rescheduled due to CLK_PENDING awaiting I_CHIPACTIVE interrupt\n");
26105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		resched = true;
26115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	} else if (bus->intstatus || bus->ipend ||
26125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		(!bus->fcstate && brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol)
26135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		 && data_ok(bus)) || PKT_AVAILABLE()) {
26145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		resched = true;
26155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
26165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
26175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->dpc_sched = resched;
26185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
26195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* If we're done for now, turn off clock request. */
26205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if ((bus->clkstate != CLK_PENDING)
26215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	    && bus->idletime == BRCMF_IDLE_IMMEDIATE) {
26225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->activity = false;
26235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
26245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
26255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
26265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	up(&bus->sdsem);
26275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
26285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	return resched;
26295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
26305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
26315b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic int brcmf_sdbrcm_dpc_thread(void *data)
26325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
2633e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Lin	struct brcmf_sdio *bus = (struct brcmf_sdio *) data;
26345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
26355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	allow_signal(SIGTERM);
26365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Run until signal received */
26375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	while (1) {
26385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (kthread_should_stop())
26395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			break;
26405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (!wait_for_completion_interruptible(&bus->dpc_wait)) {
26415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			/* Call bus dpc unless it indicated down
26425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			(then clean stop) */
2643712ac5b37a3348cac4e040c551a6ca6186d33682Franky Lin			if (bus->sdiodev->bus_if->state != BRCMF_BUS_DOWN) {
26445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				if (brcmf_sdbrcm_dpc(bus))
26455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					complete(&bus->dpc_wait);
26465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			} else {
26475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				/* after stopping the bus, exit thread */
264894c2fb82bd7c9055bec8e410c387befce33d1299Franky Lin				brcmf_sdbrcm_bus_stop(bus->sdiodev->dev);
26495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				bus->dpc_tsk = NULL;
26505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				break;
26515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			}
26525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		} else
26535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			break;
26545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
26555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	return 0;
26565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
26575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
2658b9692d17e842fadb8c18faf24f550db80886763eFranky Linstatic int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt)
26595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
26605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	int ret = -EBADE;
26615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint datalen, prec;
2662bf347bb9768ab0da028a0d9f92142df738211debFranky Lin	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
2663bf347bb9768ab0da028a0d9f92142df738211debFranky Lin	struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv;
2664bf347bb9768ab0da028a0d9f92142df738211debFranky Lin	struct brcmf_sdio *bus = sdiodev->bus;
26655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
26665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_dbg(TRACE, "Enter\n");
26675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
26685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	datalen = pkt->len;
26695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
26705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Add space for the header */
26715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	skb_push(pkt, SDPCM_HDRLEN);
26725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* precondition: IS_ALIGNED((unsigned long)(pkt->data), 2) */
26735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
26745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	prec = prio2prec((pkt->priority & PRIOMASK));
26755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
26765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Check for existing queue, current flow-control,
26775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			 pending event, or pending clock */
26785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_dbg(TRACE, "deferring pktq len %d\n", pktq_len(&bus->txq));
26795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->fcqueued++;
26805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
26815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Priority based enq */
26825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	spin_lock_bh(&bus->txqlock);
2683b63487ed3d7d8bc08c966eac0543e8f3f70b7fb4Franky Lin	if (brcmf_c_prec_enq(bus->sdiodev->dev, &bus->txq, pkt, prec) ==
2684b63487ed3d7d8bc08c966eac0543e8f3f70b7fb4Franky Lin	    false) {
26855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		skb_pull(pkt, SDPCM_HDRLEN);
2686c995788f4761f175f811cbeabb2f88ab8565ec1eFranky Lin		brcmf_txcomplete(bus->sdiodev->dev, pkt, false);
26875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmu_pkt_buf_free_skb(pkt);
26885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(ERROR, "out of bus->txq !!!\n");
26895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		ret = -ENOSR;
26905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	} else {
26915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		ret = 0;
26925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
26935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	spin_unlock_bh(&bus->txqlock);
26945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
2695c8bf34849f92c5894a3d7e12573d3789d7851f23Franky Lin	if (pktq_len(&bus->txq) >= TXHI) {
2696c8bf34849f92c5894a3d7e12573d3789d7851f23Franky Lin		bus->txoff = ON;
26972b4590569ead15fb88a83c1d8a07e3ca5507f4c6Franky Lin		brcmf_txflowcontrol(bus->sdiodev->dev, 0, ON);
2698c8bf34849f92c5894a3d7e12573d3789d7851f23Franky Lin	}
26995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
27005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#ifdef BCMDBG
27015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (pktq_plen(&bus->txq, prec) > qcount[prec])
27025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		qcount[prec] = pktq_plen(&bus->txq, prec);
27035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#endif
27045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Schedule DPC if needed to send queued packet(s) */
27055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (!bus->dpc_sched) {
27065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->dpc_sched = true;
27075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (bus->dpc_tsk)
27085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			complete(&bus->dpc_wait);
27095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
27105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
27115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	return ret;
27125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
27135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
27145b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic int
2715e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linbrcmf_sdbrcm_membytes(struct brcmf_sdio *bus, bool write, u32 address, u8 *data,
27165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		 uint size)
27175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
27185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	int bcmerror = 0;
27195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 sdaddr;
27205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint dsize;
27215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
27225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Determine initial transfer parameters */
27235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	sdaddr = address & SBSDIO_SB_OFT_ADDR_MASK;
27245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if ((sdaddr + size) & SBSDIO_SBWINDOW_MASK)
27255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		dsize = (SBSDIO_SB_OFT_ADDR_LIMIT - sdaddr);
27265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	else
27275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		dsize = size;
27285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
27295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Set the backplane window to include the start address */
27305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bcmerror = brcmf_sdcard_set_sbaddr_window(bus->sdiodev, address);
27315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (bcmerror) {
27325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(ERROR, "window change failed\n");
27335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		goto xfer_done;
27345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
27355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
27365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Do the transfer(s) */
27375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	while (size) {
27385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(INFO, "%s %d bytes at offset 0x%08x in window 0x%08x\n",
27395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			  write ? "write" : "read", dsize,
27405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			  sdaddr, address & SBSDIO_SBWINDOW_MASK);
27415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bcmerror = brcmf_sdcard_rwdata(bus->sdiodev, write,
27425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					       sdaddr, data, dsize);
27435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (bcmerror) {
27445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(ERROR, "membytes transfer failed\n");
27455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			break;
27465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
27475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
27485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Adjust for next transfer (if any) */
27495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		size -= dsize;
27505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (size) {
27515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			data += dsize;
27525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			address += dsize;
27535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			bcmerror = brcmf_sdcard_set_sbaddr_window(bus->sdiodev,
27545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel								  address);
27555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			if (bcmerror) {
27565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				brcmf_dbg(ERROR, "window change failed\n");
27575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				break;
27585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			}
27595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			sdaddr = 0;
27605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			dsize = min_t(uint, SBSDIO_SB_OFT_ADDR_LIMIT, size);
27615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
27625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
27635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
27645b435de0d786869c95d1962121af0d7df2542009Arend van Sprielxfer_done:
27655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Return the window to backplane enumeration space for core access */
27665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (brcmf_sdcard_set_sbaddr_window(bus->sdiodev, bus->sdiodev->sbwad))
27675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(ERROR, "FAILED to set window back to 0x%x\n",
27685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			  bus->sdiodev->sbwad);
27695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
27705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	return bcmerror;
27715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
27725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
27735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#ifdef BCMDBG
27745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define CONSOLE_LINE_MAX	192
27755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
2776e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic int brcmf_sdbrcm_readconsole(struct brcmf_sdio *bus)
27775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
27785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	struct brcmf_console *c = &bus->console;
27795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u8 line[CONSOLE_LINE_MAX], ch;
27805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 n, idx, addr;
27815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	int rv;
27825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
27835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Don't do anything until FWREADY updates console address */
27845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (bus->console_addr == 0)
27855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		return 0;
27865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
27875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Read console log struct */
27885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	addr = bus->console_addr + offsetof(struct rte_console, log_le);
27895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	rv = brcmf_sdbrcm_membytes(bus, false, addr, (u8 *)&c->log_le,
27905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				   sizeof(c->log_le));
27915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (rv < 0)
27925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		return rv;
27935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
27945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Allocate console buffer (one time only) */
27955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (c->buf == NULL) {
27965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		c->bufsize = le32_to_cpu(c->log_le.buf_size);
27975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		c->buf = kmalloc(c->bufsize, GFP_ATOMIC);
27985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (c->buf == NULL)
27995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			return -ENOMEM;
28005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
28015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
28025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	idx = le32_to_cpu(c->log_le.idx);
28035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
28045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Protect against corrupt value */
28055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (idx > c->bufsize)
28065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		return -EBADE;
28075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
28085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Skip reading the console buffer if the index pointer
28095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	 has not moved */
28105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (idx == c->last)
28115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		return 0;
28125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
28135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Read the console buffer */
28145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	addr = le32_to_cpu(c->log_le.buf);
28155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	rv = brcmf_sdbrcm_membytes(bus, false, addr, c->buf, c->bufsize);
28165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (rv < 0)
28175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		return rv;
28185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
28195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	while (c->last != idx) {
28205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) {
28215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			if (c->last == idx) {
28225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				/* This would output a partial line.
28235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				 * Instead, back up
28245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				 * the buffer pointer and output this
28255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				 * line next time around.
28265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				 */
28275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				if (c->last >= n)
28285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					c->last -= n;
28295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				else
28305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					c->last = c->bufsize - n;
28315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				goto break2;
28325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			}
28335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			ch = c->buf[c->last];
28345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			c->last = (c->last + 1) % c->bufsize;
28355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			if (ch == '\n')
28365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				break;
28375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			line[n] = ch;
28385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
28395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
28405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (n > 0) {
28415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			if (line[n - 1] == '\r')
28425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				n--;
28435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			line[n] = 0;
28445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			printk(KERN_DEBUG "CONSOLE: %s\n", line);
28455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
28465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
28475b435de0d786869c95d1962121af0d7df2542009Arend van Sprielbreak2:
28485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
28495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	return 0;
28505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
28515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#endif				/* BCMDBG */
28525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
2853e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic int brcmf_tx_frame(struct brcmf_sdio *bus, u8 *frame, u16 len)
28545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
28555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	int i;
28565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	int ret;
28575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
28585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->ctrl_frame_stat = false;
28595adfeb632c52a6c15e98fa6465bdade6fff915d9Arend van Spriel	ret = brcmf_sdcard_send_buf(bus->sdiodev, bus->sdiodev->sbwad,
28605adfeb632c52a6c15e98fa6465bdade6fff915d9Arend van Spriel				    SDIO_FUNC_2, F2SYNC, frame, len);
28615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
28625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (ret < 0) {
28635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* On failure, abort the command and terminate the frame */
28645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n",
28655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			  ret);
28665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->tx_sderrs++;
28675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
28685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2);
28695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
28705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
28715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				       SBSDIO_FUNC1_FRAMECTRL,
28725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				       SFC_WF_TERM, NULL);
28735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->f1regdata++;
28745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
28755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		for (i = 0; i < 3; i++) {
28765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			u8 hi, lo;
28775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			hi = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
28785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel						   SBSDIO_FUNC1_WFRAMEBCHI,
28795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel						   NULL);
28805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			lo = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
28815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel						   SBSDIO_FUNC1_WFRAMEBCLO,
28825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel						   NULL);
28835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			bus->f1regdata += 2;
28845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			if (hi == 0 && lo == 0)
28855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				break;
28865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
28875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		return ret;
28885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
28895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
28905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
28915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
28925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	return ret;
28935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
28945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
2895fcf094f414f9e9c088f6c2aa9e19a59f7b41e1f5Franky Linstatic int
289647a1ce78d544b9fb3b776a62de3c084cf0020fdaFranky Linbrcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
28975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
28985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u8 *frame;
28995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u16 len;
29005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 swheader;
29015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint retries = 0;
29025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u8 doff = 0;
29035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	int ret = -1;
290447a1ce78d544b9fb3b776a62de3c084cf0020fdaFranky Lin	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
290547a1ce78d544b9fb3b776a62de3c084cf0020fdaFranky Lin	struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv;
290647a1ce78d544b9fb3b776a62de3c084cf0020fdaFranky Lin	struct brcmf_sdio *bus = sdiodev->bus;
29075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
29085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_dbg(TRACE, "Enter\n");
29095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
29105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Back the pointer to make a room for bus header */
29115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	frame = msg - SDPCM_HDRLEN;
29125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	len = (msglen += SDPCM_HDRLEN);
29135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
29145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Add alignment padding (optional for ctl frames) */
29155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	doff = ((unsigned long)frame % BRCMF_SDALIGN);
29165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (doff) {
29175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		frame -= doff;
29185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		len += doff;
29195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		msglen += doff;
29205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		memset(frame, 0, doff + SDPCM_HDRLEN);
29215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
29225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* precondition: doff < BRCMF_SDALIGN */
29235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	doff += SDPCM_HDRLEN;
29245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
29255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Round send length to next SDIO block */
29265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
29275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		u16 pad = bus->blocksize - (len % bus->blocksize);
29285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if ((pad <= bus->roundup) && (pad < bus->blocksize))
29295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			len += pad;
29305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	} else if (len % BRCMF_SDALIGN) {
29315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		len += BRCMF_SDALIGN - (len % BRCMF_SDALIGN);
29325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
29335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
29345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Satisfy length-alignment requirements */
29355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (len & (ALIGNMENT - 1))
29365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		len = roundup(len, ALIGNMENT);
29375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
29385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* precondition: IS_ALIGNED((unsigned long)frame, 2) */
29395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
29405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Need to lock here to protect txseq and SDIO tx calls */
29415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	down(&bus->sdsem);
29425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
29435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus_wake(bus);
29445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
29455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Make sure backplane clock is on */
29465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
29475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
29485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
29495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	*(__le16 *) frame = cpu_to_le16((u16) msglen);
29505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	*(((__le16 *) frame) + 1) = cpu_to_le16(~msglen);
29515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
29525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Software tag: channel, sequence number, data offset */
29535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	swheader =
29545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	    ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) &
29555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	     SDPCM_CHANNEL_MASK)
29565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	    | bus->tx_seq | ((doff << SDPCM_DOFFSET_SHIFT) &
29575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			     SDPCM_DOFFSET_MASK);
29585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	put_unaligned_le32(swheader, frame + SDPCM_FRAMETAG_LEN);
29595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	put_unaligned_le32(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
29605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
29615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (!data_ok(bus)) {
29625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(INFO, "No bus credit bus->tx_max %d, bus->tx_seq %d\n",
29635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			  bus->tx_max, bus->tx_seq);
29645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->ctrl_frame_stat = true;
29655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Send from dpc */
29665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->ctrl_frame_buf = frame;
29675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->ctrl_frame_len = len;
29685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
29695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_sdbrcm_wait_for_event(bus, &bus->ctrl_frame_stat);
29705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
29715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (bus->ctrl_frame_stat == false) {
29725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(INFO, "ctrl_frame_stat == false\n");
29735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			ret = 0;
29745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		} else {
29755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(INFO, "ctrl_frame_stat == true\n");
29765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			ret = -1;
29775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
29785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
29795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
29805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (ret == -1) {
29815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#ifdef BCMDBG
29825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (BRCMF_BYTES_ON() && BRCMF_CTL_ON()) {
29835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			printk(KERN_DEBUG "Tx Frame:\n");
29845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
29855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					     frame, len);
29865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		} else if (BRCMF_HDRS_ON()) {
29875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			printk(KERN_DEBUG "TxHdr:\n");
29885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
29895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					     frame, min_t(u16, len, 16));
29905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
29915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#endif
29925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
29935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		do {
29945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			ret = brcmf_tx_frame(bus, frame, len);
29955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		} while (ret < 0 && retries++ < TXRETRIES);
29965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
29975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
29985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if ((bus->idletime == BRCMF_IDLE_IMMEDIATE) && !bus->dpc_sched) {
29995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->activity = false;
30005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_sdbrcm_clkctl(bus, CLK_NONE, true);
30015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
30025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
30035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	up(&bus->sdsem);
30045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
30055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (ret)
300628a1a3bdaf4cce5ee8e473c332e2f371888341bbFranky Lin		bus->tx_ctlerrs++;
30075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	else
300828a1a3bdaf4cce5ee8e473c332e2f371888341bbFranky Lin		bus->tx_ctlpkts++;
30095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
30105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	return ret ? -EIO : 0;
30115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
30125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
3013fcf094f414f9e9c088f6c2aa9e19a59f7b41e1f5Franky Linstatic int
3014532cdd3b99b7a89fdc128c2b58abea780f3bbb4dFranky Linbrcmf_sdbrcm_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen)
30155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
30165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	int timeleft;
30175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint rxlen = 0;
30185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bool pending;
3019532cdd3b99b7a89fdc128c2b58abea780f3bbb4dFranky Lin	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
3020532cdd3b99b7a89fdc128c2b58abea780f3bbb4dFranky Lin	struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv;
3021532cdd3b99b7a89fdc128c2b58abea780f3bbb4dFranky Lin	struct brcmf_sdio *bus = sdiodev->bus;
30225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
30235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_dbg(TRACE, "Enter\n");
30245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
30255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Wait until control frame is available */
30265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	timeleft = brcmf_sdbrcm_dcmd_resp_wait(bus, &bus->rxlen, &pending);
30275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
30285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	down(&bus->sdsem);
30295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	rxlen = bus->rxlen;
30305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	memcpy(msg, bus->rxctl, min(msglen, rxlen));
30315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->rxlen = 0;
30325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	up(&bus->sdsem);
30335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
30345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (rxlen) {
30355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(CTL, "resumed on rxctl frame, got %d expected %d\n",
30365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			  rxlen, msglen);
30375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	} else if (timeleft == 0) {
30385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(ERROR, "resumed on timeout\n");
30395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	} else if (pending == true) {
30405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(CTL, "cancelled\n");
30415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		return -ERESTARTSYS;
30425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	} else {
30435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(CTL, "resumed for unknown reason?\n");
30445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
30455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
30465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (rxlen)
304728a1a3bdaf4cce5ee8e473c332e2f371888341bbFranky Lin		bus->rx_ctlpkts++;
30485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	else
304928a1a3bdaf4cce5ee8e473c332e2f371888341bbFranky Lin		bus->rx_ctlerrs++;
30505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
30515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	return rxlen ? (int)rxlen : -ETIMEDOUT;
30525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
30535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
3054e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic int brcmf_sdbrcm_downloadvars(struct brcmf_sdio *bus, void *arg, int len)
30555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
30565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	int bcmerror = 0;
30575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
30585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_dbg(TRACE, "Enter\n");
30595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
30605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Basic sanity checks */
30613fb1d8d2dad35f5094350c175b778b78df894284Franky Lin	if (bus->sdiodev->bus_if->drvr_up) {
30625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bcmerror = -EISCONN;
30635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		goto err;
30645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
30655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (!len) {
30665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bcmerror = -EOVERFLOW;
30675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		goto err;
30685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
30695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
30705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Free the old ones and replace with passed variables */
30715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	kfree(bus->vars);
30725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
30735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->vars = kmalloc(len, GFP_ATOMIC);
30745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->varsz = bus->vars ? len : 0;
30755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (bus->vars == NULL) {
30765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bcmerror = -ENOMEM;
30775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		goto err;
30785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
30795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
30805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Copy the passed variables, which should include the
30815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		 terminating double-null */
30825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	memcpy(bus->vars, arg, bus->varsz);
30835b435de0d786869c95d1962121af0d7df2542009Arend van Sprielerr:
30845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	return bcmerror;
30855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
30865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
3087e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic int brcmf_sdbrcm_write_vars(struct brcmf_sdio *bus)
30885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
30895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	int bcmerror = 0;
30905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 varsize;
30915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 varaddr;
30925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u8 *vbuffer;
30935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 varsizew;
30945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	__le32 varsizew_le;
30955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#ifdef BCMDBG
30965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	char *nvram_ularray;
30975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#endif				/* BCMDBG */
30985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
30995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Even if there are no vars are to be written, we still
31005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		 need to set the ramsize. */
31015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	varsize = bus->varsz ? roundup(bus->varsz, 4) : 0;
31025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	varaddr = (bus->ramsize - 4) - varsize;
31035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
31045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (bus->vars) {
31055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		vbuffer = kzalloc(varsize, GFP_ATOMIC);
31065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (!vbuffer)
31075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			return -ENOMEM;
31085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
31095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		memcpy(vbuffer, bus->vars, bus->varsz);
31105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
31115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Write the vars list */
31125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bcmerror =
31135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		    brcmf_sdbrcm_membytes(bus, true, varaddr, vbuffer, varsize);
31145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#ifdef BCMDBG
31155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Verify NVRAM bytes */
31165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(INFO, "Compare NVRAM dl & ul; varsize=%d\n", varsize);
31175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		nvram_ularray = kmalloc(varsize, GFP_ATOMIC);
31185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (!nvram_ularray)
31195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			return -ENOMEM;
31205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
31215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Upload image to verify downloaded contents. */
31225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		memset(nvram_ularray, 0xaa, varsize);
31235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
31245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Read the vars list to temp buffer for comparison */
31255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bcmerror =
31265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		    brcmf_sdbrcm_membytes(bus, false, varaddr, nvram_ularray,
31275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				     varsize);
31285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (bcmerror) {
31295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(ERROR, "error %d on reading %d nvram bytes at 0x%08x\n",
31305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				  bcmerror, varsize, varaddr);
31315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
31325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Compare the org NVRAM with the one read from RAM */
31335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (memcmp(vbuffer, nvram_ularray, varsize))
31345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(ERROR, "Downloaded NVRAM image is corrupted\n");
31355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		else
31365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(ERROR, "Download/Upload/Compare of NVRAM ok\n");
31375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
31385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		kfree(nvram_ularray);
31395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#endif				/* BCMDBG */
31405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
31415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		kfree(vbuffer);
31425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
31435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
31445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* adjust to the user specified RAM */
31455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_dbg(INFO, "Physical memory size: %d\n", bus->ramsize);
31465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_dbg(INFO, "Vars are at %d, orig varsize is %d\n",
31475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		  varaddr, varsize);
31485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	varsize = ((bus->ramsize - 4) - varaddr);
31495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
31505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/*
31515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	 * Determine the length token:
31525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	 * Varsize, converted to words, in lower 16-bits, checksum
31535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	 * in upper 16-bits.
31545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	 */
31555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (bcmerror) {
31565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		varsizew = 0;
31575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		varsizew_le = cpu_to_le32(0);
31585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	} else {
31595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		varsizew = varsize / 4;
31605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF);
31615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		varsizew_le = cpu_to_le32(varsizew);
31625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
31635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
31645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_dbg(INFO, "New varsize is %d, length token=0x%08x\n",
31655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		  varsize, varsizew);
31665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
31675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Write the length token to the last word */
31685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bcmerror = brcmf_sdbrcm_membytes(bus, true, (bus->ramsize - 4),
31695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					 (u8 *)&varsizew_le, 4);
31705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
31715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	return bcmerror;
31725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
31735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
3174e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic int brcmf_sdbrcm_download_state(struct brcmf_sdio *bus, bool enter)
31755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
31765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint retries;
31775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	int bcmerror = 0;
317899ba15cd75ed22e4ae86804ca2982a724e8102c2Franky Lin	struct chip_info *ci = bus->ci;
31795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
31805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* To enter download state, disable ARM and reset SOCRAM.
31815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	 * To exit download state, simply reset ARM (default is RAM boot).
31825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	 */
31835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (enter) {
31845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->alp_only = true;
31855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
3186086a2e0a63eef367dab9b4499ba0cfe3a309ec94Franky Lin		ci->coredisable(bus->sdiodev, ci, BCMA_CORE_ARM_CM3);
31875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
3188d77e70ff5ace175f19447a1965691a794c27de24Franky Lin		ci->resetcore(bus->sdiodev, ci, BCMA_CORE_INTERNAL_MEM);
31895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
31905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Clear the top bit of memory */
31915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (bus->ramsize) {
31925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			u32 zeros = 0;
31935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_sdbrcm_membytes(bus, true, bus->ramsize - 4,
31945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					 (u8 *)&zeros, 4);
31955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
31965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	} else {
31976ca687d9461b25ce2339ba1809ec13ef459d4661Franky Lin		if (!ci->iscoreup(bus->sdiodev, ci, BCMA_CORE_INTERNAL_MEM)) {
31985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(ERROR, "SOCRAM core is down after reset?\n");
31995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			bcmerror = -EBADE;
32005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			goto fail;
32015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
32025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
32035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bcmerror = brcmf_sdbrcm_write_vars(bus);
32045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (bcmerror) {
32055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(ERROR, "no vars written to RAM\n");
32065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			bcmerror = 0;
32075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
32085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
32095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		w_sdreg32(bus, 0xFFFFFFFF,
32105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			  offsetof(struct sdpcmd_regs, intstatus), &retries);
32115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
3212d77e70ff5ace175f19447a1965691a794c27de24Franky Lin		ci->resetcore(bus->sdiodev, ci, BCMA_CORE_ARM_CM3);
32135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
32145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Allow HT Clock now that the ARM is running. */
32155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->alp_only = false;
32165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
3217712ac5b37a3348cac4e040c551a6ca6186d33682Franky Lin		bus->sdiodev->bus_if->state = BRCMF_BUS_LOAD;
32185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
32195b435de0d786869c95d1962121af0d7df2542009Arend van Sprielfail:
32205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	return bcmerror;
32215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
32225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
3223e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic int brcmf_sdbrcm_get_image(char *buf, int len, struct brcmf_sdio *bus)
32245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
32255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (bus->firmware->size < bus->fw_ptr + len)
32265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		len = bus->firmware->size - bus->fw_ptr;
32275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
32285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	memcpy(buf, &bus->firmware->data[bus->fw_ptr], len);
32295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->fw_ptr += len;
32305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	return len;
32315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
32325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
3233e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic int brcmf_sdbrcm_download_code_file(struct brcmf_sdio *bus)
32345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
32355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	int offset = 0;
32365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint len;
32375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u8 *memblock = NULL, *memptr;
32385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	int ret;
32395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
32405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_dbg(INFO, "Enter\n");
32415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
32428dd939cade92647a7c87db5ae895a6e120258320Franky Lin	ret = request_firmware(&bus->firmware, BRCMFMAC_FW_NAME,
32435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			       &bus->sdiodev->func[2]->dev);
32445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (ret) {
32455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(ERROR, "Fail to request firmware %d\n", ret);
32465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		return ret;
32475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
32485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->fw_ptr = 0;
32495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
32505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	memptr = memblock = kmalloc(MEMBLOCK + BRCMF_SDALIGN, GFP_ATOMIC);
32515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (memblock == NULL) {
32525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		ret = -ENOMEM;
32535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		goto err;
32545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
32555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if ((u32)(unsigned long)memblock % BRCMF_SDALIGN)
32565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		memptr += (BRCMF_SDALIGN -
32575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			   ((u32)(unsigned long)memblock % BRCMF_SDALIGN));
32585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
32595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Download image */
32605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	while ((len =
32615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_sdbrcm_get_image((char *)memptr, MEMBLOCK, bus))) {
32625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		ret = brcmf_sdbrcm_membytes(bus, true, offset, memptr, len);
32635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (ret) {
32645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(ERROR, "error %d on writing %d membytes at 0x%08x\n",
32655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				  ret, MEMBLOCK, offset);
32665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			goto err;
32675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
32685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
32695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		offset += MEMBLOCK;
32705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
32715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
32725b435de0d786869c95d1962121af0d7df2542009Arend van Sprielerr:
32735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	kfree(memblock);
32745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
32755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	release_firmware(bus->firmware);
32765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->fw_ptr = 0;
32775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
32785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	return ret;
32795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
32805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
32815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/*
32825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * ProcessVars:Takes a buffer of "<var>=<value>\n" lines read from a file
32835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * and ending in a NUL.
32845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * Removes carriage returns, empty lines, comment lines, and converts
32855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * newlines to NULs.
32865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * Shortens buffer as needed and pads with NULs.  End of buffer is marked
32875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * by two NULs.
32885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel*/
32895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
32905b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic uint brcmf_process_nvram_vars(char *varbuf, uint len)
32915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
32925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	char *dp;
32935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bool findNewline;
32945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	int column;
32955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint buf_len, n;
32965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
32975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	dp = varbuf;
32985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
32995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	findNewline = false;
33005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	column = 0;
33015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
33025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	for (n = 0; n < len; n++) {
33035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (varbuf[n] == 0)
33045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			break;
33055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (varbuf[n] == '\r')
33065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			continue;
33075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (findNewline && varbuf[n] != '\n')
33085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			continue;
33095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		findNewline = false;
33105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (varbuf[n] == '#') {
33115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			findNewline = true;
33125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			continue;
33135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
33145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (varbuf[n] == '\n') {
33155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			if (column == 0)
33165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				continue;
33175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			*dp++ = 0;
33185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			column = 0;
33195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			continue;
33205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
33215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		*dp++ = varbuf[n];
33225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		column++;
33235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
33245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	buf_len = dp - varbuf;
33255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
33265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	while (dp < varbuf + n)
33275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		*dp++ = 0;
33285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
33295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	return buf_len;
33305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
33315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
3332e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic int brcmf_sdbrcm_download_nvram(struct brcmf_sdio *bus)
33335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
33345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint len;
33355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	char *memblock = NULL;
33365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	char *bufp;
33375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	int ret;
33385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
33398dd939cade92647a7c87db5ae895a6e120258320Franky Lin	ret = request_firmware(&bus->firmware, BRCMFMAC_NV_NAME,
33405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			       &bus->sdiodev->func[2]->dev);
33415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (ret) {
33425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(ERROR, "Fail to request nvram %d\n", ret);
33435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		return ret;
33445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
33455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->fw_ptr = 0;
33465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
33475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	memblock = kmalloc(MEMBLOCK, GFP_ATOMIC);
33485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (memblock == NULL) {
33495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		ret = -ENOMEM;
33505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		goto err;
33515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
33525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
33535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	len = brcmf_sdbrcm_get_image(memblock, MEMBLOCK, bus);
33545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
33555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (len > 0 && len < MEMBLOCK) {
33565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bufp = (char *)memblock;
33575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bufp[len] = 0;
33585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		len = brcmf_process_nvram_vars(bufp, len);
33595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bufp += len;
33605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		*bufp++ = 0;
33615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (len)
33625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			ret = brcmf_sdbrcm_downloadvars(bus, memblock, len + 1);
33635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (ret)
33645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(ERROR, "error downloading vars: %d\n", ret);
33655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	} else {
33665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(ERROR, "error reading nvram file: %d\n", len);
33675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		ret = -EIO;
33685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
33695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
33705b435de0d786869c95d1962121af0d7df2542009Arend van Sprielerr:
33715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	kfree(memblock);
33725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
33735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	release_firmware(bus->firmware);
33745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->fw_ptr = 0;
33755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
33765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	return ret;
33775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
33785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
3379e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic int _brcmf_sdbrcm_download_firmware(struct brcmf_sdio *bus)
33805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
33815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	int bcmerror = -1;
33825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
33835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Keep arm in reset */
33845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (brcmf_sdbrcm_download_state(bus, true)) {
33855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(ERROR, "error placing ARM core in reset\n");
33865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		goto err;
33875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
33885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
33895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* External image takes precedence if specified */
33905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (brcmf_sdbrcm_download_code_file(bus)) {
33915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(ERROR, "dongle image file download failed\n");
33925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		goto err;
33935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
33945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
33955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* External nvram takes precedence if specified */
33965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (brcmf_sdbrcm_download_nvram(bus))
33975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(ERROR, "dongle nvram file download failed\n");
33985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
33995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Take arm out of reset */
34005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (brcmf_sdbrcm_download_state(bus, false)) {
34015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(ERROR, "error getting out of ARM core reset\n");
34025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		goto err;
34035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
34045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
34055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bcmerror = 0;
34065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
34075b435de0d786869c95d1962121af0d7df2542009Arend van Sprielerr:
34085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	return bcmerror;
34095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
34105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
34115b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic bool
3412e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linbrcmf_sdbrcm_download_firmware(struct brcmf_sdio *bus)
34135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
34145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bool ret;
34155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
34165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Download the firmware */
34175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
34185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
34195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	ret = _brcmf_sdbrcm_download_firmware(bus) == 0;
34205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
34215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false);
34225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
34235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	return ret;
34245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
34255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
342699a0b8ff9105d9b78e7e4e6aaa077264707e4e1cFranky Linstatic int brcmf_sdbrcm_bus_init(struct device *dev)
34275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
3428fa20b91143c616d402f1ed61f27693477279d0c6Franky Lin	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
3429fa20b91143c616d402f1ed61f27693477279d0c6Franky Lin	struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv;
3430fa20b91143c616d402f1ed61f27693477279d0c6Franky Lin	struct brcmf_sdio *bus = sdiodev->bus;
34315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	unsigned long timeout;
34325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	uint retries = 0;
34335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u8 ready, enable;
34345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	int err, ret = 0;
34355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u8 saveclk;
34365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
34375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_dbg(TRACE, "Enter\n");
34385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
34395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* try to download image and nvram to the dongle */
3440fa20b91143c616d402f1ed61f27693477279d0c6Franky Lin	if (bus_if->state == BRCMF_BUS_DOWN) {
34415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (!(brcmf_sdbrcm_download_firmware(bus)))
34425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			return -1;
34435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
34445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
3445712ac5b37a3348cac4e040c551a6ca6186d33682Franky Lin	if (!bus->sdiodev->bus_if->drvr)
34465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		return 0;
34475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
34485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Start the watchdog timer */
344928a1a3bdaf4cce5ee8e473c332e2f371888341bbFranky Lin	bus->tickcnt = 0;
34505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS);
34515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
34525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	down(&bus->sdsem);
34535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
34545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Make sure backplane clock is on, needed to generate F2 interrupt */
34555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
34565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (bus->clkstate != CLK_AVAIL)
34575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		goto exit;
34585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
34595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Force clocks on backplane to be sure F2 interrupt propagates */
34605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	saveclk =
34615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	    brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
34625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				  SBSDIO_FUNC1_CHIPCLKCSR, &err);
34635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (!err) {
34645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
34655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				       SBSDIO_FUNC1_CHIPCLKCSR,
34665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				       (saveclk | SBSDIO_FORCE_HT), &err);
34675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
34685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (err) {
34695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(ERROR, "Failed to force clock for F2: err %d\n", err);
34705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		goto exit;
34715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
34725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
34735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Enable function 2 (frame transfers) */
34745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	w_sdreg32(bus, SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT,
34755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		  offsetof(struct sdpcmd_regs, tosbmailboxdata), &retries);
34765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2);
34775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
34785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx,
34795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			       enable, NULL);
34805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
34815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	timeout = jiffies + msecs_to_jiffies(BRCMF_WAIT_F2RDY);
34825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	ready = 0;
34835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	while (enable != ready) {
34845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		ready = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_0,
34855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					      SDIO_CCCR_IORx, NULL);
34865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (time_after(jiffies, timeout))
34875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			break;
34885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		else if (time_after(jiffies, timeout - BRCMF_WAIT_F2RDY + 50))
34895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			/* prevent busy waiting if it takes too long */
34905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			msleep_interruptible(20);
34915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
34925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
34935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_dbg(INFO, "enable 0x%02x, ready 0x%02x\n", enable, ready);
34945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
34955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* If F2 successfully enabled, set core and enable interrupts */
34965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (ready == enable) {
34975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Set up the interrupt mask and enable interrupts */
34985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->hostintmask = HOSTINTMASK;
34995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		w_sdreg32(bus, bus->hostintmask,
35005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			  offsetof(struct sdpcmd_regs, hostintmask), &retries);
35015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
35025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
35035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				       SBSDIO_WATERMARK, 8, &err);
35045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
35055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Set bus state according to enable result */
3506fa20b91143c616d402f1ed61f27693477279d0c6Franky Lin		bus_if->state = BRCMF_BUS_DATA;
35075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
35085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
35095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	else {
35105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Disable F2 again */
35115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		enable = SDIO_FUNC_ENABLE_1;
35125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0,
35135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				       SDIO_CCCR_IOEx, enable, NULL);
35145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
35155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
35165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Restore previous clock setting */
35175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
35185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			       SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err);
35195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
35205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* If we didn't come up, turn off backplane clock */
3521fa20b91143c616d402f1ed61f27693477279d0c6Franky Lin	if (bus_if->state != BRCMF_BUS_DATA)
35225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
35235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
35245b435de0d786869c95d1962121af0d7df2542009Arend van Sprielexit:
35255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	up(&bus->sdsem);
35265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
35275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	return ret;
35285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
35295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
35305b435de0d786869c95d1962121af0d7df2542009Arend van Sprielvoid brcmf_sdbrcm_isr(void *arg)
35315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
3532e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Lin	struct brcmf_sdio *bus = (struct brcmf_sdio *) arg;
35335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
35345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_dbg(TRACE, "Enter\n");
35355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
35365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (!bus) {
35375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(ERROR, "bus is null pointer, exiting\n");
35385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		return;
35395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
35405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
3541712ac5b37a3348cac4e040c551a6ca6186d33682Franky Lin	if (bus->sdiodev->bus_if->state == BRCMF_BUS_DOWN) {
35425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(ERROR, "bus is down. we have nothing to do\n");
35435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		return;
35445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
35455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Count the interrupt call */
35465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->intrcount++;
35475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->ipend = true;
35485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
35495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Shouldn't get this interrupt if we're sleeping? */
35505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (bus->sleeping) {
35515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(ERROR, "INTERRUPT WHILE SLEEPING??\n");
35525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		return;
35535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
35545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
35555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Disable additional interrupts (is this needed now)? */
35565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (!bus->intr)
35575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(ERROR, "isr w/o interrupt configured!\n");
35585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
35595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->dpc_sched = true;
35605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (bus->dpc_tsk)
35615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		complete(&bus->dpc_wait);
35625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
35635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
3564cad2b26b1010d0694d2f08d408486451b9f919d2Franky Linstatic bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)
35655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
3566cad2b26b1010d0694d2f08d408486451b9f919d2Franky Lin#ifdef BCMDBG
3567cad2b26b1010d0694d2f08d408486451b9f919d2Franky Lin	struct brcmf_bus *bus_if = dev_get_drvdata(bus->sdiodev->dev);
3568cad2b26b1010d0694d2f08d408486451b9f919d2Franky Lin#endif	/* BCMDBG */
35695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
35705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_dbg(TIMER, "Enter\n");
35715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
35725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Ignore the timer if simulating bus down */
35735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (bus->sleeping)
35745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		return false;
35755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
35765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	down(&bus->sdsem);
35775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
35785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Poll period: check device if appropriate. */
35795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (bus->poll && (++bus->polltick >= bus->pollrate)) {
35805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		u32 intstatus = 0;
35815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
35825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Reset poll tick */
35835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->polltick = 0;
35845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
35855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Check device if no interrupts */
35865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (!bus->intr || (bus->intrcount == bus->lastintrs)) {
35875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
35885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			if (!bus->dpc_sched) {
35895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				u8 devpend;
35905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				devpend = brcmf_sdcard_cfg_read(bus->sdiodev,
35915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel						SDIO_FUNC_0, SDIO_CCCR_INTx,
35925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel						NULL);
35935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				intstatus =
35945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				    devpend & (INTR_STATUS_FUNC1 |
35955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					       INTR_STATUS_FUNC2);
35965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			}
35975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
35985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			/* If there is something, make like the ISR and
35995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				 schedule the DPC */
36005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			if (intstatus) {
36015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				bus->pollcnt++;
36025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				bus->ipend = true;
36035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
36045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				bus->dpc_sched = true;
36055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				if (bus->dpc_tsk)
36065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					complete(&bus->dpc_wait);
36075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			}
36085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
36095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
36105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Update interrupt tracking */
36115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->lastintrs = bus->intrcount;
36125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
36135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#ifdef BCMDBG
36145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Poll for console output periodically */
3615cad2b26b1010d0694d2f08d408486451b9f919d2Franky Lin	if (bus_if->state == BRCMF_BUS_DATA &&
36168d169aa00d0356f915e84dbdf6c9be381cce34a4Franky Lin	    bus->console_interval != 0) {
36175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->console.count += BRCMF_WD_POLL_MS;
36185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (bus->console.count >= bus->console_interval) {
36195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			bus->console.count -= bus->console_interval;
36205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			/* Make sure backplane clock is on */
36215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
36225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			if (brcmf_sdbrcm_readconsole(bus) < 0)
36235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				/* stop on error */
36245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				bus->console_interval = 0;
36255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
36265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
36275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#endif				/* BCMDBG */
36285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
36295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* On idle timeout clear activity flag and/or turn off clock */
36305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if ((bus->idletime > 0) && (bus->clkstate == CLK_AVAIL)) {
36315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (++bus->idlecount >= bus->idletime) {
36325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			bus->idlecount = 0;
36335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			if (bus->activity) {
36345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				bus->activity = false;
36355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS);
36365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			} else {
36375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
36385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			}
36395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
36405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
36415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
36425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	up(&bus->sdsem);
36435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
36445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	return bus->ipend;
36455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
36465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
36475b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic bool brcmf_sdbrcm_chipmatch(u16 chipid)
36485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
36495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (chipid == BCM4329_CHIP_ID)
36505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		return true;
3651ce2d7d7e8fd88191f5d1c92a8b33aeb0cb12ea34Franky Lin	if (chipid == BCM4330_CHIP_ID)
3652ce2d7d7e8fd88191f5d1c92a8b33aeb0cb12ea34Franky Lin		return true;
36535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	return false;
36545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
36555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
3656e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic void brcmf_sdbrcm_release_malloc(struct brcmf_sdio *bus)
36575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
36585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_dbg(TRACE, "Enter\n");
36595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
36605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	kfree(bus->rxbuf);
36615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->rxctl = bus->rxbuf = NULL;
36625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->rxlen = 0;
36635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
36645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	kfree(bus->databuf);
36655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->databuf = NULL;
36665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
36675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
3668e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic bool brcmf_sdbrcm_probe_malloc(struct brcmf_sdio *bus)
36695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
36705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_dbg(TRACE, "Enter\n");
36715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
3672b01a6b3ca714e2bb86ee387aee487c7360363c93Franky Lin	if (bus->sdiodev->bus_if->maxctl) {
36735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->rxblen =
3674b01a6b3ca714e2bb86ee387aee487c7360363c93Franky Lin		    roundup((bus->sdiodev->bus_if->maxctl + SDPCM_HDRLEN),
36755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			    ALIGNMENT) + BRCMF_SDALIGN;
36765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->rxbuf = kmalloc(bus->rxblen, GFP_ATOMIC);
36775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (!(bus->rxbuf))
36785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			goto fail;
36795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
36805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
36815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Allocate buffer to receive glomed packet */
36825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->databuf = kmalloc(MAX_DATA_BUF, GFP_ATOMIC);
36835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (!(bus->databuf)) {
36845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* release rxbuf which was already located as above */
36855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (!bus->rxblen)
36865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			kfree(bus->rxbuf);
36875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		goto fail;
36885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
36895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
36905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Align the buffer */
36915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if ((unsigned long)bus->databuf % BRCMF_SDALIGN)
36925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->dataptr = bus->databuf + (BRCMF_SDALIGN -
36935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			       ((unsigned long)bus->databuf % BRCMF_SDALIGN));
36945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	else
36955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->dataptr = bus->databuf;
36965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
36975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	return true;
36985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
36995b435de0d786869c95d1962121af0d7df2542009Arend van Sprielfail:
37005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	return false;
37015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
37025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
37035b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic bool
3704e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linbrcmf_sdbrcm_probe_attach(struct brcmf_sdio *bus, u32 regsva)
37055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
37065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u8 clkctl = 0;
37075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	int err = 0;
37085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	int reg_addr;
37095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	u32 reg_val;
371099ba15cd75ed22e4ae86804ca2982a724e8102c2Franky Lin	u8 idx;
37115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
37125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->alp_only = true;
37135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
37145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Return the window to backplane enumeration space for core access */
37155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (brcmf_sdcard_set_sbaddr_window(bus->sdiodev, SI_ENUM_BASE))
37165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(ERROR, "FAILED to return to SI_ENUM_BASE\n");
37175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
37185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#ifdef BCMDBG
37195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	printk(KERN_DEBUG "F1 signature read @0x18000000=0x%4x\n",
37205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	       brcmf_sdcard_reg_read(bus->sdiodev, SI_ENUM_BASE, 4));
37215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
37225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#endif				/* BCMDBG */
37235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
37245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/*
3725a97e4fc5ae4b00187b25a8216a61b2105efa9c60Franky Lin	 * Force PLL off until brcmf_sdio_chip_attach()
37265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	 * programs PLL control regs
37275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	 */
37285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
37295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
37305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			       SBSDIO_FUNC1_CHIPCLKCSR,
37315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			       BRCMF_INIT_CLKCTL1, &err);
37325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (!err)
37335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		clkctl =
37345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		    brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
37355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					  SBSDIO_FUNC1_CHIPCLKCSR, &err);
37365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
37375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (err || ((clkctl & ~SBSDIO_AVBITS) != BRCMF_INIT_CLKCTL1)) {
37385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(ERROR, "ChipClkCSR access: err %d wrote 0x%02x read 0x%02x\n",
37395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			  err, BRCMF_INIT_CLKCTL1, clkctl);
37405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		goto fail;
37415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
37425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
3743a97e4fc5ae4b00187b25a8216a61b2105efa9c60Franky Lin	if (brcmf_sdio_chip_attach(bus->sdiodev, &bus->ci, regsva)) {
3744a97e4fc5ae4b00187b25a8216a61b2105efa9c60Franky Lin		brcmf_dbg(ERROR, "brcmf_sdio_chip_attach failed!\n");
37455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		goto fail;
37465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
37475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
37485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (!brcmf_sdbrcm_chipmatch((u16) bus->ci->chip)) {
37495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(ERROR, "unsupported chip: 0x%04x\n", bus->ci->chip);
37505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		goto fail;
37515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
37525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
3753e12afb6c5d13ebff64d4a2feb97cce0c2d7e1128Franky Lin	brcmf_sdio_chip_drivestrengthinit(bus->sdiodev, bus->ci,
3754e12afb6c5d13ebff64d4a2feb97cce0c2d7e1128Franky Lin					  SDIO_DRIVE_STRENGTH);
37555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
3756454d2a8816d6bc6594d3d475392290623af63656Franky Lin	/* Get info on the SOCRAM cores... */
37575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->ramsize = bus->ci->ramsize;
37585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (!(bus->ramsize)) {
37595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(ERROR, "failed to find SOCRAM memory!\n");
37605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		goto fail;
37615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
37625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
37635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Set core control so an SDIO reset does a backplane reset */
376499ba15cd75ed22e4ae86804ca2982a724e8102c2Franky Lin	idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV);
376599ba15cd75ed22e4ae86804ca2982a724e8102c2Franky Lin	reg_addr = bus->ci->c_inf[idx].base +
37665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		   offsetof(struct sdpcmd_regs, corecontrol);
37675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	reg_val = brcmf_sdcard_reg_read(bus->sdiodev, reg_addr, sizeof(u32));
37685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_sdcard_reg_write(bus->sdiodev, reg_addr, sizeof(u32),
37695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			       reg_val | CC_BPRESEN);
37705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
37715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmu_pktq_init(&bus->txq, (PRIOMASK + 1), TXQLEN);
37725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
37735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Locate an appropriately-aligned portion of hdrbuf */
37745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->rxhdr = (u8 *) roundup((unsigned long)&bus->hdrbuf[0],
37755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				    BRCMF_SDALIGN);
37765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
37775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Set the poll and/or interrupt flags */
37785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->intr = true;
37795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->poll = false;
37805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (bus->poll)
37815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->pollrate = 1;
37825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
37835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	return true;
37845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
37855b435de0d786869c95d1962121af0d7df2542009Arend van Sprielfail:
37865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	return false;
37875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
37885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
3789e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic bool brcmf_sdbrcm_probe_init(struct brcmf_sdio *bus)
37905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
37915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_dbg(TRACE, "Enter\n");
37925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
37935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Disable F2 to clear any intermediate frame state on the dongle */
37945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx,
37955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			       SDIO_FUNC_ENABLE_1, NULL);
37965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
3797712ac5b37a3348cac4e040c551a6ca6186d33682Franky Lin	bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
37985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->sleeping = false;
37995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->rxflow = false;
38005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
38015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Done with backplane-dependent accesses, can drop clock... */
38025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
38035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			       SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
38045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
38055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* ...and initialize clock/power states */
38065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->clkstate = CLK_SDONLY;
38075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->idletime = BRCMF_IDLE_INTERVAL;
38085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->idleclock = BRCMF_IDLE_ACTIVE;
38095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
38105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Query the F2 block size, set roundup accordingly */
38115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->blocksize = bus->sdiodev->func[2]->cur_blksize;
38125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->roundup = min(max_roundup, bus->blocksize);
38135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
38145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* bus module does not support packet chaining */
38155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->use_rxchain = false;
38165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->sd_rxchain = false;
38175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
38185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	return true;
38195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
38205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
38215b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic int
38225b435de0d786869c95d1962121af0d7df2542009Arend van Sprielbrcmf_sdbrcm_watchdog_thread(void *data)
38235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
3824e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Lin	struct brcmf_sdio *bus = (struct brcmf_sdio *)data;
38255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
38265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	allow_signal(SIGTERM);
38275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Run until signal received */
38285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	while (1) {
38295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (kthread_should_stop())
38305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			break;
38315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (!wait_for_completion_interruptible(&bus->watchdog_wait)) {
3832cad2b26b1010d0694d2f08d408486451b9f919d2Franky Lin			brcmf_sdbrcm_bus_watchdog(bus);
38335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			/* Count the tick for reference */
383428a1a3bdaf4cce5ee8e473c332e2f371888341bbFranky Lin			bus->tickcnt++;
38355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		} else
38365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			break;
38375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
38385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	return 0;
38395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
38405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
38415b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic void
38425b435de0d786869c95d1962121af0d7df2542009Arend van Sprielbrcmf_sdbrcm_watchdog(unsigned long data)
38435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
3844e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Lin	struct brcmf_sdio *bus = (struct brcmf_sdio *)data;
38455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
38465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (bus->watchdog_tsk) {
38475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		complete(&bus->watchdog_wait);
38485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* Reschedule the watchdog */
38495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (bus->wd_timer_valid)
38505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			mod_timer(&bus->timer,
38515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				  jiffies + BRCMF_WD_POLL_MS * HZ / 1000);
38525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
38535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
38545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
3855e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic void brcmf_sdbrcm_release_dongle(struct brcmf_sdio *bus)
38565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
38575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_dbg(TRACE, "Enter\n");
38585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
38595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (bus->ci) {
38605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
38615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
3862a8a6c04586233e12551552c292797cb56b31dadeFranky Lin		brcmf_sdio_chip_detach(&bus->ci);
38635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (bus->vars && bus->varsz)
38645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			kfree(bus->vars);
38655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->vars = NULL;
38665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
38675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
38685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_dbg(TRACE, "Disconnected\n");
38695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
38705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
38715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* Detach and free everything */
3872e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic void brcmf_sdbrcm_release(struct brcmf_sdio *bus)
38735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
38745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_dbg(TRACE, "Enter\n");
38755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
38765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (bus) {
38775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		/* De-register interrupt handler */
38785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_sdcard_intr_dereg(bus->sdiodev);
38795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
38805f947ad942a72e7f96942da97d719dd62037dbc2Franky Lin		if (bus->sdiodev->bus_if->drvr) {
38815f947ad942a72e7f96942da97d719dd62037dbc2Franky Lin			brcmf_detach(bus->sdiodev->dev);
38825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_sdbrcm_release_dongle(bus);
38835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
38845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
38855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_sdbrcm_release_malloc(bus);
38865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
38875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		kfree(bus);
38885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
38895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
38905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_dbg(TRACE, "Disconnected\n");
38915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
38925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
38934175b88bd22022a60de175f94fdb303bed087eb9Franky Linvoid *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev)
38945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
38955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	int ret;
3896e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Lin	struct brcmf_sdio *bus;
38975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
38985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_dbg(TRACE, "Enter\n");
38995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
39005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* We make an assumption about address window mappings:
39015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	 * regsva == SI_ENUM_BASE*/
39025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
39035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Allocate private bus interface state */
3904e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Lin	bus = kzalloc(sizeof(struct brcmf_sdio), GFP_ATOMIC);
39055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (!bus)
39065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		goto fail;
39075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
39085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->sdiodev = sdiodev;
39095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	sdiodev->bus = bus;
3910b83db862ffb871e3131e5d2160c741b288eea9aaArend van Spriel	skb_queue_head_init(&bus->glom);
39115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->txbound = BRCMF_TXBOUND;
39125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->rxbound = BRCMF_RXBOUND;
39135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->txminmax = BRCMF_TXMINMAX;
39145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1;
39155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->usebufpool = false;	/* Use bufpool if allocated,
39165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					 else use locally malloced rxbuf */
39175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
39185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* attempt to attach to the dongle */
39195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (!(brcmf_sdbrcm_probe_attach(bus, regsva))) {
39205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(ERROR, "brcmf_sdbrcm_probe_attach failed\n");
39215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		goto fail;
39225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
39235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
39245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	spin_lock_init(&bus->txqlock);
39255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	init_waitqueue_head(&bus->ctrl_wait);
39265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	init_waitqueue_head(&bus->dcmd_resp_wait);
39275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
39285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Set up the watchdog timer */
39295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	init_timer(&bus->timer);
39305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->timer.data = (unsigned long)bus;
39315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->timer.function = brcmf_sdbrcm_watchdog;
39325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
39335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Initialize thread based operation and lock */
39345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	sema_init(&bus->sdsem, 1);
39355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
39365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Initialize watchdog thread */
39375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	init_completion(&bus->watchdog_wait);
39385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->watchdog_tsk = kthread_run(brcmf_sdbrcm_watchdog_thread,
39395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel					bus, "brcmf_watchdog");
39405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (IS_ERR(bus->watchdog_tsk)) {
39415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		printk(KERN_WARNING
39425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		       "brcmf_watchdog thread failed to start\n");
39435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->watchdog_tsk = NULL;
39445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
39455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Initialize DPC thread */
39465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	init_completion(&bus->dpc_wait);
39475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	bus->dpc_tsk = kthread_run(brcmf_sdbrcm_dpc_thread,
39485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				   bus, "brcmf_dpc");
39495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (IS_ERR(bus->dpc_tsk)) {
39505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		printk(KERN_WARNING
39515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		       "brcmf_dpc thread failed to start\n");
39525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->dpc_tsk = NULL;
39535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
39545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
3955a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin	/* Assign bus interface call back */
3956a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin	bus->sdiodev->bus_if->brcmf_bus_stop = brcmf_sdbrcm_bus_stop;
395799a0b8ff9105d9b78e7e4e6aaa077264707e4e1cFranky Lin	bus->sdiodev->bus_if->brcmf_bus_init = brcmf_sdbrcm_bus_init;
3958b9692d17e842fadb8c18faf24f550db80886763eFranky Lin	bus->sdiodev->bus_if->brcmf_bus_txdata = brcmf_sdbrcm_bus_txdata;
3959fcf094f414f9e9c088f6c2aa9e19a59f7b41e1f5Franky Lin	bus->sdiodev->bus_if->brcmf_bus_txctl = brcmf_sdbrcm_bus_txctl;
3960fcf094f414f9e9c088f6c2aa9e19a59f7b41e1f5Franky Lin	bus->sdiodev->bus_if->brcmf_bus_rxctl = brcmf_sdbrcm_bus_rxctl;
39615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Attach to the brcmf/OS/network interface */
39622447ffb0bdf89d14c9a9503e33b32b73d3040feeFranky Lin	ret = brcmf_attach(SDPCM_RESERVE, bus->sdiodev->dev);
3963712ac5b37a3348cac4e040c551a6ca6186d33682Franky Lin	if (ret != 0) {
39645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(ERROR, "brcmf_attach failed\n");
39655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		goto fail;
39665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
39675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
39685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Allocate buffers */
39695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (!(brcmf_sdbrcm_probe_malloc(bus))) {
39705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(ERROR, "brcmf_sdbrcm_probe_malloc failed\n");
39715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		goto fail;
39725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
39735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
39745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (!(brcmf_sdbrcm_probe_init(bus))) {
39755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(ERROR, "brcmf_sdbrcm_probe_init failed\n");
39765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		goto fail;
39775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
39785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
39795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Register interrupt callback, but mask it (not operational yet). */
39805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_dbg(INTR, "disable SDIO interrupts (not interested yet)\n");
39815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	ret = brcmf_sdcard_intr_reg(bus->sdiodev);
39825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (ret != 0) {
39835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_dbg(ERROR, "FAILED: sdcard_intr_reg returned %d\n", ret);
39845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		goto fail;
39855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
39865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_dbg(INTR, "registered SDIO interrupt function ok\n");
39875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
39885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_dbg(INFO, "completed!!\n");
39895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
39905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* if firmware path present try to download and bring up bus */
3991ed683c986f6fff6b9d9fe2adc8b11e0b0be7c085Franky Lin	ret = brcmf_bus_start(bus->sdiodev->dev);
39925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (ret != 0) {
39935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (ret == -ENOLINK) {
39945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			brcmf_dbg(ERROR, "dongle is not responding\n");
39955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			goto fail;
39965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
39975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
399815d45b6fbd01ecebc5a77b1e06ae7ebffad8018aFranky Lin
399915d45b6fbd01ecebc5a77b1e06ae7ebffad8018aFranky Lin	/* add interface and open for business */
400055a63bcc4cdeabf76f7e42a76d0c59dbe37d0d64Franky Lin	if (brcmf_add_if(bus->sdiodev->dev, 0, "wlan%d", NULL)) {
400115d45b6fbd01ecebc5a77b1e06ae7ebffad8018aFranky Lin		brcmf_dbg(ERROR, "Add primary net device interface failed!!\n");
40025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		goto fail;
40035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
40045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
40055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	return bus;
40065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
40075b435de0d786869c95d1962121af0d7df2542009Arend van Sprielfail:
40085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_sdbrcm_release(bus);
40095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	return NULL;
40105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
40115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
40125b435de0d786869c95d1962121af0d7df2542009Arend van Sprielvoid brcmf_sdbrcm_disconnect(void *ptr)
40135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
4014e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Lin	struct brcmf_sdio *bus = (struct brcmf_sdio *)ptr;
40155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
40165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_dbg(TRACE, "Enter\n");
40175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
40185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (bus)
40195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		brcmf_sdbrcm_release(bus);
40205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
40215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	brcmf_dbg(TRACE, "Disconnected\n");
40225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
40235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
40245b435de0d786869c95d1962121af0d7df2542009Arend van Sprielvoid
4025e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linbrcmf_sdbrcm_wd_timer(struct brcmf_sdio *bus, uint wdtick)
40265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{
40275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	/* Totally stop the timer */
40285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (!wdtick && bus->wd_timer_valid == true) {
40295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		del_timer_sync(&bus->timer);
40305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->wd_timer_valid = false;
40315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->save_ms = wdtick;
40325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		return;
40335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
40345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
4035ece960eae81c604aa14a1bf431eda34f4fe71c0cFranky Lin	/* don't start the wd until fw is loaded */
4036712ac5b37a3348cac4e040c551a6ca6186d33682Franky Lin	if (bus->sdiodev->bus_if->state == BRCMF_BUS_DOWN)
4037ece960eae81c604aa14a1bf431eda34f4fe71c0cFranky Lin		return;
4038ece960eae81c604aa14a1bf431eda34f4fe71c0cFranky Lin
40395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	if (wdtick) {
40405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		if (bus->save_ms != BRCMF_WD_POLL_MS) {
40415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			if (bus->wd_timer_valid == true)
40425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				/* Stop timer and restart at new value */
40435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				del_timer_sync(&bus->timer);
40445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
40455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			/* Create timer again when watchdog period is
40465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			   dynamically changed or in the first instance
40475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			 */
40485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			bus->timer.expires =
40495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				jiffies + BRCMF_WD_POLL_MS * HZ / 1000;
40505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			add_timer(&bus->timer);
40515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
40525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		} else {
40535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			/* Re arm the timer, at last watchdog period */
40545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel			mod_timer(&bus->timer,
40555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel				jiffies + BRCMF_WD_POLL_MS * HZ / 1000);
40565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		}
40575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel
40585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->wd_timer_valid = true;
40595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel		bus->save_ms = wdtick;
40605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel	}
40615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}
4062