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 1702f77195db6ce252d5488b6d48d8edc1c5e2aa30Joe Perches#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 1802f77195db6ce252d5488b6d48d8edc1c5e2aa30Joe Perches 195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include <linux/types.h> 205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include <linux/kernel.h> 215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include <linux/kthread.h> 225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include <linux/printk.h> 235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include <linux/pci_ids.h> 245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include <linux/netdevice.h> 255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include <linux/interrupt.h> 265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include <linux/sched.h> 275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include <linux/mmc/sdio.h> 285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include <linux/mmc/sdio_func.h> 295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include <linux/mmc/card.h> 305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include <linux/semaphore.h> 315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include <linux/firmware.h> 32b7a57e762ecf5d9971549ab3f9eb66b559840e72Stephen Rothwell#include <linux/module.h> 3399ba15cd75ed22e4ae86804ca2982a724e8102c2Franky Lin#include <linux/bcma/bcma.h> 345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include <asm/unaligned.h> 355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include <defs.h> 365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include <brcmu_wifi.h> 375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include <brcmu_utils.h> 385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include <brcm_hw_ids.h> 395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include <soc.h> 405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include "sdio_host.h" 41a83369b6e1e7285edd5217601a0618b9a43bdc4bFranky Lin#include "sdio_chip.h" 425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define DCMD_RESP_TIMEOUT 2000 /* In milli second */ 445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 458ae746543c8370fd04c28aaf8f185c1687b0e694Joe Perches#ifdef DEBUG 465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define BRCMF_TRAP_INFO_SIZE 80 485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define CBUF_LEN (128) 505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 515b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstruct rte_log_le { 525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel __le32 buf; /* Can't be pointer on (64-bit) hosts */ 535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel __le32 buf_size; 545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel __le32 idx; 555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel char *_buf_compat; /* Redundant pointer for backward compat. */ 565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}; 575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 585b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstruct rte_console { 595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Virtual UART 605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * When there is no UART (e.g. Quickturn), 615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * the host should write a complete 625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * input line directly into cbuf and then write 635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * the length into vcons_in. 645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * This may also be used when there is a real UART 655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * (at risk of conflicting with 665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * the real UART). vcons_out is currently unused. 675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint vcons_in; 695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint vcons_out; 705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Output (logging) buffer 725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * Console output is written to a ring buffer log_buf at index log_idx. 735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * The host may read the output when it sees log_idx advance. 745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * Output will be lost if the output wraps around faster than the host 755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * polls. 765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct rte_log_le log_le; 785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Console input line buffer 805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * Characters are read one at a time into cbuf 815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * until <CR> is received, then 825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * the buffer is processed as a command line. 835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * Also used for virtual UART. 845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint cbuf_idx; 865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel char cbuf[CBUF_LEN]; 875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}; 885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 898ae746543c8370fd04c28aaf8f185c1687b0e694Joe Perches#endif /* DEBUG */ 905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include <chipcommon.h> 915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include "dhd_bus.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 31252e1409f72d629644b496db80c119e04ebabad90Arend van Spriel#define BRCMF_SDIO_FW_NAME "brcm/brcmfmac-sdio.bin" 31352e1409f72d629644b496db80c119e04ebabad90Arend van Spriel#define BRCMF_SDIO_NV_NAME "brcm/brcmfmac-sdio.txt" 31452e1409f72d629644b496db80c119e04ebabad90Arend van SprielMODULE_FIRMWARE(BRCMF_SDIO_FW_NAME); 31552e1409f72d629644b496db80c119e04ebabad90Arend van SprielMODULE_FIRMWARE(BRCMF_SDIO_NV_NAME); 3168dd939cade92647a7c87db5ae895a6e120258320Franky Lin 317382a9e0f31235e4efd63977646da5c84e73febf7Franky Lin#define BRCMF_IDLE_IMMEDIATE (-1) /* Enter idle immediately */ 318382a9e0f31235e4efd63977646da5c84e73febf7Franky Lin#define BRCMF_IDLE_ACTIVE 0 /* Do not request any SD clock change 319382a9e0f31235e4efd63977646da5c84e73febf7Franky Lin * when idle 320382a9e0f31235e4efd63977646da5c84e73febf7Franky Lin */ 321382a9e0f31235e4efd63977646da5c84e73febf7Franky Lin#define BRCMF_IDLE_INTERVAL 1 322382a9e0f31235e4efd63977646da5c84e73febf7Franky Lin 3235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* 3245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * Conversion of 802.1D priority to precedence level 3255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 3265b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic uint prio2prec(u32 prio) 3275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 3285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return (prio == PRIO_8021D_NONE || prio == PRIO_8021D_BE) ? 3295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel (prio^2) : prio; 3305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 3315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 3325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* core registers */ 3335b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstruct sdpcmd_regs { 3345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 corecontrol; /* 0x00, rev8 */ 3355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 corestatus; /* rev8 */ 3365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 PAD[1]; 3375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 biststatus; /* rev8 */ 3385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 3395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* PCMCIA access */ 3405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u16 pcmciamesportaladdr; /* 0x010, rev8 */ 3415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u16 PAD[1]; 3425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u16 pcmciamesportalmask; /* rev8 */ 3435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u16 PAD[1]; 3445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u16 pcmciawrframebc; /* rev8 */ 3455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u16 PAD[1]; 3465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u16 pcmciaunderflowtimer; /* rev8 */ 3475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u16 PAD[1]; 3485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 3495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* interrupt */ 3505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 intstatus; /* 0x020, rev8 */ 3515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 hostintmask; /* rev8 */ 3525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 intmask; /* rev8 */ 3535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 sbintstatus; /* rev8 */ 3545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 sbintmask; /* rev8 */ 3555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 funcintmask; /* rev4 */ 3565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 PAD[2]; 3575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 tosbmailbox; /* 0x040, rev8 */ 3585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 tohostmailbox; /* rev8 */ 3595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 tosbmailboxdata; /* rev8 */ 3605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 tohostmailboxdata; /* rev8 */ 3615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 3625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* synchronized access to registers in SDIO clock domain */ 3635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 sdioaccess; /* 0x050, rev8 */ 3645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 PAD[3]; 3655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 3665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* PCMCIA frame control */ 3675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 pcmciaframectrl; /* 0x060, rev8 */ 3685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 PAD[3]; 3695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 pcmciawatermark; /* rev8 */ 3705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 PAD[155]; 3715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 3725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* interrupt batching control */ 3735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 intrcvlazy; /* 0x100, rev8 */ 3745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 PAD[3]; 3755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 3765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* counters */ 3775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 cmd52rd; /* 0x110, rev8 */ 3785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 cmd52wr; /* rev8 */ 3795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 cmd53rd; /* rev8 */ 3805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 cmd53wr; /* rev8 */ 3815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 abort; /* rev8 */ 3825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 datacrcerror; /* rev8 */ 3835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 rdoutofsync; /* rev8 */ 3845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 wroutofsync; /* rev8 */ 3855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 writebusy; /* rev8 */ 3865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 readwait; /* rev8 */ 3875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 readterm; /* rev8 */ 3885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 writeterm; /* rev8 */ 3895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 PAD[40]; 3905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 clockctlstatus; /* rev8 */ 3915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 PAD[7]; 3925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 3935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 PAD[128]; /* DMA engines */ 3945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 3955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* SDIO/PCMCIA CIS region */ 3965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel char cis[512]; /* 0x400-0x5ff, rev6 */ 3975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 3985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* PCMCIA function control registers */ 3995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel char pcmciafcr[256]; /* 0x600-6ff, rev6 */ 4005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u16 PAD[55]; 4015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 4025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* PCMCIA backplane access */ 4035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u16 backplanecsr; /* 0x76E, rev6 */ 4045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u16 backplaneaddr0; /* rev6 */ 4055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u16 backplaneaddr1; /* rev6 */ 4065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u16 backplaneaddr2; /* rev6 */ 4075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u16 backplaneaddr3; /* rev6 */ 4085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u16 backplanedata0; /* rev6 */ 4095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u16 backplanedata1; /* rev6 */ 4105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u16 backplanedata2; /* rev6 */ 4115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u16 backplanedata3; /* rev6 */ 4125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u16 PAD[31]; 4135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 4145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* sprom "size" & "blank" info */ 4155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u16 spromstatus; /* 0x7BE, rev2 */ 4165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 PAD[464]; 4175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 4185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u16 PAD[0x80]; 4195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}; 4205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 4218ae746543c8370fd04c28aaf8f185c1687b0e694Joe Perches#ifdef DEBUG 4225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* Device console log buffer state */ 4235b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstruct brcmf_console { 4245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint count; /* Poll interval msec counter */ 4255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint log_addr; /* Log struct address (fixed) */ 4265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct rte_log_le log_le; /* Log struct (host copy) */ 4275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint bufsize; /* Size of log buffer */ 4285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 *buf; /* Log buffer (host copy) */ 4295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint last; /* Last buffer read index */ 4305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}; 4318ae746543c8370fd04c28aaf8f185c1687b0e694Joe Perches#endif /* DEBUG */ 4325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 4335b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstruct sdpcm_shared { 4345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 flags; 4355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 trap_addr; 4365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 assert_exp_addr; 4375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 assert_file_addr; 4385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 assert_line; 4395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 console_addr; /* Address of struct rte_console */ 4405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 msgtrace_addr; 4415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 tag[32]; 4425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}; 4435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 4445b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstruct sdpcm_shared_le { 4455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel __le32 flags; 4465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel __le32 trap_addr; 4475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel __le32 assert_exp_addr; 4485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel __le32 assert_file_addr; 4495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel __le32 assert_line; 4505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel __le32 console_addr; /* Address of struct rte_console */ 4515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel __le32 msgtrace_addr; 4525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 tag[32]; 4535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}; 4545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 4555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 4565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* misc chip info needed by some of the routines */ 4575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* Private data for SDIO bus interaction */ 458e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstruct brcmf_sdio { 4595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct brcmf_sdio_dev *sdiodev; /* sdio device handler */ 4605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct chip_info *ci; /* Chip info struct */ 4615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel char *vars; /* Variables (from CIS and/or other) */ 4625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint varsz; /* Size of variables buffer */ 4635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 4645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 ramsize; /* Size of RAM in SOCRAM (bytes) */ 4655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 4665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 hostintmask; /* Copy of Host Interrupt Mask */ 4675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 intstatus; /* Intstatus bits (events) pending */ 4685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bool dpc_sched; /* Indicates DPC schedule (intrpt rcvd) */ 4695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bool fcstate; /* State of dongle flow-control */ 4705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 4715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint blocksize; /* Block size of SDIO transfers */ 4725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint roundup; /* Max roundup limit */ 4735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 4745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct pktq txq; /* Queue length used for flow-control */ 4755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 flowcontrol; /* per prio flow control bitmask */ 4765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 tx_seq; /* Transmit sequence number (next) */ 4775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 tx_max; /* Maximum transmit sequence allowed */ 4785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 4795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 hdrbuf[MAX_HDR_READ + BRCMF_SDALIGN]; 4805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 *rxhdr; /* Header of current rx frame (in hdrbuf) */ 4815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u16 nextlen; /* Next Read Len from last header */ 4825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 rx_seq; /* Receive sequence number (expected) */ 4835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bool rxskip; /* Skip receive (awaiting NAK ACK) */ 4845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 4855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint rxbound; /* Rx frames to read before resched */ 4865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint txbound; /* Tx frames to send before resched */ 4875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint txminmax; 4885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 4895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct sk_buff *glomd; /* Packet containing glomming descriptor */ 490b83db862ffb871e3131e5d2160c741b288eea9aaArend van Spriel struct sk_buff_head glom; /* Packet list for glommed superframe */ 4915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint glomerr; /* Glom packet read errors */ 4925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 4935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 *rxbuf; /* Buffer for receiving control packets */ 4945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint rxblen; /* Allocated length of rxbuf */ 4955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 *rxctl; /* Aligned pointer into rxbuf */ 4965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 *databuf; /* Buffer for receiving big glom packet */ 4975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 *dataptr; /* Aligned pointer into databuf */ 4985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint rxlen; /* Length of valid data in buffer */ 4995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 5005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 sdpcm_ver; /* Bus protocol reported by dongle */ 5015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 5025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bool intr; /* Use interrupts */ 5035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bool poll; /* Use polling */ 5045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bool ipend; /* Device interrupt is pending */ 5055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint intrcount; /* Count of device interrupt callbacks */ 5065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint lastintrs; /* Count as of last watchdog timer */ 5075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint spurious; /* Count of spurious interrupts */ 5085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint pollrate; /* Ticks between device polls */ 5095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint polltick; /* Tick counter */ 5105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint pollcnt; /* Count of active polls */ 5115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 5128ae746543c8370fd04c28aaf8f185c1687b0e694Joe Perches#ifdef DEBUG 5135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint console_interval; 5145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct brcmf_console console; /* Console output polling support */ 5155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint console_addr; /* Console address from shared struct */ 5168ae746543c8370fd04c28aaf8f185c1687b0e694Joe Perches#endif /* DEBUG */ 5175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 5185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint regfails; /* Count of R_REG failures */ 5195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 5205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint clkstate; /* State of sd and backplane clock(s) */ 5215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bool activity; /* Activity flag for clock down */ 5225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel s32 idletime; /* Control for activity timeout */ 5235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel s32 idlecount; /* Activity timeout counter */ 5245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel s32 idleclock; /* How to set bus driver when idle */ 5255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel s32 sd_rxchain; 5265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bool use_rxchain; /* If brcmf should use PKT chains */ 5275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bool sleeping; /* Is SDIO bus sleeping? */ 5285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bool rxflow_mode; /* Rx flow control mode */ 5295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bool rxflow; /* Is rx flow control on */ 5305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bool alp_only; /* Don't use HT clock (ALP only) */ 5315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* Field to decide if rx of control frames happen in rxbuf or lb-pool */ 5325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bool usebufpool; 5335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 5345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Some additional counters */ 5355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint tx_sderrs; /* Count of tx attempts with sd errors */ 5365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint fcqueued; /* Tx packets that got queued */ 5375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint rxrtx; /* Count of rtx requests (NAK to dongle) */ 5385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint rx_toolong; /* Receive frames too long to receive */ 5395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint rxc_errors; /* SDIO errors when reading control frames */ 5405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint rx_hdrfail; /* SDIO errors on header reads */ 5415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint rx_badhdr; /* Bad received headers (roosync?) */ 5425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint rx_badseq; /* Mismatched rx sequence number */ 5435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint fc_rcvd; /* Number of flow-control events received */ 5445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint fc_xoff; /* Number which turned on flow-control */ 5455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint fc_xon; /* Number which turned off flow-control */ 5465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint rxglomfail; /* Failed deglom attempts */ 5475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint rxglomframes; /* Number of glom frames (superframes) */ 5485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint rxglompkts; /* Number of packets from glom frames */ 5495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint f2rxhdrs; /* Number of header reads */ 5505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint f2rxdata; /* Number of frame data reads */ 5515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint f2txdata; /* Number of f2 frame writes */ 5525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint f1regdata; /* Number of f1 register accesses */ 55328a1a3bdaf4cce5ee8e473c332e2f371888341bbFranky Lin uint tickcnt; /* Number of watchdog been schedule */ 55428a1a3bdaf4cce5ee8e473c332e2f371888341bbFranky Lin unsigned long tx_ctlerrs; /* Err of sending ctrl frames */ 55528a1a3bdaf4cce5ee8e473c332e2f371888341bbFranky Lin unsigned long tx_ctlpkts; /* Ctrl frames sent to dongle */ 55628a1a3bdaf4cce5ee8e473c332e2f371888341bbFranky Lin unsigned long rx_ctlerrs; /* Err of processing rx ctrl frames */ 55728a1a3bdaf4cce5ee8e473c332e2f371888341bbFranky Lin unsigned long rx_ctlpkts; /* Ctrl frames processed from dongle */ 55828a1a3bdaf4cce5ee8e473c332e2f371888341bbFranky Lin unsigned long rx_readahead_cnt; /* Number of packets where header 55928a1a3bdaf4cce5ee8e473c332e2f371888341bbFranky Lin * read-ahead was used. */ 5605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 5615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 *ctrl_frame_buf; 5625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 ctrl_frame_len; 5635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bool ctrl_frame_stat; 5645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 5655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spinlock_t txqlock; 5665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wait_queue_head_t ctrl_wait; 5675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wait_queue_head_t dcmd_resp_wait; 5685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 5695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct timer_list timer; 5705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct completion watchdog_wait; 5715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct task_struct *watchdog_tsk; 5725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bool wd_timer_valid; 5735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint save_ms; 5745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 5755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct task_struct *dpc_tsk; 5765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct completion dpc_wait; 577b948a85c1f26d48395de8c6c7e392f008f1be666Franky Lin struct list_head dpc_tsklst; 578b948a85c1f26d48395de8c6c7e392f008f1be666Franky Lin spinlock_t dpc_tl_lock; 5795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 5805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct semaphore sdsem; 5815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 5825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel const struct firmware *firmware; 5835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 fw_ptr; 584c8bf34849f92c5894a3d7e12573d3789d7851f23Franky Lin 585c8bf34849f92c5894a3d7e12573d3789d7851f23Franky Lin bool txoff; /* Transmit flow-controlled */ 5865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}; 5875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 5885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* clkstate */ 5895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define CLK_NONE 0 5905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define CLK_SDONLY 1 5915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define CLK_PENDING 2 /* Not used yet */ 5925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define CLK_AVAIL 3 5935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 5948ae746543c8370fd04c28aaf8f185c1687b0e694Joe Perches#ifdef DEBUG 5955b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic int qcount[NUMPRIO]; 5965b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic int tx_packets[NUMPRIO]; 5978ae746543c8370fd04c28aaf8f185c1687b0e694Joe Perches#endif /* DEBUG */ 5985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 5995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define SDIO_DRIVE_STRENGTH 6 /* in milliamps */ 6005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 6015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define RETRYCHAN(chan) ((chan) == SDPCM_EVENT_CHANNEL) 6025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 6035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* Retry count for register access failures */ 6045b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic const uint retry_limit = 2; 6055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 6065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* Limit on rounding up frames */ 6075b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic const uint max_roundup = 512; 6085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 6095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define ALIGNMENT 4 6105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 6115b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic void pkt_align(struct sk_buff *p, int len, int align) 6125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 6135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint datalign; 6145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel datalign = (unsigned long)(p->data); 6155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel datalign = roundup(datalign, (align)) - datalign; 6165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (datalign) 6175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel skb_pull(p, datalign); 6185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel __skb_trim(p, len); 6195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 6205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 6215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* To check if there's window offered */ 622e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic bool data_ok(struct brcmf_sdio *bus) 6235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 6245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return (u8)(bus->tx_max - bus->tx_seq) != 0 && 6255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel ((u8)(bus->tx_max - bus->tx_seq) & 0x80) == 0; 6265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 6275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 6285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* 6295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * Reads a register in the SDIO hardware block. This block occupies a series of 6305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * adresses on the 32 bit backplane bus. 6315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 6325b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic void 633e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linr_sdreg32(struct brcmf_sdio *bus, u32 *regvar, u32 reg_offset, u32 *retryvar) 6345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 63599ba15cd75ed22e4ae86804ca2982a724e8102c2Franky Lin u8 idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV); 6365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel *retryvar = 0; 6375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel do { 6385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel *regvar = brcmf_sdcard_reg_read(bus->sdiodev, 63999ba15cd75ed22e4ae86804ca2982a724e8102c2Franky Lin bus->ci->c_inf[idx].base + reg_offset, 64099ba15cd75ed22e4ae86804ca2982a724e8102c2Franky Lin sizeof(u32)); 6415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } while (brcmf_sdcard_regfail(bus->sdiodev) && 6425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel (++(*retryvar) <= retry_limit)); 6435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (*retryvar) { 6445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->regfails += (*retryvar-1); 6455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (*retryvar > retry_limit) { 6465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "FAILED READ %Xh\n", reg_offset); 6475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel *regvar = 0; 6485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 6495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 6505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 6515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 6525b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic void 653e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linw_sdreg32(struct brcmf_sdio *bus, u32 regval, u32 reg_offset, u32 *retryvar) 6545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 65599ba15cd75ed22e4ae86804ca2982a724e8102c2Franky Lin u8 idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV); 6565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel *retryvar = 0; 6575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel do { 6585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdcard_reg_write(bus->sdiodev, 65999ba15cd75ed22e4ae86804ca2982a724e8102c2Franky Lin bus->ci->c_inf[idx].base + reg_offset, 6605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel sizeof(u32), regval); 6615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } while (brcmf_sdcard_regfail(bus->sdiodev) && 6625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel (++(*retryvar) <= retry_limit)); 6635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (*retryvar) { 6645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->regfails += (*retryvar-1); 6655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (*retryvar > retry_limit) 6665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "FAILED REGISTER WRITE %Xh\n", 6675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel reg_offset); 6685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 6695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 6705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 6715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define PKT_AVAILABLE() (intstatus & I_HMB_FRAME_IND) 6725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 6735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define HOSTINTMASK (I_HMB_SW_MASK | I_CHIPACTIVE) 6745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 6755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* Packet free applicable unconditionally for sdio and sdspi. 6765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * Conditional if bufpool was present for gspi bus. 6775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 678e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic void brcmf_sdbrcm_pktfree2(struct brcmf_sdio *bus, struct sk_buff *pkt) 6795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 6805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bus->usebufpool) 6815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmu_pkt_buf_free_skb(pkt); 6825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 6835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 6845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* Turn backplane clock on or off */ 685e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok) 6865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 6875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel int err; 6885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 clkctl, clkreq, devctl; 6895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel unsigned long timeout; 6905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 6915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(TRACE, "Enter\n"); 6925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 6935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel clkctl = 0; 6945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 6955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (on) { 6965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Request HT Avail */ 6975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel clkreq = 6985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ; 6995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 7005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, 7015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err); 7025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (err) { 7035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "HT Avail request error: %d\n", err); 7045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return -EBADE; 7055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 7065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 7075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Check current status */ 7085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel clkctl = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, 7095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SBSDIO_FUNC1_CHIPCLKCSR, &err); 7105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (err) { 7115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "HT Avail read error: %d\n", err); 7125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return -EBADE; 7135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 7145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 7155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Go to pending and await interrupt if appropriate */ 7165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (!SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) { 7175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Allow only clock-available interrupt */ 7185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel devctl = brcmf_sdcard_cfg_read(bus->sdiodev, 7195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SDIO_FUNC_1, 7205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SBSDIO_DEVICE_CTL, &err); 7215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (err) { 7225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "Devctl error setting CA: %d\n", 7235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel err); 7245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return -EBADE; 7255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 7265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 7275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel devctl |= SBSDIO_DEVCTL_CA_INT_ONLY; 7285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, 7295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SBSDIO_DEVICE_CTL, devctl, &err); 7305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(INFO, "CLKCTL: set PENDING\n"); 7315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->clkstate = CLK_PENDING; 7325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 7335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return 0; 7345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } else if (bus->clkstate == CLK_PENDING) { 7355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Cancel CA-only interrupt filter */ 7365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel devctl = 7375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, 7385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SBSDIO_DEVICE_CTL, &err); 7395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; 7405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, 7415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SBSDIO_DEVICE_CTL, devctl, &err); 7425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 7435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 7445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Otherwise, wait here (polling) for HT Avail */ 7455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel timeout = jiffies + 7465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel msecs_to_jiffies(PMU_MAX_TRANSITION_DLY/1000); 7475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel while (!SBSDIO_CLKAV(clkctl, bus->alp_only)) { 7485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel clkctl = brcmf_sdcard_cfg_read(bus->sdiodev, 7495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SDIO_FUNC_1, 7505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SBSDIO_FUNC1_CHIPCLKCSR, 7515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel &err); 7525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (time_after(jiffies, timeout)) 7535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel break; 7545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel else 7555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel usleep_range(5000, 10000); 7565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 7575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (err) { 7585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "HT Avail request error: %d\n", err); 7595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return -EBADE; 7605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 7615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) { 7625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "HT Avail timeout (%d): clkctl 0x%02x\n", 7635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel PMU_MAX_TRANSITION_DLY, clkctl); 7645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return -EBADE; 7655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 7665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 7675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Mark clock available */ 7685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->clkstate = CLK_AVAIL; 7695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(INFO, "CLKCTL: turned ON\n"); 7705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 7718ae746543c8370fd04c28aaf8f185c1687b0e694Joe Perches#if defined(DEBUG) 77223677ce3172fcb93522a1df077d21019e73ee1e3Joe Perches if (!bus->alp_only) { 7735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (SBSDIO_ALPONLY(clkctl)) 7745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "HT Clock should be on\n"); 7755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 7768ae746543c8370fd04c28aaf8f185c1687b0e694Joe Perches#endif /* defined (DEBUG) */ 7775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 7785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->activity = true; 7795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } else { 7805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel clkreq = 0; 7815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 7825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bus->clkstate == CLK_PENDING) { 7835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Cancel CA-only interrupt filter */ 7845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel devctl = brcmf_sdcard_cfg_read(bus->sdiodev, 7855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SDIO_FUNC_1, 7865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SBSDIO_DEVICE_CTL, &err); 7875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; 7885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, 7895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SBSDIO_DEVICE_CTL, devctl, &err); 7905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 7915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 7925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->clkstate = CLK_SDONLY; 7935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, 7945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err); 7955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(INFO, "CLKCTL: turned OFF\n"); 7965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (err) { 7975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "Failed access turning clock off: %d\n", 7985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel err); 7995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return -EBADE; 8005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 8015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 8025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return 0; 8035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 8045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 8055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* Change idle/active SD state */ 806e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic int brcmf_sdbrcm_sdclk(struct brcmf_sdio *bus, bool on) 8075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 8085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(TRACE, "Enter\n"); 8095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 8105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (on) 8115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->clkstate = CLK_SDONLY; 8125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel else 8135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->clkstate = CLK_NONE; 8145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 8155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return 0; 8165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 8175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 8185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* Transition SD and backplane clock readiness */ 819e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic int brcmf_sdbrcm_clkctl(struct brcmf_sdio *bus, uint target, bool pendok) 8205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 8218ae746543c8370fd04c28aaf8f185c1687b0e694Joe Perches#ifdef DEBUG 8225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint oldstate = bus->clkstate; 8238ae746543c8370fd04c28aaf8f185c1687b0e694Joe Perches#endif /* DEBUG */ 8245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 8255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(TRACE, "Enter\n"); 8265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 8275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Early exit if we're already there */ 8285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bus->clkstate == target) { 8295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (target == CLK_AVAIL) { 8305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS); 8315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->activity = true; 8325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 8335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return 0; 8345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 8355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 8365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel switch (target) { 8375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel case CLK_AVAIL: 8385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Make sure SD clock is available */ 8395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bus->clkstate == CLK_NONE) 8405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_sdclk(bus, true); 8415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Now request HT Avail on the backplane */ 8425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_htclk(bus, true, pendok); 8435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS); 8445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->activity = true; 8455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel break; 8465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 8475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel case CLK_SDONLY: 8485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Remove HT request, or bring up SD clock */ 8495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bus->clkstate == CLK_NONE) 8505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_sdclk(bus, true); 8515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel else if (bus->clkstate == CLK_AVAIL) 8525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_htclk(bus, false, false); 8535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel else 8545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "request for %d -> %d\n", 8555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->clkstate, target); 8565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS); 8575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel break; 8585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 8595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel case CLK_NONE: 8605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Make sure to remove HT request */ 8615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bus->clkstate == CLK_AVAIL) 8625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_htclk(bus, false, false); 8635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Now remove the SD clock */ 8645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_sdclk(bus, false); 8655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_wd_timer(bus, 0); 8665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel break; 8675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 8688ae746543c8370fd04c28aaf8f185c1687b0e694Joe Perches#ifdef DEBUG 8695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(INFO, "%d -> %d\n", oldstate, bus->clkstate); 8708ae746543c8370fd04c28aaf8f185c1687b0e694Joe Perches#endif /* DEBUG */ 8715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 8725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return 0; 8735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 8745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 875e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic int brcmf_sdbrcm_bussleep(struct brcmf_sdio *bus, bool sleep) 8765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 8775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint retries = 0; 8785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 8795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(INFO, "request %s (currently %s)\n", 8805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel sleep ? "SLEEP" : "WAKE", 8815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->sleeping ? "SLEEP" : "WAKE"); 8825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 8835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Done if we're already in the requested state */ 8845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (sleep == bus->sleeping) 8855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return 0; 8865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 8875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Going to sleep: set the alarm and turn off the lights... */ 8885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (sleep) { 8895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Don't sleep if something is pending */ 8905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bus->dpc_sched || bus->rxskip || pktq_len(&bus->txq)) 8915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return -EBUSY; 8925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 8935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Make sure the controller has the bus up */ 8945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); 8955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 8965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Tell device to start using OOB wakeup */ 8975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel w_sdreg32(bus, SMB_USE_OOB, 8985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel offsetof(struct sdpcmd_regs, tosbmailbox), &retries); 8995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (retries > retry_limit) 9005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"); 9015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 9025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Turn off our contribution to the HT clock request */ 9035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false); 9045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 9055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, 9065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SBSDIO_FUNC1_CHIPCLKCSR, 9075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SBSDIO_FORCE_HW_CLKREQ_OFF, NULL); 9085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 9095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Isolate the bus */ 910718897eb3f90a47a56acb504762d521388a3231cFranky Lin brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, 911718897eb3f90a47a56acb504762d521388a3231cFranky Lin SBSDIO_DEVICE_CTL, 912718897eb3f90a47a56acb504762d521388a3231cFranky Lin SBSDIO_DEVCTL_PADS_ISO, NULL); 9135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 9145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Change state */ 9155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->sleeping = true; 9165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 9175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } else { 9185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Waking up: bus power up is ok, set local state */ 9195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 9205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, 9215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL); 9225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 9235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Make sure the controller has the bus up */ 9245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); 9255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 9265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Send misc interrupt to indicate OOB not needed */ 9275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel w_sdreg32(bus, 0, offsetof(struct sdpcmd_regs, tosbmailboxdata), 9285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel &retries); 9295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (retries <= retry_limit) 9305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel w_sdreg32(bus, SMB_DEV_INT, 9315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel offsetof(struct sdpcmd_regs, tosbmailbox), 9325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel &retries); 9335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 9345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (retries > retry_limit) 9355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "CANNOT SIGNAL CHIP TO CLEAR OOB!!\n"); 9365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 9375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Make sure we have SD bus access */ 9385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false); 9395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 9405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Change state */ 9415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->sleeping = false; 9425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 9435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 9445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return 0; 9455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 9465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 947e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic void bus_wake(struct brcmf_sdio *bus) 9485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 9495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bus->sleeping) 9505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_bussleep(bus, false); 9515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 9525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 953e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic u32 brcmf_sdbrcm_hostmail(struct brcmf_sdio *bus) 9545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 9555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 intstatus = 0; 9565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 hmb_data; 9575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 fcbits; 9585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint retries = 0; 9595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 9605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(TRACE, "Enter\n"); 9615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 9625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Read mailbox data and ack that we did so */ 9635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel r_sdreg32(bus, &hmb_data, 9645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel offsetof(struct sdpcmd_regs, tohostmailboxdata), &retries); 9655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 9665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (retries <= retry_limit) 9675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel w_sdreg32(bus, SMB_INT_ACK, 9685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel offsetof(struct sdpcmd_regs, tosbmailbox), &retries); 9695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->f1regdata += 2; 9705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 9715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Dongle recomposed rx frames, accept them again */ 9725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (hmb_data & HMB_DATA_NAKHANDLED) { 9735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(INFO, "Dongle reports NAK handled, expect rtx of %d\n", 9745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->rx_seq); 9755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (!bus->rxskip) 9765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "unexpected NAKHANDLED!\n"); 9775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 9785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->rxskip = false; 9795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel intstatus |= I_HMB_FRAME_IND; 9805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 9815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 9825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* 9835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * DEVREADY does not occur with gSPI. 9845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 9855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (hmb_data & (HMB_DATA_DEVREADY | HMB_DATA_FWREADY)) { 9865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->sdpcm_ver = 9875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel (hmb_data & HMB_DATA_VERSION_MASK) >> 9885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel HMB_DATA_VERSION_SHIFT; 9895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bus->sdpcm_ver != SDPCM_PROT_VERSION) 9905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "Version mismatch, dongle reports %d, " 9915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel "expecting %d\n", 9925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->sdpcm_ver, SDPCM_PROT_VERSION); 9935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel else 9945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(INFO, "Dongle ready, protocol version %d\n", 9955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->sdpcm_ver); 9965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 9975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 9985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* 9995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * Flow Control has been moved into the RX headers and this out of band 10005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * method isn't used any more. 10015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * remaining backward compatible with older dongles. 10025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 10035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (hmb_data & HMB_DATA_FC) { 10045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel fcbits = (hmb_data & HMB_DATA_FCDATA_MASK) >> 10055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel HMB_DATA_FCDATA_SHIFT; 10065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 10075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (fcbits & ~bus->flowcontrol) 10085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->fc_xoff++; 10095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 10105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bus->flowcontrol & ~fcbits) 10115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->fc_xon++; 10125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 10135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->fc_rcvd++; 10145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->flowcontrol = fcbits; 10155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 10165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 10175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Shouldn't be any others */ 10185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (hmb_data & ~(HMB_DATA_DEVREADY | 10195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel HMB_DATA_NAKHANDLED | 10205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel HMB_DATA_FC | 10215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel HMB_DATA_FWREADY | 10225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel HMB_DATA_FCDATA_MASK | HMB_DATA_VERSION_MASK)) 10235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "Unknown mailbox data content: 0x%02x\n", 10245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel hmb_data); 10255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 10265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return intstatus; 10275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 10285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 1029e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic void brcmf_sdbrcm_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx) 10305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 10315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint retries = 0; 10325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u16 lastrbc; 10335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 hi, lo; 10345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel int err; 10355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 10365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "%sterminate frame%s\n", 10375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel abort ? "abort command, " : "", 10385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel rtx ? ", send NAK" : ""); 10395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 10405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (abort) 10415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2); 10425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 10435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, 10445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SBSDIO_FUNC1_FRAMECTRL, 10455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SFC_RF_TERM, &err); 10465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->f1regdata++; 10475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 10485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Wait until the packet has been flushed (device/FIFO stable) */ 10495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel for (lastrbc = retries = 0xffff; retries > 0; retries--) { 10505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel hi = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, 10515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SBSDIO_FUNC1_RFRAMEBCHI, NULL); 10525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel lo = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, 10535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SBSDIO_FUNC1_RFRAMEBCLO, NULL); 10545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->f1regdata += 2; 10555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 10565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if ((hi == 0) && (lo == 0)) 10575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel break; 10585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 10595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if ((hi > (lastrbc >> 8)) && (lo > (lastrbc & 0x00ff))) { 10605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "count growing: last 0x%04x now 0x%04x\n", 10615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel lastrbc, (hi << 8) + lo); 10625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 10635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel lastrbc = (hi << 8) + lo; 10645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 10655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 10665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (!retries) 10675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "count never zeroed: last 0x%04x\n", lastrbc); 10685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel else 10695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(INFO, "flush took %d iterations\n", 0xffff - retries); 10705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 10715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (rtx) { 10725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->rxrtx++; 10735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel w_sdreg32(bus, SMB_NAK, 10745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel offsetof(struct sdpcmd_regs, tosbmailbox), &retries); 10755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 10765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->f1regdata++; 10775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (retries <= retry_limit) 10785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->rxskip = true; 10795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 10805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 10815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Clear partial in any case */ 10825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->nextlen = 0; 10835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 10845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* If we can't reach the device, signal failure */ 10855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (err || brcmf_sdcard_regfail(bus->sdiodev)) 1086712ac5b37a3348cac4e040c551a6ca6186d33682Franky Lin bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN; 10875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 10885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 108920e5ca16397648811a9e1ad531360c843e005a57Arend van Spriel/* copy a buffer into a pkt buffer chain */ 1090e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic uint brcmf_sdbrcm_glom_from_buf(struct brcmf_sdio *bus, uint len) 109120e5ca16397648811a9e1ad531360c843e005a57Arend van Spriel{ 109220e5ca16397648811a9e1ad531360c843e005a57Arend van Spriel uint n, ret = 0; 109320e5ca16397648811a9e1ad531360c843e005a57Arend van Spriel struct sk_buff *p; 109420e5ca16397648811a9e1ad531360c843e005a57Arend van Spriel u8 *buf; 109520e5ca16397648811a9e1ad531360c843e005a57Arend van Spriel 109620e5ca16397648811a9e1ad531360c843e005a57Arend van Spriel buf = bus->dataptr; 109720e5ca16397648811a9e1ad531360c843e005a57Arend van Spriel 109820e5ca16397648811a9e1ad531360c843e005a57Arend van Spriel /* copy the data */ 1099b83db862ffb871e3131e5d2160c741b288eea9aaArend van Spriel skb_queue_walk(&bus->glom, p) { 110020e5ca16397648811a9e1ad531360c843e005a57Arend van Spriel n = min_t(uint, p->len, len); 110120e5ca16397648811a9e1ad531360c843e005a57Arend van Spriel memcpy(p->data, buf, n); 110220e5ca16397648811a9e1ad531360c843e005a57Arend van Spriel buf += n; 110320e5ca16397648811a9e1ad531360c843e005a57Arend van Spriel len -= n; 110420e5ca16397648811a9e1ad531360c843e005a57Arend van Spriel ret += n; 1105b83db862ffb871e3131e5d2160c741b288eea9aaArend van Spriel if (!len) 1106b83db862ffb871e3131e5d2160c741b288eea9aaArend van Spriel break; 110720e5ca16397648811a9e1ad531360c843e005a57Arend van Spriel } 110820e5ca16397648811a9e1ad531360c843e005a57Arend van Spriel 110920e5ca16397648811a9e1ad531360c843e005a57Arend van Spriel return ret; 111020e5ca16397648811a9e1ad531360c843e005a57Arend van Spriel} 111120e5ca16397648811a9e1ad531360c843e005a57Arend van Spriel 11129a95e60e0610bb8ec39c74d2c8546514a76428dfArend van Spriel/* return total length of buffer chain */ 1113e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic uint brcmf_sdbrcm_glom_len(struct brcmf_sdio *bus) 11149a95e60e0610bb8ec39c74d2c8546514a76428dfArend van Spriel{ 11159a95e60e0610bb8ec39c74d2c8546514a76428dfArend van Spriel struct sk_buff *p; 11169a95e60e0610bb8ec39c74d2c8546514a76428dfArend van Spriel uint total; 11179a95e60e0610bb8ec39c74d2c8546514a76428dfArend van Spriel 11189a95e60e0610bb8ec39c74d2c8546514a76428dfArend van Spriel total = 0; 11199a95e60e0610bb8ec39c74d2c8546514a76428dfArend van Spriel skb_queue_walk(&bus->glom, p) 11209a95e60e0610bb8ec39c74d2c8546514a76428dfArend van Spriel total += p->len; 11219a95e60e0610bb8ec39c74d2c8546514a76428dfArend van Spriel return total; 11229a95e60e0610bb8ec39c74d2c8546514a76428dfArend van Spriel} 11239a95e60e0610bb8ec39c74d2c8546514a76428dfArend van Spriel 1124e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic void brcmf_sdbrcm_free_glom(struct brcmf_sdio *bus) 1125046808daf9f6b8c5275861330d4f8c2e6cfe3c31Arend van Spriel{ 1126046808daf9f6b8c5275861330d4f8c2e6cfe3c31Arend van Spriel struct sk_buff *cur, *next; 1127046808daf9f6b8c5275861330d4f8c2e6cfe3c31Arend van Spriel 1128046808daf9f6b8c5275861330d4f8c2e6cfe3c31Arend van Spriel skb_queue_walk_safe(&bus->glom, cur, next) { 1129046808daf9f6b8c5275861330d4f8c2e6cfe3c31Arend van Spriel skb_unlink(cur, &bus->glom); 1130046808daf9f6b8c5275861330d4f8c2e6cfe3c31Arend van Spriel brcmu_pkt_buf_free_skb(cur); 1131046808daf9f6b8c5275861330d4f8c2e6cfe3c31Arend van Spriel } 1132046808daf9f6b8c5275861330d4f8c2e6cfe3c31Arend van Spriel} 1133046808daf9f6b8c5275861330d4f8c2e6cfe3c31Arend van Spriel 1134e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) 11355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 11365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u16 dlen, totlen; 11375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 *dptr, num = 0; 11385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 11395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u16 sublen, check; 11400b45bf74f91e781b74bfadb8bb08ef341b6befd3Arend van Spriel struct sk_buff *pfirst, *pnext; 11415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 11425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel int errcode; 11435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 chan, seq, doff, sfdoff; 11445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 txmax; 11455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 11465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel int ifidx = 0; 11475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bool usechain = bus->use_rxchain; 11485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 11495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* If packets, issue read(s) and send up packet chain */ 11505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Return sequence numbers consumed? */ 11515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 1152b83db862ffb871e3131e5d2160c741b288eea9aaArend van Spriel brcmf_dbg(TRACE, "start: glomd %p glom %p\n", 1153b83db862ffb871e3131e5d2160c741b288eea9aaArend van Spriel bus->glomd, skb_peek(&bus->glom)); 11545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 11555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* If there's a descriptor, generate the packet chain */ 11565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bus->glomd) { 11570b45bf74f91e781b74bfadb8bb08ef341b6befd3Arend van Spriel pfirst = pnext = NULL; 11585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel dlen = (u16) (bus->glomd->len); 11595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel dptr = bus->glomd->data; 11605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (!dlen || (dlen & 1)) { 11615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "bad glomd len(%d), ignore descriptor\n", 11625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel dlen); 11635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel dlen = 0; 11645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 11655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 11665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel for (totlen = num = 0; dlen; num++) { 11675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Get (and move past) next length */ 11685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel sublen = get_unaligned_le16(dptr); 11695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel dlen -= sizeof(u16); 11705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel dptr += sizeof(u16); 11715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if ((sublen < SDPCM_HDRLEN) || 11725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel ((num == 0) && (sublen < (2 * SDPCM_HDRLEN)))) { 11735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "descriptor len %d bad: %d\n", 11745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel num, sublen); 11755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel pnext = NULL; 11765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel break; 11775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 11785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (sublen % BRCMF_SDALIGN) { 11795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "sublen %d not multiple of %d\n", 11805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel sublen, BRCMF_SDALIGN); 11815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel usechain = false; 11825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 11835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel totlen += sublen; 11845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 11855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* For last frame, adjust read len so total 11865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel is a block multiple */ 11875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (!dlen) { 11885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel sublen += 11895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel (roundup(totlen, bus->blocksize) - totlen); 11905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel totlen = roundup(totlen, bus->blocksize); 11915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 11925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 11935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Allocate/chain packet for next subframe */ 11945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel pnext = brcmu_pkt_buf_get_skb(sublen + BRCMF_SDALIGN); 11955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (pnext == NULL) { 11965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "bcm_pkt_buf_get_skb failed, num %d len %d\n", 11975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel num, sublen); 11985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel break; 11995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 1200b83db862ffb871e3131e5d2160c741b288eea9aaArend van Spriel skb_queue_tail(&bus->glom, pnext); 12015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 12025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Adhere to start alignment requirements */ 12035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel pkt_align(pnext, sublen, BRCMF_SDALIGN); 12045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 12055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 12065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* If all allocations succeeded, save packet chain 12075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel in bus structure */ 12085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (pnext) { 12095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(GLOM, "allocated %d-byte packet chain for %d subframes\n", 12105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel totlen, num); 12115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (BRCMF_GLOM_ON() && bus->nextlen && 12125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel totlen != bus->nextlen) { 12135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(GLOM, "glomdesc mismatch: nextlen %d glomdesc %d rxseq %d\n", 12145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->nextlen, totlen, rxseq); 12155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 12165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel pfirst = pnext = NULL; 12175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } else { 1218046808daf9f6b8c5275861330d4f8c2e6cfe3c31Arend van Spriel brcmf_sdbrcm_free_glom(bus); 12195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel num = 0; 12205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 12215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 12225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Done with descriptor packet */ 12235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmu_pkt_buf_free_skb(bus->glomd); 12245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->glomd = NULL; 12255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->nextlen = 0; 12265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 12275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 12285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Ok -- either we just generated a packet chain, 12295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel or had one from before */ 1230b83db862ffb871e3131e5d2160c741b288eea9aaArend van Spriel if (!skb_queue_empty(&bus->glom)) { 12315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (BRCMF_GLOM_ON()) { 12325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(GLOM, "try superframe read, packet chain:\n"); 1233b83db862ffb871e3131e5d2160c741b288eea9aaArend van Spriel skb_queue_walk(&bus->glom, pnext) { 12345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(GLOM, " %p: %p len 0x%04x (%d)\n", 12355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel pnext, (u8 *) (pnext->data), 12365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel pnext->len, pnext->len); 12375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 12385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 12395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 1240b83db862ffb871e3131e5d2160c741b288eea9aaArend van Spriel pfirst = skb_peek(&bus->glom); 12419a95e60e0610bb8ec39c74d2c8546514a76428dfArend van Spriel dlen = (u16) brcmf_sdbrcm_glom_len(bus); 12425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 12435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Do an SDIO read for the superframe. Configurable iovar to 12445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * read directly into the chained packet, or allocate a large 12455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * packet and and copy into the chain. 12465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 12475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (usechain) { 12485adfeb632c52a6c15e98fa6465bdade6fff915d9Arend van Spriel errcode = brcmf_sdcard_recv_chain(bus->sdiodev, 12495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->sdiodev->sbwad, 12505adfeb632c52a6c15e98fa6465bdade6fff915d9Arend van Spriel SDIO_FUNC_2, F2SYNC, &bus->glom); 12515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } else if (bus->dataptr) { 12525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel errcode = brcmf_sdcard_recv_buf(bus->sdiodev, 12535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->sdiodev->sbwad, 12545adfeb632c52a6c15e98fa6465bdade6fff915d9Arend van Spriel SDIO_FUNC_2, F2SYNC, 12555adfeb632c52a6c15e98fa6465bdade6fff915d9Arend van Spriel bus->dataptr, dlen); 125620e5ca16397648811a9e1ad531360c843e005a57Arend van Spriel sublen = (u16) brcmf_sdbrcm_glom_from_buf(bus, dlen); 12575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (sublen != dlen) { 12585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "FAILED TO COPY, dlen %d sublen %d\n", 12595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel dlen, sublen); 12605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel errcode = -1; 12615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 12625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel pnext = NULL; 12635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } else { 12645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "COULDN'T ALLOC %d-BYTE GLOM, FORCE FAILURE\n", 12655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel dlen); 12665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel errcode = -1; 12675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 12685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->f2rxdata++; 12695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 12705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* On failure, kill the superframe, allow a couple retries */ 12715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (errcode < 0) { 12725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "glom read of %d bytes failed: %d\n", 12735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel dlen, errcode); 1274719f2733baa1e6a6a782c5109bfe054431db4259Franky Lin bus->sdiodev->bus_if->dstats.rx_errors++; 12755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 12765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bus->glomerr++ < 3) { 12775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_rxfail(bus, true, true); 12785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } else { 12795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->glomerr = 0; 12805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_rxfail(bus, true, false); 12815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->rxglomfail++; 1282046808daf9f6b8c5275861330d4f8c2e6cfe3c31Arend van Spriel brcmf_sdbrcm_free_glom(bus); 12835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 12845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return 0; 12855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 12861e02382979dd422e3b1bdb45545a0699497e3692Joe Perches 12871e02382979dd422e3b1bdb45545a0699497e3692Joe Perches brcmf_dbg_hex_dump(BRCMF_GLOM_ON(), 12881e02382979dd422e3b1bdb45545a0699497e3692Joe Perches pfirst->data, min_t(int, pfirst->len, 48), 12891e02382979dd422e3b1bdb45545a0699497e3692Joe Perches "SUPERFRAME:\n"); 12905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 12915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Validate the superframe header */ 12925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel dptr = (u8 *) (pfirst->data); 12935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel sublen = get_unaligned_le16(dptr); 12945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel check = get_unaligned_le16(dptr + sizeof(u16)); 12955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 12965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]); 12975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]); 12985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->nextlen = dptr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET]; 12995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if ((bus->nextlen << 4) > MAX_RX_DATASZ) { 13005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(INFO, "nextlen too large (%d) seq %d\n", 13015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->nextlen, seq); 13025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->nextlen = 0; 13035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 13045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); 13055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel txmax = SDPCM_WINDOW_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); 13065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 13075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel errcode = 0; 13085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if ((u16)~(sublen ^ check)) { 13095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "(superframe): HW hdr error: len/check 0x%04x/0x%04x\n", 13105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel sublen, check); 13115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel errcode = -1; 13125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } else if (roundup(sublen, bus->blocksize) != dlen) { 13135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "(superframe): len 0x%04x, rounded 0x%04x, expect 0x%04x\n", 13145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel sublen, roundup(sublen, bus->blocksize), 13155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel dlen); 13165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel errcode = -1; 13175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } else if (SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]) != 13185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SDPCM_GLOM_CHANNEL) { 13195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "(superframe): bad channel %d\n", 13205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SDPCM_PACKET_CHANNEL( 13215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel &dptr[SDPCM_FRAMETAG_LEN])); 13225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel errcode = -1; 13235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } else if (SDPCM_GLOMDESC(&dptr[SDPCM_FRAMETAG_LEN])) { 13245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "(superframe): got 2nd descriptor?\n"); 13255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel errcode = -1; 13265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } else if ((doff < SDPCM_HDRLEN) || 13275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel (doff > (pfirst->len - SDPCM_HDRLEN))) { 13285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "(superframe): Bad data offset %d: HW %d pkt %d min %d\n", 13295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel doff, sublen, pfirst->len, SDPCM_HDRLEN); 13305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel errcode = -1; 13315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 13325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 13335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Check sequence number of superframe SW header */ 13345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (rxseq != seq) { 13355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(INFO, "(superframe) rx_seq %d, expected %d\n", 13365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel seq, rxseq); 13375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->rx_badseq++; 13385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel rxseq = seq; 13395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 13405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 13415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Check window for sanity */ 13425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if ((u8) (txmax - bus->tx_seq) > 0x40) { 13435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "unlikely tx max %d with tx_seq %d\n", 13445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel txmax, bus->tx_seq); 13455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel txmax = bus->tx_seq + 2; 13465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 13475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->tx_max = txmax; 13485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 13495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Remove superframe header, remember offset */ 13505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel skb_pull(pfirst, doff); 13515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel sfdoff = doff; 13520b45bf74f91e781b74bfadb8bb08ef341b6befd3Arend van Spriel num = 0; 13535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 13545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Validate all the subframe headers */ 13550b45bf74f91e781b74bfadb8bb08ef341b6befd3Arend van Spriel skb_queue_walk(&bus->glom, pnext) { 13560b45bf74f91e781b74bfadb8bb08ef341b6befd3Arend van Spriel /* leave when invalid subframe is found */ 13570b45bf74f91e781b74bfadb8bb08ef341b6befd3Arend van Spriel if (errcode) 13580b45bf74f91e781b74bfadb8bb08ef341b6befd3Arend van Spriel break; 13590b45bf74f91e781b74bfadb8bb08ef341b6befd3Arend van Spriel 13605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel dptr = (u8 *) (pnext->data); 13615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel dlen = (u16) (pnext->len); 13625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel sublen = get_unaligned_le16(dptr); 13635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel check = get_unaligned_le16(dptr + sizeof(u16)); 13645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]); 13655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); 13661e02382979dd422e3b1bdb45545a0699497e3692Joe Perches brcmf_dbg_hex_dump(BRCMF_GLOM_ON(), 13671e02382979dd422e3b1bdb45545a0699497e3692Joe Perches dptr, 32, "subframe:\n"); 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 14321e02382979dd422e3b1bdb45545a0699497e3692Joe Perches brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && BRCMF_DATA_ON(), 14331e02382979dd422e3b1bdb45545a0699497e3692Joe Perches dptr, dlen, "Rx Subframe Data:\n"); 14345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 14355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel __skb_trim(pfirst, sublen); 14365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel skb_pull(pfirst, doff); 14375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 14385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (pfirst->len == 0) { 14390b45bf74f91e781b74bfadb8bb08ef341b6befd3Arend van Spriel skb_unlink(pfirst, &bus->glom); 14405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmu_pkt_buf_free_skb(pfirst); 14415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel continue; 1442d5625ee66f82162acb7189c1974e688ebc178cf3Franky Lin } else if (brcmf_proto_hdrpull(bus->sdiodev->dev, 1443d5625ee66f82162acb7189c1974e688ebc178cf3Franky Lin &ifidx, pfirst) != 0) { 14445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "rx protocol error\n"); 1445719f2733baa1e6a6a782c5109bfe054431db4259Franky Lin bus->sdiodev->bus_if->dstats.rx_errors++; 14460b45bf74f91e781b74bfadb8bb08ef341b6befd3Arend van Spriel skb_unlink(pfirst, &bus->glom); 14475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmu_pkt_buf_free_skb(pfirst); 14485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel continue; 14495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 14505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 14511e02382979dd422e3b1bdb45545a0699497e3692Joe Perches brcmf_dbg_hex_dump(BRCMF_GLOM_ON(), 14521e02382979dd422e3b1bdb45545a0699497e3692Joe Perches pfirst->data, 14531e02382979dd422e3b1bdb45545a0699497e3692Joe Perches min_t(int, pfirst->len, 32), 14541e02382979dd422e3b1bdb45545a0699497e3692Joe Perches "subframe %d to stack, %p (%p/%d) nxt/lnk %p/%p\n", 14551e02382979dd422e3b1bdb45545a0699497e3692Joe Perches bus->glom.qlen, pfirst, pfirst->data, 14561e02382979dd422e3b1bdb45545a0699497e3692Joe Perches pfirst->len, pfirst->next, 14571e02382979dd422e3b1bdb45545a0699497e3692Joe Perches pfirst->prev); 14585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 14590b45bf74f91e781b74bfadb8bb08ef341b6befd3Arend van Spriel /* sent any remaining packets up */ 14600b45bf74f91e781b74bfadb8bb08ef341b6befd3Arend van Spriel if (bus->glom.qlen) { 14615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel up(&bus->sdsem); 1462228bb43d5d82549c43eee29e12d7632d4df4e4dfFranky Lin brcmf_rx_frame(bus->sdiodev->dev, ifidx, &bus->glom); 14635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel down(&bus->sdsem); 14645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 14655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 14665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->rxglomframes++; 14670b45bf74f91e781b74bfadb8bb08ef341b6befd3Arend van Spriel bus->rxglompkts += bus->glom.qlen; 14685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 14695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return num; 14705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 14715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 1472e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic int brcmf_sdbrcm_dcmd_resp_wait(struct brcmf_sdio *bus, uint *condition, 14735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bool *pending) 14745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 14755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel DECLARE_WAITQUEUE(wait, current); 14765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel int timeout = msecs_to_jiffies(DCMD_RESP_TIMEOUT); 14775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 14785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Wait until control frame is available */ 14795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel add_wait_queue(&bus->dcmd_resp_wait, &wait); 14805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel set_current_state(TASK_INTERRUPTIBLE); 14815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 14825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel while (!(*condition) && (!signal_pending(current) && timeout)) 14835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel timeout = schedule_timeout(timeout); 14845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 14855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (signal_pending(current)) 14865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel *pending = true; 14875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 14885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel set_current_state(TASK_RUNNING); 14895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel remove_wait_queue(&bus->dcmd_resp_wait, &wait); 14905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 14915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return timeout; 14925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 14935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 1494e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic int brcmf_sdbrcm_dcmd_resp_wake(struct brcmf_sdio *bus) 14955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 14965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (waitqueue_active(&bus->dcmd_resp_wait)) 14975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wake_up_interruptible(&bus->dcmd_resp_wait); 14985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 14995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return 0; 15005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 15015b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic void 1502e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linbrcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff) 15035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 15045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint rdlen, pad; 15055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 15065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel int sdret; 15075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 15085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(TRACE, "Enter\n"); 15095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 15105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Set rxctl for frame (w/optional alignment) */ 15115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->rxctl = bus->rxbuf; 15125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->rxctl += BRCMF_FIRSTREAD; 15135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel pad = ((unsigned long)bus->rxctl % BRCMF_SDALIGN); 15145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (pad) 15155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->rxctl += (BRCMF_SDALIGN - pad); 15165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->rxctl -= BRCMF_FIRSTREAD; 15175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 15185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Copy the already-read portion over */ 15195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel memcpy(bus->rxctl, hdr, BRCMF_FIRSTREAD); 15205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (len <= BRCMF_FIRSTREAD) 15215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto gotpkt; 15225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 15235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Raise rdlen to next SDIO block to avoid tail command */ 15245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel rdlen = len - BRCMF_FIRSTREAD; 15255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) { 15265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel pad = bus->blocksize - (rdlen % bus->blocksize); 15275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if ((pad <= bus->roundup) && (pad < bus->blocksize) && 1528b01a6b3ca714e2bb86ee387aee487c7360363c93Franky Lin ((len + pad) < bus->sdiodev->bus_if->maxctl)) 15295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel rdlen += pad; 15305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } else if (rdlen % BRCMF_SDALIGN) { 15315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel rdlen += BRCMF_SDALIGN - (rdlen % BRCMF_SDALIGN); 15325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 15335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 15345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Satisfy length-alignment requirements */ 15355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (rdlen & (ALIGNMENT - 1)) 15365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel rdlen = roundup(rdlen, ALIGNMENT); 15375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 15385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Drop if the read is too big or it exceeds our maximum */ 1539b01a6b3ca714e2bb86ee387aee487c7360363c93Franky Lin if ((rdlen + BRCMF_FIRSTREAD) > bus->sdiodev->bus_if->maxctl) { 15405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "%d-byte control read exceeds %d-byte buffer\n", 1541b01a6b3ca714e2bb86ee387aee487c7360363c93Franky Lin rdlen, bus->sdiodev->bus_if->maxctl); 1542719f2733baa1e6a6a782c5109bfe054431db4259Franky Lin bus->sdiodev->bus_if->dstats.rx_errors++; 15435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_rxfail(bus, false, false); 15445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto done; 15455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 15465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 1547b01a6b3ca714e2bb86ee387aee487c7360363c93Franky Lin if ((len - doff) > bus->sdiodev->bus_if->maxctl) { 15485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "%d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n", 1549b01a6b3ca714e2bb86ee387aee487c7360363c93Franky Lin len, len - doff, bus->sdiodev->bus_if->maxctl); 1550719f2733baa1e6a6a782c5109bfe054431db4259Franky Lin bus->sdiodev->bus_if->dstats.rx_errors++; 15515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->rx_toolong++; 15525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_rxfail(bus, false, false); 15535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto done; 15545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 15555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 15565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Read remainder of frame body into the rxctl buffer */ 15575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel sdret = brcmf_sdcard_recv_buf(bus->sdiodev, 15585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->sdiodev->sbwad, 15595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SDIO_FUNC_2, 15605adfeb632c52a6c15e98fa6465bdade6fff915d9Arend van Spriel F2SYNC, (bus->rxctl + BRCMF_FIRSTREAD), rdlen); 15615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->f2rxdata++; 15625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 15635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Control frame failures need retransmission */ 15645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (sdret < 0) { 15655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "read %d control bytes failed: %d\n", 15665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel rdlen, sdret); 15675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->rxc_errors++; 15685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_rxfail(bus, true, true); 15695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto done; 15705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 15715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 15725b435de0d786869c95d1962121af0d7df2542009Arend van Sprielgotpkt: 15735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 15741e02382979dd422e3b1bdb45545a0699497e3692Joe Perches brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && BRCMF_CTL_ON(), 15751e02382979dd422e3b1bdb45545a0699497e3692Joe Perches bus->rxctl, len, "RxCtrl:\n"); 15765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 15775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Point to valid data and indicate its length */ 15785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->rxctl += doff; 15795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->rxlen = len - doff; 15805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 15815b435de0d786869c95d1962121af0d7df2542009Arend van Sprieldone: 15825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Awake any waiters */ 15835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_dcmd_resp_wake(bus); 15845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 15855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 15865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* Pad read to blocksize for efficiency */ 1587e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic void brcmf_pad(struct brcmf_sdio *bus, u16 *pad, u16 *rdlen) 15885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 15895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bus->roundup && bus->blocksize && *rdlen > bus->blocksize) { 15905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel *pad = bus->blocksize - (*rdlen % bus->blocksize); 15915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (*pad <= bus->roundup && *pad < bus->blocksize && 15925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel *rdlen + *pad + BRCMF_FIRSTREAD < MAX_RX_DATASZ) 15935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel *rdlen += *pad; 15945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } else if (*rdlen % BRCMF_SDALIGN) { 15955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel *rdlen += BRCMF_SDALIGN - (*rdlen % BRCMF_SDALIGN); 15965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 15975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 15985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 15995b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic void 1600e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linbrcmf_alloc_pkt_and_read(struct brcmf_sdio *bus, u16 rdlen, 16015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct sk_buff **pkt, u8 **rxbuf) 16025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 16035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel int sdret; /* Return code from calls */ 16045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 16055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel *pkt = brcmu_pkt_buf_get_skb(rdlen + BRCMF_SDALIGN); 16065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (*pkt == NULL) 16075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return; 16085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 16095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel pkt_align(*pkt, rdlen, BRCMF_SDALIGN); 16105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel *rxbuf = (u8 *) ((*pkt)->data); 16115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Read the entire frame */ 16125adfeb632c52a6c15e98fa6465bdade6fff915d9Arend van Spriel sdret = brcmf_sdcard_recv_pkt(bus->sdiodev, bus->sdiodev->sbwad, 16135adfeb632c52a6c15e98fa6465bdade6fff915d9Arend van Spriel SDIO_FUNC_2, F2SYNC, *pkt); 16145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->f2rxdata++; 16155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 16165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (sdret < 0) { 16175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "(nextlen): read %d bytes failed: %d\n", 16185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel rdlen, sdret); 16195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmu_pkt_buf_free_skb(*pkt); 1620719f2733baa1e6a6a782c5109bfe054431db4259Franky Lin bus->sdiodev->bus_if->dstats.rx_errors++; 16215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Force retry w/normal header read. 16225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * Don't attempt NAK for 16235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * gSPI 16245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 16255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_rxfail(bus, true, true); 16265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel *pkt = NULL; 16275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 16285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 16295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 16305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* Checks the header */ 16315b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic int 1632e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linbrcmf_check_rxbuf(struct brcmf_sdio *bus, struct sk_buff *pkt, u8 *rxbuf, 16335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 rxseq, u16 nextlen, u16 *len) 16345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 16355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u16 check; 16365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bool len_consistent; /* Result of comparing readahead len and 16375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel len from hw-hdr */ 16385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 16395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel memcpy(bus->rxhdr, rxbuf, SDPCM_HDRLEN); 16405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 16415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Extract hardware header fields */ 16425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel *len = get_unaligned_le16(bus->rxhdr); 16435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel check = get_unaligned_le16(bus->rxhdr + sizeof(u16)); 16445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 16455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* All zeros means readahead info was bad */ 16465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (!(*len | check)) { 16475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(INFO, "(nextlen): read zeros in HW header???\n"); 16485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto fail; 16495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 16505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 16515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Validate check bytes */ 16525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if ((u16)~(*len ^ check)) { 16535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "(nextlen): HW hdr error: nextlen/len/check 0x%04x/0x%04x/0x%04x\n", 16545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel nextlen, *len, check); 16555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->rx_badhdr++; 16565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_rxfail(bus, false, false); 16575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto fail; 16585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 16595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 16605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Validate frame length */ 16615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (*len < SDPCM_HDRLEN) { 16625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "(nextlen): HW hdr length invalid: %d\n", 16635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel *len); 16645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto fail; 16655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 16665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 16675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Check for consistency with readahead info */ 16685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel len_consistent = (nextlen != (roundup(*len, 16) >> 4)); 16695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (len_consistent) { 16705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Mismatch, force retry w/normal 16715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel header (may be >4K) */ 16725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "(nextlen): mismatch, nextlen %d len %d rnd %d; expected rxseq %d\n", 16735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel nextlen, *len, roundup(*len, 16), 16745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel rxseq); 16755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_rxfail(bus, true, true); 16765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto fail; 16775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 16785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 16795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return 0; 16805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 16815b435de0d786869c95d1962121af0d7df2542009Arend van Sprielfail: 16825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_pktfree2(bus, pkt); 16835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return -EINVAL; 16845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 16855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 16865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* Return true if there may be more frames to read */ 16875b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic uint 1688e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linbrcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished) 16895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 16905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u16 len, check; /* Extracted hardware header fields */ 16915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 chan, seq, doff; /* Extracted software header fields */ 16925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 fcbits; /* Extracted fcbits from software header */ 16935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 16945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct sk_buff *pkt; /* Packet for event or data frames */ 16955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u16 pad; /* Number of pad bytes to read */ 16965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u16 rdlen; /* Total number of bytes to read */ 16975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 rxseq; /* Next sequence number to expect */ 16985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint rxleft = 0; /* Remaining number of frames allowed */ 16995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel int sdret; /* Return code from calls */ 17005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 txmax; /* Maximum tx sequence offered */ 17015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 *rxbuf; 17025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel int ifidx = 0; 17035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint rxcount = 0; /* Total frames read */ 17045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 17055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(TRACE, "Enter\n"); 17065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 17075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Not finished unless we encounter no more frames indication */ 17085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel *finished = false; 17095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 17105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel for (rxseq = bus->rx_seq, rxleft = maxframes; 17118d169aa00d0356f915e84dbdf6c9be381cce34a4Franky Lin !bus->rxskip && rxleft && 1712712ac5b37a3348cac4e040c551a6ca6186d33682Franky Lin bus->sdiodev->bus_if->state != BRCMF_BUS_DOWN; 17135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel rxseq++, rxleft--) { 17145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 17155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Handle glomming separately */ 1716b83db862ffb871e3131e5d2160c741b288eea9aaArend van Spriel if (bus->glomd || !skb_queue_empty(&bus->glom)) { 17175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 cnt; 17185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(GLOM, "calling rxglom: glomd %p, glom %p\n", 1719b83db862ffb871e3131e5d2160c741b288eea9aaArend van Spriel bus->glomd, skb_peek(&bus->glom)); 17205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel cnt = brcmf_sdbrcm_rxglom(bus, rxseq); 17215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(GLOM, "rxglom returned %d\n", cnt); 17225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel rxseq += cnt - 1; 17235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel rxleft = (rxleft > cnt) ? (rxleft - cnt) : 1; 17245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel continue; 17255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 17265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 17275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Try doing single read if we can */ 17285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bus->nextlen) { 17295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u16 nextlen = bus->nextlen; 17305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->nextlen = 0; 17315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 17325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel rdlen = len = nextlen << 4; 17335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_pad(bus, &pad, &rdlen); 17345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 17355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* 17365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * After the frame is received we have to 17375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * distinguish whether it is data 17385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * or non-data frame. 17395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 17405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_alloc_pkt_and_read(bus, rdlen, &pkt, &rxbuf); 17415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (pkt == NULL) { 17425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Give up on data, request rtx of events */ 17435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "(nextlen): brcmf_alloc_pkt_and_read failed: len %d rdlen %d expected rxseq %d\n", 17445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel len, rdlen, rxseq); 17455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel continue; 17465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 17475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 17485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (brcmf_check_rxbuf(bus, pkt, rxbuf, rxseq, nextlen, 17495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel &len) < 0) 17505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel continue; 17515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 17525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Extract software header fields */ 17535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel chan = SDPCM_PACKET_CHANNEL( 17545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel &bus->rxhdr[SDPCM_FRAMETAG_LEN]); 17555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel seq = SDPCM_PACKET_SEQUENCE( 17565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel &bus->rxhdr[SDPCM_FRAMETAG_LEN]); 17575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel doff = SDPCM_DOFFSET_VALUE( 17585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel &bus->rxhdr[SDPCM_FRAMETAG_LEN]); 17595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel txmax = SDPCM_WINDOW_VALUE( 17605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel &bus->rxhdr[SDPCM_FRAMETAG_LEN]); 17615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 17625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->nextlen = 17635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->rxhdr[SDPCM_FRAMETAG_LEN + 17645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SDPCM_NEXTLEN_OFFSET]; 17655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if ((bus->nextlen << 4) > MAX_RX_DATASZ) { 17665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(INFO, "(nextlen): got frame w/nextlen too large (%d), seq %d\n", 17675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->nextlen, seq); 17685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->nextlen = 0; 17695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 17705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 177128a1a3bdaf4cce5ee8e473c332e2f371888341bbFranky Lin bus->rx_readahead_cnt++; 17725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 17735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Handle Flow Control */ 17745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel fcbits = SDPCM_FCMASK_VALUE( 17755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel &bus->rxhdr[SDPCM_FRAMETAG_LEN]); 17765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 17775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bus->flowcontrol != fcbits) { 17785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (~bus->flowcontrol & fcbits) 17795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->fc_xoff++; 17805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 17815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bus->flowcontrol & ~fcbits) 17825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->fc_xon++; 17835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 17845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->fc_rcvd++; 17855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->flowcontrol = fcbits; 17865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 17875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 17885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Check and update sequence number */ 17895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (rxseq != seq) { 17905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(INFO, "(nextlen): rx_seq %d, expected %d\n", 17915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel seq, rxseq); 17925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->rx_badseq++; 17935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel rxseq = seq; 17945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 17955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 17965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Check window for sanity */ 17975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if ((u8) (txmax - bus->tx_seq) > 0x40) { 17985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "got unlikely tx max %d with tx_seq %d\n", 17995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel txmax, bus->tx_seq); 18005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel txmax = bus->tx_seq + 2; 18015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 18025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->tx_max = txmax; 18035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 18041e02382979dd422e3b1bdb45545a0699497e3692Joe Perches brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && BRCMF_DATA_ON(), 18051e02382979dd422e3b1bdb45545a0699497e3692Joe Perches rxbuf, len, "Rx Data:\n"); 18061e02382979dd422e3b1bdb45545a0699497e3692Joe Perches brcmf_dbg_hex_dump(!(BRCMF_BYTES_ON() && 18071e02382979dd422e3b1bdb45545a0699497e3692Joe Perches BRCMF_DATA_ON()) && 18081e02382979dd422e3b1bdb45545a0699497e3692Joe Perches BRCMF_HDRS_ON(), 18091e02382979dd422e3b1bdb45545a0699497e3692Joe Perches bus->rxhdr, SDPCM_HDRLEN, 18101e02382979dd422e3b1bdb45545a0699497e3692Joe Perches "RxHdr:\n"); 18115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 18125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (chan == SDPCM_CONTROL_CHANNEL) { 18135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "(nextlen): readahead on control packet %d?\n", 18145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel seq); 18155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Force retry w/normal header read */ 18165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->nextlen = 0; 18175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_rxfail(bus, false, true); 18185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_pktfree2(bus, pkt); 18195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel continue; 18205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 18215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 18225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Validate data offset */ 18235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if ((doff < SDPCM_HDRLEN) || (doff > len)) { 18245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "(nextlen): bad data offset %d: HW len %d min %d\n", 18255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel doff, len, SDPCM_HDRLEN); 18265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_rxfail(bus, false, false); 18275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_pktfree2(bus, pkt); 18285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel continue; 18295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 18305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 18315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* All done with this one -- now deliver the packet */ 18325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto deliver; 18335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 18345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 18355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Read frame header (hardware and software) */ 18365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel sdret = brcmf_sdcard_recv_buf(bus->sdiodev, bus->sdiodev->sbwad, 18375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SDIO_FUNC_2, F2SYNC, bus->rxhdr, 18385adfeb632c52a6c15e98fa6465bdade6fff915d9Arend van Spriel BRCMF_FIRSTREAD); 18395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->f2rxhdrs++; 18405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 18415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (sdret < 0) { 18425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "RXHEADER FAILED: %d\n", sdret); 18435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->rx_hdrfail++; 18445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_rxfail(bus, true, true); 18455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel continue; 18465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 18471e02382979dd422e3b1bdb45545a0699497e3692Joe Perches brcmf_dbg_hex_dump(BRCMF_BYTES_ON() || BRCMF_HDRS_ON(), 18481e02382979dd422e3b1bdb45545a0699497e3692Joe Perches bus->rxhdr, SDPCM_HDRLEN, "RxHdr:\n"); 18491e02382979dd422e3b1bdb45545a0699497e3692Joe Perches 18505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 18515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Extract hardware header fields */ 18525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel len = get_unaligned_le16(bus->rxhdr); 18535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel check = get_unaligned_le16(bus->rxhdr + sizeof(u16)); 18545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 18555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* All zeros means no more frames */ 18565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (!(len | check)) { 18575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel *finished = true; 18585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel break; 18595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 18605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 18615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Validate check bytes */ 18625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if ((u16) ~(len ^ check)) { 18635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "HW hdr err: len/check 0x%04x/0x%04x\n", 18645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel len, check); 18655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->rx_badhdr++; 18665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_rxfail(bus, false, false); 18675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel continue; 18685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 18695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 18705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Validate frame length */ 18715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (len < SDPCM_HDRLEN) { 18725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "HW hdr length invalid: %d\n", len); 18735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel continue; 18745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 18755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 18765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Extract software header fields */ 18775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); 18785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); 18795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); 18805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); 18815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 18825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Validate data offset */ 18835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if ((doff < SDPCM_HDRLEN) || (doff > len)) { 18845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "Bad data offset %d: HW len %d, min %d seq %d\n", 18855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel doff, len, SDPCM_HDRLEN, seq); 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 /* Save the readahead length if there is one */ 18925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->nextlen = 18935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET]; 18945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if ((bus->nextlen << 4) > MAX_RX_DATASZ) { 18955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(INFO, "(nextlen): got frame w/nextlen too large (%d), seq %d\n", 18965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->nextlen, seq); 18975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->nextlen = 0; 18985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 18995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 19005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Handle Flow Control */ 19015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); 19025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 19035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bus->flowcontrol != fcbits) { 19045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (~bus->flowcontrol & fcbits) 19055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->fc_xoff++; 19065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 19075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bus->flowcontrol & ~fcbits) 19085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->fc_xon++; 19095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 19105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->fc_rcvd++; 19115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->flowcontrol = fcbits; 19125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 19135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 19145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Check and update sequence number */ 19155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (rxseq != seq) { 19165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(INFO, "rx_seq %d, expected %d\n", seq, rxseq); 19175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->rx_badseq++; 19185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel rxseq = seq; 19195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 19205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 19215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Check window for sanity */ 19225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if ((u8) (txmax - bus->tx_seq) > 0x40) { 19235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "unlikely tx max %d with tx_seq %d\n", 19245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel txmax, bus->tx_seq); 19255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel txmax = bus->tx_seq + 2; 19265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 19275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->tx_max = txmax; 19285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 19295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Call a separate function for control frames */ 19305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (chan == SDPCM_CONTROL_CHANNEL) { 19315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_read_control(bus, bus->rxhdr, len, doff); 19325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel continue; 19335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 19345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 19355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* precondition: chan is either SDPCM_DATA_CHANNEL, 19365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SDPCM_EVENT_CHANNEL, SDPCM_TEST_CHANNEL or 19375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SDPCM_GLOM_CHANNEL */ 19385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 19395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Length to read */ 19405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel rdlen = (len > BRCMF_FIRSTREAD) ? (len - BRCMF_FIRSTREAD) : 0; 19415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 19425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* May pad read to blocksize for efficiency */ 19435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bus->roundup && bus->blocksize && 19445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel (rdlen > bus->blocksize)) { 19455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel pad = bus->blocksize - (rdlen % bus->blocksize); 19465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if ((pad <= bus->roundup) && (pad < bus->blocksize) && 19475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel ((rdlen + pad + BRCMF_FIRSTREAD) < MAX_RX_DATASZ)) 19485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel rdlen += pad; 19495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } else if (rdlen % BRCMF_SDALIGN) { 19505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel rdlen += BRCMF_SDALIGN - (rdlen % BRCMF_SDALIGN); 19515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 19525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 19535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Satisfy length-alignment requirements */ 19545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (rdlen & (ALIGNMENT - 1)) 19555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel rdlen = roundup(rdlen, ALIGNMENT); 19565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 19575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if ((rdlen + BRCMF_FIRSTREAD) > MAX_RX_DATASZ) { 19585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Too long -- skip this frame */ 19595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "too long: len %d rdlen %d\n", 19605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel len, rdlen); 1961719f2733baa1e6a6a782c5109bfe054431db4259Franky Lin bus->sdiodev->bus_if->dstats.rx_errors++; 19625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->rx_toolong++; 19635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_rxfail(bus, false, false); 19645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel continue; 19655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 19665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 19675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel pkt = brcmu_pkt_buf_get_skb(rdlen + 19685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel BRCMF_FIRSTREAD + BRCMF_SDALIGN); 19695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (!pkt) { 19705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Give up on data, request rtx of events */ 19715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: rdlen %d chan %d\n", 19725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel rdlen, chan); 1973719f2733baa1e6a6a782c5109bfe054431db4259Franky Lin bus->sdiodev->bus_if->dstats.rx_dropped++; 19745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_rxfail(bus, false, RETRYCHAN(chan)); 19755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel continue; 19765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 19775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 19785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Leave room for what we already read, and align remainder */ 19795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel skb_pull(pkt, BRCMF_FIRSTREAD); 19805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel pkt_align(pkt, rdlen, BRCMF_SDALIGN); 19815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 19825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Read the remaining frame data */ 19835adfeb632c52a6c15e98fa6465bdade6fff915d9Arend van Spriel sdret = brcmf_sdcard_recv_pkt(bus->sdiodev, bus->sdiodev->sbwad, 19845adfeb632c52a6c15e98fa6465bdade6fff915d9Arend van Spriel SDIO_FUNC_2, F2SYNC, pkt); 19855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->f2rxdata++; 19865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 19875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (sdret < 0) { 19885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "read %d %s bytes failed: %d\n", rdlen, 19895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel ((chan == SDPCM_EVENT_CHANNEL) ? "event" 19905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel : ((chan == SDPCM_DATA_CHANNEL) ? "data" 19915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel : "test")), sdret); 19925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmu_pkt_buf_free_skb(pkt); 1993719f2733baa1e6a6a782c5109bfe054431db4259Franky Lin bus->sdiodev->bus_if->dstats.rx_errors++; 19945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_rxfail(bus, true, RETRYCHAN(chan)); 19955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel continue; 19965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 19975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 19985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Copy the already-read portion */ 19995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel skb_push(pkt, BRCMF_FIRSTREAD); 20005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel memcpy(pkt->data, bus->rxhdr, BRCMF_FIRSTREAD); 20015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 20021e02382979dd422e3b1bdb45545a0699497e3692Joe Perches brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && BRCMF_DATA_ON(), 20031e02382979dd422e3b1bdb45545a0699497e3692Joe Perches pkt->data, len, "Rx Data:\n"); 20045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 20055b435de0d786869c95d1962121af0d7df2542009Arend van Sprieldeliver: 20065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Save superframe descriptor and allocate packet frame */ 20075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (chan == SDPCM_GLOM_CHANNEL) { 20085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (SDPCM_GLOMDESC(&bus->rxhdr[SDPCM_FRAMETAG_LEN])) { 20095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(GLOM, "glom descriptor, %d bytes:\n", 20105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel len); 20111e02382979dd422e3b1bdb45545a0699497e3692Joe Perches brcmf_dbg_hex_dump(BRCMF_GLOM_ON(), 20121e02382979dd422e3b1bdb45545a0699497e3692Joe Perches pkt->data, len, 20131e02382979dd422e3b1bdb45545a0699497e3692Joe Perches "Glom Data:\n"); 20145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel __skb_trim(pkt, len); 20155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel skb_pull(pkt, SDPCM_HDRLEN); 20165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->glomd = pkt; 20175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } else { 20185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "%s: glom superframe w/o " 20195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel "descriptor!\n", __func__); 20205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_rxfail(bus, false, false); 20215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 20225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel continue; 20235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 20245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 20255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Fill in packet len and prio, deliver upward */ 20265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel __skb_trim(pkt, len); 20275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel skb_pull(pkt, doff); 20285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 20295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (pkt->len == 0) { 20305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmu_pkt_buf_free_skb(pkt); 20315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel continue; 2032d5625ee66f82162acb7189c1974e688ebc178cf3Franky Lin } else if (brcmf_proto_hdrpull(bus->sdiodev->dev, &ifidx, 2033d5625ee66f82162acb7189c1974e688ebc178cf3Franky Lin pkt) != 0) { 20345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "rx protocol error\n"); 20355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmu_pkt_buf_free_skb(pkt); 2036719f2733baa1e6a6a782c5109bfe054431db4259Franky Lin bus->sdiodev->bus_if->dstats.rx_errors++; 20375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel continue; 20385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 20395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 20405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Unlock during rx call */ 20415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel up(&bus->sdsem); 2042228bb43d5d82549c43eee29e12d7632d4df4e4dfFranky Lin brcmf_rx_packet(bus->sdiodev->dev, ifidx, pkt); 20435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel down(&bus->sdsem); 20445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 20455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel rxcount = maxframes - rxleft; 20465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Message if we hit the limit */ 20475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (!rxleft) 20485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(DATA, "hit rx limit of %d frames\n", 20495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel maxframes); 20505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel else 20515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(DATA, "processed %d frames\n", rxcount); 20525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Back off rxseq if awaiting rtx, update rx_seq */ 20535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bus->rxskip) 20545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel rxseq--; 20555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->rx_seq = rxseq; 20565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 20575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return rxcount; 20585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 20595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 20605b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic void 2061e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linbrcmf_sdbrcm_wait_for_event(struct brcmf_sdio *bus, bool *lockvar) 20625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 20635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel up(&bus->sdsem); 206423677ce3172fcb93522a1df077d21019e73ee1e3Joe Perches wait_event_interruptible_timeout(bus->ctrl_wait, !*lockvar, HZ * 2); 20655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel down(&bus->sdsem); 20665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return; 20675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 20685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 20695b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic void 2070e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linbrcmf_sdbrcm_wait_event_wakeup(struct brcmf_sdio *bus) 20715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 20725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (waitqueue_active(&bus->ctrl_wait)) 20735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel wake_up_interruptible(&bus->ctrl_wait); 20745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return; 20755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 20765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 20775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* Writes a HW/SW header into the packet and sends it. */ 20785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* Assumes: (a) header space already there, (b) caller holds lock */ 2079e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt, 20805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint chan, bool free_pkt) 20815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 20825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel int ret; 20835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 *frame; 20845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u16 len, pad = 0; 20855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 swheader; 20865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct sk_buff *new; 20875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel int i; 20885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 20895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(TRACE, "Enter\n"); 20905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 20915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel frame = (u8 *) (pkt->data); 20925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 20935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Add alignment padding, allocate new packet if needed */ 20945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel pad = ((unsigned long)frame % BRCMF_SDALIGN); 20955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (pad) { 20965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (skb_headroom(pkt) < pad) { 20975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(INFO, "insufficient headroom %d for %d pad\n", 20985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel skb_headroom(pkt), pad); 20999c1a043ae688151444578f15208233143526bb88Franky Lin bus->sdiodev->bus_if->tx_realloc++; 21005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel new = brcmu_pkt_buf_get_skb(pkt->len + BRCMF_SDALIGN); 21015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (!new) { 21025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "couldn't allocate new %d-byte packet\n", 21035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel pkt->len + BRCMF_SDALIGN); 21045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel ret = -ENOMEM; 21055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto done; 21065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 21075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 21085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel pkt_align(new, pkt->len, BRCMF_SDALIGN); 21095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel memcpy(new->data, pkt->data, pkt->len); 21105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (free_pkt) 21115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmu_pkt_buf_free_skb(pkt); 21125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* free the pkt if canned one is not used */ 21135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel free_pkt = true; 21145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel pkt = new; 21155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel frame = (u8 *) (pkt->data); 21165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* precondition: (frame % BRCMF_SDALIGN) == 0) */ 21175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel pad = 0; 21185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } else { 21195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel skb_push(pkt, pad); 21205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel frame = (u8 *) (pkt->data); 21215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* precondition: pad + SDPCM_HDRLEN <= pkt->len */ 21225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel memset(frame, 0, pad + SDPCM_HDRLEN); 21235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 21245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 21255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* precondition: pad < BRCMF_SDALIGN */ 21265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 21275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */ 21285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel len = (u16) (pkt->len); 21295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel *(__le16 *) frame = cpu_to_le16(len); 21305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel *(((__le16 *) frame) + 1) = cpu_to_le16(~len); 21315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 21325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Software tag: channel, sequence number, data offset */ 21335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel swheader = 21345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) | bus->tx_seq | 21355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel (((pad + 21365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK); 21375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 21385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel put_unaligned_le32(swheader, frame + SDPCM_FRAMETAG_LEN); 21395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel put_unaligned_le32(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader)); 21405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 21418ae746543c8370fd04c28aaf8f185c1687b0e694Joe Perches#ifdef DEBUG 21425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel tx_packets[pkt->priority]++; 214318aad4f8e11530fd7e41d0faea0752c3a0ce799cJoe Perches#endif 21441e02382979dd422e3b1bdb45545a0699497e3692Joe Perches 21451e02382979dd422e3b1bdb45545a0699497e3692Joe Perches brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && 21461e02382979dd422e3b1bdb45545a0699497e3692Joe Perches ((BRCMF_CTL_ON() && chan == SDPCM_CONTROL_CHANNEL) || 21471e02382979dd422e3b1bdb45545a0699497e3692Joe Perches (BRCMF_DATA_ON() && chan != SDPCM_CONTROL_CHANNEL)), 21481e02382979dd422e3b1bdb45545a0699497e3692Joe Perches frame, len, "Tx Frame:\n"); 21491e02382979dd422e3b1bdb45545a0699497e3692Joe Perches brcmf_dbg_hex_dump(!(BRCMF_BYTES_ON() && 21501e02382979dd422e3b1bdb45545a0699497e3692Joe Perches ((BRCMF_CTL_ON() && 21511e02382979dd422e3b1bdb45545a0699497e3692Joe Perches chan == SDPCM_CONTROL_CHANNEL) || 21521e02382979dd422e3b1bdb45545a0699497e3692Joe Perches (BRCMF_DATA_ON() && 21531e02382979dd422e3b1bdb45545a0699497e3692Joe Perches chan != SDPCM_CONTROL_CHANNEL))) && 21541e02382979dd422e3b1bdb45545a0699497e3692Joe Perches BRCMF_HDRS_ON(), 21551e02382979dd422e3b1bdb45545a0699497e3692Joe Perches frame, min_t(u16, len, 16), "TxHdr:\n"); 21565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 21575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Raise len to next SDIO block to eliminate tail command */ 21585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bus->roundup && bus->blocksize && (len > bus->blocksize)) { 21595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u16 pad = bus->blocksize - (len % bus->blocksize); 21605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if ((pad <= bus->roundup) && (pad < bus->blocksize)) 21615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel len += pad; 21625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } else if (len % BRCMF_SDALIGN) { 21635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel len += BRCMF_SDALIGN - (len % BRCMF_SDALIGN); 21645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 21655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 21665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Some controllers have trouble with odd bytes -- round to even */ 21675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (len & (ALIGNMENT - 1)) 21685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel len = roundup(len, ALIGNMENT); 21695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 21705adfeb632c52a6c15e98fa6465bdade6fff915d9Arend van Spriel ret = brcmf_sdcard_send_pkt(bus->sdiodev, bus->sdiodev->sbwad, 21715adfeb632c52a6c15e98fa6465bdade6fff915d9Arend van Spriel SDIO_FUNC_2, F2SYNC, pkt); 21725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->f2txdata++; 21735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 21745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (ret < 0) { 21755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* On failure, abort the command and terminate the frame */ 21765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n", 21775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel ret); 21785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->tx_sderrs++; 21795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 21805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2); 21815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, 21825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SBSDIO_FUNC1_FRAMECTRL, SFC_WF_TERM, 21835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel NULL); 21845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->f1regdata++; 21855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 21865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel for (i = 0; i < 3; i++) { 21875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 hi, lo; 21885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel hi = brcmf_sdcard_cfg_read(bus->sdiodev, 21895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SDIO_FUNC_1, 21905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SBSDIO_FUNC1_WFRAMEBCHI, 21915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel NULL); 21925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel lo = brcmf_sdcard_cfg_read(bus->sdiodev, 21935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SDIO_FUNC_1, 21945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SBSDIO_FUNC1_WFRAMEBCLO, 21955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel NULL); 21965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->f1regdata += 2; 21975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if ((hi == 0) && (lo == 0)) 21985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel break; 21995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 22005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 22015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 22025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (ret == 0) 22035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; 22045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 22055b435de0d786869c95d1962121af0d7df2542009Arend van Sprieldone: 22065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* restore pkt buffer pointer before calling tx complete routine */ 22075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel skb_pull(pkt, SDPCM_HDRLEN + pad); 22085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel up(&bus->sdsem); 2209c995788f4761f175f811cbeabb2f88ab8565ec1eFranky Lin brcmf_txcomplete(bus->sdiodev->dev, pkt, ret != 0); 22105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel down(&bus->sdsem); 22115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 22125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (free_pkt) 22135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmu_pkt_buf_free_skb(pkt); 22145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 22155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return ret; 22165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 22175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 2218e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes) 22195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 22205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct sk_buff *pkt; 22215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 intstatus = 0; 22225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint retries = 0; 22235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel int ret = 0, prec_out; 22245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint cnt = 0; 22255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint datalen; 22265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 tx_prec_map; 22275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 22285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(TRACE, "Enter\n"); 22295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 22305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel tx_prec_map = ~bus->flowcontrol; 22315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 22325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Send frames until the limit or some other event */ 22335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel for (cnt = 0; (cnt < maxframes) && data_ok(bus); cnt++) { 22345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_lock_bh(&bus->txqlock); 22355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel pkt = brcmu_pktq_mdeq(&bus->txq, tx_prec_map, &prec_out); 22365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (pkt == NULL) { 22375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_unlock_bh(&bus->txqlock); 22385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel break; 22395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 22405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_unlock_bh(&bus->txqlock); 22415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel datalen = pkt->len - SDPCM_HDRLEN; 22425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 22435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel ret = brcmf_sdbrcm_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, true); 22445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (ret) 2245719f2733baa1e6a6a782c5109bfe054431db4259Franky Lin bus->sdiodev->bus_if->dstats.tx_errors++; 22465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel else 2247719f2733baa1e6a6a782c5109bfe054431db4259Franky Lin bus->sdiodev->bus_if->dstats.tx_bytes += datalen; 22485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 22495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* In poll mode, need to check for other events */ 22505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (!bus->intr && cnt) { 22515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Check device status, signal pending interrupt */ 22525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel r_sdreg32(bus, &intstatus, 22535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel offsetof(struct sdpcmd_regs, intstatus), 22545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel &retries); 22555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->f2txdata++; 22565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (brcmf_sdcard_regfail(bus->sdiodev)) 22575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel break; 22585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (intstatus & bus->hostintmask) 22595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->ipend = true; 22605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 22615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 22625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 22635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Deflow-control stack if needed */ 2264712ac5b37a3348cac4e040c551a6ca6186d33682Franky Lin if (bus->sdiodev->bus_if->drvr_up && 2265712ac5b37a3348cac4e040c551a6ca6186d33682Franky Lin (bus->sdiodev->bus_if->state == BRCMF_BUS_DATA) && 2266c8bf34849f92c5894a3d7e12573d3789d7851f23Franky Lin bus->txoff && (pktq_len(&bus->txq) < TXLOW)) { 2267c8bf34849f92c5894a3d7e12573d3789d7851f23Franky Lin bus->txoff = OFF; 22682b4590569ead15fb88a83c1d8a07e3ca5507f4c6Franky Lin brcmf_txflowcontrol(bus->sdiodev->dev, 0, OFF); 2269c8bf34849f92c5894a3d7e12573d3789d7851f23Franky Lin } 22705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 22715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return cnt; 22725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 22735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 2274a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Linstatic void brcmf_sdbrcm_bus_stop(struct device *dev) 2275a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin{ 2276a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin u32 local_hostintmask; 2277a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin u8 saveclk; 2278a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin uint retries; 2279a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin int err; 2280a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin struct brcmf_bus *bus_if = dev_get_drvdata(dev); 22810a332e4678e4e4f0030f10827980c72d32300274Arend van Spriel struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; 2282a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin struct brcmf_sdio *bus = sdiodev->bus; 2283a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin 2284a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin brcmf_dbg(TRACE, "Enter\n"); 2285a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin 2286a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin if (bus->watchdog_tsk) { 2287a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin send_sig(SIGTERM, bus->watchdog_tsk, 1); 2288a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin kthread_stop(bus->watchdog_tsk); 2289a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin bus->watchdog_tsk = NULL; 2290a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin } 2291a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin 2292a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin if (bus->dpc_tsk && bus->dpc_tsk != current) { 2293a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin send_sig(SIGTERM, bus->dpc_tsk, 1); 2294a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin kthread_stop(bus->dpc_tsk); 2295a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin bus->dpc_tsk = NULL; 2296a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin } 2297a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin 2298a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin down(&bus->sdsem); 2299a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin 2300a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin bus_wake(bus); 2301a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin 2302a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin /* Enable clock for device interrupts */ 2303a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); 2304a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin 2305a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin /* Disable and clear interrupts at the chip level also */ 2306a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin w_sdreg32(bus, 0, offsetof(struct sdpcmd_regs, hostintmask), &retries); 2307a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin local_hostintmask = bus->hostintmask; 2308a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin bus->hostintmask = 0; 2309a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin 2310a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin /* Change our idea of bus state */ 2311a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN; 2312a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin 2313a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin /* Force clocks on backplane to be sure F2 interrupt propagates */ 2314a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin saveclk = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, 2315a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin SBSDIO_FUNC1_CHIPCLKCSR, &err); 2316a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin if (!err) { 2317a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, 2318a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin SBSDIO_FUNC1_CHIPCLKCSR, 2319a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin (saveclk | SBSDIO_FORCE_HT), &err); 2320a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin } 2321a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin if (err) 2322a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin brcmf_dbg(ERROR, "Failed to force clock for F2: err %d\n", err); 2323a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin 2324a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin /* Turn off the bus (F2), free any pending packets */ 2325a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin brcmf_dbg(INTR, "disable SDIO interrupts\n"); 2326a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx, 2327a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin SDIO_FUNC_ENABLE_1, NULL); 2328a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin 2329a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin /* Clear any pending interrupts now that F2 is disabled */ 2330a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin w_sdreg32(bus, local_hostintmask, 2331a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin offsetof(struct sdpcmd_regs, intstatus), &retries); 2332a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin 2333a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin /* Turn off the backplane clock (only) */ 2334a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false); 2335a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin 2336a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin /* Clear the data packet queues */ 2337a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin brcmu_pktq_flush(&bus->txq, true, NULL, NULL); 2338a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin 2339a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin /* Clear any held glomming stuff */ 2340a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin if (bus->glomd) 2341a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin brcmu_pkt_buf_free_skb(bus->glomd); 2342a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin brcmf_sdbrcm_free_glom(bus); 2343a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin 2344a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin /* Clear rx control and wake any waiters */ 2345a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin bus->rxlen = 0; 2346a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin brcmf_sdbrcm_dcmd_resp_wake(bus); 2347a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin 2348a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin /* Reset some F2 state stuff */ 2349a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin bus->rxskip = false; 2350a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin bus->tx_seq = bus->rx_seq = 0; 2351a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin 2352a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin up(&bus->sdsem); 2353a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin} 2354a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin 2355e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus) 23565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 23575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 intstatus, newstatus = 0; 23585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint retries = 0; 23595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint rxlimit = bus->rxbound; /* Rx frames to read before resched */ 23605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint txlimit = bus->txbound; /* Tx frames to send before resched */ 23615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint framecnt = 0; /* Temporary counter of tx/rx frames */ 23625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bool rxdone = true; /* Flag for no more read data */ 23635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bool resched = false; /* Flag indicating resched wanted */ 23645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 23655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(TRACE, "Enter\n"); 23665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 23675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Start with leftover status bits */ 23685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel intstatus = bus->intstatus; 23695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 23705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel down(&bus->sdsem); 23715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 23725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* If waiting for HTAVAIL, check status */ 23735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bus->clkstate == CLK_PENDING) { 23745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel int err; 23755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 clkctl, devctl = 0; 23765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 23778ae746543c8370fd04c28aaf8f185c1687b0e694Joe Perches#ifdef DEBUG 23785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Check for inconsistent device control */ 23795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel devctl = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, 23805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SBSDIO_DEVICE_CTL, &err); 23815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (err) { 23825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "error reading DEVCTL: %d\n", err); 2383712ac5b37a3348cac4e040c551a6ca6186d33682Franky Lin bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN; 23845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 23858ae746543c8370fd04c28aaf8f185c1687b0e694Joe Perches#endif /* DEBUG */ 23865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 23875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Read CSR, if clock on switch to AVAIL, else ignore */ 23885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel clkctl = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, 23895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SBSDIO_FUNC1_CHIPCLKCSR, &err); 23905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (err) { 23915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "error reading CSR: %d\n", 23925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel err); 2393712ac5b37a3348cac4e040c551a6ca6186d33682Franky Lin bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN; 23945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 23955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 23965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(INFO, "DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n", 23975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel devctl, clkctl); 23985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 23995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (SBSDIO_HTAV(clkctl)) { 24005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel devctl = brcmf_sdcard_cfg_read(bus->sdiodev, 24015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SDIO_FUNC_1, 24025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SBSDIO_DEVICE_CTL, &err); 24035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (err) { 24045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "error reading DEVCTL: %d\n", 24055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel err); 2406712ac5b37a3348cac4e040c551a6ca6186d33682Franky Lin bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN; 24075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 24085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; 24095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, 24105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SBSDIO_DEVICE_CTL, devctl, &err); 24115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (err) { 24125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "error writing DEVCTL: %d\n", 24135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel err); 2414712ac5b37a3348cac4e040c551a6ca6186d33682Franky Lin bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN; 24155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 24165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->clkstate = CLK_AVAIL; 24175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } else { 24185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto clkwait; 24195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 24205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 24215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 24225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus_wake(bus); 24235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 24245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Make sure backplane clock is on */ 24255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, true); 24265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bus->clkstate == CLK_PENDING) 24275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto clkwait; 24285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 24295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Pending interrupt indicates new device status */ 24305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bus->ipend) { 24315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->ipend = false; 24325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel r_sdreg32(bus, &newstatus, 24335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel offsetof(struct sdpcmd_regs, intstatus), &retries); 24345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->f1regdata++; 24355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (brcmf_sdcard_regfail(bus->sdiodev)) 24365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel newstatus = 0; 24375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel newstatus &= bus->hostintmask; 24385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->fcstate = !!(newstatus & I_HMB_FC_STATE); 24395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (newstatus) { 24405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel w_sdreg32(bus, newstatus, 24415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel offsetof(struct sdpcmd_regs, intstatus), 24425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel &retries); 24435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->f1regdata++; 24445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 24455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 24465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 24475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Merge new bits with previous */ 24485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel intstatus |= newstatus; 24495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->intstatus = 0; 24505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 24515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Handle flow-control change: read new state in case our ack 24525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * crossed another change interrupt. If change still set, assume 24535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * FC ON for safety, let next loop through do the debounce. 24545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 24555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (intstatus & I_HMB_FC_CHANGE) { 24565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel intstatus &= ~I_HMB_FC_CHANGE; 24575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel w_sdreg32(bus, I_HMB_FC_CHANGE, 24585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel offsetof(struct sdpcmd_regs, intstatus), &retries); 24595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 24605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel r_sdreg32(bus, &newstatus, 24615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel offsetof(struct sdpcmd_regs, intstatus), &retries); 24625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->f1regdata += 2; 24635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->fcstate = 24645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel !!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE)); 24655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel intstatus |= (newstatus & bus->hostintmask); 24665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 24675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 24685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Handle host mailbox indication */ 24695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (intstatus & I_HMB_HOST_INT) { 24705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel intstatus &= ~I_HMB_HOST_INT; 24715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel intstatus |= brcmf_sdbrcm_hostmail(bus); 24725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 24735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 24745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Generally don't ask for these, can get CRC errors... */ 24755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (intstatus & I_WR_OOSYNC) { 24765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "Dongle reports WR_OOSYNC\n"); 24775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel intstatus &= ~I_WR_OOSYNC; 24785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 24795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 24805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (intstatus & I_RD_OOSYNC) { 24815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "Dongle reports RD_OOSYNC\n"); 24825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel intstatus &= ~I_RD_OOSYNC; 24835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 24845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 24855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (intstatus & I_SBINT) { 24865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "Dongle reports SBINT\n"); 24875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel intstatus &= ~I_SBINT; 24885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 24895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 24905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Would be active due to wake-wlan in gSPI */ 24915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (intstatus & I_CHIPACTIVE) { 24925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(INFO, "Dongle reports CHIPACTIVE\n"); 24935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel intstatus &= ~I_CHIPACTIVE; 24945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 24955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 24965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Ignore frame indications if rxskip is set */ 24975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bus->rxskip) 24985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel intstatus &= ~I_HMB_FRAME_IND; 24995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 25005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* On frame indication, read available frames */ 25015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (PKT_AVAILABLE()) { 25025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel framecnt = brcmf_sdbrcm_readframes(bus, rxlimit, &rxdone); 25035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (rxdone || bus->rxskip) 25045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel intstatus &= ~I_HMB_FRAME_IND; 25055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel rxlimit -= min(framecnt, rxlimit); 25065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 25075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 25085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Keep still-pending events for next scheduling */ 25095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->intstatus = intstatus; 25105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 25115b435de0d786869c95d1962121af0d7df2542009Arend van Sprielclkwait: 25125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (data_ok(bus) && bus->ctrl_frame_stat && 25135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel (bus->clkstate == CLK_AVAIL)) { 25145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel int ret, i; 25155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 25165adfeb632c52a6c15e98fa6465bdade6fff915d9Arend van Spriel ret = brcmf_sdcard_send_buf(bus->sdiodev, bus->sdiodev->sbwad, 25175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SDIO_FUNC_2, F2SYNC, (u8 *) bus->ctrl_frame_buf, 25185adfeb632c52a6c15e98fa6465bdade6fff915d9Arend van Spriel (u32) bus->ctrl_frame_len); 25195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 25205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (ret < 0) { 25215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* On failure, abort the command and 25225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel terminate the frame */ 25235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n", 25245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel ret); 25255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->tx_sderrs++; 25265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 25275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2); 25285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 25295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, 25305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SBSDIO_FUNC1_FRAMECTRL, SFC_WF_TERM, 25315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel NULL); 25325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->f1regdata++; 25335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 25345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel for (i = 0; i < 3; i++) { 25355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 hi, lo; 25365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel hi = brcmf_sdcard_cfg_read(bus->sdiodev, 25375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SDIO_FUNC_1, 25385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SBSDIO_FUNC1_WFRAMEBCHI, 25395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel NULL); 25405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel lo = brcmf_sdcard_cfg_read(bus->sdiodev, 25415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SDIO_FUNC_1, 25425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SBSDIO_FUNC1_WFRAMEBCLO, 25435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel NULL); 25445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->f1regdata += 2; 25455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if ((hi == 0) && (lo == 0)) 25465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel break; 25475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 25485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 25495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 25505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (ret == 0) 25515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; 25525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 25535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(INFO, "Return_dpc value is : %d\n", ret); 25545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->ctrl_frame_stat = false; 25555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_wait_event_wakeup(bus); 25565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 25575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Send queued frames (limit 1 if rx may still be pending) */ 25585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate && 25595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit 25605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel && data_ok(bus)) { 25615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel framecnt = rxdone ? txlimit : min(txlimit, bus->txminmax); 25625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel framecnt = brcmf_sdbrcm_sendfromq(bus, framecnt); 25635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel txlimit -= framecnt; 25645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 25655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 25665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Resched if events or tx frames are pending, 25675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel else await next interrupt */ 25685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* On failed register access, all bets are off: 25695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel no resched or interrupts */ 2570712ac5b37a3348cac4e040c551a6ca6186d33682Franky Lin if ((bus->sdiodev->bus_if->state == BRCMF_BUS_DOWN) || 25715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdcard_regfail(bus->sdiodev)) { 25725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "failed backplane access over SDIO, halting operation %d\n", 25735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdcard_regfail(bus->sdiodev)); 2574712ac5b37a3348cac4e040c551a6ca6186d33682Franky Lin bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN; 25755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->intstatus = 0; 25765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } else if (bus->clkstate == CLK_PENDING) { 25775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(INFO, "rescheduled due to CLK_PENDING awaiting I_CHIPACTIVE interrupt\n"); 25785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel resched = true; 25795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } else if (bus->intstatus || bus->ipend || 25805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel (!bus->fcstate && brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) 25815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel && data_ok(bus)) || PKT_AVAILABLE()) { 25825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel resched = true; 25835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 25845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 25855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->dpc_sched = resched; 25865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 25875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* If we're done for now, turn off clock request. */ 25885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if ((bus->clkstate != CLK_PENDING) 25895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel && bus->idletime == BRCMF_IDLE_IMMEDIATE) { 25905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->activity = false; 25915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_clkctl(bus, CLK_NONE, false); 25925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 25935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 25945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel up(&bus->sdsem); 25955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 25965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return resched; 25975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 25985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 2599b948a85c1f26d48395de8c6c7e392f008f1be666Franky Linstatic inline void brcmf_sdbrcm_adddpctsk(struct brcmf_sdio *bus) 2600b948a85c1f26d48395de8c6c7e392f008f1be666Franky Lin{ 2601b948a85c1f26d48395de8c6c7e392f008f1be666Franky Lin struct list_head *new_hd; 2602b948a85c1f26d48395de8c6c7e392f008f1be666Franky Lin unsigned long flags; 2603b948a85c1f26d48395de8c6c7e392f008f1be666Franky Lin 2604b948a85c1f26d48395de8c6c7e392f008f1be666Franky Lin if (in_interrupt()) 2605b948a85c1f26d48395de8c6c7e392f008f1be666Franky Lin new_hd = kzalloc(sizeof(struct list_head), GFP_ATOMIC); 2606b948a85c1f26d48395de8c6c7e392f008f1be666Franky Lin else 2607b948a85c1f26d48395de8c6c7e392f008f1be666Franky Lin new_hd = kzalloc(sizeof(struct list_head), GFP_KERNEL); 2608b948a85c1f26d48395de8c6c7e392f008f1be666Franky Lin if (new_hd == NULL) 2609b948a85c1f26d48395de8c6c7e392f008f1be666Franky Lin return; 2610b948a85c1f26d48395de8c6c7e392f008f1be666Franky Lin 2611b948a85c1f26d48395de8c6c7e392f008f1be666Franky Lin spin_lock_irqsave(&bus->dpc_tl_lock, flags); 2612b948a85c1f26d48395de8c6c7e392f008f1be666Franky Lin list_add_tail(new_hd, &bus->dpc_tsklst); 2613b948a85c1f26d48395de8c6c7e392f008f1be666Franky Lin spin_unlock_irqrestore(&bus->dpc_tl_lock, flags); 2614b948a85c1f26d48395de8c6c7e392f008f1be666Franky Lin} 2615b948a85c1f26d48395de8c6c7e392f008f1be666Franky Lin 26165b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic int brcmf_sdbrcm_dpc_thread(void *data) 26175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 2618e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Lin struct brcmf_sdio *bus = (struct brcmf_sdio *) data; 2619b948a85c1f26d48395de8c6c7e392f008f1be666Franky Lin struct list_head *cur_hd, *tmp_hd; 2620b948a85c1f26d48395de8c6c7e392f008f1be666Franky Lin unsigned long flags; 26215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 26225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel allow_signal(SIGTERM); 26235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Run until signal received */ 26245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel while (1) { 26255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (kthread_should_stop()) 26265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel break; 2627b948a85c1f26d48395de8c6c7e392f008f1be666Franky Lin 2628b948a85c1f26d48395de8c6c7e392f008f1be666Franky Lin if (list_empty(&bus->dpc_tsklst)) 2629b948a85c1f26d48395de8c6c7e392f008f1be666Franky Lin if (wait_for_completion_interruptible(&bus->dpc_wait)) 2630b948a85c1f26d48395de8c6c7e392f008f1be666Franky Lin break; 2631b948a85c1f26d48395de8c6c7e392f008f1be666Franky Lin 2632b948a85c1f26d48395de8c6c7e392f008f1be666Franky Lin spin_lock_irqsave(&bus->dpc_tl_lock, flags); 2633b948a85c1f26d48395de8c6c7e392f008f1be666Franky Lin list_for_each_safe(cur_hd, tmp_hd, &bus->dpc_tsklst) { 2634b948a85c1f26d48395de8c6c7e392f008f1be666Franky Lin spin_unlock_irqrestore(&bus->dpc_tl_lock, flags); 2635b948a85c1f26d48395de8c6c7e392f008f1be666Franky Lin 2636b948a85c1f26d48395de8c6c7e392f008f1be666Franky Lin if (bus->sdiodev->bus_if->state == BRCMF_BUS_DOWN) { 26375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* after stopping the bus, exit thread */ 263894c2fb82bd7c9055bec8e410c387befce33d1299Franky Lin brcmf_sdbrcm_bus_stop(bus->sdiodev->dev); 26395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->dpc_tsk = NULL; 2640cf04317227d0c53d931a0b963e7ac6f7f0125e8aFranky Lin spin_lock_irqsave(&bus->dpc_tl_lock, flags); 26415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel break; 26425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 2643b948a85c1f26d48395de8c6c7e392f008f1be666Franky Lin 2644b948a85c1f26d48395de8c6c7e392f008f1be666Franky Lin if (brcmf_sdbrcm_dpc(bus)) 2645b948a85c1f26d48395de8c6c7e392f008f1be666Franky Lin brcmf_sdbrcm_adddpctsk(bus); 2646b948a85c1f26d48395de8c6c7e392f008f1be666Franky Lin 2647b948a85c1f26d48395de8c6c7e392f008f1be666Franky Lin spin_lock_irqsave(&bus->dpc_tl_lock, flags); 2648b948a85c1f26d48395de8c6c7e392f008f1be666Franky Lin list_del(cur_hd); 2649b948a85c1f26d48395de8c6c7e392f008f1be666Franky Lin kfree(cur_hd); 2650b948a85c1f26d48395de8c6c7e392f008f1be666Franky Lin } 2651b948a85c1f26d48395de8c6c7e392f008f1be666Franky Lin spin_unlock_irqrestore(&bus->dpc_tl_lock, flags); 26525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 26535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return 0; 26545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 26555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 2656b9692d17e842fadb8c18faf24f550db80886763eFranky Linstatic int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt) 26575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 26585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel int ret = -EBADE; 26595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint datalen, prec; 2660bf347bb9768ab0da028a0d9f92142df738211debFranky Lin struct brcmf_bus *bus_if = dev_get_drvdata(dev); 26610a332e4678e4e4f0030f10827980c72d32300274Arend van Spriel struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; 2662bf347bb9768ab0da028a0d9f92142df738211debFranky Lin struct brcmf_sdio *bus = sdiodev->bus; 26635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 26645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(TRACE, "Enter\n"); 26655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 26665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel datalen = pkt->len; 26675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 26685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Add space for the header */ 26695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel skb_push(pkt, SDPCM_HDRLEN); 26705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* precondition: IS_ALIGNED((unsigned long)(pkt->data), 2) */ 26715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 26725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel prec = prio2prec((pkt->priority & PRIOMASK)); 26735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 26745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Check for existing queue, current flow-control, 26755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel pending event, or pending clock */ 26765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(TRACE, "deferring pktq len %d\n", pktq_len(&bus->txq)); 26775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->fcqueued++; 26785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 26795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Priority based enq */ 26805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_lock_bh(&bus->txqlock); 268123677ce3172fcb93522a1df077d21019e73ee1e3Joe Perches if (!brcmf_c_prec_enq(bus->sdiodev->dev, &bus->txq, pkt, prec)) { 26825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel skb_pull(pkt, SDPCM_HDRLEN); 2683c995788f4761f175f811cbeabb2f88ab8565ec1eFranky Lin brcmf_txcomplete(bus->sdiodev->dev, pkt, false); 26845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmu_pkt_buf_free_skb(pkt); 26855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "out of bus->txq !!!\n"); 26865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel ret = -ENOSR; 26875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } else { 26885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel ret = 0; 26895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 26905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_unlock_bh(&bus->txqlock); 26915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 2692c8bf34849f92c5894a3d7e12573d3789d7851f23Franky Lin if (pktq_len(&bus->txq) >= TXHI) { 2693c8bf34849f92c5894a3d7e12573d3789d7851f23Franky Lin bus->txoff = ON; 26942b4590569ead15fb88a83c1d8a07e3ca5507f4c6Franky Lin brcmf_txflowcontrol(bus->sdiodev->dev, 0, ON); 2695c8bf34849f92c5894a3d7e12573d3789d7851f23Franky Lin } 26965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 26978ae746543c8370fd04c28aaf8f185c1687b0e694Joe Perches#ifdef DEBUG 26985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (pktq_plen(&bus->txq, prec) > qcount[prec]) 26995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel qcount[prec] = pktq_plen(&bus->txq, prec); 27005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#endif 27015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Schedule DPC if needed to send queued packet(s) */ 27025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (!bus->dpc_sched) { 27035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->dpc_sched = true; 2704b948a85c1f26d48395de8c6c7e392f008f1be666Franky Lin if (bus->dpc_tsk) { 2705b948a85c1f26d48395de8c6c7e392f008f1be666Franky Lin brcmf_sdbrcm_adddpctsk(bus); 27065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel complete(&bus->dpc_wait); 2707b948a85c1f26d48395de8c6c7e392f008f1be666Franky Lin } 27085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 27095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 27105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return ret; 27115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 27125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 27135b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic int 2714e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linbrcmf_sdbrcm_membytes(struct brcmf_sdio *bus, bool write, u32 address, u8 *data, 27155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint size) 27165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 27175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel int bcmerror = 0; 27185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 sdaddr; 27195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint dsize; 27205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 27215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Determine initial transfer parameters */ 27225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel sdaddr = address & SBSDIO_SB_OFT_ADDR_MASK; 27235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if ((sdaddr + size) & SBSDIO_SBWINDOW_MASK) 27245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel dsize = (SBSDIO_SB_OFT_ADDR_LIMIT - sdaddr); 27255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel else 27265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel dsize = size; 27275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 27285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Set the backplane window to include the start address */ 27295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bcmerror = brcmf_sdcard_set_sbaddr_window(bus->sdiodev, address); 27305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bcmerror) { 27315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "window change failed\n"); 27325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto xfer_done; 27335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 27345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 27355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Do the transfer(s) */ 27365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel while (size) { 27375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(INFO, "%s %d bytes at offset 0x%08x in window 0x%08x\n", 27385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel write ? "write" : "read", dsize, 27395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel sdaddr, address & SBSDIO_SBWINDOW_MASK); 27405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bcmerror = brcmf_sdcard_rwdata(bus->sdiodev, write, 27415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel sdaddr, data, dsize); 27425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bcmerror) { 27435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "membytes transfer failed\n"); 27445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel break; 27455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 27465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 27475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Adjust for next transfer (if any) */ 27485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel size -= dsize; 27495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (size) { 27505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel data += dsize; 27515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel address += dsize; 27525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bcmerror = brcmf_sdcard_set_sbaddr_window(bus->sdiodev, 27535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel address); 27545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bcmerror) { 27555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "window change failed\n"); 27565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel break; 27575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 27585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel sdaddr = 0; 27595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel dsize = min_t(uint, SBSDIO_SB_OFT_ADDR_LIMIT, size); 27605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 27615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 27625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 27635b435de0d786869c95d1962121af0d7df2542009Arend van Sprielxfer_done: 27645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Return the window to backplane enumeration space for core access */ 27655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (brcmf_sdcard_set_sbaddr_window(bus->sdiodev, bus->sdiodev->sbwad)) 27665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "FAILED to set window back to 0x%x\n", 27675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->sdiodev->sbwad); 27685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 27695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return bcmerror; 27705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 27715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 27728ae746543c8370fd04c28aaf8f185c1687b0e694Joe Perches#ifdef DEBUG 27735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define CONSOLE_LINE_MAX 192 27745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 2775e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic int brcmf_sdbrcm_readconsole(struct brcmf_sdio *bus) 27765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 27775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct brcmf_console *c = &bus->console; 27785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 line[CONSOLE_LINE_MAX], ch; 27795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 n, idx, addr; 27805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel int rv; 27815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 27825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Don't do anything until FWREADY updates console address */ 27835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bus->console_addr == 0) 27845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return 0; 27855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 27865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Read console log struct */ 27875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel addr = bus->console_addr + offsetof(struct rte_console, log_le); 27885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel rv = brcmf_sdbrcm_membytes(bus, false, addr, (u8 *)&c->log_le, 27895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel sizeof(c->log_le)); 27905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (rv < 0) 27915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return rv; 27925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 27935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Allocate console buffer (one time only) */ 27945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (c->buf == NULL) { 27955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel c->bufsize = le32_to_cpu(c->log_le.buf_size); 27965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel c->buf = kmalloc(c->bufsize, GFP_ATOMIC); 27975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (c->buf == NULL) 27985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return -ENOMEM; 27995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 28005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 28015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel idx = le32_to_cpu(c->log_le.idx); 28025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 28035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Protect against corrupt value */ 28045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (idx > c->bufsize) 28055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return -EBADE; 28065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 28075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Skip reading the console buffer if the index pointer 28085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel has not moved */ 28095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (idx == c->last) 28105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return 0; 28115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 28125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Read the console buffer */ 28135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel addr = le32_to_cpu(c->log_le.buf); 28145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel rv = brcmf_sdbrcm_membytes(bus, false, addr, c->buf, c->bufsize); 28155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (rv < 0) 28165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return rv; 28175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 28185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel while (c->last != idx) { 28195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) { 28205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (c->last == idx) { 28215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* This would output a partial line. 28225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * Instead, back up 28235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * the buffer pointer and output this 28245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * line next time around. 28255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 28265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (c->last >= n) 28275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel c->last -= n; 28285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel else 28295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel c->last = c->bufsize - n; 28305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto break2; 28315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 28325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel ch = c->buf[c->last]; 28335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel c->last = (c->last + 1) % c->bufsize; 28345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (ch == '\n') 28355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel break; 28365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel line[n] = ch; 28375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 28385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 28395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (n > 0) { 28405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (line[n - 1] == '\r') 28415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel n--; 28425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel line[n] = 0; 284318aad4f8e11530fd7e41d0faea0752c3a0ce799cJoe Perches pr_debug("CONSOLE: %s\n", line); 28445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 28455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 28465b435de0d786869c95d1962121af0d7df2542009Arend van Sprielbreak2: 28475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 28485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return 0; 28495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 28508ae746543c8370fd04c28aaf8f185c1687b0e694Joe Perches#endif /* DEBUG */ 28515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 2852e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic int brcmf_tx_frame(struct brcmf_sdio *bus, u8 *frame, u16 len) 28535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 28545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel int i; 28555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel int ret; 28565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 28575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->ctrl_frame_stat = false; 28585adfeb632c52a6c15e98fa6465bdade6fff915d9Arend van Spriel ret = brcmf_sdcard_send_buf(bus->sdiodev, bus->sdiodev->sbwad, 28595adfeb632c52a6c15e98fa6465bdade6fff915d9Arend van Spriel SDIO_FUNC_2, F2SYNC, frame, len); 28605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 28615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (ret < 0) { 28625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* On failure, abort the command and terminate the frame */ 28635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n", 28645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel ret); 28655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->tx_sderrs++; 28665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 28675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2); 28685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 28695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, 28705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SBSDIO_FUNC1_FRAMECTRL, 28715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SFC_WF_TERM, NULL); 28725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->f1regdata++; 28735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 28745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel for (i = 0; i < 3; i++) { 28755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 hi, lo; 28765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel hi = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, 28775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SBSDIO_FUNC1_WFRAMEBCHI, 28785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel NULL); 28795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel lo = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, 28805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SBSDIO_FUNC1_WFRAMEBCLO, 28815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel NULL); 28825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->f1regdata += 2; 28835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (hi == 0 && lo == 0) 28845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel break; 28855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 28865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return ret; 28875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 28885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 28895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; 28905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 28915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return ret; 28925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 28935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 2894fcf094f414f9e9c088f6c2aa9e19a59f7b41e1f5Franky Linstatic int 289547a1ce78d544b9fb3b776a62de3c084cf0020fdaFranky Linbrcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen) 28965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 28975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 *frame; 28985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u16 len; 28995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 swheader; 29005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint retries = 0; 29015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 doff = 0; 29025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel int ret = -1; 290347a1ce78d544b9fb3b776a62de3c084cf0020fdaFranky Lin struct brcmf_bus *bus_if = dev_get_drvdata(dev); 29040a332e4678e4e4f0030f10827980c72d32300274Arend van Spriel struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; 290547a1ce78d544b9fb3b776a62de3c084cf0020fdaFranky Lin struct brcmf_sdio *bus = sdiodev->bus; 29065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 29075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(TRACE, "Enter\n"); 29085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 29095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Back the pointer to make a room for bus header */ 29105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel frame = msg - SDPCM_HDRLEN; 29115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel len = (msglen += SDPCM_HDRLEN); 29125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 29135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Add alignment padding (optional for ctl frames) */ 29145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel doff = ((unsigned long)frame % BRCMF_SDALIGN); 29155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (doff) { 29165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel frame -= doff; 29175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel len += doff; 29185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel msglen += doff; 29195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel memset(frame, 0, doff + SDPCM_HDRLEN); 29205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 29215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* precondition: doff < BRCMF_SDALIGN */ 29225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel doff += SDPCM_HDRLEN; 29235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 29245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Round send length to next SDIO block */ 29255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bus->roundup && bus->blocksize && (len > bus->blocksize)) { 29265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u16 pad = bus->blocksize - (len % bus->blocksize); 29275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if ((pad <= bus->roundup) && (pad < bus->blocksize)) 29285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel len += pad; 29295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } else if (len % BRCMF_SDALIGN) { 29305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel len += BRCMF_SDALIGN - (len % BRCMF_SDALIGN); 29315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 29325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 29335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Satisfy length-alignment requirements */ 29345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (len & (ALIGNMENT - 1)) 29355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel len = roundup(len, ALIGNMENT); 29365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 29375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* precondition: IS_ALIGNED((unsigned long)frame, 2) */ 29385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 29395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Need to lock here to protect txseq and SDIO tx calls */ 29405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel down(&bus->sdsem); 29415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 29425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus_wake(bus); 29435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 29445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Make sure backplane clock is on */ 29455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); 29465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 29475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */ 29485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel *(__le16 *) frame = cpu_to_le16((u16) msglen); 29495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel *(((__le16 *) frame) + 1) = cpu_to_le16(~msglen); 29505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 29515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Software tag: channel, sequence number, data offset */ 29525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel swheader = 29535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) & 29545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SDPCM_CHANNEL_MASK) 29555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel | bus->tx_seq | ((doff << SDPCM_DOFFSET_SHIFT) & 29565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SDPCM_DOFFSET_MASK); 29575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel put_unaligned_le32(swheader, frame + SDPCM_FRAMETAG_LEN); 29585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel put_unaligned_le32(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader)); 29595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 29605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (!data_ok(bus)) { 29615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(INFO, "No bus credit bus->tx_max %d, bus->tx_seq %d\n", 29625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->tx_max, bus->tx_seq); 29635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->ctrl_frame_stat = true; 29645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Send from dpc */ 29655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->ctrl_frame_buf = frame; 29665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->ctrl_frame_len = len; 29675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 29685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_wait_for_event(bus, &bus->ctrl_frame_stat); 29695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 297023677ce3172fcb93522a1df077d21019e73ee1e3Joe Perches if (!bus->ctrl_frame_stat) { 29715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(INFO, "ctrl_frame_stat == false\n"); 29725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel ret = 0; 29735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } else { 29745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(INFO, "ctrl_frame_stat == true\n"); 29755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel ret = -1; 29765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 29775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 29785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 29795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (ret == -1) { 29801e02382979dd422e3b1bdb45545a0699497e3692Joe Perches brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && BRCMF_CTL_ON(), 29811e02382979dd422e3b1bdb45545a0699497e3692Joe Perches frame, len, "Tx Frame:\n"); 29821e02382979dd422e3b1bdb45545a0699497e3692Joe Perches brcmf_dbg_hex_dump(!(BRCMF_BYTES_ON() && BRCMF_CTL_ON()) && 29831e02382979dd422e3b1bdb45545a0699497e3692Joe Perches BRCMF_HDRS_ON(), 29841e02382979dd422e3b1bdb45545a0699497e3692Joe Perches frame, min_t(u16, len, 16), "TxHdr:\n"); 29855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 29865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel do { 29875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel ret = brcmf_tx_frame(bus, frame, len); 29885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } while (ret < 0 && retries++ < TXRETRIES); 29895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 29905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 29915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if ((bus->idletime == BRCMF_IDLE_IMMEDIATE) && !bus->dpc_sched) { 29925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->activity = false; 29935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_clkctl(bus, CLK_NONE, true); 29945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 29955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 29965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel up(&bus->sdsem); 29975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 29985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (ret) 299928a1a3bdaf4cce5ee8e473c332e2f371888341bbFranky Lin bus->tx_ctlerrs++; 30005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel else 300128a1a3bdaf4cce5ee8e473c332e2f371888341bbFranky Lin bus->tx_ctlpkts++; 30025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 30035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return ret ? -EIO : 0; 30045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 30055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 3006fcf094f414f9e9c088f6c2aa9e19a59f7b41e1f5Franky Linstatic int 3007532cdd3b99b7a89fdc128c2b58abea780f3bbb4dFranky Linbrcmf_sdbrcm_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen) 30085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 30095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel int timeleft; 30105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint rxlen = 0; 30115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bool pending; 3012532cdd3b99b7a89fdc128c2b58abea780f3bbb4dFranky Lin struct brcmf_bus *bus_if = dev_get_drvdata(dev); 30130a332e4678e4e4f0030f10827980c72d32300274Arend van Spriel struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; 3014532cdd3b99b7a89fdc128c2b58abea780f3bbb4dFranky Lin struct brcmf_sdio *bus = sdiodev->bus; 30155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 30165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(TRACE, "Enter\n"); 30175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 30185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Wait until control frame is available */ 30195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel timeleft = brcmf_sdbrcm_dcmd_resp_wait(bus, &bus->rxlen, &pending); 30205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 30215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel down(&bus->sdsem); 30225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel rxlen = bus->rxlen; 30235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel memcpy(msg, bus->rxctl, min(msglen, rxlen)); 30245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->rxlen = 0; 30255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel up(&bus->sdsem); 30265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 30275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (rxlen) { 30285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(CTL, "resumed on rxctl frame, got %d expected %d\n", 30295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel rxlen, msglen); 30305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } else if (timeleft == 0) { 30315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "resumed on timeout\n"); 303223677ce3172fcb93522a1df077d21019e73ee1e3Joe Perches } else if (pending) { 30335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(CTL, "cancelled\n"); 30345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return -ERESTARTSYS; 30355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } else { 30365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(CTL, "resumed for unknown reason?\n"); 30375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 30385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 30395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (rxlen) 304028a1a3bdaf4cce5ee8e473c332e2f371888341bbFranky Lin bus->rx_ctlpkts++; 30415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel else 304228a1a3bdaf4cce5ee8e473c332e2f371888341bbFranky Lin bus->rx_ctlerrs++; 30435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 30445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return rxlen ? (int)rxlen : -ETIMEDOUT; 30455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 30465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 3047e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic int brcmf_sdbrcm_downloadvars(struct brcmf_sdio *bus, void *arg, int len) 30485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 30495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel int bcmerror = 0; 30505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 30515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(TRACE, "Enter\n"); 30525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 30535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Basic sanity checks */ 30543fb1d8d2dad35f5094350c175b778b78df894284Franky Lin if (bus->sdiodev->bus_if->drvr_up) { 30555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bcmerror = -EISCONN; 30565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto err; 30575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 30585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (!len) { 30595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bcmerror = -EOVERFLOW; 30605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto err; 30615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 30625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 30635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Free the old ones and replace with passed variables */ 30645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel kfree(bus->vars); 30655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 30665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->vars = kmalloc(len, GFP_ATOMIC); 30675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->varsz = bus->vars ? len : 0; 30685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bus->vars == NULL) { 30695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bcmerror = -ENOMEM; 30705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto err; 30715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 30725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 30735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Copy the passed variables, which should include the 30745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel terminating double-null */ 30755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel memcpy(bus->vars, arg, bus->varsz); 30765b435de0d786869c95d1962121af0d7df2542009Arend van Sprielerr: 30775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return bcmerror; 30785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 30795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 3080e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic int brcmf_sdbrcm_write_vars(struct brcmf_sdio *bus) 30815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 30825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel int bcmerror = 0; 30835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 varsize; 30845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 varaddr; 30855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 *vbuffer; 30865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 varsizew; 30875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel __le32 varsizew_le; 30888ae746543c8370fd04c28aaf8f185c1687b0e694Joe Perches#ifdef DEBUG 30895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel char *nvram_ularray; 30908ae746543c8370fd04c28aaf8f185c1687b0e694Joe Perches#endif /* DEBUG */ 30915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 30925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Even if there are no vars are to be written, we still 30935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel need to set the ramsize. */ 30945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel varsize = bus->varsz ? roundup(bus->varsz, 4) : 0; 30955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel varaddr = (bus->ramsize - 4) - varsize; 30965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 30975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bus->vars) { 30985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel vbuffer = kzalloc(varsize, GFP_ATOMIC); 30995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (!vbuffer) 31005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return -ENOMEM; 31015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 31025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel memcpy(vbuffer, bus->vars, bus->varsz); 31035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 31045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Write the vars list */ 31055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bcmerror = 31065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_membytes(bus, true, varaddr, vbuffer, varsize); 31078ae746543c8370fd04c28aaf8f185c1687b0e694Joe Perches#ifdef DEBUG 31085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Verify NVRAM bytes */ 31095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(INFO, "Compare NVRAM dl & ul; varsize=%d\n", varsize); 31105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel nvram_ularray = kmalloc(varsize, GFP_ATOMIC); 3111c40701eacbaebcfe3fb6fac8ef3da653021c212cJesper Juhl if (!nvram_ularray) { 3112c40701eacbaebcfe3fb6fac8ef3da653021c212cJesper Juhl kfree(vbuffer); 31135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return -ENOMEM; 3114c40701eacbaebcfe3fb6fac8ef3da653021c212cJesper Juhl } 31155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 31165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Upload image to verify downloaded contents. */ 31175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel memset(nvram_ularray, 0xaa, varsize); 31185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 31195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Read the vars list to temp buffer for comparison */ 31205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bcmerror = 31215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_membytes(bus, false, varaddr, nvram_ularray, 31225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel varsize); 31235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bcmerror) { 31245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "error %d on reading %d nvram bytes at 0x%08x\n", 31255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bcmerror, varsize, varaddr); 31265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 31275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Compare the org NVRAM with the one read from RAM */ 31285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (memcmp(vbuffer, nvram_ularray, varsize)) 31295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "Downloaded NVRAM image is corrupted\n"); 31305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel else 31315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "Download/Upload/Compare of NVRAM ok\n"); 31325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 31335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel kfree(nvram_ularray); 31348ae746543c8370fd04c28aaf8f185c1687b0e694Joe Perches#endif /* DEBUG */ 31355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 31365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel kfree(vbuffer); 31375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 31385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 31395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* adjust to the user specified RAM */ 31405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(INFO, "Physical memory size: %d\n", bus->ramsize); 31415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(INFO, "Vars are at %d, orig varsize is %d\n", 31425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel varaddr, varsize); 31435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel varsize = ((bus->ramsize - 4) - varaddr); 31445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 31455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* 31465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * Determine the length token: 31475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * Varsize, converted to words, in lower 16-bits, checksum 31485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * in upper 16-bits. 31495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 31505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bcmerror) { 31515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel varsizew = 0; 31525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel varsizew_le = cpu_to_le32(0); 31535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } else { 31545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel varsizew = varsize / 4; 31555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF); 31565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel varsizew_le = cpu_to_le32(varsizew); 31575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 31585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 31595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(INFO, "New varsize is %d, length token=0x%08x\n", 31605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel varsize, varsizew); 31615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 31625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Write the length token to the last word */ 31635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bcmerror = brcmf_sdbrcm_membytes(bus, true, (bus->ramsize - 4), 31645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel (u8 *)&varsizew_le, 4); 31655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 31665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return bcmerror; 31675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 31685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 3169e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic int brcmf_sdbrcm_download_state(struct brcmf_sdio *bus, bool enter) 31705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 31715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint retries; 31725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel int bcmerror = 0; 317399ba15cd75ed22e4ae86804ca2982a724e8102c2Franky Lin struct chip_info *ci = bus->ci; 31745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 31755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* To enter download state, disable ARM and reset SOCRAM. 31765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * To exit download state, simply reset ARM (default is RAM boot). 31775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 31785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (enter) { 31795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->alp_only = true; 31805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 3181086a2e0a63eef367dab9b4499ba0cfe3a309ec94Franky Lin ci->coredisable(bus->sdiodev, ci, BCMA_CORE_ARM_CM3); 31825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 3183d77e70ff5ace175f19447a1965691a794c27de24Franky Lin ci->resetcore(bus->sdiodev, ci, BCMA_CORE_INTERNAL_MEM); 31845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 31855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Clear the top bit of memory */ 31865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bus->ramsize) { 31875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 zeros = 0; 31885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_membytes(bus, true, bus->ramsize - 4, 31895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel (u8 *)&zeros, 4); 31905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 31915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } else { 31926ca687d9461b25ce2339ba1809ec13ef459d4661Franky Lin if (!ci->iscoreup(bus->sdiodev, ci, BCMA_CORE_INTERNAL_MEM)) { 31935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "SOCRAM core is down after reset?\n"); 31945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bcmerror = -EBADE; 31955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto fail; 31965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 31975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 31985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bcmerror = brcmf_sdbrcm_write_vars(bus); 31995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bcmerror) { 32005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "no vars written to RAM\n"); 32015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bcmerror = 0; 32025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 32035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 32045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel w_sdreg32(bus, 0xFFFFFFFF, 32055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel offsetof(struct sdpcmd_regs, intstatus), &retries); 32065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 3207d77e70ff5ace175f19447a1965691a794c27de24Franky Lin ci->resetcore(bus->sdiodev, ci, BCMA_CORE_ARM_CM3); 32085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 32095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Allow HT Clock now that the ARM is running. */ 32105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->alp_only = false; 32115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 3212712ac5b37a3348cac4e040c551a6ca6186d33682Franky Lin bus->sdiodev->bus_if->state = BRCMF_BUS_LOAD; 32135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 32145b435de0d786869c95d1962121af0d7df2542009Arend van Sprielfail: 32155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return bcmerror; 32165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 32175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 3218e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic int brcmf_sdbrcm_get_image(char *buf, int len, struct brcmf_sdio *bus) 32195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 32205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bus->firmware->size < bus->fw_ptr + len) 32215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel len = bus->firmware->size - bus->fw_ptr; 32225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 32235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel memcpy(buf, &bus->firmware->data[bus->fw_ptr], len); 32245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->fw_ptr += len; 32255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return len; 32265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 32275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 3228e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic int brcmf_sdbrcm_download_code_file(struct brcmf_sdio *bus) 32295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 32305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel int offset = 0; 32315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint len; 32325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 *memblock = NULL, *memptr; 32335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel int ret; 32345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 32355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(INFO, "Enter\n"); 32365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 323752e1409f72d629644b496db80c119e04ebabad90Arend van Spriel ret = request_firmware(&bus->firmware, BRCMF_SDIO_FW_NAME, 32385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel &bus->sdiodev->func[2]->dev); 32395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (ret) { 32405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "Fail to request firmware %d\n", ret); 32415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return ret; 32425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 32435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->fw_ptr = 0; 32445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 32455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel memptr = memblock = kmalloc(MEMBLOCK + BRCMF_SDALIGN, GFP_ATOMIC); 32465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (memblock == NULL) { 32475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel ret = -ENOMEM; 32485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto err; 32495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 32505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if ((u32)(unsigned long)memblock % BRCMF_SDALIGN) 32515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel memptr += (BRCMF_SDALIGN - 32525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel ((u32)(unsigned long)memblock % BRCMF_SDALIGN)); 32535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 32545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Download image */ 32555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel while ((len = 32565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_get_image((char *)memptr, MEMBLOCK, bus))) { 32575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel ret = brcmf_sdbrcm_membytes(bus, true, offset, memptr, len); 32585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (ret) { 32595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "error %d on writing %d membytes at 0x%08x\n", 32605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel ret, MEMBLOCK, offset); 32615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto err; 32625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 32635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 32645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel offset += MEMBLOCK; 32655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 32665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 32675b435de0d786869c95d1962121af0d7df2542009Arend van Sprielerr: 32685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel kfree(memblock); 32695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 32705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel release_firmware(bus->firmware); 32715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->fw_ptr = 0; 32725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 32735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return ret; 32745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 32755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 32765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* 32775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * ProcessVars:Takes a buffer of "<var>=<value>\n" lines read from a file 32785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * and ending in a NUL. 32795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * Removes carriage returns, empty lines, comment lines, and converts 32805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * newlines to NULs. 32815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * Shortens buffer as needed and pads with NULs. End of buffer is marked 32825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * by two NULs. 32835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel*/ 32845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 32855b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic uint brcmf_process_nvram_vars(char *varbuf, uint len) 32865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 32875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel char *dp; 32885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bool findNewline; 32895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel int column; 32905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint buf_len, n; 32915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 32925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel dp = varbuf; 32935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 32945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel findNewline = false; 32955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel column = 0; 32965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 32975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel for (n = 0; n < len; n++) { 32985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (varbuf[n] == 0) 32995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel break; 33005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (varbuf[n] == '\r') 33015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel continue; 33025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (findNewline && varbuf[n] != '\n') 33035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel continue; 33045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel findNewline = false; 33055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (varbuf[n] == '#') { 33065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel findNewline = true; 33075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel continue; 33085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 33095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (varbuf[n] == '\n') { 33105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (column == 0) 33115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel continue; 33125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel *dp++ = 0; 33135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel column = 0; 33145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel continue; 33155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 33165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel *dp++ = varbuf[n]; 33175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel column++; 33185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 33195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel buf_len = dp - varbuf; 33205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 33215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel while (dp < varbuf + n) 33225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel *dp++ = 0; 33235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 33245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return buf_len; 33255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 33265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 3327e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic int brcmf_sdbrcm_download_nvram(struct brcmf_sdio *bus) 33285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 33295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint len; 33305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel char *memblock = NULL; 33315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel char *bufp; 33325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel int ret; 33335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 333452e1409f72d629644b496db80c119e04ebabad90Arend van Spriel ret = request_firmware(&bus->firmware, BRCMF_SDIO_NV_NAME, 33355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel &bus->sdiodev->func[2]->dev); 33365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (ret) { 33375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "Fail to request nvram %d\n", ret); 33385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return ret; 33395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 33405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->fw_ptr = 0; 33415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 33425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel memblock = kmalloc(MEMBLOCK, GFP_ATOMIC); 33435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (memblock == NULL) { 33445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel ret = -ENOMEM; 33455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto err; 33465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 33475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 33485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel len = brcmf_sdbrcm_get_image(memblock, MEMBLOCK, bus); 33495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 33505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (len > 0 && len < MEMBLOCK) { 33515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bufp = (char *)memblock; 33525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bufp[len] = 0; 33535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel len = brcmf_process_nvram_vars(bufp, len); 33545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bufp += len; 33555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel *bufp++ = 0; 33565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (len) 33575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel ret = brcmf_sdbrcm_downloadvars(bus, memblock, len + 1); 33585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (ret) 33595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "error downloading vars: %d\n", ret); 33605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } else { 33615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "error reading nvram file: %d\n", len); 33625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel ret = -EIO; 33635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 33645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 33655b435de0d786869c95d1962121af0d7df2542009Arend van Sprielerr: 33665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel kfree(memblock); 33675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 33685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel release_firmware(bus->firmware); 33695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->fw_ptr = 0; 33705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 33715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return ret; 33725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 33735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 3374e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic int _brcmf_sdbrcm_download_firmware(struct brcmf_sdio *bus) 33755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 33765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel int bcmerror = -1; 33775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 33785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Keep arm in reset */ 33795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (brcmf_sdbrcm_download_state(bus, true)) { 33805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "error placing ARM core in reset\n"); 33815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto err; 33825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 33835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 33845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* External image takes precedence if specified */ 33855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (brcmf_sdbrcm_download_code_file(bus)) { 33865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "dongle image file download failed\n"); 33875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto err; 33885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 33895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 33905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* External nvram takes precedence if specified */ 33915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (brcmf_sdbrcm_download_nvram(bus)) 33925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "dongle nvram file download failed\n"); 33935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 33945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Take arm out of reset */ 33955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (brcmf_sdbrcm_download_state(bus, false)) { 33965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "error getting out of ARM core reset\n"); 33975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto err; 33985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 33995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 34005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bcmerror = 0; 34015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 34025b435de0d786869c95d1962121af0d7df2542009Arend van Sprielerr: 34035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return bcmerror; 34045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 34055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 34065b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic bool 3407e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linbrcmf_sdbrcm_download_firmware(struct brcmf_sdio *bus) 34085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 34095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bool ret; 34105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 34115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Download the firmware */ 34125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); 34135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 34145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel ret = _brcmf_sdbrcm_download_firmware(bus) == 0; 34155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 34165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false); 34175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 34185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return ret; 34195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 34205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 342199a0b8ff9105d9b78e7e4e6aaa077264707e4e1cFranky Linstatic int brcmf_sdbrcm_bus_init(struct device *dev) 34225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 3423fa20b91143c616d402f1ed61f27693477279d0c6Franky Lin struct brcmf_bus *bus_if = dev_get_drvdata(dev); 34240a332e4678e4e4f0030f10827980c72d32300274Arend van Spriel struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; 3425fa20b91143c616d402f1ed61f27693477279d0c6Franky Lin struct brcmf_sdio *bus = sdiodev->bus; 34265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel unsigned long timeout; 34275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel uint retries = 0; 34285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 ready, enable; 34295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel int err, ret = 0; 34305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 saveclk; 34315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 34325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(TRACE, "Enter\n"); 34335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 34345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* try to download image and nvram to the dongle */ 3435fa20b91143c616d402f1ed61f27693477279d0c6Franky Lin if (bus_if->state == BRCMF_BUS_DOWN) { 34365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (!(brcmf_sdbrcm_download_firmware(bus))) 34375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return -1; 34385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 34395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 3440712ac5b37a3348cac4e040c551a6ca6186d33682Franky Lin if (!bus->sdiodev->bus_if->drvr) 34415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return 0; 34425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 34435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Start the watchdog timer */ 344428a1a3bdaf4cce5ee8e473c332e2f371888341bbFranky Lin bus->tickcnt = 0; 34455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS); 34465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 34475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel down(&bus->sdsem); 34485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 34495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Make sure backplane clock is on, needed to generate F2 interrupt */ 34505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); 34515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bus->clkstate != CLK_AVAIL) 34525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto exit; 34535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 34545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Force clocks on backplane to be sure F2 interrupt propagates */ 34555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel saveclk = 34565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, 34575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SBSDIO_FUNC1_CHIPCLKCSR, &err); 34585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (!err) { 34595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, 34605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SBSDIO_FUNC1_CHIPCLKCSR, 34615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel (saveclk | SBSDIO_FORCE_HT), &err); 34625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 34635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (err) { 34645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "Failed to force clock for F2: err %d\n", err); 34655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto exit; 34665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 34675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 34685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Enable function 2 (frame transfers) */ 34695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel w_sdreg32(bus, SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT, 34705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel offsetof(struct sdpcmd_regs, tosbmailboxdata), &retries); 34715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2); 34725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 34735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx, 34745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel enable, NULL); 34755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 34765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel timeout = jiffies + msecs_to_jiffies(BRCMF_WAIT_F2RDY); 34775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel ready = 0; 34785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel while (enable != ready) { 34795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel ready = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_0, 34805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SDIO_CCCR_IORx, NULL); 34815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (time_after(jiffies, timeout)) 34825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel break; 34835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel else if (time_after(jiffies, timeout - BRCMF_WAIT_F2RDY + 50)) 34845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* prevent busy waiting if it takes too long */ 34855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel msleep_interruptible(20); 34865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 34875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 34885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(INFO, "enable 0x%02x, ready 0x%02x\n", enable, ready); 34895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 34905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* If F2 successfully enabled, set core and enable interrupts */ 34915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (ready == enable) { 34925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Set up the interrupt mask and enable interrupts */ 34935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->hostintmask = HOSTINTMASK; 34945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel w_sdreg32(bus, bus->hostintmask, 34955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel offsetof(struct sdpcmd_regs, hostintmask), &retries); 34965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 34975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, 34985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SBSDIO_WATERMARK, 8, &err); 3499c0e89f084b5089acdfdda1cb45c88896fa0f5139Arend van Spriel } else { 35005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Disable F2 again */ 35015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel enable = SDIO_FUNC_ENABLE_1; 35025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, 35035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SDIO_CCCR_IOEx, enable, NULL); 3504c0e89f084b5089acdfdda1cb45c88896fa0f5139Arend van Spriel ret = -ENODEV; 35055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 35065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 35075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Restore previous clock setting */ 35085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, 35095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err); 35105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 35115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* If we didn't come up, turn off backplane clock */ 3512c0e89f084b5089acdfdda1cb45c88896fa0f5139Arend van Spriel if (!ret) 35135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_clkctl(bus, CLK_NONE, false); 35145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 35155b435de0d786869c95d1962121af0d7df2542009Arend van Sprielexit: 35165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel up(&bus->sdsem); 35175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 35185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return ret; 35195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 35205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 35215b435de0d786869c95d1962121af0d7df2542009Arend van Sprielvoid brcmf_sdbrcm_isr(void *arg) 35225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 3523e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Lin struct brcmf_sdio *bus = (struct brcmf_sdio *) arg; 35245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 35255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(TRACE, "Enter\n"); 35265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 35275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (!bus) { 35285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "bus is null pointer, exiting\n"); 35295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return; 35305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 35315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 3532712ac5b37a3348cac4e040c551a6ca6186d33682Franky Lin if (bus->sdiodev->bus_if->state == BRCMF_BUS_DOWN) { 35335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "bus is down. we have nothing to do\n"); 35345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return; 35355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 35365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Count the interrupt call */ 35375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->intrcount++; 35385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->ipend = true; 35395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 35405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Shouldn't get this interrupt if we're sleeping? */ 35415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bus->sleeping) { 35425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "INTERRUPT WHILE SLEEPING??\n"); 35435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return; 35445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 35455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 35465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Disable additional interrupts (is this needed now)? */ 35475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (!bus->intr) 35485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "isr w/o interrupt configured!\n"); 35495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 35505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->dpc_sched = true; 3551b948a85c1f26d48395de8c6c7e392f008f1be666Franky Lin if (bus->dpc_tsk) { 3552b948a85c1f26d48395de8c6c7e392f008f1be666Franky Lin brcmf_sdbrcm_adddpctsk(bus); 35535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel complete(&bus->dpc_wait); 3554b948a85c1f26d48395de8c6c7e392f008f1be666Franky Lin } 35555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 35565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 3557cad2b26b1010d0694d2f08d408486451b9f919d2Franky Linstatic bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus) 35585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 35598ae746543c8370fd04c28aaf8f185c1687b0e694Joe Perches#ifdef DEBUG 3560cad2b26b1010d0694d2f08d408486451b9f919d2Franky Lin struct brcmf_bus *bus_if = dev_get_drvdata(bus->sdiodev->dev); 35618ae746543c8370fd04c28aaf8f185c1687b0e694Joe Perches#endif /* DEBUG */ 35625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 35635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(TIMER, "Enter\n"); 35645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 35655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Ignore the timer if simulating bus down */ 35665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bus->sleeping) 35675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return false; 35685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 35695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel down(&bus->sdsem); 35705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 35715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Poll period: check device if appropriate. */ 35725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bus->poll && (++bus->polltick >= bus->pollrate)) { 35735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 intstatus = 0; 35745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 35755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Reset poll tick */ 35765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->polltick = 0; 35775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 35785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Check device if no interrupts */ 35795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (!bus->intr || (bus->intrcount == bus->lastintrs)) { 35805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 35815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (!bus->dpc_sched) { 35825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 devpend; 35835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel devpend = brcmf_sdcard_cfg_read(bus->sdiodev, 35845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SDIO_FUNC_0, SDIO_CCCR_INTx, 35855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel NULL); 35865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel intstatus = 35875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel devpend & (INTR_STATUS_FUNC1 | 35885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel INTR_STATUS_FUNC2); 35895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 35905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 35915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* If there is something, make like the ISR and 35925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel schedule the DPC */ 35935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (intstatus) { 35945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->pollcnt++; 35955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->ipend = true; 35965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 35975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->dpc_sched = true; 3598b948a85c1f26d48395de8c6c7e392f008f1be666Franky Lin if (bus->dpc_tsk) { 3599b948a85c1f26d48395de8c6c7e392f008f1be666Franky Lin brcmf_sdbrcm_adddpctsk(bus); 36005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel complete(&bus->dpc_wait); 3601b948a85c1f26d48395de8c6c7e392f008f1be666Franky Lin } 36025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 36035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 36045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 36055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Update interrupt tracking */ 36065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->lastintrs = bus->intrcount; 36075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 36088ae746543c8370fd04c28aaf8f185c1687b0e694Joe Perches#ifdef DEBUG 36095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Poll for console output periodically */ 3610cad2b26b1010d0694d2f08d408486451b9f919d2Franky Lin if (bus_if->state == BRCMF_BUS_DATA && 36118d169aa00d0356f915e84dbdf6c9be381cce34a4Franky Lin bus->console_interval != 0) { 36125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->console.count += BRCMF_WD_POLL_MS; 36135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bus->console.count >= bus->console_interval) { 36145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->console.count -= bus->console_interval; 36155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Make sure backplane clock is on */ 36165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); 36175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (brcmf_sdbrcm_readconsole(bus) < 0) 36185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* stop on error */ 36195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->console_interval = 0; 36205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 36215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 36228ae746543c8370fd04c28aaf8f185c1687b0e694Joe Perches#endif /* DEBUG */ 36235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 36245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* On idle timeout clear activity flag and/or turn off clock */ 36255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if ((bus->idletime > 0) && (bus->clkstate == CLK_AVAIL)) { 36265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (++bus->idlecount >= bus->idletime) { 36275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->idlecount = 0; 36285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bus->activity) { 36295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->activity = false; 36305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS); 36315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } else { 36325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_clkctl(bus, CLK_NONE, false); 36335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 36345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 36355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 36365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 36375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel up(&bus->sdsem); 36385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 36395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return bus->ipend; 36405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 36415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 36425b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic bool brcmf_sdbrcm_chipmatch(u16 chipid) 36435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 36445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (chipid == BCM4329_CHIP_ID) 36455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return true; 3646ce2d7d7e8fd88191f5d1c92a8b33aeb0cb12ea34Franky Lin if (chipid == BCM4330_CHIP_ID) 3647ce2d7d7e8fd88191f5d1c92a8b33aeb0cb12ea34Franky Lin return true; 36485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return false; 36495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 36505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 3651e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic void brcmf_sdbrcm_release_malloc(struct brcmf_sdio *bus) 36525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 36535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(TRACE, "Enter\n"); 36545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 36555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel kfree(bus->rxbuf); 36565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->rxctl = bus->rxbuf = NULL; 36575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->rxlen = 0; 36585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 36595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel kfree(bus->databuf); 36605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->databuf = NULL; 36615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 36625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 3663e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic bool brcmf_sdbrcm_probe_malloc(struct brcmf_sdio *bus) 36645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 36655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(TRACE, "Enter\n"); 36665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 3667b01a6b3ca714e2bb86ee387aee487c7360363c93Franky Lin if (bus->sdiodev->bus_if->maxctl) { 36685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->rxblen = 3669b01a6b3ca714e2bb86ee387aee487c7360363c93Franky Lin roundup((bus->sdiodev->bus_if->maxctl + SDPCM_HDRLEN), 36705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel ALIGNMENT) + BRCMF_SDALIGN; 36715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->rxbuf = kmalloc(bus->rxblen, GFP_ATOMIC); 36725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (!(bus->rxbuf)) 36735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto fail; 36745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 36755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 36765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Allocate buffer to receive glomed packet */ 36775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->databuf = kmalloc(MAX_DATA_BUF, GFP_ATOMIC); 36785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (!(bus->databuf)) { 36795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* release rxbuf which was already located as above */ 36805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (!bus->rxblen) 36815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel kfree(bus->rxbuf); 36825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto fail; 36835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 36845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 36855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Align the buffer */ 36865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if ((unsigned long)bus->databuf % BRCMF_SDALIGN) 36875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->dataptr = bus->databuf + (BRCMF_SDALIGN - 36885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel ((unsigned long)bus->databuf % BRCMF_SDALIGN)); 36895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel else 36905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->dataptr = bus->databuf; 36915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 36925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return true; 36935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 36945b435de0d786869c95d1962121af0d7df2542009Arend van Sprielfail: 36955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return false; 36965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 36975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 36985b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic bool 3699e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linbrcmf_sdbrcm_probe_attach(struct brcmf_sdio *bus, u32 regsva) 37005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 37015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 clkctl = 0; 37025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel int err = 0; 37035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel int reg_addr; 37045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 reg_val; 370599ba15cd75ed22e4ae86804ca2982a724e8102c2Franky Lin u8 idx; 37065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 37075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->alp_only = true; 37085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 37095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Return the window to backplane enumeration space for core access */ 37105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (brcmf_sdcard_set_sbaddr_window(bus->sdiodev, SI_ENUM_BASE)) 37115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "FAILED to return to SI_ENUM_BASE\n"); 37125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 371318aad4f8e11530fd7e41d0faea0752c3a0ce799cJoe Perches pr_debug("F1 signature read @0x18000000=0x%4x\n", 371418aad4f8e11530fd7e41d0faea0752c3a0ce799cJoe Perches brcmf_sdcard_reg_read(bus->sdiodev, SI_ENUM_BASE, 4)); 37155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 37165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* 3717a97e4fc5ae4b00187b25a8216a61b2105efa9c60Franky Lin * Force PLL off until brcmf_sdio_chip_attach() 37185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * programs PLL control regs 37195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 37205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 37215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, 37225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SBSDIO_FUNC1_CHIPCLKCSR, 37235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel BRCMF_INIT_CLKCTL1, &err); 37245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (!err) 37255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel clkctl = 37265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, 37275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SBSDIO_FUNC1_CHIPCLKCSR, &err); 37285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 37295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (err || ((clkctl & ~SBSDIO_AVBITS) != BRCMF_INIT_CLKCTL1)) { 37305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "ChipClkCSR access: err %d wrote 0x%02x read 0x%02x\n", 37315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel err, BRCMF_INIT_CLKCTL1, clkctl); 37325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto fail; 37335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 37345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 3735a97e4fc5ae4b00187b25a8216a61b2105efa9c60Franky Lin if (brcmf_sdio_chip_attach(bus->sdiodev, &bus->ci, regsva)) { 3736a97e4fc5ae4b00187b25a8216a61b2105efa9c60Franky Lin brcmf_dbg(ERROR, "brcmf_sdio_chip_attach failed!\n"); 37375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto fail; 37385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 37395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 37405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (!brcmf_sdbrcm_chipmatch((u16) bus->ci->chip)) { 37415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "unsupported chip: 0x%04x\n", bus->ci->chip); 37425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto fail; 37435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 37445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 3745e12afb6c5d13ebff64d4a2feb97cce0c2d7e1128Franky Lin brcmf_sdio_chip_drivestrengthinit(bus->sdiodev, bus->ci, 3746e12afb6c5d13ebff64d4a2feb97cce0c2d7e1128Franky Lin SDIO_DRIVE_STRENGTH); 37475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 3748454d2a8816d6bc6594d3d475392290623af63656Franky Lin /* Get info on the SOCRAM cores... */ 37495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->ramsize = bus->ci->ramsize; 37505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (!(bus->ramsize)) { 37515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "failed to find SOCRAM memory!\n"); 37525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto fail; 37535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 37545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 37555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Set core control so an SDIO reset does a backplane reset */ 375699ba15cd75ed22e4ae86804ca2982a724e8102c2Franky Lin idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV); 375799ba15cd75ed22e4ae86804ca2982a724e8102c2Franky Lin reg_addr = bus->ci->c_inf[idx].base + 37585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel offsetof(struct sdpcmd_regs, corecontrol); 37595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel reg_val = brcmf_sdcard_reg_read(bus->sdiodev, reg_addr, sizeof(u32)); 37605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdcard_reg_write(bus->sdiodev, reg_addr, sizeof(u32), 37615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel reg_val | CC_BPRESEN); 37625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 37635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmu_pktq_init(&bus->txq, (PRIOMASK + 1), TXQLEN); 37645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 37655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Locate an appropriately-aligned portion of hdrbuf */ 37665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->rxhdr = (u8 *) roundup((unsigned long)&bus->hdrbuf[0], 37675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel BRCMF_SDALIGN); 37685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 37695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Set the poll and/or interrupt flags */ 37705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->intr = true; 37715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->poll = false; 37725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bus->poll) 37735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->pollrate = 1; 37745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 37755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return true; 37765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 37775b435de0d786869c95d1962121af0d7df2542009Arend van Sprielfail: 37785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return false; 37795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 37805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 3781e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic bool brcmf_sdbrcm_probe_init(struct brcmf_sdio *bus) 37825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 37835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(TRACE, "Enter\n"); 37845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 37855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Disable F2 to clear any intermediate frame state on the dongle */ 37865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx, 37875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SDIO_FUNC_ENABLE_1, NULL); 37885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 3789712ac5b37a3348cac4e040c551a6ca6186d33682Franky Lin bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN; 37905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->sleeping = false; 37915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->rxflow = false; 37925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 37935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Done with backplane-dependent accesses, can drop clock... */ 37945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, 37955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL); 37965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 37975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* ...and initialize clock/power states */ 37985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->clkstate = CLK_SDONLY; 37995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->idletime = BRCMF_IDLE_INTERVAL; 38005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->idleclock = BRCMF_IDLE_ACTIVE; 38015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 38025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Query the F2 block size, set roundup accordingly */ 38035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->blocksize = bus->sdiodev->func[2]->cur_blksize; 38045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->roundup = min(max_roundup, bus->blocksize); 38055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 38065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* bus module does not support packet chaining */ 38075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->use_rxchain = false; 38085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->sd_rxchain = false; 38095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 38105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return true; 38115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 38125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 38135b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic int 38145b435de0d786869c95d1962121af0d7df2542009Arend van Sprielbrcmf_sdbrcm_watchdog_thread(void *data) 38155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 3816e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Lin struct brcmf_sdio *bus = (struct brcmf_sdio *)data; 38175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 38185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel allow_signal(SIGTERM); 38195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Run until signal received */ 38205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel while (1) { 38215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (kthread_should_stop()) 38225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel break; 38235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (!wait_for_completion_interruptible(&bus->watchdog_wait)) { 3824cad2b26b1010d0694d2f08d408486451b9f919d2Franky Lin brcmf_sdbrcm_bus_watchdog(bus); 38255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Count the tick for reference */ 382628a1a3bdaf4cce5ee8e473c332e2f371888341bbFranky Lin bus->tickcnt++; 38275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } else 38285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel break; 38295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 38305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return 0; 38315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 38325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 38335b435de0d786869c95d1962121af0d7df2542009Arend van Sprielstatic void 38345b435de0d786869c95d1962121af0d7df2542009Arend van Sprielbrcmf_sdbrcm_watchdog(unsigned long data) 38355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 3836e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Lin struct brcmf_sdio *bus = (struct brcmf_sdio *)data; 38375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 38385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bus->watchdog_tsk) { 38395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel complete(&bus->watchdog_wait); 38405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Reschedule the watchdog */ 38415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bus->wd_timer_valid) 38425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel mod_timer(&bus->timer, 38435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel jiffies + BRCMF_WD_POLL_MS * HZ / 1000); 38445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 38455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 38465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 3847e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic void brcmf_sdbrcm_release_dongle(struct brcmf_sdio *bus) 38485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 38495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(TRACE, "Enter\n"); 38505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 38515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bus->ci) { 38525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); 38535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_clkctl(bus, CLK_NONE, false); 3854a8a6c04586233e12551552c292797cb56b31dadeFranky Lin brcmf_sdio_chip_detach(&bus->ci); 38555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bus->vars && bus->varsz) 38565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel kfree(bus->vars); 38575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->vars = NULL; 38585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 38595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 38605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(TRACE, "Disconnected\n"); 38615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 38625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 38635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* Detach and free everything */ 3864e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linstatic void brcmf_sdbrcm_release(struct brcmf_sdio *bus) 38655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 38665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(TRACE, "Enter\n"); 38675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 38685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bus) { 38695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* De-register interrupt handler */ 38705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdcard_intr_dereg(bus->sdiodev); 38715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 38725f947ad942a72e7f96942da97d719dd62037dbc2Franky Lin if (bus->sdiodev->bus_if->drvr) { 38735f947ad942a72e7f96942da97d719dd62037dbc2Franky Lin brcmf_detach(bus->sdiodev->dev); 38745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_release_dongle(bus); 38755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 38765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 38775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_release_malloc(bus); 38785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 38795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel kfree(bus); 38805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 38815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 38825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(TRACE, "Disconnected\n"); 38835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 38845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 38854175b88bd22022a60de175f94fdb303bed087eb9Franky Linvoid *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev) 38865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 38875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel int ret; 3888e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Lin struct brcmf_sdio *bus; 38895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 38905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(TRACE, "Enter\n"); 38915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 38925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* We make an assumption about address window mappings: 38935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * regsva == SI_ENUM_BASE*/ 38945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 38955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Allocate private bus interface state */ 3896e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Lin bus = kzalloc(sizeof(struct brcmf_sdio), GFP_ATOMIC); 38975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (!bus) 38985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto fail; 38995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 39005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->sdiodev = sdiodev; 39015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel sdiodev->bus = bus; 3902b83db862ffb871e3131e5d2160c741b288eea9aaArend van Spriel skb_queue_head_init(&bus->glom); 39035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->txbound = BRCMF_TXBOUND; 39045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->rxbound = BRCMF_RXBOUND; 39055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->txminmax = BRCMF_TXMINMAX; 39065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1; 39075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->usebufpool = false; /* Use bufpool if allocated, 39085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel else use locally malloced rxbuf */ 39095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 39105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* attempt to attach to the dongle */ 39115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (!(brcmf_sdbrcm_probe_attach(bus, regsva))) { 39125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "brcmf_sdbrcm_probe_attach failed\n"); 39135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto fail; 39145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 39155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 39165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel spin_lock_init(&bus->txqlock); 39175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel init_waitqueue_head(&bus->ctrl_wait); 39185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel init_waitqueue_head(&bus->dcmd_resp_wait); 39195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 39205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Set up the watchdog timer */ 39215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel init_timer(&bus->timer); 39225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->timer.data = (unsigned long)bus; 39235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->timer.function = brcmf_sdbrcm_watchdog; 39245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 39255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Initialize thread based operation and lock */ 39265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel sema_init(&bus->sdsem, 1); 39275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 39285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Initialize watchdog thread */ 39295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel init_completion(&bus->watchdog_wait); 39305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->watchdog_tsk = kthread_run(brcmf_sdbrcm_watchdog_thread, 39315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus, "brcmf_watchdog"); 39325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (IS_ERR(bus->watchdog_tsk)) { 393302f77195db6ce252d5488b6d48d8edc1c5e2aa30Joe Perches pr_warn("brcmf_watchdog thread failed to start\n"); 39345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->watchdog_tsk = NULL; 39355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 39365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Initialize DPC thread */ 39375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel init_completion(&bus->dpc_wait); 3938b948a85c1f26d48395de8c6c7e392f008f1be666Franky Lin INIT_LIST_HEAD(&bus->dpc_tsklst); 3939b948a85c1f26d48395de8c6c7e392f008f1be666Franky Lin spin_lock_init(&bus->dpc_tl_lock); 39405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->dpc_tsk = kthread_run(brcmf_sdbrcm_dpc_thread, 39415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus, "brcmf_dpc"); 39425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (IS_ERR(bus->dpc_tsk)) { 394302f77195db6ce252d5488b6d48d8edc1c5e2aa30Joe Perches pr_warn("brcmf_dpc thread failed to start\n"); 39445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->dpc_tsk = NULL; 39455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 39465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 3947a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin /* Assign bus interface call back */ 3948a9ffda88be7416b8336f644806c2b3ed3ce08b26Franky Lin bus->sdiodev->bus_if->brcmf_bus_stop = brcmf_sdbrcm_bus_stop; 394999a0b8ff9105d9b78e7e4e6aaa077264707e4e1cFranky Lin bus->sdiodev->bus_if->brcmf_bus_init = brcmf_sdbrcm_bus_init; 3950b9692d17e842fadb8c18faf24f550db80886763eFranky Lin bus->sdiodev->bus_if->brcmf_bus_txdata = brcmf_sdbrcm_bus_txdata; 3951fcf094f414f9e9c088f6c2aa9e19a59f7b41e1f5Franky Lin bus->sdiodev->bus_if->brcmf_bus_txctl = brcmf_sdbrcm_bus_txctl; 3952fcf094f414f9e9c088f6c2aa9e19a59f7b41e1f5Franky Lin bus->sdiodev->bus_if->brcmf_bus_rxctl = brcmf_sdbrcm_bus_rxctl; 39535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Attach to the brcmf/OS/network interface */ 39542447ffb0bdf89d14c9a9503e33b32b73d3040feeFranky Lin ret = brcmf_attach(SDPCM_RESERVE, bus->sdiodev->dev); 3955712ac5b37a3348cac4e040c551a6ca6186d33682Franky Lin if (ret != 0) { 39565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "brcmf_attach failed\n"); 39575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto fail; 39585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 39595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 39605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Allocate buffers */ 39615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (!(brcmf_sdbrcm_probe_malloc(bus))) { 39625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "brcmf_sdbrcm_probe_malloc failed\n"); 39635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto fail; 39645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 39655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 39665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (!(brcmf_sdbrcm_probe_init(bus))) { 39675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "brcmf_sdbrcm_probe_init failed\n"); 39685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto fail; 39695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 39705b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 39715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Register interrupt callback, but mask it (not operational yet). */ 39725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(INTR, "disable SDIO interrupts (not interested yet)\n"); 39735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel ret = brcmf_sdcard_intr_reg(bus->sdiodev); 39745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (ret != 0) { 39755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "FAILED: sdcard_intr_reg returned %d\n", ret); 39765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto fail; 39775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 39785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(INTR, "registered SDIO interrupt function ok\n"); 39795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 39805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(INFO, "completed!!\n"); 39815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 39825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* if firmware path present try to download and bring up bus */ 3983ed683c986f6fff6b9d9fe2adc8b11e0b0be7c085Franky Lin ret = brcmf_bus_start(bus->sdiodev->dev); 39845b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (ret != 0) { 39855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (ret == -ENOLINK) { 39865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(ERROR, "dongle is not responding\n"); 39875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto fail; 39885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 39895b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 399015d45b6fbd01ecebc5a77b1e06ae7ebffad8018aFranky Lin 399115d45b6fbd01ecebc5a77b1e06ae7ebffad8018aFranky Lin /* add interface and open for business */ 399255a63bcc4cdeabf76f7e42a76d0c59dbe37d0d64Franky Lin if (brcmf_add_if(bus->sdiodev->dev, 0, "wlan%d", NULL)) { 399315d45b6fbd01ecebc5a77b1e06ae7ebffad8018aFranky Lin brcmf_dbg(ERROR, "Add primary net device interface failed!!\n"); 39945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto fail; 39955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 39965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 39975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return bus; 39985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 39995b435de0d786869c95d1962121af0d7df2542009Arend van Sprielfail: 40005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_release(bus); 40015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return NULL; 40025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 40035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 40045b435de0d786869c95d1962121af0d7df2542009Arend van Sprielvoid brcmf_sdbrcm_disconnect(void *ptr) 40055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 4006e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Lin struct brcmf_sdio *bus = (struct brcmf_sdio *)ptr; 40075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 40085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(TRACE, "Enter\n"); 40095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 40105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bus) 40115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_sdbrcm_release(bus); 40125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 40135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_dbg(TRACE, "Disconnected\n"); 40145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 40155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 40165b435de0d786869c95d1962121af0d7df2542009Arend van Sprielvoid 4017e92eedf4e080fc0bd98e892cb9d31d2163ae8b29Franky Linbrcmf_sdbrcm_wd_timer(struct brcmf_sdio *bus, uint wdtick) 40185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 40195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Totally stop the timer */ 402023677ce3172fcb93522a1df077d21019e73ee1e3Joe Perches if (!wdtick && bus->wd_timer_valid) { 40215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel del_timer_sync(&bus->timer); 40225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->wd_timer_valid = false; 40235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->save_ms = wdtick; 40245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return; 40255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 40265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 4027ece960eae81c604aa14a1bf431eda34f4fe71c0cFranky Lin /* don't start the wd until fw is loaded */ 4028712ac5b37a3348cac4e040c551a6ca6186d33682Franky Lin if (bus->sdiodev->bus_if->state == BRCMF_BUS_DOWN) 4029ece960eae81c604aa14a1bf431eda34f4fe71c0cFranky Lin return; 4030ece960eae81c604aa14a1bf431eda34f4fe71c0cFranky Lin 40315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (wdtick) { 40325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (bus->save_ms != BRCMF_WD_POLL_MS) { 403323677ce3172fcb93522a1df077d21019e73ee1e3Joe Perches if (bus->wd_timer_valid) 40345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Stop timer and restart at new value */ 40355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel del_timer_sync(&bus->timer); 40365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 40375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Create timer again when watchdog period is 40385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel dynamically changed or in the first instance 40395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 40405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->timer.expires = 40415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel jiffies + BRCMF_WD_POLL_MS * HZ / 1000; 40425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel add_timer(&bus->timer); 40435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 40445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } else { 40455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Re arm the timer, at last watchdog period */ 40465b435de0d786869c95d1962121af0d7df2542009Arend van Spriel mod_timer(&bus->timer, 40475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel jiffies + BRCMF_WD_POLL_MS * HZ / 1000); 40485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 40495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 40505b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->wd_timer_valid = true; 40515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel bus->save_ms = wdtick; 40525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 40535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 4054