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