/*
* DHD Bus Module for SDIO
*
- * $Copyright Open Broadcom Corporation$
+ * Copyright (C) 1999-2016, Broadcom Corporation
+ *
+ * Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2 (the "GPL"),
+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the
+ * following added to such license:
+ *
+ * As a special exception, the copyright holders of this software give you
+ * permission to link this software with independent modules, and to copy and
+ * distribute the resulting executable under terms of your choice, provided that
+ * you also meet, for each linked independent module, the terms and conditions of
+ * the license of that module. An independent module is a module which is not
+ * derived from this software. The special exception does not apply to any
+ * modifications of the software.
+ *
+ * Notwithstanding the above, under no circumstances may you combine this
+ * 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 506046 2014-10-02 12:40:12Z $
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: dhd_sdio.c 593728 2015-10-19 09:20:32Z $
*/
#include <typedefs.h>
#include <hndpmu.h>
#include <hndsoc.h>
#include <bcmsdpcm.h>
-#if defined(DHD_DEBUG)
#include <hnd_armtrap.h>
#include <hnd_cons.h>
-#endif /* defined(DHD_DEBUG) */
#include <sbchipc.h>
#include <sbhnddma.h>
#define DHD_TXMINMAX 1 /* Max tx frames if rx still pending */
#define MEMBLOCK 2048 /* Block size used for downloading of dongle image */
-#define MAX_NVRAMBUF_SIZE 4096 /* max nvram buf size */
#define MAX_DATA_BUF (64 * 1024) /* Must be large enough to hold biggest possible glom */
#ifndef DHD_FIRSTREAD
*/
#define PKTFREE2() if ((bus->bus != SPI_BUS) || bus->usebufpool) \
PKTFREE(bus->dhd->osh, pkt, FALSE);
+
+#ifdef PKT_STATICS
+pkt_statics_t tx_statics = {0};
+#endif
+
DHD_SPINWAIT_SLEEP_INIT(sdioh_spinwait_sleep);
#if defined(MULTIPLE_SUPPLICANT)
#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
#endif
-#ifdef DHD_DEBUG
/* Device console log buffer state */
#define CONSOLE_LINE_MAX 192
#define CONSOLE_BUFFER_MAX 2024
uint8 *buf; /* Log buffer (host copy) */
uint last; /* Last buffer read index */
} dhd_console_t;
-#endif /* DHD_DEBUG */
#define REMAP_ENAB(bus) ((bus)->remap)
#define REMAP_ISADDR(bus, a) (((a) >= ((bus)->orig_ramsize)) && ((a) < ((bus)->ramsize)))
uint16 cl_devid; /* cached devid for dhdsdio_probe_attach() */
char *fw_path; /* module_param: path to firmware image */
char *nv_path; /* module_param: path to nvram vars file */
- const char *nvram_params; /* user specified nvram params. */
uint blocksize; /* Block size of SDIO transfers */
uint roundup; /* Max roundup limit */
int32 sd_rxchain; /* If bcmsdh api accepts PKT chains */
bool use_rxchain; /* If dhd should use PKT chains */
bool sleeping; /* Is SDIO bus sleeping? */
+#if defined(SUPPORT_P2P_GO_PS)
wait_queue_head_t bus_sleep;
+#endif /* LINUX && SUPPORT_P2P_GO_PS */
uint rxflow_mode; /* Rx flow control mode */
bool rxflow; /* Is rx flow control on */
uint prev_rxlim_hit; /* Is prev rx limit exceeded (per dpc schedule) */
#ifdef DHDENABLE_TAILPAD
void *pad_pkt;
#endif /* DHDENABLE_TAILPAD */
- uint txglomframes; /* Number of tx glom frames (superframes) */
- uint txglompkts; /* Number of packets from tx glom frames */
+ uint txglomframes; /* Number of tx glom frames (superframes) */
+ uint txglompkts; /* Number of packets from tx glom frames */
} dhd_bus_t;
/* clkstate */
#define DHD_NOPMU(dhd) (FALSE)
+#if defined(BCMSDIOH_STD)
+#define BLK_64_MAXTXGLOM 20
+#endif /* BCMSDIOH_STD */
+
#ifdef DHD_DEBUG
static int qcount[NUMPRIO];
static int tx_packets[NUMPRIO];
extern uint dhd_watchdog_ms;
extern void dhd_os_wd_timer(void *bus, uint wdtick);
+int dhd_enableOOB(dhd_pub_t *dhd, bool sleep);
/* Tx/Rx bounds */
uint dhd_txbound;
#define ALIGNMENT 4
-#if defined(OOB_INTR_ONLY) && defined(HW_OOB)
+#if (defined(OOB_INTR_ONLY) && defined(HW_OOB)) || defined(FORCE_WOWLAN)
extern void bcmsdh_enable_hw_oob_intr(void *sdh, bool enable);
#endif
/* Try doing readahead */
static bool dhd_readahead;
+#if defined(SWTXGLOM) || defined(BCMSDIOH_TXGLOM_EXT)
+bool
+dhdsdio_is_dataok(dhd_bus_t *bus) {
+ return (((uint8)(bus->tx_max - bus->tx_seq) - bus->dhd->conf->tx_max_offset > 1) && \
+ (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0));
+}
+
+uint8
+dhdsdio_get_databufcnt(dhd_bus_t *bus) {
+ return ((uint8)(bus->tx_max - bus->tx_seq) - 1 - bus->dhd->conf->tx_max_offset);
+}
+#endif
+
/* To check if there's window offered */
+#if defined(SWTXGLOM) || defined(BCMSDIOH_TXGLOM_EXT)
+#define DATAOK(bus) dhdsdio_is_dataok(bus)
+#else
#define DATAOK(bus) \
(((uint8)(bus->tx_max - bus->tx_seq) > 1) && \
(((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0))
+#endif
/* To check if there's window offered for ctrl frame */
#define TXCTLOK(bus) \
(((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0))
/* Number of pkts available in dongle for data RX */
+#if defined(SWTXGLOM) || defined(BCMSDIOH_TXGLOM_EXT)
+#define DATABUFCNT(bus) dhdsdio_get_databufcnt(bus)
+#else
#define DATABUFCNT(bus) \
((uint8)(bus->tx_max - bus->tx_seq) - 1)
+#endif
/* Macros to get register read/write status */
/* NOTE: these assume a local dhdsdio_bus_t *bus! */
static void dhdsdio_sdtest_set(dhd_bus_t *bus, uint count);
#endif
-#ifdef DHD_DEBUG
static int dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size);
+#ifdef DHD_DEBUG
static int dhd_serialconsole(dhd_bus_t *bus, bool get, bool enable, int *bcmerror);
#endif /* DHD_DEBUG */
+#if defined(DHD_FW_COREDUMP)
+static int dhdsdio_mem_dump(dhd_bus_t *bus);
+#endif /* DHD_FW_COREDUMP */
static int dhdsdio_devcap_set(dhd_bus_t *bus, uint8 cap);
static int dhdsdio_download_state(dhd_bus_t *bus, bool enter);
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);
+ int *pad_pkt_len, void **new_pkt
+#if defined(BCMSDIOH_TXGLOM_EXT)
+ , int frist_frame
+#endif
+);
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);
(bus->sih->chip == BCM4339_CHIP_ID) ||
(bus->sih->chip == BCM43349_CHIP_ID) ||
(bus->sih->chip == BCM4345_CHIP_ID) ||
+ (bus->sih->chip == BCM43454_CHIP_ID) ||
(bus->sih->chip == BCM4354_CHIP_ID) ||
(bus->sih->chip == BCM4356_CHIP_ID) ||
(bus->sih->chip == BCM4358_CHIP_ID) ||
(bus->sih->chip == BCM4339_CHIP_ID) ||
(bus->sih->chip == BCM43349_CHIP_ID) ||
(bus->sih->chip == BCM4345_CHIP_ID) ||
+ (bus->sih->chip == BCM43454_CHIP_ID) ||
(bus->sih->chip == BCM4354_CHIP_ID) ||
(bus->sih->chip == BCM4356_CHIP_ID) ||
(bus->sih->chip == BCM4358_CHIP_ID) ||
if ((bus->sih->chip == BCM4350_CHIP_ID) ||
(bus->sih->chip == BCM4345_CHIP_ID) ||
+ (bus->sih->chip == BCM43454_CHIP_ID) ||
(bus->sih->chip == BCM4354_CHIP_ID) ||
(bus->sih->chip == BCM4356_CHIP_ID) ||
(bus->sih->chip == BCM4358_CHIP_ID) ||
static int
dhdsdio_srwar_init(dhd_bus_t *bus)
{
-#if !defined(NDISVER) || (NDISVER < 0x0630)
bcmsdh_gpio_init(bus->sdh);
-#endif /* !defined(NDISVER) || (NDISVER < 0x0630) */
#ifdef USE_OOB_GPIO1
dhdsdio_oobwakeup_init(bus);
#define KSO_WAIT_US 50
#define KSO_WAIT_MS 1
#define KSO_SLEEP_RETRY_COUNT 20
+#define KSO_WAKE_RETRY_COUNT 100
#define ERROR_BCME_NODEVICE_MAX 1
-#define MAX_KSO_ATTEMPTS (PMU_MAX_TRANSITION_DLY/KSO_WAIT_US)
+#define DEFAULT_MAX_KSO_ATTEMPTS (PMU_MAX_TRANSITION_DLY/KSO_WAIT_US)
+#ifndef CUSTOM_MAX_KSO_ATTEMPTS
+#define CUSTOM_MAX_KSO_ATTEMPTS DEFAULT_MAX_KSO_ATTEMPTS
+#endif
+
static int
dhdsdio_clk_kso_enab(dhd_bus_t *bus, bool on)
{
int err = 0;
int try_cnt = 0;
- if (!bus->dhd->conf->kso_enable)
- return 0;
-
KSO_DBG(("%s> op:%s\n", __FUNCTION__, (on ? "KSO_SET" : "KSO_CLR")));
wr_val |= (on << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT);
bmask = cmp_val;
OSL_SLEEP(3);
+
} else {
/* Put device to sleep, turn off KSO */
cmp_val = 0;
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);
+ } while (try_cnt++ < CUSTOM_MAX_KSO_ATTEMPTS);
if (try_cnt > 2)
KSO_DBG(("%s> op:%s, try_cnt:%d, rd_val:%x, ERR:%x \n",
__FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"), try_cnt, rd_val, err));
- if (try_cnt > MAX_KSO_ATTEMPTS) {
+ if (try_cnt > CUSTOM_MAX_KSO_ATTEMPTS) {
DHD_ERROR(("%s> op:%s, ERROR: try_cnt:%d, rd_val:%x, ERR:%x \n",
__FUNCTION__, (on ? "KSO_SET" : "KSO_CLR"), try_cnt, rd_val, err));
}
+
return err;
}
#ifdef USE_CMD14
err = bcmsdh_sleep(bus->sdh, TRUE);
#else
+
+
err = dhdsdio_clk_kso_enab(bus, FALSE);
if (OOB_WAKEUP_ENAB(bus))
{
-#if !defined(NDISVER) || (NDISVER < 0x0630)
err = bcmsdh_gpioout(bus->sdh, GPIO_DEV_WAKEUP, FALSE); /* GPIO_1 is off */
-#endif /* !defined(NDISVER) || (NDISVER < 0x0630) */
}
#endif /* USE_CMD14 */
} else {
DHD_TRACE(("%s: Request SD clk\n", __FUNCTION__));
dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
}
-#if !defined(NDISVER) || (NDISVER < 0x0630)
if ((bus->sih->chip == BCM4334_CHIP_ID) && (bus->sih->chiprev == 2)) {
SPINWAIT_SLEEP(sdioh_spinwait_sleep,
DHD_ERROR(("ERROR: GPIO_DEV_SRSTATE still low!\n"));
}
}
-#endif
#ifdef USE_CMD14
err = bcmsdh_sleep(bus->sdh, FALSE);
if (SLPAUTO_ENAB(bus) && (err != 0)) {
#else
if (OOB_WAKEUP_ENAB(bus))
{
-#if !defined(NDISVER) || (NDISVER < 0x0630)
err = bcmsdh_gpioout(bus->sdh, GPIO_DEV_WAKEUP, TRUE); /* GPIO_1 is on */
-#endif /* !defined(NDISVER) || (NDISVER < 0x0630) */
}
do {
err = dhdsdio_clk_kso_enab(bus, TRUE);
DHD_ERROR(("ERROR: kso set failed retry: %d\n", retry));
err = 0; /* continue anyway */
}
+
+
#endif /* !USE_CMD14 */
if (err == 0) {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
else if (ht_avail_error == HT_AVAIL_ERROR_MAX) {
+ bus->dhd->hang_reason = HANG_REASON_HT_AVAIL_ERROR;
dhd_os_send_hang_message(bus->dhd);
}
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) */
/* Going to sleep: set the alarm and turn off the lights... */
if (sleep) {
/* Don't sleep if something is pending */
+#ifdef DHD_USE_IDLECOUNT
+ 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 /* DHD_USE_IDLECOUNT */
return BCME_BUSY;
/* Change state */
bus->sleeping = TRUE;
+#if defined(SUPPORT_P2P_GO_PS)
wake_up(&bus->bus_sleep);
+#endif /* LINUX && SUPPORT_P2P_GO_PS */
} else {
/* Waking up: bus power up is ok, set local state */
return err;
}
+#ifdef USE_DYNAMIC_F2_BLKSIZE
+int dhdsdio_func_blocksize(dhd_pub_t *dhd, int function_num, int block_size)
+{
+ int func_blk_size = function_num;
+ int bcmerr = 0;
+ int result;
+
+ bcmerr = dhd_bus_iovar_op(dhd, "sd_blocksize", &func_blk_size,
+ sizeof(int), &result, sizeof(int), IOV_GET);
-#if defined(OOB_INTR_ONLY)
+ if (bcmerr != BCME_OK) {
+ DHD_ERROR(("%s: Get F%d Block size error\n", __FUNCTION__, function_num));
+ return BCME_ERROR;
+ }
+
+ if (result != block_size) {
+ DHD_TRACE_HW4(("%s: F%d Block size set from %d to %d\n",
+ __FUNCTION__, function_num, result, block_size));
+ func_blk_size = function_num << 16 | block_size;
+ bcmerr = dhd_bus_iovar_op(dhd, "sd_blocksize", NULL,
+ 0, &func_blk_size, sizeof(int32), IOV_SET);
+ if (bcmerr != BCME_OK) {
+ DHD_ERROR(("%s: Set F2 Block size error\n", __FUNCTION__));
+ return BCME_ERROR;
+ }
+ }
+
+ return BCME_OK;
+}
+#endif /* USE_DYNAMIC_F2_BLKSIZE */
+
+#if defined(OOB_INTR_ONLY) || defined(FORCE_WOWLAN)
void
dhd_enable_oob_intr(struct dhd_bus *bus, bool enable)
{
-#if defined(HW_OOB)
+#if defined(HW_OOB) || defined(FORCE_WOWLAN)
bcmsdh_enable_hw_oob_intr(bus->sdh, enable);
#else
sdpcmd_regs_t *regs = bus->regs;
/* 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 (bus->dhd->conf->deferred_tx_len) {
+ if(dhd_os_wd_timer_enabled(bus->dhd) == FALSE) {
+ bus->dpc_sched = TRUE;
+ dhd_sched_dpc(bus->dhd);
+ }
+ if(pktq_len(&bus->txq) >= bus->dhd->conf->deferred_tx_len &&
+ dhd_os_wd_timer_enabled(bus->dhd) == FALSE) {
+ bus->dpc_sched = TRUE;
+ dhd_sched_dpc(bus->dhd);
+ }
+ } else {
+ bus->dpc_sched = TRUE;
+ dhd_sched_dpc(bus->dhd);
+ }
}
} else {
int chan = SDPCM_DATA_CHANNEL;
*/
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 *pad_pkt_len, void **new_pkt
+#if defined(BCMSDIOH_TXGLOM_EXT)
+ , int first_frame
+#endif
+)
{
osl_t *osh;
uint8 *frame;
uint32 swhdr_offset;
bool alloc_new_pkt = FALSE;
uint8 sdpcm_hdrlen = bus->txglom_enable ? SDPCM_HDRLEN_TXGLOM : SDPCM_HDRLEN;
+#ifdef PKT_STATICS
+ uint16 len;
+#endif
*new_pkt = NULL;
osh = bus->dhd->osh;
}
}
#endif /* WLMEDIA_HTSF */
+#ifdef PKT_STATICS
+ len = (uint16)PKTLEN(osh, pkt);
+ switch(chan) {
+ case SDPCM_CONTROL_CHANNEL:
+ tx_statics.ctrl_count++;
+ tx_statics.ctrl_size += len;
+ break;
+ case SDPCM_DATA_CHANNEL:
+ tx_statics.data_count++;
+ tx_statics.data_size += len;
+ break;
+ case SDPCM_GLOM_CHANNEL:
+ tx_statics.glom_count++;
+ tx_statics.glom_size += len;
+ break;
+ case SDPCM_EVENT_CHANNEL:
+ tx_statics.event_count++;
+ tx_statics.event_size += len;
+ break;
+ case SDPCM_TEST_CHANNEL:
+ tx_statics.test_count++;
+ tx_statics.test_size += len;
+ break;
+
+ default:
+ break;
+ }
+#endif /* PKT_STATICS */
#ifdef DHD_DEBUG
if (PKTPRIO(pkt) < ARRAYSIZE(tx_packets))
tx_packets[PKTPRIO(pkt)]++;
* referred to in sdioh_request_buffer(). The tail length will be excluded in
* dhdsdio_txpkt_postprocess().
*/
+#if defined(BCMSDIOH_TXGLOM_EXT)
+ if (bus->dhd->conf->txglom_bucket_size)
+ tail_padding = 0;
+#endif
*(uint16*)frame = (uint16)htol16(pkt_len);
*(((uint16*)frame) + 1) = (uint16)htol16(~pkt_len);
pkt_len += tail_padding;
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);
+#ifdef BCMSDIOH_TXGLOM_EXT
+ uint32 act_len = pkt_len - tail_padding;
+ uint32 real_pad = 0;
+ if(bus->dhd->conf->txglom_ext && !last_chained_pkt) {
+ tail_padding = 0;
+ if(first_frame == 0) {
+ // first pkt, add pad to bucket size - recv offset
+ pkt_len = bus->dhd->conf->txglom_bucket_size - TXGLOM_RECV_OFFSET;
+ } else {
+ // add pad to bucket size
+ pkt_len = bus->dhd->conf->txglom_bucket_size;
+ }
+ swhdr_offset += SDPCM_HWEXT_LEN;
+ hwheader1 = (act_len - SDPCM_FRAMETAG_LEN) | (last_chained_pkt << 24);
+ hwheader2 = (pkt_len - act_len) << 16;
+ htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN);
+ htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4);
+ real_pad = pkt_len - act_len;
+
+ if (PKTTAILROOM(osh, pkt) < real_pad) {
+ DHD_INFO(("%s : insufficient tailroom %d for %d real_pad\n",
+ __func__, (int)PKTTAILROOM(osh, pkt), real_pad));
+ if (PKTPADTAILROOM(osh, pkt, real_pad)) {
+ DHD_ERROR(("CHK1: padding error size %d\n", real_pad));
+ } else
+ frame = (uint8 *)PKTDATA(osh, pkt);
+ }
+ } else
+#endif
+ {
+ 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);
+ }
}
PKTSETLEN((osh), (pkt), (pkt_len));
(void)osh;
osh = bus->dhd->osh;
- /* restore pkt buffer pointer, but keeps the header pushed by dhd_prot_hdrpush */
- frame = (uint8*)PKTDATA(osh, pkt);
+ /* 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 {
+ /* 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)));
+ }
+
+ 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);
+
+ DHD_INFO(("%s data_offset %d, PKTLEN %d\n",
+ __FUNCTION__, data_offset, PKTLEN(osh, pkt)));
+
+ return BCME_OK;
+}
+
+#if defined(SWTXGLOM)
+static int
+dhd_bcmsdh_send_swtxglom_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes,
+ void *pkt, bcmsdh_cmplt_fn_t complete, void *handle, int max_retry)
+{
+ int ret;
+ int i = 0;
+ int retries = 0;
+ bcmsdh_info_t *sdh;
+
+ if (!KSO_ENAB(bus)) {
+ DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
+ return BCME_NODEVICE;
+ }
+
+ sdh = bus->sdh;
+ do {
+ ret = bcmsdh_send_swtxglom_buf(bus->sdh, addr, fn, flags, buf, nbytes,
+ pkt, complete, handle);
+
+ bus->f2txdata++;
+ 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_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;
+ }
+ }
+ if (ret == 0) {
+#ifdef BCMSDIOH_TXGLOM
+ if (bus->txglom_enable) {
+ bus->tx_seq = (bus->tx_seq + bus->txglom_cnt) % SDPCM_SEQUENCE_WRAP;
+ } else
+#endif
+ {
+ bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
+ }
+ }
+ } while ((ret < 0) && retrydata && ++retries < max_retry);
+
+ 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_swtxglom(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt, bool queue_only)
+{
+ int ret;
+ osl_t *osh;
+ uint8 *frame;
+ uint16 len, pad1 = 0, act_len = 0;
+ uint32 swheader;
+ uint32 real_pad = 0;
+ bcmsdh_info_t *sdh;
+ void *new;
+ 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__));
+
+ sdh = bus->sdh;
+ osh = bus->dhd->osh;
+
+#ifdef DHDTCPACK_SUPPRESS
+ 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, TCPACK_SUP_OFF);
+ }
+#endif /* DHDTCPACK_SUPPRESS */
+
+ /* Add space for the header */
+ PKTPUSH(osh, pkt, SDPCM_HDRLEN_TXGLOM);
+ ASSERT(ISALIGNED((uintptr)PKTDATA(osh, pkt), 2));
+
+ if (bus->dhd->dongle_reset) {
+ ret = BCME_NOTREADY;
+ goto done;
+ }
+
+ frame = (uint8*)PKTDATA(osh, pkt);
+
+#ifdef WLMEDIA_HTSF
+ if (PKTLEN(osh, pkt) >= 100) {
+ p = PKTDATA(osh, pkt);
+ htsf_ts = (htsfts_t*) (p + 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 PKT_STATICS
+ len = (uint16)PKTLEN(osh, pkt);
+ switch(chan) {
+ case SDPCM_CONTROL_CHANNEL:
+ tx_statics.ctrl_count++;
+ tx_statics.ctrl_size += len;
+ break;
+ case SDPCM_DATA_CHANNEL:
+ tx_statics.data_count++;
+ tx_statics.data_size += len;
+ break;
+ case SDPCM_GLOM_CHANNEL:
+ tx_statics.glom_count++;
+ tx_statics.glom_size += len;
+ break;
+ case SDPCM_EVENT_CHANNEL:
+ tx_statics.event_count++;
+ tx_statics.event_size += len;
+ break;
+ case SDPCM_TEST_CHANNEL:
+ tx_statics.test_count++;
+ tx_statics.test_size += len;
+ break;
+
+ default:
+ break;
+ }
+#endif /* PKT_STATICS */
+
+ /* 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;
+ }
+
+ 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);
+
+ ASSERT((pad1 + SDPCM_HDRLEN_TXGLOM) <= (int) PKTLEN(osh, pkt));
+ bzero(frame, pad1 + SDPCM_HDRLEN_TXGLOM);
+ }
+ }
+ ASSERT(pad1 < DHD_SDALIGN);
+
+ /* 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);
+
+#ifdef BCMSDIOH_TXGLOM
+ if (bus->txglom_enable) {
+ uint32 hwheader1 = 0, hwheader2 = 0;
+ act_len = len;
+
+ /* Software tag: channel, sequence number, data offset */
+ swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) |
+ ((bus->tx_seq + bus->txglom_cnt) % SDPCM_SEQUENCE_WRAP) |
+ (((pad1 + SDPCM_HDRLEN_TXGLOM) << 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) {
+ if (bus->dhd->conf->txglom_ext) {
+ if(bus->txglom_cnt == 0) {
+ // first pkt, add pad to bucket size - recv offset
+ len = bus->dhd->conf->txglom_bucket_size - TXGLOM_RECV_OFFSET;
+ } else {
+ // add pad to bucket size
+ len = bus->dhd->conf->txglom_bucket_size;
+ }
+ } else {
+ uint8 alignment = ALIGNMENT;
+ 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(("CHK1: padding error size %d\n", real_pad));
+ ret = BCME_NOMEM;
+ goto done;
+ }
+#ifndef BCMLXSDMMC
+ else
+ PKTSETLEN(osh, pkt, act_len);
+#endif
+ }
+#ifdef BCMLXSDMMC
+ PKTSETLEN(osh, pkt, len);
+#endif /* BCMLXSDMMC */
+ /* Post the frame pointer to sdio glom array */
+ bcmsdh_glom_post(bus->sdh, frame, pkt, len);
+ /* Save the pkt pointer in bus glom array */
+ bus->glom_pkt_arr[bus->txglom_cnt] = pkt;
+ bus->txglom_total_len += len;
+ bus->txglom_cnt++;
+ return BCME_OK;
+ } else {
+ /* Raise len to next SDIO block to eliminate tail command */
+ if (bus->roundup && bus->blocksize &&
+ ((bus->txglom_total_len + len) > bus->blocksize)) {
+ uint16 pad2 = bus->blocksize -
+ ((bus->txglom_total_len + len) % bus->blocksize);
+ if ((pad2 <= bus->roundup) && (pad2 < bus->blocksize)) {
+ len += pad2;
+ } else {
+ }
+ } else if ((bus->txglom_total_len + len) % DHD_SDALIGN) {
+ len += DHD_SDALIGN
+ - ((bus->txglom_total_len + len) % DHD_SDALIGN);
+ }
+ if (forcealign && (len & (ALIGNMENT - 1))) {
+ len = ROUNDUP(len, ALIGNMENT);
+ }
+
+ /* Hardware extention tag */
+ /* 2byte frame length, 1byte-, 1byte frame flag,
+ * 2byte-hdrlength, 2byte padlenght
+ */
+ if (bus->dhd->conf->txglom_ext) {
+ // copy way, the last packet pad2 is set to 0 it will be dropped by HW
+ hwheader1 = (act_len - SDPCM_FRAMETAG_LEN) | (1 << 24);
+ hwheader2 = 0;
+ htol32_ua_store(hwheader1, frame + SDPCM_FRAMETAG_LEN);
+ htol32_ua_store(hwheader2, frame + SDPCM_FRAMETAG_LEN + 4);
+ } else {
+ 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(("CHK2: padding error size %d."
+ " %d more pkts are discarded together.\n",
+ real_pad, bus->txglom_cnt));
+ /* Save the pkt pointer in bus glom array
+ * Otherwise, this last pkt will not be
+ * cleaned under "goto done"
+ */
+ bus->glom_pkt_arr[bus->txglom_cnt] = pkt;
+ bus->txglom_cnt++;
+ bus->txglom_total_len += len;
+ ret = BCME_NOMEM;
+ goto done;
+ }
+#ifndef BCMLXSDMMC
+ else
+ PKTSETLEN(osh, pkt, act_len);
+#endif
+ }
+#ifdef BCMLXSDMMC
+ PKTSETLEN(osh, pkt, len);
+#endif /* BCMLXSDMMC */
+
+ /* Post the frame pointer to sdio glom array */
+ bcmsdh_glom_post(bus->sdh, frame, pkt, len);
+ /* Save the pkt pointer in bus glom array */
+ bus->glom_pkt_arr[bus->txglom_cnt] = pkt;
+ bus->txglom_cnt++;
+ if (bus->dhd->conf->txglom_ext)
+ //copy way, the last buffer padding is not need add to len
+ bus->txglom_total_len += act_len;
+ else
+ bus->txglom_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->txglom_total_len);
+ *(((uint16*)frame_tmp) + 1) = htol16(~bus->txglom_total_len);
+ }
+ } else
+#endif /* BCMSDIOH_TXGLOM */
+ {
+ act_len = len;
+ /* Software tag: channel, sequence number, data offset */
+ swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) | bus->tx_seq |
+ (((pad1 + SDPCM_HDRLEN_TXGLOM) << 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));
+ }
+#endif
+
+ /* 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);
+ }
+
+ /* 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(("CHK3: padding error size %d\n", real_pad));
+ ret = BCME_NOMEM;
+ goto done;
+ }
+#ifndef BCMLXSDMMC
+ else
+ PKTSETLEN(osh, pkt, act_len);
+#endif
+ }
+#ifdef BCMLXSDMMC
+ PKTSETLEN(osh, pkt, len);
+#endif /* BCMLXSDMMC */
+ }
+#ifdef DHD_DEBUG
+ if (PKTPRIO(pkt) < ARRAYSIZE(tx_packets)) {
+ tx_packets[PKTPRIO(pkt)]++;
+ }
+#endif
+ ret = dhd_bcmsdh_send_swtxglom_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
+ frame, len, pkt, NULL, NULL, TXRETRIES);
+
+done:
+
+#ifdef BCMSDIOH_TXGLOM
+ if (bus->txglom_enable && !queue_only) {
+ bcmsdh_glom_clear(bus->sdh);
+ pkt_cnt = bus->txglom_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->txglom_enable) {
+#ifdef BCMLXSDMMC
+ uint32 pad2 = 0;
+#endif /* BCMLXSDMMC */
+ if (!queue_only)
+ pkt = bus->glom_pkt_arr[bus->txglom_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 */
+ {
+#ifdef BCMLXSDMMC
+ if (act_len > 0)
+ PKTSETLEN(osh, pkt, act_len);
+#endif /* BCMLXSDMMC */
+ PKTPULL(osh, pkt, SDPCM_HDRLEN_TXGLOM + 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);
+ } else {
+#endif /* PROP_TXSTATUS */
+#ifdef SDTEST
+ if (chan != SDPCM_TEST_CHANNEL) {
+ dhd_txcomplete(bus->dhd, pkt, ret != 0);
+ }
+#else /* SDTEST */
+ dhd_txcomplete(bus->dhd, pkt, ret != 0);
+#endif /* SDTEST */
+ if (free_pkt)
+ PKTFREE(osh, pkt, TRUE);
+#ifdef PROP_TXSTATUS
+ }
+#endif
+ pkt_cnt--;
+ }
+
+#ifdef BCMSDIOH_TXGLOM
+ /* Reset the glom array */
+ if (bus->txglom_enable && !queue_only) {
+ bus->txglom_cnt = 0;
+ bus->txglom_total_len = 0;
+ }
+#endif
+ return ret;
+}
+
+static uint
+dhdsdio_sendfromq_swtxglom(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;
+ uint16 txpktqlen = 0;
+#ifdef BCMSDIOH_TXGLOM
+ uint i;
+ uint8 txglom_cnt;
+#endif
+
+ dhd_pub_t *dhd = bus->dhd;
+ sdpcmd_regs_t *regs = bus->regs;
+
+ DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+
+ if (!KSO_ENAB(bus)) {
+ DHD_ERROR(("%s: Device asleep\n", __FUNCTION__));
+ return BCME_NODEVICE;
+ }
+
+ 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->txglom_enable) {
+ void *pkttable[SDPCM_MAXGLOM_SIZE];
+ dhd_os_sdlock_txq(bus->dhd);
+ txglom_cnt = MIN(DATABUFCNT(bus), bus->txglomsize);
+ txglom_cnt = MIN(txglom_cnt, pktq_mlen(&bus->txq, tx_prec_map));
+ txglom_cnt = MIN(txglom_cnt, maxframes-cnt);
+
+ /* Limiting the size to 2pkts in case of copy */
+ if (bus->dhd->conf->txglom_ext)
+ txglom_cnt = MIN(txglom_cnt, SDPCM_MAXGLOM_SIZE);
+ else
+ txglom_cnt = MIN(txglom_cnt, 10);
+
+ for (i = 0; i < txglom_cnt; i++)
+ pkttable[i] = pktq_mdeq(&bus->txq, tx_prec_map, &prec_out);
+
+ txpktqlen = pktq_len(&bus->txq);
+ dhd_os_sdunlock_txq(bus->dhd);
+
+ if (txglom_cnt == 0)
+ break;
+ datalen = 0;
+
+#ifdef PKT_STATICS
+ if (txglom_cnt < 2)
+ tx_statics.glom_1_count++;
+ else if (txglom_cnt < 3)
+ tx_statics.glom_3_count++;
+ else if (txglom_cnt < 8)
+ tx_statics.glom_3_8_count++;
+ else
+ tx_statics.glom_8_count++;
+ if (txglom_cnt > tx_statics.glom_max)
+ tx_statics.glom_max = txglom_cnt;
+#endif
+ for (i = 0; i < txglom_cnt; i++) {
+ uint datalen_tmp = 0;
+
+ if ((pkt = pkttable[i]) == NULL) {
+ /* This case should not happen */
+ DHD_ERROR(("No pkts in the queue for glomming\n"));
+ break;
+ }
+
+ datalen_tmp = (PKTLEN(bus->dhd->osh, pkt) - SDPCM_HDRLEN_TXGLOM);
+
+#ifndef SDTEST
+ ret = dhdsdio_txpkt_swtxglom(bus,
+ pkt,
+ SDPCM_DATA_CHANNEL,
+ TRUE,
+ (i == (txglom_cnt-1))? FALSE: TRUE);
+#else
+ ret = dhdsdio_txpkt_swtxglom(bus,
+ pkt,
+ (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL),
+ TRUE,
+ (i == (txglom_cnt-1))? FALSE: TRUE);
+#endif
+ if (ret == BCME_OK)
+ datalen += datalen_tmp;
+ }
+ 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;
+ }
+ txpktqlen = pktq_len(&bus->txq);
+ dhd_os_sdunlock_txq(bus->dhd);
+ datalen = PKTLEN(bus->dhd->osh, pkt) - SDPCM_HDRLEN_TXGLOM;
+
+#ifndef SDTEST
+ ret = dhdsdio_txpkt_swtxglom(bus, pkt, SDPCM_DATA_CHANNEL, TRUE, FALSE);
+#else
+ ret = dhdsdio_txpkt_swtxglom(bus,
+ pkt,
+ (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL),
+ TRUE,
+ FALSE);
+#endif
+ }
- DHD_INFO(("%s PKTLEN before postprocess %d",
- __FUNCTION__, PKTLEN(osh, pkt)));
+ if (ret)
+ bus->dhd->tx_errors++;
+ else
+ bus->dhd->dstats.tx_bytes += datalen;
- /* 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 {
- /* 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)));
+ /* In poll mode, need to check for other events */
+ if (!bus->intr && cnt)
+ {
+ /* Check device status, signal pending interrupt */
+ R_SDREG(intstatus, ®s->intstatus, retries);
+ bus->f2txdata++;
+ if (bcmsdh_regfail(bus->sdh))
+ break;
+ if (intstatus & bus->hostintmask)
+ bus->ipend = TRUE;
+ }
}
- 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);
-
- DHD_INFO(("%s data_offset %d, PKTLEN %d\n",
- __FUNCTION__, data_offset, PKTLEN(osh, pkt)));
+ /* 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);
- return BCME_OK;
+ return cnt;
}
+#endif
static int dhdsdio_txpkt(dhd_bus_t *bus, uint chan, void** pkts, int num_pkt, bool free_pkt)
{
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);
+ total_len, last_pkt, &pad_pkt_len, &new_pkt
+#if defined(BCMSDIOH_TXGLOM_EXT)
+ , i
+#endif
+ );
if (pkt_len <= 0)
goto done;
if (new_pkt) {
* so it will take the aligned length and buffer pointer.
*/
pkt_chain = PKTNEXT(osh, head_pkt) ? head_pkt : NULL;
+#if defined(SWTXGLOM)
+ if (bus->dhd->conf->swtxglom)
+ ret = dhd_bcmsdh_send_swtxglom_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
+ PKTDATA(osh, head_pkt), total_len, pkt_chain, NULL, NULL, TXRETRIES);
+ else
+#endif
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)
osh = dhd->osh;
tx_prec_map = ~bus->flowcontrol;
+#ifdef DHD_LOSSLESS_ROAMING
+ tx_prec_map &= dhd->dequeue_prec_map;
+#endif
for (cnt = 0; (cnt < maxframes) && DATAOK(bus);) {
int i;
int num_pkt = 1;
dhd_os_sdlock_txq(bus->dhd);
if (bus->txglom_enable) {
- num_pkt = MIN((uint32)DATABUFCNT(bus), (uint32)bus->txglomsize);
+ uint32 glomlimit = (uint32)bus->txglomsize;
+#if defined(BCMSDIOH_STD)
+ if (bus->blocksize == 64) {
+ glomlimit = MIN((uint32)bus->txglomsize, BLK_64_MAXTXGLOM);
+ }
+#endif /* BCMSDIOH_STD */
+ num_pkt = MIN((uint32)DATABUFCNT(bus), glomlimit);
num_pkt = MIN(num_pkt, ARRAYSIZE(pkts));
}
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);
+ pkts[i] = pktq_mdeq(&bus->txq, tx_prec_map, &prec_out);
if (!pkts[i]) {
DHD_ERROR(("%s: pktq_mlen non-zero when no pkt\n",
__FUNCTION__));
bus->txglompkts += num_pkt;
}
cnt += i;
+#ifdef PKT_STATICS
+ if (num_pkt < 2)
+ tx_statics.glom_1_count++;
+ else if (num_pkt < 3)
+ tx_statics.glom_3_count++;
+ else if (num_pkt < 8)
+ tx_statics.glom_3_8_count++;
+ else
+ tx_statics.glom_8_count++;
+ if (num_pkt > tx_statics.glom_max)
+ tx_statics.glom_max = num_pkt;
+#endif
/* In poll mode, need to check for other events */
if (!bus->intr && cnt)
*frame_seq = bus->tx_seq;
}
+#if defined(SWTXGLOM)
+ if (bus->dhd->conf->swtxglom)
+ ret = dhd_bcmsdh_send_swtxglom_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
+ (uint8 *)bus->ctrl_frame_buf, (uint32)bus->ctrl_frame_len,
+ NULL, NULL, NULL, 1);
+ else
+#endif
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, 1);
} else {
bus->dhd->txcnt_timeout++;
if (!bus->dhd->hang_was_sent) {
+#ifdef CUSTOMER_HW4_DEBUG
+ uint32 status, retry = 0;
+ R_SDREG(status, &bus->regs->intstatus, retry);
+ DHD_TRACE_HW4(("%s: txcnt_timeout, INT status=0x%08X\n",
+ __FUNCTION__, status));
+ DHD_TRACE_HW4(("%s : tx_max : %d, tx_seq : %d, clkstate : %d \n",
+ __FUNCTION__, bus->tx_max, bus->tx_seq, bus->clkstate));
+#endif /* CUSTOMER_HW4_DEBUG */
DHD_ERROR(("%s: ctrl_frame_stat == TRUE txcnt_timeout=%d\n",
__FUNCTION__, bus->dhd->txcnt_timeout));
}
} else if (DHD_HDRS_ON()) {
prhex("TxHdr", frame, MIN(len, 16));
}
+#endif
+#ifdef PKT_STATICS
+ tx_statics.ctrl_count++;
+ tx_statics.ctrl_size += len;
+#endif
+#if defined(SWTXGLOM)
+ if (bus->dhd->conf->swtxglom)
+ ret = dhd_bcmsdh_send_swtxglom_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
+ frame, len, NULL, NULL, NULL, TXRETRIES);
+ else
#endif
ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
frame, len, NULL, NULL, NULL, TXRETRIES);
{
int timeleft;
uint rxlen = 0;
- bool pending;
DHD_TRACE(("%s: Enter\n", __FUNCTION__));
return -EIO;
/* Wait until control frame is available */
- timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->rxlen, &pending);
+ timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->rxlen);
dhd_os_sdlock(bus->dhd);
rxlen = bus->rxlen;
#else
DHD_ERROR(("%s: resumed on timeout\n", __FUNCTION__));
#endif /* DHD_DEBUG */
-#ifdef DHD_DEBUG
- dhd_os_sdlock(bus->dhd);
- dhdsdio_checkdied(bus, NULL, 0);
- dhd_os_sdunlock(bus->dhd);
-#endif /* DHD_DEBUG */
- } else if (pending == TRUE) {
- /* signal pending */
- DHD_ERROR(("%s: signal pending\n", __FUNCTION__));
- return -EINTR;
-
+ dhd_os_sdlock(bus->dhd);
+ dhdsdio_checkdied(bus, NULL, 0);
+ dhd_os_sdunlock(bus->dhd);
} else {
DHD_CTL(("%s: resumed for unknown reason?\n", __FUNCTION__));
-#ifdef DHD_DEBUG
dhd_os_sdlock(bus->dhd);
dhdsdio_checkdied(bus, NULL, 0);
dhd_os_sdunlock(bus->dhd);
-#endif /* DHD_DEBUG */
}
if (timeleft == 0) {
if (rxlen == 0)
return bcmerror;
}
-#ifdef DHD_DEBUG
static int
dhdsdio_readshared(dhd_bus_t *bus, sdpcm_shared_t *sh)
{
int rv, i;
uint32 shaddr = 0;
+ if (bus->sih == NULL) {
+ if (bus->dhd && bus->dhd->dongle_reset) {
+ DHD_ERROR(("%s: Dongle is in reset state\n", __FUNCTION__));
+ return BCME_NOTREADY;
+ } else {
+ ASSERT(bus->dhd);
+ ASSERT(bus->sih);
+ DHD_ERROR(("%s: The address of sih is invalid\n", __FUNCTION__));
+ return BCME_ERROR;
+ }
+ }
if (CHIPID(bus->sih->chip) == BCM43430_CHIP_ID && !dhdsdio_sr_cap(bus))
bus->srmemsize = 0;
#define CONSOLE_LINE_MAX 192
+#ifdef DHD_DEBUG
static int
dhdsdio_readconsole(dhd_bus_t *bus)
{
return BCME_OK;
}
+#endif /* DHD_DEBUG */
static int
dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size)
DHD_ERROR(("%s: %s\n", __FUNCTION__, strbuf.origbuf));
}
+#if defined(DHD_FW_COREDUMP)
+ if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) {
+ /* Mem dump to a file on device */
+ dhdsdio_mem_dump(bus);
+ }
+#endif /* #if defined(DHD_FW_COREDUMP) */
done:
if (mbuffer)
return bcmerror;
}
-#endif /* #ifdef DHD_DEBUG */
+#if defined(DHD_FW_COREDUMP)
+static int
+dhdsdio_mem_dump(dhd_bus_t *bus)
+{
+ int ret = 0;
+ int size; /* Full mem size */
+ int start = bus->dongle_ram_base; /* Start address */
+ int read_size = 0; /* Read size of each iteration */
+ uint8 *buf = NULL, *databuf = NULL;
+
+ /* Get full mem size */
+ size = bus->ramsize;
+ buf = MALLOC(bus->dhd->osh, size);
+ if (!buf) {
+ printf("%s: Out of memory (%d bytes)\n", __FUNCTION__, size);
+ return -1;
+ }
+
+ /* Read mem content */
+ printf("Dump dongle memory");
+ databuf = buf;
+ while (size)
+ {
+ read_size = MIN(MEMBLOCK, size);
+ if ((ret = dhdsdio_membytes(bus, FALSE, start, databuf, read_size)))
+ {
+ printf("%s: Error membytes %d\n", __FUNCTION__, ret);
+ if (buf) {
+ MFREE(bus->dhd->osh, buf, size);
+ }
+ return -1;
+ }
+ /* Decrement size and increment start address */
+ size -= read_size;
+ start += read_size;
+ databuf += read_size;
+ }
+ printf("Done\n");
+
+ dhd_save_fwdump(bus->dhd, buf, bus->ramsize);
+ /* free buf before return !!! */
+ if (write_to_file(bus->dhd, buf, bus->ramsize))
+ {
+ printf("%s: Error writing to files\n", __FUNCTION__);
+ return -1;
+ }
+
+ /* buf free handled in write_to_file, not here */
+ return 0;
+}
+#endif /* DHD_FW_COREDUMP */
+
+int
+dhd_socram_dump(dhd_bus_t * bus)
+{
+#if defined(DHD_FW_COREDUMP)
+ return (dhdsdio_mem_dump(bus));
+#else
+ return -1;
+#endif
+}
int
dhdsdio_downloadvars(dhd_bus_t *bus, void *arg, int len)
bcmerror = dhdsdio_membytes(bus, TRUE, 0,
(uint8 *)&bus->resetinstr, sizeof(bus->resetinstr));
+ if (bcmerror == BCME_OK) {
+ uint32 tmp;
+
+ /* verify write */
+ bcmerror = dhdsdio_membytes(bus, FALSE, 0,
+ (uint8 *)&tmp, sizeof(tmp));
+
+ if (bcmerror == BCME_OK && tmp != bus->resetinstr) {
+ DHD_ERROR(("%s: Failed to write 0x%08x to addr 0\n",
+ __FUNCTION__, bus->resetinstr));
+ DHD_ERROR(("%s: contents of addr 0 is 0x%08x\n",
+ __FUNCTION__, tmp));
+ bcmerror = BCME_SDIO_ERROR;
+ goto fail;
+ }
+ }
+
/* now remove reset and halt and continue to run CR4 */
}
BUS_WAKE(bus);
- /* Change our idea of bus state */
- bus->dhd->busstate = DHD_BUS_DOWN;
-
if (KSO_ENAB(bus)) {
/* Enable clock for device interrupts */
/* Turn off the bus (F2), free any pending packets */
DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
-#if !defined(NDISVER) || (NDISVER < 0x0630)
bcmsdh_intr_disable(bus->sdh);
-#endif /* !defined(NDISVER) || (NDISVER < 0x0630) */
bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL);
/* Clear any pending interrupts now that F2 is disabled */
/* Turn off the backplane clock (only) */
dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
+
+ /* Change our idea of bus state */
+ bus->dhd->busstate = DHD_BUS_DOWN;
}
#ifdef PROP_TXSTATUS
#endif /* BCMSDIOH_TXGLOM */
bus->txglom_enable = FALSE;
printf("%s: enable %d\n", __FUNCTION__, bus->txglom_enable);
+ dhd_conf_set_txglom_params(bus->dhd, bus->txglom_enable);
}
int
/* Set bus state according to enable result */
dhdp->busstate = DHD_BUS_DATA;
+ /* Need to set fn2 block size to match fn1 block size.
+ * Requests to fn2 go thru fn1. *
+ * faltwig has this code contitioned with #if !BCMSPI_ANDROID.
+ * It would be cleaner to use the ->sdh->block_sz[fno] instead of
+ * 64, but this layer has no access to sdh types.
+ */
+
/* bcmsdh_intr_unmask(bus->sdh); */
bus->intdis = FALSE;
else {
+ if (dhdp->conf->chip == BCM4354_CHIP_ID) {
+ ret = -1;
+ goto exit;
+ }
/* Disable F2 again */
enable = SDIO_FUNC_ENABLE_1;
bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL);
dhdsdio_sendpendctl(bus);
} else if (bus->dotxinrx && (bus->clkstate == CLK_AVAIL) &&
!bus->fcstate && DATAOK(bus) &&
- (pktq_mlen(&bus->txq, ~bus->flowcontrol) > bus->txinrx_thres)) {
+ (pktq_mlen(&bus->txq, ~bus->flowcontrol) > bus->txinrx_thres) &&
+ bus->dhd->conf->tx_in_rx) {
+#if defined(SWTXGLOM)
+ if (bus->dhd->conf->swtxglom)
+ dhdsdio_sendfromq_swtxglom(bus, dhd_txbound);
+ else
+#endif
dhdsdio_sendfromq(bus, dhd_txbound);
#ifdef DHDTCPACK_SUPPRESS
/* In TCPACK_SUP_DELAYTX mode, do txinrx only if
bus->flowcontrol = fcbits;
}
-#ifdef DHD_DEBUG
/* At least print a message if FW halted */
if (hmb_data & HMB_DATA_FWHALT) {
DHD_ERROR(("INTERNAL ERROR: FIRMWARE HALTED : set BUS DOWN\n"));
dhdsdio_checkdied(bus, NULL, 0);
bus->dhd->busstate = DHD_BUS_DOWN;
}
-#endif /* DHD_DEBUG */
/* Shouldn't be any others */
if (hmb_data & ~(HMB_DATA_DEVREADY |
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 */
+#ifdef DEBUG_DPC_THREAD_WATCHDOG
+ bool is_resched_by_readframe = FALSE;
+#endif /* DEBUG_DPC_THREAD_WATCHDOG */
DHD_TRACE(("%s: Enter\n", __FUNCTION__));
dhd_os_sdlock(bus->dhd);
#if defined(OOB_INTR_ONLY)
bcmsdh_oob_intr_set(bus->sdh, TRUE);
#endif /* defined(OOB_INTR_ONLY) */
-#if !defined(NDISVER) || (NDISVER < 0x0630)
bcmsdh_intr_enable(sdh);
-#endif /* !defined(NDISVER) || (NDISVER < 0x0630) */
}
#if defined(OOB_INTR_ONLY) && !defined(HW_OOB)
else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate &&
pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit && DATAOK(bus)) {
framecnt = rxdone ? txlimit : MIN(txlimit, dhd_txminmax);
+#if defined(SWTXGLOM)
+ if (bus->dhd->conf->swtxglom)
+ framecnt = dhdsdio_sendfromq_swtxglom(bus, framecnt);
+ else
+#endif
framecnt = dhdsdio_sendfromq(bus, framecnt);
txlimit -= framecnt;
}
/* Resched the DPC if ctrl cmd is pending on bus credit */
- if (bus->ctrl_frame_stat)
+ if (bus->ctrl_frame_stat) {
+ if (bus->dhd->conf->txctl_tmo_fix) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (!kthread_should_stop())
+ schedule_timeout(1);
+ set_current_state(TASK_RUNNING);
+ }
resched = TRUE;
+ }
/* Resched if events or tx frames are pending, else await next interrupt */
/* On failed register access, all bets are off: no resched or interrupts */
exit:
if (!resched && dhd_dpcpoll) {
- if (dhdsdio_readframes(bus, dhd_rxbound, &rxdone) != 0)
+ if (dhdsdio_readframes(bus, dhd_rxbound, &rxdone) != 0) {
resched = TRUE;
+#ifdef DEBUG_DPC_THREAD_WATCHDOG
+ is_resched_by_readframe = TRUE;
+#endif /* DEBUG_DPC_THREAD_WATCHDOG */
+ }
}
dhd_os_sdunlock(bus->dhd);
+#ifdef DEBUG_DPC_THREAD_WATCHDOG
+ if (bus->dhd->dhd_bug_on) {
+ DHD_INFO(("%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 /* DEBUG_DPC_THREAD_WATCHDOG */
return resched;
}
DHD_ERROR(("dhdsdio_isr() w/o interrupt configured!\n"));
}
-#if !defined(NDISVER) || (NDISVER < 0x0630)
bcmsdh_intr_disable(sdh);
-#endif /* !defined(NDISVER) || (NDISVER < 0x0630) */
bus->intdis = TRUE;
#if defined(SDIO_ISR_THREAD)
}
DHD_OS_WAKE_UNLOCK(bus->dhd);
#else
-
-#if !defined(NDISVER) || (NDISVER < 0x0630)
bus->dpc_sched = TRUE;
dhd_sched_dpc(bus->dhd);
-#endif /* !defined(NDISVER) || (NDISVER < 0x0630) */
#endif /* defined(SDIO_ISR_THREAD) */
}
+#ifdef PKT_STATICS
+void dhdsdio_txpktstatics(void)
+{
+ uint total, f1, f2, f3, f4;
+ printf("Randy: TYPE EVENT: %d pkts (size=%d) transfered\n", tx_statics.event_count, tx_statics.event_size);
+ printf("Randy: TYPE CTRL: %d pkts (size=%d) transfered\n", tx_statics.ctrl_count, tx_statics.ctrl_size);
+ printf("Randy: TYPE DATA: %d pkts (size=%d) transfered\n", tx_statics.data_count, tx_statics.data_size);
+ if(tx_statics.glom_1_count || tx_statics.glom_3_count || tx_statics.glom_3_8_count || tx_statics.glom_8_count) {
+ total = tx_statics.glom_1_count + tx_statics.glom_3_count + tx_statics.glom_3_8_count + tx_statics.glom_8_count;
+ f1 = (tx_statics.glom_1_count*100) / total;
+ f2 = (tx_statics.glom_3_count*100) / total;
+ f3 = (tx_statics.glom_3_8_count*100) / total;
+ f4 = (tx_statics.glom_8_count*100) / total;
+ printf("Randy: glomsize==1: %d(%d), tglomsize==2: %d(%d), pkts 3<=glomsize<8: %d(%d), pkts glomszie>=8: %d(%d)\n",
+ tx_statics.glom_1_count, f1, tx_statics.glom_3_count, f2, tx_statics.glom_3_8_count, f3, tx_statics.glom_8_count, f4);
+ printf("Randy: data/glom=%d, glom_max=%d\n", tx_statics.data_count/total, tx_statics.glom_max);
+ }
+ printf("Randy: TYPE RX GLOM: %d pkts (size=%d) transfered\n", tx_statics.glom_count, tx_statics.glom_size);
+ printf("Randy: TYPE TEST: %d pkts (size=%d) transfered\n\n\n", tx_statics.test_count, tx_statics.test_size);
+}
+#endif
+
#ifdef SDTEST
static void
dhdsdio_pktgen_init(dhd_bus_t *bus)
bus->lastintrs = bus->intrcount;
}
+ if ((!bus->dpc_sched) && pktq_len(&bus->txq)) {
+ bus->dpc_sched = TRUE;
+ dhd_sched_dpc(bus->dhd);
+ }
+
#ifdef DHD_DEBUG
/* Poll for console output periodically */
if (dhdp->busstate == DHD_BUS_DATA && dhd_console_ms != 0) {
if ((bus->idletime > 0) && (bus->idlecount >= bus->idletime)) {
DHD_TIMER(("%s: DHD Idle state!!\n", __FUNCTION__));
- if (SLPAUTO_ENAB(bus)) {
+ if (!bus->poll && SLPAUTO_ENAB(bus)) {
if (dhdsdio_bussleep(bus, TRUE) != BCME_BUSY)
dhd_os_wd_timer(bus->dhd, 0);
} else
bus->idlecount = 0;
if (bus->activity) {
bus->activity = FALSE;
- if (SLPAUTO_ENAB(bus)) {
+ if (!bus->poll && SLPAUTO_ENAB(bus)) {
if (!bus->readframes)
dhdsdio_bussleep(bus, TRUE);
else
return TRUE;
if (chipid == BCM43349_CHIP_ID)
return TRUE;
- if (chipid == BCM4345_CHIP_ID)
+ if (chipid == BCM4345_CHIP_ID || chipid == BCM43454_CHIP_ID)
return TRUE;
if (chipid == BCM4350_CHIP_ID)
return TRUE;
{
int ret;
dhd_bus_t *bus;
+#ifdef GET_OTP_MAC_ENABLE
struct ether_addr ea_addr;
+#endif
#if defined(MULTIPLE_SUPPLICANT)
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
sd1idle = TRUE;
dhd_readahead = TRUE;
retrydata = FALSE;
-#if !defined(PLATFORM_MPS)
+
+#ifdef DISABLE_FLOW_CONTROL
dhd_doflow = FALSE;
-#else
- dhd_doflow = TRUE;
-#endif /* OEM_ANDROID */
+#endif /* DISABLE_FLOW_CONTROL */
dhd_dongle_ramsize = 0;
dhd_txminmax = DHD_TXMINMAX;
bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1;
bus->usebufpool = FALSE; /* Use bufpool if allocated, else use locally malloced rxbuf */
+#if defined(SUPPORT_P2P_GO_PS)
+ init_waitqueue_head(&bus->bus_sleep);
+#endif /* LINUX && SUPPORT_P2P_GO_PS */
+
/* attempt to attach to the dongle */
if (!(dhdsdio_probe_attach(bus, osh, sdh, regsva, devid))) {
DHD_ERROR(("%s: dhdsdio_probe_attach failed\n", __FUNCTION__));
goto fail;
}
}
+ else {
+ /* Set random 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
#ifdef GET_OTP_MAC_ENABLE
goto fail;
}
+#ifdef 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 /* BCM4330_CHIP */
+#endif /* BCMHOST_XTAL_PU_TIME_MOD */
#if defined(MULTIPLE_SUPPLICANT)
wl_android_post_init(); // terence 20120530: fix critical section in dhd_open and dhdsdio_probe
#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
#endif
- init_waitqueue_head(&bus->bus_sleep);
-
return bus;
fail:
return NULL;
}
-#ifdef REGON_BP_HANG_FIX
-static int dhd_sdio_backplane_reset(struct dhd_bus *bus)
-{
- uint32 temp = 0;
- DHD_ERROR(("Resetting the backplane to avoid failure in firmware download..\n"));
-
- temp = bcmsdh_reg_read(bus->sdh, 0x180021e0, 4);
- DHD_INFO(("SDIO Clk Control Reg = %x\n", temp));
-
- /* Force HT req from PMU */
- bcmsdh_reg_write(bus->sdh, 0x18000644, 4, 0x6000005);
-
- /* Increase the clock stretch duration. */
- bcmsdh_reg_write(bus->sdh, 0x18000630, 4, 0xC8FFC8);
-
- /* Setting ALP clock request in SDIOD clock control status register */
- bcmsdh_reg_write(bus->sdh, 0x180021e0, 4, 0x41);
-
- /* Allowing clock from SR engine to SR memory */
- bcmsdh_reg_write(bus->sdh, 0x18004400, 4, 0xf92f1);
- /* Disabling SR Engine before SR binary download. */
- bcmsdh_reg_write(bus->sdh, 0x18000650, 4, 0x3);
- bcmsdh_reg_write(bus->sdh, 0x18000654, 4, 0x0);
-
- /* Enabling clock from backplane to SR memory */
- bcmsdh_reg_write(bus->sdh, 0x18004400, 4, 0xf9af1);
-
- /* Initializing SR memory address register in SOCRAM */
- bcmsdh_reg_write(bus->sdh, 0x18004408, 4, 0x0);
-
- /* Downloading the SR binary */
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0xc0002000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x80008000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x1051f080);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x80008000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x1050f080);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x80008000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x1050f080);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x80008000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x1050f080);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000004);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000604);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00001604);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00001404);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a08c80);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010001);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x14a00000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00011404);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00002000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x04a00000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00002000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0xf8000000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00002000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x04a00000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00002000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0xf8000000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00011604);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010604);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010004);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x14a00000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000004);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010001);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x14a00000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010004);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00010000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x14a00000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x30a00000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000008);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x04a00000);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0x00000008);
- bcmsdh_reg_write(bus->sdh, 0x1800440c, 4, 0xfc000000);
- /* SR Binary Download complete */
-
- /* Allowing clock from SR engine to SR memory */
- bcmsdh_reg_write(bus->sdh, 0x18004400, 4, 0xf92f1);
-
- /* Turning ON SR Engine to initiate backplane reset Repeated ?? Maharana */
- bcmsdh_reg_write(bus->sdh, 0x18000650, 4, 0x3);
- bcmsdh_reg_write(bus->sdh, 0x18000654, 4, 0x0);
- bcmsdh_reg_write(bus->sdh, 0x18000650, 4, 0x3);
- bcmsdh_reg_write(bus->sdh, 0x18000654, 4, 0x2);
- bcmsdh_reg_write(bus->sdh, 0x18000650, 4, 0x3);
- bcmsdh_reg_write(bus->sdh, 0x18000654, 4, 0x3);
- bcmsdh_reg_write(bus->sdh, 0x18000650, 4, 0x3);
- bcmsdh_reg_write(bus->sdh, 0x18000654, 4, 0x37);
- bcmsdh_reg_write(bus->sdh, 0x18000650, 4, 0x3);
- temp = bcmsdh_reg_read(bus->sdh, 0x18000654, 4);
- DHD_INFO(("0x18000654 = %x\n", temp));
- bcmsdh_reg_write(bus->sdh, 0x18000654, 4, 0x800037);
- OSL_DELAY(100000);
- /* Rolling back the original values for clock stretch and PMU timers */
- bcmsdh_reg_write(bus->sdh, 0x18000644, 4, 0x0);
- bcmsdh_reg_write(bus->sdh, 0x18000630, 4, 0xC800C8);
- /* Removing ALP clock request in SDIOD clock control status register */
- bcmsdh_reg_write(bus->sdh, 0x180021e0, 4, 0x40);
- OSL_DELAY(10000);
- return TRUE;
-}
-
-static int dhdsdio_sdio_hang_war(struct dhd_bus *bus)
-{
- uint32 temp = 0, temp2 = 0, counter = 0, BT_pwr_up = 0, BT_ready = 0;
- /* Removing reset of D11 Core */
- bcmsdh_reg_write(bus->sdh, 0x18101408, 4, 0x3);
- bcmsdh_reg_write(bus->sdh, 0x18101800, 4, 0x0);
- bcmsdh_reg_write(bus->sdh, 0x18101408, 4, 0x1);
- /* Reading CLB XTAL BT cntrl register */
- bcmsdh_reg_write(bus->sdh, 0x180013D8, 2, 0xD1);
- bcmsdh_reg_write(bus->sdh, 0x180013DA, 2, 0x12);
- bcmsdh_reg_write(bus->sdh, 0x180013D8, 2, 0x2D0);
- /* Read if BT is powered up */
- temp = bcmsdh_reg_read(bus->sdh, 0x180013DA, 2);
- /* Read BT_ready from WLAN wireless register */
- temp2 = bcmsdh_reg_read(bus->sdh, 0x1800002C, 4);
- /*
- Check if the BT is powered up and ready. The duration between BT being powered up
- and BT becoming ready is the problematic window for WLAN. If we move ahead at this
- time then we may encounter a corrupted backplane later. So we wait for BT to be ready
- and then proceed after checking the health of the backplane. If the backplane shows
- indications of failure then we have to do a full reset of the backplane using SR engine
- and then proceed.
- */
- (temp & 0xF0) ? (BT_pwr_up = 1):(BT_pwr_up = 0);
- (temp2 & (1<<17)) ? (BT_ready = 1):(BT_ready = 0);
- DHD_ERROR(("WARNING: Checking if BT is ready BT_pwr_up = %x"
- "BT_ready = %x \n", BT_pwr_up, BT_ready));
- while (BT_pwr_up && !BT_ready)
- {
- OSL_DELAY(1000);
- bcmsdh_reg_write(bus->sdh, 0x180013D8, 2, 0x2D0);
- temp = bcmsdh_reg_read(bus->sdh, 0x180013DA, 2);
- temp2 = bcmsdh_reg_read(bus->sdh, 0x1800002C, 4);
- (temp & 0xF0) ? (BT_pwr_up = 1):(BT_pwr_up = 0);
- (temp2 & (1<<17)) ? (BT_ready = 1):(BT_ready = 0);
- counter++;
- if (counter == 5000)
- {
- DHD_ERROR(("WARNING: Going ahead after 5 secs with"
- "risk of failure because BT ready is not yet set\n"));
- break;
- }
- }
- DHD_ERROR(("\nWARNING: WL Proceeding BT_pwr_up = %x BT_ready = %x"
- "\n", BT_pwr_up, BT_ready));
- counter = 0;
- OSL_DELAY(10000);
- /*
- Get the information of who accessed the crucial backplane entities
- by reading read and write access registers
- */
- DHD_TRACE(("%d: Read Value @ 0x18104808 = %x."
- "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18104808, 4)));
- DHD_TRACE(("%d: Read Value @ 0x1810480C = %x."
- "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810480C, 4)));
- DHD_TRACE(("%d: Read Value @ 0x18106808 = %x."
- "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18106808, 4)));
- DHD_TRACE(("%d: Read Value @ 0x1810680C = %x."
- "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810680C, 4)));
- DHD_TRACE(("%d: Read Value @ 0x18107808 = %x."
- "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18107808, 4)));
- DHD_TRACE(("%d: Read Value @ 0x1810780C = %x."
- "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810780C, 4)));
- DHD_TRACE(("%d: Read Value @ 0x18108808 = %x."
- "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18108808, 4)));
- DHD_TRACE(("%d: Read Value @ 0x1810880C = %x."
- "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810880C, 4)));
- DHD_TRACE(("%d: Read Value @ 0x18109808 = %x."
- "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18109808, 4)));
- DHD_TRACE(("%d: Read Value @ 0x1810980C = %x."
- "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810980C, 4)));
- DHD_TRACE(("%d: Read Value @ 0x1810C808 = %x."
- "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810c808, 4)));
- DHD_TRACE(("%d: Read Value @ 0x1810C80C = %x."
- "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810c80C, 4)));
- counter = 0;
- while ((bcmsdh_reg_read(bus->sdh, 0x18104808, 4) == 5) ||
- (bcmsdh_reg_read(bus->sdh, 0x1810480C, 4) == 5) ||
- (bcmsdh_reg_read(bus->sdh, 0x18106808, 4) == 5) ||
- (bcmsdh_reg_read(bus->sdh, 0x1810680C, 4) == 5) ||
- (bcmsdh_reg_read(bus->sdh, 0x1810780C, 4) == 5) ||
- (bcmsdh_reg_read(bus->sdh, 0x1810780C, 4) == 5) ||
- (bcmsdh_reg_read(bus->sdh, 0x1810880C, 4) == 5) ||
- (bcmsdh_reg_read(bus->sdh, 0x1810880C, 4) == 5) ||
- (bcmsdh_reg_read(bus->sdh, 0x1810980C, 4) == 5) ||
- (bcmsdh_reg_read(bus->sdh, 0x1810980C, 4) == 5) ||
- (bcmsdh_reg_read(bus->sdh, 0x1810C80C, 4) == 5) ||
- (bcmsdh_reg_read(bus->sdh, 0x1810C80C, 4) == 5))
- {
- if (++counter > 10)
- {
- DHD_ERROR(("Unable to recover the backkplane corruption"
- "..Tried %d times.. Exiting\n", counter));
- break;
- }
- OSL_DELAY(10000);
- dhd_sdio_backplane_reset(bus);
- /*
- Get the information of who accessed the crucial backplane
- entities by reading read and write access registers
- */
- DHD_ERROR(("%d: Read Value @ 0x18104808 = %x."
- "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18104808, 4)));
- DHD_ERROR(("%d: Read Value @ 0x1810480C = %x."
- "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810480C, 4)));
- DHD_ERROR(("%d: Read Value @ 0x18106808 = %x."
- "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18106808, 4)));
- DHD_ERROR(("%d: Read Value @ 0x1810680C = %x."
- "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810680C, 4)));
- DHD_ERROR(("%d: Read Value @ 0x18107808 = %x."
- "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18107808, 4)));
- DHD_ERROR(("%d: Read Value @ 0x1810780C = %x."
- "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810780C, 4)));
- DHD_ERROR(("%d: Read Value @ 0x18108808 = %x."
- "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18108808, 4)));
- DHD_ERROR(("%d: Read Value @ 0x1810880C = %x."
- "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810880C, 4)));
- DHD_ERROR(("%d: Read Value @ 0x18109808 = %x."
- "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x18109808, 4)));
- DHD_ERROR(("%d: Read Value @ 0x1810980C = %x."
- "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810980C, 4)));
- DHD_ERROR(("%d: Read Value @ 0x1810C808 = %x."
- "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810c808, 4)));
- DHD_ERROR(("%d: Read Value @ 0x1810C80C = %x."
- "\n", __LINE__, bcmsdh_reg_read(bus->sdh, 0x1810c80C, 4)));
- }
- /* Set the WL ready to indicate BT that we are done with backplane reset */
- DHD_ERROR(("Setting up AXI_OK\n"));
- bcmsdh_reg_write(bus->sdh, 0x18000658, 4, 0x3);
- temp = bcmsdh_reg_read(bus->sdh, 0x1800065c, 4);
- temp |= 0x80000000;
- bcmsdh_reg_write(bus->sdh, 0x1800065c, 4, temp);
- return TRUE;
-}
-#endif /* REGON_BP_HANG_FIX */
static bool
dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva,
uint16 devid)
DHD_ERROR(("%s: FAILED to return to SI_ENUM_BASE\n", __FUNCTION__));
}
-#if defined(DHD_DEBUG)
+#if defined(DHD_DEBUG) && !defined(CUSTOMER_HW4_DEBUG)
DHD_ERROR(("F1 signature read @0x18000000=0x%4x\n",
bcmsdh_reg_read(bus->sdh, SI_ENUM_BASE, 4)));
-#endif
+#endif /* DHD_DEBUG && !CUSTOMER_HW4_DEBUG */
/* Force PLL off until si_attach() programs PLL control regs */
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))
- dhdsdio_sdio_hang_war(bus);
-#endif /* REGON_BP_HANG_FIX */
bcmsdh_chipinfo(sdh, bus->sih->chip, bus->sih->chiprev);
bus->dongle_ram_base = CR4_4360_RAM_BASE;
break;
case BCM4345_CHIP_ID:
+ case BCM43454_CHIP_ID:
bus->dongle_ram_base = (bus->sih->chiprev < 6) /* from 4345C0 */
? CR4_4345_LT_C0_RAM_BASE : CR4_4345_GE_C0_RAM_BASE;
break;
case BCM4349_CHIP_GRPID:
- bus->dongle_ram_base = CR4_4349_RAM_BASE;
+ /* RAM base changed from 4349c0(revid=9) onwards */
+ bus->dongle_ram_base = ((bus->sih->chiprev < 9) ?
+ CR4_4349_RAM_BASE: CR4_4349_RAM_BASE_FROM_REV_9);
break;
default:
bus->dongle_ram_base = 0;
__FUNCTION__, (bus->sd_rxchain ? "supports" : "does not support")));
}
bus->use_rxchain = (bool)bus->sd_rxchain;
- if (bus->dhd->conf->use_rxchain >= 0) {
- printf("%s: set use_rxchain %d from config.txt\n", __FUNCTION__, bus->dhd->conf->use_rxchain);
- bus->use_rxchain = (bool)bus->dhd->conf->use_rxchain;
- }
- /* Setting default Glom size */
- if (bus->dhd->conf->txglomsize >= 0) {
- printf("%s: set txglomsize %d from config.txt\n", __FUNCTION__, bus->dhd->conf->txglomsize);
- bus->txglomsize = bus->dhd->conf->txglomsize;
- }
bus->txinrx_thres = CUSTOM_TXINRX_THRES;
/* TX first in dhdsdio_readframes() */
bus->dotxinrx = TRUE;
+#ifdef PKT_STATICS
+ memset((uint8*) &tx_statics, 0, sizeof(pkt_statics_t));
+#endif
+
return TRUE;
}
{
int ret;
+
DHD_TRACE_HW4(("%s: firmware path=%s, nvram path=%s\n",
__FUNCTION__, bus->fw_path, bus->nv_path));
DHD_OS_WAKE_LOCK(bus->dhd);
/* External conf takes precedence if specified */
dhd_conf_preinit(bus->dhd);
dhd_conf_read_config(bus->dhd, bus->dhd->conf_path);
- dhd_conf_set_fw_name_by_chip(bus->dhd, bus->fw_path, bus->nv_path);
+ dhd_conf_set_fw_name_by_chip(bus->dhd, bus->fw_path);
dhd_conf_set_nv_name_by_chip(bus->dhd, bus->nv_path);
dhd_conf_set_fw_name_by_mac(bus->dhd, bus->sdh, bus->fw_path);
dhd_conf_set_nv_name_by_mac(bus->dhd, bus->sdh, bus->nv_path);
+ if (bus->dhd->conf->dhd_poll >= 0) {
+ printf("%s: set polling mode %d\n", __FUNCTION__, bus->dhd->conf->dhd_poll);
+ bus->poll = TRUE;
+ if (!bus->pollrate)
+ bus->pollrate = 1;
+ }
+ if (bus->dhd->conf->use_rxchain >= 0) {
+ printf("%s: set use_rxchain %d\n", __FUNCTION__, bus->dhd->conf->use_rxchain);
+ bus->use_rxchain = (bool)bus->dhd->conf->use_rxchain;
+ }
+ if (bus->dhd->conf->txglomsize >= 0) {
+ printf("%s: set txglomsize %d\n", __FUNCTION__, bus->dhd->conf->txglomsize);
+ bus->txglomsize = bus->dhd->conf->txglomsize;
+ }
+ bcmsdh_set_mode(sdh, bus->dhd->conf->txglom_mode);
printf("Final fw_path=%s\n", bus->fw_path);
printf("Final nv_path=%s\n", bus->nv_path);
int ret = 0;
dhd_bus_t *bus = (dhd_bus_t*)context;
+#ifdef SUPPORT_P2P_GO_PS
int wait_time = 0;
+
if (bus->idletime > 0) {
wait_time = msecs_to_jiffies(bus->idletime * dhd_watchdog_ms);
}
-
+#endif /* SUPPORT_P2P_GO_PS */
ret = dhd_os_check_wakelock(bus->dhd);
+#ifdef SUPPORT_P2P_GO_PS
// terence 20141124: fix for suspend issue
- if (SLPAUTO_ENAB(bus) && (!ret) && (bus->dhd->up)) {
+ if (SLPAUTO_ENAB(bus) && (!ret) && (bus->dhd->up) && (bus->dhd->op_mode != DHD_FLAG_HOSTAP_MODE)) {
if (wait_event_timeout(bus->bus_sleep, bus->sleeping, wait_time) == 0) {
if (!bus->sleeping) {
return 1;
}
}
}
+#endif /* SUPPORT_P2P_GO_PS */
return ret;
}
// terence 20150412: fix for firmware failed to download
if (bus->dhd->conf->chip == BCM43340_CHIP_ID ||
bus->dhd->conf->chip == BCM43341_CHIP_ID) {
- if (len%64 != 0) {
- memset(memptr+len, 0, len%64);
- len += (64 - len%64);
- }
+ if (len%64 != 0) {
+ memset(memptr+len, 0, len%64);
+ len += (64 - len%64);
+ }
}
if (len < 0) {
DHD_ERROR(("%s: dhd_os_get_image_block failed (%d)\n", __FUNCTION__, len));
return bcmerror;
}
-/*
- EXAMPLE: nvram_array
- nvram_arry format:
- name=value
- Use carriage return at the end of each assignment, and an empty string with
- carriage return at the end of array.
-
- For example:
- unsigned char nvram_array[] = {"name1=value1\n", "name2=value2\n", "\n"};
- Hex values start with 0x, and mac addr format: xx:xx:xx:xx:xx:xx.
-
- Search "EXAMPLE: nvram_array" to see how the array is activated.
-*/
-
-void
-dhd_bus_set_nvram_params(struct dhd_bus * bus, const char *nvram_params)
-{
- bus->nvram_params = nvram_params;
-}
-
static int
dhdsdio_download_nvram(struct dhd_bus *bus)
{
pnv_path = bus->nv_path;
nvram_file_exists = ((pnv_path != NULL) && (pnv_path[0] != '\0'));
- if (!nvram_file_exists && (bus->nvram_params == NULL))
- return (0);
+ /* For Get nvram from UEFI */
if (nvram_file_exists) {
image = dhd_os_open_image(pnv_path);
if (image == NULL) {
goto err;
}
- /* Download variables */
- if (nvram_file_exists) {
- len = dhd_os_get_image_block(memblock, MAX_NVRAMBUF_SIZE, image);
- }
- else {
- len = strlen(bus->nvram_params);
- ASSERT(len <= MAX_NVRAMBUF_SIZE);
- memcpy(memblock, bus->nvram_params, len);
- }
+ /* For Get nvram from image or UEFI (when image == NULL ) */
+ len = dhd_os_get_image_block(memblock, MAX_NVRAMBUF_SIZE, image);
+
if (len > 0 && len < MAX_NVRAMBUF_SIZE) {
bufp = (char *)memblock;
bufp[len] = 0;
goto err;
}
- /* EXAMPLE: nvram_array */
- /* If a valid nvram_arry is specified as above, it can be passed down to dongle */
- /* dhd_bus_set_nvram_params(bus, (char *)&nvram_array); */
-
/* External nvram takes precedence if specified */
if (dhdsdio_download_nvram(bus)) {
DHD_ERROR(("%s: dongle nvram file download failed\n", __FUNCTION__));
return ret;
}
+uint8
+dhd_bus_is_ioready(struct dhd_bus *bus)
+{
+ uint8 enable;
+ bcmsdh_info_t *sdh;
+ ASSERT(bus);
+ ASSERT(bus->sih != NULL);
+ enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2);
+ sdh = bus->sdh;
+ return (enable == bcmsdh_cfg_read(sdh, SDIO_FUNC_0, SDIOD_CCCR_IORDY, NULL));
+}
+
uint
dhd_bus_chip(struct dhd_bus *bus)
{
bcmsdh_oob_intr_register(bus->sdh,
dhdsdio_isr, bus);
bcmsdh_oob_intr_set(bus->sdh, TRUE);
+#elif defined(FORCE_WOWLAN)
+ dhd_enable_oob_intr(bus, TRUE);
#endif
bus->dhd->dongle_reset = FALSE;
dhdsdio_release_dongle(bus, bus->dhd->osh,
TRUE, FALSE);
}
- } else
+ } else {
+ DHD_ERROR(("%s Failed to download binary to the dongle\n",
+ __FUNCTION__));
+ if (bus->sih != NULL) {
+ si_detach(bus->sih);
+ bus->sih = NULL;
+ }
bcmerror = BCME_SDIO_ERROR;
+ }
} else
bcmerror = BCME_SDIO_ERROR;
__FUNCTION__);
printf("Will call dhd_bus_start instead\n");
dhd_bus_resume(dhdp, 1);
-#if defined(HW_OOB)
+#if defined(HW_OOB) || defined(FORCE_WOWLAN)
dhd_conf_set_hw_oob_intr(bus->sdh, bus->sih->chip); // terence 20120615: fix for OOB initial issue
#endif
if ((bcmerror = dhd_bus_start(dhdp)) != 0)
__FUNCTION__, bcmerror));
}
}
+
+#ifdef PKT_STATICS
+ memset((uint8*) &tx_statics, 0, sizeof(pkt_statics_t));
+#endif
return bcmerror;
}
return dhdsdio_membytes(bus, set, address, data, size);
}
-#if defined(NDISVER) && (NDISVER >= 0x0630)
-void
-dhd_bus_reject_ioreqs(dhd_pub_t *dhdp, bool reject)
-{
-
- DHD_TRACE(("%s: Enter\n", __FUNCTION__));
-
- bcmsdh_reject_ioreqs(dhdp->bus->sdh, reject);
-}
-
-void
-dhd_bus_waitfor_iodrain(dhd_pub_t *dhdp)
-{
-
- DHD_TRACE(("%s: Enter\n", __FUNCTION__));
-
- bcmsdh_waitfor_iodrain(dhdp->bus->sdh);
-}
-#endif /* (NDISVER) && (NDISVER >= 0x0630) */
void
dhd_bus_update_fw_nv_path(struct dhd_bus *bus, char *pfw_path, char *pnv_path, char *pconf_path)
dhd_os_sdunlock(bus->dhd);
}
#endif /* DEBUGGER */
-
-#if defined(SOFTAP_TPUT_ENHANCE)
-void dhd_bus_setidletime(dhd_pub_t *dhdp, int idle_time)
-{
- if (!dhdp || !dhdp->bus) {
- DHD_ERROR(("%s:Bus is Invalid\n", __FUNCTION__));
- return;
- }
- dhdp->bus->idletime = idle_time;
-}
-
-void dhd_bus_getidletime(dhd_pub_t *dhdp, int* idle_time)
-{
- if (!dhdp || !dhdp->bus) {
- DHD_ERROR(("%s:Bus is Invalid\n", __FUNCTION__));
- return;
- }
-
- if (!idle_time) {
- DHD_ERROR(("%s:Arg idle_time is NULL\n", __FUNCTION__));
- return;
- }
- *idle_time = dhdp->bus->idletime;
-}
-#endif /* SOFTAP_TPUT_ENHANCE */