aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/bcmdhd/dhd_sdio.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/bcmdhd/dhd_sdio.c')
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_sdio.c2755
1 files changed, 1514 insertions, 1241 deletions
diff --git a/drivers/net/wireless/bcmdhd/dhd_sdio.c b/drivers/net/wireless/bcmdhd/dhd_sdio.c
index 138e8e5..745ebf7 100644
--- a/drivers/net/wireless/bcmdhd/dhd_sdio.c
+++ b/drivers/net/wireless/bcmdhd/dhd_sdio.c
@@ -1,7 +1,7 @@
/*
* DHD Bus Module for SDIO
*
- * Copyright (C) 1999-2012, Broadcom Corporation
+ * Copyright (C) 1999-2014, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: dhd_sdio.c 394690 2013-04-03 09:18:44Z $
+ * $Id: dhd_sdio.c 456607 2014-02-19 09:26:42Z $
*/
#include <typedefs.h>
@@ -69,16 +69,29 @@
#include <dhdioctl.h>
#include <sdiovar.h>
+#ifdef PROP_TXSTATUS
+#include <dhd_wlfc.h>
+#endif
+#ifdef DHDTCPACK_SUPPRESS
+#include <dhd_ip.h>
+#endif /* DHDTCPACK_SUPPRESS */
+
+bool dhd_mp_halting(dhd_pub_t *dhdp);
+extern void bcmsdh_waitfor_iodrain(void *sdh);
+extern void bcmsdh_reject_ioreqs(void *sdh, bool reject);
+extern bool bcmsdh_fatal_error(void *sdh);
+
#ifndef DHDSDIO_MEM_DUMP_FNAME
#define DHDSDIO_MEM_DUMP_FNAME "mem_dump"
#endif
-#define QLEN 256 /* bulk rx and tx queue lengths */
+#define QLEN (1024) /* bulk rx and tx queue lengths */
#define FCHI (QLEN - 10)
#define FCLOW (FCHI / 2)
#define PRIOMASK 7
#define TXRETRIES 2 /* # of retries for tx frames */
+#define READ_FRM_CNT_RETRIES 3
#ifndef DHD_RXBOUND
#define DHD_RXBOUND 50 /* Default for max rx frames in one scheduling */
#endif
@@ -91,7 +104,7 @@
#define MEMBLOCK 2048 /* Block size used for downloading of dongle image */
#define MAX_NVRAMBUF_SIZE 4096 /* max nvram buf size */
-#define MAX_DATA_BUF (32 * 1024) /* Must be large enough to hold biggest possible glom */
+#define MAX_DATA_BUF (64 * 1024) /* Must be large enough to hold biggest possible glom */
#ifndef DHD_FIRSTREAD
#define DHD_FIRSTREAD 32
@@ -100,16 +113,10 @@
#error DHD_FIRSTREAD is not a power of 2!
#endif
-#ifdef BCMSDIOH_TXGLOM
-/* Total length of TX frame header for dongle protocol */
-#define SDPCM_HDRLEN (SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN + SDPCM_SWHEADER_LEN)
-/* Total length of RX frame for dongle protocol */
-#else
-/* Total length of TX frame header for dongle protocol */
+/* Total length of frame header for dongle protocol */
#define SDPCM_HDRLEN (SDPCM_FRAMETAG_LEN + SDPCM_SWHEADER_LEN)
-#endif
-
-#define SDPCM_HDRLEN_RX (SDPCM_FRAMETAG_LEN + SDPCM_SWHEADER_LEN)
+#define SDPCM_HDRLEN_TXGLOM (SDPCM_HDRLEN + SDPCM_HWEXT_LEN)
+#define MAX_TX_PKTCHAIN_CNT SDPCM_MAXGLOM_SIZE
#ifdef SDTEST
#define SDPCM_RESERVE (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN)
@@ -140,6 +147,12 @@
#define PMU_MAX_TRANSITION_DLY 1000000
#endif
+/* hooks for limiting threshold custom tx num in rx processing */
+#define DEFAULT_TXINRX_THRES 0
+#ifndef CUSTOM_TXINRX_THRES
+#define CUSTOM_TXINRX_THRES DEFAULT_TXINRX_THRES
+#endif
+
/* Value for ChipClockCSR during initial setup */
#define DHD_INIT_CLKCTL1 (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ)
#define DHD_INIT_CLKCTL2 (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP)
@@ -153,17 +166,12 @@
#define PKTFREE2() if ((bus->bus != SPI_BUS) || bus->usebufpool) \
PKTFREE(bus->dhd->osh, pkt, FALSE);
DHD_SPINWAIT_SLEEP_INIT(sdioh_spinwait_sleep);
-#if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
-extern void bcmsdh_set_irq(int flag);
-#endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */
-#ifdef PROP_TXSTATUS
-extern void dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success);
-extern void dhd_wlfc_trigger_pktcommit(dhd_pub_t *dhd);
-#endif
+#if defined(MULTIPLE_SUPPLICANT)
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
DEFINE_MUTEX(_dhd_sdio_mutex_lock_);
#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
+#endif
#ifdef DHD_DEBUG
/* Device console log buffer state */
@@ -196,7 +204,8 @@ typedef struct dhd_console {
#define GPIO_DEV_SRSTATE_TIMEOUT 320000 /* 320ms */
#define GPIO_DEV_WAKEUP 17 /* Host gpio17 mapped to device gpio1 wakeup */
#define CC_CHIPCTRL2_GPIO1_WAKEUP (1 << 0)
-#define OVERFLOW_BLKSZ512_WM 48
+#define CC_CHIPCTRL3_SR_ENG_ENABLE (1 << 2)
+#define OVERFLOW_BLKSZ512_WM 96
#define OVERFLOW_BLKSZ512_MES 80
#define CC_PMUCC3 (0x3)
@@ -219,7 +228,9 @@ typedef struct dhd_bus {
uint32 srmemsize; /* Size of SRMEM */
uint32 bus; /* gSPI or SDIO bus */
- uint32 hostintmask; /* Copy of Host Interrupt Mask */
+ uint32 bus_num; /* bus number */
+ uint32 slot_num; /* slot ID */
+ uint32 hostintmask; /* Copy of Host Interrupt Mask */
uint32 intstatus; /* Intstatus bits (events) pending */
bool dpc_sched; /* Indicates DPC schedule (intrpt rcvd) */
bool fcstate; /* State of dongle flow-control */
@@ -290,6 +301,7 @@ typedef struct dhd_bus {
bool alp_only; /* Don't use HT clock (ALP only) */
/* Field to decide if rx of control frames happen in rxbuf or lb-pool */
bool usebufpool;
+ int32 txinrx_thres; /* num of in-queued pkts */
#ifdef SDTEST
/* external loopback */
@@ -348,7 +360,10 @@ typedef struct dhd_bus {
#ifdef BCMSPI
bool dwordmode;
#endif /* BCMSPI */
-
+#ifdef DHDENABLE_TAILPAD
+ uint tx_tailpad_chain; /* Number of tail padding by chaining pad_pkt */
+ uint tx_tailpad_pktget; /* Number of tail padding by new PKTGET */
+#endif
uint8 *ctrl_frame_buf;
uint32 ctrl_frame_len;
bool ctrl_frame_stat;
@@ -367,14 +382,13 @@ typedef struct dhd_bus {
bool reqbussleep;
uint32 resetinstr;
uint32 dongle_ram_base;
-#ifdef BCMSDIOH_TXGLOM
+
void *glom_pkt_arr[SDPCM_MAXGLOM_SIZE]; /* Array of pkts for glomming */
- uint16 glom_cnt; /* Number of pkts in the glom array */
- uint16 glom_total_len; /* Total length of pkts in glom array */
- bool glom_enable; /* Flag to indicate whether tx glom is enabled/disabled */
- uint8 glom_mode; /* Glom mode - 0-copy mode, 1 - Multi-descriptor mode */
- uint32 glomsize; /* Glom size limitation */
-#endif
+ uint32 txglom_cnt; /* Number of pkts in the glom array */
+ uint32 txglom_total_len; /* Total length of pkts in glom array */
+ bool txglom_enable; /* Flag to indicate whether tx glom is enabled/disabled */
+ uint32 txglomsize; /* Glom size limitation */
+ void *pad_pkt;
} dhd_bus_t;
/* clkstate */
@@ -394,6 +408,10 @@ static int tx_packets[NUMPRIO];
const uint dhd_deferred_tx = 1;
extern uint dhd_watchdog_ms;
+#ifdef BCMSPI_ANDROID
+extern uint *dhd_spi_lockcount;
+#endif /* BCMSPI_ANDROID */
+
extern void dhd_os_wd_timer(void *bus, uint wdtick);
/* Tx/Rx bounds */
@@ -402,14 +420,15 @@ uint dhd_rxbound;
uint dhd_txminmax = DHD_TXMINMAX;
/* override the RAM size if possible */
-#define DONGLE_MIN_MEMSIZE (128 *1024)
-int dhd_dongle_memsize;
+#define DONGLE_MIN_RAMSIZE (128 *1024)
+int dhd_dongle_ramsize;
+
+uint dhd_doflow = TRUE;
+uint dhd_dpcpoll = FALSE;
+
+module_param(dhd_doflow, uint, 0644);
+module_param(dhd_dpcpoll, uint, 0644);
-#ifndef REPEAT_READFRAME
-static bool dhd_doflow;
-#else
-extern bool dhd_doflow;
-#endif /* REPEAT_READFRAME */
static bool dhd_alignctl;
static bool sd1idle;
@@ -419,19 +438,14 @@ static bool retrydata;
#ifdef BCMSPI
/* At a watermark around 8 the spid hits underflow error. */
-static const uint watermark = 32;
-static const uint mesbusyctrl = 0;
-#elif defined(SDIO_CRC_ERROR_FIX)
-static uint watermark = 48;
-static uint mesbusyctrl = 80;
+static uint watermark = 32;
+static uint mesbusyctrl = 0;
#else
-static const uint watermark = 8;
-static const uint mesbusyctrl = 0;
+static uint watermark = 8;
+static uint mesbusyctrl = 0;
#endif /* BCMSPI */
static const uint firstread = DHD_FIRSTREAD;
-#define HDATLEN (firstread - (SDPCM_HDRLEN))
-
/* Retry count for register access failures */
static const uint retry_limit = 2;
@@ -449,13 +463,13 @@ extern void bcmsdh_enable_hw_oob_intr(void *sdh, bool enable);
#endif /* defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD) */
#define PKTALIGN(osh, p, len, align) \
do { \
- uint datalign; \
+ uintptr datalign; \
datalign = (uintptr)PKTDATA((osh), (p)); \
datalign = ROUNDUP(datalign, (align)) - datalign; \
ASSERT(datalign < (align)); \
ASSERT(PKTLEN((osh), (p)) >= ((len) + datalign)); \
if (datalign) \
- PKTPULL((osh), (p), datalign); \
+ PKTPULL((osh), (p), (uint)datalign); \
PKTSETLEN((osh), (p), (len)); \
} while (0)
@@ -604,19 +618,20 @@ static bool dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh);
static void dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation,
bool reset_flag);
-static void dhd_dongle_setmemsize(struct dhd_bus *bus, int mem_size);
+static void dhd_dongle_setramsize(struct dhd_bus *bus, int mem_size);
static int dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags,
uint8 *buf, uint nbytes,
void *pkt, bcmsdh_cmplt_fn_t complete, void *handle);
static int dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags,
uint8 *buf, uint nbytes,
- void *pkt, bcmsdh_cmplt_fn_t complete, void *handle);
-#ifdef BCMSDIOH_TXGLOM
-static void dhd_bcmsdh_glom_post(dhd_bus_t *bus, uint8 *frame, void *pkt, uint len);
-static void dhd_bcmsdh_glom_clear(dhd_bus_t *bus);
-#endif
-
-static bool dhdsdio_download_firmware(dhd_bus_t *bus, osl_t *osh, void *sdh);
+ void *pkt, bcmsdh_cmplt_fn_t complete, void *handle, int max_retry);
+static int dhdsdio_txpkt(dhd_bus_t *bus, uint chan, void** pkts, int num_pkt, bool free_pkt);
+static int dhdsdio_txpkt_preprocess(dhd_bus_t *bus, void *pkt, int chan, int txseq,
+ int prev_chain_total_len, bool last_chained_pkt,
+ int *pad_pkt_len, void **new_pkt);
+static int dhdsdio_txpkt_postprocess(dhd_bus_t *bus, void *pkt);
+
+static int dhdsdio_download_firmware(dhd_bus_t *bus, osl_t *osh, void *sdh);
static int _dhdsdio_download_firmware(dhd_bus_t *bus);
static int dhdsdio_download_code_file(dhd_bus_t *bus, char *image_path);
@@ -634,31 +649,43 @@ extern uint32 dhd_get_htsf(void *dhd, int ifidx);
#endif /* WLMEDIA_HTSF */
static void
-dhd_overflow_war(struct dhd_bus *bus)
+dhdsdio_tune_fifoparam(struct dhd_bus *bus)
{
int err;
uint8 devctl, wm, mes;
- /* See .ppt in PR for these recommended values */
- if (bus->blocksize == 512) {
- wm = OVERFLOW_BLKSZ512_WM;
- mes = OVERFLOW_BLKSZ512_MES;
+ if (bus->sih->buscorerev >= 15) {
+ /* See .ppt in PR for these recommended values */
+ if (bus->blocksize == 512) {
+ wm = OVERFLOW_BLKSZ512_WM;
+ mes = OVERFLOW_BLKSZ512_MES;
+ } else {
+ mes = bus->blocksize/4;
+ wm = bus->blocksize/4;
+ }
+
+ watermark = wm;
+ mesbusyctrl = mes;
} else {
- mes = bus->blocksize/4;
- wm = bus->blocksize/4;
+ DHD_INFO(("skip fifotune: SdioRev(%d) is lower than minimal requested ver\n",
+ bus->sih->buscorerev));
+ return;
}
-
/* Update watermark */
- bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, wm, &err);
+ if (wm > 0) {
+ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, wm, &err);
- devctl = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
- devctl |= SBSDIO_DEVCTL_F2WM_ENAB;
- bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
+ devctl = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
+ devctl |= SBSDIO_DEVCTL_F2WM_ENAB;
+ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
+ }
/* Update MES */
- bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL,
- (mes | SBSDIO_MESBUSYCTRL_ENAB), &err);
+ if (mes > 0) {
+ bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL,
+ (mes | SBSDIO_MESBUSYCTRL_ENAB), &err);
+ }
DHD_INFO(("Apply overflow WAR: 0x%02x 0x%02x 0x%02x\n",
bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err),
@@ -667,15 +694,15 @@ dhd_overflow_war(struct dhd_bus *bus)
}
static void
-dhd_dongle_setmemsize(struct dhd_bus *bus, int mem_size)
+dhd_dongle_setramsize(struct dhd_bus *bus, int mem_size)
{
- int32 min_size = DONGLE_MIN_MEMSIZE;
- /* Restrict the memsize to user specified limit */
+ int32 min_size = DONGLE_MIN_RAMSIZE;
+ /* Restrict the ramsize to user specified limit */
DHD_ERROR(("user: Restrict the dongle ram size to %d, min accepted %d\n",
- dhd_dongle_memsize, min_size));
- if ((dhd_dongle_memsize > min_size) &&
- (dhd_dongle_memsize < (int32)bus->orig_ramsize))
- bus->ramsize = dhd_dongle_memsize;
+ dhd_dongle_ramsize, min_size));
+ if ((dhd_dongle_ramsize > min_size) &&
+ (dhd_dongle_ramsize < (int32)bus->orig_ramsize))
+ bus->ramsize = dhd_dongle_ramsize;
}
static int
@@ -748,6 +775,7 @@ dhdsdio_sr_cap(dhd_bus_t *bus)
{
bool cap = FALSE;
uint32 core_capext, addr, data;
+
if (bus->sih->chip == BCM4324_CHIP_ID) {
addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr);
data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data);
@@ -755,7 +783,12 @@ dhdsdio_sr_cap(dhd_bus_t *bus)
core_capext = bcmsdh_reg_read(bus->sdh, data, 4);
} else if (bus->sih->chip == BCM4330_CHIP_ID) {
core_capext = FALSE;
- } else if (bus->sih->chip == BCM4335_CHIP_ID) {
+ } else if ((bus->sih->chip == BCM4335_CHIP_ID) ||
+ (bus->sih->chip == BCM4339_CHIP_ID) ||
+ (bus->sih->chip == BCM43349_CHIP_ID) ||
+ (bus->sih->chip == BCM4345_CHIP_ID) ||
+ (bus->sih->chip == BCM4354_CHIP_ID) ||
+ (bus->sih->chip == BCM4350_CHIP_ID)) {
core_capext = TRUE;
} else {
core_capext = bcmsdh_reg_read(bus->sdh, CORE_CAPEXT_ADDR, 4);
@@ -767,13 +800,23 @@ dhdsdio_sr_cap(dhd_bus_t *bus)
if (bus->sih->chip == BCM4324_CHIP_ID) {
/* FIX: Should change to query SR control register instead */
cap = TRUE;
- } else if (bus->sih->chip == BCM4335_CHIP_ID) {
+ } else if ((bus->sih->chip == BCM4335_CHIP_ID) ||
+ (bus->sih->chip == BCM4339_CHIP_ID) ||
+ (bus->sih->chip == BCM43349_CHIP_ID) ||
+ (bus->sih->chip == BCM4345_CHIP_ID) ||
+ (bus->sih->chip == BCM4354_CHIP_ID) ||
+ (bus->sih->chip == BCM4350_CHIP_ID)) {
uint32 enabval = 0;
addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr);
data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data);
bcmsdh_reg_write(bus->sdh, addr, 4, CC_PMUCC3);
enabval = bcmsdh_reg_read(bus->sdh, data, 4);
+ if ((bus->sih->chip == BCM4350_CHIP_ID) ||
+ (bus->sih->chip == BCM4345_CHIP_ID) ||
+ (bus->sih->chip == BCM4354_CHIP_ID))
+ enabval &= CC_CHIPCTRL3_SR_ENG_ENABLE;
+
if (enabval)
cap = TRUE;
} else {
@@ -789,7 +832,6 @@ dhdsdio_sr_cap(dhd_bus_t *bus)
static int
dhdsdio_srwar_init(dhd_bus_t *bus)
{
-
bcmsdh_gpio_init(bus->sdh);
#ifdef USE_OOB_GPIO1
@@ -860,6 +902,10 @@ dhdsdio_clk_kso_init(dhd_bus_t *bus)
#define KSO_DBG(x)
#define KSO_WAIT_US 50
+#define KSO_WAIT_MS 1
+#define KSO_SLEEP_RETRY_COUNT 20
+#define ERROR_BCME_NODEVICE_MAX 1
+
#if defined(CUSTOMER_HW4)
#define MAX_KSO_ATTEMPTS 64
#else
@@ -882,7 +928,7 @@ dhdsdio_clk_kso_enab(dhd_bus_t *bus, bool on)
cmp_val = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK | SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK;
bmask = cmp_val;
- msleep(3);
+ OSL_SLEEP(3);
} else {
/* Put device to sleep, turn off KSO */
cmp_val = 0;
@@ -895,7 +941,11 @@ dhdsdio_clk_kso_enab(dhd_bus_t *bus, bool on)
break;
KSO_DBG(("%s> KSO wr/rd retry:%d, ERR:%x \n", __FUNCTION__, try_cnt, err));
- OSL_DELAY(KSO_WAIT_US);
+
+ if (((try_cnt + 1) % KSO_SLEEP_RETRY_COUNT) == 0) {
+ OSL_SLEEP(KSO_WAIT_MS);
+ } else
+ OSL_DELAY(KSO_WAIT_US);
bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, wr_val, &err);
} while (try_cnt++ < MAX_KSO_ATTEMPTS);
@@ -935,16 +985,7 @@ dhdsdio_clk_kso_iovar(dhd_bus_t *bus, bool on)
dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
}
- /* Double-write to be safe in case transition of AOS */
- dhdsdio_clk_kso_enab(bus, TRUE);
dhdsdio_clk_kso_enab(bus, TRUE);
- OSL_DELAY(4000);
-
- /* Wait for device ready during transition to wake-up */
- SPINWAIT(((dhdsdio_sleepcsr_get(bus)) !=
- (SBSDIO_FUNC1_SLEEPCSR_KSO_MASK |
- SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK)),
- (10000));
DHD_ERROR(("%s: sleepcsr: 0x%x\n", __FUNCTION__,
dhdsdio_sleepcsr_get(bus)));
@@ -1026,8 +1067,10 @@ dhdsdio_clk_devsleep_iovar(dhd_bus_t *bus, bool on)
#else
err = dhdsdio_clk_kso_enab(bus, FALSE);
if (OOB_WAKEUP_ENAB(bus))
+ {
err = bcmsdh_gpioout(bus->sdh, GPIO_DEV_WAKEUP, FALSE); /* GPIO_1 is off */
-#endif
+ }
+#endif /* USE_CMD14 */
} else {
/* Exit Sleep */
/* Make sure we have SD bus access */
@@ -1037,7 +1080,8 @@ dhdsdio_clk_devsleep_iovar(dhd_bus_t *bus, bool on)
}
if ((bus->sih->chip == BCM4334_CHIP_ID) && (bus->sih->chiprev == 2)) {
- SPINWAIT((bcmsdh_gpioin(bus->sdh, GPIO_DEV_SRSTATE) != TRUE),
+ SPINWAIT_SLEEP(sdioh_spinwait_sleep,
+ (bcmsdh_gpioin(bus->sdh, GPIO_DEV_SRSTATE) != TRUE),
GPIO_DEV_SRSTATE_TIMEOUT);
if (bcmsdh_gpioin(bus->sdh, GPIO_DEV_SRSTATE) == FALSE) {
@@ -1073,12 +1117,13 @@ dhdsdio_clk_devsleep_iovar(dhd_bus_t *bus, bool on)
}
#else
if (OOB_WAKEUP_ENAB(bus))
+ {
err = bcmsdh_gpioout(bus->sdh, GPIO_DEV_WAKEUP, TRUE); /* GPIO_1 is on */
-
+ }
do {
err = dhdsdio_clk_kso_enab(bus, TRUE);
if (err)
- OSL_DELAY(10000);
+ OSL_SLEEP(10);
} while ((err != 0) && (++retry < 3));
if (err != 0) {
@@ -1091,7 +1136,8 @@ dhdsdio_clk_devsleep_iovar(dhd_bus_t *bus, bool on)
uint8 csr;
/* Wait for device ready during transition to wake-up */
- SPINWAIT((((csr = dhdsdio_sleepcsr_get(bus)) &
+ SPINWAIT_SLEEP(sdioh_spinwait_sleep,
+ (((csr = dhdsdio_sleepcsr_get(bus)) &
SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK) !=
(SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK)), (20000));
@@ -1103,10 +1149,17 @@ dhdsdio_clk_devsleep_iovar(dhd_bus_t *bus, bool on)
err = BCME_NODEVICE;
}
- SPINWAIT((((csr = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
+ SPINWAIT_SLEEP(sdioh_spinwait_sleep,
+ (((csr = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
SBSDIO_FUNC1_CHIPCLKCSR, &err)) & SBSDIO_HT_AVAIL) !=
(SBSDIO_HT_AVAIL)), (10000));
+ DHD_TRACE(("%s: SBSDIO_FUNC1_CHIPCLKCSR : 0x%x\n", __FUNCTION__, csr));
+ if (!err && ((csr & SBSDIO_HT_AVAIL) != SBSDIO_HT_AVAIL)) {
+ DHD_ERROR(("%s:ERROR: device NOT Ready! 0x%x\n",
+ __FUNCTION__, csr));
+ err = BCME_NODEVICE;
+ }
}
}
@@ -1114,9 +1167,10 @@ dhdsdio_clk_devsleep_iovar(dhd_bus_t *bus, bool on)
if (err == 0)
bus->kso = on ? FALSE : TRUE;
else {
- DHD_ERROR(("%s: Sleep request failed: on:%d err:%d\n", __FUNCTION__, on, err));
+ DHD_ERROR(("%s: Sleep request failed: kso:%d on:%d err:%d\n",
+ __FUNCTION__, bus->kso, on, err));
if (!on && retry > 2)
- bus->kso = TRUE;
+ bus->kso = FALSE;
}
return err;
@@ -1446,6 +1500,9 @@ dhdsdio_bussleep(dhd_bus_t *bus, bool sleep)
(sleep ? "SLEEP" : "WAKE"),
(bus->sleeping ? "SLEEP" : "WAKE")));
+ if (bus->dhd->hang_was_sent)
+ return BCME_ERROR;
+
/* Done if we're already in the requested state */
if (sleep == bus->sleeping)
return BCME_OK;
@@ -1454,7 +1511,8 @@ dhdsdio_bussleep(dhd_bus_t *bus, bool sleep)
if (sleep) {
/* Don't sleep if something is pending */
#ifdef CUSTOMER_HW4
- if (bus->dpc_sched || bus->rxskip || pktq_len(&bus->txq) || bus->readframes)
+ if (bus->dpc_sched || bus->rxskip || pktq_len(&bus->txq) || bus->readframes ||
+ bus->ctrl_frame_stat)
#else
if (bus->dpc_sched || bus->rxskip || pktq_len(&bus->txq))
#endif /* CUSTOMER_HW4 */
@@ -1568,11 +1626,13 @@ int dhdsdio_func_blocksize(dhd_pub_t *dhd, int function_num, int block_size)
}
#endif /* CUSTOMER_HW4 && USE_DYNAMIC_F2_BLKSIZE */
-#if defined(OOB_INTR_ONLY)
+#if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
void
dhd_enable_oob_intr(struct dhd_bus *bus, bool enable)
{
-#if defined(HW_OOB)
+#if defined(BCMSPI_ANDROID)
+ bcmsdh_intr_enable(bus->sdh);
+#elif defined(HW_OOB)
bcmsdh_enable_hw_oob_intr(bus->sdh, enable);
#else
sdpcmd_regs_t *regs = bus->regs;
@@ -1597,745 +1657,542 @@ dhd_enable_oob_intr(struct dhd_bus *bus, bool enable)
dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
#endif /* !defined(HW_OOB) */
}
-#endif /* defined(OOB_INTR_ONLY) */
-
-
-#ifdef DHDTCPACK_SUPPRESS
-extern bool dhd_use_tcpack_suppress;
+#endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */
-/* Please be sure this function is called under dhd_os_tcpacklock() */
-void dhd_onoff_tcpack_sup(void *pub, bool on)
+int
+dhd_bus_txdata(struct dhd_bus *bus, void *pkt)
{
- dhd_pub_t *dhdp = (dhd_pub_t *)pub;
-
- if (dhd_use_tcpack_suppress != on) {
-
- DHD_ERROR(("dhd_onoff_tcpack_sup: %d -> %d\n", dhd_use_tcpack_suppress, on));
- dhd_use_tcpack_suppress = on;
- dhdp->tcp_ack_info_cnt = 0;
- bzero(dhdp->tcp_ack_info_tbl, sizeof(struct tcp_ack_info)*MAXTCPSTREAMS);
-
- } else
- DHD_ERROR(("dhd_onoff_tcpack_sup: alread %d\n", on));
-
- return;
-}
+ int ret = BCME_ERROR;
+ osl_t *osh;
+ uint datalen, prec;
+#if defined(DHD_TX_DUMP) || defined(DHD_8021X_DUMP)
+ uint8 *dump_data;
+ uint16 protocol;
+#endif /* DHD_TX_DUMP || DHD_8021X_DUMP */
-inline void dhd_tcpack_check_xmit(dhd_pub_t *dhdp, void *pkt)
-{
- uint8 i;
- tcp_ack_info_t *tcp_ack_info = NULL;
- int tbl_cnt;
-
- dhd_os_tcpacklock(dhdp);
- tbl_cnt = dhdp->tcp_ack_info_cnt;
- for (i = 0; i < tbl_cnt; i++) {
- tcp_ack_info = &dhdp->tcp_ack_info_tbl[i];
- if (tcp_ack_info->p_tcpackinqueue == pkt) {
- /* This pkt is being transmitted so remove the tcp_ack_info of it.
- * compact the array unless the last element,
- * then the pkt's array is removed.
- */
- if (i < tbl_cnt-1) {
- memmove(&dhdp->tcp_ack_info_tbl[i],
- &dhdp->tcp_ack_info_tbl[i+1],
- sizeof(struct tcp_ack_info)*(tbl_cnt - (i+1)));
- }
- bzero(&dhdp->tcp_ack_info_tbl[tbl_cnt-1], sizeof(struct tcp_ack_info));
- if (--dhdp->tcp_ack_info_cnt < 0) {
- DHD_ERROR(("dhdsdio_sendfromq:(ERROR) tcp_ack_info_cnt %d"
- " Stop using tcpack_suppress\n", dhdp->tcp_ack_info_cnt));
- dhd_onoff_tcpack_sup(dhdp, FALSE);
- }
- break;
- }
- }
- dhd_os_tcpackunlock(dhdp);
-}
+ DHD_TRACE(("%s: Enter\n", __FUNCTION__));
-bool
-dhd_tcpack_suppress(dhd_pub_t *dhdp, void *pkt)
-{
- uint8 *eh_header;
- uint16 eh_type;
- uint8 *ip_header;
- uint8 *tcp_header;
- uint32 ip_hdr_len;
- uint32 cur_framelen;
- uint8 bdc_hdr_len = BDC_HEADER_LEN;
- uint8 wlfc_hdr_len = 0;
- uint8 *data = PKTDATA(dhdp->osh, pkt);
- cur_framelen = PKTLEN(dhdp->osh, pkt);
+ osh = bus->dhd->osh;
+ datalen = PKTLEN(osh, pkt);
-#ifdef PROP_TXSTATUS
- /* In this case, BDC header is not pushed in dhd_sendpkt() */
- if (dhdp->wlfc_state) {
- bdc_hdr_len = 0;
- wlfc_hdr_len = 8;
- }
-#endif
- if (cur_framelen < bdc_hdr_len + ETHER_HDR_LEN) {
- DHD_TRACE(("dhd_tcpack_suppress: Too short packet length %d\n", cur_framelen));
- return FALSE;
+#ifdef SDTEST
+ /* Push the test header if doing loopback */
+ if (bus->ext_loop) {
+ uint8* data;
+ PKTPUSH(osh, pkt, SDPCM_TEST_HDRLEN);
+ data = PKTDATA(osh, pkt);
+ *data++ = SDPCM_TEST_ECHOREQ;
+ *data++ = (uint8)bus->loopid++;
+ *data++ = (datalen >> 0);
+ *data++ = (datalen >> 8);
+ datalen += SDPCM_TEST_HDRLEN;
}
+#else /* SDTEST */
+ BCM_REFERENCE(datalen);
+#endif /* SDTEST */
- /* Get rid of BDC header */
- eh_header = data + bdc_hdr_len;
- cur_framelen -= bdc_hdr_len;
- eh_type = eh_header[12] << 8 | eh_header[13];
+#if defined(DHD_TX_DUMP) || defined(DHD_8021X_DUMP)
+ dump_data = PKTDATA(osh, pkt);
+ dump_data += 4; /* skip 4 bytes header */
+ protocol = (dump_data[12] << 8) | dump_data[13];
- if (eh_type != ETHER_TYPE_IP) {
- DHD_TRACE(("dhd_tcpack_suppress: Not a IP packet 0x%x\n", eh_type));
- return FALSE;
+ if (protocol == ETHER_TYPE_802_1X) {
+ DHD_ERROR(("ETHER_TYPE_802_1X [TX]: ver %d, type %d, replay %d\n",
+ dump_data[14], dump_data[15], dump_data[30]));
}
+#endif /* DHD_TX_DUMP || DHD_8021X_DUMP */
- DHD_TRACE(("dhd_tcpack_suppress: IP pkt! 0x%x\n", eh_type));
-
- ip_header = eh_header + ETHER_HDR_LEN;
- cur_framelen -= ETHER_HDR_LEN;
- ip_hdr_len = 4 * (ip_header[0] & 0x0f);
+#if defined(DHD_TX_DUMP) && defined(DHD_TX_FULL_DUMP)
+ {
+ int i;
+ DHD_ERROR(("TX DUMP\n"));
- if ((ip_header[0] & 0xf0) != 0x40) {
- DHD_TRACE(("dhd_tcpack_suppress: Not IPv4!\n"));
- return FALSE;
+ for (i = 0; i < (datalen - 4); i++) {
+ DHD_ERROR(("%02X ", dump_data[i]));
+ if ((i & 15) == 15)
+ printk("\n");
+ }
+ DHD_ERROR(("\n"));
}
+#endif /* DHD_TX_DUMP && DHD_TX_FULL_DUMP */
- if (cur_framelen < ip_hdr_len) {
- DHD_ERROR(("dhd_tcpack_suppress: IP packet length %d wrong!\n", cur_framelen));
- return FALSE;
- }
+ prec = PRIO2PREC((PKTPRIO(pkt) & PRIOMASK));
- /* not tcp */
- if (ip_header[9] != 0x06) {
- DHD_TRACE(("dhd_tcpack_suppress: Not a TCP packet 0x%x\n", ip_header[9]));
- return FALSE;
- }
+ /* Check for existing queue, current flow-control, pending event, or pending clock */
+ if (dhd_deferred_tx || bus->fcstate || pktq_len(&bus->txq) || bus->dpc_sched ||
+ (!DATAOK(bus)) || (bus->flowcontrol & NBITVAL(prec)) ||
+ (bus->clkstate != CLK_AVAIL)) {
+ bool deq_ret;
+ int pkq_len;
- DHD_TRACE(("dhd_tcpack_suppress: TCP pkt!\n"));
+ DHD_TRACE(("%s: deferring pktq len %d\n", __FUNCTION__, pktq_len(&bus->txq)));
+ bus->fcqueued++;
- tcp_header = ip_header + ip_hdr_len;
+ /* Priority based enq */
+ dhd_os_sdlock_txq(bus->dhd);
+ deq_ret = dhd_prec_enq(bus->dhd, &bus->txq, pkt, prec);
+ dhd_os_sdunlock_txq(bus->dhd);
- /* is it an ack ? */
- if (tcp_header[13] == 0x10) {
-#if defined(DHD_DEBUG)
- uint32 tcp_seq_num = tcp_header[4] << 24 | tcp_header[5] << 16 |
- tcp_header[6] << 8 | tcp_header[7];
-#endif
- uint32 tcp_ack_num = tcp_header[8] << 24 | tcp_header[9] << 16 |
- tcp_header[10] << 8 | tcp_header[11];
- uint16 ip_tcp_ttllen = (ip_header[3] & 0xff) + (ip_header[2] << 8);
- uint32 tcp_hdr_len = 4*((tcp_header[12] & 0xf0) >> 4);
- DHD_TRACE(("dhd_tcpack_suppress: TCP ACK seq %ud ack %ud\n",
- tcp_seq_num, tcp_ack_num));
-
-
- /* zero length ? */
- if (ip_tcp_ttllen == ip_hdr_len + tcp_hdr_len) {
- int i;
- tcp_ack_info_t *tcp_ack_info = NULL;
- DHD_TRACE(("dhd_tcpack_suppress: TCP ACK zero length\n"));
- /* Look for tcp_ack_info that has the same
- * ip src/dst addrs and tcp src/dst ports
- */
- dhd_os_tcpacklock(dhdp);
- for (i = 0; i < dhdp->tcp_ack_info_cnt; i++) {
- if (dhdp->tcp_ack_info_tbl[i].p_tcpackinqueue &&
- !memcmp(&ip_header[12], dhdp->tcp_ack_info_tbl[i].ipaddrs, 8) &&
- !memcmp(tcp_header, dhdp->tcp_ack_info_tbl[i].tcpports, 4)) {
- tcp_ack_info = &dhdp->tcp_ack_info_tbl[i];
- break;
+ if (!deq_ret) {
+#ifdef PROP_TXSTATUS
+ if (DHD_PKTTAG_WLFCPKT(PKTTAG(pkt)) == 0)
+#endif /* PROP_TXSTATUS */
+ {
+#ifdef DHDTCPACK_SUPPRESS
+ if (dhd_tcpack_check_xmit(bus->dhd, pkt) == BCME_ERROR) {
+ DHD_ERROR(("%s %d: tcpack_suppress ERROR!!! Stop using\n",
+ __FUNCTION__, __LINE__));
+ dhd_tcpack_suppress_set(bus->dhd, FALSE);
}
+#endif /* DHDTCPACK_SUPPRESS */
+ dhd_txcomplete(bus->dhd, pkt, FALSE);
+ PKTFREE(osh, pkt, TRUE);
}
+ ret = BCME_NORESOURCE;
+ } else
+ ret = BCME_OK;
- if (i == dhdp->tcp_ack_info_cnt && i < MAXTCPSTREAMS)
- tcp_ack_info = &dhdp->tcp_ack_info_tbl[dhdp->tcp_ack_info_cnt++];
-
- if (!tcp_ack_info) {
- DHD_TRACE(("dhd_tcpack_suppress: No empty tcp ack info"
- "%d %d %d %d, %d %d %d %d\n",
- tcp_header[0], tcp_header[1], tcp_header[2], tcp_header[3],
- dhdp->tcp_ack_info_tbl[i].tcpports[0],
- dhdp->tcp_ack_info_tbl[i].tcpports[1],
- dhdp->tcp_ack_info_tbl[i].tcpports[2],
- dhdp->tcp_ack_info_tbl[i].tcpports[3]));
- dhd_os_tcpackunlock(dhdp);
- return FALSE;
- }
-
- if (tcp_ack_info->p_tcpackinqueue) {
- if (tcp_ack_num > tcp_ack_info->tcpack_number) {
- void *prevpkt = tcp_ack_info->p_tcpackinqueue;
- uint8 pushed_len = SDPCM_HDRLEN +
- (BDC_HEADER_LEN - bdc_hdr_len) + wlfc_hdr_len;
+ dhd_os_sdlock_txq(bus->dhd);
+ pkq_len = pktq_len(&bus->txq);
+ dhd_os_sdunlock_txq(bus->dhd);
+ if (pkq_len >= FCHI) {
+ bool wlfc_enabled = FALSE;
#ifdef PROP_TXSTATUS
- /* In case the prev pkt is delayenqueued
- * but not delayedequeued yet, it may not have
- * any additional header yet.
- */
- if (dhdp->wlfc_state && (PKTLEN(dhdp->osh, prevpkt) ==
- tcp_ack_info->ip_tcp_ttllen + ETHER_HDR_LEN))
- pushed_len = 0;
+ wlfc_enabled = (dhd_wlfc_flowcontrol(bus->dhd, ON, FALSE) !=
+ WLFC_UNSUPPORTED);
#endif
- if ((ip_tcp_ttllen == tcp_ack_info->ip_tcp_ttllen) &&
- (PKTLEN(dhdp->osh, pkt) ==
- PKTLEN(dhdp->osh, prevpkt) - pushed_len)) {
- bcopy(PKTDATA(dhdp->osh, pkt),
- PKTDATA(dhdp->osh, prevpkt) + pushed_len,
- PKTLEN(dhdp->osh, pkt));
- PKTFREE(dhdp->osh, pkt, FALSE);
- DHD_TRACE(("dhd_tcpack_suppress: pkt 0x%p"
- " TCP ACK replace %ud -> %ud\n", prevpkt,
- tcp_ack_info->tcpack_number, tcp_ack_num));
- tcp_ack_info->tcpack_number = tcp_ack_num;
- dhd_os_tcpackunlock(dhdp);
- return TRUE;
- } else
- DHD_TRACE(("dhd_tcpack_suppress: len mismatch"
- " %d(%d) %d(%d)\n",
- PKTLEN(dhdp->osh, pkt), ip_tcp_ttllen,
- PKTLEN(dhdp->osh, prevpkt),
- tcp_ack_info->ip_tcp_ttllen));
- } else {
-#ifdef TCPACK_TEST
- void *prevpkt = tcp_ack_info->p_tcpackinqueue;
+ if (!wlfc_enabled && dhd_doflow) {
+ dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON);
+ }
+ }
+
+#ifdef DHD_DEBUG
+ dhd_os_sdlock_txq(bus->dhd);
+ if (pktq_plen(&bus->txq, prec) > qcount[prec])
+ qcount[prec] = pktq_plen(&bus->txq, prec);
+ dhd_os_sdunlock_txq(bus->dhd);
#endif
- DHD_TRACE(("dhd_tcpack_suppress: TCP ACK number reverse"
- " prev %ud (0x%p) new %ud (0x%p)\n",
- tcp_ack_info->tcpack_number,
- tcp_ack_info->p_tcpackinqueue,
- tcp_ack_num, pkt));
-#ifdef TCPACK_TEST
- if (PKTLEN(dhdp->osh, pkt) == PKTLEN(dhdp->osh, prevpkt)) {
- PKTFREE(dhdp->osh, pkt, FALSE);
- dhd_os_tcpackunlock(dhdp);
- return TRUE;
- }
+
+ /* Schedule DPC if needed to send queued packet(s) */
+ if (dhd_deferred_tx && !bus->dpc_sched) {
+ bus->dpc_sched = TRUE;
+ dhd_sched_dpc(bus->dhd);
+ }
+ } else {
+ int chan = SDPCM_DATA_CHANNEL;
+
+#ifdef SDTEST
+ chan = (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL);
#endif
- }
- } else {
- tcp_ack_info->p_tcpackinqueue = pkt;
- tcp_ack_info->tcpack_number = tcp_ack_num;
- tcp_ack_info->ip_tcp_ttllen = ip_tcp_ttllen;
- bcopy(&ip_header[12], tcp_ack_info->ipaddrs, 8);
- bcopy(tcp_header, tcp_ack_info->tcpports, 4);
- }
- dhd_os_tcpackunlock(dhdp);
- } else
- DHD_TRACE(("dhd_tcpack_suppress: TCP ACK with DATA len %d\n",
- ip_tcp_ttllen - ip_hdr_len - tcp_hdr_len));
+ /* Lock: we're about to use shared data/code (and SDIO) */
+ dhd_os_sdlock(bus->dhd);
+
+ /* Otherwise, send it now */
+ BUS_WAKE(bus);
+ /* Make sure back plane ht clk is on, no pending allowed */
+ dhdsdio_clkctl(bus, CLK_AVAIL, TRUE);
+
+ ret = dhdsdio_txpkt(bus, chan, &pkt, 1, TRUE);
+
+ if (ret != BCME_OK)
+ bus->dhd->tx_errors++;
+ else
+ bus->dhd->dstats.tx_bytes += datalen;
+
+ if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
+ bus->activity = FALSE;
+ dhdsdio_clkctl(bus, CLK_NONE, TRUE);
+ }
+
+ dhd_os_sdunlock(bus->dhd);
}
- return FALSE;
-}
-#endif /* DHDTCPACK_SUPPRESS */
+ return ret;
+}
-/* Writes a HW/SW header into the packet and sends it. */
-/* Assumes: (a) header space already there, (b) caller holds lock */
-static int
-dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt, bool queue_only)
+/* align packet data pointer and packet length to n-byte boundary, process packet headers,
+ * a new packet may be allocated if there is not enough head and/or tail from for padding.
+ * the caller is responsible for updating the glom size in the head packet (when glom is
+ * used)
+ *
+ * pad_pkt_len: returns the length of extra padding needed from the padding packet, this parameter
+ * is taken in tx glom mode only
+ *
+ * new_pkt: out, pointer of the new packet allocated due to insufficient head room for alignment
+ * padding, NULL if not needed, the caller is responsible for freeing the new packet
+ *
+ * return: positive value - length of the packet, including head and tail padding
+ * negative value - errors
+ */
+static int dhdsdio_txpkt_preprocess(dhd_bus_t *bus, void *pkt, int chan, int txseq,
+ int prev_chain_total_len, bool last_chained_pkt,
+ int *pad_pkt_len, void **new_pkt)
{
- int ret;
osl_t *osh;
uint8 *frame;
- uint16 len, pad1 = 0;
+ int pkt_len;
+ int modulo;
+ int head_padding;
+ int tail_padding = 0;
uint32 swheader;
- uint retries = 0;
- uint32 real_pad = 0;
- bcmsdh_info_t *sdh;
- void *new;
- int i;
- int pkt_cnt;
-#ifdef BCMSDIOH_TXGLOM
- uint8 *frame_tmp;
-#endif
-#ifdef WLMEDIA_HTSF
- char *p;
- htsfts_t *htsf_ts;
-#endif
-
- DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+ uint32 swhdr_offset;
+ bool alloc_new_pkt = FALSE;
+ uint8 sdpcm_hdrlen = bus->txglom_enable ? SDPCM_HDRLEN_TXGLOM : SDPCM_HDRLEN;
- sdh = bus->sdh;
+ *new_pkt = NULL;
osh = bus->dhd->osh;
#ifdef DHDTCPACK_SUPPRESS
- if (dhd_use_tcpack_suppress) {
- dhd_tcpack_check_xmit(bus->dhd, pkt);
+ if (dhd_tcpack_check_xmit(bus->dhd, pkt) == BCME_ERROR) {
+ DHD_ERROR(("%s %d: tcpack_suppress ERROR!!! Stop using it\n",
+ __FUNCTION__, __LINE__));
+ dhd_tcpack_suppress_set(bus->dhd, FALSE);
}
#endif /* DHDTCPACK_SUPPRESS */
- if (bus->dhd->dongle_reset) {
- ret = BCME_NOTREADY;
- goto done;
- }
+ /* Add space for the SDPCM hardware/software headers */
+ PKTPUSH(osh, pkt, sdpcm_hdrlen);
+ ASSERT(ISALIGNED((uintptr)PKTDATA(osh, pkt), 2));
frame = (uint8*)PKTDATA(osh, pkt);
+ pkt_len = (uint16)PKTLEN(osh, pkt);
#ifdef WLMEDIA_HTSF
+ frame = (uint8*)PKTDATA(osh, pkt);
if (PKTLEN(osh, pkt) >= 100) {
- p = PKTDATA(osh, pkt);
- htsf_ts = (htsfts_t*) (p + HTSF_HOSTOFFSET + 12);
+ htsf_ts = (htsfts_t*) (frame + HTSF_HOSTOFFSET + 12);
if (htsf_ts->magic == HTSFMAGIC) {
htsf_ts->c20 = get_cycles();
htsf_ts->t20 = dhd_get_htsf(bus->dhd->info, 0);
}
}
#endif /* WLMEDIA_HTSF */
+#ifdef DHD_DEBUG
+ if (PKTPRIO(pkt) < ARRAYSIZE(tx_packets))
+ tx_packets[PKTPRIO(pkt)]++;
+#endif /* DHD_DEBUG */
- /* Add alignment padding, allocate new packet if needed */
- if ((pad1 = ((uintptr)frame % DHD_SDALIGN))) {
- if (PKTHEADROOM(osh, pkt) < pad1) {
- DHD_INFO(("%s: insufficient headroom %d for %d pad1\n",
- __FUNCTION__, (int)PKTHEADROOM(osh, pkt), pad1));
- bus->dhd->tx_realloc++;
- new = PKTGET(osh, (PKTLEN(osh, pkt) + DHD_SDALIGN), TRUE);
- if (!new) {
- DHD_ERROR(("%s: couldn't allocate new %d-byte packet\n",
- __FUNCTION__, PKTLEN(osh, pkt) + DHD_SDALIGN));
- ret = BCME_NOMEM;
- goto done;
+ /* align the data pointer, allocate a new packet if there is not enough space (new
+ * packet data pointer will be aligned thus no padding will be needed)
+ */
+ head_padding = (ulong)frame % DHD_SDALIGN;
+ if (PKTHEADROOM(osh, pkt) < head_padding) {
+ head_padding = 0;
+ alloc_new_pkt = TRUE;
+ } else {
+ uint cur_chain_total_len;
+ int chain_tail_padding = 0;
+
+ /* All packets need to be aligned by DHD_SDALIGN */
+ modulo = (pkt_len + head_padding) % DHD_SDALIGN;
+ tail_padding = modulo > 0 ? (DHD_SDALIGN - modulo) : 0;
+
+ /* Total pkt chain length needs to be aligned by block size,
+ * unless it is a single pkt chain with total length less than one block size,
+ * which we prefer sending by byte mode.
+ *
+ * Do the chain alignment here if
+ * 1. This is the last pkt of the chain of multiple pkts or a single pkt.
+ * 2-1. This chain is of multiple pkts, or
+ * 2-2. This is a single pkt whose size is longer than one block size.
+ */
+ cur_chain_total_len = prev_chain_total_len +
+ (head_padding + pkt_len + tail_padding);
+ if (last_chained_pkt && bus->blocksize != 0 &&
+ (cur_chain_total_len > (int)bus->blocksize || prev_chain_total_len > 0)) {
+ modulo = cur_chain_total_len % bus->blocksize;
+ chain_tail_padding = modulo > 0 ? (bus->blocksize - modulo) : 0;
+ }
+
+#ifdef DHDENABLE_TAILPAD
+ if (PKTTAILROOM(osh, pkt) < tail_padding) {
+ /* We don't have tail room to align by DHD_SDALIGN */
+ alloc_new_pkt = TRUE;
+ bus->tx_tailpad_pktget++;
+ } else if (PKTTAILROOM(osh, pkt) < tail_padding + chain_tail_padding) {
+ /* We have tail room for tail_padding of this pkt itself, but not for
+ * total pkt chain alignment by block size.
+ * Use the padding packet to avoid memory copy if applicable,
+ * otherwise, just allocate a new pkt.
+ */
+ if (bus->pad_pkt) {
+ *pad_pkt_len = chain_tail_padding;
+ bus->tx_tailpad_chain++;
+ } else {
+ alloc_new_pkt = TRUE;
+ bus->tx_tailpad_pktget++;
}
+ } else
+ /* This last pkt's tailroom is sufficient to hold both tail_padding
+ * of the pkt itself and chain_tail_padding of total pkt chain
+ */
+#endif /* DHDENABLE_TAILPAD */
+ tail_padding += chain_tail_padding;
+ }
- PKTALIGN(osh, new, PKTLEN(osh, pkt), DHD_SDALIGN);
- bcopy(PKTDATA(osh, pkt), PKTDATA(osh, new), PKTLEN(osh, pkt));
- if (free_pkt)
- PKTFREE(osh, pkt, TRUE);
- /* free the pkt if canned one is not used */
- free_pkt = TRUE;
- pkt = new;
- frame = (uint8*)PKTDATA(osh, pkt);
- ASSERT(((uintptr)frame % DHD_SDALIGN) == 0);
- pad1 = 0;
- } else {
- PKTPUSH(osh, pkt, pad1);
- frame = (uint8*)PKTDATA(osh, pkt);
+ DHD_INFO(("%s sdhdr len + orig_pkt_len %d h_pad %d t_pad %d pad_pkt_len %d\n",
+ __FUNCTION__, pkt_len, head_padding, tail_padding, *pad_pkt_len));
- ASSERT((pad1 + SDPCM_HDRLEN) <= (int) PKTLEN(osh, pkt));
- bzero(frame, pad1 + SDPCM_HDRLEN);
- }
- }
- ASSERT(pad1 < DHD_SDALIGN);
+ if (alloc_new_pkt) {
+ void *tmp_pkt;
+ int newpkt_size;
+ int cur_total_len;
- /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
- len = (uint16)PKTLEN(osh, pkt);
- *(uint16*)frame = htol16(len);
- *(((uint16*)frame) + 1) = htol16(~len);
+ ASSERT(*pad_pkt_len == 0);
-#ifdef BCMSDIOH_TXGLOM
- if (bus->glom_enable) {
- uint32 hwheader1 = 0, hwheader2 = 0, act_len = len;
+ DHD_INFO(("%s allocating new packet for padding\n", __FUNCTION__));
- /* Software tag: channel, sequence number, data offset */
- swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) |
- ((bus->tx_seq + bus->glom_cnt) % SDPCM_SEQUENCE_WRAP) |
- (((pad1 + SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
- htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN);
- htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN + sizeof(swheader));
-
- if (queue_only) {
- uint8 alignment = ALIGNMENT;
-#if defined(BCMLXSDMMC) && defined(CUSTOMER_HW4)
- if (bus->glom_mode == SDPCM_TXGLOM_MDESC)
- alignment = DHD_SDALIGN;
-#endif /* defined(BCMLXSDMMC) && defined(CUSTOMER_HW4) */
- if (forcealign && (len & (alignment - 1)))
- len = ROUNDUP(len, alignment);
- /* Hardware extention tag */
- /* 2byte frame length, 1byte-, 1byte frame flag,
- * 2byte-hdrlength, 2byte padlenght
- */
- hwheader1 = (act_len - SDPCM_FRAMETAG_LEN) | (0 << 24);
- hwheader2 = (len - act_len) << 16;
- htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN);
- htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4);
- real_pad = len - act_len;
- if (PKTTAILROOM(osh, pkt) < real_pad) {
- DHD_INFO(("%s 1: insufficient tailroom %d for %d real_pad\n",
- __FUNCTION__, (int)PKTTAILROOM(osh, pkt), real_pad));
- if (PKTPADTAILROOM(osh, pkt, real_pad)) {
- DHD_ERROR(("padding error size %d\n", real_pad));
- }
- }
-#ifdef BCMLXSDMMC
- PKTSETLEN(osh, pkt, len);
-#endif /* BCMLXSDMMC */
- /* Post the frame pointer to sdio glom array */
- dhd_bcmsdh_glom_post(bus, frame, pkt, len);
- /* Save the pkt pointer in bus glom array */
- bus->glom_pkt_arr[bus->glom_cnt] = pkt;
- bus->glom_total_len += len;
- bus->glom_cnt++;
- return BCME_OK;
- } else {
- /* Raise len to next SDIO block to eliminate tail command */
- if (bus->roundup && bus->blocksize &&
- ((bus->glom_total_len + len) > bus->blocksize)) {
- uint16 pad2 = bus->blocksize -
- ((bus->glom_total_len + len) % bus->blocksize);
- if ((pad2 <= bus->roundup) && (pad2 < bus->blocksize)) {
- len += pad2;
- } else {
- }
- } else if ((bus->glom_total_len + len) % DHD_SDALIGN) {
- len += DHD_SDALIGN
- - ((bus->glom_total_len + len) % DHD_SDALIGN);
- }
- if (forcealign && (len & (ALIGNMENT - 1))) {
- len = ROUNDUP(len, ALIGNMENT);
- }
+ /* head pointer is aligned now, no padding needed */
+ head_padding = 0;
- /* Hardware extention tag */
- /* 2byte frame length, 1byte-, 1byte frame flag,
- * 2byte-hdrlength, 2byte padlenght
- */
- hwheader1 = (act_len - SDPCM_FRAMETAG_LEN) | (1 << 24);
- hwheader2 = (len - act_len) << 16;
- htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN);
- htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4);
- real_pad = len - act_len;
- if (PKTTAILROOM(osh, pkt) < real_pad) {
- DHD_INFO(("%s 2: insufficient tailroom %d"
- " for %d real_pad\n",
- __FUNCTION__, (int)PKTTAILROOM(osh, pkt), real_pad));
- if (PKTPADTAILROOM(osh, pkt, real_pad)) {
- DHD_ERROR(("padding error size %d\n", real_pad));
- }
- }
-#ifdef BCMLXSDMMC
- PKTSETLEN(osh, pkt, len);
-#endif /* BCMLXSDMMC */
- /* Post the frame pointer to sdio glom array */
- dhd_bcmsdh_glom_post(bus, frame, pkt, len);
- /* Save the pkt pointer in bus glom array */
- bus->glom_pkt_arr[bus->glom_cnt] = pkt;
- bus->glom_cnt++;
- bus->glom_total_len += len;
-
- /* Update the total length on the first pkt */
- frame_tmp = (uint8*)PKTDATA(osh, bus->glom_pkt_arr[0]);
- *(uint16*)frame_tmp = htol16(bus->glom_total_len);
- *(((uint16*)frame_tmp) + 1) = htol16(~bus->glom_total_len);
+ /* update the tail padding as it depends on the head padding, since a new packet is
+ * allocated, the head padding is non longer needed and packet length is chagned
+ */
+
+ cur_total_len = prev_chain_total_len + pkt_len;
+ if (last_chained_pkt && bus->blocksize != 0 &&
+ (cur_total_len > (int)bus->blocksize || prev_chain_total_len > 0)) {
+ modulo = cur_total_len % bus->blocksize;
+ tail_padding = modulo > 0 ? (bus->blocksize - modulo) : 0;
+ }
+ else {
+ modulo = pkt_len % DHD_SDALIGN;
+ tail_padding = modulo > 0 ? (DHD_SDALIGN - modulo) : 0;
}
- } else
-#endif /* BCMSDIOH_TXGLOM */
- {
- uint32 act_len = len;
- /* Software tag: channel, sequence number, data offset */
- swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) | bus->tx_seq |
- (((pad1 + SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
- htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN);
- htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
-#ifdef DHD_DEBUG
- if (PKTPRIO(pkt) < ARRAYSIZE(tx_packets)) {
- tx_packets[PKTPRIO(pkt)]++;
- }
- if (DHD_BYTES_ON() &&
- (((DHD_CTL_ON() && (chan == SDPCM_CONTROL_CHANNEL)) ||
- (DHD_DATA_ON() && (chan != SDPCM_CONTROL_CHANNEL))))) {
- prhex("Tx Frame", frame, len);
- } else if (DHD_HDRS_ON()) {
- prhex("TxHdr", frame, MIN(len, 16));
+ newpkt_size = PKTLEN(osh, pkt) + bus->blocksize + DHD_SDALIGN;
+ bus->dhd->tx_realloc++;
+ tmp_pkt = PKTGET(osh, newpkt_size, TRUE);
+ if (tmp_pkt == NULL) {
+ DHD_ERROR(("failed to alloc new %d byte packet\n", newpkt_size));
+ return BCME_NOMEM;
+ }
+ PKTALIGN(osh, tmp_pkt, PKTLEN(osh, pkt), DHD_SDALIGN);
+ bcopy(PKTDATA(osh, pkt), PKTDATA(osh, tmp_pkt), PKTLEN(osh, pkt));
+ *new_pkt = tmp_pkt;
+ pkt = tmp_pkt;
}
-#endif
-#ifndef BCMSPI
- /* Raise len to next SDIO block to eliminate tail command */
- if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
- uint16 pad2 = bus->blocksize - (len % bus->blocksize);
- if ((pad2 <= bus->roundup) && (pad2 < bus->blocksize))
-#ifdef NOTUSED
- if (pad2 <= PKTTAILROOM(osh, pkt))
-#endif /* NOTUSED */
- len += pad2;
- } else if (len % DHD_SDALIGN) {
- len += DHD_SDALIGN - (len % DHD_SDALIGN);
- }
-#endif /* BCMSPI */
+ if (head_padding)
+ PKTPUSH(osh, pkt, head_padding);
- /* Some controllers have trouble with odd bytes -- round to even */
- if (forcealign && (len & (ALIGNMENT - 1))) {
-#ifdef NOTUSED
- if (PKTTAILROOM(osh, pkt))
-#endif
- len = ROUNDUP(len, ALIGNMENT);
-#ifdef NOTUSED
- else
- DHD_ERROR(("%s: sending unrounded %d-byte packet\n", __FUNCTION__, len));
-#endif
- }
- real_pad = len - act_len;
- if (PKTTAILROOM(osh, pkt) < real_pad) {
- DHD_INFO(("%s 3: insufficient tailroom %d for %d real_pad\n",
- __FUNCTION__, (int)PKTTAILROOM(osh, pkt), real_pad));
- if (PKTPADTAILROOM(osh, pkt, real_pad)) {
- DHD_ERROR(("padding error size %d\n", real_pad));
- }
- }
+ frame = (uint8*)PKTDATA(osh, pkt);
+ bzero(frame, head_padding + sdpcm_hdrlen);
+ pkt_len = (uint16)PKTLEN(osh, pkt);
+
+ /* the header has the followming format
+ * 4-byte HW frame tag: length, ~length (for glom this is the total length)
+ *
+ * 8-byte HW extesion flags (glom mode only) as the following:
+ * 2-byte packet length, excluding HW tag and padding
+ * 2-byte frame channel and frame flags (e.g. next frame following)
+ * 2-byte header length
+ * 2-byte tail padding size
+ *
+ * 8-byte SW frame tags as the following
+ * 4-byte flags: host tx seq, channel, data offset
+ * 4-byte flags: TBD
+ */
+
+ swhdr_offset = SDPCM_FRAMETAG_LEN;
+
+ /* hardware frame tag:
+ *
+ * in tx-glom mode, dongle only checks the hardware frame tag in the first
+ * packet and sees it as the total lenght of the glom (including tail padding),
+ * for each packet in the glom, the packet length needs to be updated, (see
+ * below PKTSETLEN)
+ *
+ * in non tx-glom mode, PKTLEN still need to include tail padding as to be
+ * referred to in sdioh_request_buffer(). The tail length will be excluded in
+ * dhdsdio_txpkt_postprocess().
+ */
+ *(uint16*)frame = (uint16)htol16(pkt_len);
+ *(((uint16*)frame) + 1) = (uint16)htol16(~pkt_len);
+ pkt_len += tail_padding;
+
+ /* hardware extesion flags */
+ if (bus->txglom_enable) {
+ uint32 hwheader1;
+ uint32 hwheader2;
+
+ swhdr_offset += SDPCM_HWEXT_LEN;
+ hwheader1 = (pkt_len - SDPCM_FRAMETAG_LEN - tail_padding) |
+ (last_chained_pkt << 24);
+ hwheader2 = (tail_padding) << 16;
+ htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN);
+ htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4);
}
- do {
- ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
- frame, len, pkt, NULL, NULL);
- bus->f2txdata++;
- ASSERT(ret != BCME_PENDING);
+ PKTSETLEN((osh), (pkt), (pkt_len));
- if (ret == BCME_NODEVICE) {
- DHD_ERROR(("%s: Device asleep already\n", __FUNCTION__));
- } else if (ret < 0) {
- /* On failure, abort the command and terminate the frame */
- DHD_ERROR(("%s: sdio error %d, abort command and terminate frame.\n",
- __FUNCTION__, ret));
- bus->tx_sderrs++;
+ /* software frame tags */
+ swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK)
+ | (txseq % SDPCM_SEQUENCE_WRAP) |
+ (((head_padding + sdpcm_hdrlen) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
+ htol32_ua_store(swheader, frame + swhdr_offset);
+ htol32_ua_store(0, frame + swhdr_offset + sizeof(swheader));
- bcmsdh_abort(sdh, SDIO_FUNC_2);
-#ifdef BCMSPI
- DHD_ERROR(("%s: gSPI transmit error. Check Overflow or F2-fifo-not-ready"
- " counters.\n", __FUNCTION__));
-#endif /* BCMSPI */
- bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
- SFC_WF_TERM, NULL);
- bus->f1regdata++;
+ return pkt_len;
+}
- for (i = 0; i < 3; i++) {
- uint8 hi, lo;
- hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
- SBSDIO_FUNC1_WFRAMEBCHI, NULL);
- lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
- SBSDIO_FUNC1_WFRAMEBCLO, NULL);
- bus->f1regdata += 2;
- if ((hi == 0) && (lo == 0))
- break;
- }
- }
- if (ret == 0) {
-#ifdef BCMSDIOH_TXGLOM
- if (bus->glom_enable) {
- bus->tx_seq = (bus->tx_seq + bus->glom_cnt) % SDPCM_SEQUENCE_WRAP;
- } else
-#endif
- {
- bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
- }
- }
- } while ((ret < 0) && retrydata && retries++ < TXRETRIES);
+static int dhdsdio_txpkt_postprocess(dhd_bus_t *bus, void *pkt)
+{
+ osl_t *osh;
+ uint8 *frame;
+ int data_offset;
+ int tail_padding;
+ int swhdr_offset = SDPCM_FRAMETAG_LEN + (bus->txglom_enable ? SDPCM_HWEXT_LEN : 0);
-done:
+ (void)osh;
+ osh = bus->dhd->osh;
-#ifdef BCMSDIOH_TXGLOM
- if (bus->glom_enable) {
- dhd_bcmsdh_glom_clear(bus);
- pkt_cnt = bus->glom_cnt;
- } else
-#endif
- {
- pkt_cnt = 1;
- }
- /* restore pkt buffer pointer before calling tx complete routine */
- while (pkt_cnt) {
-#ifdef BCMSDIOH_TXGLOM
- uint32 doff;
- if (bus->glom_enable) {
-#ifdef BCMLXSDMMC
- uint32 pad2 = 0;
-#endif /* BCMLXSDMMC */
- pkt = bus->glom_pkt_arr[bus->glom_cnt - pkt_cnt];
- frame = (uint8*)PKTDATA(osh, pkt);
- doff = ltoh32_ua(frame + SDPCM_FRAMETAG_LEN + SDPCM_HWEXT_LEN);
- doff = (doff & SDPCM_DOFFSET_MASK) >> SDPCM_DOFFSET_SHIFT;
-#ifdef BCMLXSDMMC
- pad2 = ltoh32_ua(frame + SDPCM_FRAMETAG_LEN + 4) >> 16;
- PKTSETLEN(osh, pkt, PKTLEN(osh, pkt) - pad2);
-#endif /* BCMLXSDMMC */
- PKTPULL(osh, pkt, doff);
- } else
-#endif /* BCMSDIOH_TXGLOM */
- {
- PKTPULL(osh, pkt, SDPCM_HDRLEN + pad1);
- }
-#ifdef PROP_TXSTATUS
- if (bus->dhd->wlfc_state) {
- dhd_os_sdunlock(bus->dhd);
- dhd_wlfc_txcomplete(bus->dhd, pkt, ret == 0);
- dhd_os_sdlock(bus->dhd);
+ /* restore pkt buffer pointer, but keeps the header pushed by dhd_prot_hdrpush */
+ frame = (uint8*)PKTDATA(osh, pkt);
+
+ DHD_INFO(("%s PKTLEN before postprocess %d",
+ __FUNCTION__, PKTLEN(osh, pkt)));
+
+ /* PKTLEN still includes tail_padding, so exclude it.
+ * We shall have head_padding + original pkt_len for PKTLEN afterwards.
+ */
+ if (bus->txglom_enable) {
+ /* txglom pkts have tail_padding length in HW ext header */
+ tail_padding = ltoh32_ua(frame + SDPCM_FRAMETAG_LEN + 4) >> 16;
+ PKTSETLEN(osh, pkt, PKTLEN(osh, pkt) - tail_padding);
+ DHD_INFO((" txglom pkt: tail_padding %d PKTLEN %d\n",
+ tail_padding, PKTLEN(osh, pkt)));
} else {
-#endif /* PROP_TXSTATUS */
-#ifdef SDTEST
- if (chan != SDPCM_TEST_CHANNEL) {
- dhd_txcomplete(bus->dhd, pkt, ret != 0);
+ /* non-txglom pkts have head_padding + original pkt length in HW frame tag.
+ * We cannot refer to this field for txglom pkts as the first pkt of the chain will
+ * have the field for the total length of the chain.
+ */
+ PKTSETLEN(osh, pkt, *(uint16*)frame);
+ DHD_INFO((" non-txglom pkt: HW frame tag len %d after PKTLEN %d\n",
+ *(uint16*)frame, PKTLEN(osh, pkt)));
}
-#else /* SDTEST */
- dhd_txcomplete(bus->dhd, pkt, ret != 0);
-#endif /* SDTEST */
- if (free_pkt)
- PKTFREE(osh, pkt, TRUE);
-#ifdef PROP_TXSTATUS
- }
-#endif
- pkt_cnt--;
- }
+ data_offset = ltoh32_ua(frame + swhdr_offset);
+ data_offset = (data_offset & SDPCM_DOFFSET_MASK) >> SDPCM_DOFFSET_SHIFT;
+ /* Get rid of sdpcm header + head_padding */
+ PKTPULL(osh, pkt, data_offset);
-#ifdef BCMSDIOH_TXGLOM
- /* Reset the glom array */
- if (bus->glom_enable) {
- bus->glom_cnt = 0;
- bus->glom_total_len = 0;
- }
-#endif
- return ret;
+ DHD_INFO(("%s data_offset %d, PKTLEN %d\n",
+ __FUNCTION__, data_offset, PKTLEN(osh, pkt)));
+
+ return BCME_OK;
}
-int
-dhd_bus_txdata(struct dhd_bus *bus, void *pkt)
+static int dhdsdio_txpkt(dhd_bus_t *bus, uint chan, void** pkts, int num_pkt, bool free_pkt)
{
- int ret = BCME_ERROR;
- osl_t *osh;
- uint datalen, prec;
-#ifdef DHD_TX_DUMP
- uint8 *dump_data;
- uint16 protocol;
-#ifdef DHD_TX_FULL_DUMP
int i;
-#endif /* DHD_TX_FULL_DUMP */
-#endif /* DHD_TX_DUMP */
- DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+ int ret = 0;
+ osl_t *osh;
+ bcmsdh_info_t *sdh;
+ void *pkt = NULL;
+ void *pkt_chain;
+ int total_len = 0;
+ void *head_pkt = NULL;
+ void *prev_pkt = NULL;
+ int pad_pkt_len = 0;
+ int new_pkt_num = 0;
+ void *new_pkts[MAX_TX_PKTCHAIN_CNT];
+ bool wlfc_enabled = FALSE;
+
+ if (bus->dhd->dongle_reset)
+ return BCME_NOTREADY;
+ sdh = bus->sdh;
osh = bus->dhd->osh;
- datalen = PKTLEN(osh, pkt);
+ /* init new_pkts[0] to make some compiler happy, not necessary as we check new_pkt_num */
+ new_pkts[0] = NULL;
+
+ for (i = 0; i < num_pkt; i++) {
+ int pkt_len;
+ bool last_pkt;
+ void *new_pkt = NULL;
+
+ pkt = pkts[i];
+ ASSERT(pkt);
+ last_pkt = (i == num_pkt - 1);
+ pkt_len = dhdsdio_txpkt_preprocess(bus, pkt, chan, bus->tx_seq + i,
+ total_len, last_pkt, &pad_pkt_len, &new_pkt);
+ if (pkt_len <= 0)
+ goto done;
+ if (new_pkt) {
+ pkt = new_pkt;
+ new_pkts[new_pkt_num++] = new_pkt;
+ }
+ total_len += pkt_len;
+
+ PKTSETNEXT(osh, pkt, NULL);
+ /* insert the packet into the list */
+ head_pkt ? PKTSETNEXT(osh, prev_pkt, pkt) : (head_pkt = pkt);
+ prev_pkt = pkt;
-#ifdef SDTEST
- /* Push the test header if doing loopback */
- if (bus->ext_loop) {
- uint8* data;
- PKTPUSH(osh, pkt, SDPCM_TEST_HDRLEN);
- data = PKTDATA(osh, pkt);
- *data++ = SDPCM_TEST_ECHOREQ;
- *data++ = (uint8)bus->loopid++;
- *data++ = (datalen >> 0);
- *data++ = (datalen >> 8);
- datalen += SDPCM_TEST_HDRLEN;
}
-#endif /* SDTEST */
-#ifdef DHD_TX_DUMP
- dump_data = PKTDATA(osh, pkt);
- dump_data += 4; /* skip 4 bytes header */
- protocol = (dump_data[12] << 8) | dump_data[13];
-#ifdef DHD_TX_FULL_DUMP
- DHD_ERROR(("TX DUMP\n"));
+ /* Update the HW frame tag (total length) in the first pkt of the glom */
+ if (bus->txglom_enable) {
+ uint8 *frame;
+
+ total_len += pad_pkt_len;
+ frame = (uint8*)PKTDATA(osh, head_pkt);
+ *(uint16*)frame = (uint16)htol16(total_len);
+ *(((uint16*)frame) + 1) = (uint16)htol16(~total_len);
- for (i = 0; i < (datalen - 4); i++) {
- DHD_ERROR(("%02X ", dump_data[i]));
- if ((i & 15) == 15)
- printk("\n");
}
- DHD_ERROR(("\n"));
-#endif /* DHD_TX_FULL_DUMP */
- if (protocol == ETHER_TYPE_802_1X) {
- DHD_ERROR(("ETHER_TYPE_802_1X: ver %d, type %d, replay %d\n",
- dump_data[14], dump_data[15], dump_data[30]));
+ /* if a padding packet if needed, insert it to the end of the link list */
+ if (pad_pkt_len) {
+ PKTSETLEN(osh, bus->pad_pkt, pad_pkt_len);
+ PKTSETNEXT(osh, pkt, bus->pad_pkt);
}
-#endif /* DHD_TX_DUMP */
- /* Add space for the header */
- PKTPUSH(osh, pkt, SDPCM_HDRLEN);
- ASSERT(ISALIGNED((uintptr)PKTDATA(osh, pkt), 2));
+ /* dhd_bcmsdh_send_buf ignores the buffer pointer if he packet
+ * parameter is not NULL, for non packet chian we pass NULL pkt pointer
+ * so it will take the aligned length and buffer pointer.
+ */
+ pkt_chain = PKTNEXT(osh, head_pkt) ? head_pkt : NULL;
+ ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
+ PKTDATA(osh, head_pkt), total_len, pkt_chain, NULL, NULL, TXRETRIES);
+ if (ret == BCME_OK)
+ bus->tx_seq = (bus->tx_seq + num_pkt) % SDPCM_SEQUENCE_WRAP;
- prec = PRIO2PREC((PKTPRIO(pkt) & PRIOMASK));
-#ifndef DHDTHREAD
- /* Lock: we're about to use shared data/code (and SDIO) */
- dhd_os_sdlock(bus->dhd);
-#endif /* DHDTHREAD */
+ /* if a padding packet was needed, remove it from the link list as it not a data pkt */
+ if (pad_pkt_len && pkt)
+ PKTSETNEXT(osh, pkt, NULL);
- /* Check for existing queue, current flow-control, pending event, or pending clock */
- if (dhd_deferred_tx || bus->fcstate || pktq_len(&bus->txq) || bus->dpc_sched ||
- (!DATAOK(bus)) || (bus->flowcontrol & NBITVAL(prec)) ||
- (bus->clkstate != CLK_AVAIL)) {
- DHD_TRACE(("%s: deferring pktq len %d\n", __FUNCTION__,
- pktq_len(&bus->txq)));
- bus->fcqueued++;
+done:
+ pkt = head_pkt;
+ while (pkt) {
+ void *pkt_next = PKTNEXT(osh, pkt);
+ PKTSETNEXT(osh, pkt, NULL);
+ dhdsdio_txpkt_postprocess(bus, pkt);
+ pkt = pkt_next;
+ }
- /* Priority based enq */
- dhd_os_sdlock_txq(bus->dhd);
- if (dhd_prec_enq(bus->dhd, &bus->txq, pkt, prec) == FALSE) {
- PKTPULL(osh, pkt, SDPCM_HDRLEN);
-#ifndef DHDTHREAD
- /* Need to also release txqlock before releasing sdlock.
- * This thread still has txqlock and releases sdlock.
- * Deadlock happens when dpc() grabs sdlock first then
- * attempts to grab txqlock.
- */
- dhd_os_sdunlock_txq(bus->dhd);
- dhd_os_sdunlock(bus->dhd);
-#endif
-#ifdef PROP_TXSTATUS
- if (bus->dhd->wlfc_state)
- dhd_wlfc_txcomplete(bus->dhd, pkt, FALSE);
- else
-#endif
- dhd_txcomplete(bus->dhd, pkt, FALSE);
-#ifndef DHDTHREAD
- dhd_os_sdlock(bus->dhd);
- dhd_os_sdlock_txq(bus->dhd);
-#endif
+ /* new packets might be allocated due to insufficient room for padding, but we
+ * still have to indicate the original packets to upper layer
+ */
+ for (i = 0; i < num_pkt; i++) {
+ pkt = pkts[i];
+ wlfc_enabled = FALSE;
#ifdef PROP_TXSTATUS
- /* let the caller decide whether to free the packet */
- if (!bus->dhd->wlfc_state)
-#endif
- PKTFREE(osh, pkt, TRUE);
- ret = BCME_NORESOURCE;
- }
- else
- ret = BCME_OK;
- if ((pktq_len(&bus->txq) >= FCHI) && dhd_doflow)
- dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON);
-
-#ifdef DHD_DEBUG
- if (pktq_plen(&bus->txq, prec) > qcount[prec])
- qcount[prec] = pktq_plen(&bus->txq, prec);
-#endif
- dhd_os_sdunlock_txq(bus->dhd);
-
- /* Schedule DPC if needed to send queued packet(s) */
- if (dhd_deferred_tx && !bus->dpc_sched) {
- bus->dpc_sched = TRUE;
- dhd_sched_dpc(bus->dhd);
+ if (DHD_PKTTAG_WLFCPKT(PKTTAG(pkt))) {
+ wlfc_enabled = (dhd_wlfc_txcomplete(bus->dhd, pkt, ret == 0) !=
+ WLFC_UNSUPPORTED);
}
- } else {
-#ifdef DHDTHREAD
- /* Lock: we're about to use shared data/code (and SDIO) */
- dhd_os_sdlock(bus->dhd);
-#endif /* DHDTHREAD */
-
- /* Otherwise, send it now */
- BUS_WAKE(bus);
- /* Make sure back plane ht clk is on, no pending allowed */
- dhdsdio_clkctl(bus, CLK_AVAIL, TRUE);
-#ifndef SDTEST
- ret = dhdsdio_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, TRUE, FALSE);
-#else
- ret = dhdsdio_txpkt(bus, pkt,
- (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL), TRUE, FALSE);
-#endif
- if (ret)
- bus->dhd->tx_errors++;
- else
- bus->dhd->dstats.tx_bytes += datalen;
-
- if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
- bus->activity = FALSE;
- dhdsdio_clkctl(bus, CLK_NONE, TRUE);
+#endif /* PROP_TXSTATUS */
+ if (!wlfc_enabled) {
+ PKTSETNEXT(osh, pkt, NULL);
+ dhd_txcomplete(bus->dhd, pkt, ret != 0);
+ if (free_pkt)
+ PKTFREE(osh, pkt, TRUE);
}
-
-#ifdef DHDTHREAD
- dhd_os_sdunlock(bus->dhd);
-#endif /* DHDTHREAD */
}
-#ifndef DHDTHREAD
- dhd_os_sdunlock(bus->dhd);
-#endif /* DHDTHREAD */
+ for (i = 0; i < new_pkt_num; i++)
+ PKTFREE(osh, new_pkts[i], TRUE);
return ret;
}
@@ -2343,19 +2200,13 @@ dhd_bus_txdata(struct dhd_bus *bus, void *pkt)
static uint
dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes)
{
- void *pkt;
- uint32 intstatus = 0;
- uint retries = 0;
- int ret = 0, prec_out;
uint cnt = 0;
- uint datalen;
uint8 tx_prec_map;
- uint8 txpktqlen = 0;
-#ifdef BCMSDIOH_TXGLOM
- uint i;
- uint8 glom_cnt;
-#endif
-
+ uint16 txpktqlen = 0;
+ uint32 intstatus = 0;
+ uint retries = 0;
+ osl_t *osh;
+ uint datalen = 0;
dhd_pub_t *dhd = bus->dhd;
sdpcmd_regs_t *regs = bus->regs;
@@ -2366,81 +2217,33 @@ dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes)
return BCME_NODEVICE;
}
+ osh = dhd->osh;
tx_prec_map = ~bus->flowcontrol;
- /* Send frames until the limit or some other event */
- for (cnt = 0; (cnt < maxframes) && DATAOK(bus); cnt++) {
-#ifdef BCMSDIOH_TXGLOM
- if (bus->glom_enable) {
- void *pkttable[SDPCM_MAXGLOM_SIZE];
- dhd_os_sdlock_txq(bus->dhd);
- glom_cnt = MIN(DATABUFCNT(bus), bus->glomsize);
- glom_cnt = MIN(glom_cnt, pktq_mlen(&bus->txq, tx_prec_map));
- glom_cnt = MIN(glom_cnt, maxframes-cnt);
-
- /* Limiting the size to 2pkts in case of copy */
- if (bus->glom_mode == SDPCM_TXGLOM_CPY)
- glom_cnt = MIN(glom_cnt, 10);
-
- for (i = 0; i < glom_cnt; i++)
- pkttable[i] = pktq_mdeq(&bus->txq, tx_prec_map, &prec_out);
+ for (cnt = 0; (cnt < maxframes) && DATAOK(bus);) {
+ int i;
+ int num_pkt = 1;
+ void *pkts[MAX_TX_PKTCHAIN_CNT];
+ int prec_out;
- txpktqlen = pktq_len(&bus->txq);
- dhd_os_sdunlock_txq(bus->dhd);
-
- if (glom_cnt == 0)
- break;
- datalen = 0;
- for (i = 0; i < glom_cnt; i++) {
- if ((pkt = pkttable[i]) == NULL) {
- /* This case should not happen */
- DHD_ERROR(("No pkts in the queue for glomming\n"));
- break;
- }
-
- datalen += (PKTLEN(bus->dhd->osh, pkt) - SDPCM_HDRLEN);
-#ifndef SDTEST
- ret = dhdsdio_txpkt(bus,
- pkt,
- SDPCM_DATA_CHANNEL,
- TRUE,
- (i == (glom_cnt-1))? FALSE: TRUE);
-#else
- ret = dhdsdio_txpkt(bus,
- pkt,
- (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL),
- TRUE,
- (i == (glom_cnt-1))? FALSE: TRUE);
-#endif
- }
- cnt += i-1;
- } else
-#endif /* BCMSDIOH_TXGLOM */
- {
dhd_os_sdlock_txq(bus->dhd);
- if ((pkt = pktq_mdeq(&bus->txq, tx_prec_map, &prec_out)) == NULL) {
- txpktqlen = pktq_len(&bus->txq);
- dhd_os_sdunlock_txq(bus->dhd);
- break;
+ if (bus->txglom_enable) {
+ num_pkt = MIN((uint32)DATABUFCNT(bus), (uint32)bus->txglomsize);
+ num_pkt = MIN(num_pkt, ARRAYSIZE(pkts));
}
- txpktqlen = pktq_len(&bus->txq);
- dhd_os_sdunlock_txq(bus->dhd);
- datalen = PKTLEN(bus->dhd->osh, pkt) - SDPCM_HDRLEN;
-
-#ifndef SDTEST
- ret = dhdsdio_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, TRUE, FALSE);
-#else
- ret = dhdsdio_txpkt(bus,
- pkt,
- (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL),
- TRUE,
- FALSE);
-#endif
+ num_pkt = MIN(num_pkt, pktq_mlen(&bus->txq, tx_prec_map));
+ for (i = 0; i < num_pkt; i++) {
+ pkts[i] = pktq_mdeq(&bus->txq, ~bus->flowcontrol, &prec_out);
+ datalen += PKTLEN(osh, pkts[i]);
}
+ dhd_os_sdunlock_txq(bus->dhd);
- if (ret)
- bus->dhd->tx_errors++;
+ if (i == 0)
+ break;
+ if (dhdsdio_txpkt(bus, SDPCM_DATA_CHANNEL, pkts, i, TRUE) != BCME_OK)
+ dhd->tx_errors++;
else
- bus->dhd->dstats.tx_bytes += datalen;
+ dhd->dstats.tx_bytes += datalen;
+ cnt += i;
/* In poll mode, need to check for other events */
if (!bus->intr && cnt)
@@ -2453,12 +2256,23 @@ dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes)
if (intstatus & bus->hostintmask)
bus->ipend = TRUE;
}
+
}
- /* Deflow-control stack if needed */
- if (dhd_doflow && dhd->up && (dhd->busstate == DHD_BUS_DATA) &&
- dhd->txoff && (txpktqlen < FCLOW))
- dhd_txflowcontrol(dhd, ALL_INTERFACES, OFF);
+ dhd_os_sdlock_txq(bus->dhd);
+ txpktqlen = pktq_len(&bus->txq);
+ dhd_os_sdunlock_txq(bus->dhd);
+
+ /* Do flow-control if needed */
+ if (dhd->up && (dhd->busstate == DHD_BUS_DATA) && (txpktqlen < FCLOW)) {
+ bool wlfc_enabled = FALSE;
+#ifdef PROP_TXSTATUS
+ wlfc_enabled = (dhd_wlfc_flowcontrol(dhd, OFF, TRUE) != WLFC_UNSUPPORTED);
+#endif
+ if (!wlfc_enabled && dhd_doflow && dhd->txoff) {
+ dhd_txflowcontrol(dhd, ALL_INTERFACES, OFF);
+ }
+ }
return cnt;
}
@@ -2467,13 +2281,11 @@ static void
dhdsdio_sendpendctl(dhd_bus_t *bus)
{
bcmsdh_info_t *sdh = bus->sdh;
- int ret, i;
+ int ret;
uint8* frame_seq = bus->ctrl_frame_buf + SDPCM_FRAMETAG_LEN;
-#ifdef BCMSDIOH_TXGLOM
- if (bus->glom_enable)
+ if (bus->txglom_enable)
frame_seq += SDPCM_HWEXT_LEN;
-#endif
if (*frame_seq != bus->tx_seq) {
DHD_INFO(("%s IOCTL frame seq lag detected!"
@@ -2483,37 +2295,10 @@ dhdsdio_sendpendctl(dhd_bus_t *bus)
}
ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
- (uint8 *)bus->ctrl_frame_buf, (uint32)bus->ctrl_frame_len,
- NULL, NULL, NULL);
- ASSERT(ret != BCME_PENDING);
- if (ret == BCME_NODEVICE) {
- DHD_ERROR(("%s: Device asleep already\n", __FUNCTION__));
- } else if (ret < 0) {
- /* On failure, abort the command and terminate the frame */
- DHD_INFO(("%s: sdio error %d, abort command and terminate frame.\n",
- __FUNCTION__, ret));
- bus->tx_sderrs++;
-
- bcmsdh_abort(sdh, SDIO_FUNC_2);
-
- bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
- SFC_WF_TERM, NULL);
- bus->f1regdata++;
-
- for (i = 0; i < 3; i++) {
- uint8 hi, lo;
- hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
- SBSDIO_FUNC1_WFRAMEBCHI, NULL);
- lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
- SBSDIO_FUNC1_WFRAMEBCLO, NULL);
- bus->f1regdata += 2;
- if ((hi == 0) && (lo == 0))
- break;
- }
- }
- if (ret == 0) {
+ (uint8 *)bus->ctrl_frame_buf, (uint32)bus->ctrl_frame_len,
+ NULL, NULL, NULL, 1);
+ if (ret == BCME_OK)
bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
- }
bus->ctrl_frame_stat = FALSE;
dhd_wait_event_wakeup(bus->dhd);
@@ -2522,14 +2307,14 @@ dhdsdio_sendpendctl(dhd_bus_t *bus)
int
dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen)
{
+ static int err_nodevice = 0;
uint8 *frame;
uint16 len;
uint32 swheader;
- uint retries = 0;
bcmsdh_info_t *sdh = bus->sdh;
uint8 doff = 0;
int ret = -1;
- int i;
+ uint8 sdpcm_hdrlen = bus->txglom_enable ? SDPCM_HDRLEN_TXGLOM : SDPCM_HDRLEN;
DHD_TRACE(("%s: Enter\n", __FUNCTION__));
@@ -2537,8 +2322,8 @@ dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen)
return -EIO;
/* Back the pointer to make a room for bus header */
- frame = msg - SDPCM_HDRLEN;
- len = (msglen += SDPCM_HDRLEN);
+ frame = msg - sdpcm_hdrlen;
+ len = (msglen += sdpcm_hdrlen);
/* Add alignment padding (optional for ctl frames) */
if (dhd_alignctl) {
@@ -2546,11 +2331,11 @@ dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen)
frame -= doff;
len += doff;
msglen += doff;
- bzero(frame, doff + SDPCM_HDRLEN);
+ bzero(frame, doff + sdpcm_hdrlen);
}
ASSERT(doff < DHD_SDALIGN);
}
- doff += SDPCM_HDRLEN;
+ doff += sdpcm_hdrlen;
#ifndef BCMSPI
/* Round send length to next SDIO block */
@@ -2582,8 +2367,7 @@ dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen)
*(uint16*)frame = htol16((uint16)msglen);
*(((uint16*)frame) + 1) = htol16(~msglen);
-#ifdef BCMSDIOH_TXGLOM
- if (bus->glom_enable) {
+ if (bus->txglom_enable) {
uint32 hwheader1, hwheader2;
/* Software tag: channel, sequence number, data offset */
swheader = ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK)
@@ -2600,14 +2384,12 @@ dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen)
*(uint16*)frame = htol16(len);
*(((uint16*)frame) + 1) = htol16(~(len));
- } else
-#endif /* BCMSDIOH_TXGLOM */
- {
- /* Software tag: channel, sequence number, data offset */
- swheader = ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK)
- | bus->tx_seq | ((doff << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
- htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN);
- htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
+ } else {
+ /* Software tag: channel, sequence number, data offset */
+ swheader = ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK)
+ | bus->tx_seq | ((doff << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
+ htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN);
+ htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
}
if (!TXCTLOK(bus)) {
DHD_INFO(("%s: No bus credit bus->tx_max %d, bus->tx_seq %d\n",
@@ -2649,6 +2431,7 @@ dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen)
}
bus->dhd->txcnt_timeout = 0;
+ bus->ctrl_frame_stat = TRUE;
if (ret == -1) {
#ifdef DHD_DEBUG
@@ -2658,47 +2441,12 @@ dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen)
prhex("TxHdr", frame, MIN(len, 16));
}
#endif
-
- do {
- ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
- frame, len, NULL, NULL, NULL);
- ASSERT(ret != BCME_PENDING);
-
- if (ret == BCME_NODEVICE) {
- DHD_ERROR(("%s: Device asleep already\n", __FUNCTION__));
- } else if (ret < 0) {
- /* On failure, abort the command and terminate the frame */
- DHD_INFO(("%s: sdio error %d, abort command and terminate frame.\n",
- __FUNCTION__, ret));
- bus->tx_sderrs++;
-
- bcmsdh_abort(sdh, SDIO_FUNC_2);
-
-#ifdef BCMSPI
- DHD_ERROR(("%s: Check Overflow or F2-fifo-not-ready counters."
- " gSPI transmit error on control channel.\n",
- __FUNCTION__));
-#endif /* BCMSPI */
- bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
- SFC_WF_TERM, NULL);
- bus->f1regdata++;
-
- for (i = 0; i < 3; i++) {
- uint8 hi, lo;
- hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
- SBSDIO_FUNC1_WFRAMEBCHI, NULL);
- lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
- SBSDIO_FUNC1_WFRAMEBCLO, NULL);
- bus->f1regdata += 2;
- if ((hi == 0) && (lo == 0))
- break;
- }
- }
- if (ret == 0) {
- bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
- }
- } while ((ret < 0) && retries++ < TXRETRIES);
+ ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
+ frame, len, NULL, NULL, NULL, TXRETRIES);
+ if (ret == BCME_OK)
+ bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
}
+ bus->ctrl_frame_stat = FALSE;
done:
if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
@@ -2716,7 +2464,12 @@ done:
if (bus->dhd->txcnt_timeout >= MAX_CNTL_TX_TIMEOUT)
return -ETIMEDOUT;
- return ret ? -EIO : 0;
+ if (ret == BCME_NODEVICE)
+ err_nodevice++;
+ else
+ err_nodevice = 0;
+
+ return ret ? err_nodevice >= ERROR_BCME_NODEVICE_MAX ? -ETIMEDOUT : -EIO : 0;
}
int
@@ -2801,7 +2554,8 @@ enum {
IOV_SBREG,
IOV_SDCIS,
IOV_MEMBYTES,
- IOV_MEMSIZE,
+ IOV_RAMSIZE,
+ IOV_RAMSTART,
#ifdef DHD_DEBUG
IOV_CHECKDIED,
IOV_SERIALCONS,
@@ -2816,10 +2570,10 @@ enum {
IOV_SDALIGN,
IOV_DEVRESET,
IOV_CPU,
-#if defined(SDIO_CRC_ERROR_FIX)
+#if defined(USE_SDIOFIFO_IOVAR)
IOV_WATERMARK,
IOV_MESBUSYCTRL,
-#endif /* SDIO_CRC_ERROR_FIX */
+#endif /* USE_SDIOFIFO_IOVAR */
#ifdef SDTEST
IOV_PKTGEN,
IOV_EXTLOOP,
@@ -2841,7 +2595,9 @@ enum {
IOV_FWPATH,
#endif
IOV_TXGLOMSIZE,
- IOV_TXGLOMMODE
+ IOV_TXGLOMMODE,
+ IOV_HANGREPORT,
+ IOV_TXINRX_THRES
};
const bcm_iovar_t dhdsdio_iovars[] = {
@@ -2852,7 +2608,8 @@ const bcm_iovar_t dhdsdio_iovars[] = {
{"idleclock", IOV_IDLECLOCK, 0, IOVT_INT32, 0 },
{"sd1idle", IOV_SD1IDLE, 0, IOVT_BOOL, 0 },
{"membytes", IOV_MEMBYTES, 0, IOVT_BUFFER, 2 * sizeof(int) },
- {"memsize", IOV_MEMSIZE, 0, IOVT_UINT32, 0 },
+ {"ramsize", IOV_RAMSIZE, 0, IOVT_UINT32, 0 },
+ {"ramstart", IOV_RAMSTART, 0, IOVT_UINT32, 0 },
{"dwnldstate", IOV_SET_DOWNLOAD_STATE, 0, IOVT_BOOL, 0 },
{"socram_state", IOV_SOCRAM_STATE, 0, IOVT_BOOL, 0 },
{"vars", IOV_VARS, 0, IOVT_BUFFER, 0 },
@@ -2880,10 +2637,10 @@ const bcm_iovar_t dhdsdio_iovars[] = {
{"extloop", IOV_EXTLOOP, 0, IOVT_BOOL, 0 },
{"pktgen", IOV_PKTGEN, 0, IOVT_BUFFER, sizeof(dhd_pktgen_t) },
#endif /* SDTEST */
-#if defined(SDIO_CRC_ERROR_FIX)
+#if defined(USE_SDIOFIFO_IOVAR)
{"watermark", IOV_WATERMARK, 0, IOVT_UINT32, 0 },
{"mesbusyctrl", IOV_MESBUSYCTRL, 0, IOVT_UINT32, 0 },
-#endif /* SDIO_CRC_ERROR_FIX */
+#endif /* USE_SDIOFIFO_IOVAR */
{"devcap", IOV_DEVCAP, 0, IOVT_UINT32, 0 },
{"dngl_isolation", IOV_DONGLEISOLATION, 0, IOVT_UINT32, 0 },
{"kso", IOV_KSO, 0, IOVT_UINT32, 0 },
@@ -2892,7 +2649,8 @@ const bcm_iovar_t dhdsdio_iovars[] = {
{"fwpath", IOV_FWPATH, 0, IOVT_BUFFER, 0 },
#endif
{"txglomsize", IOV_TXGLOMSIZE, 0, IOVT_UINT32, 0 },
- {"txglommode", IOV_TXGLOMMODE, 0, IOVT_UINT32, 0 },
+ {"fw_hang_report", IOV_HANGREPORT, 0, IOVT_BOOL, 0 },
+ {"txinrx_thres", IOV_TXINRX_THRES, 0, IOVT_INT32, 0 },
{NULL, 0, 0, 0, 0 }
};
@@ -2918,25 +2676,29 @@ dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf)
bcm_bprintf(strbuf, "Bus SDIO structure:\n");
bcm_bprintf(strbuf, "hostintmask 0x%08x intstatus 0x%08x sdpcm_ver %d\n",
bus->hostintmask, bus->intstatus, bus->sdpcm_ver);
- bcm_bprintf(strbuf, "fcstate %d qlen %d tx_seq %d, max %d, rxskip %d rxlen %d rx_seq %d\n",
+ bcm_bprintf(strbuf, "fcstate %d qlen %u tx_seq %d, max %d, rxskip %d rxlen %u rx_seq %d\n",
bus->fcstate, pktq_len(&bus->txq), bus->tx_seq, bus->tx_max, bus->rxskip,
bus->rxlen, bus->rx_seq);
- bcm_bprintf(strbuf, "intr %d intrcount %d lastintrs %d spurious %d\n",
+ bcm_bprintf(strbuf, "intr %d intrcount %u lastintrs %u spurious %u\n",
bus->intr, bus->intrcount, bus->lastintrs, bus->spurious);
- bcm_bprintf(strbuf, "pollrate %d pollcnt %d regfails %d\n",
+ bcm_bprintf(strbuf, "pollrate %u pollcnt %u regfails %u\n",
bus->pollrate, bus->pollcnt, bus->regfails);
bcm_bprintf(strbuf, "\nAdditional counters:\n");
- bcm_bprintf(strbuf, "tx_sderrs %d fcqueued %d rxrtx %d rx_toolong %d rxc_errors %d\n",
+#ifdef DHDENABLE_TAILPAD
+ bcm_bprintf(strbuf, "tx_tailpad_chain %u tx_tailpad_pktget %u\n",
+ bus->tx_tailpad_chain, bus->tx_tailpad_pktget);
+#endif
+ bcm_bprintf(strbuf, "tx_sderrs %u fcqueued %u rxrtx %u rx_toolong %u rxc_errors %u\n",
bus->tx_sderrs, bus->fcqueued, bus->rxrtx, bus->rx_toolong,
bus->rxc_errors);
- bcm_bprintf(strbuf, "rx_hdrfail %d badhdr %d badseq %d\n",
+ bcm_bprintf(strbuf, "rx_hdrfail %u badhdr %u badseq %u\n",
bus->rx_hdrfail, bus->rx_badhdr, bus->rx_badseq);
- bcm_bprintf(strbuf, "fc_rcvd %d, fc_xoff %d, fc_xon %d\n",
+ bcm_bprintf(strbuf, "fc_rcvd %u, fc_xoff %u, fc_xon %u\n",
bus->fc_rcvd, bus->fc_xoff, bus->fc_xon);
- bcm_bprintf(strbuf, "rxglomfail %d, rxglomframes %d, rxglompkts %d\n",
+ bcm_bprintf(strbuf, "rxglomfail %u, rxglomframes %u, rxglompkts %u\n",
bus->rxglomfail, bus->rxglomframes, bus->rxglompkts);
- bcm_bprintf(strbuf, "f2rx (hdrs/data) %d (%d/%d), f2tx %d f1regs %d\n",
+ bcm_bprintf(strbuf, "f2rx (hdrs/data) %u (%u/%u), f2tx %u f1regs %u\n",
(bus->f2rxhdrs + bus->f2rxdata), bus->f2rxhdrs, bus->f2rxdata,
bus->f2txdata, bus->f1regdata);
{
@@ -2976,17 +2738,17 @@ dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf)
#ifdef SDTEST
if (bus->pktgen_count) {
bcm_bprintf(strbuf, "pktgen config and count:\n");
- bcm_bprintf(strbuf, "freq %d count %d print %d total %d min %d len %d\n",
+ bcm_bprintf(strbuf, "freq %u count %u print %u total %u min %u len %u\n",
bus->pktgen_freq, bus->pktgen_count, bus->pktgen_print,
bus->pktgen_total, bus->pktgen_minlen, bus->pktgen_maxlen);
- bcm_bprintf(strbuf, "send attempts %d rcvd %d fail %d\n",
+ bcm_bprintf(strbuf, "send attempts %u rcvd %u fail %u\n",
bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail);
}
#endif /* SDTEST */
#ifdef DHD_DEBUG
bcm_bprintf(strbuf, "dpc_sched %d host interrupt%spending\n",
bus->dpc_sched, (bcmsdh_intr_pending(bus->sdh) ? " " : " not "));
- bcm_bprintf(strbuf, "blocksize %d roundup %d\n", bus->blocksize, bus->roundup);
+ bcm_bprintf(strbuf, "blocksize %u roundup %u\n", bus->blocksize, bus->roundup);
#endif /* DHD_DEBUG */
bcm_bprintf(strbuf, "clkstate %d activity %d idletime %d idlecount %d sleeping %d\n",
bus->clkstate, bus->activity, bus->idletime, bus->idlecount, bus->sleeping);
@@ -3000,6 +2762,9 @@ dhd_bus_clearcounts(dhd_pub_t *dhdp)
bus->intrcount = bus->lastintrs = bus->spurious = bus->regfails = 0;
bus->rxrtx = bus->rx_toolong = bus->rxc_errors = 0;
bus->rx_hdrfail = bus->rx_badhdr = bus->rx_badseq = 0;
+#ifdef DHDENABLE_TAILPAD
+ bus->tx_tailpad_chain = bus->tx_tailpad_pktget = 0;
+#endif
bus->tx_sderrs = bus->fc_rcvd = bus->fc_xoff = bus->fc_xon = 0;
bus->rxglomfail = bus->rxglomframes = bus->rxglompkts = 0;
bus->f2rxhdrs = bus->f2rxdata = bus->f2txdata = bus->f1regdata = 0;
@@ -3269,6 +3034,9 @@ dhdsdio_readconsole(dhd_bus_t *bus)
n--;
line[n] = 0;
printf("CONSOLE: %s\n", line);
+#ifdef LOG_INTO_TCPDUMP
+ dhd_sendup_log(bus->dhd, line, n);
+#endif /* LOG_INTO_TCPDUMP */
}
}
break2:
@@ -3525,7 +3293,9 @@ dhd_serialconsole(dhd_bus_t *bus, bool set, bool enable, int *bcmerror)
uart_enab = CC_PLL_CHIPCTRL_SERIAL_ENAB;
}
else if (bus->sih->chip == BCM4334_CHIP_ID ||
+ bus->sih->chip == BCM43340_CHIP_ID ||
bus->sih->chip == BCM43341_CHIP_ID ||
+ bus->sih->chip == BCM43342_CHIP_ID ||
0) {
if (enable) {
/* Moved to PMU chipcontrol 1 from 4330 */
@@ -3724,13 +3494,13 @@ dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const ch
/* check if CR4 */
if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
- /* if address is 0, store the reset instruction to be written in 0 */
-
- if (address == 0) {
+ /*
+ * If address is start of RAM (i.e. a downloaded image),
+ * store the reset instruction to be written in 0
+ */
+ if (set && address == bus->dongle_ram_base) {
bus->resetinstr = *(((uint32*)params) + 2);
}
- /* Add start of RAM address to the address given by user */
- address += bus->dongle_ram_base;
} else {
/* If we know about SOCRAM, check for a fit */
if ((bus->orig_ramsize) &&
@@ -3784,11 +3554,16 @@ dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const ch
break;
}
- case IOV_GVAL(IOV_MEMSIZE):
+ case IOV_GVAL(IOV_RAMSIZE):
int_val = (int32)bus->ramsize;
bcopy(&int_val, arg, val_size);
break;
+ case IOV_GVAL(IOV_RAMSTART):
+ int_val = (int32)bus->dongle_ram_base;
+ bcopy(&int_val, arg, val_size);
+ break;
+
case IOV_GVAL(IOV_SDIOD_DRIVE):
int_val = (int32)dhd_sdiod_drive_strength;
bcopy(&int_val, arg, val_size);
@@ -3866,7 +3641,7 @@ dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const ch
sd_ptr = (sdreg_t *)params;
- addr = (uintptr)bus->regs + sd_ptr->offset;
+ addr = (ulong)bus->regs + sd_ptr->offset;
size = sd_ptr->func;
int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size);
if (bcmsdh_regfail(bus->sdh))
@@ -3882,7 +3657,7 @@ dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const ch
sd_ptr = (sdreg_t *)params;
- addr = (uintptr)bus->regs + sd_ptr->offset;
+ addr = (ulong)bus->regs + sd_ptr->offset;
size = sd_ptr->func;
bcmsdh_reg_write(bus->sdh, addr, size, sd_ptr->value);
if (bcmsdh_regfail(bus->sdh))
@@ -3984,7 +3759,6 @@ dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const ch
break;
-
#endif /* DHD_DEBUG */
@@ -4007,7 +3781,7 @@ dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const ch
break;
#endif /* SDTEST */
-#if defined(SDIO_CRC_ERROR_FIX)
+#if defined(USE_SDIOFIFO_IOVAR)
case IOV_GVAL(IOV_WATERMARK):
int_val = (int32)watermark;
bcopy(&int_val, arg, val_size);
@@ -4033,7 +3807,7 @@ dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const ch
bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL,
((uint8)mesbusyctrl | 0x80), NULL);
break;
-#endif /* SDIO_CRC_ERROR_FIX */
+#endif
case IOV_GVAL(IOV_DONGLEISOLATION):
@@ -4056,45 +3830,10 @@ dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const ch
dhd_bus_devreset(bus->dhd, (uint8)bool_val);
break;
-#ifdef SOFTAP
- case IOV_GVAL(IOV_FWPATH):
- {
- uint32 fw_path_len;
-
- fw_path_len = strlen(bus->fw_path);
- DHD_INFO(("[softap] get fwpath, l=%d\n", len));
-
- if (fw_path_len > len-1) {
- bcmerror = BCME_BUFTOOSHORT;
- break;
- }
-
- if (fw_path_len) {
- bcopy(bus->fw_path, arg, fw_path_len);
- ((uchar*)arg)[fw_path_len] = 0;
- }
- break;
- }
-
- case IOV_SVAL(IOV_FWPATH):
- DHD_INFO(("[softap] set fwpath, idx=%d\n", int_val));
-
- switch (int_val) {
- case 1:
- bus->fw_path = fw_path; /* ordinary one */
- break;
- case 2:
- bus->fw_path = fw_path2;
- break;
- default:
- bcmerror = BCME_BADARG;
- break;
- }
-
- DHD_INFO(("[softap] new fw path: %s\n", (bus->fw_path[0] ? bus->fw_path : "NULL")));
- break;
+ /*
+ * softap firmware is updated through module parameter or android private command
+ */
-#endif /* SOFTAP */
case IOV_GVAL(IOV_DEVRESET):
DHD_TRACE(("%s: Called get IOV_DEVRESET\n", __FUNCTION__));
@@ -4117,10 +3856,8 @@ dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const ch
case IOV_SVAL(IOV_DEVCAP):
dhdsdio_devcap_set(bus, (uint8) int_val);
break;
-
-#ifdef BCMSDIOH_TXGLOM
case IOV_GVAL(IOV_TXGLOMSIZE):
- int_val = (int32)bus->glomsize;
+ int_val = (int32)bus->txglomsize;
bcopy(&int_val, arg, val_size);
break;
@@ -4128,23 +3865,31 @@ dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const ch
if (int_val > SDPCM_MAXGLOM_SIZE) {
bcmerror = BCME_ERROR;
} else {
- bus->glomsize = (uint)int_val;
+ bus->txglomsize = (uint)int_val;
}
break;
- case IOV_GVAL(IOV_TXGLOMMODE):
- int_val = (int32)bus->glom_mode;
+ case IOV_SVAL(IOV_HANGREPORT):
+ bus->dhd->hang_report = bool_val;
+ DHD_ERROR(("%s: Set hang_report as %d\n", __FUNCTION__, bus->dhd->hang_report));
+ break;
+
+ case IOV_GVAL(IOV_HANGREPORT):
+ int_val = (int32)bus->dhd->hang_report;
bcopy(&int_val, arg, val_size);
break;
- case IOV_SVAL(IOV_TXGLOMMODE):
- if ((int_val != SDPCM_TXGLOM_CPY) && (int_val != SDPCM_TXGLOM_MDESC)) {
- bcmerror = BCME_RANGE;
+ case IOV_GVAL(IOV_TXINRX_THRES):
+ int_val = bus->txinrx_thres;
+ bcopy(&int_val, arg, val_size);
+ break;
+ case IOV_SVAL(IOV_TXINRX_THRES):
+ if (int_val < 0) {
+ bcmerror = BCME_BADARG;
} else {
- if ((bus->glom_mode = bcmsdh_set_mode(bus->sdh, (uint)int_val)) != int_val)
- bcmerror = BCME_ERROR;
+ bus->txinrx_thres = int_val;
}
break;
-#endif /* BCMSDIOH_TXGLOM */
+
default:
bcmerror = BCME_UNSUPPORTED;
break;
@@ -4487,8 +4232,7 @@ dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name,
DHD_INFO(("%s: noted %s update, value now %d\n",
__FUNCTION__, "sd_blocksize", bus->blocksize));
- if (bus->sih->chip == BCM4335_CHIP_ID)
- dhd_overflow_war(bus);
+ dhdsdio_tune_fifoparam(bus);
}
}
bus->roundup = MIN(max_roundup, bus->blocksize);
@@ -4533,16 +4277,18 @@ dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex)
{
osl_t *osh;
uint32 local_hostintmask;
- uint8 saveclk, dat;
+ uint8 saveclk;
uint retries;
int err;
+ bool wlfc_enabled = FALSE;
+
if (!bus->dhd)
return;
osh = bus->dhd->osh;
DHD_TRACE(("%s: Enter\n", __FUNCTION__));
- bcmsdh_waitlockfree(NULL);
+ bcmsdh_waitlockfree(bus->sdh);
if (enforce_mutex)
dhd_os_sdlock(bus->dhd);
@@ -4556,13 +4302,6 @@ dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex)
BUS_WAKE(bus);
- if (KSO_ENAB(bus)) {
- /* Mask the interrupt */
- dat = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_INTEN, NULL);
- dat &= ~(INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN);
- bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_INTEN, dat, NULL);
- }
-
/* Change our idea of bus state */
bus->dhd->busstate = DHD_BUS_DOWN;
@@ -4602,8 +4341,19 @@ dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex)
dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
}
- /* Clear the data packet queues */
- pktq_flush(osh, &bus->txq, TRUE, NULL, 0);
+#ifdef PROP_TXSTATUS
+ wlfc_enabled = (dhd_wlfc_cleanup_txq(bus->dhd, NULL, 0) != WLFC_UNSUPPORTED);
+#endif
+ if (!wlfc_enabled) {
+#ifdef DHDTCPACK_SUPPRESS
+ /* Clean tcp_ack_info_tbl in order to prevent access to flushed pkt,
+ * when there is a newly coming packet from network stack.
+ */
+ dhd_tcpack_info_tbl_clean(bus->dhd);
+#endif /* DHDTCPACK_SUPPRESS */
+ /* Clear the data packet queues */
+ pktq_flush(osh, &bus->txq, TRUE, NULL, 0);
+ }
/* Clear any held glomming stuff */
if (bus->glomd)
@@ -4628,33 +4378,46 @@ dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex)
dhd_os_sdunlock(bus->dhd);
}
-#ifdef BCMSDIOH_TXGLOM
+#if defined(BCMSDIOH_TXGLOM) && defined(BCMSDIOH_STD)
+extern uint sd_txglom;
+#endif
void
dhd_txglom_enable(dhd_pub_t *dhdp, bool enable)
{
+ /* can't enable host txglom by default, some platforms have no
+ * (or crappy) ADMA support and txglom will cause kernel assertions (e.g.
+ * panda board)
+ */
dhd_bus_t *bus = dhdp->bus;
-
+#ifdef BCMSDIOH_TXGLOM
char buf[256];
uint32 rxglom;
int32 ret;
+ DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+
+#ifdef BCMSDIOH_STD
+ if (enable)
+ enable = sd_txglom;
+#endif /* BCMSDIOH_STD */
+
if (enable) {
rxglom = 1;
memset(buf, 0, sizeof(buf));
- bcm_mkiovar("bus:rxglom",
- (void *)&rxglom,
- 4, buf, sizeof(buf));
- ret = dhd_wl_ioctl_cmd(dhdp,
- WLC_SET_VAR, buf,
- sizeof(buf), TRUE, 0);
- if (!(ret < 0)) {
- bus->glom_enable = TRUE;
+ bcm_mkiovar("bus:rxglom", (void *)&rxglom, 4, buf, sizeof(buf));
+ ret = dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0);
+ if (ret >= 0)
+ bus->txglom_enable = TRUE;
+ else {
+#ifdef BCMSDIOH_STD
+ sd_txglom = 0;
+#endif /* BCMSDIOH_STD */
+ bus->txglom_enable = FALSE;
}
- } else {
- bus->glom_enable = FALSE;
- }
-}
+ } else
#endif /* BCMSDIOH_TXGLOM */
+ bus->txglom_enable = FALSE;
+}
int
dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex)
@@ -4761,21 +4524,11 @@ dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex)
}
#endif /* BCMSPI */
W_SDREG(bus->hostintmask, &bus->regs->hostintmask, retries);
-#ifdef SDIO_CRC_ERROR_FIX
- if (bus->blocksize < 512) {
- mesbusyctrl = watermark = bus->blocksize / 4;
- }
-#endif /* SDIO_CRC_ERROR_FIX */
- if (bus->sih->chip != BCM4335_CHIP_ID) {
+
+ if (bus->sih->buscorerev < 15) {
bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK,
(uint8)watermark, &err);
}
-#ifdef SDIO_CRC_ERROR_FIX
- bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL,
- (uint8)mesbusyctrl|0x80, &err);
- bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL,
- SBSDIO_DEVCTL_EN_F2_BLK_WATERMARK, NULL);
-#endif /* SDIO_CRC_ERROR_FIX */
/* Set bus state according to enable result */
dhdp->busstate = DHD_BUS_DATA;
@@ -4785,7 +4538,9 @@ dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex)
bus->intdis = FALSE;
if (bus->intr) {
DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__));
+#ifndef BCMSPI_ANDROID
bcmsdh_intr_enable(bus->sdh);
+#endif /* !BCMSPI_ANDROID */
} else {
DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
bcmsdh_intr_disable(bus->sdh);
@@ -4801,8 +4556,14 @@ dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex)
bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL);
}
- if (dhdsdio_sr_cap(bus))
+ if (dhdsdio_sr_cap(bus)) {
dhdsdio_sr_init(bus);
+ /* Masking the chip active interrupt permanantly */
+ bus->hostintmask &= ~I_CHIPACTIVE;
+ W_SDREG(bus->hostintmask, &bus->regs->hostintmask, retries);
+ DHD_INFO(("%s: disable I_CHIPACTIVE in hostintmask[0x%08x]\n",
+ __FUNCTION__, bus->hostintmask));
+ }
else
bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1,
SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err);
@@ -4992,6 +4753,9 @@ done:
/* Awake any waiters */
dhd_os_ioctl_resp_wake(bus->dhd);
}
+int
+dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf, uint reorder_info_len,
+ void **pkt, uint32 *pkt_count);
static uint8
dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq)
@@ -5038,8 +4802,8 @@ dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq)
sublen = ltoh16_ua(dptr);
dlen -= sizeof(uint16);
dptr += sizeof(uint16);
- if ((sublen < SDPCM_HDRLEN_RX) ||
- ((num == 0) && (sublen < (2 * SDPCM_HDRLEN_RX)))) {
+ if ((sublen < SDPCM_HDRLEN) ||
+ ((num == 0) && (sublen < (2 * SDPCM_HDRLEN)))) {
DHD_ERROR(("%s: descriptor len %d bad: %d\n",
__FUNCTION__, num, sublen));
pnext = NULL;
@@ -5208,11 +4972,11 @@ dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq)
} else if (SDPCM_GLOMDESC(&dptr[SDPCM_FRAMETAG_LEN])) {
DHD_ERROR(("%s (superframe): got second descriptor?\n", __FUNCTION__));
errcode = -1;
- } else if ((doff < SDPCM_HDRLEN_RX) ||
- (doff > (PKTLEN(osh, pfirst) - SDPCM_HDRLEN_RX))) {
+ } else if ((doff < SDPCM_HDRLEN) ||
+ (doff > (PKTLEN(osh, pfirst) - SDPCM_HDRLEN))) {
DHD_ERROR(("%s (superframe): Bad data offset %d: HW %d pkt %d min %d\n",
__FUNCTION__, doff, sublen, PKTLEN(osh, pfirst),
- SDPCM_HDRLEN_RX));
+ SDPCM_HDRLEN));
errcode = -1;
}
@@ -5225,7 +4989,7 @@ dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq)
}
/* Check window for sanity */
- if ((uint8)(txmax - bus->tx_seq) > 0x40) {
+ if ((uint8)(txmax - bus->tx_seq) > 0x70) {
DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
__FUNCTION__, txmax, bus->tx_seq));
txmax = bus->tx_max;
@@ -5256,7 +5020,7 @@ dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq)
"len/check 0x%04x/0x%04x\n",
__FUNCTION__, num, sublen, check));
errcode = -1;
- } else if ((sublen > dlen) || (sublen < SDPCM_HDRLEN_RX)) {
+ } else if ((sublen > dlen) || (sublen < SDPCM_HDRLEN)) {
DHD_ERROR(("%s (subframe %d): length mismatch: "
"len 0x%04x, expect 0x%04x\n",
__FUNCTION__, num, sublen, dlen));
@@ -5266,9 +5030,9 @@ dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq)
DHD_ERROR(("%s (subframe %d): bad channel %d\n",
__FUNCTION__, num, chan));
errcode = -1;
- } else if ((doff < SDPCM_HDRLEN_RX) || (doff > sublen)) {
+ } else if ((doff < SDPCM_HDRLEN) || (doff > sublen)) {
DHD_ERROR(("%s (subframe %d): Bad data offset %d: HW %d min %d\n",
- __FUNCTION__, num, doff, sublen, SDPCM_HDRLEN_RX));
+ __FUNCTION__, num, doff, sublen, SDPCM_HDRLEN));
errcode = -1;
}
}
@@ -5362,14 +5126,11 @@ dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq)
temp = PKTNEXT(osh, temp);
}
pfirst = temp;
- if (list_tail[ifidx] == NULL) {
+ if (list_tail[ifidx] == NULL)
list_head[ifidx] = ppfirst;
- list_tail[ifidx] = pfirst;
- }
- else {
+ else
PKTSETNEXT(osh, list_tail[ifidx], ppfirst);
- list_tail[ifidx] = pfirst;
- }
+ list_tail[ifidx] = pfirst;
}
num += (uint8)free_buf_count;
@@ -5424,12 +5185,7 @@ dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq)
/* Return TRUE if there may be more frames to read */
static uint
-#ifdef REPEAT_READFRAME
-dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished, bool tx_enable)
-#else
dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished)
-#endif
-
{
osl_t *osh = bus->dhd->osh;
bcmsdh_info_t *sdh = bus->sdh;
@@ -5483,6 +5239,7 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished)
/* Not finished unless we encounter no more frames indication */
*finished = FALSE;
+
#ifdef BCMSPI
/* Get pktlen from gSPI device F0 reg. */
if (bus->bus == SPI_BUS) {
@@ -5520,24 +5277,13 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished)
!bus->rxskip && rxleft && bus->dhd->busstate != DHD_BUS_DOWN;
rxseq++, rxleft--) {
-#ifdef DHDTHREAD
-
- if (
-#ifdef REPEAT_READFRAME
- tx_enable &&
-#endif
- TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL))
- dhdsdio_sendpendctl(bus);
/* tx more to improve rx performance */
- else if (
-#ifdef REPEAT_READFRAME
- tx_enable &&
-#endif
- (bus->clkstate == CLK_AVAIL) && !bus->fcstate &&
- pktq_mlen(&bus->txq, ~bus->flowcontrol) && DATAOK(bus)) {
+ if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL)) {
+ dhdsdio_sendpendctl(bus);
+ } else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate && DATAOK(bus) &&
+ (pktq_mlen(&bus->txq, ~bus->flowcontrol) > bus->txinrx_thres)) {
dhdsdio_sendfromq(bus, dhd_txbound);
}
-#endif /* DHDTHREAD */
/* Handle glomming separately */
if (bus->glom || bus->glomd) {
@@ -5682,7 +5428,7 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished)
dhd_os_sdunlock_rxq(bus->dhd);
/* Now check the header */
- bcopy(rxbuf, bus->rxhdr, SDPCM_HDRLEN_RX);
+ bcopy(rxbuf, bus->rxhdr, SDPCM_HDRLEN);
/* Extract hardware header fields */
len = ltoh16_ua(bus->rxhdr);
@@ -5714,7 +5460,7 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished)
}
/* Validate frame length */
- if (len < SDPCM_HDRLEN_RX) {
+ if (len < SDPCM_HDRLEN) {
DHD_ERROR(("%s (nextlen): HW hdr length invalid: %d\n",
__FUNCTION__, len));
dhd_os_sdlock_rxq(bus->dhd);
@@ -5824,7 +5570,7 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished)
}
/* Check window for sanity */
- if ((uint8)(txmax - bus->tx_seq) > 0x40) {
+ if ((uint8)(txmax - bus->tx_seq) > 0x70) {
#ifdef BCMSPI
if ((bus->bus == SPI_BUS) && !(dstatus & STATUS_F2_RX_READY)) {
DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
@@ -5845,7 +5591,7 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished)
if (DHD_BYTES_ON() && DHD_DATA_ON()) {
prhex("Rx Data", rxbuf, len);
} else if (DHD_HDRS_ON()) {
- prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN_RX);
+ prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN);
}
#endif
@@ -5878,9 +5624,9 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished)
}
/* Validate data offset */
- if ((doff < SDPCM_HDRLEN_RX) || (doff > len)) {
+ if ((doff < SDPCM_HDRLEN) || (doff > len)) {
DHD_ERROR(("%s (nextlen): bad data offset %d: HW len %d min %d\n",
- __FUNCTION__, doff, len, SDPCM_HDRLEN_RX));
+ __FUNCTION__, doff, len, SDPCM_HDRLEN));
dhd_os_sdlock_rxq(bus->dhd);
PKTFREE2();
dhd_os_sdunlock_rxq(bus->dhd);
@@ -5912,7 +5658,7 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished)
#ifdef DHD_DEBUG
if (DHD_BYTES_ON() || DHD_HDRS_ON()) {
- prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN_RX);
+ prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN);
}
#endif
@@ -5936,7 +5682,7 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished)
}
/* Validate frame length */
- if (len < SDPCM_HDRLEN_RX) {
+ if (len < SDPCM_HDRLEN) {
DHD_ERROR(("%s: HW hdr length invalid: %d\n", __FUNCTION__, len));
continue;
}
@@ -5948,9 +5694,9 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished)
txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
/* Validate data offset */
- if ((doff < SDPCM_HDRLEN_RX) || (doff > len)) {
+ if ((doff < SDPCM_HDRLEN) || (doff > len)) {
DHD_ERROR(("%s: Bad data offset %d: HW len %d, min %d seq %d\n",
- __FUNCTION__, doff, len, SDPCM_HDRLEN_RX, seq));
+ __FUNCTION__, doff, len, SDPCM_HDRLEN, seq));
bus->rx_badhdr++;
ASSERT(0);
dhdsdio_rxfail(bus, FALSE, FALSE);
@@ -5991,7 +5737,7 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished)
}
/* Check window for sanity */
- if ((uint8)(txmax - bus->tx_seq) > 0x40) {
+ if ((uint8)(txmax - bus->tx_seq) > 0x70) {
DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
__FUNCTION__, txmax, bus->tx_seq));
txmax = bus->tx_max;
@@ -6091,8 +5837,8 @@ deliver:
}
#endif
PKTSETLEN(osh, pkt, len);
- ASSERT(doff == SDPCM_HDRLEN_RX);
- PKTPULL(osh, pkt, SDPCM_HDRLEN_RX);
+ ASSERT(doff == SDPCM_HDRLEN);
+ PKTPULL(osh, pkt, SDPCM_HDRLEN);
bus->glomd = pkt;
} else {
DHD_ERROR(("%s: glom superframe w/o descriptor!\n", __FUNCTION__));
@@ -6267,10 +6013,6 @@ dhdsdio_hostmail(dhd_bus_t *bus)
return intstatus;
}
-#ifdef REPEAT_READFRAME
-extern uint dhd_dpcpoll;
-#endif
-
static bool
dhdsdio_dpc(dhd_bus_t *bus)
{
@@ -6283,20 +6025,23 @@ dhdsdio_dpc(dhd_bus_t *bus)
uint framecnt = 0; /* Temporary counter of tx/rx frames */
bool rxdone = TRUE; /* Flag for no more read data */
bool resched = FALSE; /* Flag indicating resched wanted */
-
+#if defined(CUSTOMER_HW4)
+ bool is_resched_by_readframe = FALSE;
+#endif
DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+ dhd_os_sdlock(bus->dhd);
+
if (bus->dhd->busstate == DHD_BUS_DOWN) {
DHD_ERROR(("%s: Bus down, ret\n", __FUNCTION__));
bus->intstatus = 0;
+ dhd_os_sdunlock(bus->dhd);
return 0;
}
/* Start with leftover status bits */
intstatus = bus->intstatus;
- dhd_os_sdlock(bus->dhd);
-
if (!SLPAUTO_ENAB(bus) && !KSO_ENAB(bus)) {
DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
goto exit;
@@ -6348,6 +6093,7 @@ dhdsdio_dpc(dhd_bus_t *bus)
}
BUS_WAKE(bus);
+
/* Make sure backplane clock is on */
dhdsdio_clkctl(bus, CLK_AVAIL, TRUE);
if (bus->clkstate != CLK_AVAIL)
@@ -6378,7 +6124,6 @@ dhdsdio_dpc(dhd_bus_t *bus)
intstatus |= newstatus;
bus->intstatus = 0;
-
/* Handle flow-control change: read new state in case our ack
* crossed another change interrupt. If change still set, assume
* FC ON for safety, let next loop through do the debounce.
@@ -6426,6 +6171,11 @@ dhdsdio_dpc(dhd_bus_t *bus)
intstatus &= ~I_CHIPACTIVE;
}
+ if (intstatus & I_HMB_FC_STATE) {
+ DHD_INFO(("Dongle reports HMB_FC_STATE\n"));
+ intstatus &= ~I_HMB_FC_STATE;
+ }
+
/* Ignore frame indications if rxskip is set */
if (bus->rxskip) {
intstatus &= ~FRAME_AVAIL_MASK(bus);
@@ -6433,11 +6183,7 @@ dhdsdio_dpc(dhd_bus_t *bus)
/* On frame indication, read available frames */
if (PKT_AVAILABLE(bus, intstatus)) {
-#ifdef REPEAT_READFRAME
- framecnt = dhdsdio_readframes(bus, rxlimit, &rxdone, true);
-#else
framecnt = dhdsdio_readframes(bus, rxlimit, &rxdone);
-#endif
if (rxdone || bus->rxskip)
intstatus &= ~FRAME_AVAIL_MASK(bus);
rxlimit -= MIN(framecnt, rxlimit);
@@ -6455,10 +6201,14 @@ clkwait:
DHD_INTR(("%s: enable SDIO interrupts, rxdone %d framecnt %d\n",
__FUNCTION__, rxdone, framecnt));
bus->intdis = FALSE;
-#if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
- bcmsdh_oob_intr_set(1);
-#endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */
+#if defined(OOB_INTR_ONLY)
+ bcmsdh_oob_intr_set(bus->sdh, TRUE);
+#endif /* defined(OOB_INTR_ONLY) */
bcmsdh_intr_enable(sdh);
+#ifdef BCMSPI_ANDROID
+ if (*dhd_spi_lockcount == 0)
+ bcmsdh_oob_intr_set(bus->sdh, TRUE);
+#endif /* BCMSPI_ANDROID */
}
#if defined(OOB_INTR_ONLY) && !defined(HW_OOB)
@@ -6478,12 +6228,12 @@ clkwait:
#endif /* defined(OOB_INTR_ONLY) && !defined(HW_OOB) */
#ifdef PROP_TXSTATUS
- dhd_wlfc_trigger_pktcommit(bus->dhd);
+ dhd_wlfc_commit_packets(bus->dhd, (f_commitpkt_t)dhd_bus_txdata, (void *)bus, NULL, FALSE);
#endif
-
if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL))
dhdsdio_sendpendctl(bus);
+
/* Send queued frames (limit 1 if rx may still be pending) */
else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate &&
pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit && DATAOK(bus)) {
@@ -6526,13 +6276,27 @@ clkwait:
}
exit:
-#ifdef REPEAT_READFRAME
+
if (!resched && dhd_dpcpoll) {
- resched = dhdsdio_readframes(bus, dhd_rxbound, &rxdone, true);
- }
+ if (dhdsdio_readframes(bus, dhd_rxbound, &rxdone) != 0)
+ resched = TRUE;
+#if defined(CUSTOMER_HW4)
+ is_resched_by_readframe = TRUE;
#endif
+ }
dhd_os_sdunlock(bus->dhd);
+#if defined(CUSTOMER_HW4)
+ if (bus->dhd->dhd_bug_on) {
+ DHD_ERROR(("%s: resched = %d ctrl_frame_stat = %d intstatus 0x%08x"
+ " ipend = %d pktq_mlen = %d is_resched_by_readframe = %d \n",
+ __FUNCTION__, resched, bus->ctrl_frame_stat,
+ bus->intstatus, bus->ipend,
+ pktq_mlen(&bus->txq, ~bus->flowcontrol), is_resched_by_readframe));
+
+ bus->dhd->dhd_bug_on = FALSE;
+ }
+#endif
return resched;
}
@@ -6590,19 +6354,23 @@ dhdsdio_isr(void *arg)
DHD_ERROR(("dhdsdio_isr() w/o interrupt configured!\n"));
}
+#ifdef BCMSPI_ANDROID
+ bcmsdh_oob_intr_set(bus->sdh, FALSE);
+#endif /* BCMSPI_ANDROID */
bcmsdh_intr_disable(sdh);
bus->intdis = TRUE;
#if defined(SDIO_ISR_THREAD)
DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__));
DHD_OS_WAKE_LOCK(bus->dhd);
- while (dhdsdio_dpc(bus));
+ dhdsdio_dpc(bus);
DHD_OS_WAKE_UNLOCK(bus->dhd);
#else
+
bus->dpc_sched = TRUE;
dhd_sched_dpc(bus->dhd);
-#endif
+#endif /* defined(SDIO_ISR_THREAD) */
}
@@ -6747,7 +6515,7 @@ dhdsdio_pktgen(dhd_bus_t *bus)
#endif
/* Send it */
- if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE, FALSE)) {
+ if (dhdsdio_txpkt(bus, SDPCM_TEST_CHANNEL, &pkt, 1, TRUE) != BCME_OK) {
bus->pktgen_fail++;
if (bus->pktgen_stop && bus->pktgen_stop == bus->pktgen_fail)
bus->pktgen_count = 0;
@@ -6792,7 +6560,7 @@ dhdsdio_sdtest_set(dhd_bus_t *bus, uint count)
*data++ = (uint8)(count >> 24);
/* Send it */
- if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE, FALSE))
+ if (dhdsdio_txpkt(bus, SDPCM_TEST_CHANNEL, &pkt, 1, TRUE) != BCME_OK)
bus->pktgen_fail++;
}
@@ -6837,7 +6605,7 @@ dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq)
case SDPCM_TEST_ECHOREQ:
/* Rx->Tx turnaround ok (even on NDIS w/current implementation) */
*(uint8 *)(PKTDATA(osh, pkt)) = SDPCM_TEST_ECHORSP;
- if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE, FALSE) == 0) {
+ if (dhdsdio_txpkt(bus, SDPCM_TEST_CHANNEL, &pkt, 1, TRUE) == BCME_OK) {
bus->pktgen_sent++;
} else {
bus->pktgen_fail++;
@@ -6909,12 +6677,46 @@ dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq)
}
#endif /* SDTEST */
-extern void
-dhd_disable_intr(dhd_pub_t *dhdp)
+int dhd_bus_oob_intr_register(dhd_pub_t *dhdp)
{
- dhd_bus_t *bus;
- bus = dhdp->bus;
- bcmsdh_intr_disable(bus->sdh);
+ int err = 0;
+
+#if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
+ err = bcmsdh_oob_intr_register(dhdp->bus->sdh, dhdsdio_isr, dhdp->bus);
+#endif
+ return err;
+}
+
+void dhd_bus_oob_intr_unregister(dhd_pub_t *dhdp)
+{
+#if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
+ bcmsdh_oob_intr_unregister(dhdp->bus->sdh);
+#endif
+}
+
+void dhd_bus_oob_intr_set(dhd_pub_t *dhdp, bool enable)
+{
+#if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
+ bcmsdh_oob_intr_set(dhdp->bus->sdh, enable);
+#endif
+}
+
+void dhd_bus_dev_pm_stay_awake(dhd_pub_t *dhdpub)
+{
+ bcmsdh_dev_pm_stay_awake(dhdpub->bus->sdh);
+}
+
+void dhd_bus_dev_pm_relax(dhd_pub_t *dhdpub)
+{
+ bcmsdh_dev_relax(dhdpub->bus->sdh);
+}
+
+bool dhd_bus_dev_pm_enabled(dhd_pub_t *dhdpub)
+{
+ bool enabled = FALSE;
+
+ enabled = bcmsdh_dev_pm_enabled(dhdpub->bus->sdh);
+ return enabled;
}
extern bool
@@ -6929,6 +6731,9 @@ dhd_bus_watchdog(dhd_pub_t *dhdp)
if (bus->dhd->dongle_reset)
return FALSE;
+ if (bus->dhd->hang_was_sent)
+ return FALSE;
+
/* Ignore the timer if simulating bus down */
if (!SLPAUTO_ENAB(bus) && bus->sleeping)
return FALSE;
@@ -6971,7 +6776,6 @@ dhd_bus_watchdog(dhd_pub_t *dhdp)
}
bus->dpc_sched = TRUE;
dhd_sched_dpc(bus->dhd);
-
}
}
@@ -7016,7 +6820,7 @@ dhd_bus_watchdog(dhd_pub_t *dhdp)
else {
bus->idlecount++;
- if (bus->idlecount >= bus->idletime) {
+ if ((bus->idletime > 0) && (bus->idlecount >= bus->idletime)) {
DHD_TIMER(("%s: DHD Idle state!!\n", __FUNCTION__));
if (SLPAUTO_ENAB(bus)) {
if (dhdsdio_bussleep(bus, TRUE) != BCME_BUSY)
@@ -7029,7 +6833,7 @@ dhd_bus_watchdog(dhd_pub_t *dhdp)
}
#else
if ((bus->idletime > 0) && (bus->clkstate == CLK_AVAIL)) {
- if (++bus->idlecount > bus->idletime) {
+ if (++bus->idlecount >= bus->idletime) {
bus->idlecount = 0;
if (bus->activity) {
bus->activity = FALSE;
@@ -7097,7 +6901,7 @@ dhd_bus_console_in(dhd_pub_t *dhdp, uchar *msg, uint msglen)
* sdpcm_sendup (RX) checks for virtual console input.
*/
if ((pkt = PKTGET(bus->dhd->osh, 4 + SDPCM_RESERVE, TRUE)) != NULL)
- dhdsdio_txpkt(bus, pkt, SDPCM_EVENT_CHANNEL, TRUE, FALSE);
+ rv = dhdsdio_txpkt(bus, SDPCM_EVENT_CHANNEL, &pkt, 1, TRUE);
done:
if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
@@ -7164,6 +6968,8 @@ dhdsdio_chipmatch(uint16 chipid)
return TRUE;
if (chipid == BCM43242_CHIP_ID)
return TRUE;
+ if (chipid == BCM43340_CHIP_ID)
+ return TRUE;
if (chipid == BCM43341_CHIP_ID)
return TRUE;
if (chipid == BCM43143_CHIP_ID)
@@ -7178,8 +6984,16 @@ dhdsdio_chipmatch(uint16 chipid)
return TRUE;
if (chipid == BCM4335_CHIP_ID)
return TRUE;
+ if (chipid == BCM4339_CHIP_ID)
+ return TRUE;
+ if (chipid == BCM43349_CHIP_ID)
+ return TRUE;
+ if (chipid == BCM4345_CHIP_ID)
+ return TRUE;
if (chipid == BCM4350_CHIP_ID)
return TRUE;
+ if (chipid == BCM4354_CHIP_ID)
+ return TRUE;
return FALSE;
}
@@ -7189,10 +7003,8 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot,
{
int ret;
dhd_bus_t *bus;
-#ifdef GET_CUSTOM_MAC_ENABLE
- struct ether_addr ea_addr;
-#endif /* GET_CUSTOM_MAC_ENABLE */
+#if defined(MULTIPLE_SUPPLICANT)
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
if (mutex_is_locked(&_dhd_sdio_mutex_lock_) == 0) {
DHD_ERROR(("%s : no mutex held. set lock\n", __FUNCTION__));
@@ -7202,6 +7014,7 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot,
}
mutex_lock(&_dhd_sdio_mutex_lock_);
#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
+#endif
/* Init global variables at run-time, not as part of the declaration.
* This is required to support init/de-init of the driver. Initialization
@@ -7219,12 +7032,12 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot,
sd1idle = TRUE;
dhd_readahead = TRUE;
retrydata = FALSE;
-#ifndef REPEAT_READFRAME
+#if !defined(PLATFORM_MPS) && !defined(CUSTOMER_HW4)
dhd_doflow = FALSE;
#else
dhd_doflow = TRUE;
-#endif /* REPEAT_READFRAME */
- dhd_dongle_memsize = 0;
+#endif /* OEM_ANDROID */
+ dhd_dongle_ramsize = 0;
dhd_txminmax = DHD_TXMINMAX;
#ifdef BCMSPI
@@ -7289,11 +7102,8 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot,
}
if (osh == NULL) {
- /* Ask the OS interface part for an OSL handle */
- if (!(osh = dhd_osl_attach(sdh, DHD_BUS))) {
- DHD_ERROR(("%s: osl_attach failed!\n", __FUNCTION__));
- goto forcereturn;
- }
+ DHD_ERROR(("%s: osh is NULL!\n", __FUNCTION__));
+ goto forcereturn;
}
/* Allocate private bus interface state */
@@ -7305,12 +7115,11 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot,
bus->sdh = sdh;
bus->cl_devid = (uint16)devid;
bus->bus = DHD_BUS;
+ bus->bus_num = bus_no;
+ bus->slot_num = slot;
bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1;
bus->usebufpool = FALSE; /* Use bufpool if allocated, else use locally malloced rxbuf */
- /* attach the common module */
- dhd_common_init(osh);
-
/* attempt to attach to the dongle */
if (!(dhdsdio_probe_attach(bus, osh, sdh, regsva, devid))) {
DHD_ERROR(("%s: dhdsdio_probe_attach failed\n", __FUNCTION__));
@@ -7351,37 +7160,44 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot,
DHD_INFO(("%s: completed!!\n", __FUNCTION__));
-#ifdef GET_CUSTOM_MAC_ENABLE
- /* Read MAC address from external customer place */
- memset(&ea_addr, 0, sizeof(ea_addr));
- ret = dhd_custom_get_mac_address(ea_addr.octet);
- if (!ret) {
- memcpy(bus->dhd->mac.octet, (void *)&ea_addr, ETHER_ADDR_LEN);
- }
-#endif /* GET_CUSTOM_MAC_ENABLE */
-
/* if firmware path present try to download and bring up bus */
+ bus->dhd->hang_report = TRUE;
if (dhd_download_fw_on_driverload) {
if ((ret = dhd_bus_start(bus->dhd)) != 0) {
DHD_ERROR(("%s: dhd_bus_start failed\n", __FUNCTION__));
goto fail;
}
}
+#ifdef CUSTOMER_HW4
+ else {
+ /* Set ramdom MAC address during boot time */
+ get_random_bytes(&bus->dhd->mac.octet[3], 3);
+ /* Adding BRCM OUI */
+ bus->dhd->mac.octet[0] = 0;
+ bus->dhd->mac.octet[1] = 0x90;
+ bus->dhd->mac.octet[2] = 0x4C;
+ }
+#endif /* CUSTOMER_HW4 */
/* Ok, have the per-port tell the stack we're open for business */
- if (dhd_net_attach(bus->dhd, 0) != 0) {
+ if (dhd_register_if(bus->dhd, 0, TRUE) != 0) {
DHD_ERROR(("%s: Net attach failed!!\n", __FUNCTION__));
goto fail;
}
#if defined(CUSTOMER_HW4) && defined(BCMHOST_XTAL_PU_TIME_MOD)
bcmsdh_reg_write(bus->sdh, 0x18000620, 2, 11);
+#ifdef BCM4330_CHIP
+ bcmsdh_reg_write(bus->sdh, 0x18000628, 4, 0x0000F801);
+#else
bcmsdh_reg_write(bus->sdh, 0x18000628, 4, 0x00F80001);
-#endif
-
+#endif /* BCM4330_CHIP */
+#endif /* defined(CUSTOMER_HW4) && defined(BCMHOST_XTAL_PU_TIME_MOD */
+#if defined(MULTIPLE_SUPPLICANT)
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
mutex_unlock(&_dhd_sdio_mutex_lock_);
DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__));
#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
+#endif
return bus;
@@ -7389,10 +7205,12 @@ fail:
dhdsdio_release(bus, osh);
forcereturn:
+#if defined(MULTIPLE_SUPPLICANT)
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
mutex_unlock(&_dhd_sdio_mutex_lock_);
DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__));
#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
+#endif
return NULL;
}
@@ -7692,13 +7510,7 @@ dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva,
DHD_ERROR(("%s: FAILED to return to SI_ENUM_BASE\n", __FUNCTION__));
}
-#ifdef DHD_DEBUG
- DHD_ERROR(("F1 signature read @0x18000000=0x%4x\n",
- bcmsdh_reg_read(bus->sdh, SI_ENUM_BASE, 4)));
-
-#endif /* DHD_DEBUG */
-
-#ifndef BCMSPI /* wake-wlan in gSPI will bring up the htavail/alpavail clocks. */
+#ifndef BCMSPI /* wake-wlan in gSPI will bring up the htavail/alpavail clocks. */
/* Force PLL off until si_attach() programs PLL control regs */
@@ -7773,6 +7585,11 @@ dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva,
goto fail;
}
+#ifdef DHD_DEBUG
+ DHD_ERROR(("F1 signature OK, socitype:0x%x chip:0x%4x rev:0x%x pkg:0x%x\n",
+ bus->sih->socitype, bus->sih->chip, bus->sih->chiprev, bus->sih->chippkg));
+#endif /* DHD_DEBUG */
+
#ifdef REGON_BP_HANG_FIX
/* WAR - for 43241 B0-B1-B2. B3 onwards do not need this */
if (((uint16)bus->sih->chip == BCM4324_CHIP_ID) && (bus->sih->chiprev < 3))
@@ -7823,14 +7640,20 @@ dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva,
/* also populate base address */
switch ((uint16)bus->sih->chip) {
case BCM4335_CHIP_ID:
+ case BCM4339_CHIP_ID:
+ case BCM43349_CHIP_ID:
bus->dongle_ram_base = CR4_4335_RAM_BASE;
break;
case BCM4350_CHIP_ID:
+ case BCM4354_CHIP_ID:
bus->dongle_ram_base = CR4_4350_RAM_BASE;
break;
case BCM4360_CHIP_ID:
bus->dongle_ram_base = CR4_4360_RAM_BASE;
break;
+ case BCM4345_CHIP_ID:
+ bus->dongle_ram_base = CR4_4345_RAM_BASE;
+ break;
default:
bus->dongle_ram_base = 0;
DHD_ERROR(("%s: WARNING: Using default ram base at 0x%x\n",
@@ -7838,8 +7661,8 @@ dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva,
}
}
bus->ramsize = bus->orig_ramsize;
- if (dhd_dongle_memsize)
- dhd_dongle_setmemsize(bus, dhd_dongle_memsize);
+ if (dhd_dongle_ramsize)
+ dhd_dongle_setramsize(bus, dhd_dongle_ramsize);
DHD_ERROR(("DHD: dongle ram size is set to %d(orig %d) at 0x%x\n",
bus->ramsize, bus->orig_ramsize, bus->dongle_ram_base));
@@ -7883,12 +7706,8 @@ dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva,
if ((bus->poll = (bool)dhd_poll))
bus->pollrate = 1;
-#ifdef BCMSDIOH_TXGLOM
- /* Setting default Glom mode */
- bus->glom_mode = bcmsdh_set_mode(bus->sdh, SDPCM_DEFGLOM_MODE);
/* Setting default Glom size */
- bus->glomsize = SDPCM_DEFGLOM_SIZE;
-#endif
+ bus->txglomsize = SDPCM_DEFGLOM_SIZE;
return TRUE;
@@ -7906,20 +7725,20 @@ dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh)
DHD_TRACE(("%s: Enter\n", __FUNCTION__));
if (bus->dhd->maxctl) {
- bus->rxblen = ROUNDUP((bus->dhd->maxctl + SDPCM_HDRLEN), ALIGNMENT) + DHD_SDALIGN;
- if (!(bus->rxbuf = DHD_OS_PREALLOC(osh, DHD_PREALLOC_RXBUF, bus->rxblen))) {
+ bus->rxblen = ROUNDUP((bus->dhd->maxctl+SDPCM_HDRLEN), ALIGNMENT) + DHD_SDALIGN;
+ if (!(bus->rxbuf = DHD_OS_PREALLOC(bus->dhd, DHD_PREALLOC_RXBUF, bus->rxblen))) {
DHD_ERROR(("%s: MALLOC of %d-byte rxbuf failed\n",
__FUNCTION__, bus->rxblen));
goto fail;
}
}
/* Allocate buffer to receive glomed packet */
- if (!(bus->databuf = DHD_OS_PREALLOC(osh, DHD_PREALLOC_DATABUF, MAX_DATA_BUF))) {
+ if (!(bus->databuf = DHD_OS_PREALLOC(bus->dhd, DHD_PREALLOC_DATABUF, MAX_DATA_BUF))) {
DHD_ERROR(("%s: MALLOC of %d-byte databuf failed\n",
__FUNCTION__, MAX_DATA_BUF));
/* release rxbuf which was already located as above */
if (!bus->rxblen)
- DHD_OS_PREFREE(osh, bus->rxbuf, bus->rxblen);
+ DHD_OS_PREFREE(bus->dhd, bus->rxbuf, bus->rxblen);
goto fail;
}
@@ -7942,6 +7761,8 @@ dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh)
DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+ bus->_srenab = FALSE;
+
#ifdef SDTEST
dhdsdio_pktgen_init(bus);
#endif /* SDTEST */
@@ -7996,11 +7817,23 @@ dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh)
DHD_INFO(("%s: Initial value for %s is %d\n",
__FUNCTION__, "sd_blocksize", bus->blocksize));
- if (bus->sih->chip == BCM4335_CHIP_ID)
- dhd_overflow_war(bus);
+ dhdsdio_tune_fifoparam(bus);
}
bus->roundup = MIN(max_roundup, bus->blocksize);
+ if (bus->pad_pkt)
+ PKTFREE(osh, bus->pad_pkt, FALSE);
+ bus->pad_pkt = PKTGET(osh, SDIO_MAX_BLOCK_SIZE, FALSE);
+ if (bus->pad_pkt == NULL)
+ DHD_ERROR(("failed to allocate padding packet\n"));
+ else {
+ int alignment_offset = 0;
+ uintptr pktprt = (uintptr)PKTDATA(osh, bus->pad_pkt);
+ if (!(pktprt&1) && (pktprt = (pktprt % DHD_SDALIGN)))
+ PKTPUSH(osh, bus->pad_pkt, alignment_offset);
+ PKTSETNEXT(osh, bus->pad_pkt, NULL);
+ }
+
/* Query if bus module supports packet chaining, default to use if supported */
if (bcmsdh_iovar_op(sdh, "sd_rxchain", NULL, 0,
&bus->sd_rxchain, sizeof(int32), FALSE) != BCME_OK) {
@@ -8010,44 +7843,55 @@ dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh)
__FUNCTION__, (bus->sd_rxchain ? "supports" : "does not support")));
}
bus->use_rxchain = (bool)bus->sd_rxchain;
+ bus->txinrx_thres = CUSTOM_TXINRX_THRES;
return TRUE;
}
-bool
+int
dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh,
char *pfw_path, char *pnv_path)
{
- bool ret;
+ int ret;
+
bus->fw_path = pfw_path;
bus->nv_path = pnv_path;
ret = dhdsdio_download_firmware(bus, osh, bus->sdh);
-#ifdef BCMSPI
-#ifdef GSPI_DWORD_MODE
+#if defined(BCMSPI) && defined(GSPI_DWORD_MODE)
/* Enable the dwordmode in gSPI before first F2 transaction */
if ((bus->sih->chip == BCM4329_CHIP_ID) && (bus->sih->chiprev > 1)) {
bcmsdh_dwordmode(bus->sdh, TRUE);
bus->dwordmode = TRUE;
}
-#endif /* GSPI_DWORD_MODE */
-#endif /* BCMSPI */
+#endif /* defined(BCMSPI) && defined(GSPI_DWORD_MODE) */
return ret;
}
-static bool
+static int
dhdsdio_download_firmware(struct dhd_bus *bus, osl_t *osh, void *sdh)
{
- bool ret;
+ int ret;
+
+#if defined(SUPPORT_MULTIPLE_REVISION)
+ if (concate_revision(bus, bus->fw_path, sizeof(bus->fw_path),
+ bus->nv_path, sizeof(bus->nv_path)) != 0) {
+ DHD_ERROR(("%s: fail to concatnate revison \n",
+ __FUNCTION__));
+ return BCME_BADARG;
+ }
+#endif /* SUPPORT_MULTIPLE_REVISION */
+ DHD_TRACE_HW4(("%s: firmware path=%s, nvram path=%s\n",
+ __FUNCTION__, bus->fw_path, bus->nv_path));
DHD_OS_WAKE_LOCK(bus->dhd);
/* Download the firmware */
dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
- ret = _dhdsdio_download_firmware(bus) == 0;
+ ret = _dhdsdio_download_firmware(bus);
dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
@@ -8087,12 +7931,12 @@ dhdsdio_release(dhd_bus_t *bus, osl_t *osh)
MFREE(osh, bus->console.buf, bus->console.bufsize);
#endif
+ if (bus->pad_pkt)
+ PKTFREE(osh, bus->pad_pkt, FALSE);
+
MFREE(osh, bus, sizeof(dhd_bus_t));
}
- if (osh)
- dhd_osl_detach(osh);
-
DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
}
@@ -8164,6 +8008,7 @@ dhdsdio_disconnect(void *ptr)
DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+#if defined(MULTIPLE_SUPPLICANT)
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
if (mutex_is_locked(&_dhd_sdio_mutex_lock_) == 0) {
DHD_ERROR(("%s : no mutex held. set lock\n", __FUNCTION__));
@@ -8173,6 +8018,7 @@ dhdsdio_disconnect(void *ptr)
}
mutex_lock(&_dhd_sdio_mutex_lock_);
#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
+#endif
if (bus) {
@@ -8180,15 +8026,39 @@ dhdsdio_disconnect(void *ptr)
dhdsdio_release(bus, bus->dhd->osh);
}
+#if defined(MULTIPLE_SUPPLICANT)
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
mutex_unlock(&_dhd_sdio_mutex_lock_);
DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__));
#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
+#endif /* LINUX */
DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
}
+static int
+dhdsdio_suspend(void *context)
+{
+ int ret = 0;
+
+ dhd_bus_t *bus = (dhd_bus_t*)context;
+ ret = dhd_os_check_wakelock(bus->dhd);
+ return ret;
+}
+
+static int
+dhdsdio_resume(void *context)
+{
+#if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
+ dhd_bus_t *bus = (dhd_bus_t*)context;
+
+ if (dhd_os_check_if_up(bus->dhd))
+ bcmsdh_oob_intr_set(bus->sdh, TRUE);
+#endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */
+ return 0;
+}
+
/* Register/Unregister functions are called by the main DHD entry
* point (e.g. module insertion) to link with the bus driver, in
@@ -8197,7 +8067,9 @@ dhdsdio_disconnect(void *ptr)
static bcmsdh_driver_t dhd_sdio = {
dhdsdio_probe,
- dhdsdio_disconnect
+ dhdsdio_disconnect,
+ dhdsdio_suspend,
+ dhdsdio_resume
};
int
@@ -8568,29 +8440,48 @@ dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf
static int
dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes,
- void *pkt, bcmsdh_cmplt_fn_t complete, void *handle)
+ void *pkt, bcmsdh_cmplt_fn_t complete, void *handle, int max_retry)
{
- if (!KSO_ENAB(bus)) {
- DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
- return BCME_NODEVICE;
- }
+ int ret;
+ int i = 0;
+ int retries = 0;
+ bcmsdh_info_t *sdh;
- return (bcmsdh_send_buf(bus->sdh, addr, fn, flags, buf, nbytes, pkt, complete, handle));
-}
+ sdh = bus->sdh;
+ do {
+ ret = bcmsdh_send_buf(bus->sdh, addr, fn, flags, buf, nbytes,
+ pkt, complete, handle);
-#ifdef BCMSDIOH_TXGLOM
-static void
-dhd_bcmsdh_glom_post(dhd_bus_t *bus, uint8 *frame, void *pkt, uint len)
-{
- bcmsdh_glom_post(bus->sdh, frame, pkt, len);
-}
+ bus->f2txdata++;
+ ASSERT(ret != BCME_PENDING);
-static void
-dhd_bcmsdh_glom_clear(dhd_bus_t *bus)
-{
- bcmsdh_glom_clear(bus->sdh);
+ if (ret == BCME_NODEVICE) {
+ DHD_ERROR(("%s: Device asleep already\n", __FUNCTION__));
+ } else if (ret < 0) {
+ /* On failure, abort the command and terminate the frame */
+ DHD_ERROR(("%s: sdio error %d, abort command and terminate frame.\n",
+ __FUNCTION__, ret));
+ bus->tx_sderrs++;
+ bus->f1regdata++;
+ bus->dhd->tx_errors++;
+ bcmsdh_abort(sdh, SDIO_FUNC_2);
+ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
+ SFC_WF_TERM, NULL);
+ for (i = 0; i < READ_FRM_CNT_RETRIES; i++) {
+ uint8 hi, lo;
+ hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WFRAMEBCHI,
+ NULL);
+ lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WFRAMEBCLO,
+ NULL);
+ bus->f1regdata += 2;
+ if ((hi == 0) && (lo == 0))
+ break;
+ }
+ }
+ } while ((ret < 0) && retrydata && ++retries < max_retry);
+
+ return ret;
}
-#endif
uint
dhd_bus_chip(struct dhd_bus *bus)
@@ -8599,6 +8490,14 @@ dhd_bus_chip(struct dhd_bus *bus)
return bus->sih->chip;
}
+uint
+dhd_bus_chiprev(struct dhd_bus *bus)
+{
+ ASSERT(bus);
+ ASSERT(bus->sih != NULL);
+ return bus->sih->chiprev;
+}
+
void *
dhd_bus_pub(struct dhd_bus *bus)
{
@@ -8606,15 +8505,15 @@ dhd_bus_pub(struct dhd_bus *bus)
}
void *
-dhd_bus_txq(struct dhd_bus *bus)
+dhd_bus_sih(struct dhd_bus *bus)
{
- return &bus->txq;
+ return (void *)bus->sih;
}
-uint
-dhd_bus_hdrlen(struct dhd_bus *bus)
+void *
+dhd_bus_txq(struct dhd_bus *bus)
{
- return SDPCM_HDRLEN;
+ return &bus->txq;
}
int
@@ -8639,7 +8538,9 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag)
#if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
/* Clean up any pending IRQ */
- bcmsdh_set_irq(FALSE);
+ dhd_enable_oob_intr(bus, FALSE);
+ bcmsdh_oob_intr_set(bus->sdh, FALSE);
+ bcmsdh_oob_intr_unregister(bus->sdh);
#endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */
/* Clean tx/rx buffer pointers, detach from the dongle */
@@ -8647,9 +8548,7 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag)
bus->dhd->dongle_reset = TRUE;
bus->dhd->up = FALSE;
-#ifdef BCMSDIOH_TXGLOM
dhd_txglom_enable(dhdp, FALSE);
-#endif
dhd_os_sdunlock(dhdp);
DHD_TRACE(("%s: WLAN OFF DONE\n", __FUNCTION__));
@@ -8663,28 +8562,26 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag)
if (bus->dhd->dongle_reset) {
/* Turn on WLAN */
-#ifdef DHDTHREAD
dhd_os_sdlock(dhdp);
-#endif /* DHDTHREAD */
/* Reset SD client */
bcmsdh_reset(bus->sdh);
/* Attempt to re-attach & download */
if (dhdsdio_probe_attach(bus, bus->dhd->osh, bus->sdh,
- (uint32 *)SI_ENUM_BASE,
- bus->cl_devid)) {
+ (uint32 *)SI_ENUM_BASE,
+ bus->cl_devid)) {
/* Attempt to download binary to the dongle */
if (dhdsdio_probe_init(bus, bus->dhd->osh, bus->sdh) &&
- dhdsdio_download_firmware(bus, bus->dhd->osh, bus->sdh)) {
+ dhdsdio_download_firmware(bus, bus->dhd->osh, bus->sdh) >= 0) {
/* Re-init bus, enable F2 transfer */
bcmerror = dhd_bus_init((dhd_pub_t *) bus->dhd, FALSE);
if (bcmerror == BCME_OK) {
#if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
- bcmsdh_set_irq(TRUE);
-#ifndef BCMSPI_ANDROID
dhd_enable_oob_intr(bus, TRUE);
-#endif /* !BCMSPI_ANDROID */
+ bcmsdh_oob_intr_register(bus->sdh,
+ dhdsdio_isr, bus);
+ bcmsdh_oob_intr_set(bus->sdh, TRUE);
#endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */
bus->dhd->dongle_reset = FALSE;
@@ -8695,12 +8592,7 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag)
dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF);
#endif
dhd_os_wd_timer(dhdp, dhd_watchdog_ms);
-#ifdef BCMSDIOH_TXGLOM
- if ((dhdp->busstate == DHD_BUS_DATA) &&
- bcmsdh_glom_enabled()) {
- dhd_txglom_enable(dhdp, TRUE);
- }
-#endif /* BCMSDIOH_TXGLOM */
+
DHD_TRACE(("%s: WLAN ON DONE\n", __FUNCTION__));
} else {
dhd_bus_stop(bus, FALSE);
@@ -8712,15 +8604,13 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag)
} else
bcmerror = BCME_SDIO_ERROR;
-#ifdef DHDTHREAD
dhd_os_sdunlock(dhdp);
-#endif /* DHDTHREAD */
} else {
bcmerror = BCME_SDIO_ERROR;
DHD_INFO(("%s called when dongle is not in reset\n",
__FUNCTION__));
DHD_INFO(("Will call dhd_bus_start instead\n"));
- sdioh_start(NULL, 1);
+ dhd_bus_resume(dhdp, 1);
if ((bcmerror = dhd_bus_start(dhdp)) != 0)
DHD_ERROR(("%s: dhd_bus_start fail with %d\n",
__FUNCTION__, bcmerror));
@@ -8729,6 +8619,16 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag)
return bcmerror;
}
+int dhd_bus_suspend(dhd_pub_t *dhdpub)
+{
+ return bcmsdh_stop(dhdpub->bus->sdh);
+}
+
+int dhd_bus_resume(dhd_pub_t *dhdpub, int stage)
+{
+ return bcmsdh_start(dhdpub->bus->sdh, stage);
+}
+
/* Get Chip ID version */
uint dhd_bus_chip_id(dhd_pub_t *dhdp)
{
@@ -8736,6 +8636,31 @@ uint dhd_bus_chip_id(dhd_pub_t *dhdp)
return bus->sih->chip;
}
+
+/* Get Chip Rev ID version */
+uint dhd_bus_chiprev_id(dhd_pub_t *dhdp)
+{
+ dhd_bus_t *bus = dhdp->bus;
+
+ return bus->sih->chiprev;
+}
+
+/* Get Chip Pkg ID version */
+uint dhd_bus_chippkg_id(dhd_pub_t *dhdp)
+{
+ dhd_bus_t *bus = dhdp->bus;
+
+ return bus->sih->chippkg;
+}
+
+int dhd_bus_get_ids(struct dhd_bus *bus, uint32 *bus_type, uint32 *bus_num, uint32 *slot_num)
+{
+ *bus_type = bus->bus;
+ *bus_num = bus->bus_num;
+ *slot_num = bus->slot_num;
+ return 0;
+}
+
int
dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint size)
{
@@ -8744,9 +8669,26 @@ dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint si
bus = dhdp->bus;
return dhdsdio_membytes(bus, set, address, data, size);
}
-#if defined(CUSTOMER_HW4) && defined(SUPPORT_MULTIPLE_REVISION)
+#if defined(SUPPORT_MULTIPLE_REVISION)
+/* Just print chip revision for BCM4330 */
+static int
+concate_revision_bcm4330(dhd_bus_t *bus)
+{
+ uint chipver;
+ chipver = bus->sih->chiprev;
+
+ if (chipver == 3)
+ DHD_ERROR(("---- CHIP bcm4330 B1 ----\n"));
+ else if (chipver == 4)
+ DHD_ERROR(("---- CHIP bcm4330 B2 ----\n"));
+ else
+ DHD_ERROR(("----- Invalid chip version -----\n"));
+ return 0;
+}
+
static int
-concate_revision_bcm4334(dhd_bus_t *bus, char *path, int path_len)
+concate_revision_bcm4334(dhd_bus_t *bus,
+ char *fw_path, int fw_path_len, char *nv_path, int nv_path_len)
{
#define REV_ID_ADDR 0x1E008F90
#define BCM4334_B1_UNIQUE 0x30312E36
@@ -8754,7 +8696,11 @@ concate_revision_bcm4334(dhd_bus_t *bus, char *path, int path_len)
uint chipver;
uint32 unique_id;
uint8 data[4];
- char chipver_tag[4] = "_b?";
+#if defined(SUPPORT_MULTIPLE_CHIPS)
+ char chipver_tag[10] = "_4334";
+#else
+ char chipver_tag[4] = "";
+#endif /* defined(SUPPORT_MULTIPLE_CHIPS) */
DHD_TRACE(("%s: BCM4334 Multiple Revision Check\n", __FUNCTION__));
if (bus->sih->chip != BCM4334_CHIP_ID) {
@@ -8771,19 +8717,24 @@ concate_revision_bcm4334(dhd_bus_t *bus, char *path, int path_len)
DHD_ERROR(("CHIP VER = [0x%x]\n", chipver));
if (chipver == 1) {
DHD_ERROR(("----- CHIP bcm4334_B0 -----\n"));
- strcpy(chipver_tag, "_b0");
+ strcat(chipver_tag, "_b0");
} else if (chipver == 2) {
DHD_ERROR(("----- CHIP bcm4334_B1 -----\n"));
- strcpy(chipver_tag, "_b1");
+ strcat(chipver_tag, "_b1");
} else if (chipver == 3) {
DHD_ERROR(("----- CHIP bcm4334_B2 -----\n"));
- strcpy(chipver_tag, "_b2");
+ strcat(chipver_tag, "_b2");
}
else {
DHD_ERROR(("----- Invalid chip version -----\n"));
return -1;
}
- strcat(path, chipver_tag);
+
+ strcat(fw_path, chipver_tag);
+#if defined(SUPPORT_MULTIPLE_CHIPS)
+ strcat(nv_path, chipver_tag);
+#endif /* defined(SUPPORT_MULTIPLE_CHIPS) */
+
#undef REV_ID_ADDR
#undef BCM4334_B1_UNIQUE
return 0;
@@ -8795,7 +8746,11 @@ concate_revision_bcm4335
{
uint chipver;
+#if defined(SUPPORT_MULTIPLE_CHIPS)
+ char chipver_tag[10] = "_4335";
+#else
char chipver_tag[4] = {0, };
+#endif /* defined(SUPPORT_MULTIPLE_CHIPS) */
DHD_TRACE(("%s: BCM4335 Multiple Revision Check\n", __FUNCTION__));
if (bus->sih->chip != BCM4335_CHIP_ID) {
@@ -8806,32 +8761,350 @@ concate_revision_bcm4335
DHD_ERROR(("CHIP VER = [0x%x]\n", chipver));
if (chipver == 0x0) {
DHD_ERROR(("----- CHIP bcm4335_A0 -----\n"));
- strcpy(chipver_tag, "_a0");
+ strcat(chipver_tag, "_a0");
} else if (chipver == 0x1) {
DHD_ERROR(("----- CHIP bcm4335_B0 -----\n"));
+#if defined(SUPPORT_MULTIPLE_CHIPS)
+ strcat(chipver_tag, "_b0");
+#endif /* defined(SUPPORT_MULTIPLE_CHIPS) */
+ }
+
+ strcat(fw_path, chipver_tag);
+ strcat(nv_path, chipver_tag);
+ return 0;
+}
+
+static int
+concate_revision_bcm4339
+ (dhd_bus_t *bus, char *fw_path, int fw_path_len, char *nv_path, int nv_path_len)
+{
+
+ uint chipver;
+#if defined(SUPPORT_MULTIPLE_CHIPS)
+ char chipver_tag[10] = "_4339";
+#else
+ char chipver_tag[4] = {0, };
+#endif /* defined(SUPPORT_MULTIPLE_CHIPS) */
+
+ DHD_TRACE(("%s: BCM4339 Multiple Revision Check\n", __FUNCTION__));
+ if (bus->sih->chip != BCM4339_CHIP_ID) {
+ DHD_ERROR(("%s:Chip is not BCM4339\n", __FUNCTION__));
+ return -1;
+ }
+ chipver = bus->sih->chiprev;
+ DHD_ERROR(("CHIP VER = [0x%x]\n", chipver));
+ if (chipver == 0x1) {
+ DHD_ERROR(("----- CHIP bcm4339_A0 -----\n"));
+ strcat(chipver_tag, "_a0");
+ } else {
+ DHD_ERROR(("----- CHIP bcm4339 unknown revision %d -----\n",
+ chipver));
+ }
+
+ strcat(fw_path, chipver_tag);
+ strcat(nv_path, chipver_tag);
+ return 0;
+}
+
+static int
+concate_revision_bcm43349
+ (dhd_bus_t *bus, char *fw_path, int fw_path_len, char *nv_path, int nv_path_len)
+{
+
+ uint chipver;
+#if defined(SUPPORT_MULTIPLE_CHIPS)
+ char chipver_tag[10] = "_43349";
+#else
+ char chipver_tag[4] = {0, };
+#endif /* defined(SUPPORT_MULTIPLE_CHIPS) */
+
+ DHD_TRACE(("%s: BCM43349 Multiple Revision Check\n", __FUNCTION__));
+ if (bus->sih->chip != BCM43349_CHIP_ID) {
+ DHD_ERROR(("%s:Chip is not BCM43349\n", __FUNCTION__));
+ return -1;
+ }
+ chipver = bus->sih->chiprev;
+ DHD_ERROR(("CHIP VER = [0x%x]\n", chipver));
+ if (chipver == 0x1) {
+ DHD_ERROR(("----- CHIP bcm43349_A0 -----\n"));
+ strcat(chipver_tag, "_a0");
+ } else {
+ DHD_ERROR(("----- CHIP bcm43349 unknown revision %d -----\n",
+ chipver));
+ }
+
+ strcat(fw_path, chipver_tag);
+ strcat(nv_path, chipver_tag);
+ return 0;
+}
+
+static int concate_revision_bcm43241(dhd_bus_t *bus,
+ char *fw_path, int fw_path_len, char *nv_path, int nv_path_len)
+{
+ uint32 chip_id, chip_ver;
+#if defined(SUPPORT_MULTIPLE_CHIPS)
+ char chipver_tag[10] = "_43241";
+#else
+ char chipver_tag[4] = {0, };
+#endif /* defined(SUPPORT_MULTIPLE_CHIPS) */
+
+ DHD_TRACE(("%s: BCM43241 Multiple Revision Check\n", __FUNCTION__));
+
+ chip_id = bus->sih->chip;
+ chip_ver = bus->sih->chiprev;
+
+ if (chip_ver == 2) {
+ DHD_ERROR(("----- CHIP bcm43241_B0 -----\n"));
+ strcat(chipver_tag, "_b0");
+ } else if (chip_ver == 5) {
+ DHD_ERROR(("----- CHIP bcm43241_B4 -----\n"));
+ strcat(chipver_tag, "_b4");
+ } else {
+ DHD_ERROR(("----- Invalid chip version -----\n"));
+ return -1;
}
+
strcat(fw_path, chipver_tag);
strcat(nv_path, chipver_tag);
+ return 0;
+}
+
+static int concate_revision_bcm4350(dhd_bus_t *bus,
+ char *fw_path, int fw_path_len, char *nv_path, int nv_path_len)
+{
+ uint32 chip_id, chip_ver;
+#if defined(SUPPORT_MULTIPLE_CHIPS)
+ char chipver_tag[10] = {0, };
+#else
+ char chipver_tag[4] = {0, };
+#endif /* defined(SUPPORT_MULTIPLE_CHIPS) */
+ chip_id = bus->sih->chip;
+ chip_ver = bus->sih->chiprev;
+
+#if defined(SUPPORT_MULTIPLE_CHIPS)
+ if (chip_ver == 3)
+ strcat(chipver_tag, "_4354");
+ else
+ strcat(chipver_tag, "_4350");
+#endif
+
+ if (chip_ver == 3) {
+ DHD_ERROR(("----- CHIP 4354 A0 -----\n"));
+ strcat(chipver_tag, "_a0");
+ } else {
+ DHD_ERROR(("----- Unknown chip version, ver=%x -----\n", chip_ver));
+ }
+ strcat(fw_path, chipver_tag);
+ strcat(nv_path, chipver_tag);
return 0;
+}
+
+static int concate_revision_bcm4354(dhd_bus_t *bus,
+ char *fw_path, int fw_path_len, char *nv_path, int nv_path_len)
+{
+ uint32 chip_id, chip_ver;
+#if defined(SUPPORT_MULTIPLE_CHIPS)
+ char chipver_tag[10] = "_4354";
+#else
+#if !defined(CUSTOMER_HW4)
+ char chipver_tag[4] = {0, };
+#endif /* !CUSTOMER_HW4 */
+#endif /* SUPPORT_MULTIPLE_CHIPS */
+ chip_id = bus->sih->chip;
+ chip_ver = bus->sih->chiprev;
+#if !defined(SUPPORT_MULTIPLE_CHIPS) && defined(CUSTOMER_HW4)
+ DHD_INFO(("----- CHIP 4354, ver=%x -----\n", chip_ver));
+#else
+ if (chip_ver == 1) {
+ DHD_ERROR(("----- CHIP 4354 A1 -----\n"));
+ strcat(chipver_tag, "_a1");
+ } else {
+ DHD_ERROR(("----- Unknown chip version, ver=%x -----\n", chip_ver));
+ }
+
+ strcat(fw_path, chipver_tag);
+ strcat(nv_path, chipver_tag);
+#endif /* !SUPPORT_MULTIPLE_CHIPS && CUSTOMER_HW4 */
+
+ return 0;
}
+
int
concate_revision(dhd_bus_t *bus, char *fw_path, int fw_path_len, char *nv_path, int nv_path_len)
{
+ int res = 0;
+
if (!bus || !bus->sih) {
DHD_ERROR(("%s:Bus is Invalid\n", __FUNCTION__));
return -1;
}
+
+#if defined(PLATFORM_MPS)
+/* get the base name (prefix) for firmware & nvram from the platform */
+ wifi_get_fw_nv_path(fw_path, nv_path);
+#endif
+
switch (bus->sih->chip) {
- case BCM4334_CHIP_ID:
- return concate_revision_bcm4334(bus, fw_path, fw_path_len);
- case BCM4335_CHIP_ID:
- return concate_revision_bcm4335(bus, fw_path, fw_path_len,
- nv_path, nv_path_len);
+ case BCM4330_CHIP_ID:
+ res = concate_revision_bcm4330(bus);
+ break;
+ case BCM4334_CHIP_ID:
+ res = concate_revision_bcm4334(bus, fw_path, fw_path_len,
+ nv_path, nv_path_len);
+ break;
+ case BCM4335_CHIP_ID:
+ res = concate_revision_bcm4335(bus, fw_path, fw_path_len,
+ nv_path, nv_path_len);
+ break;
+ case BCM4339_CHIP_ID:
+ res = concate_revision_bcm4339(bus, fw_path, fw_path_len,
+ nv_path, nv_path_len);
+ break;
+ case BCM43349_CHIP_ID:
+ res = concate_revision_bcm43349(bus, fw_path, fw_path_len,
+ nv_path, nv_path_len);
+ break;
+ case BCM4324_CHIP_ID:
+ res = concate_revision_bcm43241(bus, fw_path, fw_path_len, nv_path, nv_path_len);
+ break;
+ case BCM4350_CHIP_ID:
+ res = concate_revision_bcm4350(bus, fw_path, fw_path_len, nv_path, nv_path_len);
+ break;
+ case BCM4354_CHIP_ID:
+ res = concate_revision_bcm4354(bus, fw_path, fw_path_len, nv_path, nv_path_len);
+ break;
+
+
+ default:
+ DHD_ERROR(("REVISION SPECIFIC feature is not required\n"));
+ return res;
}
- DHD_ERROR(("REVISION SPECIFIC feature is not required\n"));
- return 0;
+ if (res == 0) {
+ }
+ return res;
+}
+#endif /* SUPPORT_MULTIPLE_REVISION */
+
+
+void
+dhd_bus_update_fw_nv_path(struct dhd_bus *bus, char *pfw_path, char *pnv_path)
+{
+ bus->fw_path = pfw_path;
+ bus->nv_path = pnv_path;
+}
+
+int
+dhd_enableOOB(dhd_pub_t *dhd, bool sleep)
+{
+ dhd_bus_t *bus = dhd->bus;
+ sdpcmd_regs_t *regs = bus->regs;
+ uint retries = 0;
+
+ if (sleep) {
+ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
+ /* Tell device to start using OOB wakeup */
+ W_SDREG(SMB_USE_OOB, &regs->tosbmailbox, retries);
+ if (retries > retry_limit) {
+ DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
+ return BCME_BUSY;
+ }
+ /* Turn off our contribution to the HT clock request */
+ dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
+ } else {
+ /* Make sure the controller has the bus up */
+ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
+
+ /* Send misc interrupt to indicate OOB not needed */
+ W_SDREG(0, &regs->tosbmailboxdata, retries);
+ if (retries <= retry_limit)
+ W_SDREG(SMB_DEV_INT, &regs->tosbmailbox, retries);
+
+ if (retries > retry_limit)
+ DHD_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n"));
+
+ /* Make sure we have SD bus access */
+ dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
+ }
+ return BCME_OK;
+}
+
+void
+dhd_bus_pktq_flush(dhd_pub_t *dhdp)
+{
+ dhd_bus_t *bus = dhdp->bus;
+ bool wlfc_enabled = FALSE;
+
+#ifdef PROP_TXSTATUS
+ wlfc_enabled = (dhd_wlfc_cleanup_txq(dhdp, NULL, 0) != WLFC_UNSUPPORTED);
+#endif
+ if (!wlfc_enabled) {
+#ifdef DHDTCPACK_SUPPRESS
+ /* Clean tcp_ack_info_tbl in order to prevent access to flushed pkt,
+ * when there is a newly coming packet from network stack.
+ */
+ dhd_tcpack_info_tbl_clean(bus->dhd);
+#endif /* DHDTCPACK_SUPPRESS */
+ /* Clear the data packet queues */
+ pktq_flush(dhdp->osh, &bus->txq, TRUE, NULL, 0);
+ }
+}
+
+int
+dhd_sr_config(dhd_pub_t *dhd, bool on)
+{
+ dhd_bus_t *bus = dhd->bus;
+
+ if (!bus->_srenab)
+ return -1;
+
+ return dhdsdio_clk_devsleep_iovar(bus, on);
+}
+
+uint16
+dhd_get_chipid(dhd_pub_t *dhd)
+{
+ dhd_bus_t *bus = dhd->bus;
+
+ if (bus && bus->sih)
+ return (uint16)bus->sih->chip;
+ else
+ return 0;
+}
+
+#ifdef DEBUGGER
+uint32 dhd_sdio_reg_read(void *h, uint32 addr)
+{
+ uint32 rval;
+ struct dhd_bus *bus = (struct dhd_bus *) h;
+
+ dhd_os_sdlock(bus->dhd);
+
+ BUS_WAKE(bus);
+
+ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
+
+ rval = bcmsdh_reg_read(bus->sdh, addr, 4);
+
+ dhd_os_sdunlock(bus->dhd);
+
+ return rval;
+}
+
+void dhd_sdio_reg_write(void *h, uint32 addr, uint32 val)
+{
+ struct dhd_bus *bus = (struct dhd_bus *) h;
+
+ dhd_os_sdlock(bus->dhd);
+
+ BUS_WAKE(bus);
+
+ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
+
+ bcmsdh_reg_write(bus->sdh, addr, 4, val);
+
+ dhd_os_sdunlock(bus->dhd);
}
-#endif /* CUSTOMER_HW4 && SUPPORT_MULTIPLE_REVISION */
+#endif /* DEBUGGER */