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