build/patch/kernel/sun8i-default/m2-update-bcmdhd-driver.patch

40326 lines
1.1 MiB

diff -Nur a/drivers/net/wireless/bcmdhd/aiutils.c c/drivers/net/wireless/bcmdhd/aiutils.c
--- a/drivers/net/wireless/bcmdhd/aiutils.c 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/aiutils.c 2016-05-13 09:48:20.000000000 +0200
@@ -1094,4 +1094,4 @@
R_REG(osh, &ai->itcr));
}
}
-#endif
+#endif
diff -Nur a/drivers/net/wireless/bcmdhd/bcmevent.c c/drivers/net/wireless/bcmdhd/bcmevent.c
--- a/drivers/net/wireless/bcmdhd/bcmevent.c 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/bcmevent.c 2016-05-13 09:48:20.000000000 +0200
@@ -2,7 +2,7 @@
* bcmevent read-only data shared by kernel or app layers
*
* $Copyright Open Broadcom Corporation$
- * $Id: bcmevent.c 487838 2014-06-27 05:51:44Z $
+ * $Id: bcmevent.c 492377 2014-07-21 19:54:06Z $
*/
#include <typedefs.h>
@@ -90,19 +90,6 @@
BCMEVENT_NAME(WLC_E_ACTION_FRAME_RX),
BCMEVENT_NAME(WLC_E_ACTION_FRAME_COMPLETE),
#endif
-#if 0 && (NDISVER >= 0x0620)
- BCMEVENT_NAME(WLC_E_PRE_ASSOC_IND),
- BCMEVENT_NAME(WLC_E_PRE_REASSOC_IND),
- BCMEVENT_NAME(WLC_E_CHANNEL_ADOPTED),
- BCMEVENT_NAME(WLC_E_AP_STARTED),
- BCMEVENT_NAME(WLC_E_DFS_AP_STOP),
- BCMEVENT_NAME(WLC_E_DFS_AP_RESUME),
- BCMEVENT_NAME(WLC_E_ASSOC_IND_NDIS),
- BCMEVENT_NAME(WLC_E_REASSOC_IND_NDIS),
- BCMEVENT_NAME(WLC_E_ACTION_FRAME_RX_NDIS),
- BCMEVENT_NAME(WLC_E_AUTH_REQ),
- BCMEVENT_NAME(WLC_E_IBSS_COALESCE),
-#endif
#ifdef BCMWAPI_WAI
BCMEVENT_NAME(WLC_E_WAI_STA_EVENT),
BCMEVENT_NAME(WLC_E_WAI_MSG),
diff -Nur a/drivers/net/wireless/bcmdhd/bcmsdh.c c/drivers/net/wireless/bcmdhd/bcmsdh.c
--- a/drivers/net/wireless/bcmdhd/bcmsdh.c 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/bcmsdh.c 2016-05-13 09:48:20.000000000 +0200
@@ -36,7 +36,7 @@
extern SDIOH_API_RC sdioh_detach(osl_t *osh, sdioh_info_t *sd);
#endif
-#if defined(OOB_INTR_ONLY) && defined(HW_OOB)
+#if defined(OOB_INTR_ONLY) && defined(HW_OOB) || defined(FORCE_WOWLAN)
extern int
sdioh_enable_hw_oob_intr(void *sdioh, bool enable);
@@ -696,3 +696,64 @@
return sdioh_gpioout(sd, gpio, enab);
}
+
+uint
+bcmsdh_set_mode(void *sdh, uint mode)
+{
+ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
+ return (sdioh_set_mode(bcmsdh->sdioh, mode));
+}
+
+#if defined(SWTXGLOM)
+int
+bcmsdh_send_swtxglom_buf(void *sdh, uint32 addr, uint fn, uint flags,
+ uint8 *buf, uint nbytes, void *pkt,
+ bcmsdh_cmplt_fn_t complete_fn, void *handle)
+{
+ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
+ SDIOH_API_RC status;
+ uint incr_fix;
+ uint width;
+ int err = 0;
+
+ ASSERT(bcmsdh);
+ ASSERT(bcmsdh->init_success);
+
+ BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, size = %d\n",
+ __FUNCTION__, fn, addr, nbytes));
+
+ /* Async not implemented yet */
+ ASSERT(!(flags & SDIO_REQ_ASYNC));
+ if (flags & SDIO_REQ_ASYNC)
+ return BCME_UNSUPPORTED;
+
+ if ((err = bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, FALSE)))
+ return err;
+
+ addr &= SBSDIO_SB_OFT_ADDR_MASK;
+
+ incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC;
+ width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
+ if (width == 4)
+ addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
+
+ status = sdioh_request_swtxglom_buffer(bcmsdh->sdioh, SDIOH_DATA_PIO, incr_fix,
+ SDIOH_WRITE, fn, addr, width, nbytes, buf, pkt);
+
+ return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR);
+}
+
+void
+bcmsdh_glom_post(void *sdh, uint8 *frame, void *pkt, uint len)
+{
+ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
+ sdioh_glom_post(bcmsdh->sdioh, frame, pkt, len);
+}
+
+void
+bcmsdh_glom_clear(void *sdh)
+{
+ bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
+ sdioh_glom_clear(bcmsdh->sdioh);
+}
+#endif /* SWTXGLOM */
diff -Nur a/drivers/net/wireless/bcmdhd/bcmsdh_linux.c c/drivers/net/wireless/bcmdhd/bcmsdh_linux.c
--- a/drivers/net/wireless/bcmdhd/bcmsdh_linux.c 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/bcmsdh_linux.c 2016-05-13 09:48:20.000000000 +0200
@@ -319,10 +319,17 @@
SDLX_MSG(("%s: irq is already registered\n", __FUNCTION__));
return -EBUSY;
}
+#ifdef HW_OOB
+ printf("%s: HW_OOB enabled\n", __FUNCTION__);
+#else
+ printf("%s: SW_OOB enabled\n", __FUNCTION__);
+#endif
SDLX_MSG(("%s OOB irq=%d flags=%X\n", __FUNCTION__,
(int)bcmsdh_osinfo->oob_irq_num, (int)bcmsdh_osinfo->oob_irq_flags));
bcmsdh_osinfo->oob_irq_handler = oob_irq_handler;
bcmsdh_osinfo->oob_irq_handler_context = oob_irq_handler_context;
+ bcmsdh_osinfo->oob_irq_enabled = TRUE;
+ bcmsdh_osinfo->oob_irq_registered = TRUE;
#if defined(CONFIG_ARCH_ODIN)
err = odin_gpio_sms_request_irq(bcmsdh_osinfo->oob_irq_num, wlan_oob_irq,
bcmsdh_osinfo->oob_irq_flags, "bcmsdh_sdmmc", bcmsdh);
@@ -331,17 +338,15 @@
bcmsdh_osinfo->oob_irq_flags, "bcmsdh_sdmmc", bcmsdh);
#endif /* defined(CONFIG_ARCH_ODIN) */
if (err) {
+ bcmsdh_osinfo->oob_irq_enabled = FALSE;
+ bcmsdh_osinfo->oob_irq_registered = FALSE;
SDLX_MSG(("%s: request_irq failed with %d\n", __FUNCTION__, err));
return err;
}
#if defined(DISABLE_WOWLAN)
SDLX_MSG(("%s: disable_irq_wake\n", __FUNCTION__));
- err = disable_irq_wake(bcmsdh_osinfo->oob_irq_num);
- if (err)
- SDLX_MSG(("%s: disable_irq_wake failed with %d\n", __FUNCTION__, err));
- else
- bcmsdh_osinfo->oob_irq_wake_enabled = FALSE;
+ bcmsdh_osinfo->oob_irq_wake_enabled = FALSE;
#else
SDLX_MSG(("%s: enable_irq_wake\n", __FUNCTION__));
err = enable_irq_wake(bcmsdh_osinfo->oob_irq_num);
@@ -350,8 +355,6 @@
else
bcmsdh_osinfo->oob_irq_wake_enabled = TRUE;
#endif
- bcmsdh_osinfo->oob_irq_enabled = TRUE;
- bcmsdh_osinfo->oob_irq_registered = TRUE;
return 0;
}
diff -Nur a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c c/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c
--- a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c 2016-09-30 00:38:40.014529783 +0200
@@ -2,13 +2,13 @@
* BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel
*
* 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
* 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
@@ -16,7 +16,7 @@
* 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.
@@ -59,12 +59,20 @@
static void IRQHandlerF2(struct sdio_func *func);
#endif /* !defined(OOB_INTR_ONLY) */
static int sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, uint32 regaddr);
+#if defined(ENABLE_INSMOD_NO_FW_LOAD)
extern int sdio_reset_comm(struct mmc_card *card);
+#else
+int sdio_reset_comm(struct mmc_card *card)
+{
+ return 0;
+}
+#endif
#ifdef CONFIG_ARCH_SUNXI
extern int sunxi_mci_check_r1_ready(struct mmc_host* mmc, unsigned ms);
#endif
-
+#ifdef GLOBAL_SDMMC_INSTANCE
extern PBCMSDH_SDMMC_INSTANCE gInstance;
+#endif
#define DEFAULT_SDIO_F2_BLKSIZE 512
#ifndef CUSTOM_SDIO_F2_BLKSIZE
@@ -158,10 +166,16 @@
sd->fake_func0.num = 0;
sd->fake_func0.card = func->card;
sd->func[0] = &sd->fake_func0;
+#ifdef GLOBAL_SDMMC_INSTANCE
if (func->num == 2)
sd->func[1] = gInstance->func[1];
+#else
+ sd->func[1] = func->card->sdio_func[0];
+#endif
sd->func[2] = func->card->sdio_func[1];
+#ifdef GLOBAL_SDMMC_INSTANCE
sd->func[func->num] = func;
+#endif
sd->num_funcs = 2;
sd->sd_blockmode = TRUE;
sd->use_client_ints = TRUE;
@@ -184,6 +198,7 @@
sdio_claim_host(sd->func[2]);
sd->client_block_size[2] = sd_f2_blocksize;
+ printf("%s: set sd_f2_blocksize %d\n", __FUNCTION__, sd_f2_blocksize);
err_ret = sdio_set_block_size(sd->func[2], sd_f2_blocksize);
sdio_release_host(sd->func[2]);
if (err_ret) {
@@ -692,7 +707,7 @@
return bcmerror;
}
-#if defined(OOB_INTR_ONLY) && defined(HW_OOB)
+#if (defined(OOB_INTR_ONLY) && defined(HW_OOB)) || defined(FORCE_WOWLAN)
SDIOH_API_RC
sdioh_enable_hw_oob_intr(sdioh_info_t *sd, bool enable)
@@ -791,11 +806,16 @@
#ifdef CONFIG_ARCH_SUNXI
int ret = 0;
#endif
+ struct timespec now, before;
+
+ if (sd_msglevel && SDH_COST_VAL)
+ getnstimeofday(&before);
+
sd_info(("%s: rw=%d, func=%d, addr=0x%05x\n", __FUNCTION__, rw, func, regaddr));
DHD_PM_RESUME_WAIT(sdioh_request_byte_wait);
DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL);
- if(rw) { /* CMD52 Write */
+ if (rw) { /* CMD52 Write */
if (func == 0) {
/* Can only directly write to some F0 registers. Handle F2 enable
* as a special case.
@@ -880,16 +900,416 @@
#endif
if (err_ret) {
- if ((regaddr == 0x1001F) && ((err_ret == -ETIMEDOUT) || (err_ret == -EILSEQ))) {
+ if ((regaddr == 0x1001F) && ((err_ret == -ETIMEDOUT) || (err_ret == -EILSEQ)
+ || (err_ret == -EIO))) {
} else {
sd_err(("bcmsdh_sdmmc: Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n",
rw ? "Write" : "Read", func, regaddr, *byte, err_ret));
}
}
+ if (sd_msglevel && SDH_COST_VAL)
+ getnstimeofday(&now);
+ sd_cost(("%s: len=1 cost=%lds %luus\n", __FUNCTION__,
+ now.tv_sec-before.tv_sec, now.tv_nsec/1000-before.tv_nsec/1000));
+
+ return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL);
+}
+
+#if defined(SWTXGLOM)
+static INLINE int sdioh_request_packet_align(uint pkt_len, uint write, uint func, int blk_size)
+{
+ /* Align Patch */
+ if (!write || pkt_len < 32)
+ pkt_len = (pkt_len + 3) & 0xFFFFFFFC;
+ else if ((pkt_len > blk_size) && (pkt_len % blk_size)) {
+ if (func == SDIO_FUNC_2) {
+ sd_err(("%s: [%s] dhd_sdio must align %d bytes"
+ " packet larger than a %d bytes blk size by a blk size\n",
+ __FUNCTION__, write ? "W" : "R", pkt_len, blk_size));
+ }
+ pkt_len += blk_size - (pkt_len % blk_size);
+ }
+#ifdef CONFIG_MMC_MSM7X00A
+ if ((pkt_len % 64) == 32) {
+ sd_err(("%s: Rounding up TX packet +=32\n", __FUNCTION__));
+ pkt_len += 32;
+ }
+#endif /* CONFIG_MMC_MSM7X00A */
+ return pkt_len;
+}
+
+void
+sdioh_glom_post(sdioh_info_t *sd, uint8 *frame, void *pkt, uint len)
+{
+ void *phead = sd->glom_info.glom_pkt_head;
+ void *ptail = sd->glom_info.glom_pkt_tail;
+
+ BCM_REFERENCE(frame);
+
+ ASSERT(!PKTLINK(pkt));
+ if (!phead) {
+ ASSERT(!phead);
+ sd->glom_info.glom_pkt_head = sd->glom_info.glom_pkt_tail = pkt;
+ }
+ else {
+ ASSERT(ptail);
+ PKTSETNEXT(sd->osh, ptail, pkt);
+ sd->glom_info.glom_pkt_tail = pkt;
+ }
+ sd->glom_info.count++;
+}
+
+void
+sdioh_glom_clear(sdioh_info_t *sd)
+{
+ void *pnow, *pnext;
+
+ pnext = sd->glom_info.glom_pkt_head;
+
+ if (!pnext) {
+ sd_err(("sdioh_glom_clear: no first packet to clear!\n"));
+ return;
+ }
+
+ while (pnext) {
+ pnow = pnext;
+ pnext = PKTNEXT(sd->osh, pnow);
+ PKTSETNEXT(sd->osh, pnow, NULL);
+ sd->glom_info.count--;
+ }
+
+ sd->glom_info.glom_pkt_head = NULL;
+ sd->glom_info.glom_pkt_tail = NULL;
+ if (sd->glom_info.count != 0) {
+ sd_err(("sdioh_glom_clear: glom count mismatch!\n"));
+ sd->glom_info.count = 0;
+ }
+}
+
+static SDIOH_API_RC
+sdioh_request_swtxglom_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func,
+ uint addr, void *pkt)
+{
+ bool fifo = (fix_inc == SDIOH_DATA_FIX);
+ uint32 SGCount = 0;
+ int err_ret = 0;
+ void *pnext;
+ uint ttl_len, dma_len, lft_len, xfred_len, pkt_len;
+ uint blk_num;
+ int blk_size;
+ struct mmc_request mmc_req;
+ struct mmc_command mmc_cmd;
+ struct mmc_data mmc_dat;
+#ifdef BCMSDIOH_TXGLOM
+ uint8 *localbuf = NULL;
+ uint local_plen = 0;
+ bool need_txglom = write &&
+ (pkt == sd->glom_info.glom_pkt_tail) &&
+ (sd->glom_info.glom_pkt_head != sd->glom_info.glom_pkt_tail);
+#endif /* BCMSDIOH_TXGLOM */
+
+ sd_trace(("%s: Enter\n", __FUNCTION__));
+
+ ASSERT(pkt);
+ DHD_PM_RESUME_WAIT(sdioh_request_packet_wait);
+ DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL);
+
+ ttl_len = xfred_len = 0;
+#ifdef BCMSDIOH_TXGLOM
+ if (need_txglom) {
+ pkt = sd->glom_info.glom_pkt_head;
+ }
+#endif /* BCMSDIOH_TXGLOM */
+
+ /* at least 4 bytes alignment of skb buff is guaranteed */
+ for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext))
+ ttl_len += PKTLEN(sd->osh, pnext);
+
+ blk_size = sd->client_block_size[func];
+ if (((!write && sd->use_rxchain) ||
+#ifdef BCMSDIOH_TXGLOM
+ (need_txglom && sd->txglom_mode == SDPCM_TXGLOM_MDESC) ||
+#endif
+ 0) && (ttl_len >= blk_size)) {
+ blk_num = ttl_len / blk_size;
+ dma_len = blk_num * blk_size;
+ } else {
+ blk_num = 0;
+ dma_len = 0;
+ }
+
+ lft_len = ttl_len - dma_len;
+
+ sd_trace(("%s: %s %dB to func%d:%08x, %d blks with DMA, %dB leftover\n",
+ __FUNCTION__, write ? "W" : "R",
+ ttl_len, func, addr, blk_num, lft_len));
+
+ if (0 != dma_len) {
+ memset(&mmc_req, 0, sizeof(struct mmc_request));
+ memset(&mmc_cmd, 0, sizeof(struct mmc_command));
+ memset(&mmc_dat, 0, sizeof(struct mmc_data));
+
+ /* Set up DMA descriptors */
+ for (pnext = pkt;
+ pnext && dma_len;
+ pnext = PKTNEXT(sd->osh, pnext)) {
+ pkt_len = PKTLEN(sd->osh, pnext);
+
+ if (dma_len > pkt_len)
+ dma_len -= pkt_len;
+ else {
+ pkt_len = xfred_len = dma_len;
+ dma_len = 0;
+ pkt = pnext;
+ }
+
+ sg_set_buf(&sd->sg_list[SGCount++],
+ (uint8*)PKTDATA(sd->osh, pnext),
+ pkt_len);
+
+ if (SGCount >= SDIOH_SDMMC_MAX_SG_ENTRIES) {
+ sd_err(("%s: sg list entries exceed limit\n",
+ __FUNCTION__));
+ return (SDIOH_API_RC_FAIL);
+ }
+ }
+
+ mmc_dat.sg = sd->sg_list;
+ mmc_dat.sg_len = SGCount;
+ mmc_dat.blksz = blk_size;
+ mmc_dat.blocks = blk_num;
+ mmc_dat.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
+
+ mmc_cmd.opcode = 53; /* SD_IO_RW_EXTENDED */
+ mmc_cmd.arg = write ? 1<<31 : 0;
+ mmc_cmd.arg |= (func & 0x7) << 28;
+ mmc_cmd.arg |= 1<<27;
+ mmc_cmd.arg |= fifo ? 0 : 1<<26;
+ mmc_cmd.arg |= (addr & 0x1FFFF) << 9;
+ mmc_cmd.arg |= blk_num & 0x1FF;
+ mmc_cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC;
+
+ mmc_req.cmd = &mmc_cmd;
+ mmc_req.data = &mmc_dat;
+
+ sdio_claim_host(sd->func[func]);
+ mmc_set_data_timeout(&mmc_dat, sd->func[func]->card);
+ mmc_wait_for_req(sd->func[func]->card->host, &mmc_req);
+ sdio_release_host(sd->func[func]);
+
+ err_ret = mmc_cmd.error? mmc_cmd.error : mmc_dat.error;
+ if (0 != err_ret) {
+ sd_err(("%s:CMD53 %s failed with code %d\n",
+ __FUNCTION__,
+ write ? "write" : "read",
+ err_ret));
+ }
+ if (!fifo) {
+ addr = addr + ttl_len - lft_len - dma_len;
+ }
+ }
+
+ /* PIO mode */
+ if (0 != lft_len) {
+ /* Claim host controller */
+ sdio_claim_host(sd->func[func]);
+ for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext)) {
+ uint8 *buf = (uint8*)PKTDATA(sd->osh, pnext) +
+ xfred_len;
+ uint pad = 0;
+ pkt_len = PKTLEN(sd->osh, pnext);
+ if (0 != xfred_len) {
+ pkt_len -= xfred_len;
+ xfred_len = 0;
+ }
+#ifdef BCMSDIOH_TXGLOM
+ if (need_txglom) {
+ if (!localbuf) {
+ uint prev_lft_len = lft_len;
+ lft_len = sdioh_request_packet_align(lft_len, write,
+ func, blk_size);
+
+ if (lft_len > prev_lft_len) {
+ sd_err(("%s: padding is unexpected! lft_len %d,"
+ " prev_lft_len %d %s\n",
+ __FUNCTION__, lft_len, prev_lft_len,
+ write ? "Write" : "Read"));
+ }
+
+ localbuf = (uint8 *)MALLOC(sd->osh, lft_len);
+ if (localbuf == NULL) {
+ sd_err(("%s: %s TXGLOM: localbuf malloc FAILED\n",
+ __FUNCTION__, (write) ? "TX" : "RX"));
+ need_txglom = FALSE;
+ goto txglomfail;
+ }
+ }
+ bcopy(buf, (localbuf + local_plen), pkt_len);
+ local_plen += pkt_len;
+
+ if (PKTNEXT(sd->osh, pnext)) {
+ continue;
+ }
+
+ buf = localbuf;
+ pkt_len = local_plen;
+ }
+
+txglomfail:
+#endif /* BCMSDIOH_TXGLOM */
+
+ if (
+#ifdef BCMSDIOH_TXGLOM
+ !need_txglom &&
+#endif
+ TRUE) {
+ pkt_len = sdioh_request_packet_align(pkt_len, write,
+ func, blk_size);
+
+ pad = pkt_len - PKTLEN(sd->osh, pnext);
+
+ if (pad > 0) {
+ if (func == SDIO_FUNC_2) {
+ sd_err(("%s: padding is unexpected! pkt_len %d,"
+ " PKTLEN %d lft_len %d %s\n",
+ __FUNCTION__, pkt_len, PKTLEN(sd->osh, pnext),
+ lft_len, write ? "Write" : "Read"));
+ }
+ if (PKTTAILROOM(sd->osh, pkt) < pad) {
+ sd_info(("%s: insufficient tailroom %d, pad %d,"
+ " lft_len %d pktlen %d, func %d %s\n",
+ __FUNCTION__, (int)PKTTAILROOM(sd->osh, pkt),
+ pad, lft_len, PKTLEN(sd->osh, pnext), func,
+ write ? "W" : "R"));
+ if (PKTPADTAILROOM(sd->osh, pkt, pad)) {
+ sd_err(("%s: padding error size %d.\n",
+ __FUNCTION__, pad));
+ return SDIOH_API_RC_FAIL;
+ }
+ }
+ }
+ }
+
+ if ((write) && (!fifo))
+ err_ret = sdio_memcpy_toio(
+ sd->func[func],
+ addr, buf, pkt_len);
+ else if (write)
+ err_ret = sdio_memcpy_toio(
+ sd->func[func],
+ addr, buf, pkt_len);
+ else if (fifo)
+ err_ret = sdio_readsb(
+ sd->func[func],
+ buf, addr, pkt_len);
+ else
+ err_ret = sdio_memcpy_fromio(
+ sd->func[func],
+ buf, addr, pkt_len);
+
+ if (err_ret)
+ sd_err(("%s: %s FAILED %p[%d], addr=0x%05x, pkt_len=%d, ERR=%d\n",
+ __FUNCTION__,
+ (write) ? "TX" : "RX",
+ pnext, SGCount, addr, pkt_len, err_ret));
+ else
+ sd_trace(("%s: %s xfr'd %p[%d], addr=0x%05x, len=%d\n",
+ __FUNCTION__,
+ (write) ? "TX" : "RX",
+ pnext, SGCount, addr, pkt_len));
+
+ if (!fifo)
+ addr += pkt_len;
+ SGCount ++;
+ }
+ sdio_release_host(sd->func[func]);
+ }
+#ifdef BCMSDIOH_TXGLOM
+ if (localbuf)
+ MFREE(sd->osh, localbuf, lft_len);
+#endif /* BCMSDIOH_TXGLOM */
+
+ sd_trace(("%s: Exit\n", __FUNCTION__));
return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL);
}
+/*
+ * This function takes a buffer or packet, and fixes everything up so that in the
+ * end, a DMA-able packet is created.
+ *
+ * A buffer does not have an associated packet pointer, and may or may not be aligned.
+ * A packet may consist of a single packet, or a packet chain. If it is a packet chain,
+ * then all the packets in the chain must be properly aligned. If the packet data is not
+ * aligned, then there may only be one packet, and in this case, it is copied to a new
+ * aligned packet.
+ *
+ */
+extern SDIOH_API_RC
+sdioh_request_swtxglom_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint write, uint func,
+ uint addr, uint reg_width, uint buflen_u, uint8 *buffer, void *pkt)
+{
+ SDIOH_API_RC Status;
+ void *tmppkt;
+ void *orig_buf = NULL;
+ uint copylen = 0;
+
+ sd_trace(("%s: Enter\n", __FUNCTION__));
+
+ DHD_PM_RESUME_WAIT(sdioh_request_buffer_wait);
+ DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL);
+
+ if (pkt == NULL) {
+ /* Case 1: we don't have a packet. */
+ orig_buf = buffer;
+ copylen = buflen_u;
+ } else if ((ulong)PKTDATA(sd->osh, pkt) & DMA_ALIGN_MASK) {
+ /* Case 2: We have a packet, but it is unaligned.
+ * in this case, we cannot have a chain.
+ */
+ ASSERT(PKTNEXT(sd->osh, pkt) == NULL);
+
+ orig_buf = PKTDATA(sd->osh, pkt);
+ copylen = PKTLEN(sd->osh, pkt);
+ }
+
+ tmppkt = pkt;
+ if (copylen) {
+ tmppkt = PKTGET_STATIC(sd->osh, copylen, write ? TRUE : FALSE);
+ if (tmppkt == NULL) {
+ sd_err(("%s: PKTGET failed: len %d\n", __FUNCTION__, copylen));
+ return SDIOH_API_RC_FAIL;
+ }
+ /* For a write, copy the buffer data into the packet. */
+ if (write)
+ bcopy(orig_buf, PKTDATA(sd->osh, tmppkt), copylen);
+ }
+
+ Status = sdioh_request_swtxglom_packet(sd, fix_inc, write, func, addr, tmppkt);
+
+ if (copylen) {
+ /* For a read, copy the packet data back to the buffer. */
+ if (!write)
+ bcopy(PKTDATA(sd->osh, tmppkt), orig_buf, PKTLEN(sd->osh, tmppkt));
+ PKTFREE_STATIC(sd->osh, tmppkt, write ? TRUE : FALSE);
+ }
+
+ return (Status);
+}
+#endif
+
+uint
+sdioh_set_mode(sdioh_info_t *sd, uint mode)
+{
+ if (mode == SDPCM_TXGLOM_CPY)
+ sd->txglom_mode = mode;
+ else if (mode == SDPCM_TXGLOM_MDESC)
+ sd->txglom_mode = mode;
+ printf("%s: set txglom_mode to %s\n", __FUNCTION__, mode==SDPCM_TXGLOM_MDESC?"multi-desc":"copy");
+
+ return (sd->txglom_mode);
+}
+
extern SDIOH_API_RC
sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func, uint addr,
uint32 *word, uint nbytes)
@@ -902,6 +1322,11 @@
#ifdef CONFIG_ARCH_SUNXI
int ret = 0;
#endif
+ struct timespec now, before;
+
+ if (sd_msglevel && SDH_COST_VAL)
+ getnstimeofday(&before);
+
if (func == 0) {
sd_err(("%s: Only CMD52 allowed to F0.\n", __FUNCTION__));
return SDIOH_API_RC_FAIL;
@@ -915,7 +1340,7 @@
/* Claim host controller */
sdio_claim_host(sd->func[func]);
- if(rw) { /* CMD52 Write */
+ if (rw) { /* CMD52 Write */
if (nbytes == 4) {
sdio_writel(sd->func[func], *word, addr, &err_ret);
} else if (nbytes == 2) {
@@ -968,11 +1393,16 @@
if (err_ret)
#endif /* MMC_SDIO_ABORT */
{
- sd_err(("bcmsdh_sdmmc: Failed to %s word, Err: 0x%08x\n",
- rw ? "Write" : "Read", err_ret));
+ sd_err(("bcmsdh_sdmmc: Failed to %s word F%d:@0x%05x=%02x, Err: 0x%08x\n",
+ rw ? "Write" : "Read", func, addr, *word, err_ret));
}
}
+ if (sd_msglevel && SDH_COST_VAL)
+ getnstimeofday(&now);
+ sd_cost(("%s: len=%d cost=%lds %luus\n", __FUNCTION__,
+ nbytes, now.tv_sec-before.tv_sec, now.tv_nsec/1000 - before.tv_nsec/1000));
+
return (((err_ret == 0)&&(err_ret2 == 0)) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL);
}
@@ -994,12 +1424,21 @@
uint32 sg_count;
struct sdio_func *sdio_func = sd->func[func];
struct mmc_host *host = sdio_func->card->host;
+#ifdef BCMSDIOH_TXGLOM
+ uint8 *localbuf = NULL;
+ uint local_plen = 0;
+ uint pkt_len = 0;
+#endif /* BCMSDIOH_TXGLOM */
+ struct timespec now, before;
sd_trace(("%s: Enter\n", __FUNCTION__));
ASSERT(pkt);
DHD_PM_RESUME_WAIT(sdioh_request_packet_wait);
DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL);
+ if (sd_msglevel && SDH_COST_VAL)
+ getnstimeofday(&before);
+
blk_size = sd->client_block_size[func];
max_blk_count = min(host->max_blk_count, (uint)MAX_IO_RW_EXTENDED_BLK);
max_req_size = min(max_blk_count * blk_size, host->max_req_size);
@@ -1007,6 +1446,11 @@
pkt_offset = 0;
pnext = pkt;
+#ifdef BCMSDIOH_TXGLOM
+ ttl_len = 0;
+ sg_count = 0;
+ if(sd->txglom_mode == SDPCM_TXGLOM_MDESC) {
+#endif
while (pnext != NULL) {
ttl_len = 0;
sg_count = 0;
@@ -1094,6 +1538,86 @@
return SDIOH_API_RC_FAIL;
}
}
+#ifdef BCMSDIOH_TXGLOM
+ } else if(sd->txglom_mode == SDPCM_TXGLOM_CPY) {
+ for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext)) {
+ ttl_len += PKTLEN(sd->osh, pnext);
+ }
+ /* Claim host controller */
+ sdio_claim_host(sd->func[func]);
+ for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext)) {
+ uint8 *buf = (uint8*)PKTDATA(sd->osh, pnext);
+ pkt_len = PKTLEN(sd->osh, pnext);
+
+ if (!localbuf) {
+ localbuf = (uint8 *)MALLOC(sd->osh, ttl_len);
+ if (localbuf == NULL) {
+ sd_err(("%s: %s TXGLOM: localbuf malloc FAILED\n",
+ __FUNCTION__, (write) ? "TX" : "RX"));
+ goto txglomfail;
+ }
+ }
+
+ bcopy(buf, (localbuf + local_plen), pkt_len);
+ local_plen += pkt_len;
+ if (PKTNEXT(sd->osh, pnext))
+ continue;
+
+ buf = localbuf;
+ pkt_len = local_plen;
+txglomfail:
+ /* Align Patch */
+ if (!write || pkt_len < 32)
+ pkt_len = (pkt_len + 3) & 0xFFFFFFFC;
+ else if (pkt_len % blk_size)
+ pkt_len += blk_size - (pkt_len % blk_size);
+
+ if ((write) && (!fifo))
+ err_ret = sdio_memcpy_toio(
+ sd->func[func],
+ addr, buf, pkt_len);
+ else if (write)
+ err_ret = sdio_memcpy_toio(
+ sd->func[func],
+ addr, buf, pkt_len);
+ else if (fifo)
+ err_ret = sdio_readsb(
+ sd->func[func],
+ buf, addr, pkt_len);
+ else
+ err_ret = sdio_memcpy_fromio(
+ sd->func[func],
+ buf, addr, pkt_len);
+
+ if (err_ret)
+ sd_err(("%s: %s FAILED %p[%d], addr=0x%05x, pkt_len=%d, ERR=%d\n",
+ __FUNCTION__,
+ (write) ? "TX" : "RX",
+ pnext, sg_count, addr, pkt_len, err_ret));
+ else
+ sd_trace(("%s: %s xfr'd %p[%d], addr=0x%05x, len=%d\n",
+ __FUNCTION__,
+ (write) ? "TX" : "RX",
+ pnext, sg_count, addr, pkt_len));
+
+ if (!fifo)
+ addr += pkt_len;
+ sg_count ++;
+ }
+ sdio_release_host(sd->func[func]);
+ } else {
+ sd_err(("%s: set to wrong glom mode %d\n", __FUNCTION__, sd->txglom_mode));
+ return SDIOH_API_RC_FAIL;
+ }
+
+ if (localbuf)
+ MFREE(sd->osh, localbuf, ttl_len);
+#endif /* BCMSDIOH_TXGLOM */
+
+ if (sd_msglevel && SDH_COST_VAL)
+ getnstimeofday(&now);
+ sd_cost(("%s: cost=%lds %luus\n", __FUNCTION__,
+ now.tv_sec-before.tv_sec, now.tv_nsec/1000-before.tv_nsec/1000));
sd_trace(("%s: Exit\n", __FUNCTION__));
return SDIOH_API_RC_SUCCESS;
@@ -1105,12 +1629,17 @@
{
bool fifo = (fix_inc == SDIOH_DATA_FIX);
int err_ret = 0;
+ struct timespec now, before;
#ifdef CONFIG_ARCH_SUNXI
int ret = 0;
#endif
+
sd_trace(("%s: Enter\n", __FUNCTION__));
ASSERT(buf);
+ if (sd_msglevel && SDH_COST_VAL)
+ getnstimeofday(&before);
+
/* NOTE:
* For all writes, each packet length is aligned to 32 (or 4)
* bytes in dhdsdio_txpkt_preprocess, and for glom the last packet length
@@ -1147,6 +1676,11 @@
(write) ? "TX" : "RX", buf, addr, len));
sd_trace(("%s: Exit\n", __FUNCTION__));
+
+ if (sd_msglevel && SDH_COST_VAL)
+ getnstimeofday(&now);
+ sd_cost(("%s: len=%d cost=%lds %luus\n", __FUNCTION__,
+ len, now.tv_sec-before.tv_sec, now.tv_nsec/1000 - before.tv_nsec/1000));
return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL);
}
@@ -1168,11 +1702,15 @@
{
SDIOH_API_RC status;
void *tmppkt;
+ struct timespec now, before;
sd_trace(("%s: Enter\n", __FUNCTION__));
DHD_PM_RESUME_WAIT(sdioh_request_buffer_wait);
DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL);
+ if (sd_msglevel && SDH_COST_VAL)
+ getnstimeofday(&before);
+
if (pkt) {
/* packet chain, only used for tx/rx glom, all packets length
* are aligned, total length is a block multiple
@@ -1214,6 +1752,11 @@
PKTFREE_STATIC(sd->osh, tmppkt, write ? TRUE : FALSE);
+ if (sd_msglevel && SDH_COST_VAL)
+ getnstimeofday(&now);
+ sd_cost(("%s: len=%d cost=%lds %luus\n", __FUNCTION__,
+ buf_len, now.tv_sec-before.tv_sec, now.tv_nsec/1000 - before.tv_nsec/1000));
+
return status;
}
@@ -1399,6 +1942,7 @@
sdio_claim_host(sd->func[2]);
sd->client_block_size[2] = sd_f2_blocksize;
+ printf("%s: set sd_f2_blocksize %d\n", __FUNCTION__, sd_f2_blocksize);
ret = sdio_set_block_size(sd->func[2], sd_f2_blocksize);
if (ret) {
sd_err(("bcmsdh_sdmmc: Failed to set F2 "
diff -Nur a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c c/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c
--- a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c 2016-05-13 09:48:20.000000000 +0200
@@ -2,13 +2,13 @@
* BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel
*
* 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
* 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
@@ -16,7 +16,7 @@
* 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.
@@ -91,7 +91,9 @@
module_param(clockoverride, int, 0644);
MODULE_PARM_DESC(clockoverride, "SDIO card clock override");
+#ifdef GLOBAL_SDMMC_INSTANCE
PBCMSDH_SDMMC_INSTANCE gInstance;
+#endif
/* Maximum number of bcmsdh_sdmmc devices supported by driver */
#define BCMSDH_SDMMC_MAX_DEVICES 1
@@ -156,6 +158,7 @@
sd_err(("%s: error, no sdioh handler found\n", __FUNCTION__));
return;
}
+ sd_err(("%s: Enter\n", __FUNCTION__));
osh = sdioh->osh;
bcmsdh_remove(sdioh->bcmsdh);
@@ -177,7 +180,9 @@
sd_info(("sdio_device: 0x%04x\n", func->device));
sd_info(("Function#: 0x%04x\n", func->num));
+#ifdef GLOBAL_SDMMC_INSTANCE
gInstance->func[func->num] = func;
+#endif
/* 4318 doesn't have function 2 */
if ((func->num == 2) || (func->num == 1 && func->device == 0x4))
@@ -228,14 +233,14 @@
struct sdio_func *func = dev_to_sdio_func(pdev);
mmc_pm_flag_t sdio_flags;
- printk("%s Enter\n", __FUNCTION__);
+ printf("%s Enter func->num=%d\n", __FUNCTION__, func->num);
if (func->num != 2)
return 0;
sdioh = sdio_get_drvdata(func);
err = bcmsdh_suspend(sdioh->bcmsdh);
if (err) {
- printk("%s bcmsdh_suspend err=%d\n", __FUNCTION__, err);
+ printf("%s bcmsdh_suspend err=%d\n", __FUNCTION__, err);
return err;
}
@@ -257,7 +262,7 @@
dhd_mmc_suspend = TRUE;
smp_mb();
- printk("%s Exit\n", __FUNCTION__);
+ printf("%s Exit\n", __FUNCTION__);
return 0;
}
@@ -268,7 +273,7 @@
#endif
struct sdio_func *func = dev_to_sdio_func(pdev);
- printk("%s Enter\n", __FUNCTION__);
+ printf("%s Enter func->num=%d\n", __FUNCTION__, func->num);
if (func->num != 2)
return 0;
@@ -279,7 +284,7 @@
#endif
smp_mb();
- printk("%s Exit\n", __FUNCTION__);
+ printf("%s Exit\n", __FUNCTION__);
return 0;
}
@@ -287,7 +292,7 @@
.suspend = bcmsdh_sdmmc_suspend,
.resume = bcmsdh_sdmmc_resume,
};
-#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) */
+#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) */
#if defined(BCMLXSDMMC)
static struct semaphore *notify_semaphore = NULL;
@@ -339,7 +344,7 @@
.pm = &bcmsdh_sdmmc_pm_ops,
},
#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) */
- };
+};
struct sdos_info {
sdioh_info_t *sd;
@@ -385,9 +390,11 @@
*/
int bcmsdh_register_client_driver(void)
{
+#ifdef GLOBAL_SDMMC_INSTANCE
gInstance = kzalloc(sizeof(BCMSDH_SDMMC_INSTANCE), GFP_KERNEL);
if (!gInstance)
return -ENOMEM;
+#endif
return sdio_register_driver(&bcmsdh_sdmmc_driver);
}
@@ -398,6 +405,8 @@
void bcmsdh_unregister_client_driver(void)
{
sdio_unregister_driver(&bcmsdh_sdmmc_driver);
+#ifdef GLOBAL_SDMMC_INSTANCE
if (gInstance)
kfree(gInstance);
+#endif
}
diff -Nur a/drivers/net/wireless/bcmdhd/bcmutils.c c/drivers/net/wireless/bcmdhd/bcmutils.c
--- a/drivers/net/wireless/bcmdhd/bcmutils.c 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/bcmutils.c 2016-05-13 09:48:20.000000000 +0200
@@ -2,7 +2,7 @@
* Driver O/S-independent utility routines
*
* $Copyright Open Broadcom Corporation$
- * $Id: bcmutils.c 488316 2014-06-30 15:22:21Z $
+ * $Id: bcmutils.c 496061 2014-08-11 06:14:48Z $
*/
#include <bcm_cfg.h>
@@ -735,7 +735,7 @@
for (p = p0; p; p = PKTNEXT(osh, p))
prhex(NULL, PKTDATA(osh, p), PKTLEN(osh, p));
}
-#endif
+#endif
/* Takes an Ethernet frame and sets out-of-bound PKTPRIO.
* Also updates the inplace vlan tag if requested.
@@ -868,6 +868,23 @@
return rc;
}
+/* Add to adjust the 802.1x priority */
+void
+pktset8021xprio(void *pkt, int prio)
+{
+ struct ether_header *eh;
+ uint8 *pktdata;
+ if(prio == PKTPRIO(pkt))
+ return;
+ pktdata = (uint8 *)PKTDATA(OSH_NULL, pkt);
+ ASSERT(ISALIGNED((uintptr)pktdata, sizeof(uint16)));
+ eh = (struct ether_header *) pktdata;
+ if (eh->ether_type == hton16(ETHER_TYPE_802_1X)) {
+ ASSERT(prio >= 0 && prio <= MAXPRIO);
+ PKTSETPRIO(pkt, prio);
+ }
+}
+
/* The 0.5KB string table is not removed by compiler even though it's unused */
static char bcm_undeferrstr[32];
@@ -1526,7 +1543,7 @@
return (int)(p - buf);
}
-#endif
+#endif
/* print bytes formatted as hex to a string. return the resulting string length */
int
@@ -1972,7 +1989,7 @@
return (int)(p - buf);
}
-#endif
+#endif
#endif /* BCMDRIVER */
@@ -2003,9 +2020,9 @@
for (n=1; n<len; n++) {
if (varbuf[n] == '\n')
break;
- printf("%c", varbuf[n]);
+ printk("%c", varbuf[n]);
}
- printf("\n");
+ printk("\n");
}
for (n = 0; n < len; n++) {
@@ -2252,7 +2269,7 @@
#define BCM_MWBMAP_AUDIT(mwb) do {} while (0)
#define MWBMAP_ASSERT(exp) do {} while (0)
#define MWBMAP_DBG(x)
-#endif /* !BCM_MWBMAP_DEBUG */
+#endif /* !BCM_MWBMAP_DEBUG */
typedef struct bcm_mwbmap { /* Hierarchical multiword bitmap allocator */
@@ -2753,6 +2770,45 @@
return NULL;
}
+void
+id16_map_clear(void * id16_map_hndl, uint16 total_ids, uint16 start_val16)
+{
+ uint16 idx, val16;
+ id16_map_t * id16_map;
+
+ ASSERT(total_ids > 0);
+ ASSERT((start_val16 + total_ids) < ID16_INVALID);
+
+ id16_map = (id16_map_t *)id16_map_hndl;
+ if (id16_map == NULL) {
+ return;
+ }
+
+ id16_map->total = total_ids;
+ id16_map->start = start_val16;
+ id16_map->failures = 0;
+
+ /* Populate stack with 16bit id values, commencing with start_val16 */
+ id16_map->stack_idx = 0;
+ val16 = start_val16;
+
+ for (idx = 0; idx < total_ids; idx++, val16++) {
+ id16_map->stack_idx = idx;
+ id16_map->stack[id16_map->stack_idx] = val16;
+ }
+
+#if defined(BCM_DBG) && defined(BCM_DBG_ID16)
+ if (id16_map->dbg) {
+ id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg;
+
+ id16_map_dbg->total = total_ids;
+ for (idx = 0; idx < total_ids; idx++) {
+ id16_map_dbg->avail[idx] = TRUE;
+ }
+ }
+#endif /* BCM_DBG && BCM_DBG_ID16 */
+}
+
uint16 BCMFASTPATH /* Allocate a unique 16bit id */
id16_map_alloc(void * id16_map_hndl)
{
diff -Nur a/drivers/net/wireless/bcmdhd/dhd_bus.h c/drivers/net/wireless/bcmdhd/dhd_bus.h
--- a/drivers/net/wireless/bcmdhd/dhd_bus.h 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/dhd_bus.h 2016-05-13 09:48:20.000000000 +0200
@@ -6,7 +6,7 @@
*
* $Copyright Open Broadcom Corporation$
*
- * $Id: dhd_bus.h 491657 2014-07-17 06:29:40Z $
+ * $Id: dhd_bus.h 497466 2014-08-19 15:41:01Z $
*/
#ifndef _dhd_bus_h_
@@ -150,7 +150,7 @@
extern void dhd_bus_read_flow_ring_states(struct dhd_bus *bus,
void * data, uint8 flowid);
extern int dhd_bus_flow_ring_create_request(struct dhd_bus *bus, void *flow_ring_node);
-extern void dhd_bus_clean_flow_ring(struct dhd_bus *bus, uint16 flowid);
+extern void dhd_bus_clean_flow_ring(struct dhd_bus *bus, void *flow_ring_node);
extern void dhd_bus_flow_ring_create_response(struct dhd_bus *bus, uint16 flow_id, int32 status);
extern int dhd_bus_flow_ring_delete_request(struct dhd_bus *bus, void *flow_ring_node);
extern void dhd_bus_flow_ring_delete_response(struct dhd_bus *bus, uint16 flowid, uint32 status);
@@ -167,6 +167,7 @@
extern void dhdpcie_bus_free_resource(struct dhd_bus *bus);
extern bool dhdpcie_bus_dongle_attach(struct dhd_bus *bus);
extern int dhd_bus_release_dongle(struct dhd_bus *bus);
+extern int dhd_bus_request_irq(struct dhd_bus *bus);
#endif /* BCMPCIE */
diff -Nur a/drivers/net/wireless/bcmdhd/dhd_cdc.c c/drivers/net/wireless/bcmdhd/dhd_cdc.c
--- a/drivers/net/wireless/bcmdhd/dhd_cdc.c 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/dhd_cdc.c 2016-05-13 09:48:20.000000000 +0200
@@ -3,7 +3,7 @@
*
* $Copyright Open Broadcom Corporation$
*
- * $Id: dhd_cdc.c 472193 2014-04-23 06:27:38Z $
+ * $Id: dhd_cdc.c 492377 2014-07-21 19:54:06Z $
*
* BDC is like CDC, except it includes a header for data packets to convey
* packet priority over the bus, and flags (e.g. to indicate checksum status
@@ -437,12 +437,14 @@
PKTPULL(dhd->osh, pktbuf, BDC_HEADER_LEN);
#endif /* BDC */
-#if defined(NDISVER) && (NDISVER < 0x0630)
+#if defined(NDISVER)
+#if (NDISVER < 0x0630)
if (PKTLEN(dhd->osh, pktbuf) < (uint32) (data_offset << 2)) {
DHD_ERROR(("%s: rx data too short (%d < %d)\n", __FUNCTION__,
PKTLEN(dhd->osh, pktbuf), (data_offset * 4)));
return BCME_ERROR;
}
+#endif /* #if defined(NDISVER) */
#endif /* (NDISVER < 0x0630) */
#ifdef PROP_TXSTATUS
diff -Nur a/drivers/net/wireless/bcmdhd/dhd_cfg_vendor.c c/drivers/net/wireless/bcmdhd/dhd_cfg_vendor.c
--- a/drivers/net/wireless/bcmdhd/dhd_cfg_vendor.c 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/dhd_cfg_vendor.c 2016-05-13 09:48:20.000000000 +0200
@@ -3,9 +3,10 @@
*
* $Copyright Open Broadcom Corporation$
*
- * $Id: dhd_cfg_vendor.c 487126 2014-06-24 23:06:12Z $
+ * $Id: dhd_cfg_vendor.c 495605 2014-08-07 18:41:34Z $
*/
+#include <linux/vmalloc.h>
#include <linuxver.h>
#include <net/cfg80211.h>
#include <net/netlink.h>
@@ -15,6 +16,7 @@
#include <wl_cfgvendor.h>
#include <dngl_stats.h>
#include <dhd.h>
+#include <dhd_dbg.h>
#include <dhdioctl.h>
#include <brcm_nl80211.h>
diff -Nur a/drivers/net/wireless/bcmdhd/dhd_common.c c/drivers/net/wireless/bcmdhd/dhd_common.c
--- a/drivers/net/wireless/bcmdhd/dhd_common.c 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/dhd_common.c 2016-05-13 09:48:20.000000000 +0200
@@ -3,7 +3,7 @@
*
* $Copyright Open Broadcom Corporation$
*
- * $Id: dhd_common.c 490628 2014-07-11 07:13:31Z $
+ * $Id: dhd_common.c 492215 2014-07-20 16:44:15Z $
*/
#include <typedefs.h>
#include <osl.h>
@@ -104,7 +104,7 @@
#if defined(DHD_DEBUG)
const char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR
- DHD_COMPILED " on " __DATE__ " at " __TIME__;
+ DHD_COMPILED ;//" on " __DATE__ " at " __TIME__;
#else
const char dhd_version[] = "\nDongle Host Driver, version " EPI_VERSION_STR "\nCompiled from ";
#endif
@@ -411,6 +411,10 @@
return BCME_OK;
}
+#ifdef PKT_STATICS
+extern pkt_statics_t tx_statics;
+extern void dhdsdio_txpktstatics(void);
+#endif
static int
dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const char *name,
void *params, int plen, void *arg, int len, int val_size)
@@ -431,36 +435,42 @@
case IOV_GVAL(IOV_VERSION):
/* Need to have checked buffer length */
bcm_strncpy_s((char*)arg, len, dhd_version, len);
+#ifdef PKT_STATICS
+ memset((uint8*) &tx_statics, 0, sizeof(pkt_statics_t));
+#endif
break;
case IOV_GVAL(IOV_WLMSGLEVEL):
- printk("android_msg_level=0x%x\n", android_msg_level);
- printk("config_msg_level=0x%x\n", config_msg_level);
+ printf("android_msg_level=0x%x\n", android_msg_level);
+ printf("config_msg_level=0x%x\n", config_msg_level);
#if defined(WL_WIRELESS_EXT)
int_val = (int32)iw_msg_level;
bcopy(&int_val, arg, val_size);
- printk("iw_msg_level=0x%x\n", iw_msg_level);
+ printf("iw_msg_level=0x%x\n", iw_msg_level);
#endif
#ifdef WL_CFG80211
int_val = (int32)wl_dbg_level;
bcopy(&int_val, arg, val_size);
- printk("cfg_msg_level=0x%x\n", wl_dbg_level);
+ printf("cfg_msg_level=0x%x\n", wl_dbg_level);
+#endif
+#ifdef PKT_STATICS
+ dhdsdio_txpktstatics();
#endif
break;
case IOV_SVAL(IOV_WLMSGLEVEL):
if (int_val & DHD_ANDROID_VAL) {
android_msg_level = (uint)(int_val & 0xFFFF);
- printk("android_msg_level=0x%x\n", android_msg_level);
+ printf("android_msg_level=0x%x\n", android_msg_level);
}
if (int_val & DHD_CONFIG_VAL) {
config_msg_level = (uint)(int_val & 0xFFFF);
- printk("config_msg_level=0x%x\n", config_msg_level);
+ printf("config_msg_level=0x%x\n", config_msg_level);
}
#if defined(WL_WIRELESS_EXT)
if (int_val & DHD_IW_VAL) {
iw_msg_level = (uint)(int_val & 0xFFFF);
- printk("iw_msg_level=0x%x\n", iw_msg_level);
+ printf("iw_msg_level=0x%x\n", iw_msg_level);
}
#endif
#ifdef WL_CFG80211
@@ -1822,7 +1832,7 @@
case WLC_E_PFN_BEST_BATCHING:
dhd_pno_event_handler(dhd_pub, event, (void *)event_data);
break;
-#endif
+#endif
/* These are what external supplicant/authenticator wants */
case WLC_E_ASSOC_IND:
case WLC_E_AUTH_IND:
@@ -1852,7 +1862,7 @@
if (type != WLC_E_LINK) {
uint8 ifindex = (uint8)hostidx;
uint8 role = dhd_flow_rings_ifindex2role(dhd_pub, ifindex);
- if (role == WLC_E_IF_ROLE_STA) {
+ if (DHD_IF_ROLE_STA(role)) {
dhd_flow_rings_delete(dhd_pub, ifindex);
} else {
dhd_flow_rings_delete_for_peer(dhd_pub, ifindex,
@@ -2007,7 +2017,7 @@
rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0);
rc = rc >= 0 ? 0 : rc;
if (rc)
- DHD_TRACE(("%s: failed to %s pktfilter %s, retcode = %d\n",
+ DHD_ERROR(("%s: failed to %s pktfilter %s, retcode = %d\n",
__FUNCTION__, enable?"enable":"disable", arg, rc));
else
DHD_TRACE(("%s: successfully %s pktfilter %s\n",
@@ -2151,7 +2161,7 @@
rc = rc >= 0 ? 0 : rc;
if (rc)
- DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n",
+ DHD_ERROR(("%s: failed to add pktfilter %s, retcode = %d\n",
__FUNCTION__, arg, rc));
else
DHD_TRACE(("%s: successfully added pktfilter %s\n",
@@ -2853,7 +2863,7 @@
char* str;
char* endptr = NULL;
- if ((list_str == NULL)||(*list_str == NULL))
+ if ((list_str == NULL) || (*list_str == NULL))
return -1;
str = *list_str;
diff -Nur a/drivers/net/wireless/bcmdhd/dhd_config.c c/drivers/net/wireless/bcmdhd/dhd_config.c
--- a/drivers/net/wireless/bcmdhd/dhd_config.c 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/dhd_config.c 2016-05-13 09:48:20.000000000 +0200
@@ -4,7 +4,8 @@
#include <bcmutils.h>
#include <hndsoc.h>
-#if defined(HW_OOB)
+#include <bcmsdbus.h>
+#if defined(HW_OOB) || defined(FORCE_WOWLAN)
#include <bcmdefs.h>
#include <bcmsdh.h>
#include <sdio.h>
@@ -35,28 +36,34 @@
} \
} while (0)
-#define SBSDIO_CIS_SIZE_LIMIT 0x200 /* maximum bytes in one CIS */
#define MAXSZ_BUF 1000
#define MAXSZ_CONFIG 4096
-#define BCM43362A0_CHIP_REV 0
-#define BCM43362A2_CHIP_REV 1
-#define BCM43430A0_CHIP_REV 0
-#define BCM4330B2_CHIP_REV 4
-#define BCM43340B0_CHIP_REV 2
-#define BCM43341B0_CHIP_REV 2
-#define BCM43241B4_CHIP_REV 5
-#define BCM4335A0_CHIP_REV 2
-#define BCM4339A0_CHIP_REV 1
-#define BCM4354A1_CHIP_REV 1
-#define BCM4356A2_CHIP_REV 2
-
#define FW_TYPE_STA 0
#define FW_TYPE_APSTA 1
#define FW_TYPE_P2P 2
#define FW_TYPE_MFG 3
#define FW_TYPE_G 0
#define FW_TYPE_AG 1
+
+#ifdef CONFIG_PATH_AUTO_SELECT
+#define BCM4330B2_CONF_NAME "config_40183b2.txt"
+#define BCM43362A0_CONF_NAME "config_40181a0.txt"
+#define BCM43362A2_CONF_NAME "config_40181a2.txt"
+#define BCM43438A0_CONF_NAME "config_43438a0.txt"
+#define BCM43438A1_CONF_NAME "config_43438a1.txt"
+#define BCM4334B1_CONF_NAME "config_4334b1.txt"
+#define BCM43341B0_CONF_NAME "config_43341b0.txt"
+#define BCM43241B4_CONF_NAME "config_43241b4.txt"
+#define BCM4339A0_CONF_NAME "config_4339a0.txt"
+#define BCM43455C0_CONF_NAME "config_43455c0.txt"
+#define BCM4354A1_CONF_NAME "config_4354a1.txt"
+#define BCM4356A2_CONF_NAME "config_4356a2.txt"
+#define BCM4359B1_CONF_NAME "config_4359b1.txt"
+#endif
+
+#ifdef BCMSDIO
+#define SBSDIO_CIS_SIZE_LIMIT 0x200 /* maximum bytes in one CIS */
const static char *bcm4330b2_fw_name[] = {
"fw_bcm40183b2.bin",
@@ -86,6 +93,13 @@
"fw_bcm40181a2_mfg.bin"
};
+const static char *bcm4334b1_ag_fw_name[] = {
+ "fw_bcm4334b1_ag.bin",
+ "fw_bcm4334b1_ag_apsta.bin",
+ "fw_bcm4334b1_ag_p2p.bin",
+ "fw_bcm4334b1_ag_mfg.bin"
+};
+
const static char *bcm43438a0_fw_name[] = {
"fw_bcm43438a0.bin",
"fw_bcm43438a0_apsta.bin",
@@ -93,6 +107,13 @@
"fw_bcm43438a0_mfg.bin"
};
+const static char *bcm43438a1_fw_name[] = {
+ "fw_bcm43438a1.bin",
+ "fw_bcm43438a1_apsta.bin",
+ "fw_bcm43438a1_p2p.bin",
+ "fw_bcm43438a1_mfg.bin"
+};
+
const static char *bcm43341b0_ag_fw_name[] = {
"fw_bcm43341b0_ag.bin",
"fw_bcm43341b0_ag_apsta.bin",
@@ -114,6 +135,13 @@
"fw_bcm4339a0_ag_mfg.bin"
};
+const static char *bcm43455c0_ag_fw_name[] = {
+ "fw_bcm43455c0_ag.bin",
+ "fw_bcm43455c0_ag_apsta.bin",
+ "fw_bcm43455c0_ag_p2p.bin",
+ "fw_bcm43455c0_ag_mfg.bin"
+};
+
const static char *bcm4354a1_ag_fw_name[] = {
"fw_bcm4354a1_ag.bin",
"fw_bcm4354a1_ag_apsta.bin",
@@ -127,6 +155,22 @@
"fw_bcm4356a2_ag_p2p.bin",
"fw_bcm4356a2_ag_mfg.bin"
};
+
+const static char *bcm4359b1_ag_fw_name[] = {
+ "fw_bcm4359b1_ag.bin",
+ "fw_bcm4359b1_ag_apsta.bin",
+ "fw_bcm4359b1_ag_p2p.bin",
+ "fw_bcm4359b1_ag_mfg.bin"
+};
+#endif
+#ifdef BCMPCIE
+const static char *bcm4356a2_pcie_ag_fw_name[] = {
+ "fw_bcm4356a2_pcie_ag.bin",
+ "fw_bcm4356a2_pcie_ag_apsta.bin",
+ "fw_bcm4356a2_pcie_ag_p2p.bin",
+ "fw_bcm4356a2_pcie_ag_mfg.bin"
+};
+#endif
#define htod32(i) i
#define htod16(i) i
@@ -135,22 +179,57 @@
#define htodchanspec(i) i
#define dtohchanspec(i) i
+#ifdef BCMSDIO
void
dhd_conf_free_mac_list(wl_mac_list_ctrl_t *mac_list)
{
- CONFIG_TRACE(("%s called\n", __FUNCTION__));
+ int i;
+ CONFIG_TRACE(("%s called\n", __FUNCTION__));
if (mac_list->m_mac_list_head) {
- CONFIG_TRACE(("%s Free %p\n", __FUNCTION__, mac_list->m_mac_list_head));
- if (mac_list->m_mac_list_head->mac) {
- CONFIG_TRACE(("%s Free %p\n", __FUNCTION__, mac_list->m_mac_list_head->mac));
- kfree(mac_list->m_mac_list_head->mac);
+ for (i = 0; i < mac_list->count; i++) {
+ if (mac_list->m_mac_list_head[i].mac) {
+ CONFIG_TRACE(("%s Free mac %p\n", __FUNCTION__, mac_list->m_mac_list_head[i].mac));
+ kfree(mac_list->m_mac_list_head[i].mac);
+ }
}
+ CONFIG_TRACE(("%s Free m_mac_list_head %p\n", __FUNCTION__, mac_list->m_mac_list_head));
kfree(mac_list->m_mac_list_head);
}
mac_list->count = 0;
}
+void
+dhd_conf_free_chip_nv_path_list(wl_chip_nv_path_list_ctrl_t *chip_nv_list)
+{
+ CONFIG_TRACE(("%s called\n", __FUNCTION__));
+
+ if (chip_nv_list->m_chip_nv_path_head) {
+ CONFIG_TRACE(("%s Free %p\n", __FUNCTION__, chip_nv_list->m_chip_nv_path_head));
+ kfree(chip_nv_list->m_chip_nv_path_head);
+ }
+ chip_nv_list->count = 0;
+}
+
+#if defined(HW_OOB) || defined(FORCE_WOWLAN)
+void
+dhd_conf_set_hw_oob_intr(bcmsdh_info_t *sdh, uint chip)
+{
+ uint32 gpiocontrol, addr;
+
+ if (CHIPID(chip) == BCM43362_CHIP_ID) {
+ printf("%s: Enable HW OOB for 43362\n", __FUNCTION__);
+ addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, gpiocontrol);
+ gpiocontrol = bcmsdh_reg_read(sdh, addr, 4);
+ gpiocontrol |= 0x2;
+ bcmsdh_reg_write(sdh, addr, 4, gpiocontrol);
+ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, 0x10005, 0xf, NULL);
+ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, 0x10006, 0x0, NULL);
+ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, 0x10007, 0x2, NULL);
+ }
+}
+#endif
+
int
dhd_conf_get_mac(dhd_pub_t *dhd, bcmsdh_info_t *sdh, uint8 *mac)
{
@@ -192,13 +271,13 @@
if (config_msg_level & CONFIG_TRACE_LEVEL) {
printf("%s: tpl_code=0x%02x, tpl_link=0x%02x, tag=0x%02x\n",
__FUNCTION__, tpl_code, tpl_link, *ptr);
- printf("%s: value:", __FUNCTION__);
+ printk("%s: value:", __FUNCTION__);
for (i=0; i<tpl_link-1; i++) {
- printf("%02x ", ptr[i+1]);
- if ((i+1)%16==0)
- printf("\n");
+ printk("%02x ", ptr[i+1]);
+ if ((i+1) % 16 == 0)
+ printk("\n");
}
- printf("\n");
+ printk("\n");
}
if (tpl_code == 0x80 && tpl_link == 0x07 && *ptr == 0x19)
@@ -258,7 +337,7 @@
/* find out the last '/' */
i = strlen(fw_path);
- while (i>0){
+ while (i > 0) {
if (fw_path[i] == '/') break;
i--;
}
@@ -318,7 +397,7 @@
/* find out the last '/' */
i = strlen(nv_path);
- while (i>0){
+ while (i > 0) {
if (nv_path[i] == '/') break;
i--;
}
@@ -340,6 +419,7 @@
}
}
}
+#endif
void
dhd_conf_set_fw_name_by_chip(dhd_pub_t *dhd, char *fw_path)
@@ -367,7 +447,7 @@
/* find out the last '/' */
i = strlen(fw_path);
- while (i>0){
+ while (i > 0) {
if (fw_path[i] == '/') break;
i--;
}
@@ -382,6 +462,7 @@
FW_TYPE_P2P : FW_TYPE_STA)));
switch (chip) {
+#ifdef BCMSDIO
case BCM4330_CHIP_ID:
if (ag_type == FW_TYPE_G) {
if (chiprev == BCM4330B2_CHIP_REV)
@@ -401,11 +482,14 @@
case BCM43430_CHIP_ID:
if (chiprev == BCM43430A0_CHIP_REV)
strcpy(&fw_path[i+1], bcm43438a0_fw_name[fw_type]);
+ else if (chiprev == BCM43430A1_CHIP_REV)
+ strcpy(&fw_path[i+1], bcm43438a1_fw_name[fw_type]);
break;
- case BCM43340_CHIP_ID:
- if (chiprev == BCM43340B0_CHIP_REV)
- strcpy(&fw_path[i+1], bcm43341b0_ag_fw_name[fw_type]);
+ case BCM4334_CHIP_ID:
+ if (chiprev == BCM4334B1_CHIP_REV)
+ strcpy(&fw_path[i+1], bcm4334b1_ag_fw_name[fw_type]);
break;
+ case BCM43340_CHIP_ID:
case BCM43341_CHIP_ID:
if (chiprev == BCM43341B0_CHIP_REV)
strcpy(&fw_path[i+1], bcm43341b0_ag_fw_name[fw_type]);
@@ -418,6 +502,11 @@
if (chiprev == BCM4335A0_CHIP_REV)
strcpy(&fw_path[i+1], bcm4339a0_ag_fw_name[fw_type]);
break;
+ case BCM4345_CHIP_ID:
+ case BCM43454_CHIP_ID:
+ if (chiprev == BCM43455C0_CHIP_REV)
+ strcpy(&fw_path[i+1], bcm43455c0_ag_fw_name[fw_type]);
+ break;
case BCM4339_CHIP_ID:
if (chiprev == BCM4339A0_CHIP_REV)
strcpy(&fw_path[i+1], bcm4339a0_ag_fw_name[fw_type]);
@@ -428,57 +517,261 @@
else if (chiprev == BCM4356A2_CHIP_REV)
strcpy(&fw_path[i+1], bcm4356a2_ag_fw_name[fw_type]);
break;
+ case BCM4356_CHIP_ID:
+ case BCM4371_CHIP_ID:
+ if (chiprev == BCM4356A2_CHIP_REV)
+ strcpy(&fw_path[i+1], bcm4356a2_ag_fw_name[fw_type]);
+ break;
+ case BCM4359_CHIP_ID:
+ if (chiprev == BCM4359B1_CHIP_REV)
+ strcpy(&fw_path[i+1], bcm4359b1_ag_fw_name[fw_type]);
+ break;
+#endif
+#ifdef BCMPCIE
+ case BCM4356_CHIP_ID:
+ if (chiprev == BCM4356A2_CHIP_REV)
+ strcpy(&fw_path[i+1], bcm4356a2_pcie_ag_fw_name[fw_type]);
+ break;
+#endif
}
printf("%s: firmware_path=%s\n", __FUNCTION__, fw_path);
}
-#if defined(HW_OOB)
void
-dhd_conf_set_hw_oob_intr(bcmsdh_info_t *sdh, uint chip)
+dhd_conf_set_nv_name_by_chip(dhd_pub_t *dhd, char *nv_path)
{
- uint32 gpiocontrol, addr;
+ int matched=-1;
+ uint chip, chiprev;
+ int i;
- if (CHIPID(chip) == BCM43362_CHIP_ID) {
- printf("%s: Enable HW OOB for 43362\n", __FUNCTION__);
- addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, gpiocontrol);
- gpiocontrol = bcmsdh_reg_read(sdh, addr, 4);
- gpiocontrol |= 0x2;
- bcmsdh_reg_write(sdh, addr, 4, gpiocontrol);
- bcmsdh_cfg_write(sdh, SDIO_FUNC_1, 0x10005, 0xf, NULL);
- bcmsdh_cfg_write(sdh, SDIO_FUNC_1, 0x10006, 0x0, NULL);
- bcmsdh_cfg_write(sdh, SDIO_FUNC_1, 0x10007, 0x2, NULL);
+ chip = dhd->conf->chip;
+ chiprev = dhd->conf->chiprev;
+
+ for (i = 0;i < dhd->conf->nv_by_chip.count;i++) {
+ if (chip == dhd->conf->nv_by_chip.m_chip_nv_path_head[i].chip &&
+ chiprev==dhd->conf->nv_by_chip.m_chip_nv_path_head[i].chiprev) {
+ matched = i;
+ break;
+ }
}
-}
+ if (matched < 0)
+ return;
+
+ if (nv_path[0] == '\0') {
+#ifdef CONFIG_BCMDHD_NVRAM_PATH
+ bcm_strncpy_s(nv_path, MOD_PARAM_PATHLEN-1, CONFIG_BCMDHD_NVRAM_PATH, MOD_PARAM_PATHLEN-1);
+ if (nv_path[0] == '\0')
#endif
+ {
+ printf("nvram path is null\n");
+ return;
+ }
+ }
-void
-dhd_conf_set_fw_path(dhd_pub_t *dhd, char *fw_path)
-{
- if (dhd->conf->fw_path[0]) {
- strcpy(fw_path, dhd->conf->fw_path);
- printf("%s: fw_path is changed to %s\n", __FUNCTION__, fw_path);
+ /* find out the last '/' */
+ i = strlen(nv_path);
+ while (i > 0) {
+ if (nv_path[i] == '/') break;
+ i--;
}
+
+ strcpy(&nv_path[i+1], dhd->conf->nv_by_chip.m_chip_nv_path_head[matched].name);
+
+ printf("%s: nvram_path=%s\n", __FUNCTION__, nv_path);
}
void
-dhd_conf_set_nv_path(dhd_pub_t *dhd, char *nv_path)
+dhd_conf_set_conf_path_by_nv_path(dhd_pub_t *dhd, char *conf_path, char *nv_path)
{
- if (dhd->conf->nv_path[0]) {
- strcpy(nv_path, dhd->conf->nv_path);
- printf("%s: nv_path is changed to %s\n", __FUNCTION__, nv_path);
+ int i;
+
+ if (nv_path[0] == '\0') {
+#ifdef CONFIG_BCMDHD_NVRAM_PATH
+ bcm_strncpy_s(conf_path, MOD_PARAM_PATHLEN-1, CONFIG_BCMDHD_NVRAM_PATH, MOD_PARAM_PATHLEN-1);
+ if (nv_path[0] == '\0')
+#endif
+ {
+ printf("nvram path is null\n");
+ return;
+ }
+ } else
+ strcpy(conf_path, nv_path);
+
+ /* find out the last '/' */
+ i = strlen(conf_path);
+ while (i > 0) {
+ if (conf_path[i] == '/') break;
+ i--;
}
+ strcpy(&conf_path[i+1], "config.txt");
+
+ printf("%s: config_path=%s\n", __FUNCTION__, conf_path);
}
+#ifdef CONFIG_PATH_AUTO_SELECT
+void
+dhd_conf_set_conf_name_by_chip(dhd_pub_t *dhd, char *conf_path)
+{
+ uint chip, chiprev;
+ int i;
+
+ chip = dhd->conf->chip;
+ chiprev = dhd->conf->chiprev;
+
+ if (conf_path[0] == '\0') {
+ printf("config path is null\n");
+ return;
+ }
+
+ /* find out the last '/' */
+ i = strlen(conf_path);
+ while (i > 0) {
+ if (conf_path[i] == '/') break;
+ i--;
+ }
+
+ switch (chip) {
+#ifdef BCMSDIO
+ case BCM4330_CHIP_ID:
+ if (chiprev == BCM4330B2_CHIP_REV)
+ strcpy(&conf_path[i+1], BCM4330B2_CONF_NAME);
+ break;
+ case BCM43362_CHIP_ID:
+ if (chiprev == BCM43362A0_CHIP_REV)
+ strcpy(&conf_path[i+1], BCM43362A0_CONF_NAME);
+ else
+ strcpy(&conf_path[i+1], BCM43362A2_CONF_NAME);
+ break;
+ case BCM43430_CHIP_ID:
+ if (chiprev == BCM43430A0_CHIP_REV)
+ strcpy(&conf_path[i+1], BCM43438A0_CONF_NAME);
+ else if (chiprev == BCM43430A1_CHIP_REV)
+ strcpy(&conf_path[i+1], BCM43438A1_CONF_NAME);
+ break;
+ case BCM4334_CHIP_ID:
+ if (chiprev == BCM4334B1_CHIP_REV)
+ strcpy(&conf_path[i+1], BCM4334B1_CONF_NAME);
+ break;
+ case BCM43340_CHIP_ID:
+ case BCM43341_CHIP_ID:
+ if (chiprev == BCM43341B0_CHIP_REV)
+ strcpy(&conf_path[i+1], BCM43341B0_CONF_NAME);
+ break;
+ case BCM4324_CHIP_ID:
+ if (chiprev == BCM43241B4_CHIP_REV)
+ strcpy(&conf_path[i+1], BCM43241B4_CONF_NAME);
+ break;
+ case BCM4335_CHIP_ID:
+ if (chiprev == BCM4335A0_CHIP_REV)
+ strcpy(&conf_path[i+1], BCM4339A0_CONF_NAME);
+ break;
+ case BCM4345_CHIP_ID:
+ case BCM43454_CHIP_ID:
+ if (chiprev == BCM43455C0_CHIP_REV)
+ strcpy(&conf_path[i+1], BCM43455C0_CONF_NAME);
+ break;
+ case BCM4339_CHIP_ID:
+ if (chiprev == BCM4339A0_CHIP_REV)
+ strcpy(&conf_path[i+1], BCM4339A0_CONF_NAME);
+ break;
+ case BCM4354_CHIP_ID:
+ if (chiprev == BCM4354A1_CHIP_REV)
+ strcpy(&conf_path[i+1], BCM4354A1_CONF_NAME);
+ else if (chiprev == BCM4356A2_CHIP_REV)
+ strcpy(&conf_path[i+1], BCM4356A2_CONF_NAME);
+ break;
+ case BCM4356_CHIP_ID:
+ case BCM4371_CHIP_ID:
+ if (chiprev == BCM4356A2_CHIP_REV)
+ strcpy(&conf_path[i+1], BCM4356A2_CONF_NAME);
+ break;
+ case BCM4359_CHIP_ID:
+ if (chiprev == BCM4359B1_CHIP_REV)
+ strcpy(&conf_path[i+1], BCM4359B1_CONF_NAME);
+ break;
+#endif
+#ifdef BCMPCIE
+ case BCM4356_CHIP_ID:
+ if (chiprev == BCM4356A2_CHIP_REV)
+ strcpy(&conf_path[i+1], BCM4356A2_CONF_NAME);
+ break;
+#endif
+ }
+
+ printf("%s: config_path=%s\n", __FUNCTION__, conf_path);
+}
+#endif
+
int
-dhd_conf_set_band(dhd_pub_t *dhd)
+dhd_conf_set_fw_int_cmd(dhd_pub_t *dhd, char *name, uint cmd, int val,
+ int def, bool down)
{
int bcmerror = -1;
- printf("%s: Set band %d\n", __FUNCTION__, dhd->conf->band);
- if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_SET_BAND, &dhd->conf->band,
- sizeof(dhd->conf->band), TRUE, 0)) < 0)
- CONFIG_ERROR(("%s: WLC_SET_BAND setting failed %d\n", __FUNCTION__, bcmerror));
+ if (val >= def) {
+ if (down) {
+ if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_DOWN, NULL, 0, TRUE, 0)) < 0)
+ CONFIG_ERROR(("%s: WLC_DOWN setting failed %d\n", __FUNCTION__, bcmerror));
+ }
+ printf("%s: set %s %d %d\n", __FUNCTION__, name, cmd, val);
+ if ((bcmerror = dhd_wl_ioctl_cmd(dhd, cmd, &val, sizeof(val), TRUE, 0)) < 0)
+ CONFIG_ERROR(("%s: %s setting failed %d\n", __FUNCTION__, name, bcmerror));
+ }
+ return bcmerror;
+}
+
+int
+dhd_conf_set_fw_int_struct_cmd(dhd_pub_t *dhd, char *name, uint cmd,
+ int *val, int len, bool down)
+{
+ int bcmerror = -1;
+
+ if (down) {
+ if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_DOWN, NULL, 0, TRUE, 0)) < 0)
+ CONFIG_ERROR(("%s: WLC_DOWN setting failed %d\n", __FUNCTION__, bcmerror));
+ }
+ if ((bcmerror = dhd_wl_ioctl_cmd(dhd, cmd, val, len, TRUE, 0)) < 0)
+ CONFIG_ERROR(("%s: %s setting failed %d\n", __FUNCTION__, name, bcmerror));
+
+ return bcmerror;
+}
+
+int
+dhd_conf_set_fw_string_cmd(dhd_pub_t *dhd, char *cmd, int val, int def,
+ bool down)
+{
+ int bcmerror = -1;
+ char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */
+
+ if (val >= def) {
+ if (down) {
+ if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_DOWN, NULL, 0, TRUE, 0)) < 0)
+ CONFIG_ERROR(("%s: WLC_DOWN setting failed %d\n", __FUNCTION__, bcmerror));
+ }
+ printf("%s: set %s %d\n", __FUNCTION__, cmd, val);
+ bcm_mkiovar(cmd, (char *)&val, 4, iovbuf, sizeof(iovbuf));
+ if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
+ CONFIG_ERROR(("%s: %s setting failed %d\n", __FUNCTION__, cmd, bcmerror));
+ }
+ return bcmerror;
+}
+
+int
+dhd_conf_set_fw_string_struct_cmd(dhd_pub_t *dhd, char *cmd, char *val,
+ int len, bool down)
+{
+ int bcmerror = -1;
+ char iovbuf[WLC_IOCTL_SMLEN];
+
+ if (down) {
+ if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_DOWN, NULL, 0, TRUE, 0)) < 0)
+ CONFIG_ERROR(("%s: WLC_DOWN setting failed %d\n", __FUNCTION__, bcmerror));
+ }
+ printf("%s: set %s\n", __FUNCTION__, cmd);
+ bcm_mkiovar(cmd, val, len, iovbuf, sizeof(iovbuf));
+ if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
+ CONFIG_ERROR(("%s: %s setting failed %d\n", __FUNCTION__, cmd, bcmerror));
return bcmerror;
}
@@ -500,15 +793,11 @@
dhd_conf_set_country(dhd_pub_t *dhd)
{
int bcmerror = -1;
- char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */
memset(&dhd->dhd_cspec, 0, sizeof(wl_country_t));
- printf("%s: Set country %s, revision %d\n", __FUNCTION__,
+ printf("%s: set country %s, revision %d\n", __FUNCTION__,
dhd->conf->cspec.ccode, dhd->conf->cspec.rev);
- bcm_mkiovar("country", (char *)&dhd->conf->cspec,
- sizeof(wl_country_t), iovbuf, sizeof(iovbuf));
- if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
- printf("%s: country code setting failed %d\n", __FUNCTION__, bcmerror);
+ dhd_conf_set_fw_string_struct_cmd(dhd, "country", (char *)&dhd->conf->cspec, sizeof(wl_country_t), FALSE);
return bcmerror;
}
@@ -521,9 +810,28 @@
memset(cspec, 0, sizeof(wl_country_t));
bcm_mkiovar("country", NULL, 0, (char*)cspec, sizeof(wl_country_t));
if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, cspec, sizeof(wl_country_t), FALSE, 0)) < 0)
- printf("%s: country code getting failed %d\n", __FUNCTION__, bcmerror);
+ CONFIG_ERROR(("%s: country code getting failed %d\n", __FUNCTION__, bcmerror));
else
printf("Country code: %s (%s/%d)\n", cspec->country_abbrev, cspec->ccode, cspec->rev);
+
+ return bcmerror;
+}
+
+int
+dhd_conf_get_country_from_config(dhd_pub_t *dhd, wl_country_t *cspec)
+{
+ int bcmerror = -1, i;
+ struct dhd_conf *conf = dhd->conf;
+
+ for (i = 0; i < conf->country_list.count; i++) {
+ if (strcmp(cspec->country_abbrev, conf->country_list.cspec[i].country_abbrev) == 0) {
+ memcpy(cspec->ccode,
+ conf->country_list.cspec[i].ccode, WLC_CNTRY_BUF_SZ);
+ cspec->rev = conf->country_list.cspec[i].rev;
+ printf("%s: %s/%d\n", __FUNCTION__, cspec->ccode, cspec->rev);
+ return 0;
+ }
+ }
return bcmerror;
}
@@ -549,7 +857,7 @@
band = dhd_conf_get_band(dhd);
- if (bcmerror || ((band==WLC_BAND_AUTO || band==WLC_BAND_2G) &&
+ if (bcmerror || ((band == WLC_BAND_AUTO || band == WLC_BAND_2G) &&
dtoh32(list->count)<11)) {
CONFIG_ERROR(("%s: bcmerror=%d, # of channels %d\n",
__FUNCTION__, bcmerror, dtoh32(list->count)));
@@ -589,72 +897,31 @@
dhd_conf_set_roam(dhd_pub_t *dhd)
{
int bcmerror = -1;
- char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */
struct dhd_conf *conf = dhd->conf;
- printf("%s: Set roam_off %d\n", __FUNCTION__, conf->roam_off);
dhd_roam_disable = conf->roam_off;
- bcm_mkiovar("roam_off", (char *)&conf->roam_off, 4, iovbuf, sizeof(iovbuf));
- dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+ dhd_conf_set_fw_string_cmd(dhd, "roam_off", dhd->conf->roam_off, 0, FALSE);
if (!conf->roam_off || !conf->roam_off_suspend) {
- printf("%s: Set roam_trigger %d\n", __FUNCTION__, conf->roam_trigger[0]);
- if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_TRIGGER, conf->roam_trigger,
- sizeof(conf->roam_trigger), TRUE, 0)) < 0)
- CONFIG_ERROR(("%s: roam trigger setting failed %d\n", __FUNCTION__, bcmerror));
-
- printf("%s: Set roam_scan_period %d\n", __FUNCTION__, conf->roam_scan_period[0]);
- if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_SCAN_PERIOD, conf->roam_scan_period,
- sizeof(conf->roam_scan_period), TRUE, 0)) < 0)
- CONFIG_ERROR(("%s: roam scan period setting failed %d\n", __FUNCTION__, bcmerror));
-
- printf("%s: Set roam_delta %d\n", __FUNCTION__, conf->roam_delta[0]);
- if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_DELTA, conf->roam_delta,
- sizeof(conf->roam_delta), TRUE, 0)) < 0)
- CONFIG_ERROR(("%s: roam delta setting failed %d\n", __FUNCTION__, bcmerror));
-
- printf("%s: Set fullroamperiod %d\n", __FUNCTION__, conf->fullroamperiod);
- bcm_mkiovar("fullroamperiod", (char *)&conf->fullroamperiod, 4, iovbuf, sizeof(iovbuf));
- if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
- CONFIG_ERROR(("%s: roam fullscan period setting failed %d\n", __FUNCTION__, bcmerror));
+ printf("%s: set roam_trigger %d\n", __FUNCTION__, conf->roam_trigger[0]);
+ dhd_conf_set_fw_int_struct_cmd(dhd, "WLC_SET_ROAM_TRIGGER", WLC_SET_ROAM_TRIGGER,
+ conf->roam_trigger, sizeof(conf->roam_trigger), FALSE);
+
+ printf("%s: set roam_scan_period %d\n", __FUNCTION__, conf->roam_scan_period[0]);
+ dhd_conf_set_fw_int_struct_cmd(dhd, "WLC_SET_ROAM_SCAN_PERIOD", WLC_SET_ROAM_SCAN_PERIOD,
+ conf->roam_scan_period, sizeof(conf->roam_scan_period), FALSE);
+
+ printf("%s: set roam_delta %d\n", __FUNCTION__, conf->roam_delta[0]);
+ dhd_conf_set_fw_int_struct_cmd(dhd, "WLC_SET_ROAM_DELTA", WLC_SET_ROAM_DELTA,
+ conf->roam_delta, sizeof(conf->roam_delta), FALSE);
+
+ dhd_conf_set_fw_string_cmd(dhd, "fullroamperiod", dhd->conf->fullroamperiod, 1, FALSE);
}
return bcmerror;
}
void
-dhd_conf_set_mimo_bw_cap(dhd_pub_t *dhd)
-{
- int bcmerror = -1;
- char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */
- uint32 mimo_bw_cap;
-
- if (dhd->conf->mimo_bw_cap >= 0) {
- mimo_bw_cap = (uint)dhd->conf->mimo_bw_cap;
- if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_DOWN, NULL, 0, TRUE, 0)) < 0)
- CONFIG_ERROR(("%s: WLC_DOWN setting failed %d\n", __FUNCTION__, bcmerror));
- /* 0:HT20 in ALL, 1:HT40 in ALL, 2: HT20 in 2G HT40 in 5G */
- printf("%s: Set mimo_bw_cap %d\n", __FUNCTION__, mimo_bw_cap);
- bcm_mkiovar("mimo_bw_cap", (char *)&mimo_bw_cap, 4, iovbuf, sizeof(iovbuf));
- if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
- CONFIG_ERROR(("%s: mimo_bw_cap setting failed %d\n", __FUNCTION__, bcmerror));
- }
-}
-
-void
-dhd_conf_force_wme(dhd_pub_t *dhd)
-{
- int bcmerror = -1;
- char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */
-
- if (dhd->conf->chip == BCM43362_CHIP_ID && dhd->conf->force_wme_ac) {
- bcm_mkiovar("force_wme_ac", (char *)&dhd->conf->force_wme_ac, 4, iovbuf, sizeof(iovbuf));
- if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
- CONFIG_ERROR(("%s: force_wme_ac setting failed %d\n", __FUNCTION__, bcmerror));
- }
-}
-
-void
dhd_conf_get_wme(dhd_pub_t *dhd, edcf_acparam_t *acp)
{
int bcmerror = -1;
@@ -678,22 +945,22 @@
CONFIG_TRACE(("%s: BK: aci %d aifsn %d ecwmin %d ecwmax %d size %d\n", __FUNCTION__,
acparam->ACI, acparam->ACI&EDCF_AIFSN_MASK,
acparam->ECW&EDCF_ECWMIN_MASK, (acparam->ECW&EDCF_ECWMAX_MASK)>>EDCF_ECWMAX_SHIFT,
- sizeof(acp)));
+ (int)sizeof(acp)));
acparam = &acp[AC_BE];
CONFIG_TRACE(("%s: BE: aci %d aifsn %d ecwmin %d ecwmax %d size %d\n", __FUNCTION__,
acparam->ACI, acparam->ACI&EDCF_AIFSN_MASK,
acparam->ECW&EDCF_ECWMIN_MASK, (acparam->ECW&EDCF_ECWMAX_MASK)>>EDCF_ECWMAX_SHIFT,
- sizeof(acp)));
+ (int)sizeof(acp)));
acparam = &acp[AC_VI];
CONFIG_TRACE(("%s: VI: aci %d aifsn %d ecwmin %d ecwmax %d size %d\n", __FUNCTION__,
acparam->ACI, acparam->ACI&EDCF_AIFSN_MASK,
acparam->ECW&EDCF_ECWMIN_MASK, (acparam->ECW&EDCF_ECWMAX_MASK)>>EDCF_ECWMAX_SHIFT,
- sizeof(acp)));
+ (int)sizeof(acp)));
acparam = &acp[AC_VO];
CONFIG_TRACE(("%s: VO: aci %d aifsn %d ecwmin %d ecwmax %d size %d\n", __FUNCTION__,
acparam->ACI, acparam->ACI&EDCF_AIFSN_MASK,
acparam->ECW&EDCF_ECWMIN_MASK, (acparam->ECW&EDCF_ECWMAX_MASK)>>EDCF_ECWMAX_SHIFT,
- sizeof(acp)));
+ (int)sizeof(acp)));
return;
}
@@ -701,10 +968,8 @@
void
dhd_conf_update_wme(dhd_pub_t *dhd, edcf_acparam_t *acparam_cur, int aci)
{
- int bcmerror = -1;
int aifsn, ecwmin, ecwmax;
edcf_acparam_t *acp;
- char iovbuf[WLC_IOCTL_SMLEN];
struct dhd_conf *conf = dhd->conf;
/* Default value */
@@ -729,19 +994,15 @@
CONFIG_TRACE(("%s: mod aci %d aifsn %d ecwmin %d ecwmax %d size %d\n", __FUNCTION__,
acp->ACI, acp->ACI&EDCF_AIFSN_MASK,
acp->ECW&EDCF_ECWMIN_MASK, (acp->ECW&EDCF_ECWMAX_MASK)>>EDCF_ECWMAX_SHIFT,
- sizeof(edcf_acparam_t)));
+ (int)sizeof(edcf_acparam_t)));
/*
* Now use buf as an output buffer.
* Put WME acparams after "wme_ac\0" in buf.
* NOTE: only one of the four ACs can be set at a time.
*/
- bcm_mkiovar("wme_ac_sta", (char*)acp, sizeof(edcf_acparam_t), iovbuf,
- sizeof(iovbuf));
- if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0)) < 0) {
- CONFIG_ERROR(("%s: wme_ac_sta setting failed %d\n", __FUNCTION__, bcmerror));
- return;
- }
+ dhd_conf_set_fw_string_struct_cmd(dhd, "wme_ac_sta", (char *)acp, sizeof(edcf_acparam_t), FALSE);
+
}
void
@@ -773,58 +1034,35 @@
return;
}
-void
-dhd_conf_set_stbc(dhd_pub_t *dhd)
-{
- int bcmerror = -1;
- char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */
- uint stbc = 0;
-
- if (dhd->conf->chip == BCM4324_CHIP_ID && dhd->conf->stbc >= 0) {
- stbc = (uint)dhd->conf->stbc;
- printf("%s: set stbc_tx %d\n", __FUNCTION__, stbc);
- bcm_mkiovar("stbc_tx", (char *)&stbc, 4, iovbuf, sizeof(iovbuf));
- if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
- CONFIG_ERROR(("%s: stbc_tx setting failed %d\n", __FUNCTION__, bcmerror));
-
- printf("%s: set stbc_rx %d\n", __FUNCTION__, stbc);
- bcm_mkiovar("stbc_rx", (char *)&stbc, 4, iovbuf, sizeof(iovbuf));
- if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
- CONFIG_ERROR(("%s: stbc_rx setting failed %d\n", __FUNCTION__, bcmerror));
- }
-}
-
-void
-dhd_conf_set_phyoclscdenable(dhd_pub_t *dhd)
-{
- int bcmerror = -1;
- char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */
- uint phy_oclscdenable = 0;
-
- if (dhd->conf->chip == BCM4324_CHIP_ID && dhd->conf->phy_oclscdenable >= 0) {
- phy_oclscdenable = (uint)dhd->conf->phy_oclscdenable;
- printf("%s: set stbc_tx %d\n", __FUNCTION__, phy_oclscdenable);
- bcm_mkiovar("phy_oclscdenable", (char *)&phy_oclscdenable, 4, iovbuf, sizeof(iovbuf));
- if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
- CONFIG_ERROR(("%s: stbc_tx setting failed %d\n", __FUNCTION__, bcmerror));
- }
-}
-
#ifdef PKT_FILTER_SUPPORT
void
dhd_conf_add_pkt_filter(dhd_pub_t *dhd)
{
int i;
+ char str[12];
+#define MACS "%02x%02x%02x%02x%02x%02x"
/*
- All pkt: pkt_filter_add=99 0 0 0 0x000000000000 0x000000000000
- Netbios pkt: 120 0 0 12 0xFFFF000000000000000000FF000000000000000000000000FFFF 0x0800000000000000000000110000000000000000000000000089
- */
- for(i=0; i<dhd->conf->pkt_filter_add.count; i++) {
+ * All pkt: pkt_filter_add=99 0 0 0 0x000000000000 0x000000000000
+ * Netbios pkt: 120 0 0 12 0xFFFF000000000000000000FF000000000000000000000000FFFF 0x0800000000000000000000110000000000000000000000000089
+ */
+ for(i=0; i<dhd->conf->pkt_filter_add.count; i++) {
dhd->pktfilter[i+dhd->pktfilter_count] = dhd->conf->pkt_filter_add.filter[i];
printf("%s: %s\n", __FUNCTION__, dhd->pktfilter[i+dhd->pktfilter_count]);
}
dhd->pktfilter_count += i;
+
+ if (dhd->conf->pkt_filter_magic) {
+ strcpy(&dhd->conf->pkt_filter_add.filter[dhd->conf->pkt_filter_add.count][0], "256 0 1 0 0x");
+ for (i=0; i<16; i++)
+ strcat(&dhd->conf->pkt_filter_add.filter[dhd->conf->pkt_filter_add.count][0], "FFFFFFFFFFFF");
+ strcat(&dhd->conf->pkt_filter_add.filter[dhd->conf->pkt_filter_add.count][0], " 0x");
+ sprintf(str, MACS, MAC2STRDBG(dhd->mac.octet));
+ for (i=0; i<16; i++)
+ strcat(&dhd->conf->pkt_filter_add.filter[dhd->conf->pkt_filter_add.count][0], str);
+ dhd->pktfilter[dhd->pktfilter_count] = dhd->conf->pkt_filter_add.filter[dhd->conf->pkt_filter_add.count];
+ dhd->pktfilter_count += 1;
+ }
}
bool
@@ -832,11 +1070,14 @@
{
int i;
- for(i=0; i<dhd->conf->pkt_filter_del.count; i++) {
- if (id == dhd->conf->pkt_filter_del.id[i]) {
- printf("%s: %d\n", __FUNCTION__, dhd->conf->pkt_filter_del.id[i]);
- return true;
+ if (dhd && dhd->conf) {
+ for (i=0; i < dhd->conf->pkt_filter_del.count; i++) {
+ if (id == dhd->conf->pkt_filter_del.id[i]) {
+ printf("%s: %d\n", __FUNCTION__, dhd->conf->pkt_filter_del.id[i]);
+ return true;
+ }
}
+ return false;
}
return false;
}
@@ -869,85 +1110,28 @@
#endif /* PKT_FILTER_SUPPORT */
void
-dhd_conf_set_srl(dhd_pub_t *dhd)
-{
- int bcmerror = -1;
- uint srl = 0;
-
- if (dhd->conf->srl >= 0) {
- srl = (uint)dhd->conf->srl;
- printf("%s: set srl %d\n", __FUNCTION__, srl);
- if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_SET_SRL, &srl , sizeof(srl), true, 0)) < 0)
- CONFIG_ERROR(("%s: WLC_SET_SRL setting failed %d\n", __FUNCTION__, bcmerror));
- }
-}
-
-void
-dhd_conf_set_lrl(dhd_pub_t *dhd)
-{
- int bcmerror = -1;
- uint lrl = 0;
-
- if (dhd->conf->lrl >= 0) {
- lrl = (uint)dhd->conf->lrl;
- printf("%s: set lrl %d\n", __FUNCTION__, lrl);
- if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_SET_LRL, &lrl , sizeof(lrl), true, 0)) < 0)
- CONFIG_ERROR(("%s: WLC_SET_LRL setting failed %d\n", __FUNCTION__, bcmerror));
- }
-}
-
-void
-dhd_conf_set_glom(dhd_pub_t *dhd)
-{
- int bcmerror = -1;
- char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */
- uint32 bus_txglom = 0;
-
- if (dhd->conf->bus_txglom) {
- bus_txglom = (uint)dhd->conf->bus_txglom;
- printf("%s: set bus:txglom %d\n", __FUNCTION__, bus_txglom);
- bcm_mkiovar("bus:txglom", (char *)&bus_txglom, 4, iovbuf, sizeof(iovbuf));
- dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
- if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
- CONFIG_ERROR(("%s: bus:txglom setting failed %d\n", __FUNCTION__, bcmerror));
- }
-}
-
-void
-dhd_conf_set_ampdu_ba_wsize(dhd_pub_t *dhd)
+dhd_conf_set_disable_proptx(dhd_pub_t *dhd)
{
- int bcmerror = -1;
- char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */
- uint32 ampdu_ba_wsize = dhd->conf->ampdu_ba_wsize;
-
- /* Set ampdu ba wsize */
- if (ampdu_ba_wsize > 0) {
- printf("%s: set ampdu_ba_wsize %d\n", __FUNCTION__, ampdu_ba_wsize);
- bcm_mkiovar("ampdu_ba_wsize", (char *)&ampdu_ba_wsize, 4, iovbuf, sizeof(iovbuf));
- if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
- sizeof(iovbuf), TRUE, 0)) < 0) {
- DHD_ERROR(("%s Set ampdu_ba_wsize to %d failed %d\n",
- __FUNCTION__, ampdu_ba_wsize, bcmerror));
- }
- }
+ printf("%s: set disable_proptx %d\n", __FUNCTION__, dhd->conf->disable_proptx);
+ disable_proptx = dhd->conf->disable_proptx;
}
-void
-dhd_conf_set_spect(dhd_pub_t *dhd)
+int
+dhd_conf_get_pm(dhd_pub_t *dhd)
{
- int bcmerror = -1;
- uint spect = 0;
-
- if (dhd->conf->spect >= 0) {
- spect = (uint)dhd->conf->spect;
- if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_DOWN, NULL, 0, TRUE, 0)) < 0)
- CONFIG_ERROR(("%s: WLC_DOWN setting failed %d\n", __FUNCTION__, bcmerror));
- printf("%s: set spect %d\n", __FUNCTION__, spect);
- if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_SET_SPECT_MANAGMENT, &spect , sizeof(spect), true, 0)) < 0)
- CONFIG_ERROR(("%s: WLC_SET_SPECT_MANAGMENT setting failed %d\n", __FUNCTION__, bcmerror));
- }
+ if (dhd && dhd->conf)
+ return dhd->conf->pm;
+ return -1;
}
+int
+dhd_conf_get_tcpack_sup_mode(dhd_pub_t *dhd)
+{
+ if (dhd && dhd->conf)
+ return dhd->conf->tcpack_sup_mode;
+ return -1;
+}
+
unsigned int
process_config_vars(char *varbuf, unsigned int len, char *pickbuf, char *param)
{
@@ -982,13 +1166,13 @@
changenewline = FALSE;
continue;
}
- if (!memcmp(&varbuf[n], param, strlen(param)) && column==0) {
+ if (!memcmp(&varbuf[n], param, strlen(param)) && column == 0) {
pick = TRUE;
column = strlen(param);
n += column;
pick_column = 0;
} else {
- if (pick && column==0)
+ if (pick && column == 0)
pick = FALSE;
else
column++;
@@ -996,7 +1180,7 @@
if (pick) {
if (varbuf[n] == 0x9)
continue;
- if (pick_column>0 && pickbuf[pick_column-1]==' ' && varbuf[n]==' ')
+ if (pick_column>0 && pickbuf[pick_column-1] == ' ' && varbuf[n] == ' ')
continue;
pickbuf[pick_column] = varbuf[n];
pick_column++;
@@ -1010,7 +1194,14 @@
dhd_conf_read_log_level(dhd_pub_t *dhd, char *bufp, uint len)
{
uint len_val;
- char pick[MAXSZ_BUF];
+ char *pick;
+
+ pick = MALLOC(dhd->osh, MAXSZ_BUF);
+ if (!pick) {
+ CONFIG_ERROR(("%s: Failed to allocate memory %d bytes\n",
+ __FUNCTION__, MAXSZ_BUF));
+ return;
+ }
/* Process dhd_msglevel */
memset(pick, 0, MAXSZ_BUF);
@@ -1019,6 +1210,7 @@
dhd_msg_level = (int)simple_strtol(pick, NULL, 0);
printf("%s: dhd_msg_level = 0x%X\n", __FUNCTION__, dhd_msg_level);
}
+#ifdef BCMSDIO
/* Process sd_msglevel */
memset(pick, 0, MAXSZ_BUF);
len_val = process_config_vars(bufp, len, pick, "sd_msglevel=");
@@ -1026,6 +1218,7 @@
sd_msglevel = (int)simple_strtol(pick, NULL, 0);
printf("%s: sd_msglevel = 0x%X\n", __FUNCTION__, sd_msglevel);
}
+#endif
/* Process android_msg_level */
memset(pick, 0, MAXSZ_BUF);
len_val = process_config_vars(bufp, len, pick, "android_msg_level=");
@@ -1059,6 +1252,7 @@
}
#endif
+#if defined(DHD_DEBUG)
/* Process dhd_console_ms */
memset(pick, 0, MAXSZ_BUF);
len_val = process_config_vars(bufp, len, pick, "dhd_console_ms=");
@@ -1066,14 +1260,25 @@
dhd_console_ms = (int)simple_strtol(pick, NULL, 0);
printf("%s: dhd_console_ms = 0x%X\n", __FUNCTION__, dhd_console_ms);
}
+#endif
+
+ if (pick)
+ MFREE(dhd->osh, pick, MAXSZ_BUF);
}
void
dhd_conf_read_wme_ac_params(dhd_pub_t *dhd, char *bufp, uint len)
{
uint len_val;
- char pick[MAXSZ_BUF];
+ char *pick;
struct dhd_conf *conf = dhd->conf;
+
+ pick = MALLOC(dhd->osh, MAXSZ_BUF);
+ if (!pick) {
+ CONFIG_ERROR(("%s: Failed to allocate memory %d bytes\n",
+ __FUNCTION__, MAXSZ_BUF));
+ return;
+ }
/* Process WMM parameters */
memset(pick, 0, MAXSZ_BUF);
@@ -1169,15 +1374,214 @@
}
}
-}
-
-void
+ if (pick)
+ MFREE(dhd->osh, pick, MAXSZ_BUF);
+
+}
+
+void
+dhd_conf_read_fw_by_mac(dhd_pub_t *dhd, char *bufp, uint len)
+{
+ uint len_val;
+ int i, j;
+ char *pick;
+ char *pch, *pick_tmp;
+ wl_mac_list_t *mac_list;
+ wl_mac_range_t *mac_range;
+ struct dhd_conf *conf = dhd->conf;
+
+ pick = MALLOC(dhd->osh, MAXSZ_BUF);
+ if (!pick) {
+ CONFIG_ERROR(("%s: Failed to allocate memory %d bytes\n",
+ __FUNCTION__, MAXSZ_BUF));
+ return;
+ }
+
+ /* Process fw_by_mac:
+ * fw_by_mac=[fw_mac_num] \
+ * [fw_name1] [mac_num1] [oui1-1] [nic_start1-1] [nic_end1-1] \
+ * [oui1-1] [nic_start1-1] [nic_end1-1]... \
+ * [oui1-n] [nic_start1-n] [nic_end1-n] \
+ * [fw_name2] [mac_num2] [oui2-1] [nic_start2-1] [nic_end2-1] \
+ * [oui2-1] [nic_start2-1] [nic_end2-1]... \
+ * [oui2-n] [nic_start2-n] [nic_end2-n] \
+ * Ex: fw_by_mac=2 \
+ * fw_bcmdhd1.bin 2 0x0022F4 0xE85408 0xE8549D 0x983B16 0x3557A9 0x35582A \
+ * fw_bcmdhd2.bin 3 0x0022F4 0xE85408 0xE8549D 0x983B16 0x3557A9 0x35582A \
+ * 0x983B16 0x916157 0x916487
+ */
+ memset(pick, 0, MAXSZ_BUF);
+ len_val = process_config_vars(bufp, len, pick, "fw_by_mac=");
+ if (len_val) {
+ pick_tmp = pick;
+ pch = bcmstrtok(&pick_tmp, " ", 0);
+ conf->fw_by_mac.count = (uint32)simple_strtol(pch, NULL, 0);
+ if (!(mac_list = kmalloc(sizeof(wl_mac_list_t)*conf->fw_by_mac.count, GFP_KERNEL))) {
+ conf->fw_by_mac.count = 0;
+ CONFIG_ERROR(("%s: kmalloc failed\n", __FUNCTION__));
+ }
+ printf("%s: fw_count=%d\n", __FUNCTION__, conf->fw_by_mac.count);
+ conf->fw_by_mac.m_mac_list_head = mac_list;
+ for (i=0; i<conf->fw_by_mac.count; i++) {
+ pch = bcmstrtok(&pick_tmp, " ", 0);
+ strcpy(mac_list[i].name, pch);
+ pch = bcmstrtok(&pick_tmp, " ", 0);
+ mac_list[i].count = (uint32)simple_strtol(pch, NULL, 0);
+ printf("%s: name=%s, mac_count=%d\n", __FUNCTION__,
+ mac_list[i].name, mac_list[i].count);
+ if (!(mac_range = kmalloc(sizeof(wl_mac_range_t)*mac_list[i].count, GFP_KERNEL))) {
+ mac_list[i].count = 0;
+ CONFIG_ERROR(("%s: kmalloc failed\n", __FUNCTION__));
+ break;
+ }
+ mac_list[i].mac = mac_range;
+ for (j=0; j<mac_list[i].count; j++) {
+ pch = bcmstrtok(&pick_tmp, " ", 0);
+ mac_range[j].oui = (uint32)simple_strtol(pch, NULL, 0);
+ pch = bcmstrtok(&pick_tmp, " ", 0);
+ mac_range[j].nic_start = (uint32)simple_strtol(pch, NULL, 0);
+ pch = bcmstrtok(&pick_tmp, " ", 0);
+ mac_range[j].nic_end = (uint32)simple_strtol(pch, NULL, 0);
+ printf("%s: oui=0x%06X, nic_start=0x%06X, nic_end=0x%06X\n",
+ __FUNCTION__, mac_range[j].oui,
+ mac_range[j].nic_start, mac_range[j].nic_end);
+ }
+ }
+ }
+
+ if (pick)
+ MFREE(dhd->osh, pick, MAXSZ_BUF);
+}
+
+void
+dhd_conf_read_nv_by_mac(dhd_pub_t *dhd, char *bufp, uint len)
+{
+ uint len_val;
+ int i, j;
+ char *pick;
+ char *pch, *pick_tmp;
+ wl_mac_list_t *mac_list;
+ wl_mac_range_t *mac_range;
+ struct dhd_conf *conf = dhd->conf;
+
+ pick = MALLOC(dhd->osh, MAXSZ_BUF);
+ if (!pick) {
+ CONFIG_ERROR(("%s: Failed to allocate memory %d bytes\n",
+ __FUNCTION__, MAXSZ_BUF));
+ return;
+ }
+
+ /* Process nv_by_mac:
+ * [nv_by_mac]: The same format as fw_by_mac
+ */
+ memset(pick, 0, MAXSZ_BUF);
+ len_val = process_config_vars(bufp, len, pick, "nv_by_mac=");
+ if (len_val) {
+ pick_tmp = pick;
+ pch = bcmstrtok(&pick_tmp, " ", 0);
+ conf->nv_by_mac.count = (uint32)simple_strtol(pch, NULL, 0);
+ if (!(mac_list = kmalloc(sizeof(wl_mac_list_t)*conf->nv_by_mac.count, GFP_KERNEL))) {
+ conf->nv_by_mac.count = 0;
+ CONFIG_ERROR(("%s: kmalloc failed\n", __FUNCTION__));
+ }
+ printf("%s: nv_count=%d\n", __FUNCTION__, conf->nv_by_mac.count);
+ conf->nv_by_mac.m_mac_list_head = mac_list;
+ for (i=0; i<conf->nv_by_mac.count; i++) {
+ pch = bcmstrtok(&pick_tmp, " ", 0);
+ strcpy(mac_list[i].name, pch);
+ pch = bcmstrtok(&pick_tmp, " ", 0);
+ mac_list[i].count = (uint32)simple_strtol(pch, NULL, 0);
+ printf("%s: name=%s, mac_count=%d\n", __FUNCTION__,
+ mac_list[i].name, mac_list[i].count);
+ if (!(mac_range = kmalloc(sizeof(wl_mac_range_t)*mac_list[i].count, GFP_KERNEL))) {
+ mac_list[i].count = 0;
+ CONFIG_ERROR(("%s: kmalloc failed\n", __FUNCTION__));
+ break;
+ }
+ mac_list[i].mac = mac_range;
+ for (j=0; j<mac_list[i].count; j++) {
+ pch = bcmstrtok(&pick_tmp, " ", 0);
+ mac_range[j].oui = (uint32)simple_strtol(pch, NULL, 0);
+ pch = bcmstrtok(&pick_tmp, " ", 0);
+ mac_range[j].nic_start = (uint32)simple_strtol(pch, NULL, 0);
+ pch = bcmstrtok(&pick_tmp, " ", 0);
+ mac_range[j].nic_end = (uint32)simple_strtol(pch, NULL, 0);
+ printf("%s: oui=0x%06X, nic_start=0x%06X, nic_end=0x%06X\n",
+ __FUNCTION__, mac_range[j].oui,
+ mac_range[j].nic_start, mac_range[j].nic_end);
+ }
+ }
+ }
+
+ if (pick)
+ MFREE(dhd->osh, pick, MAXSZ_BUF);
+}
+
+void
+dhd_conf_read_nv_by_chip(dhd_pub_t *dhd, char *bufp, uint len)
+{
+ uint len_val;
+ int i;
+ char *pick;
+ char *pch, *pick_tmp;
+ wl_chip_nv_path_t *chip_nv_path;
+ struct dhd_conf *conf = dhd->conf;
+
+ pick = MALLOC(dhd->osh, MAXSZ_BUF);
+ if (!pick) {
+ CONFIG_ERROR(("%s: Failed to allocate memory %d bytes\n",
+ __FUNCTION__, MAXSZ_BUF));
+ return;
+ }
+
+ /* Process nv_by_chip:
+ * nv_by_chip=[nv_chip_num] \
+ * [chip1] [chiprev1] [nv_name1] [chip2] [chiprev2] [nv_name2] \
+ * Ex: nv_by_chip=2 \
+ * 43430 0 nvram_ap6212.txt 43430 1 nvram_ap6212a.txt \
+ */
+ memset(pick, 0, MAXSZ_BUF);
+ len_val = process_config_vars(bufp, len, pick, "nv_by_chip=");
+ if (len_val) {
+ pick_tmp = pick;
+ pch = bcmstrtok(&pick_tmp, " ", 0);
+ conf->nv_by_chip.count = (uint32)simple_strtol(pch, NULL, 0);
+ if (!(chip_nv_path = kmalloc(sizeof(wl_mac_list_t)*conf->nv_by_chip.count, GFP_KERNEL))) {
+ conf->nv_by_chip.count = 0;
+ CONFIG_ERROR(("%s: kmalloc failed\n", __FUNCTION__));
+ }
+ printf("%s: nv_by_chip_count=%d\n", __FUNCTION__, conf->nv_by_chip.count);
+ conf->nv_by_chip.m_chip_nv_path_head = chip_nv_path;
+ for (i=0; i<conf->nv_by_chip.count; i++) {
+ pch = bcmstrtok(&pick_tmp, " ", 0);
+ chip_nv_path[i].chip = (uint32)simple_strtol(pch, NULL, 0);
+ pch = bcmstrtok(&pick_tmp, " ", 0);
+ chip_nv_path[i].chiprev = (uint32)simple_strtol(pch, NULL, 0);
+ pch = bcmstrtok(&pick_tmp, " ", 0);
+ strcpy(chip_nv_path[i].name, pch);
+ printf("%s: chip=0x%x, chiprev=%d, name=%s\n", __FUNCTION__,
+ chip_nv_path[i].chip, chip_nv_path[i].chiprev, chip_nv_path[i].name);
+ }
+ }
+
+ if (pick)
+ MFREE(dhd->osh, pick, MAXSZ_BUF);
+}
+
+void
dhd_conf_read_roam_params(dhd_pub_t *dhd, char *bufp, uint len)
{
uint len_val;
- char pick[MAXSZ_BUF];
+ char *pick;
struct dhd_conf *conf = dhd->conf;
-
+
+ pick = MALLOC(dhd->osh, MAXSZ_BUF);
+ if (!pick) {
+ CONFIG_ERROR(("%s: Failed to allocate memory %d bytes\n",
+ __FUNCTION__, MAXSZ_BUF));
+ return;
+ }
+
/* Process roam */
memset(pick, 0, MAXSZ_BUF);
len_val = process_config_vars(bufp, len, pick, "roam_off=");
@@ -1229,48 +1633,83 @@
conf->fullroamperiod);
}
+ if (pick)
+ MFREE(dhd->osh, pick, MAXSZ_BUF);
+
+}
+
+void
+dhd_conf_read_country_list(dhd_pub_t *dhd, char *bufp, uint len)
+{
+ uint len_val;
+ int i;
+ char *pick, *pch, *pick_tmp;
+ struct dhd_conf *conf = dhd->conf;
+
+ pick = MALLOC(dhd->osh, MAXSZ_BUF);
+ if (!pick) {
+ CONFIG_ERROR(("%s: Failed to allocate memory %d bytes\n",
+ __FUNCTION__, MAXSZ_BUF));
+ return;
+ }
+
+ /* Process country_list:
+ * country_list=[country1]:[ccode1]/[regrev1],
+ * [country2]:[ccode2]/[regrev2] \
+ * Ex: country_list=US:US/0, TW:TW/1
+ */
+ memset(pick, 0, MAXSZ_BUF);
+ len_val = process_config_vars(bufp, len, pick, "country_list=");
+ if (len_val) {
+ pick_tmp = pick;
+ for (i=0; i<CONFIG_COUNTRY_LIST_SIZE; i++) {
+ /* Process country code */
+ pch = bcmstrtok(&pick_tmp, ":", 0);
+ if (!pch)
+ break;
+ strcpy(conf->country_list.cspec[i].country_abbrev, pch);
+ pch = bcmstrtok(&pick_tmp, "/", 0);
+ if (!pch)
+ break;
+ memcpy(conf->country_list.cspec[i].ccode, pch, 2);
+ pch = bcmstrtok(&pick_tmp, ", ", 0);
+ if (!pch)
+ break;
+ conf->country_list.cspec[i].rev = (int32)simple_strtol(pch, NULL, 10);
+ conf->country_list.count ++;
+ CONFIG_TRACE(("%s: country_list abbrev=%s, ccode=%s, regrev=%d\n", __FUNCTION__,
+ conf->country_list.cspec[i].country_abbrev,
+ conf->country_list.cspec[i].ccode,
+ conf->country_list.cspec[i].rev));
+ }
+ printf("%s: %d country in list\n", __FUNCTION__, conf->country_list.count);
+ }
+
+ if (pick)
+ MFREE(dhd->osh, pick, MAXSZ_BUF);
}
-/*
- * [fw_by_mac]:
- * fw_by_mac=[fw_mac_num] \
- * [fw_name1] [mac_num1] [oui1-1] [nic_start1-1] [nic_end1-1] \
- * [oui1-1] [nic_start1-1] [nic_end1-1]... \
- * [oui1-n] [nic_start1-n] [nic_end1-n] \
- * [fw_name2] [mac_num2] [oui2-1] [nic_start2-1] [nic_end2-1] \
- * [oui2-1] [nic_start2-1] [nic_end2-1]... \
- * [oui2-n] [nic_start2-n] [nic_end2-n] \
- * Ex: fw_by_mac=2 \
- * fw_bcmdhd1.bin 2 0x0022F4 0xE85408 0xE8549D 0x983B16 0x3557A9 0x35582A \
- * fw_bcmdhd2.bin 3 0x0022F4 0xE85408 0xE8549D 0x983B16 0x3557A9 0x35582A \
- * 0x983B16 0x916157 0x916487
- * [nv_by_mac]: The same format as fw_by_mac
- *
-*/
int
-dhd_conf_read_config(dhd_pub_t *dhd)
+dhd_conf_read_config(dhd_pub_t *dhd, char *conf_path)
{
- int bcmerror = -1, i, j;
+ int bcmerror = -1, i;
uint len, len_val;
void * image = NULL;
char * memblock = NULL;
- char *bufp, pick[MAXSZ_BUF], *pch, *pick_tmp;
- char *pconf_path;
+ char *bufp, *pick = NULL, *pch, *pick_tmp;
bool conf_file_exists;
- wl_mac_list_t *mac_list;
- wl_mac_range_t *mac_range;
struct dhd_conf *conf = dhd->conf;
- pconf_path = dhd->conf_path;
-
- conf_file_exists = ((pconf_path != NULL) && (pconf_path[0] != '\0'));
- if (!conf_file_exists)
- return (0);
+ conf_file_exists = ((conf_path != NULL) && (conf_path[0] != '\0'));
+ if (!conf_file_exists) {
+ printf("%s: config path %s\n", __FUNCTION__, conf_path);
+ return (0);
+ }
if (conf_file_exists) {
- image = dhd_os_open_image(pconf_path);
+ image = dhd_os_open_image(conf_path);
if (image == NULL) {
- printk("%s: Ignore config file %s\n", __FUNCTION__, pconf_path);
+ printf("%s: Ignore config file %s\n", __FUNCTION__, conf_path);
goto err;
}
}
@@ -1279,6 +1718,13 @@
if (memblock == NULL) {
CONFIG_ERROR(("%s: Failed to allocate memory %d bytes\n",
__FUNCTION__, MAXSZ_CONFIG));
+ goto err;
+ }
+
+ pick = MALLOC(dhd->osh, MAXSZ_BUF);
+ if (!pick) {
+ CONFIG_ERROR(("%s: Failed to allocate memory %d bytes\n",
+ __FUNCTION__, MAXSZ_BUF));
goto err;
}
@@ -1294,104 +1740,14 @@
dhd_conf_read_log_level(dhd, bufp, len);
dhd_conf_read_roam_params(dhd, bufp, len);
dhd_conf_read_wme_ac_params(dhd, bufp, len);
-
- /* Process fw_by_mac */
- memset(pick, 0, MAXSZ_BUF);
- len_val = process_config_vars(bufp, len, pick, "fw_by_mac=");
- if (len_val) {
- pick_tmp = pick;
- pch = bcmstrtok(&pick_tmp, " ", 0);
- conf->fw_by_mac.count = (uint32)simple_strtol(pch, NULL, 0);
- if (!(mac_list = kmalloc(sizeof(wl_mac_list_t)*conf->fw_by_mac.count, GFP_KERNEL))) {
- conf->fw_by_mac.count = 0;
- CONFIG_ERROR(("%s: kmalloc failed\n", __FUNCTION__));
- }
- printf("%s: fw_count=%d\n", __FUNCTION__, conf->fw_by_mac.count);
- conf->fw_by_mac.m_mac_list_head = mac_list;
- for (i=0; i<conf->fw_by_mac.count; i++) {
- pch = bcmstrtok(&pick_tmp, " ", 0);
- strcpy(mac_list[i].name, pch);
- pch = bcmstrtok(&pick_tmp, " ", 0);
- mac_list[i].count = (uint32)simple_strtol(pch, NULL, 0);
- printf("%s: name=%s, mac_count=%d\n", __FUNCTION__,
- mac_list[i].name, mac_list[i].count);
- if (!(mac_range = kmalloc(sizeof(wl_mac_range_t)*mac_list[i].count, GFP_KERNEL))) {
- mac_list[i].count = 0;
- CONFIG_ERROR(("%s: kmalloc failed\n", __FUNCTION__));
- break;
- }
- mac_list[i].mac = mac_range;
- for (j=0; j<mac_list[i].count; j++) {
- pch = bcmstrtok(&pick_tmp, " ", 0);
- mac_range[j].oui = (uint32)simple_strtol(pch, NULL, 0);
- pch = bcmstrtok(&pick_tmp, " ", 0);
- mac_range[j].nic_start = (uint32)simple_strtol(pch, NULL, 0);
- pch = bcmstrtok(&pick_tmp, " ", 0);
- mac_range[j].nic_end = (uint32)simple_strtol(pch, NULL, 0);
- printf("%s: oui=0x%06X, nic_start=0x%06X, nic_end=0x%06X\n",
- __FUNCTION__, mac_range[j].oui,
- mac_range[j].nic_start, mac_range[j].nic_end);
- }
- }
- }
-
- /* Process nv_by_mac */
- memset(pick, 0, MAXSZ_BUF);
- len_val = process_config_vars(bufp, len, pick, "nv_by_mac=");
- if (len_val) {
- pick_tmp = pick;
- pch = bcmstrtok(&pick_tmp, " ", 0);
- conf->nv_by_mac.count = (uint32)simple_strtol(pch, NULL, 0);
- if (!(mac_list = kmalloc(sizeof(wl_mac_list_t)*conf->nv_by_mac.count, GFP_KERNEL))) {
- conf->nv_by_mac.count = 0;
- CONFIG_ERROR(("%s: kmalloc failed\n", __FUNCTION__));
- }
- printf("%s: nv_count=%d\n", __FUNCTION__, conf->nv_by_mac.count);
- conf->nv_by_mac.m_mac_list_head = mac_list;
- for (i=0; i<conf->nv_by_mac.count; i++) {
- pch = bcmstrtok(&pick_tmp, " ", 0);
- strcpy(mac_list[i].name, pch);
- pch = bcmstrtok(&pick_tmp, " ", 0);
- mac_list[i].count = (uint32)simple_strtol(pch, NULL, 0);
- printf("%s: name=%s, mac_count=%d\n", __FUNCTION__,
- mac_list[i].name, mac_list[i].count);
- if (!(mac_range = kmalloc(sizeof(wl_mac_range_t)*mac_list[i].count, GFP_KERNEL))) {
- mac_list[i].count = 0;
- CONFIG_ERROR(("%s: kmalloc failed\n", __FUNCTION__));
- break;
- }
- mac_list[i].mac = mac_range;
- for (j=0; j<mac_list[i].count; j++) {
- pch = bcmstrtok(&pick_tmp, " ", 0);
- mac_range[j].oui = (uint32)simple_strtol(pch, NULL, 0);
- pch = bcmstrtok(&pick_tmp, " ", 0);
- mac_range[j].nic_start = (uint32)simple_strtol(pch, NULL, 0);
- pch = bcmstrtok(&pick_tmp, " ", 0);
- mac_range[j].nic_end = (uint32)simple_strtol(pch, NULL, 0);
- printf("%s: oui=0x%06X, nic_start=0x%06X, nic_end=0x%06X\n",
- __FUNCTION__, mac_range[j].oui,
- mac_range[j].nic_start, mac_range[j].nic_end);
- }
- }
- }
-
- /* Process firmware path */
- memset(pick, 0, MAXSZ_BUF);
- len_val = process_config_vars(bufp, len, pick, "fw_path=");
- if (len_val) {
- memcpy(conf->fw_path, pick, len_val);
- printf("%s: fw_path = %s\n", __FUNCTION__, conf->fw_path);
- }
-
- /* Process nvram path */
- memset(pick, 0, MAXSZ_BUF);
- len_val = process_config_vars(bufp, len, pick, "nv_path=");
- if (len_val) {
- memcpy(conf->nv_path, pick, len_val);
- printf("%s: nv_path = %s\n", __FUNCTION__, conf->nv_path);
- }
-
- /* Process band */
+ dhd_conf_read_fw_by_mac(dhd, bufp, len);
+ dhd_conf_read_nv_by_mac(dhd, bufp, len);
+ dhd_conf_read_nv_by_chip(dhd, bufp, len);
+ dhd_conf_read_country_list(dhd, bufp, len);
+
+ /* Process band:
+ * band=a for 5GHz only and band=b for 2.4GHz only
+ */
memset(pick, 0, MAXSZ_BUF);
len_val = process_config_vars(bufp, len, pick, "band=");
if (len_val) {
@@ -1404,7 +1760,7 @@
printf("%s: band = %d\n", __FUNCTION__, conf->band);
}
- /* Process bandwidth */
+ /* Process mimo_bw_cap */
memset(pick, 0, MAXSZ_BUF);
len_val = process_config_vars(bufp, len, pick, "mimo_bw_cap=");
if (len_val) {
@@ -1448,7 +1804,7 @@
memset(pick, 0, MAXSZ_BUF);
len_val = process_config_vars(bufp, len, pick, "keep_alive_period=");
if (len_val) {
- conf->keep_alive_period = (int)simple_strtol(pick, NULL, 10);
+ conf->keep_alive_period = (uint)simple_strtol(pick, NULL, 10);
printf("%s: keep_alive_period = %d\n", __FUNCTION__,
conf->keep_alive_period);
}
@@ -1469,6 +1825,7 @@
printf("%s: phy_oclscdenable = %d\n", __FUNCTION__, conf->phy_oclscdenable);
}
+#ifdef BCMSDIO
/* Process dhd_doflow parameters */
memset(pick, 0, MAXSZ_BUF);
len_val = process_config_vars(bufp, len, pick, "dhd_doflow=");
@@ -1478,7 +1835,19 @@
else
dhd_doflow = TRUE;
printf("%s: dhd_doflow = %d\n", __FUNCTION__, dhd_doflow);
+ }
+
+ /* Process dhd_slpauto parameters */
+ memset(pick, 0, MAXSZ_BUF);
+ len_val = process_config_vars(bufp, len, pick, "dhd_slpauto=");
+ if (len_val) {
+ if (!strncmp(pick, "0", len_val))
+ dhd_slpauto = FALSE;
+ else
+ dhd_slpauto = TRUE;
+ printf("%s: dhd_slpauto = %d\n", __FUNCTION__, dhd_slpauto);
}
+#endif
/* Process dhd_master_mode parameters */
memset(pick, 0, MAXSZ_BUF);
@@ -1491,7 +1860,10 @@
printf("%s: dhd_master_mode = %d\n", __FUNCTION__, dhd_master_mode);
}
- /* Process pkt_filter_add */
+#ifdef PKT_FILTER_SUPPORT
+ /* Process pkt_filter_add:
+ * All pkt: pkt_filter_add=99 0 0 0 0x000000000000 0x000000000000
+ */
memset(pick, 0, MAXSZ_BUF);
len_val = process_config_vars(bufp, len, pick, "pkt_filter_add=");
pick_tmp = pick;
@@ -1525,6 +1897,7 @@
printf("%d ", conf->pkt_filter_del.id[i]);
printf("\n");
}
+#endif
/* Process srl parameters */
memset(pick, 0, MAXSZ_BUF);
@@ -1546,11 +1919,11 @@
memset(pick, 0, MAXSZ_BUF);
len_val = process_config_vars(bufp, len, pick, "bcn_timeout=");
if (len_val) {
- conf->bcn_timeout= (int)simple_strtol(pick, NULL, 10);
+ conf->bcn_timeout= (uint)simple_strtol(pick, NULL, 10);
printf("%s: bcn_timeout = %d\n", __FUNCTION__, conf->bcn_timeout);
}
- /* Process bus_txglom */
+ /* Process bus:txglom */
memset(pick, 0, MAXSZ_BUF);
len_val = process_config_vars(bufp, len, pick, "bus:txglom=");
if (len_val) {
@@ -1566,7 +1939,7 @@
printf("%s: ampdu_ba_wsize = %d\n", __FUNCTION__, conf->ampdu_ba_wsize);
}
- /* Process kso parameters */
+ /* Process kso_enable parameters */
memset(pick, 0, MAXSZ_BUF);
len_val = process_config_vars(bufp, len, pick, "kso_enable=");
if (len_val) {
@@ -1584,7 +1957,238 @@
conf->spect = (int)simple_strtol(pick, NULL, 10);
printf("%s: spect = %d\n", __FUNCTION__, conf->spect);
}
-
+
+ /* Process txbf parameters */
+ memset(pick, 0, MAXSZ_BUF);
+ len_val = process_config_vars(bufp, len, pick, "txbf=");
+ if (len_val) {
+ conf->txbf = (int)simple_strtol(pick, NULL, 10);
+ printf("%s: txbf = %d\n", __FUNCTION__, conf->txbf);
+ }
+
+ /* Process frameburst parameters */
+ memset(pick, 0, MAXSZ_BUF);
+ len_val = process_config_vars(bufp, len, pick, "frameburst=");
+ if (len_val) {
+ conf->frameburst = (int)simple_strtol(pick, NULL, 10);
+ printf("%s: frameburst = %d\n", __FUNCTION__, conf->frameburst);
+ }
+
+ /* Process lpc parameters */
+ memset(pick, 0, MAXSZ_BUF);
+ len_val = process_config_vars(bufp, len, pick, "lpc=");
+ if (len_val) {
+ conf->lpc = (int)simple_strtol(pick, NULL, 10);
+ printf("%s: lpc = %d\n", __FUNCTION__, conf->lpc);
+ }
+
+ /* Process use_rxchain parameters */
+ memset(pick, 0, MAXSZ_BUF);
+ len_val = process_config_vars(bufp, len, pick, "use_rxchain=");
+ if (len_val) {
+ conf->use_rxchain = (int)simple_strtol(pick, NULL, 10);
+ printf("%s: use_rxchain = %d\n", __FUNCTION__, conf->use_rxchain);
+ }
+
+#if defined(BCMSDIOH_TXGLOM)
+ /* Process txglomsize parameters */
+ memset(pick, 0, MAXSZ_BUF);
+ len_val = process_config_vars(bufp, len, pick, "txglomsize=");
+ if (len_val) {
+ conf->txglomsize = (uint)simple_strtol(pick, NULL, 10);
+ if (conf->txglomsize > SDPCM_MAXGLOM_SIZE)
+ conf->txglomsize = SDPCM_MAXGLOM_SIZE;
+ printf("%s: txglomsize = %d\n", __FUNCTION__, conf->txglomsize);
+ }
+
+ /* Process swtxglom parameters */
+ memset(pick, 0, MAXSZ_BUF);
+ len_val = process_config_vars(bufp, len, pick, "swtxglom=");
+ if (len_val) {
+ if (!strncmp(pick, "0", len_val))
+ conf->swtxglom = FALSE;
+ else
+ conf->swtxglom = TRUE;
+ printf("%s: swtxglom = %d\n", __FUNCTION__, conf->swtxglom);
+ }
+
+ /* Process txglom_ext parameters */
+ memset(pick, 0, MAXSZ_BUF);
+ len_val = process_config_vars(bufp, len, pick, "txglom_ext=");
+ if (len_val) {
+ if (!strncmp(pick, "0", len_val))
+ conf->txglom_ext = FALSE;
+ else
+ conf->txglom_ext = TRUE;
+ printf("%s: txglom_ext = %d\n", __FUNCTION__, conf->txglom_ext);
+ if (conf->txglom_ext) {
+ if ((conf->chip == BCM43362_CHIP_ID) || (conf->chip == BCM4330_CHIP_ID))
+ conf->txglom_bucket_size = 1680;
+ else if (conf->chip == BCM43340_CHIP_ID || conf->chip == BCM43341_CHIP_ID ||
+ conf->chip == BCM4334_CHIP_ID || conf->chip == BCM4324_CHIP_ID)
+ conf->txglom_bucket_size = 1684;
+ }
+ printf("%s: txglom_bucket_size = %d\n", __FUNCTION__, conf->txglom_bucket_size);
+ }
+#endif
+
+ /* Process disable_proptx parameters */
+ memset(pick, 0, MAXSZ_BUF);
+ len_val = process_config_vars(bufp, len, pick, "disable_proptx=");
+ if (len_val) {
+ conf->disable_proptx = (int)simple_strtol(pick, NULL, 10);
+ printf("%s: disable_proptx = %d\n", __FUNCTION__, conf->disable_proptx);
+ }
+
+ /* Process dpc_cpucore parameters */
+ memset(pick, 0, MAXSZ_BUF);
+ len_val = process_config_vars(bufp, len, pick, "dpc_cpucore=");
+ if (len_val) {
+ conf->dpc_cpucore = (int)simple_strtol(pick, NULL, 10);
+ printf("%s: dpc_cpucore = %d\n", __FUNCTION__, conf->dpc_cpucore);
+ }
+
+ /* Process bus:rxglom parameters */
+ memset(pick, 0, MAXSZ_BUF);
+ len_val = process_config_vars(bufp, len, pick, "bus:rxglom=");
+ if (len_val) {
+ if (!strncmp(pick, "0", len_val))
+ conf->bus_rxglom = FALSE;
+ else
+ conf->bus_rxglom = TRUE;
+ printf("%s: bus:rxglom = %d\n", __FUNCTION__, conf->bus_rxglom);
+ }
+
+ /* Process deepsleep parameters */
+ memset(pick, 0, MAXSZ_BUF);
+ len_val = process_config_vars(bufp, len, pick, "deepsleep=");
+ if (len_val) {
+ if (!strncmp(pick, "1", len_val))
+ conf->deepsleep = TRUE;
+ else
+ conf->deepsleep = FALSE;
+ printf("%s: deepsleep = %d\n", __FUNCTION__, conf->deepsleep);
+ }
+
+ /* Process PM parameters */
+ memset(pick, 0, MAXSZ_BUF);
+ len_val = process_config_vars(bufp, len, pick, "PM=");
+ if (len_val) {
+ conf->pm = (int)simple_strtol(pick, NULL, 10);
+ printf("%s: PM = %d\n", __FUNCTION__, conf->pm);
+ }
+
+ /* Process tcpack_sup_mode parameters */
+ memset(pick, 0, MAXSZ_BUF);
+ len_val = process_config_vars(bufp, len, pick, "tcpack_sup_mode=");
+ if (len_val) {
+ conf->tcpack_sup_mode = (uint)simple_strtol(pick, NULL, 10);
+ printf("%s: tcpack_sup_mode = %d\n", __FUNCTION__, conf->tcpack_sup_mode);
+ }
+
+ /* Process dhd_poll parameters */
+ memset(pick, 0, MAXSZ_BUF);
+ len_val = process_config_vars(bufp, len, pick, "dhd_poll=");
+ if (len_val) {
+ if (!strncmp(pick, "0", len_val))
+ conf->dhd_poll = 0;
+ else
+ conf->dhd_poll = 1;
+ printf("%s: dhd_poll = %d\n", __FUNCTION__, conf->dhd_poll);
+ }
+
+ /* Process deferred_tx_len parameters */
+ memset(pick, 0, MAXSZ_BUF);
+ len_val = process_config_vars(bufp, len, pick, "deferred_tx_len=");
+ if (len_val) {
+ conf->deferred_tx_len = (int)simple_strtol(pick, NULL, 10);
+ printf("%s: deferred_tx_len = %d\n", __FUNCTION__, conf->deferred_tx_len);
+ }
+
+ /* Process pktprio8021x parameters */
+ memset(pick, 0, MAXSZ_BUF);
+ len_val = process_config_vars(bufp, len, pick, "pktprio8021x=");
+ if (len_val) {
+ conf->pktprio8021x = (int)simple_strtol(pick, NULL, 10);
+ printf("%s: pktprio8021x = %d\n", __FUNCTION__, conf->pktprio8021x);
+ }
+
+ /* Process txctl_tmo_fix parameters */
+ memset(pick, 0, MAXSZ_BUF);
+ len_val = process_config_vars(bufp, len, pick, "txctl_tmo_fix=");
+ if (len_val) {
+ if (!strncmp(pick, "0", len_val))
+ conf->txctl_tmo_fix = FALSE;
+ else
+ conf->txctl_tmo_fix = TRUE;
+ printf("%s: txctl_tmo_fix = %d\n", __FUNCTION__, conf->txctl_tmo_fix);
+ }
+
+ /* Process tx_in_rx parameters */
+ memset(pick, 0, MAXSZ_BUF);
+ len_val = process_config_vars(bufp, len, pick, "tx_in_rx=");
+ if (len_val) {
+ if (!strncmp(pick, "0", len_val))
+ conf->tx_in_rx = FALSE;
+ else
+ conf->tx_in_rx = TRUE;
+ printf("%s: tx_in_rx = %d\n", __FUNCTION__, conf->tx_in_rx);
+ }
+
+ /* Process dhd_txbound parameters */
+ memset(pick, 0, MAXSZ_BUF);
+ len_val = process_config_vars(bufp, len, pick, "dhd_txbound=");
+ if (len_val) {
+ dhd_txbound = (uint)simple_strtol(pick, NULL, 10);
+ printf("%s: dhd_txbound = %d\n", __FUNCTION__, dhd_txbound);
+ }
+
+ /* Process dhd_rxbound parameters */
+ memset(pick, 0, MAXSZ_BUF);
+ len_val = process_config_vars(bufp, len, pick, "dhd_rxbound=");
+ if (len_val) {
+ dhd_rxbound = (uint)simple_strtol(pick, NULL, 10);
+ printf("%s: dhd_rxbound = %d\n", __FUNCTION__, dhd_rxbound);
+ }
+
+ /* Process tx_max_offset parameters */
+ memset(pick, 0, MAXSZ_BUF);
+ len_val = process_config_vars(bufp, len, pick, "tx_max_offset=");
+ if (len_val) {
+ conf->tx_max_offset = (int)simple_strtol(pick, NULL, 10);
+ printf("%s: tx_max_offset = %d\n", __FUNCTION__, conf->tx_max_offset);
+ }
+
+ /* Process rsdb_mode parameters */
+ memset(pick, 0, MAXSZ_BUF);
+ len_val = process_config_vars(bufp, len, pick, "rsdb_mode=");
+ if (len_val) {
+ conf->rsdb_mode = (int)simple_strtol(pick, NULL, 10);
+ printf("%s: rsdb_mode = %d\n", __FUNCTION__, conf->rsdb_mode);
+ }
+
+ /* Process txglom_mode parameters */
+ memset(pick, 0, MAXSZ_BUF);
+ len_val = process_config_vars(bufp, len, pick, "txglom_mode=");
+ if (len_val) {
+ if (!strncmp(pick, "0", len_val))
+ conf->txglom_mode = FALSE;
+ else
+ conf->txglom_mode = TRUE;
+ printf("%s: txglom_mode = %d\n", __FUNCTION__, conf->txglom_mode);
+ }
+
+ /* Process vhtmode parameters */
+ memset(pick, 0, MAXSZ_BUF);
+ len_val = process_config_vars(bufp, len, pick, "vhtmode=");
+ if (len_val) {
+ if (!strncmp(pick, "0", len_val))
+ conf->vhtmode = 0;
+ else
+ conf->vhtmode = 1;
+ printf("%s: vhtmode = %d\n", __FUNCTION__, conf->vhtmode);
+ }
+
bcmerror = 0;
} else {
CONFIG_ERROR(("%s: error reading config file: %d\n", __FUNCTION__, len));
@@ -1592,6 +2196,9 @@
}
err:
+ if (pick)
+ MFREE(dhd->osh, pick, MAXSZ_BUF);
+
if (memblock)
MFREE(dhd->osh, memblock, MAXSZ_CONFIG);
@@ -1604,6 +2211,7 @@
int
dhd_conf_set_chiprev(dhd_pub_t *dhd, uint chip, uint chiprev)
{
+ printf("%s: chip=0x%x, chiprev=%d\n", __FUNCTION__, chip, chiprev);
dhd->conf->chip = chip;
dhd->conf->chiprev = chiprev;
return 0;
@@ -1629,6 +2237,44 @@
return 0;
}
+void
+dhd_conf_set_txglom_params(dhd_pub_t *dhd, bool enable)
+{
+ struct dhd_conf *conf = dhd->conf;
+
+ if (enable) {
+#if defined(SWTXGLOM)
+ if (conf->chip == BCM43362_CHIP_ID || conf->chip == BCM4330_CHIP_ID ||
+ conf->chip == BCM43340_CHIP_ID || conf->chip == BCM43341_CHIP_ID ||
+ conf->chip == BCM4334_CHIP_ID || conf->chip == BCM4324_CHIP_ID) {
+ // 43362/4330/4334/43340/43341/43241 must use 1.88.45.x swtxglom if txglom_ext is true, since 1.201.59 not support swtxglom
+ conf->swtxglom = TRUE;
+ conf->txglom_ext = TRUE;
+ }
+ if (conf->chip == BCM43362_CHIP_ID && conf->bus_txglom == 0) {
+ conf->bus_txglom = 1; // improve tcp tx tput. and cpu idle for 43362 only
+ }
+#endif
+ // other parameters set in preinit or config.txt
+ } else {
+ // clear txglom parameters, but don't change swtxglom since it's possible enabled in config.txt
+ conf->txglom_ext = FALSE;
+ conf->txglom_bucket_size = 0;
+ conf->tx_in_rx = TRUE;
+ conf->tx_max_offset = 0;
+ conf->txglomsize = 0;
+ conf->deferred_tx_len = 0;
+ }
+ printf("%s: swtxglom=%d, txglom_ext=%d\n", __FUNCTION__,
+ conf->swtxglom, conf->txglom_ext);
+ printf("%s: txglom_bucket_size=%d\n", __FUNCTION__, conf->txglom_bucket_size);
+ printf("%s: txglomsize=%d, deferred_tx_len=%d, bus_txglom=%d\n", __FUNCTION__,
+ conf->txglomsize, conf->deferred_tx_len, conf->bus_txglom);
+ printf("%s: tx_in_rx=%d, tx_max_offset=%d\n", __FUNCTION__,
+ conf->tx_in_rx, conf->tx_max_offset);
+
+}
+
int
dhd_conf_preinit(dhd_pub_t *dhd)
{
@@ -1636,8 +2282,12 @@
CONFIG_TRACE(("%s: Enter\n", __FUNCTION__));
+#ifdef BCMSDIO
dhd_conf_free_mac_list(&conf->fw_by_mac);
dhd_conf_free_mac_list(&conf->nv_by_mac);
+ dhd_conf_free_chip_nv_path_list(&conf->nv_by_chip);
+#endif
+ memset(&conf->country_list, 0, sizeof(conf_country_list_t));
conf->band = WLC_BAND_AUTO;
conf->mimo_bw_cap = -1;
if (conf->chip == BCM43362_CHIP_ID || conf->chip == BCM4330_CHIP_ID) {
@@ -1645,7 +2295,9 @@
strcpy(conf->cspec.ccode, "ALL");
conf->cspec.rev = 0;
} else if (conf->chip == BCM4335_CHIP_ID || conf->chip == BCM4339_CHIP_ID ||
- conf->chip == BCM4354_CHIP_ID) {
+ conf->chip == BCM4354_CHIP_ID || conf->chip == BCM4356_CHIP_ID ||
+ conf->chip == BCM4345_CHIP_ID || conf->chip == BCM4371_CHIP_ID ||
+ conf->chip == BCM4359_CHIP_ID) {
strcpy(conf->cspec.country_abbrev, "CN");
strcpy(conf->cspec.ccode, "CN");
conf->cspec.rev = 38;
@@ -1687,16 +2339,128 @@
#ifdef PKT_FILTER_SUPPORT
memset(&conf->pkt_filter_add, 0, sizeof(conf_pkt_filter_add_t));
memset(&conf->pkt_filter_del, 0, sizeof(conf_pkt_filter_del_t));
+ conf->pkt_filter_magic = FALSE;
#endif
conf->srl = -1;
conf->lrl = -1;
conf->bcn_timeout = 15;
- if (conf->chip == BCM4339_CHIP_ID) {
- conf->bus_txglom = 8;
- conf->ampdu_ba_wsize = 40;
- }
conf->kso_enable = TRUE;
conf->spect = -1;
+ conf->txbf = -1;
+ conf->lpc = -1;
+ conf->disable_proptx = 0;
+ conf->bus_txglom = 0;
+ conf->use_rxchain = 0;
+ conf->bus_rxglom = TRUE;
+ conf->txglom_ext = FALSE;
+ conf->tx_max_offset = 0;
+ conf->deferred_tx_len = 0;
+ conf->txglomsize = SDPCM_DEFGLOM_SIZE;
+ conf->ampdu_ba_wsize = 0;
+ conf->dpc_cpucore = 0;
+ conf->frameburst = -1;
+ conf->deepsleep = FALSE;
+ conf->pm = -1;
+#ifdef DHDTCPACK_SUPPRESS
+ conf->tcpack_sup_mode = TCPACK_SUP_OFF;
+#endif
+ conf->dhd_poll = -1;
+ conf->pktprio8021x = -1;
+ conf->txctl_tmo_fix = FALSE;
+ conf->tx_in_rx = TRUE;
+ conf->rsdb_mode = -2;
+ conf->txglom_mode = SDPCM_TXGLOM_MDESC;
+ conf->vhtmode = -1;
+ if ((conf->chip == BCM43362_CHIP_ID) || (conf->chip == BCM4330_CHIP_ID)) {
+ conf->disable_proptx = 1;
+ }
+ if (conf->chip == BCM43430_CHIP_ID) {
+ conf->bus_rxglom = FALSE;
+ }
+ if (conf->chip == BCM4339_CHIP_ID) {
+ conf->txbf = 1;
+ }
+ if (conf->chip == BCM4345_CHIP_ID) {
+ conf->txbf = 1;
+ }
+ if (conf->chip == BCM4354_CHIP_ID) {
+ conf->txbf = 1;
+ }
+ if (conf->chip == BCM4356_CHIP_ID) {
+ conf->txbf = 1;
+ }
+ if (conf->chip == BCM4371_CHIP_ID) {
+ conf->txbf = 1;
+ }
+ if (conf->chip == BCM4359_CHIP_ID) {
+ conf->txbf = 1;
+ conf->rsdb_mode = 0;
+ }
+
+#if defined(SWTXGLOM)
+ if (conf->chip == BCM43362_CHIP_ID || conf->chip == BCM4330_CHIP_ID ||
+ conf->chip == BCM43340_CHIP_ID || conf->chip == BCM43341_CHIP_ID ||
+ conf->chip == BCM4334_CHIP_ID || conf->chip == BCM4324_CHIP_ID) {
+ conf->swtxglom = FALSE; // disabled by default
+ conf->txglom_ext = TRUE; // enabled by default
+ conf->use_rxchain = 0; // use_rxchain have been disabled if swtxglom enabled
+ conf->txglomsize = 16;
+ } else {
+ conf->swtxglom = FALSE; // use 1.201.59.x txglom by default
+ conf->txglom_ext = FALSE;
+ }
+
+ if (conf->chip == BCM43362_CHIP_ID) {
+ conf->txglom_bucket_size = 1680; // fixed value, don't change
+ conf->tx_in_rx = FALSE;
+ conf->tx_max_offset = 1;
+ }
+ if (conf->chip == BCM4330_CHIP_ID) {
+ conf->txglom_bucket_size = 1680; // fixed value, don't change
+ conf->tx_in_rx = FALSE;
+ conf->tx_max_offset = 0;
+ }
+ if (conf->chip == BCM4334_CHIP_ID) {
+ conf->txglom_bucket_size = 1684; // fixed value, don't change
+ conf->tx_in_rx = TRUE; // improve tcp tx tput. and cpu idle
+ conf->tx_max_offset = 0; // reduce udp tx: dhdsdio_readframes: got unlikely tx max 109 with tx_seq 110
+ }
+ if (conf->chip == BCM43340_CHIP_ID || conf->chip == BCM43341_CHIP_ID) {
+ conf->txglom_bucket_size = 1684; // fixed value, don't change
+ conf->tx_in_rx = TRUE; // improve tcp tx tput. and cpu idle
+ conf->tx_max_offset = 1;
+ }
+ if (conf->chip == BCM4324_CHIP_ID) {
+ conf->txglom_bucket_size = 1684; // fixed value, don't change
+ conf->tx_in_rx = TRUE; // improve tcp tx tput. and cpu idle
+ conf->tx_max_offset = 0;
+ }
+#endif
+#if defined(BCMSDIOH_TXGLOM_EXT)
+ conf->txglom_mode = SDPCM_TXGLOM_CPY;
+ if (conf->chip == BCM43362_CHIP_ID || conf->chip == BCM4330_CHIP_ID ||
+ conf->chip == BCM43340_CHIP_ID || conf->chip == BCM43341_CHIP_ID ||
+ conf->chip == BCM4334_CHIP_ID || conf->chip == BCM4324_CHIP_ID) {
+ conf->txglom_ext = TRUE;
+ conf->use_rxchain = 0;
+ conf->tx_in_rx = TRUE;
+ conf->tx_max_offset = 1;
+ } else {
+ conf->txglom_ext = FALSE;
+ }
+ if (conf->chip == BCM43362_CHIP_ID || conf->chip == BCM4330_CHIP_ID) {
+ conf->txglom_bucket_size = 1680; // fixed value, don't change
+ conf->txglomsize = 6;
+ }
+ if (conf->chip == BCM4334_CHIP_ID || conf->chip == BCM43340_CHIP_ID ||
+ conf->chip == BCM43341_CHIP_ID || conf->chip == BCM4324_CHIP_ID) {
+ conf->txglom_bucket_size = 1684; // fixed value, don't change
+ conf->txglomsize = 16;
+ }
+#endif
+ if (conf->txglomsize > SDPCM_MAXGLOM_SIZE)
+ conf->txglomsize = SDPCM_MAXGLOM_SIZE;
+ conf->deferred_tx_len = conf->txglomsize;
return 0;
}
@@ -1704,8 +2468,11 @@
int
dhd_conf_reset(dhd_pub_t *dhd)
{
+#ifdef BCMSDIO
dhd_conf_free_mac_list(&dhd->conf->fw_by_mac);
dhd_conf_free_mac_list(&dhd->conf->nv_by_mac);
+ dhd_conf_free_chip_nv_path_list(&dhd->conf->nv_by_chip);
+#endif
memset(dhd->conf, 0, sizeof(dhd_conf_t));
return 0;
}
@@ -1744,8 +2511,11 @@
CONFIG_TRACE(("%s: Enter\n", __FUNCTION__));
if (dhd->conf) {
+#ifdef BCMSDIO
dhd_conf_free_mac_list(&dhd->conf->fw_by_mac);
dhd_conf_free_mac_list(&dhd->conf->nv_by_mac);
+ dhd_conf_free_chip_nv_path_list(&dhd->conf->nv_by_chip);
+#endif
MFREE(dhd->osh, dhd->conf, sizeof(dhd_conf_t));
}
dhd->conf = NULL;
diff -Nur a/drivers/net/wireless/bcmdhd/dhd_config.h c/drivers/net/wireless/bcmdhd/dhd_config.h
--- a/drivers/net/wireless/bcmdhd/dhd_config.h 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/dhd_config.h 2016-05-13 09:48:20.000000000 +0200
@@ -1,145 +1,217 @@
-
-#ifndef _dhd_config_
-#define _dhd_config_
-
-#include <bcmdevs.h>
-#include <dngl_stats.h>
-#include <dhd.h>
-#include <wlioctl.h>
-#include <proto/802.11.h>
-
-#define FW_PATH_AUTO_SELECT 1
-extern char firmware_path[MOD_PARAM_PATHLEN];
-extern int disable_proptx;
-extern uint dhd_doflow;
-
-/* mac range */
-typedef struct wl_mac_range {
- uint32 oui;
- uint32 nic_start;
- uint32 nic_end;
-} wl_mac_range_t;
-
-/* mac list */
-typedef struct wl_mac_list {
- int count;
- wl_mac_range_t *mac;
- char name[MOD_PARAM_PATHLEN]; /* path */
-} wl_mac_list_t;
-
-/* mac list head */
-typedef struct wl_mac_list_ctrl {
- int count;
- struct wl_mac_list *m_mac_list_head;
-} wl_mac_list_ctrl_t;
-
-/* channel list */
-typedef struct wl_channel_list {
- /* in - # of channels, out - # of entries */
- uint32 count;
- /* variable length channel list */
- uint32 channel[WL_NUMCHANNELS];
-} wl_channel_list_t;
-
-typedef struct wmes_param {
- int aifsn[AC_COUNT];
- int cwmin[AC_COUNT];
- int cwmax[AC_COUNT];
-} wme_param_t;
-
-#ifdef PKT_FILTER_SUPPORT
-#define DHD_CONF_FILTER_MAX 8
-/* filter list */
-#define PKT_FILTER_LEN 150
-typedef struct conf_pkt_filter_add {
- /* in - # of channels, out - # of entries */
- uint32 count;
- /* variable length filter list */
- char filter[DHD_CONF_FILTER_MAX][PKT_FILTER_LEN];
-} conf_pkt_filter_add_t;
-
-/* pkt_filter_del list */
-typedef struct conf_pkt_filter_del {
- /* in - # of channels, out - # of entries */
- uint32 count;
- /* variable length filter list */
- uint32 id[DHD_CONF_FILTER_MAX];
-} conf_pkt_filter_del_t;
-#endif
-
-typedef struct dhd_conf {
+
+#ifndef _dhd_config_
+#define _dhd_config_
+
+#include <bcmdevs.h>
+#include <dngl_stats.h>
+#include <dhd.h>
+#include <wlioctl.h>
+#include <proto/802.11.h>
+
+#define FW_PATH_AUTO_SELECT 1
+//#define CONFIG_PATH_AUTO_SELECT
+extern char firmware_path[MOD_PARAM_PATHLEN];
+extern int disable_proptx;
+extern uint dhd_rxbound;
+extern uint dhd_txbound;
+#define TXGLOM_RECV_OFFSET 8
+#ifdef BCMSDIO
+extern uint dhd_doflow;
+extern uint dhd_slpauto;
+
+#define BCM43362A0_CHIP_REV 0
+#define BCM43362A2_CHIP_REV 1
+#define BCM43430A0_CHIP_REV 0
+#define BCM43430A1_CHIP_REV 1
+#define BCM4330B2_CHIP_REV 4
+#define BCM4334B1_CHIP_REV 3
+#define BCM43341B0_CHIP_REV 2
+#define BCM43241B4_CHIP_REV 5
+#define BCM4335A0_CHIP_REV 2
+#define BCM4339A0_CHIP_REV 1
+#define BCM43455C0_CHIP_REV 6
+#define BCM4354A1_CHIP_REV 1
+#define BCM4359B1_CHIP_REV 5
+#endif
+#define BCM4356A2_CHIP_REV 2
+
+/* mac range */
+typedef struct wl_mac_range {
+ uint32 oui;
+ uint32 nic_start;
+ uint32 nic_end;
+} wl_mac_range_t;
+
+/* mac list */
+typedef struct wl_mac_list {
+ int count;
+ wl_mac_range_t *mac;
+ char name[MOD_PARAM_PATHLEN]; /* path */
+} wl_mac_list_t;
+
+/* mac list head */
+typedef struct wl_mac_list_ctrl {
+ int count;
+ struct wl_mac_list *m_mac_list_head;
+} wl_mac_list_ctrl_t;
+
+/* chip_nv_path */
+typedef struct wl_chip_nv_path {
+ uint chip;
+ uint chiprev;
+ char name[MOD_PARAM_PATHLEN]; /* path */
+} wl_chip_nv_path_t;
+
+/* chip_nv_path list head */
+typedef struct wl_chip_nv_path_list_ctrl {
+ int count;
+ struct wl_chip_nv_path *m_chip_nv_path_head;
+} wl_chip_nv_path_list_ctrl_t;
+
+/* channel list */
+typedef struct wl_channel_list {
+ /* in - # of channels, out - # of entries */
+ uint32 count;
+ /* variable length channel list */
+ uint32 channel[WL_NUMCHANNELS];
+} wl_channel_list_t;
+
+typedef struct wmes_param {
+ int aifsn[AC_COUNT];
+ int cwmin[AC_COUNT];
+ int cwmax[AC_COUNT];
+} wme_param_t;
+
+#ifdef PKT_FILTER_SUPPORT
+#define DHD_CONF_FILTER_MAX 8
+/* filter list */
+#define PKT_FILTER_LEN 300
+typedef struct conf_pkt_filter_add {
+ /* in - # of channels, out - # of entries */
+ uint32 count;
+ /* variable length filter list */
+ char filter[DHD_CONF_FILTER_MAX][PKT_FILTER_LEN];
+} conf_pkt_filter_add_t;
+
+/* pkt_filter_del list */
+typedef struct conf_pkt_filter_del {
+ /* in - # of channels, out - # of entries */
+ uint32 count;
+ /* variable length filter list */
+ uint32 id[DHD_CONF_FILTER_MAX];
+} conf_pkt_filter_del_t;
+#endif
+
+#define CONFIG_COUNTRY_LIST_SIZE 100
+/* country list */
+typedef struct conf_country_list {
+ uint32 count;
+ wl_country_t cspec[CONFIG_COUNTRY_LIST_SIZE];
+} conf_country_list_t;
+
+typedef struct dhd_conf {
uint chip; /* chip number */
- uint chiprev; /* chip revision */
- wl_mac_list_ctrl_t fw_by_mac; /* Firmware auto selection by MAC */
- wl_mac_list_ctrl_t nv_by_mac; /* NVRAM auto selection by MAC */
- char fw_path[MOD_PARAM_PATHLEN]; /* Firmware path */
- char nv_path[MOD_PARAM_PATHLEN]; /* NVRAM path */
- uint band; /* Band, b:2.4G only, otherwise for auto */
- int mimo_bw_cap; /* Bandwidth, 0:HT20ALL, 1: HT40ALL, 2:HT20IN2G_HT40PIN5G */
- wl_country_t cspec; /* Country */
- wl_channel_list_t channels; /* Support channels */
- uint roam_off; /* Roaming, 0:enable, 1:disable */
- uint roam_off_suspend; /* Roaming in suspend, 0:enable, 1:disable */
- int roam_trigger[2]; /* The RSSI threshold to trigger roaming */
- int roam_scan_period[2]; /* Roaming scan period */
- int roam_delta[2]; /* Roaming candidate qualification delta */
- int fullroamperiod; /* Full Roaming period */
- uint keep_alive_period; /* The perioid in ms to send keep alive packet */
- uint force_wme_ac;
- wme_param_t wme; /* WME parameters */
- int stbc; /* STBC for Tx/Rx */
- int phy_oclscdenable; /* phy_oclscdenable */
-#ifdef PKT_FILTER_SUPPORT
- conf_pkt_filter_add_t pkt_filter_add; /* Packet filter add */
- conf_pkt_filter_del_t pkt_filter_del; /* Packet filter add */
-#endif
- int srl; /* short retry limit */
- int lrl; /* long retry limit */
- uint bcn_timeout; /* beacon timeout */
- uint32 bus_txglom; /* bus:txglom */
- uint32 ampdu_ba_wsize;
- bool kso_enable;
- int spect;
-} dhd_conf_t;
-
-int dhd_conf_get_mac(dhd_pub_t *dhd, bcmsdh_info_t *sdh, uint8 *mac);
-void dhd_conf_set_fw_name_by_mac(dhd_pub_t *dhd, bcmsdh_info_t *sdh, char *fw_path);
-void dhd_conf_set_nv_name_by_mac(dhd_pub_t *dhd, bcmsdh_info_t *sdh, char *nv_path);
-void dhd_conf_set_fw_name_by_chip(dhd_pub_t *dhd, char *fw_path);
-#if defined(HW_OOB)
-void dhd_conf_set_hw_oob_intr(bcmsdh_info_t *sdh, uint chip);
-#endif
-void dhd_conf_set_fw_path(dhd_pub_t *dhd, char *fw_path);
-void dhd_conf_set_nv_path(dhd_pub_t *dhd, char *nv_path);
-int dhd_conf_set_band(dhd_pub_t *dhd);
-uint dhd_conf_get_band(dhd_pub_t *dhd);
-int dhd_conf_set_country(dhd_pub_t *dhd);
-int dhd_conf_get_country(dhd_pub_t *dhd, wl_country_t *cspec);
-int dhd_conf_fix_country(dhd_pub_t *dhd);
-bool dhd_conf_match_channel(dhd_pub_t *dhd, uint32 channel);
-int dhd_conf_set_roam(dhd_pub_t *dhd);
-void dhd_conf_set_mimo_bw_cap(dhd_pub_t *dhd);
-void dhd_conf_force_wme(dhd_pub_t *dhd);
-void dhd_conf_get_wme(dhd_pub_t *dhd, edcf_acparam_t *acp);
-void dhd_conf_set_wme(dhd_pub_t *dhd);
-void dhd_conf_set_stbc(dhd_pub_t *dhd);
-void dhd_conf_set_phyoclscdenable(dhd_pub_t *dhd);
-void dhd_conf_add_pkt_filter(dhd_pub_t *dhd);
-bool dhd_conf_del_pkt_filter(dhd_pub_t *dhd, uint32 id);
-void dhd_conf_discard_pkt_filter(dhd_pub_t *dhd);
-void dhd_conf_set_srl(dhd_pub_t *dhd);
-void dhd_conf_set_lrl(dhd_pub_t *dhd);
-void dhd_conf_set_glom(dhd_pub_t *dhd);
-void dhd_conf_set_ampdu_ba_wsize(dhd_pub_t *dhd);
-void dhd_conf_set_spect(dhd_pub_t *dhd);
-int dhd_conf_read_config(dhd_pub_t *dhd);
-int dhd_conf_set_chiprev(dhd_pub_t *dhd, uint chip, uint chiprev);
-uint dhd_conf_get_chip(void *context);
-uint dhd_conf_get_chiprev(void *context);
-int dhd_conf_preinit(dhd_pub_t *dhd);
-int dhd_conf_reset(dhd_pub_t *dhd);
-int dhd_conf_attach(dhd_pub_t *dhd);
-void dhd_conf_detach(dhd_pub_t *dhd);
-void *dhd_get_pub(struct net_device *dev);
-
-#endif /* _dhd_config_ */
+ uint chiprev; /* chip revision */
+ wl_mac_list_ctrl_t fw_by_mac; /* Firmware auto selection by MAC */
+ wl_mac_list_ctrl_t nv_by_mac; /* NVRAM auto selection by MAC */
+ wl_chip_nv_path_list_ctrl_t nv_by_chip; /* NVRAM auto selection by chip */
+ conf_country_list_t country_list; /* Country list */
+ int band; /* Band, b:2.4G only, otherwise for auto */
+ int mimo_bw_cap; /* Bandwidth, 0:HT20ALL, 1: HT40ALL, 2:HT20IN2G_HT40PIN5G */
+ wl_country_t cspec; /* Country */
+ wl_channel_list_t channels; /* Support channels */
+ uint roam_off; /* Roaming, 0:enable, 1:disable */
+ uint roam_off_suspend; /* Roaming in suspend, 0:enable, 1:disable */
+ int roam_trigger[2]; /* The RSSI threshold to trigger roaming */
+ int roam_scan_period[2]; /* Roaming scan period */
+ int roam_delta[2]; /* Roaming candidate qualification delta */
+ int fullroamperiod; /* Full Roaming period */
+ uint keep_alive_period; /* The perioid in ms to send keep alive packet */
+ int force_wme_ac;
+ wme_param_t wme; /* WME parameters */
+ int stbc; /* STBC for Tx/Rx */
+ int phy_oclscdenable; /* phy_oclscdenable */
+#ifdef PKT_FILTER_SUPPORT
+ conf_pkt_filter_add_t pkt_filter_add; /* Packet filter add */
+ conf_pkt_filter_del_t pkt_filter_del; /* Packet filter add */
+ bool pkt_filter_magic;
+#endif
+ int srl; /* short retry limit */
+ int lrl; /* long retry limit */
+ uint bcn_timeout; /* beacon timeout */
+ bool kso_enable;
+ int spect;
+ int txbf;
+ int lpc;
+ int disable_proptx;
+ int bus_txglom; /* bus:txglom */
+ int use_rxchain;
+ bool bus_rxglom; /* bus:rxglom */
+ uint txglomsize;
+ int ampdu_ba_wsize;
+ int dpc_cpucore;
+ int frameburst;
+ bool deepsleep;
+ int pm;
+ uint8 tcpack_sup_mode;
+ int dhd_poll;
+ uint deferred_tx_len;
+ int pktprio8021x;
+ bool txctl_tmo_fix;
+ bool swtxglom; /* SW TXGLOM */
+ bool txglom_ext; /* Only for 43362/4330/43340/43341/43241 */
+ /*txglom_bucket_size:
+ * 43362/4330: 1680
+ * 43340/43341/43241: 1684
+ */
+ int txglom_bucket_size;
+ int tx_max_offset;
+ bool tx_in_rx; // Skip tx before rx, in order to get more glomed in tx
+ int rsdb_mode;
+ bool txglom_mode;
+ int vhtmode;
+} dhd_conf_t;
+
+#ifdef BCMSDIO
+int dhd_conf_get_mac(dhd_pub_t *dhd, bcmsdh_info_t *sdh, uint8 *mac);
+void dhd_conf_set_fw_name_by_mac(dhd_pub_t *dhd, bcmsdh_info_t *sdh, char *fw_path);
+void dhd_conf_set_nv_name_by_mac(dhd_pub_t *dhd, bcmsdh_info_t *sdh, char *nv_path);
+#if defined(HW_OOB) || defined(FORCE_WOWLAN)
+void dhd_conf_set_hw_oob_intr(bcmsdh_info_t *sdh, uint chip);
+#endif
+#endif
+void dhd_conf_set_fw_name_by_chip(dhd_pub_t *dhd, char *fw_path);
+void dhd_conf_set_nv_name_by_chip(dhd_pub_t *dhd, char *nv_path);
+void dhd_conf_set_conf_path_by_nv_path(dhd_pub_t *dhd, char *conf_path, char *nv_path);
+#ifdef CONFIG_PATH_AUTO_SELECT
+void dhd_conf_set_conf_name_by_chip(dhd_pub_t *dhd, char *conf_path);
+#endif
+int dhd_conf_set_fw_int_cmd(dhd_pub_t *dhd, char *name, uint cmd, int val, int def, bool down);
+int dhd_conf_set_fw_string_cmd(dhd_pub_t *dhd, char *cmd, int val, int def, bool down);
+uint dhd_conf_get_band(dhd_pub_t *dhd);
+int dhd_conf_set_country(dhd_pub_t *dhd);
+int dhd_conf_get_country(dhd_pub_t *dhd, wl_country_t *cspec);
+int dhd_conf_get_country_from_config(dhd_pub_t *dhd, wl_country_t *cspec);
+int dhd_conf_fix_country(dhd_pub_t *dhd);
+bool dhd_conf_match_channel(dhd_pub_t *dhd, uint32 channel);
+int dhd_conf_set_roam(dhd_pub_t *dhd);
+void dhd_conf_get_wme(dhd_pub_t *dhd, edcf_acparam_t *acp);
+void dhd_conf_set_wme(dhd_pub_t *dhd);
+void dhd_conf_add_pkt_filter(dhd_pub_t *dhd);
+bool dhd_conf_del_pkt_filter(dhd_pub_t *dhd, uint32 id);
+void dhd_conf_discard_pkt_filter(dhd_pub_t *dhd);
+void dhd_conf_set_disable_proptx(dhd_pub_t *dhd);
+int dhd_conf_read_config(dhd_pub_t *dhd, char *conf_path);
+int dhd_conf_set_chiprev(dhd_pub_t *dhd, uint chip, uint chiprev);
+uint dhd_conf_get_chip(void *context);
+uint dhd_conf_get_chiprev(void *context);
+void dhd_conf_set_txglom_params(dhd_pub_t *dhd, bool enable);
+int dhd_conf_get_pm(dhd_pub_t *dhd);
+int dhd_conf_get_tcpack_sup_mode(dhd_pub_t *dhd);
+int dhd_conf_preinit(dhd_pub_t *dhd);
+int dhd_conf_reset(dhd_pub_t *dhd);
+int dhd_conf_attach(dhd_pub_t *dhd);
+void dhd_conf_detach(dhd_pub_t *dhd);
+void *dhd_get_pub(struct net_device *dev);
+
+#endif /* _dhd_config_ */
diff -Nur a/drivers/net/wireless/bcmdhd/dhd_custom_gpio.c c/drivers/net/wireless/bcmdhd/dhd_custom_gpio.c
--- a/drivers/net/wireless/bcmdhd/dhd_custom_gpio.c 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/dhd_custom_gpio.c 2016-05-13 09:48:20.000000000 +0200
@@ -2,7 +2,7 @@
* Customer code to add GPIO control during WLAN start/stop
* $Copyright Open Broadcom Corporation$
*
-* $Id: dhd_custom_gpio.c 447105 2014-01-08 05:27:09Z $
+* $Id: dhd_custom_gpio.c 493822 2014-07-29 13:20:26Z $
*/
#include <typedefs.h>
@@ -25,7 +25,7 @@
int __attribute__ ((weak)) wifi_get_fw_nv_path(char *fw, char *nv) { return 0;};
#endif
-#endif
+#endif
#if defined(OOB_INTR_ONLY)
@@ -82,11 +82,11 @@
host_oob_irq = gpio_to_irq(dhd_oob_gpio_num);
gpio_direction_input(dhd_oob_gpio_num);
#endif /* defined CUSTOMER_HW3 || defined(PLATFORM_MPS) */
-#endif
+#endif
return (host_oob_irq);
}
-#endif
+#endif
/* Customer function to control hw specific wlan gpios */
int
@@ -98,81 +98,16 @@
}
#ifdef GET_CUSTOM_MAC_ENABLE
-extern char *saved_command_line;
-#define MAC_KEY_VALUE "wifi_mac"
-s32 get_para_from_cmdline(const char *cmdline, const char *name, char *value)
-{
- char *value_p = value;
-
- if(!cmdline || !name || !value) {
- return -1;
- }
-
- for(; *cmdline != 0;) {
- if(*cmdline++ == ' ') {
- if(0 == strncmp(cmdline, name, strlen(name))) {
- cmdline += strlen(name);
- if(*cmdline++ != '=') {
- continue;
- }
- while(*cmdline != 0 && *cmdline != ' ') {
- *value_p++ = *cmdline++;
- }
- return value_p - value;
- }
- }
- }
-
- return 0;
-}
-static u8 key_char2num(u8 ch)
-{
- if((ch>='0')&&(ch<='9'))
- return ch - '0';
- else if ((ch>='a')&&(ch<='f'))
- return ch - 'a' + 10;
- else if ((ch>='A')&&(ch<='F'))
- return ch - 'A' + 10;
- else
- return 0xff;
-}
-u8 key_2char2num(u8 hch, u8 lch)
-{
- return ((key_char2num(hch) << 4) | key_char2num(lch));
-}
/* Function to get custom MAC address */
int
-dhd_custom_get_mac_address(unsigned char *buf)
+dhd_custom_get_mac_address(void *adapter, unsigned char *buf)
{
int ret = 0;
- char mac_str[18] = {0};
- u8 mac[ETH_ALEN];
- struct ether_addr mac_addr;
- int jj,kk;
- printk("%s Enter\n", __FUNCTION__);
WL_TRACE(("%s Enter\n", __FUNCTION__));
if (!buf)
return -EINVAL;
- get_para_from_cmdline(saved_command_line, MAC_KEY_VALUE, mac_str);
- printk("%s wifi_mac=%s\n", __FUNCTION__, mac_str);
- if(mac_str != NULL) {
- //printk(KERN_ERR "mac_str=%s\n",mac_str);
- for( jj = 0, kk = 0; jj < ETH_ALEN; jj++, kk += 3 ) {
- mac[jj] = key_2char2num(mac_str[kk], mac_str[kk+ 1]);
- }
- if(is_valid_ether_addr(mac)) {
- memcpy(mac_addr.octet, mac, ETHER_ADDR_LEN);
- bcopy((char *)&mac_addr, buf, sizeof(struct ether_addr));
- ret = 0;
- } else
- ret = -1;
- } else {
- printk("get mac from cmdline failed.\n");
- ret = -1;
- }
-
/* Customer access to MAC address stored outside of DHD driver */
#if (defined(CUSTOMER_HW2) || defined(CUSTOMER_HW10)) && (LINUX_VERSION_CODE >= \
KERNEL_VERSION(2, 6, 35))
@@ -238,7 +173,7 @@
{"TR", "TR", 0},
{"NO", "NO", 0},
#endif /* EXMAPLE_TABLE */
-#if defined(CUSTOMER_HW2)
+#if defined(CUSTOMER_HW2) && !defined(CUSTOMER_HW5)
#if defined(BCM4335_CHIP)
{"", "XZ", 11}, /* Universal if Country code is unknown or empty */
#endif
@@ -299,7 +234,143 @@
{"RU", "RU", 1},
{"US", "US", 5}
#endif
-#endif /* CUSTOMER_HW2 */
+
+#elif defined(CUSTOMER_HW5)
+ {"", "XZ", 11},
+ {"AE", "AE", 212},
+ {"AG", "AG", 2},
+ {"AI", "AI", 2},
+ {"AL", "AL", 2},
+ {"AN", "AN", 3},
+ {"AR", "AR", 212},
+ {"AS", "AS", 15},
+ {"AT", "AT", 4},
+ {"AU", "AU", 212},
+ {"AW", "AW", 2},
+ {"AZ", "AZ", 2},
+ {"BA", "BA", 2},
+ {"BD", "BD", 2},
+ {"BE", "BE", 4},
+ {"BG", "BG", 4},
+ {"BH", "BH", 4},
+ {"BM", "BM", 15},
+ {"BN", "BN", 4},
+ {"BR", "BR", 212},
+ {"BS", "BS", 2},
+ {"BY", "BY", 3},
+ {"BW", "BW", 1},
+ {"CA", "CA", 212},
+ {"CH", "CH", 212},
+ {"CL", "CL", 212},
+ {"CN", "CN", 212},
+ {"CO", "CO", 212},
+ {"CR", "CR", 21},
+ {"CY", "CY", 212},
+ {"CZ", "CZ", 212},
+ {"DE", "DE", 212},
+ {"DK", "DK", 4},
+ {"DZ", "DZ", 1},
+ {"EC", "EC", 23},
+ {"EE", "EE", 4},
+ {"EG", "EG", 212},
+ {"ES", "ES", 212},
+ {"ET", "ET", 2},
+ {"FI", "FI", 4},
+ {"FR", "FR", 212},
+ {"GB", "GB", 212},
+ {"GD", "GD", 2},
+ {"GF", "GF", 2},
+ {"GP", "GP", 2},
+ {"GR", "GR", 212},
+ {"GT", "GT", 0},
+ {"GU", "GU", 17},
+ {"HK", "HK", 212},
+ {"HR", "HR", 4},
+ {"HU", "HU", 4},
+ {"IN", "IN", 212},
+ {"ID", "ID", 212},
+ {"IE", "IE", 5},
+ {"IL", "IL", 7},
+ {"IN", "IN", 212},
+ {"IS", "IS", 4},
+ {"IT", "IT", 212},
+ {"JO", "JO", 3},
+ {"JP", "JP", 212},
+ {"KH", "KH", 4},
+ {"KI", "KI", 1},
+ {"KR", "KR", 212},
+ {"KW", "KW", 5},
+ {"KY", "KY", 4},
+ {"KZ", "KZ", 212},
+ {"LA", "LA", 4},
+ {"LB", "LB", 6},
+ {"LI", "LI", 4},
+ {"LK", "LK", 3},
+ {"LS", "LS", 2},
+ {"LT", "LT", 4},
+ {"LR", "LR", 2},
+ {"LU", "LU", 3},
+ {"LV", "LV", 4},
+ {"MA", "MA", 2},
+ {"MC", "MC", 1},
+ {"MD", "MD", 2},
+ {"ME", "ME", 2},
+ {"MK", "MK", 2},
+ {"MN", "MN", 0},
+ {"MO", "MO", 2},
+ {"MR", "MR", 2},
+ {"MT", "MT", 4},
+ {"MQ", "MQ", 2},
+ {"MU", "MU", 2},
+ {"MV", "MV", 3},
+ {"MX", "MX", 212},
+ {"MY", "MY", 212},
+ {"NI", "NI", 0},
+ {"NL", "NL", 212},
+ {"NO", "NO", 4},
+ {"NP", "NP", 3},
+ {"NZ", "NZ", 9},
+ {"OM", "OM", 4},
+ {"PA", "PA", 17},
+ {"PE", "PE", 212},
+ {"PG", "PG", 2},
+ {"PH", "PH", 212},
+ {"PL", "PL", 212},
+ {"PR", "PR", 25},
+ {"PT", "PT", 212},
+ {"PY", "PY", 4},
+ {"RE", "RE", 2},
+ {"RO", "RO", 212},
+ {"RS", "RS", 2},
+ {"RU", "RU", 212},
+ {"SA", "SA", 212},
+ {"SE", "SE", 212},
+ {"SG", "SG", 212},
+ {"SI", "SI", 4},
+ {"SK", "SK", 212},
+ {"SN", "SN", 2},
+ {"SV", "SV", 25},
+ {"TH", "TH", 212},
+ {"TR", "TR", 212},
+ {"TT", "TT", 5},
+ {"TW", "TW", 212},
+ {"UA", "UA", 212},
+ {"UG", "UG", 2},
+ {"US", "US", 212},
+ {"UY", "UY", 5},
+ {"VA", "VA", 2},
+ {"VE", "VE", 3},
+ {"VG", "VG", 2},
+ {"VI", "VI", 18},
+ {"VN", "VN", 4},
+ {"YT", "YT", 2},
+ {"ZA", "ZA", 212},
+ {"ZM", "ZM", 2},
+ {"XT", "XT", 212},
+ {"XZ", "XZ", 11},
+ {"XV", "XV", 17},
+ {"Q1", "Q1", 77},
+#endif /* CUSTOMER_HW2 and CUSTOMER_HW5 */
};
@@ -309,7 +380,7 @@
*/
void get_customized_country_code(void *adapter, char *country_iso_code, wl_country_t *cspec)
{
-#if defined(CUSTOMER_HW2) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
+#if (defined(CUSTOMER_HW) || defined(CUSTOMER_HW2)) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
struct cntry_locales_custom *cloc_ptr;
diff -Nur a/drivers/net/wireless/bcmdhd/dhd_dbg.h c/drivers/net/wireless/bcmdhd/dhd_dbg.h
--- a/drivers/net/wireless/bcmdhd/dhd_dbg.h 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/dhd_dbg.h 2016-05-13 09:48:20.000000000 +0200
@@ -92,7 +92,7 @@
#define DHD_NOCHECKDIED_ON() 0
#define DHD_PNO_ON() 0
-#endif
+#endif
#define DHD_LOG(args)
diff -Nur a/drivers/net/wireless/bcmdhd/dhd_flowring.c c/drivers/net/wireless/bcmdhd/dhd_flowring.c
--- a/drivers/net/wireless/bcmdhd/dhd_flowring.c 1970-01-01 01:00:00.000000000 +0100
+++ c/drivers/net/wireless/bcmdhd/dhd_flowring.c 2016-05-13 09:48:20.000000000 +0200
@@ -0,0 +1,810 @@
+/*
+ * Broadcom Dongle Host Driver (DHD), Flow ring specific code at top level
+ * $Copyright Open Broadcom Corporation$
+ *
+ * $Id: dhd_flowrings.c jaganlv $
+ */
+
+#include <typedefs.h>
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include <bcmdevs.h>
+
+#include <proto/ethernet.h>
+#include <proto/bcmevent.h>
+#include <dngl_stats.h>
+
+#include <dhd.h>
+
+#include <dhd_flowring.h>
+#include <dhd_bus.h>
+#include <dhd_proto.h>
+#include <dhd_dbg.h>
+#include <proto/802.1d.h>
+#include <pcie_core.h>
+#include <bcmmsgbuf.h>
+#include <dhd_pcie.h>
+
+static INLINE uint16 dhd_flowid_alloc(dhd_pub_t *dhdp, uint8 ifindex,
+ uint8 prio, char *sa, char *da);
+
+static INLINE int dhd_flowid_lookup(dhd_pub_t *dhdp, uint8 ifindex,
+ uint8 prio, char *sa, char *da, uint16 *flowid);
+int BCMFASTPATH dhd_flow_queue_overflow(flow_queue_t *queue, void *pkt);
+
+#define FLOW_QUEUE_PKT_NEXT(p) PKTLINK(p)
+#define FLOW_QUEUE_PKT_SETNEXT(p, x) PKTSETLINK((p), (x))
+
+const uint8 prio2ac[8] = { 0, 1, 1, 0, 2, 2, 3, 3 };
+const uint8 prio2tid[8] = { 0, 1, 2, 3, 4, 5, 6, 7 };
+
+int BCMFASTPATH
+dhd_flow_queue_overflow(flow_queue_t *queue, void *pkt)
+{
+ return BCME_NORESOURCE;
+}
+
+/* Flow ring's queue management functions */
+
+void /* Initialize a flow ring's queue */
+dhd_flow_queue_init(dhd_pub_t *dhdp, flow_queue_t *queue, int max)
+{
+ ASSERT((queue != NULL) && (max > 0));
+
+ dll_init(&queue->list);
+ queue->head = queue->tail = NULL;
+ queue->len = 0;
+ queue->max = max - 1;
+ queue->failures = 0U;
+ queue->cb = &dhd_flow_queue_overflow;
+}
+
+void /* Register an enqueue overflow callback handler */
+dhd_flow_queue_register(flow_queue_t *queue, flow_queue_cb_t cb)
+{
+ ASSERT(queue != NULL);
+ queue->cb = cb;
+}
+
+
+int BCMFASTPATH /* Enqueue a packet in a flow ring's queue */
+dhd_flow_queue_enqueue(dhd_pub_t *dhdp, flow_queue_t *queue, void *pkt)
+{
+ int ret = BCME_OK;
+
+ ASSERT(queue != NULL);
+
+ if (queue->len >= queue->max) {
+ queue->failures++;
+ ret = (*queue->cb)(queue, pkt);
+ goto done;
+ }
+
+ if (queue->head) {
+ FLOW_QUEUE_PKT_SETNEXT(queue->tail, pkt);
+ } else {
+ queue->head = pkt;
+ }
+
+ FLOW_QUEUE_PKT_SETNEXT(pkt, NULL);
+
+ queue->tail = pkt; /* at tail */
+
+ queue->len++;
+
+done:
+ return ret;
+}
+
+void * BCMFASTPATH /* Dequeue a packet from a flow ring's queue, from head */
+dhd_flow_queue_dequeue(dhd_pub_t *dhdp, flow_queue_t *queue)
+{
+ void * pkt;
+
+ ASSERT(queue != NULL);
+
+ pkt = queue->head; /* from head */
+
+ if (pkt == NULL) {
+ ASSERT((queue->len == 0) && (queue->tail == NULL));
+ goto done;
+ }
+
+ queue->head = FLOW_QUEUE_PKT_NEXT(pkt);
+ if (queue->head == NULL)
+ queue->tail = NULL;
+
+ queue->len--;
+
+ FLOW_QUEUE_PKT_SETNEXT(pkt, NULL); /* dettach packet from queue */
+
+done:
+ return pkt;
+}
+
+void BCMFASTPATH /* Reinsert a dequeued packet back at the head */
+dhd_flow_queue_reinsert(dhd_pub_t *dhdp, flow_queue_t *queue, void *pkt)
+{
+ if (queue->head == NULL) {
+ queue->tail = pkt;
+ }
+
+ FLOW_QUEUE_PKT_SETNEXT(pkt, queue->head);
+ queue->head = pkt;
+ queue->len++;
+}
+
+
+/* Init Flow Ring specific data structures */
+int
+dhd_flow_rings_init(dhd_pub_t *dhdp, uint32 num_flow_rings)
+{
+ uint32 idx;
+ uint32 flow_ring_table_sz;
+ uint32 if_flow_lkup_sz;
+ void * flowid_allocator;
+ flow_ring_table_t *flow_ring_table;
+ if_flow_lkup_t *if_flow_lkup = NULL;
+#ifdef PCIE_TX_DEFERRAL
+ uint32 count;
+#endif
+ void *lock = NULL;
+ unsigned long flags;
+
+ DHD_INFO(("%s\n", __FUNCTION__));
+
+ /* Construct a 16bit flow1d allocator */
+ flowid_allocator = id16_map_init(dhdp->osh,
+ num_flow_rings - FLOW_RING_COMMON, FLOWID_RESERVED);
+ if (flowid_allocator == NULL) {
+ DHD_ERROR(("%s: flowid allocator init failure\n", __FUNCTION__));
+ return BCME_NOMEM;
+ }
+
+ /* Allocate a flow ring table, comprising of requested number of rings */
+ flow_ring_table_sz = (num_flow_rings * sizeof(flow_ring_node_t));
+ flow_ring_table = (flow_ring_table_t *)MALLOC(dhdp->osh, flow_ring_table_sz);
+ if (flow_ring_table == NULL) {
+ DHD_ERROR(("%s: flow ring table alloc failure\n", __FUNCTION__));
+ goto fail;
+ }
+
+ /* Initialize flow ring table state */
+ bzero((uchar *)flow_ring_table, flow_ring_table_sz);
+ for (idx = 0; idx < num_flow_rings; idx++) {
+ flow_ring_table[idx].status = FLOW_RING_STATUS_CLOSED;
+ flow_ring_table[idx].flowid = (uint16)idx;
+ flow_ring_table[idx].lock = dhd_os_spin_lock_init(dhdp->osh);
+ if (flow_ring_table[idx].lock == NULL) {
+ DHD_ERROR(("%s: Failed to init spinlock for queue!\n", __FUNCTION__));
+ goto fail;
+ }
+
+ dll_init(&flow_ring_table[idx].list);
+
+ /* Initialize the per flow ring backup queue */
+ dhd_flow_queue_init(dhdp, &flow_ring_table[idx].queue,
+ FLOW_RING_QUEUE_THRESHOLD);
+ }
+
+ /* Allocate per interface hash table */
+ if_flow_lkup_sz = sizeof(if_flow_lkup_t) * DHD_MAX_IFS;
+ if_flow_lkup = (if_flow_lkup_t *)DHD_OS_PREALLOC(dhdp,
+ DHD_PREALLOC_IF_FLOW_LKUP, if_flow_lkup_sz);
+ if (if_flow_lkup == NULL) {
+ DHD_ERROR(("%s: if flow lkup alloc failure\n", __FUNCTION__));
+ goto fail;
+ }
+
+ /* Initialize per interface hash table */
+ bzero((uchar *)if_flow_lkup, if_flow_lkup_sz);
+ for (idx = 0; idx < DHD_MAX_IFS; idx++) {
+ int hash_ix;
+ if_flow_lkup[idx].status = 0;
+ if_flow_lkup[idx].role = 0;
+ for (hash_ix = 0; hash_ix < DHD_FLOWRING_HASH_SIZE; hash_ix++)
+ if_flow_lkup[idx].fl_hash[hash_ix] = NULL;
+ }
+
+#ifdef PCIE_TX_DEFERRAL
+ count = BITS_TO_LONGS(num_flow_rings);
+ dhdp->bus->delete_flow_map = kzalloc(count, GFP_ATOMIC);
+ if (!dhdp->bus->delete_flow_map) {
+ DHD_ERROR(("%s: delete_flow_map alloc failure\n", __FUNCTION__));
+ goto fail;
+ }
+#endif
+
+ lock = dhd_os_spin_lock_init(dhdp->osh);
+ if (lock == NULL)
+ goto fail;
+
+ dhdp->flow_prio_map_type = DHD_FLOW_PRIO_AC_MAP;
+ bcopy(prio2ac, dhdp->flow_prio_map, sizeof(uint8) * NUMPRIO);
+
+ /* Now populate into dhd pub */
+ DHD_FLOWID_LOCK(lock, flags);
+ dhdp->num_flow_rings = num_flow_rings;
+ dhdp->flowid_allocator = (void *)flowid_allocator;
+ dhdp->flow_ring_table = (void *)flow_ring_table;
+ dhdp->if_flow_lkup = (void *)if_flow_lkup;
+ dhdp->flowid_lock = lock;
+ DHD_FLOWID_UNLOCK(lock, flags);
+
+ DHD_INFO(("%s done\n", __FUNCTION__));
+ return BCME_OK;
+
+fail:
+
+#ifdef PCIE_TX_DEFERRAL
+ if (dhdp->bus->delete_flow_map)
+ kfree(dhdp->bus->delete_flow_map);
+#endif
+ /* Destruct the per interface flow lkup table */
+ if (dhdp->if_flow_lkup != NULL) {
+ DHD_OS_PREFREE(dhdp, if_flow_lkup, if_flow_lkup_sz);
+ }
+ if (flow_ring_table != NULL) {
+ for (idx = 0; idx < num_flow_rings; idx++) {
+ if (flow_ring_table[idx].lock != NULL)
+ dhd_os_spin_lock_deinit(dhdp->osh, flow_ring_table[idx].lock);
+ }
+ MFREE(dhdp->osh, flow_ring_table, flow_ring_table_sz);
+ }
+ id16_map_fini(dhdp->osh, flowid_allocator);
+
+ return BCME_NOMEM;
+}
+
+/* Deinit Flow Ring specific data structures */
+void dhd_flow_rings_deinit(dhd_pub_t *dhdp)
+{
+ uint16 idx;
+ uint32 flow_ring_table_sz;
+ uint32 if_flow_lkup_sz;
+ flow_ring_table_t *flow_ring_table;
+ unsigned long flags;
+ void *lock;
+
+ DHD_INFO(("dhd_flow_rings_deinit\n"));
+
+ if (dhdp->flow_ring_table != NULL) {
+
+ ASSERT(dhdp->num_flow_rings > 0);
+
+ DHD_FLOWID_LOCK(dhdp->flowid_lock, flags);
+ flow_ring_table = (flow_ring_table_t *)dhdp->flow_ring_table;
+ dhdp->flow_ring_table = NULL;
+ DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags);
+ for (idx = 0; idx < dhdp->num_flow_rings; idx++) {
+ if (flow_ring_table[idx].active) {
+ dhd_bus_clean_flow_ring(dhdp->bus, &flow_ring_table[idx]);
+ }
+ ASSERT(flow_queue_empty(&flow_ring_table[idx].queue));
+
+ /* Deinit flow ring queue locks before destroying flow ring table */
+ dhd_os_spin_lock_deinit(dhdp->osh, flow_ring_table[idx].lock);
+ flow_ring_table[idx].lock = NULL;
+ }
+
+ /* Destruct the flow ring table */
+ flow_ring_table_sz = dhdp->num_flow_rings * sizeof(flow_ring_table_t);
+ MFREE(dhdp->osh, flow_ring_table, flow_ring_table_sz);
+ }
+
+ DHD_FLOWID_LOCK(dhdp->flowid_lock, flags);
+
+ /* Destruct the per interface flow lkup table */
+ if (dhdp->if_flow_lkup != NULL) {
+ if_flow_lkup_sz = sizeof(if_flow_lkup_t) * DHD_MAX_IFS;
+ bzero(dhdp->if_flow_lkup, sizeof(if_flow_lkup_sz));
+ DHD_OS_PREFREE(dhdp, dhdp->if_flow_lkup, if_flow_lkup_sz);
+ dhdp->if_flow_lkup = NULL;
+ }
+
+#ifdef PCIE_TX_DEFERRAL
+ if (dhdp->bus->delete_flow_map)
+ kfree(dhdp->bus->delete_flow_map);
+#endif
+
+ /* Destruct the flowid allocator */
+ if (dhdp->flowid_allocator != NULL)
+ dhdp->flowid_allocator = id16_map_fini(dhdp->osh, dhdp->flowid_allocator);
+
+ dhdp->num_flow_rings = 0U;
+ lock = dhdp->flowid_lock;
+ dhdp->flowid_lock = NULL;
+
+ DHD_FLOWID_UNLOCK(lock, flags);
+ dhd_os_spin_lock_deinit(dhdp->osh, lock);
+}
+
+uint8
+dhd_flow_rings_ifindex2role(dhd_pub_t *dhdp, uint8 ifindex)
+{
+ if_flow_lkup_t *if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup;
+ ASSERT(if_flow_lkup);
+ return if_flow_lkup[ifindex].role;
+}
+
+#ifdef WLTDLS
+bool is_tdls_destination(dhd_pub_t *dhdp, uint8 *da)
+{
+ tdls_peer_node_t *cur = dhdp->peer_tbl.node;
+ while (cur != NULL) {
+ if (!memcmp(da, cur->addr, ETHER_ADDR_LEN)) {
+ return TRUE;
+ }
+ cur = cur->next;
+ }
+ return FALSE;
+}
+#endif /* WLTDLS */
+
+/* For a given interface, search the hash table for a matching flow */
+uint16
+dhd_flowid_find(dhd_pub_t *dhdp, uint8 ifindex, uint8 prio, char *sa, char *da)
+{
+ int hash;
+ bool ismcast = FALSE;
+ flow_hash_info_t *cur;
+ if_flow_lkup_t *if_flow_lkup;
+ unsigned long flags;
+
+ DHD_FLOWID_LOCK(dhdp->flowid_lock, flags);
+ if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup;
+
+ if (DHD_IF_ROLE_STA(if_flow_lkup[ifindex].role)) {
+#ifdef WLTDLS
+ if (dhdp->peer_tbl.tdls_peer_count && !(ETHER_ISMULTI(da)) &&
+ is_tdls_destination(dhdp, da)) {
+ hash = DHD_FLOWRING_HASHINDEX(da, prio);
+ cur = if_flow_lkup[ifindex].fl_hash[hash];
+ while (cur != NULL) {
+ if (!memcmp(cur->flow_info.da, da, ETHER_ADDR_LEN)) {
+ DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags);
+ return cur->flowid;
+ }
+ cur = cur->next;
+ }
+ DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags);
+ return FLOWID_INVALID;
+ }
+#endif /* WLTDLS */
+ cur = if_flow_lkup[ifindex].fl_hash[prio];
+ if (cur) {
+ DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags);
+ return cur->flowid;
+ }
+
+ } else {
+
+ if (ETHER_ISMULTI(da)) {
+ ismcast = TRUE;
+ hash = 0;
+ } else {
+ hash = DHD_FLOWRING_HASHINDEX(da, prio);
+ }
+
+ cur = if_flow_lkup[ifindex].fl_hash[hash];
+
+ while (cur) {
+ if ((ismcast && ETHER_ISMULTI(cur->flow_info.da)) ||
+ (!memcmp(cur->flow_info.da, da, ETHER_ADDR_LEN) &&
+ (cur->flow_info.tid == prio))) {
+ DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags);
+ return cur->flowid;
+ }
+ cur = cur->next;
+ }
+ }
+ DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags);
+
+ return FLOWID_INVALID;
+}
+
+/* Allocate Flow ID */
+static INLINE uint16
+dhd_flowid_alloc(dhd_pub_t *dhdp, uint8 ifindex, uint8 prio, char *sa, char *da)
+{
+ flow_hash_info_t *fl_hash_node, *cur;
+ if_flow_lkup_t *if_flow_lkup;
+ int hash;
+ uint16 flowid;
+ unsigned long flags;
+
+ fl_hash_node = (flow_hash_info_t *) MALLOC(dhdp->osh, sizeof(flow_hash_info_t));
+ memcpy(fl_hash_node->flow_info.da, da, sizeof(fl_hash_node->flow_info.da));
+
+ DHD_FLOWID_LOCK(dhdp->flowid_lock, flags);
+ ASSERT(dhdp->flowid_allocator != NULL);
+ flowid = id16_map_alloc(dhdp->flowid_allocator);
+ DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags);
+
+ if (flowid == FLOWID_INVALID) {
+ MFREE(dhdp->osh, fl_hash_node, sizeof(flow_hash_info_t));
+ DHD_ERROR(("%s: cannot get free flowid \n", __FUNCTION__));
+ return FLOWID_INVALID;
+ }
+
+ fl_hash_node->flowid = flowid;
+ fl_hash_node->flow_info.tid = prio;
+ fl_hash_node->flow_info.ifindex = ifindex;
+ fl_hash_node->next = NULL;
+
+ DHD_FLOWID_LOCK(dhdp->flowid_lock, flags);
+ if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup;
+ if (DHD_IF_ROLE_STA(if_flow_lkup[ifindex].role)) {
+ /* For STA non TDLS dest we allocate entry based on prio only */
+#ifdef WLTDLS
+ if (dhdp->peer_tbl.tdls_peer_count &&
+ (is_tdls_destination(dhdp, da))) {
+ hash = DHD_FLOWRING_HASHINDEX(da, prio);
+ cur = if_flow_lkup[ifindex].fl_hash[hash];
+ if (cur) {
+ while (cur->next) {
+ cur = cur->next;
+ }
+ cur->next = fl_hash_node;
+ } else {
+ if_flow_lkup[ifindex].fl_hash[hash] = fl_hash_node;
+ }
+ } else
+#endif /* WLTDLS */
+ if_flow_lkup[ifindex].fl_hash[prio] = fl_hash_node;
+ } else {
+
+ /* For bcast/mcast assign first slot in in interface */
+ hash = ETHER_ISMULTI(da) ? 0 : DHD_FLOWRING_HASHINDEX(da, prio);
+ cur = if_flow_lkup[ifindex].fl_hash[hash];
+ if (cur) {
+ while (cur->next) {
+ cur = cur->next;
+ }
+ cur->next = fl_hash_node;
+ } else
+ if_flow_lkup[ifindex].fl_hash[hash] = fl_hash_node;
+ }
+ DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags);
+
+ DHD_INFO(("%s: allocated flowid %d\n", __FUNCTION__, fl_hash_node->flowid));
+
+ return fl_hash_node->flowid;
+}
+
+/* Get flow ring ID, if not present try to create one */
+static INLINE int
+dhd_flowid_lookup(dhd_pub_t *dhdp, uint8 ifindex,
+ uint8 prio, char *sa, char *da, uint16 *flowid)
+{
+ uint16 id;
+ flow_ring_node_t *flow_ring_node;
+ flow_ring_table_t *flow_ring_table;
+ unsigned long flags;
+
+ DHD_INFO(("%s\n", __FUNCTION__));
+
+ if (!dhdp->flow_ring_table)
+ return BCME_ERROR;
+
+ flow_ring_table = (flow_ring_table_t *)dhdp->flow_ring_table;
+
+ id = dhd_flowid_find(dhdp, ifindex, prio, sa, da);
+
+ if (id == FLOWID_INVALID) {
+
+ if_flow_lkup_t *if_flow_lkup;
+ if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup;
+
+ if (!if_flow_lkup[ifindex].status)
+ return BCME_ERROR;
+
+ id = dhd_flowid_alloc(dhdp, ifindex, prio, sa, da);
+ if (id == FLOWID_INVALID) {
+ DHD_ERROR(("%s: alloc flowid ifindex %u status %u\n",
+ __FUNCTION__, ifindex, if_flow_lkup[ifindex].status));
+ return BCME_ERROR;
+ }
+
+ /* register this flowid in dhd_pub */
+ dhd_add_flowid(dhdp, ifindex, prio, da, id);
+ }
+
+ ASSERT(id < dhdp->num_flow_rings);
+
+ flow_ring_node = (flow_ring_node_t *) &flow_ring_table[id];
+ DHD_FLOWRING_LOCK(flow_ring_node->lock, flags);
+ if (flow_ring_node->active) {
+ DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags);
+ *flowid = id;
+ return BCME_OK;
+ }
+ /* Init Flow info */
+ memcpy(flow_ring_node->flow_info.sa, sa, sizeof(flow_ring_node->flow_info.sa));
+ memcpy(flow_ring_node->flow_info.da, da, sizeof(flow_ring_node->flow_info.da));
+ flow_ring_node->flow_info.tid = prio;
+ flow_ring_node->flow_info.ifindex = ifindex;
+ flow_ring_node->active = TRUE;
+ flow_ring_node->status = FLOW_RING_STATUS_PENDING;
+ DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags);
+ DHD_FLOWID_LOCK(dhdp->flowid_lock, flags);
+ dll_prepend(&dhdp->bus->const_flowring, &flow_ring_node->list);
+ DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags);
+
+ /* Create and inform device about the new flow */
+ if (dhd_bus_flow_ring_create_request(dhdp->bus, (void *)flow_ring_node)
+ != BCME_OK) {
+ DHD_ERROR(("%s: create error %d\n", __FUNCTION__, id));
+ return BCME_ERROR;
+ }
+
+ *flowid = id;
+ return BCME_OK;
+}
+
+/* Update flowid information on the packet */
+int BCMFASTPATH
+dhd_flowid_update(dhd_pub_t *dhdp, uint8 ifindex, uint8 prio, void *pktbuf)
+{
+ uint8 *pktdata = (uint8 *)PKTDATA(dhdp->osh, pktbuf);
+ struct ether_header *eh = (struct ether_header *)pktdata;
+ uint16 flowid;
+
+ if (dhd_bus_is_txmode_push(dhdp->bus))
+ return BCME_OK;
+
+ ASSERT(ifindex < DHD_MAX_IFS);
+ if (ifindex >= DHD_MAX_IFS) {
+ return BCME_BADARG;
+ }
+
+ if (!dhdp->flowid_allocator) {
+ DHD_ERROR(("%s: Flow ring not intited yet \n", __FUNCTION__));
+ return BCME_ERROR;
+ }
+ if (dhd_flowid_lookup(dhdp, ifindex, prio, eh->ether_shost, eh->ether_dhost,
+ &flowid) != BCME_OK) {
+ return BCME_ERROR;
+ }
+
+ DHD_INFO(("%s: prio %d flowid %d\n", __FUNCTION__, prio, flowid));
+
+ /* Tag the packet with flowid */
+ DHD_PKTTAG_SET_FLOWID((dhd_pkttag_fr_t *)PKTTAG(pktbuf), flowid);
+ return BCME_OK;
+}
+
+void
+dhd_flowid_free(dhd_pub_t *dhdp, uint8 ifindex, uint16 flowid)
+{
+ int hashix;
+ bool found = FALSE;
+ flow_hash_info_t *cur, *prev;
+ if_flow_lkup_t *if_flow_lkup;
+ unsigned long flags;
+
+ DHD_FLOWID_LOCK(dhdp->flowid_lock, flags);
+ if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup;
+
+ for (hashix = 0; hashix < DHD_FLOWRING_HASH_SIZE; hashix++) {
+
+ cur = if_flow_lkup[ifindex].fl_hash[hashix];
+
+ if (cur) {
+ if (cur->flowid == flowid) {
+ found = TRUE;
+ }
+
+ prev = NULL;
+ while (!found && cur) {
+ if (cur->flowid == flowid) {
+ found = TRUE;
+ break;
+ }
+ prev = cur;
+ cur = cur->next;
+ }
+ if (found) {
+ if (!prev) {
+ if_flow_lkup[ifindex].fl_hash[hashix] = cur->next;
+ } else {
+ prev->next = cur->next;
+ }
+
+ /* deregister flowid from dhd_pub. */
+ dhd_del_flowid(dhdp, ifindex, flowid);
+
+ id16_map_free(dhdp->flowid_allocator, flowid);
+ DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags);
+ MFREE(dhdp->osh, cur, sizeof(flow_hash_info_t));
+
+ return;
+ }
+ }
+ }
+
+ DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags);
+ DHD_ERROR(("%s: could not free flow ring hash entry flowid %d\n",
+ __FUNCTION__, flowid));
+}
+
+
+/* Delete all Flow rings assocaited with the given Interface */
+void
+dhd_flow_rings_delete(dhd_pub_t *dhdp, uint8 ifindex)
+{
+ uint32 id;
+ flow_ring_table_t *flow_ring_table;
+
+ DHD_INFO(("%s: ifindex %u\n", __FUNCTION__, ifindex));
+
+ ASSERT(ifindex < DHD_MAX_IFS);
+ if (ifindex >= DHD_MAX_IFS)
+ return;
+
+ if (!dhdp->flow_ring_table)
+ return;
+
+ flow_ring_table = (flow_ring_table_t *)dhdp->flow_ring_table;
+ for (id = 0; id < dhdp->num_flow_rings; id++) {
+ if (flow_ring_table[id].active &&
+ (flow_ring_table[id].flow_info.ifindex == ifindex) &&
+ (flow_ring_table[id].status != FLOW_RING_STATUS_DELETE_PENDING)) {
+ DHD_INFO(("%s: deleting flowid %d\n",
+ __FUNCTION__, flow_ring_table[id].flowid));
+ dhd_bus_flow_ring_delete_request(dhdp->bus,
+ (void *) &flow_ring_table[id]);
+ }
+ }
+}
+
+/* Delete flow/s for given peer address */
+void
+dhd_flow_rings_delete_for_peer(dhd_pub_t *dhdp, uint8 ifindex, char *addr)
+{
+ uint32 id;
+ flow_ring_table_t *flow_ring_table;
+
+ DHD_ERROR(("%s: ifindex %u\n", __FUNCTION__, ifindex));
+
+ ASSERT(ifindex < DHD_MAX_IFS);
+ if (ifindex >= DHD_MAX_IFS)
+ return;
+
+ if (!dhdp->flow_ring_table)
+ return;
+
+ flow_ring_table = (flow_ring_table_t *)dhdp->flow_ring_table;
+ for (id = 0; id < dhdp->num_flow_rings; id++) {
+ if (flow_ring_table[id].active &&
+ (flow_ring_table[id].flow_info.ifindex == ifindex) &&
+ (!memcmp(flow_ring_table[id].flow_info.da, addr, ETHER_ADDR_LEN)) &&
+ (flow_ring_table[id].status != FLOW_RING_STATUS_DELETE_PENDING)) {
+ DHD_INFO(("%s: deleting flowid %d\n",
+ __FUNCTION__, flow_ring_table[id].flowid));
+ dhd_bus_flow_ring_delete_request(dhdp->bus,
+ (void *) &flow_ring_table[id]);
+ }
+ }
+}
+
+/* Handle Interface ADD, DEL operations */
+void
+dhd_update_interface_flow_info(dhd_pub_t *dhdp, uint8 ifindex,
+ uint8 op, uint8 role)
+{
+ if_flow_lkup_t *if_flow_lkup;
+ unsigned long flags;
+
+ ASSERT(ifindex < DHD_MAX_IFS);
+ if (ifindex >= DHD_MAX_IFS)
+ return;
+
+ DHD_INFO(("%s: ifindex %u op %u role is %u \n",
+ __FUNCTION__, ifindex, op, role));
+ if (!dhdp->flowid_allocator) {
+ DHD_ERROR(("%s: Flow ring not intited yet \n", __FUNCTION__));
+ return;
+ }
+
+ DHD_FLOWID_LOCK(dhdp->flowid_lock, flags);
+ if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup;
+
+ if (op == WLC_E_IF_ADD || op == WLC_E_IF_CHANGE) {
+
+ if_flow_lkup[ifindex].role = role;
+
+ if (!(DHD_IF_ROLE_STA(role))) {
+ if_flow_lkup[ifindex].status = TRUE;
+ DHD_INFO(("%s: Mcast Flow ring for ifindex %d role is %d \n",
+ __FUNCTION__, ifindex, role));
+ /* Create Mcast Flow */
+ }
+ } else if (op == WLC_E_IF_DEL) {
+ if_flow_lkup[ifindex].status = FALSE;
+ DHD_INFO(("%s: cleanup all Flow rings for ifindex %d role is %d \n",
+ __FUNCTION__, ifindex, role));
+ }
+ DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags);
+}
+
+/* Handle a STA interface link status update */
+int
+dhd_update_interface_link_status(dhd_pub_t *dhdp, uint8 ifindex, uint8 status)
+{
+ if_flow_lkup_t *if_flow_lkup;
+ unsigned long flags;
+
+ ASSERT(ifindex < DHD_MAX_IFS);
+ if (ifindex >= DHD_MAX_IFS)
+ return BCME_BADARG;
+
+ DHD_INFO(("%s: ifindex %d status %d\n", __FUNCTION__, ifindex, status));
+
+ DHD_FLOWID_LOCK(dhdp->flowid_lock, flags);
+ if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup;
+
+ if (DHD_IF_ROLE_STA(if_flow_lkup[ifindex].role)) {
+ if (status)
+ if_flow_lkup[ifindex].status = TRUE;
+ else
+ if_flow_lkup[ifindex].status = FALSE;
+ }
+ DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags);
+
+ return BCME_OK;
+}
+/* Update flow priority mapping */
+int dhd_update_flow_prio_map(dhd_pub_t *dhdp, uint8 map)
+{
+ uint16 flowid;
+ flow_ring_node_t *flow_ring_node;
+
+ if (map > DHD_FLOW_PRIO_TID_MAP)
+ return BCME_BADOPTION;
+
+ /* Check if we need to change prio map */
+ if (map == dhdp->flow_prio_map_type)
+ return BCME_OK;
+
+ /* If any ring is active we cannot change priority mapping for flow rings */
+ for (flowid = 0; flowid < dhdp->num_flow_rings; flowid++) {
+ flow_ring_node = DHD_FLOW_RING(dhdp, flowid);
+ if (flow_ring_node->active)
+ return BCME_EPERM;
+ }
+ /* Infor firmware about new mapping type */
+ if (BCME_OK != dhd_flow_prio_map(dhdp, &map, TRUE))
+ return BCME_ERROR;
+
+ /* update internal structures */
+ dhdp->flow_prio_map_type = map;
+ if (dhdp->flow_prio_map_type == DHD_FLOW_PRIO_TID_MAP)
+ bcopy(prio2tid, dhdp->flow_prio_map, sizeof(uint8) * NUMPRIO);
+ else
+ bcopy(prio2ac, dhdp->flow_prio_map, sizeof(uint8) * NUMPRIO);
+
+ return BCME_OK;
+}
+
+/* Set/Get flwo ring priority map */
+int dhd_flow_prio_map(dhd_pub_t *dhd, uint8 *map, bool set)
+{
+ uint8 iovbuf[24];
+ if (!set) {
+ bcm_mkiovar("bus:fl_prio_map", NULL, 0, (char*)iovbuf, sizeof(iovbuf));
+ if (dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0) < 0) {
+ DHD_ERROR(("%s: failed to get fl_prio_map\n", __FUNCTION__));
+ return BCME_ERROR;
+ }
+ *map = iovbuf[0];
+ return BCME_OK;
+ }
+ bcm_mkiovar("bus:fl_prio_map", (char *)map, 4, (char*)iovbuf, sizeof(iovbuf));
+ if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0) < 0) {
+ DHD_ERROR(("%s: failed to set fl_prio_map \n",
+ __FUNCTION__));
+ return BCME_ERROR;
+ }
+ return BCME_OK;
+}
diff -Nur a/drivers/net/wireless/bcmdhd/dhd_flowring.h c/drivers/net/wireless/bcmdhd/dhd_flowring.h
--- a/drivers/net/wireless/bcmdhd/dhd_flowring.h 1970-01-01 01:00:00.000000000 +0100
+++ c/drivers/net/wireless/bcmdhd/dhd_flowring.h 2016-05-13 09:48:20.000000000 +0200
@@ -0,0 +1,159 @@
+/*
+ * Header file describing the flow rings DHD interfaces.
+ *
+ * Provides type definitions and function prototypes used to create, delete and manage
+ *
+ * flow rings at high level
+ *
+ * $Copyright Open Broadcom Corporation$
+ *
+ * $Id: dhd_flowrings.h jaganlv $
+ */
+
+/****************
+ * Common types *
+ */
+
+#ifndef _dhd_flowrings_h_
+#define _dhd_flowrings_h_
+
+/* Max pkts held in a flow ring's backup queue */
+#define FLOW_RING_QUEUE_THRESHOLD (2048)
+
+/* Number of H2D common rings : PCIE Spec Rev? */
+#define FLOW_RING_COMMON 2
+
+#define FLOWID_INVALID (ID16_INVALID)
+#define FLOWID_RESERVED (FLOW_RING_COMMON)
+
+#define FLOW_RING_STATUS_OPEN 0
+#define FLOW_RING_STATUS_PENDING 1
+#define FLOW_RING_STATUS_CLOSED 2
+#define FLOW_RING_STATUS_DELETE_PENDING 3
+#define FLOW_RING_STATUS_FLUSH_PENDING 4
+
+#define DHD_FLOWRING_RX_BUFPOST_PKTSZ 2048
+
+#define DHD_FLOW_PRIO_AC_MAP 0
+#define DHD_FLOW_PRIO_TID_MAP 1
+
+
+/* Pkttag not compatible with PROP_TXSTATUS or WLFC */
+typedef struct dhd_pkttag_fr {
+ uint16 flowid;
+ int dataoff;
+} dhd_pkttag_fr_t;
+
+#define DHD_PKTTAG_SET_FLOWID(tag, flow) ((tag)->flowid = (uint16)(flow))
+#define DHD_PKTTAG_SET_DATAOFF(tag, offset) ((tag)->dataoff = (int)(offset))
+
+#define DHD_PKTTAG_FLOWID(tag) ((tag)->flowid)
+#define DHD_PKTTAG_DATAOFF(tag) ((tag)->dataoff)
+
+/* Hashing a MacAddress for lkup into a per interface flow hash table */
+#define DHD_FLOWRING_HASH_SIZE 256
+#define DHD_FLOWRING_HASHINDEX(ea, prio) \
+ ((((uint8 *)(ea))[3] ^ ((uint8 *)(ea))[4] ^ ((uint8 *)(ea))[5] ^ ((uint8)(prio))) \
+ % DHD_FLOWRING_HASH_SIZE)
+
+#define DHD_IF_ROLE(pub, idx) (((if_flow_lkup_t *)(pub)->if_flow_lkup)[idx].role)
+#define DHD_IF_ROLE_AP(pub, idx) (DHD_IF_ROLE(pub, idx) == WLC_E_IF_ROLE_AP)
+#define DHD_IF_ROLE_P2PGO(pub, idx) (DHD_IF_ROLE(pub, idx) == WLC_E_IF_ROLE_P2P_GO)
+#define DHD_FLOW_RING(dhdp, flowid) \
+ (flow_ring_node_t *)&(((flow_ring_node_t *)((dhdp)->flow_ring_table))[flowid])
+
+struct flow_queue;
+
+/* Flow Ring Queue Enqueue overflow callback */
+typedef int (*flow_queue_cb_t)(struct flow_queue * queue, void * pkt);
+
+typedef struct flow_queue {
+ dll_t list; /* manage a flowring queue in a dll */
+ void * head; /* first packet in the queue */
+ void * tail; /* last packet in the queue */
+ uint16 len; /* number of packets in the queue */
+ uint16 max; /* maximum number of packets, queue may hold */
+ uint32 failures; /* enqueue failures due to queue overflow */
+ flow_queue_cb_t cb; /* callback invoked on threshold crossing */
+} flow_queue_t;
+
+#define flow_queue_len(queue) ((int)(queue)->len)
+#define flow_queue_max(queue) ((int)(queue)->max)
+#define flow_queue_avail(queue) ((int)((queue)->max - (queue)->len))
+#define flow_queue_full(queue) ((queue)->len >= (queue)->max)
+#define flow_queue_empty(queue) ((queue)->len == 0)
+
+typedef struct flow_info {
+ uint8 tid;
+ uint8 ifindex;
+ char sa[ETHER_ADDR_LEN];
+ char da[ETHER_ADDR_LEN];
+} flow_info_t;
+
+typedef struct flow_ring_node {
+ dll_t list; /* manage a constructed flowring in a dll, must be at first place */
+ flow_queue_t queue;
+ bool active;
+ uint8 status;
+ uint16 flowid;
+ flow_info_t flow_info;
+ void *prot_info;
+ void *lock; /* lock for flowring access protection */
+} flow_ring_node_t;
+typedef flow_ring_node_t flow_ring_table_t;
+
+typedef struct flow_hash_info {
+ uint16 flowid;
+ flow_info_t flow_info;
+ struct flow_hash_info *next;
+} flow_hash_info_t;
+
+typedef struct if_flow_lkup {
+ bool status;
+ uint8 role; /* Interface role: STA/AP */
+ flow_hash_info_t *fl_hash[DHD_FLOWRING_HASH_SIZE]; /* Lkup Hash table */
+} if_flow_lkup_t;
+
+static INLINE flow_ring_node_t *
+dhd_constlist_to_flowring(dll_t *item)
+{
+ return ((flow_ring_node_t *)item);
+}
+
+/* Exported API */
+
+/* Flow ring's queue management functions */
+extern void dhd_flow_queue_init(dhd_pub_t *dhdp, flow_queue_t *queue, int max);
+extern void dhd_flow_queue_register(flow_queue_t *queue, flow_queue_cb_t cb);
+extern int dhd_flow_queue_enqueue(dhd_pub_t *dhdp, flow_queue_t *queue, void *pkt);
+extern void * dhd_flow_queue_dequeue(dhd_pub_t *dhdp, flow_queue_t *queue);
+extern void dhd_flow_queue_reinsert(dhd_pub_t *dhdp, flow_queue_t *queue, void *pkt);
+
+extern int dhd_flow_rings_init(dhd_pub_t *dhdp, uint32 num_flow_rings);
+
+extern void dhd_flow_rings_deinit(dhd_pub_t *dhdp);
+
+extern uint16 dhd_flowid_find(dhd_pub_t *dhdp, uint8 ifindex, uint8 prio, char *sa, char *da);
+
+extern int dhd_flowid_update(dhd_pub_t *dhdp, uint8 ifindex, uint8 prio,
+ void *pktbuf);
+
+extern void dhd_flowid_free(dhd_pub_t *dhdp, uint8 ifindex, uint16 flowid);
+
+extern void dhd_flow_rings_delete(dhd_pub_t *dhdp, uint8 ifindex);
+
+extern void dhd_flow_rings_delete_for_peer(dhd_pub_t *dhdp, uint8 ifindex,
+ char *addr);
+
+/* Handle Interface ADD, DEL operations */
+extern void dhd_update_interface_flow_info(dhd_pub_t *dhdp, uint8 ifindex,
+ uint8 op, uint8 role);
+
+/* Handle a STA interface link status update */
+extern int dhd_update_interface_link_status(dhd_pub_t *dhdp, uint8 ifindex,
+ uint8 status);
+extern int dhd_flow_prio_map(dhd_pub_t *dhd, uint8 *map, bool set);
+extern int dhd_update_flow_prio_map(dhd_pub_t *dhdp, uint8 map);
+
+extern uint8 dhd_flow_rings_ifindex2role(dhd_pub_t *dhdp, uint8 ifindex);
+#endif /* _dhd_flowrings_h_ */
diff -Nur a/drivers/net/wireless/bcmdhd/dhd_gpio.c c/drivers/net/wireless/bcmdhd/dhd_gpio.c
--- a/drivers/net/wireless/bcmdhd/dhd_gpio.c 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/dhd_gpio.c 2016-09-30 00:48:52.927893893 +0200
@@ -1,19 +1,15 @@
#include <osl.h>
-
-#ifdef CUSTOMER_HW
+#include <dhd_linux.h>
#ifdef CONFIG_MACH_ODROID_4210
#include <mach/gpio.h>
#include <mach/regs-gpio.h>
#include <plat/gpio-cfg.h>
-
#include <plat/sdhci.h>
-#include <plat/devs.h> // modifed plat-samsung/dev-hsmmcX.c EXPORT_SYMBOL(s3c_device_hsmmcx) added
-
+#include <plat/devs.h>
#define sdmmc_channel s3c_device_hsmmc0
#endif
-
#ifdef CONFIG_ARCH_SUNXI
#include <linux/gpio.h>
#include <mach/sys_config.h>
@@ -24,15 +20,6 @@
extern void wifi_pm_power(int on);
#endif
-struct wifi_platform_data {
- int (*set_power)(bool val);
- int (*set_carddetect)(bool val);
- void *(*mem_prealloc)(int section, unsigned long size);
- int (*get_mac_addr)(unsigned char *buf);
- void *(*get_country_code)(char *ccode);
-};
-
-struct resource dhd_wlan_resources = {0};
struct wifi_platform_data dhd_wlan_control = {0};
#ifdef CUSTOMER_OOB
@@ -41,7 +28,7 @@
uint host_oob_irq = 0;
#ifdef CONFIG_MACH_ODROID_4210
- printk("GPIO(WL_HOST_WAKE) = EXYNOS4_GPX0(7) = %d\n", EXYNOS4_GPX0(7));
+ printf("GPIO(WL_HOST_WAKE) = EXYNOS4_GPX0(7) = %d\n", EXYNOS4_GPX0(7));
host_oob_irq = gpio_to_irq(EXYNOS4_GPX0(7));
gpio_direction_input(EXYNOS4_GPX0(7));
#endif
@@ -66,7 +53,7 @@
}
printk("gpio [%d] map to virq [%d] ok\n",wl_host_wake, host_oob_irq);
#endif
- printk("host_oob_irq: %d \r\n", host_oob_irq);
+ printf("host_oob_irq: %d\n", host_oob_irq);
return host_oob_irq;
}
@@ -75,28 +62,13 @@
{
uint host_oob_irq_flags = 0;
-#ifdef CONFIG_MACH_ODROID_4210
- host_oob_irq_flags = (IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | IORESOURCE_IRQ_SHAREABLE) & IRQF_TRIGGER_MASK;
-#endif
-#ifdef CONFIG_ARCH_SUNXI
- script_item_value_type_e type;
- script_item_u val;
- int host_wake_invert = 0;
-
- type = script_get_item("wifi_para", "wl_host_wake_invert", &val);
- if (SCIRPT_ITEM_VALUE_TYPE_INT != type) {
- printk(("has no wl_host_wake_invert\n"));
- } else {
- host_wake_invert = val.val;
- }
-
- if(!host_wake_invert)
- host_oob_irq_flags = (IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | IORESOURCE_IRQ_SHAREABLE) & IRQF_TRIGGER_MASK;
- else
- host_oob_irq_flags = (IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL | IORESOURCE_IRQ_SHAREABLE) & IRQF_TRIGGER_MASK;
+#ifdef HW_OOB
+ host_oob_irq_flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | IORESOURCE_IRQ_SHAREABLE;
+#else
+ host_oob_irq_flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE | IORESOURCE_IRQ_SHAREABLE;
#endif
- printk("host_oob_irq_flags=%d\n", host_oob_irq_flags);
+ printf("host_oob_irq_flags=0x%X\n", host_oob_irq_flags);
return host_oob_irq_flags;
}
@@ -107,22 +79,25 @@
int err = 0;
if (on) {
- printk("======== PULL WL_REG_ON HIGH! ========\n");
+ printf("======== PULL WL_REG_ON HIGH! ========\n");
#ifdef CONFIG_MACH_ODROID_4210
err = gpio_set_value(EXYNOS4_GPK1(0), 1);
#endif
#ifdef CONFIG_ARCH_SUNXI
+ wifi_pm_power(0);
+ mdelay(200);
wifi_pm_power(1);
+ mdelay(200);
+#endif
/* Lets customer power to get stable */
mdelay(100);
-#endif
} else {
- printk("======== PULL WL_REG_ON LOW! ========\n");
+ printf("======== PULL WL_REG_ON LOW! ========\n");
#ifdef CONFIG_MACH_ODROID_4210
err = gpio_set_value(EXYNOS4_GPK1(0), 0);
#endif
#ifdef CONFIG_ARCH_SUNXI
- wifi_pm_power(0);
+ //wifi_pm_power(0);
#endif
}
@@ -134,7 +109,7 @@
int err = 0;
if (present) {
- printk("======== Card detection to detect SDIO card! ========\n");
+ printf("======== Card detection to detect SDIO card! ========\n");
#ifdef CONFIG_MACH_ODROID_4210
err = sdhci_s3c_force_presence_change(&sdmmc_channel, 1);
#endif
@@ -142,7 +117,7 @@
sunxi_mci_rescan_card(sdc_id, 1);
#endif
} else {
- printk("======== Card detection to remove SDIO card! ========\n");
+ printf("======== Card detection to remove SDIO card! ========\n");
#ifdef CONFIG_MACH_ODROID_4210
err = sdhci_s3c_force_presence_change(&sdmmc_channel, 0);
#endif
@@ -154,6 +129,22 @@
return err;
}
+int bcm_wlan_get_mac_address(unsigned char *buf)
+{
+ int err = 0;
+
+ printf("======== %s ========\n", __FUNCTION__);
+#ifdef EXAMPLE_GET_MAC
+ /* EXAMPLE code */
+ {
+ struct ether_addr ea_example = {{0x00, 0x11, 0x22, 0x33, 0x44, 0xFF}};
+ bcopy((char *)&ea_example, buf, sizeof(struct ether_addr));
+ }
+#endif /* EXAMPLE_GET_MAC */
+
+ return err;
+}
+
#ifdef CONFIG_DHD_USE_STATIC_BUF
extern void *bcmdhd_mem_prealloc(int section, unsigned long size);
void* bcm_wlan_prealloc(int section, unsigned long size)
@@ -161,26 +152,54 @@
void *alloc_ptr = NULL;
alloc_ptr = bcmdhd_mem_prealloc(section, size);
if (alloc_ptr) {
- printk("success alloc section %d, size %ld\n", section, size);
+ printf("success alloc section %d, size %ld\n", section, size);
if (size != 0L)
bzero(alloc_ptr, size);
return alloc_ptr;
}
- printk("can't alloc section %d\n", section);
+ printf("can't alloc section %d\n", section);
return NULL;
}
#endif
-#ifdef GET_CUSTOM_MAC_ENABLE
-extern int dhd_custom_get_mac_address(unsigned char *buf);
+#if !defined(WL_WIRELESS_EXT)
+struct cntry_locales_custom {
+ char iso_abbrev[WLC_CNTRY_BUF_SZ]; /* ISO 3166-1 country abbreviation */
+ char custom_locale[WLC_CNTRY_BUF_SZ]; /* Custom firmware locale */
+ int32 custom_locale_rev; /* Custom local revisin default -1 */
+};
#endif
+static struct cntry_locales_custom brcm_wlan_translate_custom_table[] = {
+ /* Table should be filled out based on custom platform regulatory requirement */
+ {"", "XT", 49}, /* Universal if Country code is unknown or empty */
+ {"US", "US", 0},
+};
+
+static void *bcm_wlan_get_country_code(char *ccode)
+{
+ struct cntry_locales_custom *locales;
+ int size;
+ int i;
+
+ if (!ccode)
+ return NULL;
+
+ locales = brcm_wlan_translate_custom_table;
+ size = ARRAY_SIZE(brcm_wlan_translate_custom_table);
+
+ for (i = 0; i < size; i++)
+ if (strcmp(ccode, locales[i].iso_abbrev) == 0)
+ return &locales[i];
+ return NULL;
+}
+
int bcm_wlan_set_plat_data(void) {
#ifdef CONFIG_ARCH_SUNXI
script_item_value_type_e type;
script_item_u val;
#endif
- printk("======== %s ========\n", __FUNCTION__);
+ printf("======== %s ========\n", __FUNCTION__);
#ifdef CONFIG_ARCH_SUNXI
type = script_get_item("wifi_para", "wifi_sdc_id", &val);
if (SCIRPT_ITEM_VALUE_TYPE_INT != type) {
@@ -191,13 +210,11 @@
#endif
dhd_wlan_control.set_power = bcm_wlan_set_power;
dhd_wlan_control.set_carddetect = bcm_wlan_set_carddetect;
+ dhd_wlan_control.get_mac_addr = bcm_wlan_get_mac_address;
#ifdef CONFIG_DHD_USE_STATIC_BUF
dhd_wlan_control.mem_prealloc = bcm_wlan_prealloc;
#endif
-#ifdef GET_CUSTOM_MAC_ENABLE
- dhd_wlan_control.get_mac_addr = dhd_custom_get_mac_address;
-#endif
+ dhd_wlan_control.get_country_code = bcm_wlan_get_country_code;
return 0;
}
-#endif /* CUSTOMER_HW */
diff -Nur a/drivers/net/wireless/bcmdhd/dhd.h c/drivers/net/wireless/bcmdhd/dhd.h
--- a/drivers/net/wireless/bcmdhd/dhd.h 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/dhd.h 2016-05-13 09:48:20.000000000 +0200
@@ -6,7 +6,7 @@
*
* $Copyright Open Broadcom Corporation$
*
- * $Id: dhd.h 491170 2014-07-15 06:23:58Z $
+ * $Id: dhd.h 504503 2014-09-24 11:28:56Z $
*/
/****************
@@ -41,6 +41,7 @@
#include <wlioctl.h>
#include <wlfc_proto.h>
+#include <hnd_pktq.h>
#if defined(BCMWDF)
#include <wdf.h>
@@ -70,7 +71,8 @@
DHD_BUS_SUSPEND, /* Bus has been suspended */
};
-#if defined(NDISVER) && (NDISVER >= 0x0600)
+#if defined(NDISVER)
+#if (NDISVER >= 0x0600)
/* Firmware requested operation mode */
#define STA_MASK 0x0001
#define HOSTAPD_MASK 0x0002
@@ -80,6 +82,10 @@
#define P2P_GC_ENABLED 0x0020
#define CONCURENT_MASK 0x00F0
#endif /* (NDISVER >= 0x0600) */
+#endif /* #if defined(NDISVER) */
+
+#define DHD_IF_ROLE_STA(role) (role == WLC_E_IF_ROLE_STA ||\
+ role == WLC_E_IF_ROLE_P2P_CLIENT)
/* For supporting multiple interfaces */
#define DHD_MAX_IFS 16
@@ -145,13 +151,20 @@
#if defined(STATIC_WL_PRIV_STRUCT)
DHD_PREALLOC_WIPHY_ESCAN0 = 5,
#endif /* STATIC_WL_PRIV_STRUCT */
- DHD_PREALLOC_DHD_INFO = 7
+ DHD_PREALLOC_DHD_INFO = 7,
+ DHD_PREALLOC_DHD_WLFC_INFO = 8,
+ DHD_PREALLOC_IF_FLOW_LKUP = 9,
+ DHD_PREALLOC_FLOWRING = 10
};
/* Packet alignment for most efficient SDIO (can change based on platform) */
#ifndef DHD_SDALIGN
+#ifdef CUSTOM_SDIO_F2_BLKSIZE
+#define DHD_SDALIGN CUSTOM_SDIO_F2_BLKSIZE
+#else
#define DHD_SDALIGN 32
#endif
+#endif
/* host reordering packts logic */
/* followed the structure to hold the reorder buffers (void **p) */
@@ -177,6 +190,7 @@
* 2. TCPACKs that don't need to hurry delivered remains longer in TXQ so can be suppressed.
*/
TCPACK_SUP_DELAYTX,
+ TCPACK_SUP_HOLD,
TCPACK_SUP_LAST_MODE
};
#endif /* DHDTCPACK_SUPPRESS */
@@ -294,7 +308,7 @@
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1
struct mutex wl_start_stop_lock; /* lock/unlock for Android start/stop */
struct mutex wl_softap_lock; /* lock/unlock for any SoftAP/STA settings */
-#endif
+#endif
#ifdef WLBTAMP
uint16 maxdatablks;
@@ -351,6 +365,8 @@
#ifdef DHDTCPACK_SUPPRESS
uint8 tcpack_sup_mode; /* TCPACK suppress mode */
void *tcpack_sup_module; /* TCPACK suppress module */
+ uint32 tcpack_sup_ratio;
+ uint32 tcpack_sup_delay;
#endif /* DHDTCPACK_SUPPRESS */
#if defined(ARP_OFFLOAD_SUPPORT)
uint32 arp_version;
@@ -358,20 +374,30 @@
#if defined(BCMSUP_4WAY_HANDSHAKE) && defined(WLAN_AKM_SUITE_FT_8021X)
bool fw_4way_handshake; /* Whether firmware will to do the 4way handshake. */
#endif
+#if defined(CUSTOM_PLATFORM_NV_TEGRA)
+#ifdef PKT_FILTER_SUPPORT
+ uint pkt_filter_mode;
+ uint pkt_filter_ports_count;
+ uint16 pkt_filter_ports[WL_PKT_FILTER_PORTS_MAX];
+#endif /* PKT_FILTER_SUPPORT */
+#endif /* defined(CUSTOM_PLATFORM_NV_TEGRA) */
#ifdef CUSTOM_SET_CPUCORE
struct task_struct * current_dpc;
struct task_struct * current_rxf;
int chan_isvht80;
#endif /* CUSTOM_SET_CPUCORE */
-
void *sta_pool; /* pre-allocated pool of sta objects */
void *staid_allocator; /* allocator of sta indexes */
void *flowid_allocator; /* unique flowid allocator */
void *flow_ring_table; /* flow ring table, include prot and bus info */
void *if_flow_lkup; /* per interface flowid lkup hash table */
+ void *flowid_lock; /* per os lock for flowid info protection */
uint32 num_flow_rings;
+
+ uint32 d2h_sync_mode; /* D2H DMA completion sync mode */
+
uint8 flow_prio_map[NUMPRIO];
uint8 flow_prio_map_type;
char enable_log[MAX_EVENT];
@@ -431,7 +457,7 @@
#else
#define DHD_PM_RESUME_RETURN_ERROR(a) do { \
if (dhd_mmc_suspend) return a; } while (0)
- #endif
+ #endif
#define DHD_PM_RESUME_RETURN do { if (dhd_mmc_suspend) return; } while (0)
#define DHD_SPINWAIT_SLEEP_INIT(a) DECLARE_WAIT_QUEUE_HEAD(a);
@@ -483,6 +509,10 @@
extern int dhd_os_wake_lock_ctrl_timeout_cancel(dhd_pub_t *pub);
extern int dhd_os_wd_wake_lock(dhd_pub_t *pub);
extern int dhd_os_wd_wake_unlock(dhd_pub_t *pub);
+#ifdef BCMPCIE_OOB_HOST_WAKE
+extern int dhd_os_oob_irq_wake_lock_timeout(dhd_pub_t *pub, int val);
+extern int dhd_os_oob_irq_wake_unlock(dhd_pub_t *pub);
+#endif /* BCMPCIE_OOB_HOST_WAKE */
extern int dhd_os_wake_lock_waive(dhd_pub_t *pub);
extern int dhd_os_wake_lock_restore(dhd_pub_t *pub);
@@ -521,6 +551,11 @@
#define DHD_OS_WD_WAKE_LOCK(pub) dhd_os_wd_wake_lock(pub)
#define DHD_OS_WD_WAKE_UNLOCK(pub) dhd_os_wd_wake_unlock(pub)
+#ifdef BCMPCIE_OOB_HOST_WAKE
+#define OOB_WAKE_LOCK_TIMEOUT 500
+#define DHD_OS_OOB_IRQ_WAKE_LOCK_TIMEOUT(pub, val) dhd_os_oob_irq_wake_lock_timeout(pub, val)
+#define DHD_OS_OOB_IRQ_WAKE_UNLOCK(pub) dhd_os_oob_irq_wake_unlock(pub)
+#endif /* BCMPCIE_OOB_HOST_WAKE */
#define DHD_PACKET_TIMEOUT_MS 500
#define DHD_EVENT_TIMEOUT_MS 1500
@@ -532,7 +567,7 @@
void dhd_net_if_unlock(struct net_device *dev);
#if defined(MULTIPLE_SUPPLICANT)
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 && defined(BCMSDIO)
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1
extern struct mutex _dhd_sdio_mutex_lock_;
#endif
#endif /* MULTIPLE_SUPPLICANT */
@@ -577,6 +612,7 @@
/* Indication from bus module regarding removal/absence of dongle */
extern void dhd_detach(dhd_pub_t *dhdp);
extern void dhd_free(dhd_pub_t *dhdp);
+extern void dhd_clear(dhd_pub_t *dhdp);
/* Indication from bus module to change flow-control state */
extern void dhd_txflowcontrol(dhd_pub_t *dhdp, int ifidx, bool on);
@@ -605,11 +641,6 @@
extern int dhd_os_ioctl_resp_wake(dhd_pub_t * pub);
extern unsigned int dhd_os_get_ioctl_resp_timeout(void);
extern void dhd_os_set_ioctl_resp_timeout(unsigned int timeout_msec);
-#if 0 && (NDISVER >= 0x0600)
-#define dhd_os_open_image(a) wl_os_open_image(a)
-#define dhd_os_close_image(a) wl_os_close_image(a)
-#define dhd_os_get_image_block(a, b, c) wl_os_get_image_block(a, b, c)
-#endif /* (NDISVER >= 0x0600) */
extern int dhd_os_get_image_block(char * buf, int len, void * image);
extern void * dhd_os_open_image(char * filename);
@@ -629,7 +660,7 @@
extern int dhd_customer_oob_irq_map(void *adapter, unsigned long *irq_flags_ptr);
extern int dhd_customer_gpio_wlan_ctrl(void *adapter, int onoff);
-extern int dhd_custom_get_mac_address(unsigned char *buf);
+extern int dhd_custom_get_mac_address(void *adapter, unsigned char *buf);
extern void get_customized_country_code(void *adapter, char *country_iso_code, wl_country_t *cspec);
extern void dhd_os_sdunlock_sndup_rxq(dhd_pub_t * pub);
extern void dhd_os_sdlock_eventq(dhd_pub_t * pub);
@@ -639,6 +670,7 @@
extern void dhd_set_version_info(dhd_pub_t *pub, char *fw);
extern bool dhd_os_check_if_up(dhd_pub_t *pub);
extern int dhd_os_check_wakelock(dhd_pub_t *pub);
+extern int dhd_os_check_wakelock_all(dhd_pub_t *pub);
extern int dhd_get_instance(dhd_pub_t *pub);
#ifdef CUSTOM_SET_CPUCORE
extern void dhd_set_cpucore(dhd_pub_t *dhd, int set);
@@ -648,6 +680,10 @@
extern int dhd_keep_alive_onoff(dhd_pub_t *dhd);
#endif /* KEEP_ALIVE */
+#ifdef SUPPORT_AP_POWERSAVE
+extern int dhd_set_ap_powersave(dhd_pub_t *dhdp, int ifidx, int enable);
+#endif
+
#ifdef PKT_FILTER_SUPPORT
#define DHD_UNICAST_FILTER_NUM 0
@@ -656,10 +692,24 @@
#define DHD_MULTICAST6_FILTER_NUM 3
#define DHD_MDNS_FILTER_NUM 4
#define DHD_ARP_FILTER_NUM 5
-extern int dhd_os_enable_packet_filter(dhd_pub_t *dhdp, int val);
+
+#if defined(CUSTOM_PLATFORM_NV_TEGRA)
+/* Port based packet filtering command actions */
+#define PKT_FILTER_PORTS_CLEAR 0
+#define PKT_FILTER_PORTS_ADD 1
+#define PKT_FILTER_PORTS_DEL 2
+#define PKT_FILTER_PORTS_LOOPBACK 3
+#define PKT_FILTER_PORTS_MAX PKT_FILTER_PORTS_LOOPBACK
+#endif /* defined(CUSTOM_PLATFORM_NV_TEGRA) */
+
+extern int dhd_os_enable_packet_filter(dhd_pub_t *dhdp, int val);
extern void dhd_enable_packet_filter(int value, dhd_pub_t *dhd);
extern int net_os_enable_packet_filter(struct net_device *dev, int val);
extern int net_os_rxfilter_add_remove(struct net_device *dev, int val, int num);
+#if defined(CUSTOM_PLATFORM_NV_TEGRA)
+extern void dhd_set_packet_filter_mode(struct net_device *dev, char *command);
+extern int dhd_set_packet_filter_ports(struct net_device *dev, char *command);
+#endif /* defined(CUSTOM_PLATFORM_NV_TEGRA) */
#endif /* PKT_FILTER_SUPPORT */
extern int dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd);
@@ -776,6 +826,27 @@
/* Watchdog timer interval */
extern uint dhd_watchdog_ms;
+extern bool dhd_os_wd_timer_enabled(void *bus);
+
+#ifdef PKT_STATICS
+typedef struct pkt_statics {
+ uint16 event_count;
+ uint32 event_size;
+ uint16 ctrl_count;
+ uint32 ctrl_size;
+ uint32 data_count;
+ uint32 data_size;
+ uint16 glom_1_count;
+ uint16 glom_3_count;
+ uint16 glom_3_8_count;
+ uint16 glom_8_count;
+ uint16 glom_max;
+ uint16 glom_count;
+ uint32 glom_size;
+ uint16 test_count;
+ uint32 test_size;
+} pkt_statics_t;
+#endif
#if defined(DHD_DEBUG)
/* Console output poll interval */
@@ -897,7 +968,11 @@
#define WIFI_TURNON_DELAY DEFAULT_WIFI_TURNON_DELAY
#endif /* WIFI_TURNON_DELAY */
+#ifdef BCMSDIO
#define DEFAULT_DHD_WATCHDOG_INTERVAL_MS 10 /* msec */
+#else
+#define DEFAULT_DHD_WATCHDOG_INTERVAL_MS 0 /* msec */
+#endif
#ifndef CUSTOM_DHD_WATCHDOG_MS
#define CUSTOM_DHD_WATCHDOG_MS DEFAULT_DHD_WATCHDOG_INTERVAL_MS
#endif /* DEFAULT_DHD_WATCHDOG_INTERVAL_MS */
@@ -914,6 +989,10 @@
#endif
#endif /* WLTDLS */
+#define DEFAULT_BCN_TIMEOUT 8
+#ifndef CUSTOM_BCN_TIMEOUT
+#define CUSTOM_BCN_TIMEOUT DEFAULT_BCN_TIMEOUT
+#endif
#define MAX_DTIM_SKIP_BEACON_INTERVAL 100 /* max allowed associated AP beacon for DTIM skip */
#ifndef MAX_DTIM_ALLOWED_INTERVAL
@@ -1020,9 +1099,13 @@
#define DHD_GENERAL_UNLOCK(dhdp, flags) \
dhd_os_general_spin_unlock((dhdp), (flags))
-/* Enable DHD flowring queue spin lock/unlock */
-#define DHD_QUEUE_LOCK(lock, flags) (flags) = dhd_os_spin_lock(lock)
-#define DHD_QUEUE_UNLOCK(lock, flags) dhd_os_spin_unlock((lock), (flags))
+/* Enable DHD flowring spin lock/unlock */
+#define DHD_FLOWRING_LOCK(lock, flags) (flags) = dhd_os_spin_lock(lock)
+#define DHD_FLOWRING_UNLOCK(lock, flags) dhd_os_spin_unlock((lock), (flags))
+
+/* Enable DHD common flowring info spin lock/unlock */
+#define DHD_FLOWID_LOCK(lock, flags) (flags) = dhd_os_spin_lock(lock)
+#define DHD_FLOWID_UNLOCK(lock, flags) dhd_os_spin_unlock((lock), (flags))
@@ -1032,9 +1115,7 @@
} wl_io_pport_t;
extern void *dhd_pub_wlinfo(dhd_pub_t *dhd_pub);
-#ifdef EXYNOS5433_PCIE_WAR
-extern void exynos_pcie_set_l1_exit(void);
-extern void exynos_pcie_clear_l1_exit(void);
-extern int enum_wifi;
-#endif /* EXYNOS5433_PCIE_WAR */
+#ifdef CONFIG_MACH_UNIVERSAL5433
+extern int check_rev(void);
+#endif
#endif /* _dhd_h_ */
diff -Nur a/drivers/net/wireless/bcmdhd/dhd_ip.c c/drivers/net/wireless/bcmdhd/dhd_ip.c
--- a/drivers/net/wireless/bcmdhd/dhd_ip.c 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/dhd_ip.c 2016-05-13 09:48:20.000000000 +0200
@@ -3,7 +3,7 @@
*
* $Copyright Open Broadcom Corporation$
*
- * $Id: dhd_ip.c 468932 2014-04-09 06:58:15Z $
+ * $Id: dhd_ip.c 502735 2014-09-16 00:53:02Z $
*/
#include <typedefs.h>
#include <osl.h>
@@ -98,11 +98,79 @@
}
}
+bool pkt_is_dhcp(osl_t *osh, void *p)
+{
+ uint8 *frame;
+ int length;
+ uint8 *pt; /* Pointer to type field */
+ uint16 ethertype;
+ struct ipv4_hdr *iph; /* IP frame pointer */
+ int ipl; /* IP frame length */
+ uint16 src_port;
+
+ ASSERT(osh && p);
+
+ frame = PKTDATA(osh, p);
+ length = PKTLEN(osh, p);
+
+ /* Process Ethernet II or SNAP-encapsulated 802.3 frames */
+ if (length < ETHER_HDR_LEN) {
+ DHD_INFO(("%s: short eth frame (%d)\n", __FUNCTION__, length));
+ return FALSE;
+ } else if (ntoh16(*(uint16 *)(frame + ETHER_TYPE_OFFSET)) >= ETHER_TYPE_MIN) {
+ /* Frame is Ethernet II */
+ pt = frame + ETHER_TYPE_OFFSET;
+ } else if (length >= ETHER_HDR_LEN + SNAP_HDR_LEN + ETHER_TYPE_LEN &&
+ !bcmp(llc_snap_hdr, frame + ETHER_HDR_LEN, SNAP_HDR_LEN)) {
+ pt = frame + ETHER_HDR_LEN + SNAP_HDR_LEN;
+ } else {
+ DHD_INFO(("%s: non-SNAP 802.3 frame\n", __FUNCTION__));
+ return FALSE;
+ }
+
+ ethertype = ntoh16(*(uint16 *)pt);
+
+ /* Skip VLAN tag, if any */
+ if (ethertype == ETHER_TYPE_8021Q) {
+ pt += VLAN_TAG_LEN;
+
+ if (pt + ETHER_TYPE_LEN > frame + length) {
+ DHD_INFO(("%s: short VLAN frame (%d)\n", __FUNCTION__, length));
+ return FALSE;
+ }
+
+ ethertype = ntoh16(*(uint16 *)pt);
+ }
+
+ if (ethertype != ETHER_TYPE_IP) {
+ DHD_INFO(("%s: non-IP frame (ethertype 0x%x, length %d)\n",
+ __FUNCTION__, ethertype, length));
+ return FALSE;
+ }
+
+ iph = (struct ipv4_hdr *)(pt + ETHER_TYPE_LEN);
+ ipl = (uint)(length - (pt + ETHER_TYPE_LEN - frame));
+
+ /* We support IPv4 only */
+ if ((ipl < (IPV4_OPTIONS_OFFSET + 2)) || (IP_VER(iph) != IP_VER_4)) {
+ DHD_INFO(("%s: short frame (%d) or non-IPv4\n", __FUNCTION__, ipl));
+ return FALSE;
+ }
+
+ src_port = ntoh16(*(uint16 *)(pt + ETHER_TYPE_LEN + IPV4_OPTIONS_OFFSET));
+
+ return (src_port == 0x43 || src_port == 0x44);
+}
+
#ifdef DHDTCPACK_SUPPRESS
typedef struct {
- void *pkt_in_q; /* TCP ACK packet that is already in txq or DelayQ */
+ void *pkt_in_q; /* TCP ACK packet that is already in txq or DelayQ */
void *pkt_ether_hdr; /* Ethernet header pointer of pkt_in_q */
+ int ifidx;
+ uint8 supp_cnt;
+ dhd_pub_t *dhdp;
+ struct timer_list timer;
} tcpack_info_t;
typedef struct _tdata_psh_info_t {
@@ -258,6 +326,46 @@
return;
}
+static void dhd_tcpack_send(ulong data)
+{
+ tcpack_sup_module_t *tcpack_sup_mod;
+ tcpack_info_t *cur_tbl = (tcpack_info_t *)data;
+ dhd_pub_t *dhdp;
+ int ifidx;
+ void* pkt;
+
+ if (!cur_tbl) {
+ return;
+ }
+
+ dhdp = cur_tbl->dhdp;
+ if (!dhdp) {
+ return;
+ }
+
+ dhd_os_tcpacklock(dhdp);
+
+ tcpack_sup_mod = dhdp->tcpack_sup_module;
+ pkt = cur_tbl->pkt_in_q;
+ ifidx = cur_tbl->ifidx;
+ if (!pkt) {
+ dhd_os_tcpackunlock(dhdp);
+ return;
+ }
+ cur_tbl->pkt_in_q = NULL;
+ cur_tbl->pkt_ether_hdr = NULL;
+ cur_tbl->ifidx = 0;
+ cur_tbl->supp_cnt = 0;
+ if (--tcpack_sup_mod->tcpack_info_cnt < 0) {
+ DHD_ERROR(("%s %d: ERROR!!! tcp_ack_info_cnt %d\n",
+ __FUNCTION__, __LINE__, tcpack_sup_mod->tcpack_info_cnt));
+ }
+
+ dhd_os_tcpackunlock(dhdp);
+
+ dhd_sendpkt(dhdp, ifidx, pkt);
+}
+
int dhd_tcpack_suppress_set(dhd_pub_t *dhdp, uint8 mode)
{
int ret = BCME_OK;
@@ -325,6 +433,22 @@
dhd_bus_set_dotxinrx(dhdp->bus, FALSE);
}
+ if (mode == TCPACK_SUP_HOLD) {
+ int i;
+ tcpack_sup_module_t *tcpack_sup_mod =
+ (tcpack_sup_module_t *)dhdp->tcpack_sup_module;
+ dhdp->tcpack_sup_ratio = TCPACK_SUPP_RATIO;
+ dhdp->tcpack_sup_delay = TCPACK_DELAY_TIME;
+ for (i = 0; i < TCPACK_INFO_MAXNUM; i++)
+ {
+ tcpack_sup_mod->tcpack_info_tbl[i].dhdp = dhdp;
+ init_timer(&tcpack_sup_mod->tcpack_info_tbl[i].timer);
+ tcpack_sup_mod->tcpack_info_tbl[i].timer.data =
+ (ulong)&tcpack_sup_mod->tcpack_info_tbl[i];
+ tcpack_sup_mod->tcpack_info_tbl[i].timer.function = dhd_tcpack_send;
+ }
+ }
+
exit:
dhd_os_tcpackunlock(dhdp);
return ret;
@@ -334,6 +458,7 @@
dhd_tcpack_info_tbl_clean(dhd_pub_t *dhdp)
{
tcpack_sup_module_t *tcpack_sup_mod = dhdp->tcpack_sup_module;
+ int i;
if (dhdp->tcpack_sup_mode == TCPACK_SUP_OFF)
goto exit;
@@ -347,10 +472,30 @@
goto exit;
}
- tcpack_sup_mod->tcpack_info_cnt = 0;
- bzero(tcpack_sup_mod->tcpack_info_tbl, sizeof(tcpack_info_t) * TCPACK_INFO_MAXNUM);
+ if (dhdp->tcpack_sup_mode == TCPACK_SUP_HOLD) {
+ for (i = 0; i < TCPACK_INFO_MAXNUM; i++) {
+ if (tcpack_sup_mod->tcpack_info_tbl[i].pkt_in_q) {
+ PKTFREE(dhdp->osh, tcpack_sup_mod->tcpack_info_tbl[i].pkt_in_q,
+ TRUE);
+ tcpack_sup_mod->tcpack_info_tbl[i].pkt_in_q = NULL;
+ tcpack_sup_mod->tcpack_info_tbl[i].pkt_ether_hdr = NULL;
+ tcpack_sup_mod->tcpack_info_tbl[i].ifidx = 0;
+ tcpack_sup_mod->tcpack_info_tbl[i].supp_cnt = 0;
+ }
+ }
+ } else {
+ tcpack_sup_mod->tcpack_info_cnt = 0;
+ bzero(tcpack_sup_mod->tcpack_info_tbl, sizeof(tcpack_info_t) * TCPACK_INFO_MAXNUM);
+ }
+
dhd_os_tcpackunlock(dhdp);
+ if (dhdp->tcpack_sup_mode == TCPACK_SUP_HOLD) {
+ for (i = 0; i < TCPACK_INFO_MAXNUM; i++) {
+ del_timer_sync(&tcpack_sup_mod->tcpack_info_tbl[i].timer);
+ }
+ }
+
exit:
return;
}
@@ -854,7 +999,7 @@
bcopy(last_tdata_info, tdata_info_tmp, sizeof(tcpdata_info_t));
}
bzero(last_tdata_info, sizeof(tcpdata_info_t));
- DHD_TRACE(("%s %d: tcpdata_info(idx %d) is aged out. ttl cnt is now %d\n",
+ DHD_ERROR(("%s %d: tcpdata_info(idx %d) is aged out. ttl cnt is now %d\n",
__FUNCTION__, __LINE__, i, tcpack_sup_mod->tcpdata_info_cnt));
/* Don't increase "i" here, so that the prev last tcpdata_info is checked */
} else
@@ -883,7 +1028,7 @@
/* No TCP flow with the same IP addr and TCP port is found
* in tcp_data_info_tbl. So add this flow to the table.
*/
- DHD_TRACE(("%s %d: Add data info to tbl[%d]: IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR
+ DHD_ERROR(("%s %d: Add data info to tbl[%d]: IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR
" TCP port %d %d\n",
__FUNCTION__, __LINE__, tcpack_sup_mod->tcpdata_info_cnt,
IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_SRC_IP_OFFSET])),
@@ -939,4 +1084,202 @@
return ret;
}
+bool
+dhd_tcpack_hold(dhd_pub_t *dhdp, void *pkt, int ifidx)
+{
+ uint8 *new_ether_hdr; /* Ethernet header of the new packet */
+ uint16 new_ether_type; /* Ethernet type of the new packet */
+ uint8 *new_ip_hdr; /* IP header of the new packet */
+ uint8 *new_tcp_hdr; /* TCP header of the new packet */
+ uint32 new_ip_hdr_len; /* IP header length of the new packet */
+ uint32 cur_framelen;
+ uint32 new_tcp_ack_num; /* TCP acknowledge number of the new packet */
+ uint16 new_ip_total_len; /* Total length of IP packet for the new packet */
+ uint32 new_tcp_hdr_len; /* TCP header length of the new packet */
+ tcpack_sup_module_t *tcpack_sup_mod;
+ tcpack_info_t *tcpack_info_tbl;
+ int i, free_slot = TCPACK_INFO_MAXNUM;
+ bool hold = FALSE;
+
+ if (dhdp->tcpack_sup_mode != TCPACK_SUP_HOLD) {
+ goto exit;
+ }
+
+ if (dhdp->tcpack_sup_ratio == 1) {
+ goto exit;
+ }
+
+ new_ether_hdr = PKTDATA(dhdp->osh, pkt);
+ cur_framelen = PKTLEN(dhdp->osh, pkt);
+
+ if (cur_framelen < TCPACKSZMIN || cur_framelen > TCPACKSZMAX) {
+ DHD_TRACE(("%s %d: Too short or long length %d to be TCP ACK\n",
+ __FUNCTION__, __LINE__, cur_framelen));
+ goto exit;
+ }
+
+ new_ether_type = new_ether_hdr[12] << 8 | new_ether_hdr[13];
+
+ if (new_ether_type != ETHER_TYPE_IP) {
+ DHD_TRACE(("%s %d: Not a IP packet 0x%x\n",
+ __FUNCTION__, __LINE__, new_ether_type));
+ goto exit;
+ }
+
+ DHD_TRACE(("%s %d: IP pkt! 0x%x\n", __FUNCTION__, __LINE__, new_ether_type));
+
+ new_ip_hdr = new_ether_hdr + ETHER_HDR_LEN;
+ cur_framelen -= ETHER_HDR_LEN;
+
+ ASSERT(cur_framelen >= IPV4_MIN_HEADER_LEN);
+
+ new_ip_hdr_len = IPV4_HLEN(new_ip_hdr);
+ if (IP_VER(new_ip_hdr) != IP_VER_4 || IPV4_PROT(new_ip_hdr) != IP_PROT_TCP) {
+ DHD_TRACE(("%s %d: Not IPv4 nor TCP! ip ver %d, prot %d\n",
+ __FUNCTION__, __LINE__, IP_VER(new_ip_hdr), IPV4_PROT(new_ip_hdr)));
+ goto exit;
+ }
+
+ new_tcp_hdr = new_ip_hdr + new_ip_hdr_len;
+ cur_framelen -= new_ip_hdr_len;
+
+ ASSERT(cur_framelen >= TCP_MIN_HEADER_LEN);
+
+ DHD_TRACE(("%s %d: TCP pkt!\n", __FUNCTION__, __LINE__));
+
+ /* is it an ack ? Allow only ACK flag, not to suppress others. */
+ if (new_tcp_hdr[TCP_FLAGS_OFFSET] != TCP_FLAG_ACK) {
+ DHD_TRACE(("%s %d: Do not touch TCP flag 0x%x\n",
+ __FUNCTION__, __LINE__, new_tcp_hdr[TCP_FLAGS_OFFSET]));
+ goto exit;
+ }
+
+ new_ip_total_len = ntoh16_ua(&new_ip_hdr[IPV4_PKTLEN_OFFSET]);
+ new_tcp_hdr_len = 4 * TCP_HDRLEN(new_tcp_hdr[TCP_HLEN_OFFSET]);
+
+ /* This packet has TCP data, so just send */
+ if (new_ip_total_len > new_ip_hdr_len + new_tcp_hdr_len) {
+ DHD_TRACE(("%s %d: Do nothing for TCP DATA\n", __FUNCTION__, __LINE__));
+ goto exit;
+ }
+
+ ASSERT(new_ip_total_len == new_ip_hdr_len + new_tcp_hdr_len);
+
+ new_tcp_ack_num = ntoh32_ua(&new_tcp_hdr[TCP_ACK_NUM_OFFSET]);
+
+ DHD_TRACE(("%s %d: TCP ACK with zero DATA length"
+ " IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR" TCP port %d %d\n",
+ __FUNCTION__, __LINE__,
+ IPV4_ADDR_TO_STR(ntoh32_ua(&new_ip_hdr[IPV4_SRC_IP_OFFSET])),
+ IPV4_ADDR_TO_STR(ntoh32_ua(&new_ip_hdr[IPV4_DEST_IP_OFFSET])),
+ ntoh16_ua(&new_tcp_hdr[TCP_SRC_PORT_OFFSET]),
+ ntoh16_ua(&new_tcp_hdr[TCP_DEST_PORT_OFFSET])));
+
+ /* Look for tcp_ack_info that has the same ip src/dst addrs and tcp src/dst ports */
+ dhd_os_tcpacklock(dhdp);
+
+ tcpack_sup_mod = dhdp->tcpack_sup_module;
+ tcpack_info_tbl = tcpack_sup_mod->tcpack_info_tbl;
+
+ if (!tcpack_sup_mod) {
+ DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__, __LINE__));
+ dhd_os_tcpackunlock(dhdp);
+ goto exit;
+ }
+
+ hold = TRUE;
+
+ for (i = 0; i < TCPACK_INFO_MAXNUM; i++) {
+ void *oldpkt; /* TCPACK packet that is already in txq or DelayQ */
+ uint8 *old_ether_hdr, *old_ip_hdr, *old_tcp_hdr;
+ uint32 old_ip_hdr_len, old_tcp_hdr_len;
+ uint32 old_tcpack_num; /* TCP ACK number of old TCPACK packet in Q */
+
+ if ((oldpkt = tcpack_info_tbl[i].pkt_in_q) == NULL) {
+ if (free_slot == TCPACK_INFO_MAXNUM) {
+ free_slot = i;
+ }
+ continue;
+ }
+
+ if (PKTDATA(dhdp->osh, oldpkt) == NULL) {
+ DHD_ERROR(("%s %d: oldpkt data NULL!! cur idx %d\n",
+ __FUNCTION__, __LINE__, i));
+ hold = FALSE;
+ dhd_os_tcpackunlock(dhdp);
+ goto exit;
+ }
+
+ old_ether_hdr = tcpack_info_tbl[i].pkt_ether_hdr;
+ old_ip_hdr = old_ether_hdr + ETHER_HDR_LEN;
+ old_ip_hdr_len = IPV4_HLEN(old_ip_hdr);
+ old_tcp_hdr = old_ip_hdr + old_ip_hdr_len;
+ old_tcp_hdr_len = 4 * TCP_HDRLEN(old_tcp_hdr[TCP_HLEN_OFFSET]);
+
+ DHD_TRACE(("%s %d: oldpkt %p[%d], IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR
+ " TCP port %d %d\n", __FUNCTION__, __LINE__, oldpkt, i,
+ IPV4_ADDR_TO_STR(ntoh32_ua(&old_ip_hdr[IPV4_SRC_IP_OFFSET])),
+ IPV4_ADDR_TO_STR(ntoh32_ua(&old_ip_hdr[IPV4_DEST_IP_OFFSET])),
+ ntoh16_ua(&old_tcp_hdr[TCP_SRC_PORT_OFFSET]),
+ ntoh16_ua(&old_tcp_hdr[TCP_DEST_PORT_OFFSET])));
+
+ /* If either of IP address or TCP port number does not match, skip. */
+ if (memcmp(&new_ip_hdr[IPV4_SRC_IP_OFFSET],
+ &old_ip_hdr[IPV4_SRC_IP_OFFSET], IPV4_ADDR_LEN * 2) ||
+ memcmp(&new_tcp_hdr[TCP_SRC_PORT_OFFSET],
+ &old_tcp_hdr[TCP_SRC_PORT_OFFSET], TCP_PORT_LEN * 2)) {
+ continue;
+ }
+
+ old_tcpack_num = ntoh32_ua(&old_tcp_hdr[TCP_ACK_NUM_OFFSET]);
+
+ if (IS_TCPSEQ_GE(new_tcp_ack_num, old_tcpack_num)) {
+ tcpack_info_tbl[i].supp_cnt++;
+ if (tcpack_info_tbl[i].supp_cnt >= dhdp->tcpack_sup_ratio) {
+ tcpack_info_tbl[i].pkt_in_q = NULL;
+ tcpack_info_tbl[i].pkt_ether_hdr = NULL;
+ tcpack_info_tbl[i].ifidx = 0;
+ tcpack_info_tbl[i].supp_cnt = 0;
+ hold = FALSE;
+ } else {
+ tcpack_info_tbl[i].pkt_in_q = pkt;
+ tcpack_info_tbl[i].pkt_ether_hdr = new_ether_hdr;
+ tcpack_info_tbl[i].ifidx = ifidx;
+ }
+ PKTFREE(dhdp->osh, oldpkt, TRUE);
+ } else {
+ PKTFREE(dhdp->osh, pkt, TRUE);
+ }
+ dhd_os_tcpackunlock(dhdp);
+
+ if (!hold) {
+ del_timer_sync(&tcpack_info_tbl[i].timer);
+ }
+ goto exit;
+ }
+
+ if (free_slot < TCPACK_INFO_MAXNUM) {
+ /* No TCPACK packet with the same IP addr and TCP port is found
+ * in tcp_ack_info_tbl. So add this packet to the table.
+ */
+ DHD_TRACE(("%s %d: Add pkt 0x%p(ether_hdr 0x%p) to tbl[%d]\n",
+ __FUNCTION__, __LINE__, pkt, new_ether_hdr,
+ free_slot));
+
+ tcpack_info_tbl[free_slot].pkt_in_q = pkt;
+ tcpack_info_tbl[free_slot].pkt_ether_hdr = new_ether_hdr;
+ tcpack_info_tbl[free_slot].ifidx = ifidx;
+ tcpack_info_tbl[free_slot].supp_cnt = 1;
+ mod_timer(&tcpack_sup_mod->tcpack_info_tbl[free_slot].timer,
+ jiffies + msecs_to_jiffies(dhdp->tcpack_sup_delay));
+ tcpack_sup_mod->tcpack_info_cnt++;
+ } else {
+ DHD_TRACE(("%s %d: No empty tcp ack info tbl\n",
+ __FUNCTION__, __LINE__));
+ }
+ dhd_os_tcpackunlock(dhdp);
+
+exit:
+ return hold;
+}
#endif /* DHDTCPACK_SUPPRESS */
diff -Nur a/drivers/net/wireless/bcmdhd/dhd_ip.h c/drivers/net/wireless/bcmdhd/dhd_ip.h
--- a/drivers/net/wireless/bcmdhd/dhd_ip.h 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/dhd_ip.h 2016-05-13 09:48:20.000000000 +0200
@@ -5,7 +5,7 @@
*
* $Copyright Open Broadcom Corporation$
*
- * $Id: dhd_ip.h 458522 2014-02-27 02:26:15Z $
+ * $Id: dhd_ip.h 502735 2014-09-16 00:53:02Z $
*/
#ifndef _dhd_ip_h_
@@ -26,6 +26,7 @@
} pkt_frag_t;
extern pkt_frag_t pkt_frag_info(osl_t *osh, void *p);
+extern bool pkt_is_dhcp(osl_t *osh, void *p);
#ifdef DHDTCPACK_SUPPRESS
#define TCPACKSZMIN (ETHER_HDR_LEN + IPV4_MIN_HEADER_LEN + TCP_MIN_HEADER_LEN)
@@ -39,12 +40,15 @@
#define TCPDATA_INFO_TIMEOUT 5000 /* Remove tcpdata_info if inactive for this time (in ms) */
+#define TCPACK_SUPP_RATIO 3
+#define TCPACK_DELAY_TIME 10 /* ms */
+
extern int dhd_tcpack_suppress_set(dhd_pub_t *dhdp, uint8 on);
extern void dhd_tcpack_info_tbl_clean(dhd_pub_t *dhdp);
extern int dhd_tcpack_check_xmit(dhd_pub_t *dhdp, void *pkt);
extern bool dhd_tcpack_suppress(dhd_pub_t *dhdp, void *pkt);
extern bool dhd_tcpdata_info_get(dhd_pub_t *dhdp, void *pkt);
-
+extern bool dhd_tcpack_hold(dhd_pub_t *dhdp, void *pkt, int ifidx);
/* #define DHDTCPACK_SUP_DBG */
#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG)
extern counter_tbl_t tack_tbl;
diff -Nur a/drivers/net/wireless/bcmdhd/dhd_linux.c c/drivers/net/wireless/bcmdhd/dhd_linux.c
--- a/drivers/net/wireless/bcmdhd/dhd_linux.c 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/dhd_linux.c 2016-09-30 00:05:56.001097833 +0200
@@ -1,9302 +1,10391 @@
-/*
- * Broadcom Dongle Host Driver (DHD), Linux-specific network interface
- * Basically selected code segments from usb-cdc.c and usb-rndis.c
- *
- * $Copyright Open Broadcom Corporation$
- *
- * $Id: dhd_linux.c 491481 2014-07-16 14:08:43Z $
- */
-
-#include <typedefs.h>
-#include <linuxver.h>
-#include <osl.h>
-#ifdef SHOW_LOGTRACE
-#include <linux/syscalls.h>
-#include <event_log.h>
-#endif /* SHOW_LOGTRACE */
-
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/inetdevice.h>
-#include <linux/rtnetlink.h>
-#include <linux/etherdevice.h>
-#include <linux/random.h>
-#include <linux/spinlock.h>
-#include <linux/ethtool.h>
-#include <linux/fcntl.h>
-#include <linux/fs.h>
-#include <linux/ip.h>
-#include <linux/reboot.h>
-#include <linux/notifier.h>
-#include <net/addrconf.h>
-#ifdef ENABLE_ADAPTIVE_SCHED
-#include <linux/cpufreq.h>
-#endif /* ENABLE_ADAPTIVE_SCHED */
-
-#include <asm/uaccess.h>
-#include <asm/unaligned.h>
-
-#include <epivers.h>
-#include <bcmutils.h>
-#include <bcmendian.h>
-#include <bcmdevs.h>
-
-#include <proto/ethernet.h>
-#include <proto/bcmevent.h>
-#include <proto/vlan.h>
-#include <proto/bcmudp.h>
-#include <proto/bcmdhcp.h>
-#ifdef DHD_L2_FILTER
-#include <proto/bcmicmp.h>
-#endif
-#include <proto/802.3.h>
-
-#include <dngl_stats.h>
-#include <dhd_linux_wq.h>
-#include <dhd.h>
-#include <dhd_linux.h>
-#ifdef PCIE_FULL_DONGLE
-#include <dhd_flowring.h>
-#endif
-#include <dhd_bus.h>
-#include <dhd_proto.h>
-#include <dhd_config.h>
-#include <dhd_dbg.h>
-#ifdef CONFIG_HAS_WAKELOCK
-#include <linux/wakelock.h>
-#endif
-#ifdef WL_CFG80211
-#include <wl_cfg80211.h>
-#endif
-#ifdef PNO_SUPPORT
-#include <dhd_pno.h>
-#endif
-#ifdef WLBTAMP
-#include <proto/802.11_bta.h>
-#include <proto/bt_amp_hci.h>
-#include <dhd_bta.h>
-#endif
-
-#ifdef CONFIG_COMPAT
-#include <linux/compat.h>
-#endif
-
-#ifdef DHD_WMF
-#include <dhd_wmf_linux.h>
-#endif /* DHD_WMF */
-
-#ifdef AMPDU_VO_ENABLE
-#include <proto/802.1d.h>
-#endif /* AMPDU_VO_ENABLE */
-#ifdef DHDTCPACK_SUPPRESS
-#include <dhd_ip.h>
-#endif /* DHDTCPACK_SUPPRESS */
-
-#if defined(DHD_TCP_WINSIZE_ADJUST)
-#include <linux/tcp.h>
-#include <net/tcp.h>
-#endif /* DHD_TCP_WINSIZE_ADJUST */
-
-#ifdef WLMEDIA_HTSF
-#include <linux/time.h>
-#include <htsf.h>
-
-#define HTSF_MINLEN 200 /* min. packet length to timestamp */
-#define HTSF_BUS_DELAY 150 /* assume a fix propagation in us */
-#define TSMAX 1000 /* max no. of timing record kept */
-#define NUMBIN 34
-
-static uint32 tsidx = 0;
-static uint32 htsf_seqnum = 0;
-uint32 tsfsync;
-struct timeval tsync;
-static uint32 tsport = 5010;
-
-typedef struct histo_ {
- uint32 bin[NUMBIN];
-} histo_t;
-
-#if !ISPOWEROF2(DHD_SDALIGN)
-#error DHD_SDALIGN is not a power of 2!
-#endif
-
-static histo_t vi_d1, vi_d2, vi_d3, vi_d4;
-#endif /* WLMEDIA_HTSF */
-
-#if defined(DHD_TCP_WINSIZE_ADJUST)
-#define MIN_TCP_WIN_SIZE 18000
-#define WIN_SIZE_SCALE_FACTOR 2
-#define MAX_TARGET_PORTS 5
-
-static uint target_ports[MAX_TARGET_PORTS] = {20, 0, 0, 0, 0};
-static uint dhd_use_tcp_window_size_adjust = FALSE;
-static void dhd_adjust_tcp_winsize(int op_mode, struct sk_buff *skb);
-#endif /* DHD_TCP_WINSIZE_ADJUST */
-
-
-#if defined(SOFTAP)
-extern bool ap_cfg_running;
-extern bool ap_fw_loaded;
-#endif
-
-
-#ifdef ENABLE_ADAPTIVE_SCHED
-#define DEFAULT_CPUFREQ_THRESH 1000000 /* threshold frequency : 1000000 = 1GHz */
-#ifndef CUSTOM_CPUFREQ_THRESH
-#define CUSTOM_CPUFREQ_THRESH DEFAULT_CPUFREQ_THRESH
-#endif /* CUSTOM_CPUFREQ_THRESH */
-#endif /* ENABLE_ADAPTIVE_SCHED */
-
-/* enable HOSTIP cache update from the host side when an eth0:N is up */
-#define AOE_IP_ALIAS_SUPPORT 1
-
-#ifdef BCM_FD_AGGR
-#include <bcm_rpc.h>
-#include <bcm_rpc_tp.h>
-#endif
-#ifdef PROP_TXSTATUS
-#include <wlfc_proto.h>
-#include <dhd_wlfc.h>
-#endif
-
-#include <wl_android.h>
-
-/* Maximum STA per radio */
-#define DHD_MAX_STA 32
-
-
-const uint8 wme_fifo2ac[] = { 0, 1, 2, 3, 1, 1 };
-const uint8 prio2fifo[8] = { 1, 0, 0, 1, 2, 2, 3, 3 };
-#define WME_PRIO2AC(prio) wme_fifo2ac[prio2fifo[(prio)]]
-
-#ifdef ARP_OFFLOAD_SUPPORT
-void aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add, int idx);
-static int dhd_inetaddr_notifier_call(struct notifier_block *this,
- unsigned long event, void *ptr);
-static struct notifier_block dhd_inetaddr_notifier = {
- .notifier_call = dhd_inetaddr_notifier_call
-};
-/* to make sure we won't register the same notifier twice, otherwise a loop is likely to be
- * created in kernel notifier link list (with 'next' pointing to itself)
- */
-static bool dhd_inetaddr_notifier_registered = FALSE;
-#endif /* ARP_OFFLOAD_SUPPORT */
-
-#ifdef CONFIG_IPV6
-static int dhd_inet6addr_notifier_call(struct notifier_block *this,
- unsigned long event, void *ptr);
-static struct notifier_block dhd_inet6addr_notifier = {
- .notifier_call = dhd_inet6addr_notifier_call
-};
-/* to make sure we won't register the same notifier twice, otherwise a loop is likely to be
- * created in kernel notifier link list (with 'next' pointing to itself)
- */
-static bool dhd_inet6addr_notifier_registered = FALSE;
-#endif
-
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP)
-#include <linux/suspend.h>
-volatile bool dhd_mmc_suspend = FALSE;
-DECLARE_WAIT_QUEUE_HEAD(dhd_dpc_wait);
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */
-
-#if defined(OOB_INTR_ONLY)
-extern void dhd_enable_oob_intr(struct dhd_bus *bus, bool enable);
-#endif
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (1)
-static void dhd_hang_process(void *dhd_info, void *event_data, u8 event);
-#endif
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
-MODULE_LICENSE("GPL v2");
-#endif /* LinuxVer */
-
-#include <dhd_bus.h>
-
-#ifdef BCM_FD_AGGR
-#define DBUS_RX_BUFFER_SIZE_DHD(net) (BCM_RPC_TP_DNGL_AGG_MAX_BYTE)
-#else
-#ifndef PROP_TXSTATUS
-#define DBUS_RX_BUFFER_SIZE_DHD(net) (net->mtu + net->hard_header_len + dhd->pub.hdrlen)
-#else
-#define DBUS_RX_BUFFER_SIZE_DHD(net) (net->mtu + net->hard_header_len + dhd->pub.hdrlen + 128)
-#endif
-#endif /* BCM_FD_AGGR */
-
-#ifdef PROP_TXSTATUS
-extern bool dhd_wlfc_skip_fc(void);
-extern void dhd_wlfc_plat_init(void *dhd);
-extern void dhd_wlfc_plat_deinit(void *dhd);
-#endif /* PROP_TXSTATUS */
-
-#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15)
-const char *
-print_tainted()
-{
- return "";
-}
-#endif /* LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15) */
-
-/* Linux wireless extension support */
-#if defined(WL_WIRELESS_EXT)
-#include <wl_iw.h>
-extern wl_iw_extra_params_t g_wl_iw_params;
-#endif /* defined(WL_WIRELESS_EXT) */
-
-#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
-#include <linux/earlysuspend.h>
-#endif /* defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) */
-
-extern int dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd);
-
-#ifdef PKT_FILTER_SUPPORT
-extern void dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg);
-extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode);
-extern void dhd_pktfilter_offload_delete(dhd_pub_t *dhd, int id);
-#endif
-
-
-#ifdef READ_MACADDR
-extern int dhd_read_macaddr(struct dhd_info *dhd);
-#else
-static inline int dhd_read_macaddr(struct dhd_info *dhd) { return 0; }
-#endif
-#ifdef WRITE_MACADDR
-extern int dhd_write_macaddr(struct ether_addr *mac);
-#else
-static inline int dhd_write_macaddr(struct ether_addr *mac) { return 0; }
-#endif
-
-#if defined(SOFTAP_TPUT_ENHANCE)
-extern void dhd_bus_setidletime(dhd_pub_t *dhdp, int idle_time);
-extern void dhd_bus_getidletime(dhd_pub_t *dhdp, int* idle_time);
-#endif /* SOFTAP_TPUT_ENHANCE */
-
-
-static int dhd_reboot_callback(struct notifier_block *this, unsigned long code, void *unused);
-static struct notifier_block dhd_reboot_notifier = {
- .notifier_call = dhd_reboot_callback,
- .priority = 1,
-};
-
-
-typedef struct dhd_if_event {
- struct list_head list;
- wl_event_data_if_t event;
- char name[IFNAMSIZ+1];
- uint8 mac[ETHER_ADDR_LEN];
-} dhd_if_event_t;
-
-/* Interface control information */
-typedef struct dhd_if {
- struct dhd_info *info; /* back pointer to dhd_info */
- /* OS/stack specifics */
- struct net_device *net;
- int idx; /* iface idx in dongle */
- uint subunit; /* subunit */
- uint8 mac_addr[ETHER_ADDR_LEN]; /* assigned MAC address */
- bool set_macaddress;
- bool set_multicast;
- uint8 bssidx; /* bsscfg index for the interface */
- bool attached; /* Delayed attachment when unset */
- bool txflowcontrol; /* Per interface flow control indicator */
- char name[IFNAMSIZ+1]; /* linux interface name */
- struct net_device_stats stats;
-#ifdef DHD_WMF
- dhd_wmf_t wmf; /* per bsscfg wmf setting */
-#endif /* DHD_WMF */
-#ifdef PCIE_FULL_DONGLE
- struct list_head sta_list; /* sll of associated stations */
-#if !defined(BCM_GMAC3)
- spinlock_t sta_list_lock; /* lock for manipulating sll */
-#endif /* ! BCM_GMAC3 */
-#endif /* PCIE_FULL_DONGLE */
- uint32 ap_isolate; /* ap-isolation settings */
-} dhd_if_t;
-
-#ifdef WLMEDIA_HTSF
-typedef struct {
- uint32 low;
- uint32 high;
-} tsf_t;
-
-typedef struct {
- uint32 last_cycle;
- uint32 last_sec;
- uint32 last_tsf;
- uint32 coef; /* scaling factor */
- uint32 coefdec1; /* first decimal */
- uint32 coefdec2; /* second decimal */
-} htsf_t;
-
-typedef struct {
- uint32 t1;
- uint32 t2;
- uint32 t3;
- uint32 t4;
-} tstamp_t;
-
-static tstamp_t ts[TSMAX];
-static tstamp_t maxdelayts;
-static uint32 maxdelay = 0, tspktcnt = 0, maxdelaypktno = 0;
-
-#endif /* WLMEDIA_HTSF */
-
-struct ipv6_work_info_t {
- uint8 if_idx;
- char ipv6_addr[16];
- unsigned long event;
-};
-
-/* When Perimeter locks are deployed, any blocking calls must be preceeded
- * with a PERIM UNLOCK and followed by a PERIM LOCK.
- * Examples of blocking calls are: schedule_timeout(), down_interruptible(),
- * wait_event_timeout().
- */
-
-/* Local private structure (extension of pub) */
-typedef struct dhd_info {
-#if defined(WL_WIRELESS_EXT)
- wl_iw_t iw; /* wireless extensions state (must be first) */
-#endif /* defined(WL_WIRELESS_EXT) */
- dhd_pub_t pub;
- dhd_if_t *iflist[DHD_MAX_IFS]; /* for supporting multiple interfaces */
-
- void *adapter; /* adapter information, interrupt, fw path etc. */
- char fw_path[PATH_MAX]; /* path to firmware image */
- char nv_path[PATH_MAX]; /* path to nvram vars file */
- char conf_path[PATH_MAX]; /* path to config vars file */
-
- struct semaphore proto_sem;
-#ifdef PROP_TXSTATUS
- spinlock_t wlfc_spinlock;
-
-#endif /* PROP_TXSTATUS */
-#ifdef WLMEDIA_HTSF
- htsf_t htsf;
-#endif
- wait_queue_head_t ioctl_resp_wait;
- uint32 default_wd_interval;
-
- struct timer_list timer;
- bool wd_timer_valid;
- struct tasklet_struct tasklet;
- spinlock_t sdlock;
- spinlock_t txqlock;
- spinlock_t dhd_lock;
-
- struct semaphore sdsem;
- tsk_ctl_t thr_dpc_ctl;
- tsk_ctl_t thr_wdt_ctl;
-
- tsk_ctl_t thr_rxf_ctl;
- spinlock_t rxf_lock;
- bool rxthread_enabled;
-
- /* Wakelocks */
-#if defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
- struct wake_lock wl_wifi; /* Wifi wakelock */
- struct wake_lock wl_rxwake; /* Wifi rx wakelock */
- struct wake_lock wl_ctrlwake; /* Wifi ctrl wakelock */
- struct wake_lock wl_wdwake; /* Wifi wd wakelock */
-#endif
-
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1
- /* net_device interface lock, prevent race conditions among net_dev interface
- * calls and wifi_on or wifi_off
- */
- struct mutex dhd_net_if_mutex;
- struct mutex dhd_suspend_mutex;
-#endif
- spinlock_t wakelock_spinlock;
- uint32 wakelock_counter;
- int wakelock_wd_counter;
- int wakelock_rx_timeout_enable;
- int wakelock_ctrl_timeout_enable;
- bool waive_wakelock;
- uint32 wakelock_before_waive;
-
- /* Thread to issue ioctl for multicast */
- wait_queue_head_t ctrl_wait;
- atomic_t pend_8021x_cnt;
- dhd_attach_states_t dhd_state;
-#ifdef SHOW_LOGTRACE
- dhd_event_log_t event_data;
-#endif /* SHOW_LOGTRACE */
-
-#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
- struct early_suspend early_suspend;
-#endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */
-
-#ifdef ARP_OFFLOAD_SUPPORT
- u32 pend_ipaddr;
-#endif /* ARP_OFFLOAD_SUPPORT */
-#ifdef BCM_FD_AGGR
- void *rpc_th;
- void *rpc_osh;
- struct timer_list rpcth_timer;
- bool rpcth_timer_active;
- bool fdaggr;
-#endif
-#ifdef DHDTCPACK_SUPPRESS
- spinlock_t tcpack_lock;
-#endif /* DHDTCPACK_SUPPRESS */
- void *dhd_deferred_wq;
-#ifdef DEBUG_CPU_FREQ
- struct notifier_block freq_trans;
- int __percpu *new_freq;
-#endif
- unsigned int unit;
- struct notifier_block pm_notifier;
-} dhd_info_t;
-
-#define DHDIF_FWDER(dhdif) FALSE
-
-/* Flag to indicate if we should download firmware on driver load */
-uint dhd_download_fw_on_driverload = TRUE;
-
-/* Definitions to provide path to the firmware and nvram
- * example nvram_path[MOD_PARAM_PATHLEN]="/projects/wlan/nvram.txt"
- */
-char firmware_path[MOD_PARAM_PATHLEN];
-char nvram_path[MOD_PARAM_PATHLEN];
-char config_path[MOD_PARAM_PATHLEN];
-
-/* backup buffer for firmware and nvram path */
-char fw_bak_path[MOD_PARAM_PATHLEN];
-char nv_bak_path[MOD_PARAM_PATHLEN];
-
-/* information string to keep firmware, chio, cheip version info visiable from log */
-char info_string[MOD_PARAM_INFOLEN];
-module_param_string(info_string, info_string, MOD_PARAM_INFOLEN, 0444);
-int op_mode = 0;
-int disable_proptx = 0;
-module_param(op_mode, int, 0644);
-extern int wl_control_wl_start(struct net_device *dev);
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(BCMLXSDMMC)
-struct semaphore dhd_registration_sem;
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
-
-/* deferred handlers */
-static void dhd_ifadd_event_handler(void *handle, void *event_info, u8 event);
-static void dhd_ifdel_event_handler(void *handle, void *event_info, u8 event);
-static void dhd_set_mac_addr_handler(void *handle, void *event_info, u8 event);
-static void dhd_set_mcast_list_handler(void *handle, void *event_info, u8 event);
-#ifdef CONFIG_IPV6
-static void dhd_inet6_work_handler(void *dhd_info, void *event_data, u8 event);
-#endif
-
-#ifdef WL_CFG80211
-extern void dhd_netdev_free(struct net_device *ndev);
-#endif /* WL_CFG80211 */
-
-/* Error bits */
-module_param(dhd_msg_level, int, 0);
-#if defined(WL_WIRELESS_EXT)
-module_param(iw_msg_level, int, 0);
-#endif
-#ifdef WL_CFG80211
-module_param(wl_dbg_level, int, 0);
-#endif
-module_param(android_msg_level, int, 0);
-module_param(config_msg_level, int, 0);
-
-#ifdef ARP_OFFLOAD_SUPPORT
-/* ARP offload enable */
-uint dhd_arp_enable = TRUE;
-module_param(dhd_arp_enable, uint, 0);
-
-/* ARP offload agent mode : Enable ARP Host Auto-Reply and ARP Peer Auto-Reply */
-
-uint dhd_arp_mode = ARP_OL_AGENT | ARP_OL_PEER_AUTO_REPLY;
-
-module_param(dhd_arp_mode, uint, 0);
-#endif /* ARP_OFFLOAD_SUPPORT */
-
-/* Disable Prop tx */
-module_param(disable_proptx, int, 0644);
-/* load firmware and/or nvram values from the filesystem */
-module_param_string(firmware_path, firmware_path, MOD_PARAM_PATHLEN, 0660);
-module_param_string(nvram_path, nvram_path, MOD_PARAM_PATHLEN, 0660);
-module_param_string(config_path, config_path, MOD_PARAM_PATHLEN, 0);
-
-/* Watchdog interval */
-
-/* extend watchdog expiration to 2 seconds when DPC is running */
-#define WATCHDOG_EXTEND_INTERVAL (2000)
-
-uint dhd_watchdog_ms = CUSTOM_DHD_WATCHDOG_MS;
-module_param(dhd_watchdog_ms, uint, 0);
-
-#if defined(DHD_DEBUG)
-/* Console poll interval */
-uint dhd_console_ms = 0;
-module_param(dhd_console_ms, uint, 0644);
-#endif /* defined(DHD_DEBUG) */
-
-
-uint dhd_slpauto = TRUE;
-module_param(dhd_slpauto, uint, 0);
-
-#ifdef PKT_FILTER_SUPPORT
-/* Global Pkt filter enable control */
-uint dhd_pkt_filter_enable = TRUE;
-module_param(dhd_pkt_filter_enable, uint, 0);
-#endif
-
-/* Pkt filter init setup */
-uint dhd_pkt_filter_init = 0;
-module_param(dhd_pkt_filter_init, uint, 0);
-
-/* Pkt filter mode control */
-uint dhd_master_mode = FALSE;
-module_param(dhd_master_mode, uint, 0);
-
-int dhd_watchdog_prio = 0;
-module_param(dhd_watchdog_prio, int, 0);
-
-/* DPC thread priority */
-int dhd_dpc_prio = CUSTOM_DPC_PRIO_SETTING;
-module_param(dhd_dpc_prio, int, 0);
-
-/* RX frame thread priority */
-int dhd_rxf_prio = CUSTOM_RXF_PRIO_SETTING;
-module_param(dhd_rxf_prio, int, 0);
-
-#if !defined(BCMDHDUSB)
-extern int dhd_dongle_ramsize;
-module_param(dhd_dongle_ramsize, int, 0);
-#endif /* BCMDHDUSB */
-
-/* Keep track of number of instances */
-static int dhd_found = 0;
-static int instance_base = 0; /* Starting instance number */
-module_param(instance_base, int, 0644);
-
-
-/* DHD Perimiter lock only used in router with bypass forwarding. */
-#define DHD_PERIM_RADIO_INIT() do { /* noop */ } while (0)
-#define DHD_PERIM_LOCK_TRY(unit, flag) do { /* noop */ } while (0)
-#define DHD_PERIM_UNLOCK_TRY(unit, flag) do { /* noop */ } while (0)
-#define DHD_PERIM_LOCK_ALL() do { /* noop */ } while (0)
-#define DHD_PERIM_UNLOCK_ALL() do { /* noop */ } while (0)
-
-#ifdef PCIE_FULL_DONGLE
-#if defined(BCM_GMAC3)
-#define DHD_IF_STA_LIST_LOCK_INIT(ifp) do { /* noop */ } while (0)
-#define DHD_IF_STA_LIST_LOCK(ifp, flags) ({ BCM_REFERENCE(flags); })
-#define DHD_IF_STA_LIST_UNLOCK(ifp, flags) ({ BCM_REFERENCE(flags); })
-#else /* ! BCM_GMAC3 */
-#define DHD_IF_STA_LIST_LOCK_INIT(ifp) spin_lock_init(&(ifp)->sta_list_lock)
-#define DHD_IF_STA_LIST_LOCK(ifp, flags) \
- spin_lock_irqsave(&(ifp)->sta_list_lock, (flags))
-#define DHD_IF_STA_LIST_UNLOCK(ifp, flags) \
- spin_unlock_irqrestore(&(ifp)->sta_list_lock, (flags))
-#endif /* ! BCM_GMAC3 */
-#endif /* PCIE_FULL_DONGLE */
-
-/* Control fw roaming */
-#ifdef BCMCCX
-uint dhd_roam_disable = 0;
-#else
-uint dhd_roam_disable = 0;
-#endif /* BCMCCX */
-
-/* Control radio state */
-uint dhd_radio_up = 1;
-
-/* Network inteface name */
-char iface_name[IFNAMSIZ] = {'\0'};
-module_param_string(iface_name, iface_name, IFNAMSIZ, 0);
-
-/* The following are specific to the SDIO dongle */
-
-/* IOCTL response timeout */
-int dhd_ioctl_timeout_msec = IOCTL_RESP_TIMEOUT;
-
-/* Idle timeout for backplane clock */
-int dhd_idletime = DHD_IDLETIME_TICKS;
-module_param(dhd_idletime, int, 0);
-
-/* Use polling */
-uint dhd_poll = FALSE;
-module_param(dhd_poll, uint, 0);
-
-/* Use interrupts */
-uint dhd_intr = TRUE;
-module_param(dhd_intr, uint, 0);
-
-/* SDIO Drive Strength (in milliamps) */
-uint dhd_sdiod_drive_strength = 6;
-module_param(dhd_sdiod_drive_strength, uint, 0);
-
-#ifdef BCMSDIO
-/* Tx/Rx bounds */
-extern uint dhd_txbound;
-extern uint dhd_rxbound;
-module_param(dhd_txbound, uint, 0);
-module_param(dhd_rxbound, uint, 0);
-
-/* Deferred transmits */
-extern uint dhd_deferred_tx;
-module_param(dhd_deferred_tx, uint, 0);
-
-#ifdef BCMDBGFS
-extern void dhd_dbg_init(dhd_pub_t *dhdp);
-extern void dhd_dbg_remove(void);
-#endif /* BCMDBGFS */
-
-#endif /* BCMSDIO */
-
-
-#ifdef SDTEST
-/* Echo packet generator (pkts/s) */
-uint dhd_pktgen = 0;
-module_param(dhd_pktgen, uint, 0);
-
-/* Echo packet len (0 => sawtooth, max 2040) */
-uint dhd_pktgen_len = 0;
-module_param(dhd_pktgen_len, uint, 0);
-#endif /* SDTEST */
-
-#if defined(BCMSUP_4WAY_HANDSHAKE)
-/* Use in dongle supplicant for 4-way handshake */
-uint dhd_use_idsup = 0;
-module_param(dhd_use_idsup, uint, 0);
-#endif /* BCMSUP_4WAY_HANDSHAKE */
-
-extern char dhd_version[];
-
-int dhd_net_bus_devreset(struct net_device *dev, uint8 flag);
-static void dhd_net_if_lock_local(dhd_info_t *dhd);
-static void dhd_net_if_unlock_local(dhd_info_t *dhd);
-static void dhd_suspend_lock(dhd_pub_t *dhdp);
-static void dhd_suspend_unlock(dhd_pub_t *dhdp);
-
-#ifdef WLMEDIA_HTSF
-void htsf_update(dhd_info_t *dhd, void *data);
-tsf_t prev_tsf, cur_tsf;
-
-uint32 dhd_get_htsf(dhd_info_t *dhd, int ifidx);
-static int dhd_ioctl_htsf_get(dhd_info_t *dhd, int ifidx);
-static void dhd_dump_latency(void);
-static void dhd_htsf_addtxts(dhd_pub_t *dhdp, void *pktbuf);
-static void dhd_htsf_addrxts(dhd_pub_t *dhdp, void *pktbuf);
-static void dhd_dump_htsfhisto(histo_t *his, char *s);
-#endif /* WLMEDIA_HTSF */
-
-/* Monitor interface */
-int dhd_monitor_init(void *dhd_pub);
-int dhd_monitor_uninit(void);
-
-
-#if defined(WL_WIRELESS_EXT)
-struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev);
-#endif /* defined(WL_WIRELESS_EXT) */
-
-static void dhd_dpc(ulong data);
-/* forward decl */
-extern int dhd_wait_pend8021x(struct net_device *dev);
-void dhd_os_wd_timer_extend(void *bus, bool extend);
-
-#ifdef TOE
-#ifndef BDC
-#error TOE requires BDC
-#endif /* !BDC */
-static int dhd_toe_get(dhd_info_t *dhd, int idx, uint32 *toe_ol);
-static int dhd_toe_set(dhd_info_t *dhd, int idx, uint32 toe_ol);
-#endif /* TOE */
-
-static int dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata,
- wl_event_msg_t *event_ptr, void **data_ptr);
-#ifdef DHD_UNICAST_DHCP
-static const uint8 llc_snap_hdr[SNAP_HDR_LEN] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
-static int dhd_get_pkt_ip_type(dhd_pub_t *dhd, void *skb, uint8 **data_ptr,
- int *len_ptr, uint8 *prot_ptr);
-static int dhd_get_pkt_ether_type(dhd_pub_t *dhd, void *skb, uint8 **data_ptr,
- int *len_ptr, uint16 *et_ptr, bool *snap_ptr);
-
-static int dhd_convert_dhcp_broadcast_ack_to_unicast(dhd_pub_t *pub, void *pktbuf, int ifidx);
-#endif /* DHD_UNICAST_DHCP */
-#ifdef DHD_L2_FILTER
-static int dhd_l2_filter_block_ping(dhd_pub_t *pub, void *pktbuf, int ifidx);
-#endif
-#if defined(CONFIG_PM_SLEEP)
-static int dhd_pm_callback(struct notifier_block *nfb, unsigned long action, void *ignored)
-{
- int ret = NOTIFY_DONE;
- bool suspend = FALSE;
- dhd_info_t *dhdinfo = (dhd_info_t*)container_of(nfb, struct dhd_info, pm_notifier);
-
- BCM_REFERENCE(dhdinfo);
- switch (action) {
- case PM_HIBERNATION_PREPARE:
- case PM_SUSPEND_PREPARE:
- suspend = TRUE;
- break;
- case PM_POST_HIBERNATION:
- case PM_POST_SUSPEND:
- suspend = FALSE;
- break;
- }
-
-#if defined(SUPPORT_P2P_GO_PS)
-#ifdef PROP_TXSTATUS
- if (suspend) {
- DHD_OS_WAKE_LOCK_WAIVE(&dhdinfo->pub);
- dhd_wlfc_suspend(&dhdinfo->pub);
- DHD_OS_WAKE_LOCK_RESTORE(&dhdinfo->pub);
- } else
- dhd_wlfc_resume(&dhdinfo->pub);
-#endif
-#endif /* defined(SUPPORT_P2P_GO_PS) */
-
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (LINUX_VERSION_CODE <= \
- KERNEL_VERSION(2, 6, 39))
- dhd_mmc_suspend = suspend;
- smp_mb();
-#endif
-
- return ret;
-}
-
-static struct notifier_block dhd_pm_notifier = {
- .notifier_call = dhd_pm_callback,
- .priority = 10
-};
-/* to make sure we won't register the same notifier twice, otherwise a loop is likely to be
- * created in kernel notifier link list (with 'next' pointing to itself)
- */
-static bool dhd_pm_notifier_registered = FALSE;
-
-extern int register_pm_notifier(struct notifier_block *nb);
-extern int unregister_pm_notifier(struct notifier_block *nb);
-#endif /* CONFIG_PM_SLEEP */
-
-/* Request scheduling of the bus rx frame */
-static void dhd_sched_rxf(dhd_pub_t *dhdp, void *skb);
-static void dhd_os_rxflock(dhd_pub_t *pub);
-static void dhd_os_rxfunlock(dhd_pub_t *pub);
-
-/** priv_link is the link between netdev and the dhdif and dhd_info structs. */
-typedef struct dhd_dev_priv {
- dhd_info_t * dhd; /* cached pointer to dhd_info in netdevice priv */
- dhd_if_t * ifp; /* cached pointer to dhd_if in netdevice priv */
- int ifidx; /* interface index */
-} dhd_dev_priv_t;
-
-#define DHD_DEV_PRIV_SIZE (sizeof(dhd_dev_priv_t))
-#define DHD_DEV_PRIV(dev) ((dhd_dev_priv_t *)DEV_PRIV(dev))
-#define DHD_DEV_INFO(dev) (((dhd_dev_priv_t *)DEV_PRIV(dev))->dhd)
-#define DHD_DEV_IFP(dev) (((dhd_dev_priv_t *)DEV_PRIV(dev))->ifp)
-#define DHD_DEV_IFIDX(dev) (((dhd_dev_priv_t *)DEV_PRIV(dev))->ifidx)
-
-/** Clear the dhd net_device's private structure. */
-static inline void
-dhd_dev_priv_clear(struct net_device * dev)
-{
- dhd_dev_priv_t * dev_priv;
- ASSERT(dev != (struct net_device *)NULL);
- dev_priv = DHD_DEV_PRIV(dev);
- dev_priv->dhd = (dhd_info_t *)NULL;
- dev_priv->ifp = (dhd_if_t *)NULL;
- dev_priv->ifidx = DHD_BAD_IF;
-}
-
-/** Setup the dhd net_device's private structure. */
-static inline void
-dhd_dev_priv_save(struct net_device * dev, dhd_info_t * dhd, dhd_if_t * ifp,
- int ifidx)
-{
- dhd_dev_priv_t * dev_priv;
- ASSERT(dev != (struct net_device *)NULL);
- dev_priv = DHD_DEV_PRIV(dev);
- dev_priv->dhd = dhd;
- dev_priv->ifp = ifp;
- dev_priv->ifidx = ifidx;
-}
-
-#ifdef PCIE_FULL_DONGLE
-
-/** Dummy objects are defined with state representing bad|down.
- * Performance gains from reducing branch conditionals, instruction parallelism,
- * dual issue, reducing load shadows, avail of larger pipelines.
- * Use DHD_XXX_NULL instead of (dhd_xxx_t *)NULL, whenever an object pointer
- * is accessed via the dhd_sta_t.
- */
-
-/* Dummy dhd_info object */
-dhd_info_t dhd_info_null = {
-#if defined(BCM_GMAC3)
- .fwdh = FWDER_NULL,
-#endif
- .pub = {
- .info = &dhd_info_null,
-#ifdef DHDTCPACK_SUPPRESS
- .tcpack_sup_mode = TCPACK_SUP_REPLACE,
-#endif /* DHDTCPACK_SUPPRESS */
- .up = FALSE, .busstate = DHD_BUS_DOWN
- }
-};
-#define DHD_INFO_NULL (&dhd_info_null)
-#define DHD_PUB_NULL (&dhd_info_null.pub)
-
-/* Dummy netdevice object */
-struct net_device dhd_net_dev_null = {
- .reg_state = NETREG_UNREGISTERED
-};
-#define DHD_NET_DEV_NULL (&dhd_net_dev_null)
-
-/* Dummy dhd_if object */
-dhd_if_t dhd_if_null = {
-#if defined(BCM_GMAC3)
- .fwdh = FWDER_NULL,
-#endif
-#ifdef WMF
- .wmf = { .wmf_enable = TRUE },
-#endif
- .info = DHD_INFO_NULL,
- .net = DHD_NET_DEV_NULL,
- .idx = DHD_BAD_IF
-};
-#define DHD_IF_NULL (&dhd_if_null)
-
-#define DHD_STA_NULL ((dhd_sta_t *)NULL)
-
-/** Interface STA list management. */
-
-/** Fetch the dhd_if object, given the interface index in the dhd. */
-static inline dhd_if_t *dhd_get_ifp(dhd_pub_t *dhdp, uint32 ifidx);
-
-/** Alloc/Free a dhd_sta object from the dhd instances' sta_pool. */
-static void dhd_sta_free(dhd_pub_t *pub, dhd_sta_t *sta);
-static dhd_sta_t * dhd_sta_alloc(dhd_pub_t * dhdp);
-
-/* Delete a dhd_sta or flush all dhd_sta in an interface's sta_list. */
-static void dhd_if_del_sta_list(dhd_if_t * ifp);
-static void dhd_if_flush_sta(dhd_if_t * ifp);
-
-/* Construct/Destruct a sta pool. */
-static int dhd_sta_pool_init(dhd_pub_t *dhdp, int max_sta);
-static void dhd_sta_pool_fini(dhd_pub_t *dhdp, int max_sta);
-
-
-/* Return interface pointer */
-static inline dhd_if_t *dhd_get_ifp(dhd_pub_t *dhdp, uint32 ifidx)
-{
- ASSERT(ifidx < DHD_MAX_IFS);
- return dhdp->info->iflist[ifidx];
-}
-
-/** Reset a dhd_sta object and free into the dhd pool. */
-static void
-dhd_sta_free(dhd_pub_t * dhdp, dhd_sta_t * sta)
-{
- int prio;
-
- ASSERT((sta != DHD_STA_NULL) && (sta->idx != ID16_INVALID));
-
- ASSERT((dhdp->staid_allocator != NULL) && (dhdp->sta_pool != NULL));
- id16_map_free(dhdp->staid_allocator, sta->idx);
- for (prio = 0; prio < (int)NUMPRIO; prio++)
- sta->flowid[prio] = FLOWID_INVALID;
- sta->ifp = DHD_IF_NULL; /* dummy dhd_if object */
- sta->ifidx = DHD_BAD_IF;
- bzero(sta->ea.octet, ETHER_ADDR_LEN);
- INIT_LIST_HEAD(&sta->list);
- sta->idx = ID16_INVALID; /* implying free */
-}
-
-/** Allocate a dhd_sta object from the dhd pool. */
-static dhd_sta_t *
-dhd_sta_alloc(dhd_pub_t * dhdp)
-{
- uint16 idx;
- dhd_sta_t * sta;
- dhd_sta_pool_t * sta_pool;
-
- ASSERT((dhdp->staid_allocator != NULL) && (dhdp->sta_pool != NULL));
-
- idx = id16_map_alloc(dhdp->staid_allocator);
- if (idx == ID16_INVALID) {
- DHD_ERROR(("%s: cannot get free staid\n", __FUNCTION__));
- return DHD_STA_NULL;
- }
-
- sta_pool = (dhd_sta_pool_t *)(dhdp->sta_pool);
- sta = &sta_pool[idx];
-
- ASSERT((sta->idx == ID16_INVALID) &&
- (sta->ifp == DHD_IF_NULL) && (sta->ifidx == DHD_BAD_IF));
- sta->idx = idx; /* implying allocated */
-
- return sta;
-}
-
-/** Delete all STAs in an interface's STA list. */
-static void
-dhd_if_del_sta_list(dhd_if_t *ifp)
-{
- dhd_sta_t *sta, *next;
- unsigned long flags;
-
- DHD_IF_STA_LIST_LOCK(ifp, flags);
-
- list_for_each_entry_safe(sta, next, &ifp->sta_list, list) {
-#if defined(BCM_GMAC3)
- if (ifp->fwdh) {
- /* Remove sta from WOFA forwarder. */
- fwder_deassoc(ifp->fwdh, (uint16 *)(sta->ea.octet), (wofa_t)sta);
- }
-#endif /* BCM_GMAC3 */
- list_del(&sta->list);
- dhd_sta_free(&ifp->info->pub, sta);
- }
-
- DHD_IF_STA_LIST_UNLOCK(ifp, flags);
-
- return;
-}
-
-/** Router/GMAC3: Flush all station entries in the forwarder's WOFA database. */
-static void
-dhd_if_flush_sta(dhd_if_t * ifp)
-{
-#if defined(BCM_GMAC3)
-
- if (ifp && (ifp->fwdh != FWDER_NULL)) {
- dhd_sta_t *sta, *next;
- unsigned long flags;
-
- DHD_IF_STA_LIST_LOCK(ifp, flags);
-
- list_for_each_entry_safe(sta, next, &ifp->sta_list, list) {
- /* Remove any sta entry from WOFA forwarder. */
- fwder_flush(ifp->fwdh, (wofa_t)sta);
- }
-
- DHD_IF_STA_LIST_UNLOCK(ifp, flags);
- }
-#endif /* BCM_GMAC3 */
-}
-
-/** Construct a pool of dhd_sta_t objects to be used by interfaces. */
-static int
-dhd_sta_pool_init(dhd_pub_t *dhdp, int max_sta)
-{
- int idx, sta_pool_memsz;
- dhd_sta_t * sta;
- dhd_sta_pool_t * sta_pool;
- void * staid_allocator;
-
- ASSERT(dhdp != (dhd_pub_t *)NULL);
- ASSERT((dhdp->staid_allocator == NULL) && (dhdp->sta_pool == NULL));
-
- /* dhd_sta objects per radio are managed in a table. id#0 reserved. */
- staid_allocator = id16_map_init(dhdp->osh, max_sta, 1);
- if (staid_allocator == NULL) {
- DHD_ERROR(("%s: sta id allocator init failure\n", __FUNCTION__));
- return BCME_ERROR;
- }
-
- /* Pre allocate a pool of dhd_sta objects (one extra). */
- sta_pool_memsz = ((max_sta + 1) * sizeof(dhd_sta_t)); /* skip idx 0 */
- sta_pool = (dhd_sta_pool_t *)MALLOC(dhdp->osh, sta_pool_memsz);
- if (sta_pool == NULL) {
- DHD_ERROR(("%s: sta table alloc failure\n", __FUNCTION__));
- id16_map_fini(dhdp->osh, staid_allocator);
- return BCME_ERROR;
- }
-
- dhdp->sta_pool = sta_pool;
- dhdp->staid_allocator = staid_allocator;
-
- /* Initialize all sta(s) for the pre-allocated free pool. */
- bzero((uchar *)sta_pool, sta_pool_memsz);
- for (idx = max_sta; idx >= 1; idx--) { /* skip sta_pool[0] */
- sta = &sta_pool[idx];
- sta->idx = id16_map_alloc(staid_allocator);
- ASSERT(sta->idx <= max_sta);
- }
- /* Now place them into the pre-allocated free pool. */
- for (idx = 1; idx <= max_sta; idx++) {
- sta = &sta_pool[idx];
- dhd_sta_free(dhdp, sta);
- }
-
- return BCME_OK;
-}
-
-/** Destruct the pool of dhd_sta_t objects.
- * Caller must ensure that no STA objects are currently associated with an if.
- */
-static void
-dhd_sta_pool_fini(dhd_pub_t *dhdp, int max_sta)
-{
- dhd_sta_pool_t * sta_pool = (dhd_sta_pool_t *)dhdp->sta_pool;
-
- if (sta_pool) {
- int idx;
- int sta_pool_memsz = ((max_sta + 1) * sizeof(dhd_sta_t));
- for (idx = 1; idx <= max_sta; idx++) {
- ASSERT(sta_pool[idx].ifp == DHD_IF_NULL);
- ASSERT(sta_pool[idx].idx == ID16_INVALID);
- }
- MFREE(dhdp->osh, dhdp->sta_pool, sta_pool_memsz);
- dhdp->sta_pool = NULL;
- }
-
- id16_map_fini(dhdp->osh, dhdp->staid_allocator);
- dhdp->staid_allocator = NULL;
-}
-
-/** Find STA with MAC address ea in an interface's STA list. */
-dhd_sta_t *
-dhd_find_sta(void *pub, int ifidx, void *ea)
-{
- dhd_sta_t *sta;
- dhd_if_t *ifp;
- unsigned long flags;
-
- ASSERT(ea != NULL);
- ifp = dhd_get_ifp((dhd_pub_t *)pub, ifidx);
-
- DHD_IF_STA_LIST_LOCK(ifp, flags);
-
- list_for_each_entry(sta, &ifp->sta_list, list) {
- if (!memcmp(sta->ea.octet, ea, ETHER_ADDR_LEN)) {
- DHD_IF_STA_LIST_UNLOCK(ifp, flags);
- return sta;
- }
- }
-
- DHD_IF_STA_LIST_UNLOCK(ifp, flags);
-
- return DHD_STA_NULL;
-}
-
-/** Add STA into the interface's STA list. */
-dhd_sta_t *
-dhd_add_sta(void *pub, int ifidx, void *ea)
-{
- dhd_sta_t *sta;
- dhd_if_t *ifp;
- unsigned long flags;
-
- ASSERT(ea != NULL);
- ifp = dhd_get_ifp((dhd_pub_t *)pub, ifidx);
-
- sta = dhd_sta_alloc((dhd_pub_t *)pub);
- if (sta == DHD_STA_NULL) {
- DHD_ERROR(("%s: Alloc failed\n", __FUNCTION__));
- return DHD_STA_NULL;
- }
-
- memcpy(sta->ea.octet, ea, ETHER_ADDR_LEN);
-
- /* link the sta and the dhd interface */
- sta->ifp = ifp;
- sta->ifidx = ifidx;
- INIT_LIST_HEAD(&sta->list);
-
- DHD_IF_STA_LIST_LOCK(ifp, flags);
-
- list_add_tail(&sta->list, &ifp->sta_list);
-
-#if defined(BCM_GMAC3)
- if (ifp->fwdh) {
- ASSERT(ISALIGNED(ea, 2));
- /* Add sta to WOFA forwarder. */
- fwder_reassoc(ifp->fwdh, (uint16 *)ea, (wofa_t)sta);
- }
-#endif /* BCM_GMAC3 */
-
- DHD_IF_STA_LIST_UNLOCK(ifp, flags);
-
- return sta;
-}
-
-/** Delete STA from the interface's STA list. */
-void
-dhd_del_sta(void *pub, int ifidx, void *ea)
-{
- dhd_sta_t *sta, *next;
- dhd_if_t *ifp;
- unsigned long flags;
-
- ASSERT(ea != NULL);
- ifp = dhd_get_ifp((dhd_pub_t *)pub, ifidx);
-
- DHD_IF_STA_LIST_LOCK(ifp, flags);
-
- list_for_each_entry_safe(sta, next, &ifp->sta_list, list) {
- if (!memcmp(sta->ea.octet, ea, ETHER_ADDR_LEN)) {
-#if defined(BCM_GMAC3)
- if (ifp->fwdh) { /* Found a sta, remove from WOFA forwarder. */
- ASSERT(ISALIGNED(ea, 2));
- fwder_deassoc(ifp->fwdh, (uint16 *)ea, (wofa_t)sta);
- }
-#endif /* BCM_GMAC3 */
- list_del(&sta->list);
- dhd_sta_free(&ifp->info->pub, sta);
- }
- }
-
- DHD_IF_STA_LIST_UNLOCK(ifp, flags);
-
- return;
-}
-
-/** Add STA if it doesn't exist. Not reentrant. */
-dhd_sta_t*
-dhd_findadd_sta(void *pub, int ifidx, void *ea)
-{
- dhd_sta_t *sta;
-
- sta = dhd_find_sta(pub, ifidx, ea);
-
- if (!sta) {
- /* Add entry */
- sta = dhd_add_sta(pub, ifidx, ea);
- }
-
- return sta;
-}
-#else
-static inline void dhd_if_flush_sta(dhd_if_t * ifp) { }
-static inline void dhd_if_del_sta_list(dhd_if_t *ifp) {}
-static inline int dhd_sta_pool_init(dhd_pub_t *dhdp, int max_sta) { return BCME_OK; }
-static inline void dhd_sta_pool_fini(dhd_pub_t *dhdp, int max_sta) {}
-dhd_sta_t *dhd_findadd_sta(void *pub, int ifidx, void *ea) { return NULL; }
-void dhd_del_sta(void *pub, int ifidx, void *ea) {}
-#endif /* PCIE_FULL_DONGLE */
-
-
-/* Returns dhd iflist index correspondig the the bssidx provided by apps */
-int dhd_bssidx2idx(dhd_pub_t *dhdp, uint32 bssidx)
-{
- dhd_if_t *ifp;
- dhd_info_t *dhd = dhdp->info;
- int i;
-
- ASSERT(bssidx < DHD_MAX_IFS);
- ASSERT(dhdp);
-
- for (i = 0; i < DHD_MAX_IFS; i++) {
- ifp = dhd->iflist[i];
- if (ifp && (ifp->bssidx == bssidx)) {
- DHD_TRACE(("Index manipulated for %s from %d to %d\n",
- ifp->name, bssidx, i));
- break;
- }
- }
- return i;
-}
-
-static inline int dhd_rxf_enqueue(dhd_pub_t *dhdp, void* skb)
-{
- uint32 store_idx;
- uint32 sent_idx;
-
- if (!skb) {
- DHD_ERROR(("dhd_rxf_enqueue: NULL skb!!!\n"));
- return BCME_ERROR;
- }
-
- dhd_os_rxflock(dhdp);
- store_idx = dhdp->store_idx;
- sent_idx = dhdp->sent_idx;
- if (dhdp->skbbuf[store_idx] != NULL) {
- /* Make sure the previous packets are processed */
- dhd_os_rxfunlock(dhdp);
-#ifdef RXF_DEQUEUE_ON_BUSY
- DHD_TRACE(("dhd_rxf_enqueue: pktbuf not consumed %p, store idx %d sent idx %d\n",
- skb, store_idx, sent_idx));
- return BCME_BUSY;
-#else /* RXF_DEQUEUE_ON_BUSY */
- DHD_ERROR(("dhd_rxf_enqueue: pktbuf not consumed %p, store idx %d sent idx %d\n",
- skb, store_idx, sent_idx));
- /* removed msleep here, should use wait_event_timeout if we
- * want to give rx frame thread a chance to run
- */
-#if defined(WAIT_DEQUEUE)
- OSL_SLEEP(1);
-#endif
- return BCME_ERROR;
-#endif /* RXF_DEQUEUE_ON_BUSY */
- }
- DHD_TRACE(("dhd_rxf_enqueue: Store SKB %p. idx %d -> %d\n",
- skb, store_idx, (store_idx + 1) & (MAXSKBPEND - 1)));
- dhdp->skbbuf[store_idx] = skb;
- dhdp->store_idx = (store_idx + 1) & (MAXSKBPEND - 1);
- dhd_os_rxfunlock(dhdp);
-
- return BCME_OK;
-}
-
-static inline void* dhd_rxf_dequeue(dhd_pub_t *dhdp)
-{
- uint32 store_idx;
- uint32 sent_idx;
- void *skb;
-
- dhd_os_rxflock(dhdp);
-
- store_idx = dhdp->store_idx;
- sent_idx = dhdp->sent_idx;
- skb = dhdp->skbbuf[sent_idx];
-
- if (skb == NULL) {
- dhd_os_rxfunlock(dhdp);
- DHD_ERROR(("dhd_rxf_dequeue: Dequeued packet is NULL, store idx %d sent idx %d\n",
- store_idx, sent_idx));
- return NULL;
- }
-
- dhdp->skbbuf[sent_idx] = NULL;
- dhdp->sent_idx = (sent_idx + 1) & (MAXSKBPEND - 1);
-
- DHD_TRACE(("dhd_rxf_dequeue: netif_rx_ni(%p), sent idx %d\n",
- skb, sent_idx));
-
- dhd_os_rxfunlock(dhdp);
-
- return skb;
-}
-
-int dhd_process_cid_mac(dhd_pub_t *dhdp, bool prepost)
-{
-#ifndef CUSTOMER_HW10
- dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
-#endif /* !CUSTOMER_HW10 */
-
- if (prepost) { /* pre process */
- dhd_read_macaddr(dhd);
- } else { /* post process */
- dhd_write_macaddr(&dhd->pub.mac);
- }
-
- return 0;
-}
-
-#if defined(PKT_FILTER_SUPPORT) && !defined(GAN_LITE_NAT_KEEPALIVE_FILTER)
-static bool
-_turn_on_arp_filter(dhd_pub_t *dhd, int op_mode)
-{
- bool _apply = FALSE;
- /* In case of IBSS mode, apply arp pkt filter */
- if (op_mode & DHD_FLAG_IBSS_MODE) {
- _apply = TRUE;
- goto exit;
- }
- /* In case of P2P GO or GC, apply pkt filter to pass arp pkt to host */
- if ((dhd->arp_version == 1) &&
- (op_mode & (DHD_FLAG_P2P_GC_MODE | DHD_FLAG_P2P_GO_MODE))) {
- _apply = TRUE;
- goto exit;
- }
-
-exit:
- return _apply;
-}
-#endif /* PKT_FILTER_SUPPORT && !GAN_LITE_NAT_KEEPALIVE_FILTER */
-
-void dhd_set_packet_filter(dhd_pub_t *dhd)
-{
-#ifdef PKT_FILTER_SUPPORT
- int i;
-
- DHD_TRACE(("%s: enter\n", __FUNCTION__));
- if (dhd_pkt_filter_enable) {
- for (i = 0; i < dhd->pktfilter_count; i++) {
- dhd_pktfilter_offload_set(dhd, dhd->pktfilter[i]);
- }
- }
-#endif /* PKT_FILTER_SUPPORT */
-}
-
-void dhd_enable_packet_filter(int value, dhd_pub_t *dhd)
-{
-#ifdef PKT_FILTER_SUPPORT
- int i;
-
- DHD_TRACE(("%s: enter, value = %d\n", __FUNCTION__, value));
- /* 1 - Enable packet filter, only allow unicast packet to send up */
- /* 0 - Disable packet filter */
- if (dhd_pkt_filter_enable && (!value ||
- (dhd_support_sta_mode(dhd) && !dhd->dhcp_in_progress)))
- {
- for (i = 0; i < dhd->pktfilter_count; i++) {
-#ifndef GAN_LITE_NAT_KEEPALIVE_FILTER
- if (value && (i == DHD_ARP_FILTER_NUM) &&
- !_turn_on_arp_filter(dhd, dhd->op_mode)) {
- DHD_TRACE(("Do not turn on ARP white list pkt filter:"
- "val %d, cnt %d, op_mode 0x%x\n",
- value, i, dhd->op_mode));
- continue;
- }
-#endif /* !GAN_LITE_NAT_KEEPALIVE_FILTER */
- dhd_pktfilter_offload_enable(dhd, dhd->pktfilter[i],
- value, dhd_master_mode);
- }
- }
-#endif /* PKT_FILTER_SUPPORT */
-}
-
-static int dhd_set_suspend(int value, dhd_pub_t *dhd)
-{
-#ifndef SUPPORT_PM2_ONLY
- int power_mode = PM_MAX;
-#endif /* SUPPORT_PM2_ONLY */
- /* wl_pkt_filter_enable_t enable_parm; */
- char iovbuf[32];
- int bcn_li_dtim = 0; /* Default bcn_li_dtim in resume mode is 0 */
- uint roamvar = dhd->conf->roam_off_suspend;
- uint nd_ra_filter = 0;
- int ret = 0;
-
- if (!dhd)
- return -ENODEV;
-
- DHD_TRACE(("%s: enter, value = %d in_suspend=%d\n",
- __FUNCTION__, value, dhd->in_suspend));
-
- dhd_suspend_lock(dhd);
-
-#ifdef CUSTOM_SET_CPUCORE
- DHD_TRACE(("%s set cpucore(suspend%d)\n", __FUNCTION__, value));
- /* set specific cpucore */
- dhd_set_cpucore(dhd, TRUE);
-#endif /* CUSTOM_SET_CPUCORE */
- if (dhd->up) {
- if (value && dhd->in_suspend) {
-#ifdef PKT_FILTER_SUPPORT
- dhd->early_suspended = 1;
-#endif
- /* Kernel suspended */
- DHD_ERROR(("%s: force extra Suspend setting\n", __FUNCTION__));
-
-#ifndef SUPPORT_PM2_ONLY
- dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode,
- sizeof(power_mode), TRUE, 0);
-#endif /* SUPPORT_PM2_ONLY */
-
- /* Enable packet filter, only allow unicast packet to send up */
- dhd_enable_packet_filter(1, dhd);
-
- /* If DTIM skip is set up as default, force it to wake
- * each third DTIM for better power savings. Note that
- * one side effect is a chance to miss BC/MC packet.
- */
- bcn_li_dtim = dhd_get_suspend_bcn_li_dtim(dhd);
- bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim,
- 4, iovbuf, sizeof(iovbuf));
- if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf),
- TRUE, 0) < 0)
- DHD_ERROR(("%s: set dtim failed\n", __FUNCTION__));
-
- /* Disable firmware roaming during suspend */
- bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf));
- dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
- if (FW_SUPPORTED(dhd, ndoe)) {
- /* enable IPv6 RA filter in firmware during suspend */
- nd_ra_filter = 1;
- bcm_mkiovar("nd_ra_filter_enable", (char *)&nd_ra_filter, 4,
- iovbuf, sizeof(iovbuf));
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
- sizeof(iovbuf), TRUE, 0)) < 0)
- DHD_ERROR(("failed to set nd_ra_filter (%d)\n",
- ret));
- }
- } else {
-#ifdef PKT_FILTER_SUPPORT
- dhd->early_suspended = 0;
-#endif
- /* Kernel resumed */
- DHD_ERROR(("%s: Remove extra suspend setting\n", __FUNCTION__));
-
-#ifndef SUPPORT_PM2_ONLY
- power_mode = PM_FAST;
- dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode,
- sizeof(power_mode), TRUE, 0);
-#endif /* SUPPORT_PM2_ONLY */
-#ifdef PKT_FILTER_SUPPORT
- /* disable pkt filter */
- dhd_enable_packet_filter(0, dhd);
-#endif /* PKT_FILTER_SUPPORT */
-
- /* restore pre-suspend setting for dtim_skip */
- bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim,
- 4, iovbuf, sizeof(iovbuf));
-
- dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
- roamvar = dhd_roam_disable;
- bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf));
- dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
- if (FW_SUPPORTED(dhd, ndoe)) {
- /* disable IPv6 RA filter in firmware during suspend */
- nd_ra_filter = 0;
- bcm_mkiovar("nd_ra_filter_enable", (char *)&nd_ra_filter, 4,
- iovbuf, sizeof(iovbuf));
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
- sizeof(iovbuf), TRUE, 0)) < 0)
- DHD_ERROR(("failed to set nd_ra_filter (%d)\n",
- ret));
- }
- }
- }
- dhd_suspend_unlock(dhd);
-
- return 0;
-}
-
-static int dhd_suspend_resume_helper(struct dhd_info *dhd, int val, int force)
-{
- dhd_pub_t *dhdp = &dhd->pub;
- int ret = 0;
-
- DHD_OS_WAKE_LOCK(dhdp);
- DHD_PERIM_LOCK(dhdp);
-
- /* Set flag when early suspend was called */
- dhdp->in_suspend = val;
- if ((force || !dhdp->suspend_disable_flag) &&
- dhd_support_sta_mode(dhdp))
- {
- ret = dhd_set_suspend(val, dhdp);
- }
-
- DHD_PERIM_UNLOCK(dhdp);
- DHD_OS_WAKE_UNLOCK(dhdp);
- return ret;
-}
-
-#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
-static void dhd_early_suspend(struct early_suspend *h)
-{
- struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend);
- DHD_TRACE_HW4(("%s: enter\n", __FUNCTION__));
-
- if (dhd)
- dhd_suspend_resume_helper(dhd, 1, 0);
-}
-
-static void dhd_late_resume(struct early_suspend *h)
-{
- struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend);
- DHD_TRACE_HW4(("%s: enter\n", __FUNCTION__));
-
- if (dhd)
- dhd_suspend_resume_helper(dhd, 0, 0);
-}
-#endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */
-
-/*
- * Generalized timeout mechanism. Uses spin sleep with exponential back-off until
- * the sleep time reaches one jiffy, then switches over to task delay. Usage:
- *
- * dhd_timeout_start(&tmo, usec);
- * while (!dhd_timeout_expired(&tmo))
- * if (poll_something())
- * break;
- * if (dhd_timeout_expired(&tmo))
- * fatal();
- */
-
-void
-dhd_timeout_start(dhd_timeout_t *tmo, uint usec)
-{
- tmo->limit = usec;
- tmo->increment = 0;
- tmo->elapsed = 0;
- tmo->tick = jiffies_to_usecs(1);
-}
-
-int
-dhd_timeout_expired(dhd_timeout_t *tmo)
-{
- /* Does nothing the first call */
- if (tmo->increment == 0) {
- tmo->increment = 1;
- return 0;
- }
-
- if (tmo->elapsed >= tmo->limit)
- return 1;
-
- /* Add the delay that's about to take place */
- tmo->elapsed += tmo->increment;
-
- if ((!CAN_SLEEP()) || tmo->increment < tmo->tick) {
- OSL_DELAY(tmo->increment);
- tmo->increment *= 2;
- if (tmo->increment > tmo->tick)
- tmo->increment = tmo->tick;
- } else {
- wait_queue_head_t delay_wait;
- DECLARE_WAITQUEUE(wait, current);
- init_waitqueue_head(&delay_wait);
- add_wait_queue(&delay_wait, &wait);
- set_current_state(TASK_INTERRUPTIBLE);
- (void)schedule_timeout(1);
- remove_wait_queue(&delay_wait, &wait);
- set_current_state(TASK_RUNNING);
- }
-
- return 0;
-}
-
-int
-dhd_net2idx(dhd_info_t *dhd, struct net_device *net)
-{
- int i = 0;
-
- ASSERT(dhd);
- while (i < DHD_MAX_IFS) {
- if (dhd->iflist[i] && dhd->iflist[i]->net && (dhd->iflist[i]->net == net))
- return i;
- i++;
- }
-
- return DHD_BAD_IF;
-}
-
-struct net_device * dhd_idx2net(void *pub, int ifidx)
-{
- struct dhd_pub *dhd_pub = (struct dhd_pub *)pub;
- struct dhd_info *dhd_info;
-
- if (!dhd_pub || ifidx < 0 || ifidx >= DHD_MAX_IFS)
- return NULL;
- dhd_info = dhd_pub->info;
- if (dhd_info && dhd_info->iflist[ifidx])
- return dhd_info->iflist[ifidx]->net;
- return NULL;
-}
-
-int
-dhd_ifname2idx(dhd_info_t *dhd, char *name)
-{
- int i = DHD_MAX_IFS;
-
- ASSERT(dhd);
-
- if (name == NULL || *name == '\0')
- return 0;
-
- while (--i > 0)
- if (dhd->iflist[i] && !strncmp(dhd->iflist[i]->name, name, IFNAMSIZ))
- break;
-
- DHD_TRACE(("%s: return idx %d for \"%s\"\n", __FUNCTION__, i, name));
-
- return i; /* default - the primary interface */
-}
-
-int
-dhd_ifidx2hostidx(dhd_info_t *dhd, int ifidx)
-{
- int i = DHD_MAX_IFS;
-
- ASSERT(dhd);
-
- while (--i > 0)
- if (dhd->iflist[i] && (dhd->iflist[i]->idx == ifidx))
- break;
-
- DHD_TRACE(("%s: return hostidx %d for ifidx %d\n", __FUNCTION__, i, ifidx));
-
- return i; /* default - the primary interface */
-}
-
-char *
-dhd_ifname(dhd_pub_t *dhdp, int ifidx)
-{
- dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
-
- ASSERT(dhd);
-
- if (ifidx < 0 || ifidx >= DHD_MAX_IFS) {
- DHD_ERROR(("%s: ifidx %d out of range\n", __FUNCTION__, ifidx));
- return "<if_bad>";
- }
-
- if (dhd->iflist[ifidx] == NULL) {
- DHD_ERROR(("%s: null i/f %d\n", __FUNCTION__, ifidx));
- return "<if_null>";
- }
-
- if (dhd->iflist[ifidx]->net)
- return dhd->iflist[ifidx]->net->name;
-
- return "<if_none>";
-}
-
-uint8 *
-dhd_bssidx2bssid(dhd_pub_t *dhdp, int idx)
-{
- int i;
- dhd_info_t *dhd = (dhd_info_t *)dhdp;
-
- ASSERT(dhd);
- for (i = 0; i < DHD_MAX_IFS; i++)
- if (dhd->iflist[i] && dhd->iflist[i]->bssidx == idx)
- return dhd->iflist[i]->mac_addr;
-
- return NULL;
-}
-
-
-static void
-_dhd_set_multicast_list(dhd_info_t *dhd, int ifidx)
-{
- struct net_device *dev;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
- struct netdev_hw_addr *ha;
-#else
- struct dev_mc_list *mclist;
-#endif
- uint32 allmulti, cnt;
-
- wl_ioctl_t ioc;
- char *buf, *bufp;
- uint buflen;
- int ret;
-
- ASSERT(dhd && dhd->iflist[ifidx]);
- dev = dhd->iflist[ifidx]->net;
- if (!dev)
- return;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
- netif_addr_lock_bh(dev);
-#endif
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
- cnt = netdev_mc_count(dev);
-#else
- cnt = dev->mc_count;
-#endif /* LINUX_VERSION_CODE */
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
- netif_addr_unlock_bh(dev);
-#endif
-
- /* Determine initial value of allmulti flag */
- allmulti = (dev->flags & IFF_ALLMULTI) ? TRUE : FALSE;
-
- /* Send down the multicast list first. */
-
-
- buflen = sizeof("mcast_list") + sizeof(cnt) + (cnt * ETHER_ADDR_LEN);
- if (!(bufp = buf = MALLOC(dhd->pub.osh, buflen))) {
- DHD_ERROR(("%s: out of memory for mcast_list, cnt %d\n",
- dhd_ifname(&dhd->pub, ifidx), cnt));
- return;
- }
-
- strncpy(bufp, "mcast_list", buflen - 1);
- bufp[buflen - 1] = '\0';
- bufp += strlen("mcast_list") + 1;
-
- cnt = htol32(cnt);
- memcpy(bufp, &cnt, sizeof(cnt));
- bufp += sizeof(cnt);
-
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
- netif_addr_lock_bh(dev);
-#endif
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
- netdev_for_each_mc_addr(ha, dev) {
- if (!cnt)
- break;
- memcpy(bufp, ha->addr, ETHER_ADDR_LEN);
- bufp += ETHER_ADDR_LEN;
- cnt--;
- }
-#else
- for (mclist = dev->mc_list; (mclist && (cnt > 0));
- cnt--, mclist = mclist->next) {
- memcpy(bufp, (void *)mclist->dmi_addr, ETHER_ADDR_LEN);
- bufp += ETHER_ADDR_LEN;
- }
-#endif /* LINUX_VERSION_CODE */
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
- netif_addr_unlock_bh(dev);
-#endif
-
- memset(&ioc, 0, sizeof(ioc));
- ioc.cmd = WLC_SET_VAR;
- ioc.buf = buf;
- ioc.len = buflen;
- ioc.set = TRUE;
-
- ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len);
- if (ret < 0) {
- DHD_ERROR(("%s: set mcast_list failed, cnt %d\n",
- dhd_ifname(&dhd->pub, ifidx), cnt));
- allmulti = cnt ? TRUE : allmulti;
- }
-
- MFREE(dhd->pub.osh, buf, buflen);
-
- /* Now send the allmulti setting. This is based on the setting in the
- * net_device flags, but might be modified above to be turned on if we
- * were trying to set some addresses and dongle rejected it...
- */
-
- buflen = sizeof("allmulti") + sizeof(allmulti);
- if (!(buf = MALLOC(dhd->pub.osh, buflen))) {
- DHD_ERROR(("%s: out of memory for allmulti\n", dhd_ifname(&dhd->pub, ifidx)));
- return;
- }
- allmulti = htol32(allmulti);
-
- if (!bcm_mkiovar("allmulti", (void*)&allmulti, sizeof(allmulti), buf, buflen)) {
- DHD_ERROR(("%s: mkiovar failed for allmulti, datalen %d buflen %u\n",
- dhd_ifname(&dhd->pub, ifidx), (int)sizeof(allmulti), buflen));
- MFREE(dhd->pub.osh, buf, buflen);
- return;
- }
-
-
- memset(&ioc, 0, sizeof(ioc));
- ioc.cmd = WLC_SET_VAR;
- ioc.buf = buf;
- ioc.len = buflen;
- ioc.set = TRUE;
-
- ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len);
- if (ret < 0) {
- DHD_ERROR(("%s: set allmulti %d failed\n",
- dhd_ifname(&dhd->pub, ifidx), ltoh32(allmulti)));
- }
-
- MFREE(dhd->pub.osh, buf, buflen);
-
- /* Finally, pick up the PROMISC flag as well, like the NIC driver does */
-
- allmulti = (dev->flags & IFF_PROMISC) ? TRUE : FALSE;
-
- allmulti = htol32(allmulti);
-
- memset(&ioc, 0, sizeof(ioc));
- ioc.cmd = WLC_SET_PROMISC;
- ioc.buf = &allmulti;
- ioc.len = sizeof(allmulti);
- ioc.set = TRUE;
-
- ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len);
- if (ret < 0) {
- DHD_ERROR(("%s: set promisc %d failed\n",
- dhd_ifname(&dhd->pub, ifidx), ltoh32(allmulti)));
- }
-}
-
-int
-_dhd_set_mac_address(dhd_info_t *dhd, int ifidx, uint8 *addr)
-{
- char buf[32];
- wl_ioctl_t ioc;
- int ret;
-
- if (!bcm_mkiovar("cur_etheraddr", (char*)addr, ETHER_ADDR_LEN, buf, 32)) {
- DHD_ERROR(("%s: mkiovar failed for cur_etheraddr\n", dhd_ifname(&dhd->pub, ifidx)));
- return -1;
- }
- memset(&ioc, 0, sizeof(ioc));
- ioc.cmd = WLC_SET_VAR;
- ioc.buf = buf;
- ioc.len = 32;
- ioc.set = TRUE;
-
- ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len);
- if (ret < 0) {
- DHD_ERROR(("%s: set cur_etheraddr failed\n", dhd_ifname(&dhd->pub, ifidx)));
- } else {
- memcpy(dhd->iflist[ifidx]->net->dev_addr, addr, ETHER_ADDR_LEN);
- if (ifidx == 0)
- memcpy(dhd->pub.mac.octet, addr, ETHER_ADDR_LEN);
- }
-
- return ret;
-}
-
-#ifdef SOFTAP
-extern struct net_device *ap_net_dev;
-extern tsk_ctl_t ap_eth_ctl; /* ap netdev heper thread ctl */
-#endif
-
-static void
-dhd_ifadd_event_handler(void *handle, void *event_info, u8 event)
-{
- dhd_info_t *dhd = handle;
- dhd_if_event_t *if_event = event_info;
- struct net_device *ndev;
- int ifidx, bssidx;
- int ret;
-#if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
- struct wireless_dev *vwdev, *primary_wdev;
- struct net_device *primary_ndev;
-#endif /* OEM_ANDROID && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) */
-
- if (event != DHD_WQ_WORK_IF_ADD) {
- DHD_ERROR(("%s: unexpected event \n", __FUNCTION__));
- return;
- }
-
- if (!dhd) {
- DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__));
- return;
- }
-
- if (!if_event) {
- DHD_ERROR(("%s: event data is null \n", __FUNCTION__));
- return;
- }
-
- dhd_net_if_lock_local(dhd);
- DHD_OS_WAKE_LOCK(&dhd->pub);
- DHD_PERIM_LOCK(&dhd->pub);
-
- ifidx = if_event->event.ifidx;
- bssidx = if_event->event.bssidx;
- DHD_TRACE(("%s: registering if with ifidx %d\n", __FUNCTION__, ifidx));
-
- ndev = dhd_allocate_if(&dhd->pub, ifidx, if_event->name,
- if_event->mac, bssidx, TRUE);
- if (!ndev) {
- DHD_ERROR(("%s: net device alloc failed \n", __FUNCTION__));
- goto done;
- }
-
-#if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
- vwdev = kzalloc(sizeof(*vwdev), GFP_KERNEL);
- if (unlikely(!vwdev)) {
- WL_ERR(("Could not allocate wireless device\n"));
- goto done;
- }
- primary_ndev = dhd->pub.info->iflist[0]->net;
- primary_wdev = ndev_to_wdev(primary_ndev);
- vwdev->wiphy = primary_wdev->wiphy;
- vwdev->iftype = if_event->event.role;
- vwdev->netdev = ndev;
- ndev->ieee80211_ptr = vwdev;
- SET_NETDEV_DEV(ndev, wiphy_dev(vwdev->wiphy));
- DHD_ERROR(("virtual interface(%s) is created\n", if_event->name));
-#endif /* OEM_ANDROID && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) */
-
- DHD_PERIM_UNLOCK(&dhd->pub);
- ret = dhd_register_if(&dhd->pub, ifidx, TRUE);
- DHD_PERIM_LOCK(&dhd->pub);
- if (ret != BCME_OK) {
- DHD_ERROR(("%s: dhd_register_if failed\n", __FUNCTION__));
- dhd_remove_if(&dhd->pub, ifidx, TRUE);
- }
-#ifdef PCIE_FULL_DONGLE
- /* Turn on AP isolation in the firmware for interfaces operating in AP mode */
- if (FW_SUPPORTED((&dhd->pub), ap) && (if_event->event.role != WLC_E_IF_ROLE_STA)) {
- char iovbuf[WLC_IOCTL_SMLEN];
- uint32 var_int = 1;
-
- memset(iovbuf, 0, sizeof(iovbuf));
- bcm_mkiovar("ap_isolate", (char *)&var_int, 4, iovbuf, sizeof(iovbuf));
- dhd_wl_ioctl_cmd(&dhd->pub, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, ifidx);
- }
-#endif /* PCIE_FULL_DONGLE */
-done:
- MFREE(dhd->pub.osh, if_event, sizeof(dhd_if_event_t));
-
- DHD_PERIM_UNLOCK(&dhd->pub);
- DHD_OS_WAKE_UNLOCK(&dhd->pub);
- dhd_net_if_unlock_local(dhd);
-}
-
-static void
-dhd_ifdel_event_handler(void *handle, void *event_info, u8 event)
-{
- dhd_info_t *dhd = handle;
- int ifidx;
- dhd_if_event_t *if_event = event_info;
-
-
- if (event != DHD_WQ_WORK_IF_DEL) {
- DHD_ERROR(("%s: unexpected event \n", __FUNCTION__));
- return;
- }
-
- if (!dhd) {
- DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__));
- return;
- }
-
- if (!if_event) {
- DHD_ERROR(("%s: event data is null \n", __FUNCTION__));
- return;
- }
-
- dhd_net_if_lock_local(dhd);
- DHD_OS_WAKE_LOCK(&dhd->pub);
- DHD_PERIM_LOCK(&dhd->pub);
-
- ifidx = if_event->event.ifidx;
- DHD_TRACE(("Removing interface with idx %d\n", ifidx));
-
- dhd_remove_if(&dhd->pub, ifidx, TRUE);
-
- MFREE(dhd->pub.osh, if_event, sizeof(dhd_if_event_t));
-
- DHD_PERIM_UNLOCK(&dhd->pub);
- DHD_OS_WAKE_UNLOCK(&dhd->pub);
- dhd_net_if_unlock_local(dhd);
-}
-
-static void
-dhd_set_mac_addr_handler(void *handle, void *event_info, u8 event)
-{
- dhd_info_t *dhd = handle;
- dhd_if_t *ifp = event_info;
-
- if (event != DHD_WQ_WORK_SET_MAC) {
- DHD_ERROR(("%s: unexpected event \n", __FUNCTION__));
- }
-
- if (!dhd) {
- DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__));
- return;
- }
-
- dhd_net_if_lock_local(dhd);
- DHD_OS_WAKE_LOCK(&dhd->pub);
- DHD_PERIM_LOCK(&dhd->pub);
-
-#ifdef SOFTAP
- {
- unsigned long flags;
- bool in_ap = FALSE;
- DHD_GENERAL_LOCK(&dhd->pub, flags);
- in_ap = (ap_net_dev != NULL);
- DHD_GENERAL_UNLOCK(&dhd->pub, flags);
-
- if (in_ap) {
- DHD_ERROR(("attempt to set MAC for %s in AP Mode, blocked. \n",
- ifp->net->name));
- goto done;
- }
- }
-#endif /* SOFTAP */
-
- if (ifp == NULL || !dhd->pub.up) {
- DHD_ERROR(("%s: interface info not available/down \n", __FUNCTION__));
- goto done;
- }
-
- DHD_ERROR(("%s: MACID is overwritten\n", __FUNCTION__));
- ifp->set_macaddress = FALSE;
- if (_dhd_set_mac_address(dhd, ifp->idx, ifp->mac_addr) == 0)
- DHD_INFO(("%s: MACID is overwritten\n", __FUNCTION__));
- else
- DHD_ERROR(("%s: _dhd_set_mac_address() failed\n", __FUNCTION__));
-
-done:
- DHD_PERIM_UNLOCK(&dhd->pub);
- DHD_OS_WAKE_UNLOCK(&dhd->pub);
- dhd_net_if_unlock_local(dhd);
-}
-
-static void
-dhd_set_mcast_list_handler(void *handle, void *event_info, u8 event)
-{
- dhd_info_t *dhd = handle;
- dhd_if_t *ifp = event_info;
- int ifidx;
-
- if (event != DHD_WQ_WORK_SET_MCAST_LIST) {
- DHD_ERROR(("%s: unexpected event \n", __FUNCTION__));
- return;
- }
-
- if (!dhd) {
- DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__));
- return;
- }
-
- dhd_net_if_lock_local(dhd);
- DHD_OS_WAKE_LOCK(&dhd->pub);
- DHD_PERIM_LOCK(&dhd->pub);
-
-#ifdef SOFTAP
- {
- bool in_ap = FALSE;
- unsigned long flags;
- DHD_GENERAL_LOCK(&dhd->pub, flags);
- in_ap = (ap_net_dev != NULL);
- DHD_GENERAL_UNLOCK(&dhd->pub, flags);
-
- if (in_ap) {
- DHD_ERROR(("set MULTICAST list for %s in AP Mode, blocked. \n",
- ifp->net->name));
- ifp->set_multicast = FALSE;
- goto done;
- }
- }
-#endif /* SOFTAP */
-
- if (ifp == NULL || !dhd->pub.up) {
- DHD_ERROR(("%s: interface info not available/down \n", __FUNCTION__));
- goto done;
- }
-
- ifidx = ifp->idx;
-
-
- _dhd_set_multicast_list(dhd, ifidx);
- DHD_INFO(("%s: set multicast list for if %d\n", __FUNCTION__, ifidx));
-
-done:
- DHD_PERIM_UNLOCK(&dhd->pub);
- DHD_OS_WAKE_UNLOCK(&dhd->pub);
- dhd_net_if_unlock_local(dhd);
-}
-
-static int
-dhd_set_mac_address(struct net_device *dev, void *addr)
-{
- int ret = 0;
-
- dhd_info_t *dhd = DHD_DEV_INFO(dev);
- struct sockaddr *sa = (struct sockaddr *)addr;
- int ifidx;
- dhd_if_t *dhdif;
-
- ifidx = dhd_net2idx(dhd, dev);
- if (ifidx == DHD_BAD_IF)
- return -1;
-
- dhdif = dhd->iflist[ifidx];
-
- dhd_net_if_lock_local(dhd);
- memcpy(dhdif->mac_addr, sa->sa_data, ETHER_ADDR_LEN);
- dhdif->set_macaddress = TRUE;
- dhd_net_if_unlock_local(dhd);
- dhd_deferred_schedule_work(dhd->dhd_deferred_wq, (void *)dhdif, DHD_WQ_WORK_SET_MAC,
- dhd_set_mac_addr_handler, DHD_WORK_PRIORITY_LOW);
- return ret;
-}
-
-static void
-dhd_set_multicast_list(struct net_device *dev)
-{
- dhd_info_t *dhd = DHD_DEV_INFO(dev);
- int ifidx;
-
- ifidx = dhd_net2idx(dhd, dev);
- if (ifidx == DHD_BAD_IF)
- return;
-
- dhd->iflist[ifidx]->set_multicast = TRUE;
- dhd_deferred_schedule_work(dhd->dhd_deferred_wq, (void *)dhd->iflist[ifidx],
- DHD_WQ_WORK_SET_MCAST_LIST, dhd_set_mcast_list_handler, DHD_WORK_PRIORITY_LOW);
-}
-
-#ifdef PROP_TXSTATUS
-int
-dhd_os_wlfc_block(dhd_pub_t *pub)
-{
- dhd_info_t *di = (dhd_info_t *)(pub->info);
- ASSERT(di != NULL);
- spin_lock_bh(&di->wlfc_spinlock);
- return 1;
-}
-
-int
-dhd_os_wlfc_unblock(dhd_pub_t *pub)
-{
- dhd_info_t *di = (dhd_info_t *)(pub->info);
-
- ASSERT(di != NULL);
- spin_unlock_bh(&di->wlfc_spinlock);
- return 1;
-}
-
-#endif /* PROP_TXSTATUS */
-
-int BCMFASTPATH
-dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf)
-{
- int ret = BCME_OK;
- dhd_info_t *dhd = (dhd_info_t *)(dhdp->info);
- struct ether_header *eh = NULL;
-
- /* Reject if down */
- if (!dhdp->up || (dhdp->busstate == DHD_BUS_DOWN)) {
- /* free the packet here since the caller won't */
- PKTFREE(dhdp->osh, pktbuf, TRUE);
- return -ENODEV;
- }
-
-#ifdef PCIE_FULL_DONGLE
- if (dhdp->busstate == DHD_BUS_SUSPEND) {
- DHD_ERROR(("%s : pcie is still in suspend state!!\n", __FUNCTION__));
- PKTFREE(dhdp->osh, pktbuf, TRUE);
- return -EBUSY;
- }
-#endif /* PCIE_FULL_DONGLE */
-
-#ifdef DHD_UNICAST_DHCP
- /* if dhcp_unicast is enabled, we need to convert the */
- /* broadcast DHCP ACK/REPLY packets to Unicast. */
- if (dhdp->dhcp_unicast) {
- dhd_convert_dhcp_broadcast_ack_to_unicast(dhdp, pktbuf, ifidx);
- }
-#endif /* DHD_UNICAST_DHCP */
- /* Update multicast statistic */
- if (PKTLEN(dhdp->osh, pktbuf) >= ETHER_HDR_LEN) {
- uint8 *pktdata = (uint8 *)PKTDATA(dhdp->osh, pktbuf);
- eh = (struct ether_header *)pktdata;
-
- if (ETHER_ISMULTI(eh->ether_dhost))
- dhdp->tx_multicast++;
- if (ntoh16(eh->ether_type) == ETHER_TYPE_802_1X)
- atomic_inc(&dhd->pend_8021x_cnt);
- } else {
- PKTFREE(dhd->pub.osh, pktbuf, TRUE);
- return BCME_ERROR;
- }
-
-#ifdef DHDTCPACK_SUPPRESS
- /* If this packet has replaced another packet and got freed, just return */
- if (dhd_tcpack_suppress(dhdp, pktbuf))
- return ret;
-#endif /* DHDTCPACK_SUPPRESS */
-
- /* Look into the packet and update the packet priority */
-#ifndef PKTPRIO_OVERRIDE
- if (PKTPRIO(pktbuf) == 0)
-#endif
- pktsetprio(pktbuf, FALSE);
-
-
-#ifdef PCIE_FULL_DONGLE
- /*
- * Lkup the per interface hash table, for a matching flowring. If one is not
- * available, allocate a unique flowid and add a flowring entry.
- * The found or newly created flowid is placed into the pktbuf's tag.
- */
- ret = dhd_flowid_update(dhdp, ifidx, dhdp->flow_prio_map[(PKTPRIO(pktbuf))], pktbuf);
- if (ret != BCME_OK) {
- PKTCFREE(dhd->pub.osh, pktbuf, TRUE);
- return ret;
- }
-#endif
-
-#ifdef PROP_TXSTATUS
- if (dhd_wlfc_is_supported(dhdp)) {
- /* store the interface ID */
- DHD_PKTTAG_SETIF(PKTTAG(pktbuf), ifidx);
-
- /* store destination MAC in the tag as well */
- DHD_PKTTAG_SETDSTN(PKTTAG(pktbuf), eh->ether_dhost);
-
- /* decide which FIFO this packet belongs to */
- if (ETHER_ISMULTI(eh->ether_dhost))
- /* one additional queue index (highest AC + 1) is used for bc/mc queue */
- DHD_PKTTAG_SETFIFO(PKTTAG(pktbuf), AC_COUNT);
- else
- DHD_PKTTAG_SETFIFO(PKTTAG(pktbuf), WME_PRIO2AC(PKTPRIO(pktbuf)));
- } else
-#endif /* PROP_TXSTATUS */
- /* If the protocol uses a data header, apply it */
- dhd_prot_hdrpush(dhdp, ifidx, pktbuf);
-
- /* Use bus module to send data frame */
-#ifdef WLMEDIA_HTSF
- dhd_htsf_addtxts(dhdp, pktbuf);
-#endif
-#ifdef PROP_TXSTATUS
- {
- if (dhd_wlfc_commit_packets(dhdp, (f_commitpkt_t)dhd_bus_txdata,
- dhdp->bus, pktbuf, TRUE) == WLFC_UNSUPPORTED) {
- /* non-proptxstatus way */
-#ifdef BCMPCIE
- ret = dhd_bus_txdata(dhdp->bus, pktbuf, (uint8)ifidx);
-#else
- ret = dhd_bus_txdata(dhdp->bus, pktbuf);
-#endif /* BCMPCIE */
- }
- }
-#else
-#ifdef BCMPCIE
- ret = dhd_bus_txdata(dhdp->bus, pktbuf, (uint8)ifidx);
-#else
- ret = dhd_bus_txdata(dhdp->bus, pktbuf);
-#endif /* BCMPCIE */
-#endif /* PROP_TXSTATUS */
-
- return ret;
-}
-
-int BCMFASTPATH
-dhd_start_xmit(struct sk_buff *skb, struct net_device *net)
-{
- int ret;
- uint datalen;
- void *pktbuf;
- dhd_info_t *dhd = DHD_DEV_INFO(net);
- dhd_if_t *ifp = NULL;
- int ifidx;
-#ifdef WLMEDIA_HTSF
- uint8 htsfdlystat_sz = dhd->pub.htsfdlystat_sz;
-#else
- uint8 htsfdlystat_sz = 0;
-#endif
-#ifdef DHD_WMF
- struct ether_header *eh;
- uint8 *iph;
-#endif /* DHD_WMF */
-
- DHD_TRACE(("%s: Enter\n", __FUNCTION__));
-
- DHD_OS_WAKE_LOCK(&dhd->pub);
- DHD_PERIM_LOCK_TRY(DHD_FWDER_UNIT(dhd), TRUE);
-
- /* Reject if down */
- if (dhd->pub.busstate == DHD_BUS_DOWN || dhd->pub.hang_was_sent) {
- DHD_ERROR(("%s: xmit rejected pub.up=%d busstate=%d \n",
- __FUNCTION__, dhd->pub.up, dhd->pub.busstate));
- netif_stop_queue(net);
- /* Send Event when bus down detected during data session */
- if (dhd->pub.up) {
- DHD_ERROR(("%s: Event HANG sent up\n", __FUNCTION__));
- net_os_send_hang_message(net);
- }
- DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), TRUE);
- DHD_OS_WAKE_UNLOCK(&dhd->pub);
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20))
- return -ENODEV;
-#else
- return NETDEV_TX_BUSY;
-#endif
- }
-
- ifp = DHD_DEV_IFP(net);
- ifidx = DHD_DEV_IFIDX(net);
-
- ASSERT(ifidx == dhd_net2idx(dhd, net));
- ASSERT((ifp != NULL) && (ifp == dhd->iflist[ifidx]));
-
- if (ifidx == DHD_BAD_IF) {
- DHD_ERROR(("%s: bad ifidx %d\n", __FUNCTION__, ifidx));
- netif_stop_queue(net);
- DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), TRUE);
- DHD_OS_WAKE_UNLOCK(&dhd->pub);
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20))
- return -ENODEV;
-#else
- return NETDEV_TX_BUSY;
-#endif
- }
-
- /* re-align socket buffer if "skb->data" is odd address */
- if (((unsigned long)(skb->data)) & 0x1) {
- unsigned char *data = skb->data;
- uint32 length = skb->len;
- PKTPUSH(dhd->pub.osh, skb, 1);
- memmove(skb->data, data, length);
- PKTSETLEN(dhd->pub.osh, skb, length);
- }
-
- datalen = PKTLEN(dhd->pub.osh, skb);
-
- /* Make sure there's enough room for any header */
-
- if (skb_headroom(skb) < dhd->pub.hdrlen + htsfdlystat_sz) {
- struct sk_buff *skb2;
-
- DHD_INFO(("%s: insufficient headroom\n",
- dhd_ifname(&dhd->pub, ifidx)));
- dhd->pub.tx_realloc++;
-
- skb2 = skb_realloc_headroom(skb, dhd->pub.hdrlen + htsfdlystat_sz);
-
- dev_kfree_skb(skb);
- if ((skb = skb2) == NULL) {
- DHD_ERROR(("%s: skb_realloc_headroom failed\n",
- dhd_ifname(&dhd->pub, ifidx)));
- ret = -ENOMEM;
- goto done;
- }
- }
-
- /* Convert to packet */
- if (!(pktbuf = PKTFRMNATIVE(dhd->pub.osh, skb))) {
- DHD_ERROR(("%s: PKTFRMNATIVE failed\n",
- dhd_ifname(&dhd->pub, ifidx)));
- dev_kfree_skb_any(skb);
- ret = -ENOMEM;
- goto done;
- }
-#ifdef WLMEDIA_HTSF
- if (htsfdlystat_sz && PKTLEN(dhd->pub.osh, pktbuf) >= ETHER_ADDR_LEN) {
- uint8 *pktdata = (uint8 *)PKTDATA(dhd->pub.osh, pktbuf);
- struct ether_header *eh = (struct ether_header *)pktdata;
-
- if (!ETHER_ISMULTI(eh->ether_dhost) &&
- (ntoh16(eh->ether_type) == ETHER_TYPE_IP)) {
- eh->ether_type = hton16(ETHER_TYPE_BRCM_PKTDLYSTATS);
- }
- }
-#endif
-#ifdef DHD_WMF
- eh = (struct ether_header *)PKTDATA(dhd->pub.osh, pktbuf);
- iph = (uint8 *)eh + ETHER_HDR_LEN;
-
- /* WMF processing for multicast packets
- * Only IPv4 packets are handled
- */
- if (ifp->wmf.wmf_enable && (ntoh16(eh->ether_type) == ETHER_TYPE_IP) &&
- (IP_VER(iph) == IP_VER_4) && (ETHER_ISMULTI(eh->ether_dhost) ||
- ((IPV4_PROT(iph) == IP_PROT_IGMP) && dhd->pub.wmf_ucast_igmp))) {
-#if defined(DHD_IGMP_UCQUERY) || defined(DHD_UCAST_UPNP)
- void *sdu_clone;
- bool ucast_convert = FALSE;
-#ifdef DHD_UCAST_UPNP
- uint32 dest_ip;
-
- dest_ip = ntoh32(*((uint32 *)(iph + IPV4_DEST_IP_OFFSET)));
- ucast_convert = dhd->pub.wmf_ucast_upnp && MCAST_ADDR_UPNP_SSDP(dest_ip);
-#endif /* DHD_UCAST_UPNP */
-#ifdef DHD_IGMP_UCQUERY
- ucast_convert |= dhd->pub.wmf_ucast_igmp_query &&
- (IPV4_PROT(iph) == IP_PROT_IGMP) &&
- (*(iph + IPV4_HLEN(iph)) == IGMPV2_HOST_MEMBERSHIP_QUERY);
-#endif /* DHD_IGMP_UCQUERY */
- if (ucast_convert) {
- dhd_sta_t *sta;
- unsigned long flags;
-
- DHD_IF_STA_LIST_LOCK(ifp, flags);
-
- /* Convert upnp/igmp query to unicast for each assoc STA */
- list_for_each_entry(sta, &ifp->sta_list, list) {
- if ((sdu_clone = PKTDUP(dhd->pub.osh, pktbuf)) == NULL) {
- DHD_IF_STA_LIST_UNLOCK(ifp, flags);
- DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), TRUE);
- DHD_OS_WAKE_UNLOCK(&dhd->pub);
- return (WMF_NOP);
- }
- dhd_wmf_forward(ifp->wmf.wmfh, sdu_clone, 0, sta, 1);
- }
-
- DHD_IF_STA_LIST_UNLOCK(ifp, flags);
- DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), TRUE);
- DHD_OS_WAKE_UNLOCK(&dhd->pub);
-
- PKTFREE(dhd->pub.osh, pktbuf, TRUE);
- return NETDEV_TX_OK;
- } else
-#endif /* defined(DHD_IGMP_UCQUERY) || defined(DHD_UCAST_UPNP) */
- {
- /* There will be no STA info if the packet is coming from LAN host
- * Pass as NULL
- */
- ret = dhd_wmf_packets_handle(&dhd->pub, pktbuf, NULL, ifidx, 0);
- switch (ret) {
- case WMF_TAKEN:
- case WMF_DROP:
- /* Either taken by WMF or we should drop it.
- * Exiting send path
- */
- DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), TRUE);
- DHD_OS_WAKE_UNLOCK(&dhd->pub);
- return NETDEV_TX_OK;
- default:
- /* Continue the transmit path */
- break;
- }
- }
- }
-#endif /* DHD_WMF */
-
- ret = dhd_sendpkt(&dhd->pub, ifidx, pktbuf);
-
-done:
- if (ret) {
- ifp->stats.tx_dropped++;
- dhd->pub.tx_dropped++;
- }
- else {
- dhd->pub.tx_packets++;
- ifp->stats.tx_packets++;
- ifp->stats.tx_bytes += datalen;
- }
-
- DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), TRUE);
- DHD_OS_WAKE_UNLOCK(&dhd->pub);
-
- /* Return ok: we always eat the packet */
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20))
- return 0;
-#else
- return NETDEV_TX_OK;
-#endif
-}
-
-
-void
-dhd_txflowcontrol(dhd_pub_t *dhdp, int ifidx, bool state)
-{
- struct net_device *net;
- dhd_info_t *dhd = dhdp->info;
- int i;
-
- DHD_TRACE(("%s: Enter\n", __FUNCTION__));
-
- ASSERT(dhd);
-
- if (ifidx == ALL_INTERFACES) {
- /* Flow control on all active interfaces */
- dhdp->txoff = state;
- for (i = 0; i < DHD_MAX_IFS; i++) {
- if (dhd->iflist[i]) {
- net = dhd->iflist[i]->net;
- if (state == ON)
- netif_stop_queue(net);
- else
- netif_wake_queue(net);
- }
- }
- }
- else {
- if (dhd->iflist[ifidx]) {
- net = dhd->iflist[ifidx]->net;
- if (state == ON)
- netif_stop_queue(net);
- else
- netif_wake_queue(net);
- }
- }
-}
-
-#ifdef DHD_RX_DUMP
-typedef struct {
- uint16 type;
- const char *str;
-} PKTTYPE_INFO;
-
-static const PKTTYPE_INFO packet_type_info[] =
-{
- { ETHER_TYPE_IP, "IP" },
- { ETHER_TYPE_ARP, "ARP" },
- { ETHER_TYPE_BRCM, "BRCM" },
- { ETHER_TYPE_802_1X, "802.1X" },
- { ETHER_TYPE_WAI, "WAPI" },
- { 0, ""}
-};
-
-static const char *_get_packet_type_str(uint16 type)
-{
- int i;
- int n = sizeof(packet_type_info)/sizeof(packet_type_info[1]) - 1;
-
- for (i = 0; i < n; i++) {
- if (packet_type_info[i].type == type)
- return packet_type_info[i].str;
- }
-
- return packet_type_info[n].str;
-}
-#endif /* DHD_RX_DUMP */
-
-
-#ifdef DHD_WMF
-bool
-dhd_is_rxthread_enabled(dhd_pub_t *dhdp)
-{
- dhd_info_t *dhd = dhdp->info;
-
- return dhd->rxthread_enabled;
-}
-#endif /* DHD_WMF */
-
-void
-dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan)
-{
- dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
- struct sk_buff *skb;
- uchar *eth;
- uint len;
- void *data, *pnext = NULL;
- int i;
- dhd_if_t *ifp;
- wl_event_msg_t event;
- int tout_rx = 0;
- int tout_ctrl = 0;
- void *skbhead = NULL;
- void *skbprev = NULL;
-#if defined(DHD_RX_DUMP) || defined(DHD_8021X_DUMP)
- char *dump_data;
- uint16 protocol;
-#endif /* DHD_RX_DUMP || DHD_8021X_DUMP */
-
- DHD_TRACE(("%s: Enter\n", __FUNCTION__));
-
- for (i = 0; pktbuf && i < numpkt; i++, pktbuf = pnext) {
- struct ether_header *eh;
-#ifdef WLBTAMP
- struct dot11_llc_snap_header *lsh;
-#endif
-
- pnext = PKTNEXT(dhdp->osh, pktbuf);
- PKTSETNEXT(dhdp->osh, pktbuf, NULL);
-
- ifp = dhd->iflist[ifidx];
- if (ifp == NULL) {
- DHD_ERROR(("%s: ifp is NULL. drop packet\n",
- __FUNCTION__));
- PKTCFREE(dhdp->osh, pktbuf, FALSE);
- continue;
- }
-
- eh = (struct ether_header *)PKTDATA(dhdp->osh, pktbuf);
-
- /* Dropping only data packets before registering net device to avoid kernel panic */
-#ifndef PROP_TXSTATUS_VSDB
- if ((!ifp->net || ifp->net->reg_state != NETREG_REGISTERED) &&
- (ntoh16(eh->ether_type) != ETHER_TYPE_BRCM))
-#else
- if ((!ifp->net || ifp->net->reg_state != NETREG_REGISTERED || !dhd->pub.up) &&
- (ntoh16(eh->ether_type) != ETHER_TYPE_BRCM))
-#endif /* PROP_TXSTATUS_VSDB */
- {
- DHD_ERROR(("%s: net device is NOT registered yet. drop packet\n",
- __FUNCTION__));
- PKTCFREE(dhdp->osh, pktbuf, FALSE);
- continue;
- }
-
-#ifdef WLBTAMP
- lsh = (struct dot11_llc_snap_header *)&eh[1];
-
- if ((ntoh16(eh->ether_type) < ETHER_TYPE_MIN) &&
- (PKTLEN(dhdp->osh, pktbuf) >= RFC1042_HDR_LEN) &&
- bcmp(lsh, BT_SIG_SNAP_MPROT, DOT11_LLC_SNAP_HDR_LEN - 2) == 0 &&
- lsh->type == HTON16(BTA_PROT_L2CAP)) {
- amp_hci_ACL_data_t *ACL_data = (amp_hci_ACL_data_t *)
- ((uint8 *)eh + RFC1042_HDR_LEN);
- ACL_data = NULL;
- }
-#endif /* WLBTAMP */
-
-#ifdef PROP_TXSTATUS
- if (dhd_wlfc_is_header_only_pkt(dhdp, pktbuf)) {
- /* WLFC may send header only packet when
- there is an urgent message but no packet to
- piggy-back on
- */
- PKTCFREE(dhdp->osh, pktbuf, FALSE);
- continue;
- }
-#endif
-#ifdef DHD_L2_FILTER
- /* If block_ping is enabled drop the ping packet */
- if (dhdp->block_ping) {
- if (dhd_l2_filter_block_ping(dhdp, pktbuf, ifidx) == BCME_OK) {
- PKTFREE(dhdp->osh, pktbuf, FALSE);
- continue;
- }
- }
-#endif
-#ifdef DHD_WMF
- /* WMF processing for multicast packets */
- if (ifp->wmf.wmf_enable && (ETHER_ISMULTI(eh->ether_dhost))) {
- dhd_sta_t *sta;
- int ret;
-
- sta = dhd_find_sta(dhdp, ifidx, (void *)eh->ether_shost);
- ret = dhd_wmf_packets_handle(dhdp, pktbuf, sta, ifidx, 1);
- switch (ret) {
- case WMF_TAKEN:
- /* The packet is taken by WMF. Continue to next iteration */
- continue;
- case WMF_DROP:
- /* Packet DROP decision by WMF. Toss it */
- DHD_ERROR(("%s: WMF decides to drop packet\n",
- __FUNCTION__));
- PKTCFREE(dhdp->osh, pktbuf, FALSE);
- continue;
- default:
- /* Continue the transmit path */
- break;
- }
- }
-#endif /* DHD_WMF */
-#ifdef DHDTCPACK_SUPPRESS
- dhd_tcpdata_info_get(dhdp, pktbuf);
-#endif
- skb = PKTTONATIVE(dhdp->osh, pktbuf);
-
- ifp = dhd->iflist[ifidx];
- if (ifp == NULL)
- ifp = dhd->iflist[0];
-
- ASSERT(ifp);
- skb->dev = ifp->net;
-
-#ifdef PCIE_FULL_DONGLE
- if ((DHD_IF_ROLE_AP(dhdp, ifidx) || DHD_IF_ROLE_P2PGO(dhdp, ifidx)) &&
- (!ifp->ap_isolate)) {
- eh = (struct ether_header *)PKTDATA(dhdp->osh, pktbuf);
- if (ETHER_ISUCAST(eh->ether_dhost)) {
- if (dhd_find_sta(dhdp, ifidx, (void *)eh->ether_dhost)) {
- dhd_sendpkt(dhdp, ifidx, pktbuf);
- continue;
- }
- } else {
- void *npktbuf = PKTDUP(dhdp->osh, pktbuf);
- dhd_sendpkt(dhdp, ifidx, npktbuf);
- }
- }
-#endif /* PCIE_FULL_DONGLE */
-
- /* Get the protocol, maintain skb around eth_type_trans()
- * The main reason for this hack is for the limitation of
- * Linux 2.4 where 'eth_type_trans' uses the 'net->hard_header_len'
- * to perform skb_pull inside vs ETH_HLEN. Since to avoid
- * coping of the packet coming from the network stack to add
- * BDC, Hardware header etc, during network interface registration
- * we set the 'net->hard_header_len' to ETH_HLEN + extra space required
- * for BDC, Hardware header etc. and not just the ETH_HLEN
- */
- eth = skb->data;
- len = skb->len;
-
-#if defined(DHD_RX_DUMP) || defined(DHD_8021X_DUMP)
- dump_data = skb->data;
- protocol = (dump_data[12] << 8) | dump_data[13];
-
- 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]));
- }
-#endif /* DHD_RX_DUMP || DHD_8021X_DUMP */
-#if defined(DHD_RX_DUMP)
- DHD_ERROR(("RX DUMP - %s\n", _get_packet_type_str(protocol)));
- if (protocol != ETHER_TYPE_BRCM) {
- if (dump_data[0] == 0xFF) {
- DHD_ERROR(("%s: BROADCAST\n", __FUNCTION__));
-
- if ((dump_data[12] == 8) &&
- (dump_data[13] == 6)) {
- DHD_ERROR(("%s: ARP %d\n",
- __FUNCTION__, dump_data[0x15]));
- }
- } else if (dump_data[0] & 1) {
- DHD_ERROR(("%s: MULTICAST: " MACDBG "\n",
- __FUNCTION__, MAC2STRDBG(dump_data)));
- }
-#ifdef DHD_RX_FULL_DUMP
- {
- int k;
- for (k = 0; k < skb->len; k++) {
- DHD_ERROR(("%02X ", dump_data[k]));
- if ((k & 15) == 15)
- DHD_ERROR(("\n"));
- }
- DHD_ERROR(("\n"));
- }
-#endif /* DHD_RX_FULL_DUMP */
- }
-#endif /* DHD_RX_DUMP */
-
- skb->protocol = eth_type_trans(skb, skb->dev);
-
- if (skb->pkt_type == PACKET_MULTICAST) {
- dhd->pub.rx_multicast++;
- ifp->stats.multicast++;
- }
-
- skb->data = eth;
- skb->len = len;
-
-#ifdef WLMEDIA_HTSF
- dhd_htsf_addrxts(dhdp, pktbuf);
-#endif
- /* Strip header, count, deliver upward */
- skb_pull(skb, ETH_HLEN);
-
- /* Process special event packets and then discard them */
- memset(&event, 0, sizeof(event));
- if (ntoh16(skb->protocol) == ETHER_TYPE_BRCM) {
- dhd_wl_host_event(dhd, &ifidx,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
- skb_mac_header(skb),
-#else
- skb->mac.raw,
-#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) */
- &event,
- &data);
-
- wl_event_to_host_order(&event);
- if (!tout_ctrl)
- tout_ctrl = DHD_PACKET_TIMEOUT_MS;
-#ifdef WLBTAMP
- if (event.event_type == WLC_E_BTA_HCI_EVENT) {
- dhd_bta_doevt(dhdp, data, event.datalen);
- }
-#endif /* WLBTAMP */
-
-#if defined(PNO_SUPPORT)
- if (event.event_type == WLC_E_PFN_NET_FOUND) {
- /* enforce custom wake lock to garantee that Kernel not suspended */
- tout_ctrl = CUSTOM_PNO_EVENT_LOCK_xTIME * DHD_PACKET_TIMEOUT_MS;
- }
-#endif /* PNO_SUPPORT */
-
-#ifdef DHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT
- PKTFREE(dhdp->osh, pktbuf, FALSE);
- continue;
-#endif /* DHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT */
- } else {
- tout_rx = DHD_PACKET_TIMEOUT_MS;
-
-#ifdef PROP_TXSTATUS
- dhd_wlfc_save_rxpath_ac_time(dhdp, (uint8)PKTPRIO(skb));
-#endif /* PROP_TXSTATUS */
- }
-
- ASSERT(ifidx < DHD_MAX_IFS && dhd->iflist[ifidx]);
- ifp = dhd->iflist[ifidx];
-
- if (ifp->net)
- ifp->net->last_rx = jiffies;
-
- if (ntoh16(skb->protocol) != ETHER_TYPE_BRCM) {
- dhdp->dstats.rx_bytes += skb->len;
- dhdp->rx_packets++; /* Local count */
- ifp->stats.rx_bytes += skb->len;
- ifp->stats.rx_packets++;
- }
-#if defined(DHD_TCP_WINSIZE_ADJUST)
- if (dhd_use_tcp_window_size_adjust) {
- if (ifidx == 0 && ntoh16(skb->protocol) == ETHER_TYPE_IP) {
- dhd_adjust_tcp_winsize(dhdp->op_mode, skb);
- }
- }
-#endif /* DHD_TCP_WINSIZE_ADJUST */
-
- if (in_interrupt()) {
- netif_rx(skb);
- } else {
- if (dhd->rxthread_enabled) {
- if (!skbhead)
- skbhead = skb;
- else
- PKTSETNEXT(dhdp->osh, skbprev, skb);
- skbprev = skb;
- } else {
-
- /* If the receive is not processed inside an ISR,
- * the softirqd must be woken explicitly to service
- * the NET_RX_SOFTIRQ. In 2.6 kernels, this is handled
- * by netif_rx_ni(), but in earlier kernels, we need
- * to do it manually.
- */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
- netif_rx_ni(skb);
-#else
- ulong flags;
- netif_rx(skb);
- local_irq_save(flags);
- RAISE_RX_SOFTIRQ();
- local_irq_restore(flags);
-#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */
- }
- }
- }
-
- if (dhd->rxthread_enabled && skbhead)
- dhd_sched_rxf(dhdp, skbhead);
-
- DHD_OS_WAKE_LOCK_RX_TIMEOUT_ENABLE(dhdp, tout_rx);
- DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(dhdp, tout_ctrl);
-}
-
-void
-dhd_event(struct dhd_info *dhd, char *evpkt, int evlen, int ifidx)
-{
- /* Linux version has nothing to do */
- return;
-}
-
-void
-dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success)
-{
- dhd_info_t *dhd = (dhd_info_t *)(dhdp->info);
- struct ether_header *eh;
- uint16 type;
-#ifdef WLBTAMP
- uint len;
-#endif
-
- dhd_prot_hdrpull(dhdp, NULL, txp, NULL, NULL);
-
- eh = (struct ether_header *)PKTDATA(dhdp->osh, txp);
- type = ntoh16(eh->ether_type);
-
- if (type == ETHER_TYPE_802_1X)
- atomic_dec(&dhd->pend_8021x_cnt);
-
-#ifdef WLBTAMP
- /* Crack open the packet and check to see if it is BT HCI ACL data packet.
- * If yes generate packet completion event.
- */
- len = PKTLEN(dhdp->osh, txp);
-
- /* Generate ACL data tx completion event locally to avoid SDIO bus transaction */
- if ((type < ETHER_TYPE_MIN) && (len >= RFC1042_HDR_LEN)) {
- struct dot11_llc_snap_header *lsh = (struct dot11_llc_snap_header *)&eh[1];
-
- if (bcmp(lsh, BT_SIG_SNAP_MPROT, DOT11_LLC_SNAP_HDR_LEN - 2) == 0 &&
- ntoh16(lsh->type) == BTA_PROT_L2CAP) {
-
- dhd_bta_tx_hcidata_complete(dhdp, txp, success);
- }
- }
-#endif /* WLBTAMP */
-}
-
-static struct net_device_stats *
-dhd_get_stats(struct net_device *net)
-{
- dhd_info_t *dhd = DHD_DEV_INFO(net);
- dhd_if_t *ifp;
- int ifidx;
-
- DHD_TRACE(("%s: Enter\n", __FUNCTION__));
-
- ifidx = dhd_net2idx(dhd, net);
- if (ifidx == DHD_BAD_IF) {
- DHD_ERROR(("%s: BAD_IF\n", __FUNCTION__));
-
- memset(&net->stats, 0, sizeof(net->stats));
- return &net->stats;
- }
-
- ifp = dhd->iflist[ifidx];
- ASSERT(dhd && ifp);
-
- if (dhd->pub.up) {
- /* Use the protocol to get dongle stats */
- dhd_prot_dstats(&dhd->pub);
- }
- return &ifp->stats;
-}
-
-static int
-dhd_watchdog_thread(void *data)
-{
- tsk_ctl_t *tsk = (tsk_ctl_t *)data;
- dhd_info_t *dhd = (dhd_info_t *)tsk->parent;
- /* This thread doesn't need any user-level access,
- * so get rid of all our resources
- */
- if (dhd_watchdog_prio > 0) {
- struct sched_param param;
- param.sched_priority = (dhd_watchdog_prio < MAX_RT_PRIO)?
- dhd_watchdog_prio:(MAX_RT_PRIO-1);
- setScheduler(current, SCHED_FIFO, &param);
- }
-
- while (1)
- if (down_interruptible (&tsk->sema) == 0) {
- unsigned long flags;
- unsigned long jiffies_at_start = jiffies;
- unsigned long time_lapse;
-
- SMP_RD_BARRIER_DEPENDS();
- if (tsk->terminated) {
- break;
- }
-
- if (dhd->pub.dongle_reset == FALSE) {
- DHD_TIMER(("%s:\n", __FUNCTION__));
-
- /* Call the bus module watchdog */
- dhd_bus_watchdog(&dhd->pub);
-
-
- DHD_GENERAL_LOCK(&dhd->pub, flags);
- /* Count the tick for reference */
- dhd->pub.tickcnt++;
- time_lapse = jiffies - jiffies_at_start;
-
- /* Reschedule the watchdog */
- if (dhd->wd_timer_valid)
- mod_timer(&dhd->timer,
- jiffies +
- msecs_to_jiffies(dhd_watchdog_ms) -
- min(msecs_to_jiffies(dhd_watchdog_ms), time_lapse));
- DHD_GENERAL_UNLOCK(&dhd->pub, flags);
- }
- } else {
- break;
- }
-
- complete_and_exit(&tsk->completed, 0);
-}
-
-static void dhd_watchdog(ulong data)
-{
- dhd_info_t *dhd = (dhd_info_t *)data;
- unsigned long flags;
-
- if (dhd->pub.dongle_reset) {
- return;
- }
-
- if (dhd->thr_wdt_ctl.thr_pid >= 0) {
- up(&dhd->thr_wdt_ctl.sema);
- return;
- }
-
- /* Call the bus module watchdog */
- dhd_bus_watchdog(&dhd->pub);
-
- DHD_GENERAL_LOCK(&dhd->pub, flags);
- /* Count the tick for reference */
- dhd->pub.tickcnt++;
-
- /* Reschedule the watchdog */
- if (dhd->wd_timer_valid)
- mod_timer(&dhd->timer, jiffies + msecs_to_jiffies(dhd_watchdog_ms));
- DHD_GENERAL_UNLOCK(&dhd->pub, flags);
-
-}
-
-#ifdef ENABLE_ADAPTIVE_SCHED
-static void
-dhd_sched_policy(int prio)
-{
- struct sched_param param;
- if (cpufreq_quick_get(0) <= CUSTOM_CPUFREQ_THRESH) {
- param.sched_priority = 0;
- setScheduler(current, SCHED_NORMAL, &param);
- } else {
- if (get_scheduler_policy(current) != SCHED_FIFO) {
- param.sched_priority = (prio < MAX_RT_PRIO)? prio : (MAX_RT_PRIO-1);
- setScheduler(current, SCHED_FIFO, &param);
- }
- }
-}
-#endif /* ENABLE_ADAPTIVE_SCHED */
-#ifdef DEBUG_CPU_FREQ
-static int dhd_cpufreq_notifier(struct notifier_block *nb, unsigned long val, void *data)
-{
- dhd_info_t *dhd = container_of(nb, struct dhd_info, freq_trans);
- struct cpufreq_freqs *freq = data;
- if (dhd) {
- if (!dhd->new_freq)
- goto exit;
- if (val == CPUFREQ_POSTCHANGE) {
- DHD_ERROR(("cpu freq is changed to %u kHZ on CPU %d\n",
- freq->new, freq->cpu));
- *per_cpu_ptr(dhd->new_freq, freq->cpu) = freq->new;
- }
- }
-exit:
- return 0;
-}
-#endif /* DEBUG_CPU_FREQ */
-static int
-dhd_dpc_thread(void *data)
-{
- tsk_ctl_t *tsk = (tsk_ctl_t *)data;
- dhd_info_t *dhd = (dhd_info_t *)tsk->parent;
-
- /* This thread doesn't need any user-level access,
- * so get rid of all our resources
- */
- if (dhd_dpc_prio > 0)
- {
- struct sched_param param;
- param.sched_priority = (dhd_dpc_prio < MAX_RT_PRIO)?dhd_dpc_prio:(MAX_RT_PRIO-1);
- setScheduler(current, SCHED_FIFO, &param);
- }
-
-#ifdef CUSTOM_DPC_CPUCORE
- set_cpus_allowed_ptr(current, cpumask_of(CUSTOM_DPC_CPUCORE));
-#endif
-#ifdef CUSTOM_SET_CPUCORE
- dhd->pub.current_dpc = current;
-#endif /* CUSTOM_SET_CPUCORE */
-
- /* Run until signal received */
- while (1) {
- if (!binary_sema_down(tsk)) {
-#ifdef ENABLE_ADAPTIVE_SCHED
- dhd_sched_policy(dhd_dpc_prio);
-#endif /* ENABLE_ADAPTIVE_SCHED */
- SMP_RD_BARRIER_DEPENDS();
- if (tsk->terminated) {
- break;
- }
-
- /* Call bus dpc unless it indicated down (then clean stop) */
- if (dhd->pub.busstate != DHD_BUS_DOWN) {
- dhd_os_wd_timer_extend(&dhd->pub, TRUE);
- while (dhd_bus_dpc(dhd->pub.bus)) {
- /* process all data */
- }
- dhd_os_wd_timer_extend(&dhd->pub, FALSE);
- DHD_OS_WAKE_UNLOCK(&dhd->pub);
-
- } else {
- if (dhd->pub.up)
- dhd_bus_stop(dhd->pub.bus, TRUE);
- DHD_OS_WAKE_UNLOCK(&dhd->pub);
- }
- }
- else
- break;
- }
-
- complete_and_exit(&tsk->completed, 0);
-}
-
-static int
-dhd_rxf_thread(void *data)
-{
- tsk_ctl_t *tsk = (tsk_ctl_t *)data;
- dhd_info_t *dhd = (dhd_info_t *)tsk->parent;
-#if defined(WAIT_DEQUEUE)
-#define RXF_WATCHDOG_TIME 250 /* BARK_TIME(1000) / */
- ulong watchdogTime = OSL_SYSUPTIME(); /* msec */
-#endif
- dhd_pub_t *pub = &dhd->pub;
-
- /* This thread doesn't need any user-level access,
- * so get rid of all our resources
- */
- if (dhd_rxf_prio > 0)
- {
- struct sched_param param;
- param.sched_priority = (dhd_rxf_prio < MAX_RT_PRIO)?dhd_rxf_prio:(MAX_RT_PRIO-1);
- setScheduler(current, SCHED_FIFO, &param);
- }
-
- DAEMONIZE("dhd_rxf");
- /* DHD_OS_WAKE_LOCK is called in dhd_sched_dpc[dhd_linux.c] down below */
-
- /* signal: thread has started */
- complete(&tsk->completed);
-#ifdef CUSTOM_SET_CPUCORE
- dhd->pub.current_rxf = current;
-#endif /* CUSTOM_SET_CPUCORE */
-
- /* Run until signal received */
- while (1) {
- if (down_interruptible(&tsk->sema) == 0) {
- void *skb;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
- ulong flags;
-#endif
-#ifdef ENABLE_ADAPTIVE_SCHED
- dhd_sched_policy(dhd_rxf_prio);
-#endif /* ENABLE_ADAPTIVE_SCHED */
-
- SMP_RD_BARRIER_DEPENDS();
-
- if (tsk->terminated) {
- break;
- }
- skb = dhd_rxf_dequeue(pub);
-
- if (skb == NULL) {
- continue;
- }
- while (skb) {
- void *skbnext = PKTNEXT(pub->osh, skb);
- PKTSETNEXT(pub->osh, skb, NULL);
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
- netif_rx_ni(skb);
-#else
- netif_rx(skb);
- local_irq_save(flags);
- RAISE_RX_SOFTIRQ();
- local_irq_restore(flags);
-
-#endif
- skb = skbnext;
- }
-#if defined(WAIT_DEQUEUE)
- if (OSL_SYSUPTIME() - watchdogTime > RXF_WATCHDOG_TIME) {
- OSL_SLEEP(1);
- watchdogTime = OSL_SYSUPTIME();
- }
-#endif
-
- DHD_OS_WAKE_UNLOCK(pub);
- }
- else
- break;
- }
-
- complete_and_exit(&tsk->completed, 0);
-}
-
-#ifdef BCMPCIE
-void dhd_dpc_kill(dhd_pub_t *dhdp)
-{
- dhd_info_t *dhd;
-
- if (!dhdp)
- return;
-
- dhd = dhdp->info;
-
- if (!dhd)
- return;
-
- tasklet_kill(&dhd->tasklet);
- DHD_ERROR(("%s: tasklet disabled\n", __FUNCTION__));
-}
-#endif /* BCMPCIE */
-
-static void
-dhd_dpc(ulong data)
-{
- dhd_info_t *dhd;
-
- dhd = (dhd_info_t *)data;
-
- /* this (tasklet) can be scheduled in dhd_sched_dpc[dhd_linux.c]
- * down below , wake lock is set,
- * the tasklet is initialized in dhd_attach()
- */
- /* Call bus dpc unless it indicated down (then clean stop) */
- if (dhd->pub.busstate != DHD_BUS_DOWN) {
- if (dhd_bus_dpc(dhd->pub.bus))
- tasklet_schedule(&dhd->tasklet);
- else
- DHD_OS_WAKE_UNLOCK(&dhd->pub);
- } else {
- dhd_bus_stop(dhd->pub.bus, TRUE);
- DHD_OS_WAKE_UNLOCK(&dhd->pub);
- }
-}
-
-void
-dhd_sched_dpc(dhd_pub_t *dhdp)
-{
- dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
-
- DHD_OS_WAKE_LOCK(dhdp);
- if (dhd->thr_dpc_ctl.thr_pid >= 0) {
- /* If the semaphore does not get up,
- * wake unlock should be done here
- */
- if (!binary_sema_up(&dhd->thr_dpc_ctl))
- DHD_OS_WAKE_UNLOCK(dhdp);
- return;
- } else {
- tasklet_schedule(&dhd->tasklet);
- }
-}
-
-static void
-dhd_sched_rxf(dhd_pub_t *dhdp, void *skb)
-{
- dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
-#ifdef RXF_DEQUEUE_ON_BUSY
- int ret = BCME_OK;
- int retry = 2;
-#endif /* RXF_DEQUEUE_ON_BUSY */
-
- DHD_OS_WAKE_LOCK(dhdp);
-
- DHD_TRACE(("dhd_sched_rxf: Enter\n"));
-#ifdef RXF_DEQUEUE_ON_BUSY
- do {
- ret = dhd_rxf_enqueue(dhdp, skb);
- if (ret == BCME_OK || ret == BCME_ERROR)
- break;
- else
- OSL_SLEEP(50); /* waiting for dequeueing */
- } while (retry-- > 0);
-
- if (retry <= 0 && ret == BCME_BUSY) {
- void *skbp = skb;
-
- while (skbp) {
- void *skbnext = PKTNEXT(dhdp->osh, skbp);
- PKTSETNEXT(dhdp->osh, skbp, NULL);
- netif_rx_ni(skbp);
- skbp = skbnext;
- }
- DHD_ERROR(("send skb to kernel backlog without rxf_thread\n"));
- }
- else {
- if (dhd->thr_rxf_ctl.thr_pid >= 0) {
- up(&dhd->thr_rxf_ctl.sema);
- }
- }
-#else /* RXF_DEQUEUE_ON_BUSY */
- do {
- if (dhd_rxf_enqueue(dhdp, skb) == BCME_OK)
- break;
- } while (1);
- if (dhd->thr_rxf_ctl.thr_pid >= 0) {
- up(&dhd->thr_rxf_ctl.sema);
- }
- return;
-#endif /* RXF_DEQUEUE_ON_BUSY */
-}
-
-#ifdef TOE
-/* Retrieve current toe component enables, which are kept as a bitmap in toe_ol iovar */
-static int
-dhd_toe_get(dhd_info_t *dhd, int ifidx, uint32 *toe_ol)
-{
- wl_ioctl_t ioc;
- char buf[32];
- int ret;
-
- memset(&ioc, 0, sizeof(ioc));
-
- ioc.cmd = WLC_GET_VAR;
- ioc.buf = buf;
- ioc.len = (uint)sizeof(buf);
- ioc.set = FALSE;
-
- strncpy(buf, "toe_ol", sizeof(buf) - 1);
- buf[sizeof(buf) - 1] = '\0';
- if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) {
- /* Check for older dongle image that doesn't support toe_ol */
- if (ret == -EIO) {
- DHD_ERROR(("%s: toe not supported by device\n",
- dhd_ifname(&dhd->pub, ifidx)));
- return -EOPNOTSUPP;
- }
-
- DHD_INFO(("%s: could not get toe_ol: ret=%d\n", dhd_ifname(&dhd->pub, ifidx), ret));
- return ret;
- }
-
- memcpy(toe_ol, buf, sizeof(uint32));
- return 0;
-}
-
-/* Set current toe component enables in toe_ol iovar, and set toe global enable iovar */
-static int
-dhd_toe_set(dhd_info_t *dhd, int ifidx, uint32 toe_ol)
-{
- wl_ioctl_t ioc;
- char buf[32];
- int toe, ret;
-
- memset(&ioc, 0, sizeof(ioc));
-
- ioc.cmd = WLC_SET_VAR;
- ioc.buf = buf;
- ioc.len = (uint)sizeof(buf);
- ioc.set = TRUE;
-
- /* Set toe_ol as requested */
-
- strncpy(buf, "toe_ol", sizeof(buf) - 1);
- buf[sizeof(buf) - 1] = '\0';
- memcpy(&buf[sizeof("toe_ol")], &toe_ol, sizeof(uint32));
-
- if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) {
- DHD_ERROR(("%s: could not set toe_ol: ret=%d\n",
- dhd_ifname(&dhd->pub, ifidx), ret));
- return ret;
- }
-
- /* Enable toe globally only if any components are enabled. */
-
- toe = (toe_ol != 0);
-
- strcpy(buf, "toe");
- memcpy(&buf[sizeof("toe")], &toe, sizeof(uint32));
-
- if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) {
- DHD_ERROR(("%s: could not set toe: ret=%d\n", dhd_ifname(&dhd->pub, ifidx), ret));
- return ret;
- }
-
- return 0;
-}
-#endif /* TOE */
-
-#if defined(WL_CFG80211)
-void dhd_set_scb_probe(dhd_pub_t *dhd)
-{
-#define NUM_SCB_MAX_PROBE 3
- int ret = 0;
- wl_scb_probe_t scb_probe;
- char iovbuf[WL_EVENTING_MASK_LEN + 12];
-
- memset(&scb_probe, 0, sizeof(wl_scb_probe_t));
-
- if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE)
- return;
-
- bcm_mkiovar("scb_probe", NULL, 0, iovbuf, sizeof(iovbuf));
-
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
- DHD_ERROR(("%s: GET max_scb_probe failed\n", __FUNCTION__));
-
- memcpy(&scb_probe, iovbuf, sizeof(wl_scb_probe_t));
-
- scb_probe.scb_max_probe = NUM_SCB_MAX_PROBE;
-
- bcm_mkiovar("scb_probe", (char *)&scb_probe,
- sizeof(wl_scb_probe_t), iovbuf, sizeof(iovbuf));
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
- DHD_ERROR(("%s: max_scb_probe setting failed\n", __FUNCTION__));
-#undef NUM_SCB_MAX_PROBE
- return;
-}
-#endif /* WL_CFG80211 */
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
-static void
-dhd_ethtool_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info)
-{
- dhd_info_t *dhd = DHD_DEV_INFO(net);
-
- snprintf(info->driver, sizeof(info->driver), "wl");
- snprintf(info->version, sizeof(info->version), "%lu", dhd->pub.drv_version);
-}
-
-struct ethtool_ops dhd_ethtool_ops = {
- .get_drvinfo = dhd_ethtool_get_drvinfo
-};
-#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */
-
-
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2)
-static int
-dhd_ethtool(dhd_info_t *dhd, void *uaddr)
-{
- struct ethtool_drvinfo info;
- char drvname[sizeof(info.driver)];
- uint32 cmd;
-#ifdef TOE
- struct ethtool_value edata;
- uint32 toe_cmpnt, csum_dir;
- int ret;
-#endif
-
- DHD_TRACE(("%s: Enter\n", __FUNCTION__));
-
- /* all ethtool calls start with a cmd word */
- if (copy_from_user(&cmd, uaddr, sizeof (uint32)))
- return -EFAULT;
-
- switch (cmd) {
- case ETHTOOL_GDRVINFO:
- /* Copy out any request driver name */
- if (copy_from_user(&info, uaddr, sizeof(info)))
- return -EFAULT;
- strncpy(drvname, info.driver, sizeof(info.driver));
- drvname[sizeof(info.driver)-1] = '\0';
-
- /* clear struct for return */
- memset(&info, 0, sizeof(info));
- info.cmd = cmd;
-
- /* if dhd requested, identify ourselves */
- if (strcmp(drvname, "?dhd") == 0) {
- snprintf(info.driver, sizeof(info.driver), "dhd");
- strncpy(info.version, EPI_VERSION_STR, sizeof(info.version) - 1);
- info.version[sizeof(info.version) - 1] = '\0';
- }
-
- /* otherwise, require dongle to be up */
- else if (!dhd->pub.up) {
- DHD_ERROR(("%s: dongle is not up\n", __FUNCTION__));
- return -ENODEV;
- }
-
- /* finally, report dongle driver type */
- else if (dhd->pub.iswl)
- snprintf(info.driver, sizeof(info.driver), "wl");
- else
- snprintf(info.driver, sizeof(info.driver), "xx");
-
- snprintf(info.version, sizeof(info.version), "%lu", dhd->pub.drv_version);
- if (copy_to_user(uaddr, &info, sizeof(info)))
- return -EFAULT;
- DHD_CTL(("%s: given %*s, returning %s\n", __FUNCTION__,
- (int)sizeof(drvname), drvname, info.driver));
- break;
-
-#ifdef TOE
- /* Get toe offload components from dongle */
- case ETHTOOL_GRXCSUM:
- case ETHTOOL_GTXCSUM:
- if ((ret = dhd_toe_get(dhd, 0, &toe_cmpnt)) < 0)
- return ret;
-
- csum_dir = (cmd == ETHTOOL_GTXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL;
-
- edata.cmd = cmd;
- edata.data = (toe_cmpnt & csum_dir) ? 1 : 0;
-
- if (copy_to_user(uaddr, &edata, sizeof(edata)))
- return -EFAULT;
- break;
-
- /* Set toe offload components in dongle */
- case ETHTOOL_SRXCSUM:
- case ETHTOOL_STXCSUM:
- if (copy_from_user(&edata, uaddr, sizeof(edata)))
- return -EFAULT;
-
- /* Read the current settings, update and write back */
- if ((ret = dhd_toe_get(dhd, 0, &toe_cmpnt)) < 0)
- return ret;
-
- csum_dir = (cmd == ETHTOOL_STXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL;
-
- if (edata.data != 0)
- toe_cmpnt |= csum_dir;
- else
- toe_cmpnt &= ~csum_dir;
-
- if ((ret = dhd_toe_set(dhd, 0, toe_cmpnt)) < 0)
- return ret;
-
- /* If setting TX checksum mode, tell Linux the new mode */
- if (cmd == ETHTOOL_STXCSUM) {
- if (edata.data)
- dhd->iflist[0]->net->features |= NETIF_F_IP_CSUM;
- else
- dhd->iflist[0]->net->features &= ~NETIF_F_IP_CSUM;
- }
-
- break;
-#endif /* TOE */
-
- default:
- return -EOPNOTSUPP;
- }
-
- return 0;
-}
-#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) */
-
-static bool dhd_check_hang(struct net_device *net, dhd_pub_t *dhdp, int error)
-{
- dhd_info_t *dhd;
-
- if (!dhdp) {
- DHD_ERROR(("%s: dhdp is NULL\n", __FUNCTION__));
- return FALSE;
- }
-
- if (!dhdp->up)
- return FALSE;
-
- dhd = (dhd_info_t *)dhdp->info;
-#if !defined(BCMPCIE)
- if (dhd->thr_dpc_ctl.thr_pid < 0) {
- DHD_ERROR(("%s : skipped due to negative pid - unloading?\n", __FUNCTION__));
- return FALSE;
- }
-#endif
-
- if ((error == -ETIMEDOUT) || (error == -EREMOTEIO) ||
- ((dhdp->busstate == DHD_BUS_DOWN) && (!dhdp->dongle_reset))) {
- DHD_ERROR(("%s: Event HANG send up due to re=%d te=%d e=%d s=%d\n", __FUNCTION__,
- dhdp->rxcnt_timeout, dhdp->txcnt_timeout, error, dhdp->busstate));
- net_os_send_hang_message(net);
- return TRUE;
- }
- return FALSE;
-}
-
-int dhd_ioctl_process(dhd_pub_t *pub, int ifidx, dhd_ioctl_t *ioc, void *data_buf)
-{
- int bcmerror = BCME_OK;
- int buflen = 0;
- struct net_device *net;
-
- net = dhd_idx2net(pub, ifidx);
- if (!net) {
- bcmerror = BCME_BADARG;
- goto done;
- }
-
- if (data_buf)
- buflen = MIN(ioc->len, DHD_IOCTL_MAXLEN);
-
- /* check for local dhd ioctl and handle it */
- if (ioc->driver == DHD_IOCTL_MAGIC) {
- bcmerror = dhd_ioctl((void *)pub, ioc, data_buf, buflen);
- if (bcmerror)
- pub->bcmerror = bcmerror;
- goto done;
- }
-
- /* send to dongle (must be up, and wl). */
- if (pub->busstate != DHD_BUS_DATA) {
- bcmerror = BCME_DONGLE_DOWN;
- goto done;
- }
-
- if (!pub->iswl) {
- bcmerror = BCME_DONGLE_DOWN;
- goto done;
- }
-
- /*
- * Flush the TX queue if required for proper message serialization:
- * Intercept WLC_SET_KEY IOCTL - serialize M4 send and set key IOCTL to
- * prevent M4 encryption and
- * intercept WLC_DISASSOC IOCTL - serialize WPS-DONE and WLC_DISASSOC IOCTL to
- * prevent disassoc frame being sent before WPS-DONE frame.
- */
- if (ioc->cmd == WLC_SET_KEY ||
- (ioc->cmd == WLC_SET_VAR && data_buf != NULL &&
- strncmp("wsec_key", data_buf, 9) == 0) ||
- (ioc->cmd == WLC_SET_VAR && data_buf != NULL &&
- strncmp("bsscfg:wsec_key", data_buf, 15) == 0) ||
- ioc->cmd == WLC_DISASSOC)
- dhd_wait_pend8021x(net);
-
-#ifdef WLMEDIA_HTSF
- if (data_buf) {
- /* short cut wl ioctl calls here */
- if (strcmp("htsf", data_buf) == 0) {
- dhd_ioctl_htsf_get(dhd, 0);
- return BCME_OK;
- }
-
- if (strcmp("htsflate", data_buf) == 0) {
- if (ioc->set) {
- memset(ts, 0, sizeof(tstamp_t)*TSMAX);
- memset(&maxdelayts, 0, sizeof(tstamp_t));
- maxdelay = 0;
- tspktcnt = 0;
- maxdelaypktno = 0;
- memset(&vi_d1.bin, 0, sizeof(uint32)*NUMBIN);
- memset(&vi_d2.bin, 0, sizeof(uint32)*NUMBIN);
- memset(&vi_d3.bin, 0, sizeof(uint32)*NUMBIN);
- memset(&vi_d4.bin, 0, sizeof(uint32)*NUMBIN);
- } else {
- dhd_dump_latency();
- }
- return BCME_OK;
- }
- if (strcmp("htsfclear", data_buf) == 0) {
- memset(&vi_d1.bin, 0, sizeof(uint32)*NUMBIN);
- memset(&vi_d2.bin, 0, sizeof(uint32)*NUMBIN);
- memset(&vi_d3.bin, 0, sizeof(uint32)*NUMBIN);
- memset(&vi_d4.bin, 0, sizeof(uint32)*NUMBIN);
- htsf_seqnum = 0;
- return BCME_OK;
- }
- if (strcmp("htsfhis", data_buf) == 0) {
- dhd_dump_htsfhisto(&vi_d1, "H to D");
- dhd_dump_htsfhisto(&vi_d2, "D to D");
- dhd_dump_htsfhisto(&vi_d3, "D to H");
- dhd_dump_htsfhisto(&vi_d4, "H to H");
- return BCME_OK;
- }
- if (strcmp("tsport", data_buf) == 0) {
- if (ioc->set) {
- memcpy(&tsport, data_buf + 7, 4);
- } else {
- DHD_ERROR(("current timestamp port: %d \n", tsport));
- }
- return BCME_OK;
- }
- }
-#endif /* WLMEDIA_HTSF */
-
- if ((ioc->cmd == WLC_SET_VAR || ioc->cmd == WLC_GET_VAR) &&
- data_buf != NULL && strncmp("rpc_", data_buf, 4) == 0) {
-#ifdef BCM_FD_AGGR
- bcmerror = dhd_fdaggr_ioctl(pub, ifidx, (wl_ioctl_t *)ioc, data_buf, buflen);
-#else
- bcmerror = BCME_UNSUPPORTED;
-#endif
- goto done;
- }
- bcmerror = dhd_wl_ioctl(pub, ifidx, (wl_ioctl_t *)ioc, data_buf, buflen);
-
-done:
- dhd_check_hang(net, pub, bcmerror);
-
- return bcmerror;
-}
-
-static int
-dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd)
-{
- dhd_info_t *dhd = DHD_DEV_INFO(net);
- dhd_ioctl_t ioc;
- int bcmerror = 0;
- int ifidx;
- int ret;
- void *local_buf = NULL;
- u16 buflen = 0;
-
- DHD_OS_WAKE_LOCK(&dhd->pub);
- DHD_PERIM_LOCK(&dhd->pub);
-
- /* Interface up check for built-in type */
- if (!dhd_download_fw_on_driverload && dhd->pub.up == 0) {
- DHD_ERROR(("%s: Interface is down \n", __FUNCTION__));
- DHD_PERIM_UNLOCK(&dhd->pub);
- DHD_OS_WAKE_UNLOCK(&dhd->pub);
- return BCME_NOTUP;
- }
-
- /* send to dongle only if we are not waiting for reload already */
- if (dhd->pub.hang_was_sent) {
- DHD_ERROR(("%s: HANG was sent up earlier\n", __FUNCTION__));
- DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(&dhd->pub, DHD_EVENT_TIMEOUT_MS);
- DHD_OS_WAKE_UNLOCK(&dhd->pub);
- return OSL_ERROR(BCME_DONGLE_DOWN);
- }
-
- ifidx = dhd_net2idx(dhd, net);
- DHD_TRACE(("%s: ifidx %d, cmd 0x%04x\n", __FUNCTION__, ifidx, cmd));
-
- if (ifidx == DHD_BAD_IF) {
- DHD_ERROR(("%s: BAD IF\n", __FUNCTION__));
- DHD_PERIM_UNLOCK(&dhd->pub);
- DHD_OS_WAKE_UNLOCK(&dhd->pub);
- return -1;
- }
-
-#if defined(WL_WIRELESS_EXT)
- /* linux wireless extensions */
- if ((cmd >= SIOCIWFIRST) && (cmd <= SIOCIWLAST)) {
- /* may recurse, do NOT lock */
- ret = wl_iw_ioctl(net, ifr, cmd);
- DHD_PERIM_UNLOCK(&dhd->pub);
- DHD_OS_WAKE_UNLOCK(&dhd->pub);
- return ret;
- }
-#endif /* defined(WL_WIRELESS_EXT) */
-
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2)
- if (cmd == SIOCETHTOOL) {
- ret = dhd_ethtool(dhd, (void*)ifr->ifr_data);
- DHD_PERIM_UNLOCK(&dhd->pub);
- DHD_OS_WAKE_UNLOCK(&dhd->pub);
- return ret;
- }
-#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) */
-
- if (cmd == SIOCDEVPRIVATE+1) {
- ret = wl_android_priv_cmd(net, ifr, cmd);
- dhd_check_hang(net, &dhd->pub, ret);
- DHD_OS_WAKE_UNLOCK(&dhd->pub);
- return ret;
- }
-
- if (cmd != SIOCDEVPRIVATE) {
- DHD_PERIM_UNLOCK(&dhd->pub);
- DHD_OS_WAKE_UNLOCK(&dhd->pub);
- return -EOPNOTSUPP;
- }
-
- memset(&ioc, 0, sizeof(ioc));
-
-#ifdef CONFIG_COMPAT
- if (is_compat_task()) {
- compat_wl_ioctl_t compat_ioc;
- if (copy_from_user(&compat_ioc, ifr->ifr_data, sizeof(compat_wl_ioctl_t))) {
- bcmerror = BCME_BADADDR;
- goto done;
- }
- ioc.cmd = compat_ioc.cmd;
- ioc.buf = compat_ptr(compat_ioc.buf);
- ioc.len = compat_ioc.len;
- ioc.set = compat_ioc.set;
- ioc.used = compat_ioc.used;
- ioc.needed = compat_ioc.needed;
- /* To differentiate between wl and dhd read 4 more byes */
- if ((copy_from_user(&ioc.driver, (char *)ifr->ifr_data + sizeof(compat_wl_ioctl_t),
- sizeof(uint)) != 0)) {
- bcmerror = BCME_BADADDR;
- goto done;
- }
- } else
-#endif /* CONFIG_COMPAT */
- {
- /* Copy the ioc control structure part of ioctl request */
- if (copy_from_user(&ioc, ifr->ifr_data, sizeof(wl_ioctl_t))) {
- bcmerror = BCME_BADADDR;
- goto done;
- }
-
- /* To differentiate between wl and dhd read 4 more byes */
- if ((copy_from_user(&ioc.driver, (char *)ifr->ifr_data + sizeof(wl_ioctl_t),
- sizeof(uint)) != 0)) {
- bcmerror = BCME_BADADDR;
- goto done;
- }
- }
-
- if (!capable(CAP_NET_ADMIN)) {
- bcmerror = BCME_EPERM;
- goto done;
- }
-
- if (ioc.len > 0) {
- buflen = MIN(ioc.len, DHD_IOCTL_MAXLEN);
- if (!(local_buf = MALLOC(dhd->pub.osh, buflen+1))) {
- bcmerror = BCME_NOMEM;
- goto done;
- }
-
- DHD_PERIM_UNLOCK(&dhd->pub);
- if (copy_from_user(local_buf, ioc.buf, buflen)) {
- DHD_PERIM_LOCK(&dhd->pub);
- bcmerror = BCME_BADADDR;
- goto done;
- }
- DHD_PERIM_LOCK(&dhd->pub);
-
- *(char *)(local_buf + buflen) = '\0';
- }
-
- bcmerror = dhd_ioctl_process(&dhd->pub, ifidx, &ioc, local_buf);
-
- if (!bcmerror && buflen && local_buf && ioc.buf) {
- DHD_PERIM_UNLOCK(&dhd->pub);
- if (copy_to_user(ioc.buf, local_buf, buflen))
- bcmerror = -EFAULT;
- DHD_PERIM_LOCK(&dhd->pub);
- }
-
-done:
- if (local_buf)
- MFREE(dhd->pub.osh, local_buf, buflen+1);
-
- DHD_PERIM_UNLOCK(&dhd->pub);
- DHD_OS_WAKE_UNLOCK(&dhd->pub);
-
- return OSL_ERROR(bcmerror);
-}
-
-
-
-static int
-dhd_stop(struct net_device *net)
-{
- int ifidx = 0;
- dhd_info_t *dhd = DHD_DEV_INFO(net);
- DHD_OS_WAKE_LOCK(&dhd->pub);
- DHD_PERIM_LOCK(&dhd->pub);
- printk("%s: Enter %p\n", __FUNCTION__, net);
- if (dhd->pub.up == 0) {
- goto exit;
- }
-
- dhd_if_flush_sta(DHD_DEV_IFP(net));
-
-
- ifidx = dhd_net2idx(dhd, net);
- BCM_REFERENCE(ifidx);
-
- /* Set state and stop OS transmissions */
- netif_stop_queue(net);
- dhd->pub.up = 0;
-
-#ifdef WL_CFG80211
- if (ifidx == 0) {
- wl_cfg80211_down(NULL);
-
- /*
- * For CFG80211: Clean up all the left over virtual interfaces
- * when the primary Interface is brought down. [ifconfig wlan0 down]
- */
- if (!dhd_download_fw_on_driverload) {
- if ((dhd->dhd_state & DHD_ATTACH_STATE_ADD_IF) &&
- (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211)) {
- int i;
-
- dhd_net_if_lock_local(dhd);
- for (i = 1; i < DHD_MAX_IFS; i++)
- dhd_remove_if(&dhd->pub, i, FALSE);
- dhd_net_if_unlock_local(dhd);
- }
- }
- }
-#endif /* WL_CFG80211 */
-
-#ifdef PROP_TXSTATUS
- dhd_wlfc_cleanup(&dhd->pub, NULL, 0);
-#endif
- /* Stop the protocol module */
- dhd_prot_stop(&dhd->pub);
-
- OLD_MOD_DEC_USE_COUNT;
-exit:
- if (ifidx == 0 && !dhd_download_fw_on_driverload)
- wl_android_wifi_off(net);
- dhd->pub.rxcnt_timeout = 0;
- dhd->pub.txcnt_timeout = 0;
-
- dhd->pub.hang_was_sent = 0;
-
- /* Clear country spec for for built-in type driver */
- if (!dhd_download_fw_on_driverload) {
- dhd->pub.dhd_cspec.country_abbrev[0] = 0x00;
- dhd->pub.dhd_cspec.rev = 0;
- dhd->pub.dhd_cspec.ccode[0] = 0x00;
- }
-
- printk("%s: Exit\n", __FUNCTION__);
- DHD_PERIM_UNLOCK(&dhd->pub);
- DHD_OS_WAKE_UNLOCK(&dhd->pub);
- return 0;
-}
-
-#if defined(WL_CFG80211) && defined(USE_INITIAL_SHORT_DWELL_TIME)
-extern bool g_first_broadcast_scan;
-#endif
-
-#ifdef WL11U
-static int dhd_interworking_enable(dhd_pub_t *dhd)
-{
- char iovbuf[WLC_IOCTL_SMLEN];
- uint32 enable = true;
- int ret = BCME_OK;
-
- bcm_mkiovar("interworking", (char *)&enable, sizeof(enable), iovbuf, sizeof(iovbuf));
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
- DHD_ERROR(("%s: enableing interworking failed, ret=%d\n", __FUNCTION__, ret));
- }
-
- if (ret == BCME_OK) {
- /* basic capabilities for HS20 REL2 */
- uint32 cap = WL_WNM_BSSTRANS | WL_WNM_NOTIF;
- bcm_mkiovar("wnm", (char *)&cap, sizeof(cap), iovbuf, sizeof(iovbuf));
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
- iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
- DHD_ERROR(("%s: failed to set WNM info, ret=%d\n", __FUNCTION__, ret));
- }
- }
-
- return ret;
-}
-#endif /* WL11u */
-
-static int
-dhd_open(struct net_device *net)
-{
- dhd_info_t *dhd = DHD_DEV_INFO(net);
-#ifdef TOE
- uint32 toe_ol;
-#endif
- int ifidx;
- int32 ret = 0;
-
- printk("%s: Enter %p\n", __FUNCTION__, net);
-#if defined(MULTIPLE_SUPPLICANT)
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 && defined(BCMSDIO)
- if (mutex_is_locked(&_dhd_sdio_mutex_lock_) != 0) {
- DHD_ERROR(("%s : dhd_open: call dev open before insmod complete!\n", __FUNCTION__));
- }
- mutex_lock(&_dhd_sdio_mutex_lock_);
-#endif
-#endif /* MULTIPLE_SUPPLICANT */
-
- DHD_OS_WAKE_LOCK(&dhd->pub);
- DHD_PERIM_LOCK(&dhd->pub);
- dhd->pub.dongle_trap_occured = 0;
- dhd->pub.hang_was_sent = 0;
-
-#if 0
- /*
- * Force start if ifconfig_up gets called before START command
- * We keep WEXT's wl_control_wl_start to provide backward compatibility
- * This should be removed in the future
- */
- ret = wl_control_wl_start(net);
- if (ret != 0) {
- DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret));
- ret = -1;
- goto exit;
- }
-#endif
-
- ifidx = dhd_net2idx(dhd, net);
- DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx));
-
- if (ifidx < 0) {
- DHD_ERROR(("%s: Error: called with invalid IF\n", __FUNCTION__));
- ret = -1;
- goto exit;
- }
-
- if (!dhd->iflist[ifidx]) {
- DHD_ERROR(("%s: Error: called when IF already deleted\n", __FUNCTION__));
- ret = -1;
- goto exit;
- }
-
- if (ifidx == 0) {
- atomic_set(&dhd->pend_8021x_cnt, 0);
- if (!dhd_download_fw_on_driverload) {
- DHD_ERROR(("\n%s\n", dhd_version));
-#if defined(USE_INITIAL_SHORT_DWELL_TIME)
- g_first_broadcast_scan = TRUE;
-#endif
- ret = wl_android_wifi_on(net);
- if (ret != 0) {
- DHD_ERROR(("%s : wl_android_wifi_on failed (%d)\n",
- __FUNCTION__, ret));
- ret = -1;
- goto exit;
- }
- }
-
- if (dhd->pub.busstate != DHD_BUS_DATA) {
-
- /* try to bring up bus */
- DHD_PERIM_UNLOCK(&dhd->pub);
- ret = dhd_bus_start(&dhd->pub);
- DHD_PERIM_LOCK(&dhd->pub);
- if (ret) {
- DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret));
- ret = -1;
- goto exit;
- }
-
- }
-
- /* dhd_sync_with_dongle has been called in dhd_bus_start or wl_android_wifi_on */
- memcpy(net->dev_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN);
-
-#ifdef TOE
- /* Get current TOE mode from dongle */
- if (dhd_toe_get(dhd, ifidx, &toe_ol) >= 0 && (toe_ol & TOE_TX_CSUM_OL) != 0)
- dhd->iflist[ifidx]->net->features |= NETIF_F_IP_CSUM;
- else
- dhd->iflist[ifidx]->net->features &= ~NETIF_F_IP_CSUM;
-#endif /* TOE */
-
-#if defined(WL_CFG80211)
- if (unlikely(wl_cfg80211_up(NULL))) {
- DHD_ERROR(("%s: failed to bring up cfg80211\n", __FUNCTION__));
- ret = -1;
- goto exit;
- }
- dhd_set_scb_probe(&dhd->pub);
-#endif /* WL_CFG80211 */
- }
-
- /* Allow transmit calls */
- netif_start_queue(net);
- dhd->pub.up = 1;
-
-#ifdef BCMDBGFS
- dhd_dbg_init(&dhd->pub);
-#endif
-
- OLD_MOD_INC_USE_COUNT;
-exit:
- if (ret)
- dhd_stop(net);
-
- DHD_PERIM_UNLOCK(&dhd->pub);
- DHD_OS_WAKE_UNLOCK(&dhd->pub);
-
-#if defined(MULTIPLE_SUPPLICANT)
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 && defined(BCMSDIO)
- mutex_unlock(&_dhd_sdio_mutex_lock_);
-#endif
-#endif /* MULTIPLE_SUPPLICANT */
-
- printk("%s: Exit ret=%d\n", __FUNCTION__, ret);
- return ret;
-}
-
-int dhd_do_driver_init(struct net_device *net)
-{
- dhd_info_t *dhd = NULL;
-
- if (!net) {
- DHD_ERROR(("Primary Interface not initialized \n"));
- return -EINVAL;
- }
-
-#ifdef MULTIPLE_SUPPLICANT
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 && defined(BCMSDIO)
- if (mutex_is_locked(&_dhd_sdio_mutex_lock_) != 0) {
- DHD_ERROR(("%s : dhdsdio_probe is already running!\n", __FUNCTION__));
- return 0;
- }
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
-#endif /* MULTIPLE_SUPPLICANT */
-
- /* && defined(OEM_ANDROID) && defined(BCMSDIO) */
- dhd = DHD_DEV_INFO(net);
-
- /* If driver is already initialized, do nothing
- */
- if (dhd->pub.busstate == DHD_BUS_DATA) {
- DHD_TRACE(("Driver already Inititalized. Nothing to do"));
- return 0;
- }
-
- if (dhd_open(net) < 0) {
- DHD_ERROR(("Driver Init Failed \n"));
- return -1;
- }
-
- return 0;
-}
-
-int
-dhd_event_ifadd(dhd_info_t *dhdinfo, wl_event_data_if_t *ifevent, char *name, uint8 *mac)
-{
-
-#ifdef WL_CFG80211
- if (wl_cfg80211_notify_ifadd(ifevent->ifidx, name, mac, ifevent->bssidx) == BCME_OK)
- return BCME_OK;
-#endif
-
- /* handle IF event caused by wl commands, SoftAP, WEXT and
- * anything else. This has to be done asynchronously otherwise
- * DPC will be blocked (and iovars will timeout as DPC has no chance
- * to read the response back)
- */
- if (ifevent->ifidx > 0) {
- dhd_if_event_t *if_event = MALLOC(dhdinfo->pub.osh, sizeof(dhd_if_event_t));
-
- memcpy(&if_event->event, ifevent, sizeof(if_event->event));
- memcpy(if_event->mac, mac, ETHER_ADDR_LEN);
- strncpy(if_event->name, name, IFNAMSIZ);
- if_event->name[IFNAMSIZ - 1] = '\0';
- dhd_deferred_schedule_work(dhdinfo->dhd_deferred_wq, (void *)if_event,
- DHD_WQ_WORK_IF_ADD, dhd_ifadd_event_handler, DHD_WORK_PRIORITY_LOW);
- }
-
- return BCME_OK;
-}
-
-int
-dhd_event_ifdel(dhd_info_t *dhdinfo, wl_event_data_if_t *ifevent, char *name, uint8 *mac)
-{
- dhd_if_event_t *if_event;
-
-#ifdef WL_CFG80211
- if (wl_cfg80211_notify_ifdel(ifevent->ifidx, name, mac, ifevent->bssidx) == BCME_OK)
- return BCME_OK;
-#endif /* WL_CFG80211 */
-
- /* handle IF event caused by wl commands, SoftAP, WEXT and
- * anything else
- */
- if_event = MALLOC(dhdinfo->pub.osh, sizeof(dhd_if_event_t));
- memcpy(&if_event->event, ifevent, sizeof(if_event->event));
- memcpy(if_event->mac, mac, ETHER_ADDR_LEN);
- strncpy(if_event->name, name, IFNAMSIZ);
- if_event->name[IFNAMSIZ - 1] = '\0';
- dhd_deferred_schedule_work(dhdinfo->dhd_deferred_wq, (void *)if_event, DHD_WQ_WORK_IF_DEL,
- dhd_ifdel_event_handler, DHD_WORK_PRIORITY_LOW);
-
- return BCME_OK;
-}
-
-/* unregister and free the existing net_device interface (if any) in iflist and
- * allocate a new one. the slot is reused. this function does NOT register the
- * new interface to linux kernel. dhd_register_if does the job
- */
-struct net_device*
-dhd_allocate_if(dhd_pub_t *dhdpub, int ifidx, char *name,
- uint8 *mac, uint8 bssidx, bool need_rtnl_lock)
-{
- dhd_info_t *dhdinfo = (dhd_info_t *)dhdpub->info;
- dhd_if_t *ifp;
-
- ASSERT(dhdinfo && (ifidx < DHD_MAX_IFS));
- ifp = dhdinfo->iflist[ifidx];
-
- if (ifp != NULL) {
- if (ifp->net != NULL) {
- DHD_ERROR(("%s: free existing IF %s\n", __FUNCTION__, ifp->net->name));
-
- dhd_dev_priv_clear(ifp->net); /* clear net_device private */
-
- /* in unregister_netdev case, the interface gets freed by net->destructor
- * (which is set to free_netdev)
- */
- if (ifp->net->reg_state == NETREG_UNINITIALIZED) {
- free_netdev(ifp->net);
- } else {
- netif_stop_queue(ifp->net);
- if (need_rtnl_lock)
- unregister_netdev(ifp->net);
- else
- unregister_netdevice(ifp->net);
- }
- ifp->net = NULL;
- }
- } else {
- ifp = MALLOC(dhdinfo->pub.osh, sizeof(dhd_if_t));
- if (ifp == NULL) {
- DHD_ERROR(("%s: OOM - dhd_if_t(%zu)\n", __FUNCTION__, sizeof(dhd_if_t)));
- return NULL;
- }
- }
-
- memset(ifp, 0, sizeof(dhd_if_t));
- ifp->info = dhdinfo;
- ifp->idx = ifidx;
- ifp->bssidx = bssidx;
- if (mac != NULL)
- memcpy(&ifp->mac_addr, mac, ETHER_ADDR_LEN);
-
- /* Allocate etherdev, including space for private structure */
- ifp->net = alloc_etherdev(DHD_DEV_PRIV_SIZE);
- if (ifp->net == NULL) {
- DHD_ERROR(("%s: OOM - alloc_etherdev(%zu)\n", __FUNCTION__, sizeof(dhdinfo)));
- goto fail;
- }
-
- /* Setup the dhd interface's netdevice private structure. */
- dhd_dev_priv_save(ifp->net, dhdinfo, ifp, ifidx);
-
- if (name && name[0]) {
- strncpy(ifp->net->name, name, IFNAMSIZ);
- ifp->net->name[IFNAMSIZ - 1] = '\0';
- }
-#ifdef WL_CFG80211
- if (ifidx == 0)
- ifp->net->destructor = free_netdev;
- else
- ifp->net->destructor = dhd_netdev_free;
-#else
- ifp->net->destructor = free_netdev;
-#endif /* WL_CFG80211 */
- strncpy(ifp->name, ifp->net->name, IFNAMSIZ);
- ifp->name[IFNAMSIZ - 1] = '\0';
- dhdinfo->iflist[ifidx] = ifp;
-
-#ifdef PCIE_FULL_DONGLE
- /* Initialize STA info list */
- INIT_LIST_HEAD(&ifp->sta_list);
- DHD_IF_STA_LIST_LOCK_INIT(ifp);
-#endif /* PCIE_FULL_DONGLE */
-
- return ifp->net;
-
-fail:
- if (ifp != NULL) {
- if (ifp->net != NULL) {
- dhd_dev_priv_clear(ifp->net);
- free_netdev(ifp->net);
- ifp->net = NULL;
- }
- MFREE(dhdinfo->pub.osh, ifp, sizeof(*ifp));
- ifp = NULL;
- }
- dhdinfo->iflist[ifidx] = NULL;
- return NULL;
-}
-
-/* unregister and free the the net_device interface associated with the indexed
- * slot, also free the slot memory and set the slot pointer to NULL
- */
-int
-dhd_remove_if(dhd_pub_t *dhdpub, int ifidx, bool need_rtnl_lock)
-{
- dhd_info_t *dhdinfo = (dhd_info_t *)dhdpub->info;
- dhd_if_t *ifp;
-
- ifp = dhdinfo->iflist[ifidx];
- if (ifp != NULL) {
- if (ifp->net != NULL) {
- DHD_ERROR(("deleting interface '%s' idx %d\n", ifp->net->name, ifp->idx));
-
- /* in unregister_netdev case, the interface gets freed by net->destructor
- * (which is set to free_netdev)
- */
- if (ifp->net->reg_state == NETREG_UNINITIALIZED) {
- free_netdev(ifp->net);
- } else {
- netif_stop_queue(ifp->net);
-
-
-
- if (need_rtnl_lock)
- unregister_netdev(ifp->net);
- else
- unregister_netdevice(ifp->net);
- }
- ifp->net = NULL;
- }
-#ifdef DHD_WMF
- dhd_wmf_cleanup(dhdpub, ifidx);
-#endif /* DHD_WMF */
-
- dhd_if_del_sta_list(ifp);
-
- dhdinfo->iflist[ifidx] = NULL;
- MFREE(dhdinfo->pub.osh, ifp, sizeof(*ifp));
-
- }
-
- return BCME_OK;
-}
-
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31))
-static struct net_device_ops dhd_ops_pri = {
- .ndo_open = dhd_open,
- .ndo_stop = dhd_stop,
- .ndo_get_stats = dhd_get_stats,
- .ndo_do_ioctl = dhd_ioctl_entry,
- .ndo_start_xmit = dhd_start_xmit,
- .ndo_set_mac_address = dhd_set_mac_address,
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
- .ndo_set_rx_mode = dhd_set_multicast_list,
-#else
- .ndo_set_multicast_list = dhd_set_multicast_list,
-#endif
-};
-
-static struct net_device_ops dhd_ops_virt = {
- .ndo_get_stats = dhd_get_stats,
- .ndo_do_ioctl = dhd_ioctl_entry,
- .ndo_start_xmit = dhd_start_xmit,
- .ndo_set_mac_address = dhd_set_mac_address,
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
- .ndo_set_rx_mode = dhd_set_multicast_list,
-#else
- .ndo_set_multicast_list = dhd_set_multicast_list,
-#endif
-};
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) */
-
-#ifdef DEBUGGER
-extern void debugger_init(void *bus_handle);
-#endif
-
-
-#ifdef SHOW_LOGTRACE
-static char *logstrs_path = "/root/logstrs.bin";
-module_param(logstrs_path, charp, S_IRUGO);
-
-int
-dhd_init_logstrs_array(dhd_event_log_t *temp)
-{
- struct file *filep = NULL;
- struct kstat stat;
- mm_segment_t fs;
- char *raw_fmts = NULL;
- int logstrs_size = 0;
-
- logstr_header_t *hdr = NULL;
- uint32 *lognums = NULL;
- char *logstrs = NULL;
- int ram_index = 0;
- char **fmts;
- int num_fmts = 0;
- uint32 i = 0;
- int error = 0;
- set_fs(KERNEL_DS);
- fs = get_fs();
- filep = filp_open(logstrs_path, O_RDONLY, 0);
- if (IS_ERR(filep)) {
- DHD_ERROR(("Failed to open the file logstrs.bin in %s", __FUNCTION__));
- goto fail;
- }
- error = vfs_stat(logstrs_path, &stat);
- if (error) {
- DHD_ERROR(("Failed in %s to find file stat", __FUNCTION__));
- goto fail;
- }
- logstrs_size = (int) stat.size;
-
- raw_fmts = kmalloc(logstrs_size, GFP_KERNEL);
- if (raw_fmts == NULL) {
- DHD_ERROR(("Failed to allocate raw_fmts memory"));
- goto fail;
- }
- if (vfs_read(filep, raw_fmts, logstrs_size, &filep->f_pos) != logstrs_size) {
- DHD_ERROR(("Error: Log strings file read failed"));
- goto fail;
- }
-
- /* Remember header from the logstrs.bin file */
- hdr = (logstr_header_t *) (raw_fmts + logstrs_size -
- sizeof(logstr_header_t));
-
- if (hdr->log_magic == LOGSTRS_MAGIC) {
- /*
- * logstrs.bin start with header.
- */
- num_fmts = hdr->rom_logstrs_offset / sizeof(uint32);
- ram_index = (hdr->ram_lognums_offset -
- hdr->rom_lognums_offset) / sizeof(uint32);
- lognums = (uint32 *) &raw_fmts[hdr->rom_lognums_offset];
- logstrs = (char *) &raw_fmts[hdr->rom_logstrs_offset];
- } else {
- /*
- * Legacy logstrs.bin format without header.
- */
- num_fmts = *((uint32 *) (raw_fmts)) / sizeof(uint32);
- if (num_fmts == 0) {
- /* Legacy ROM/RAM logstrs.bin format:
- * - ROM 'lognums' section
- * - RAM 'lognums' section
- * - ROM 'logstrs' section.
- * - RAM 'logstrs' section.
- *
- * 'lognums' is an array of indexes for the strings in the
- * 'logstrs' section. The first uint32 is 0 (index of first
- * string in ROM 'logstrs' section).
- *
- * The 4324b5 is the only ROM that uses this legacy format. Use the
- * fixed number of ROM fmtnums to find the start of the RAM
- * 'lognums' section. Use the fixed first ROM string ("Con\n") to
- * find the ROM 'logstrs' section.
- */
- #define NUM_4324B5_ROM_FMTS 186
- #define FIRST_4324B5_ROM_LOGSTR "Con\n"
- ram_index = NUM_4324B5_ROM_FMTS;
- lognums = (uint32 *) raw_fmts;
- num_fmts = ram_index;
- logstrs = (char *) &raw_fmts[num_fmts << 2];
- while (strncmp(FIRST_4324B5_ROM_LOGSTR, logstrs, 4)) {
- num_fmts++;
- logstrs = (char *) &raw_fmts[num_fmts << 2];
- }
- } else {
- /* Legacy RAM-only logstrs.bin format:
- * - RAM 'lognums' section
- * - RAM 'logstrs' section.
- *
- * 'lognums' is an array of indexes for the strings in the
- * 'logstrs' section. The first uint32 is an index to the
- * start of 'logstrs'. Therefore, if this index is divided
- * by 'sizeof(uint32)' it provides the number of logstr
- * entries.
- */
- ram_index = 0;
- lognums = (uint32 *) raw_fmts;
- logstrs = (char *) &raw_fmts[num_fmts << 2];
- }
- }
- fmts = kmalloc(num_fmts * sizeof(char *), GFP_KERNEL);
- if (fmts == NULL) {
- DHD_ERROR(("Failed to allocate fmts memory"));
- goto fail;
- }
-
- for (i = 0; i < num_fmts; i++) {
- /* ROM lognums index into logstrs using 'rom_logstrs_offset' as a base
- * (they are 0-indexed relative to 'rom_logstrs_offset').
- *
- * RAM lognums are already indexed to point to the correct RAM logstrs (they
- * are 0-indexed relative to the start of the logstrs.bin file).
- */
- if (i == ram_index) {
- logstrs = raw_fmts;
- }
- fmts[i] = &logstrs[lognums[i]];
- }
- temp->fmts = fmts;
- temp->raw_fmts = raw_fmts;
- temp->num_fmts = num_fmts;
- filp_close(filep, NULL);
- set_fs(fs);
- return 0;
-fail:
- if (raw_fmts) {
- kfree(raw_fmts);
- raw_fmts = NULL;
- }
- if (!IS_ERR(filep))
- filp_close(filep, NULL);
- set_fs(fs);
- temp->fmts = NULL;
- return -1;
-}
-#endif /* SHOW_LOGTRACE */
-
-
-dhd_pub_t *
-dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen)
-{
- dhd_info_t *dhd = NULL;
- struct net_device *net = NULL;
- char if_name[IFNAMSIZ] = {'\0'};
- uint32 bus_type = -1;
- uint32 bus_num = -1;
- uint32 slot_num = -1;
- wifi_adapter_info_t *adapter = NULL;
-
- dhd_attach_states_t dhd_state = DHD_ATTACH_STATE_INIT;
- DHD_TRACE(("%s: Enter\n", __FUNCTION__));
-
- /* will implement get_ids for DBUS later */
-#if defined(BCMSDIO)
- dhd_bus_get_ids(bus, &bus_type, &bus_num, &slot_num);
-#endif
- adapter = dhd_wifi_platform_get_adapter(bus_type, bus_num, slot_num);
-
- /* Allocate primary dhd_info */
- dhd = wifi_platform_prealloc(adapter, DHD_PREALLOC_DHD_INFO, sizeof(dhd_info_t));
- if (dhd == NULL) {
- dhd = MALLOC(osh, sizeof(dhd_info_t));
- if (dhd == NULL) {
- DHD_ERROR(("%s: OOM - alloc dhd_info\n", __FUNCTION__));
- goto fail;
- }
- }
- memset(dhd, 0, sizeof(dhd_info_t));
- dhd_state |= DHD_ATTACH_STATE_DHD_ALLOC;
-
- dhd->unit = dhd_found + instance_base; /* do not increment dhd_found, yet */
-
- dhd->pub.osh = osh;
- dhd->adapter = adapter;
-
-#ifdef GET_CUSTOM_MAC_ENABLE
- wifi_platform_get_mac_addr(dhd->adapter, dhd->pub.mac.octet);
-#endif /* GET_CUSTOM_MAC_ENABLE */
- dhd->thr_dpc_ctl.thr_pid = DHD_PID_KT_TL_INVALID;
- dhd->thr_wdt_ctl.thr_pid = DHD_PID_KT_INVALID;
-
- /* Initialize thread based operation and lock */
- sema_init(&dhd->sdsem, 1);
-
- /* Link to info module */
- dhd->pub.info = dhd;
-
-
- /* Link to bus module */
- dhd->pub.bus = bus;
- dhd->pub.hdrlen = bus_hdrlen;
-
- /* dhd_conf must be attached after linking dhd to dhd->pub.info,
- * because dhd_detech will check .info is NULL or not.
- */
- if (dhd_conf_attach(&dhd->pub) != 0) {
- DHD_ERROR(("dhd_conf_attach failed\n"));
- goto fail;
- }
- dhd_conf_reset(&dhd->pub);
- dhd_conf_set_chiprev(&dhd->pub, dhd_bus_chip(bus), dhd_bus_chiprev(bus));
-
- /* Some DHD modules (e.g. cfg80211) configures operation mode based on firmware name.
- * This is indeed a hack but we have to make it work properly before we have a better
- * solution
- */
- dhd_update_fw_nv_path(dhd);
-
- /* Set network interface name if it was provided as module parameter */
- if (iface_name[0]) {
- int len;
- char ch;
- strncpy(if_name, iface_name, IFNAMSIZ);
- if_name[IFNAMSIZ - 1] = 0;
- len = strlen(if_name);
- ch = if_name[len - 1];
- if ((ch > '9' || ch < '0') && (len < IFNAMSIZ - 2))
- strcat(if_name, "%d");
- }
- net = dhd_allocate_if(&dhd->pub, 0, if_name, NULL, 0, TRUE);
- if (net == NULL)
- goto fail;
- dhd_state |= DHD_ATTACH_STATE_ADD_IF;
-
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31))
- net->open = NULL;
-#else
- net->netdev_ops = NULL;
-#endif
-
- sema_init(&dhd->proto_sem, 1);
-
-#ifdef PROP_TXSTATUS
- spin_lock_init(&dhd->wlfc_spinlock);
-
- dhd->pub.skip_fc = dhd_wlfc_skip_fc;
- dhd->pub.plat_init = dhd_wlfc_plat_init;
- dhd->pub.plat_deinit = dhd_wlfc_plat_deinit;
-#endif /* PROP_TXSTATUS */
-
- /* Initialize other structure content */
- init_waitqueue_head(&dhd->ioctl_resp_wait);
- init_waitqueue_head(&dhd->ctrl_wait);
-
- /* Initialize the spinlocks */
- spin_lock_init(&dhd->sdlock);
- spin_lock_init(&dhd->txqlock);
- spin_lock_init(&dhd->dhd_lock);
- spin_lock_init(&dhd->rxf_lock);
-#if defined(RXFRAME_THREAD)
- dhd->rxthread_enabled = TRUE;
-#endif /* defined(RXFRAME_THREAD) */
-
-#ifdef DHDTCPACK_SUPPRESS
- spin_lock_init(&dhd->tcpack_lock);
-#endif /* DHDTCPACK_SUPPRESS */
-
- /* Initialize Wakelock stuff */
- spin_lock_init(&dhd->wakelock_spinlock);
- dhd->wakelock_counter = 0;
- dhd->wakelock_wd_counter = 0;
- dhd->wakelock_rx_timeout_enable = 0;
- dhd->wakelock_ctrl_timeout_enable = 0;
-#ifdef CONFIG_HAS_WAKELOCK
- wake_lock_init(&dhd->wl_wifi, WAKE_LOCK_SUSPEND, "wlan_wake");
- wake_lock_init(&dhd->wl_rxwake, WAKE_LOCK_SUSPEND, "wlan_rx_wake");
- wake_lock_init(&dhd->wl_ctrlwake, WAKE_LOCK_SUSPEND, "wlan_ctrl_wake");
- wake_lock_init(&dhd->wl_wdwake, WAKE_LOCK_SUSPEND, "wlan_wd_wake");
-#endif /* CONFIG_HAS_WAKELOCK */
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1
- mutex_init(&dhd->dhd_net_if_mutex);
- mutex_init(&dhd->dhd_suspend_mutex);
-#endif
- dhd_state |= DHD_ATTACH_STATE_WAKELOCKS_INIT;
-
- /* Attach and link in the protocol */
- if (dhd_prot_attach(&dhd->pub) != 0) {
- DHD_ERROR(("dhd_prot_attach failed\n"));
- goto fail;
- }
- dhd_state |= DHD_ATTACH_STATE_PROT_ATTACH;
-
-#ifdef WL_CFG80211
- /* Attach and link in the cfg80211 */
- if (unlikely(wl_cfg80211_attach(net, &dhd->pub))) {
- DHD_ERROR(("wl_cfg80211_attach failed\n"));
- goto fail;
- }
-
- dhd_monitor_init(&dhd->pub);
- dhd_state |= DHD_ATTACH_STATE_CFG80211;
-#endif
-#if defined(WL_WIRELESS_EXT)
- /* Attach and link in the iw */
- if (!(dhd_state & DHD_ATTACH_STATE_CFG80211)) {
- if (wl_iw_attach(net, (void *)&dhd->pub) != 0) {
- DHD_ERROR(("wl_iw_attach failed\n"));
- goto fail;
- }
- dhd_state |= DHD_ATTACH_STATE_WL_ATTACH;
- }
-#endif /* defined(WL_WIRELESS_EXT) */
-
-#ifdef SHOW_LOGTRACE
- dhd_init_logstrs_array(&dhd->event_data);
-#endif /* SHOW_LOGTRACE */
-
- if (dhd_sta_pool_init(&dhd->pub, DHD_MAX_STA) != BCME_OK) {
- DHD_ERROR(("%s: Initializing %u sta\n", __FUNCTION__, DHD_MAX_STA));
- goto fail;
- }
-
-
- /* Set up the watchdog timer */
- init_timer(&dhd->timer);
- dhd->timer.data = (ulong)dhd;
- dhd->timer.function = dhd_watchdog;
- dhd->default_wd_interval = dhd_watchdog_ms;
-
- if (dhd_watchdog_prio >= 0) {
- /* Initialize watchdog thread */
- PROC_START(dhd_watchdog_thread, dhd, &dhd->thr_wdt_ctl, 0, "dhd_watchdog_thread");
-
- } else {
- dhd->thr_wdt_ctl.thr_pid = -1;
- }
-
-#ifdef DEBUGGER
- debugger_init((void *) bus);
-#endif
-
- /* Set up the bottom half handler */
- if (dhd_dpc_prio >= 0) {
- /* Initialize DPC thread */
- PROC_START(dhd_dpc_thread, dhd, &dhd->thr_dpc_ctl, 0, "dhd_dpc");
- } else {
- /* use tasklet for dpc */
- tasklet_init(&dhd->tasklet, dhd_dpc, (ulong)dhd);
- dhd->thr_dpc_ctl.thr_pid = -1;
- }
-
- if (dhd->rxthread_enabled) {
- bzero(&dhd->pub.skbbuf[0], sizeof(void *) * MAXSKBPEND);
- /* Initialize RXF thread */
- PROC_START(dhd_rxf_thread, dhd, &dhd->thr_rxf_ctl, 0, "dhd_rxf");
- }
-
- dhd_state |= DHD_ATTACH_STATE_THREADS_CREATED;
-
-#if defined(CONFIG_PM_SLEEP)
- if (!dhd_pm_notifier_registered) {
- dhd_pm_notifier_registered = TRUE;
- register_pm_notifier(&dhd_pm_notifier);
- }
-#endif /* CONFIG_PM_SLEEP */
-
-#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
- dhd->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 20;
- dhd->early_suspend.suspend = dhd_early_suspend;
- dhd->early_suspend.resume = dhd_late_resume;
- register_early_suspend(&dhd->early_suspend);
- dhd_state |= DHD_ATTACH_STATE_EARLYSUSPEND_DONE;
-#endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */
-
-#ifdef ARP_OFFLOAD_SUPPORT
- dhd->pend_ipaddr = 0;
- if (!dhd_inetaddr_notifier_registered) {
- dhd_inetaddr_notifier_registered = TRUE;
- register_inetaddr_notifier(&dhd_inetaddr_notifier);
- }
-#endif /* ARP_OFFLOAD_SUPPORT */
-#ifdef CONFIG_IPV6
- if (!dhd_inet6addr_notifier_registered) {
- dhd_inet6addr_notifier_registered = TRUE;
- register_inet6addr_notifier(&dhd_inet6addr_notifier);
- }
-#endif
- dhd->dhd_deferred_wq = dhd_deferred_work_init((void *)dhd);
-#ifdef DEBUG_CPU_FREQ
- dhd->new_freq = alloc_percpu(int);
- dhd->freq_trans.notifier_call = dhd_cpufreq_notifier;
- cpufreq_register_notifier(&dhd->freq_trans, CPUFREQ_TRANSITION_NOTIFIER);
-#endif
-#ifdef DHDTCPACK_SUPPRESS
-#ifdef BCMSDIO
- dhd_tcpack_suppress_set(&dhd->pub, TCPACK_SUP_DELAYTX);
-#elif defined(BCMPCIE)
- dhd_tcpack_suppress_set(&dhd->pub, TCPACK_SUP_REPLACE);
-#else
- dhd_tcpack_suppress_set(&dhd->pub, TCPACK_SUP_OFF);
-#endif /* BCMSDIO */
-#endif /* DHDTCPACK_SUPPRESS */
-
- dhd_state |= DHD_ATTACH_STATE_DONE;
- dhd->dhd_state = dhd_state;
-
- dhd_found++;
- return &dhd->pub;
-
-fail:
- if (dhd_state >= DHD_ATTACH_STATE_DHD_ALLOC) {
- DHD_TRACE(("%s: Calling dhd_detach dhd_state 0x%x &dhd->pub %p\n",
- __FUNCTION__, dhd_state, &dhd->pub));
- dhd->dhd_state = dhd_state;
- dhd_detach(&dhd->pub);
- dhd_free(&dhd->pub);
- }
-
- return NULL;
-}
-
-int dhd_get_fw_mode(dhd_info_t *dhdinfo)
-{
- if (strstr(dhdinfo->fw_path, "_apsta") != NULL)
- return DHD_FLAG_HOSTAP_MODE;
- if (strstr(dhdinfo->fw_path, "_p2p") != NULL)
- return DHD_FLAG_P2P_MODE;
- if (strstr(dhdinfo->fw_path, "_ibss") != NULL)
- return DHD_FLAG_IBSS_MODE;
- if (strstr(dhdinfo->fw_path, "_mfg") != NULL)
- return DHD_FLAG_MFG_MODE;
-
- return DHD_FLAG_STA_MODE;
-}
-
-bool dhd_update_fw_nv_path(dhd_info_t *dhdinfo)
-{
- int fw_len;
- int nv_len;
- int conf_len;
- const char *fw = NULL;
- const char *nv = NULL;
- const char *conf = NULL;
- wifi_adapter_info_t *adapter = dhdinfo->adapter;
-
-
- /* Update firmware and nvram path. The path may be from adapter info or module parameter
- * The path from adapter info is used for initialization only (as it won't change).
- *
- * The firmware_path/nvram_path module parameter may be changed by the system at run
- * time. When it changes we need to copy it to dhdinfo->fw_path. Also Android private
- * command may change dhdinfo->fw_path. As such we need to clear the path info in
- * module parameter after it is copied. We won't update the path until the module parameter
- * is changed again (first character is not '\0')
- */
-
- /* set default firmware and nvram path for built-in type driver */
-// if (!dhd_download_fw_on_driverload) {
-#ifdef CONFIG_BCMDHD_FW_PATH
- fw = CONFIG_BCMDHD_FW_PATH;
-#endif /* CONFIG_BCMDHD_FW_PATH */
-#ifdef CONFIG_BCMDHD_NVRAM_PATH
- nv = CONFIG_BCMDHD_NVRAM_PATH;
-#endif /* CONFIG_BCMDHD_NVRAM_PATH */
-#ifdef CONFIG_BCMDHD_CONFIG_PATH
- conf = CONFIG_BCMDHD_CONFIG_PATH;
-#endif /* CONFIG_BCMDHD_CONFIG_PATH */
-// }
-
- /* check if we need to initialize the path */
- if (dhdinfo->fw_path[0] == '\0') {
- if (adapter && adapter->fw_path && adapter->fw_path[0] != '\0')
- fw = adapter->fw_path;
-
- }
- if (dhdinfo->nv_path[0] == '\0') {
- if (adapter && adapter->nv_path && adapter->nv_path[0] != '\0')
- nv = adapter->nv_path;
- }
- if (dhdinfo->conf_path[0] == '\0') {
- if (adapter && adapter->conf_path && adapter->conf_path[0] != '\0')
- conf = adapter->conf_path;
- }
-
- /* Use module parameter if it is valid, EVEN IF the path has not been initialized
- *
- * TODO: need a solution for multi-chip, can't use the same firmware for all chips
- */
- if (firmware_path[0] != '\0')
- fw = firmware_path;
- if (nvram_path[0] != '\0')
- nv = nvram_path;
- if (config_path[0] != '\0')
- conf = config_path;
-
- if (fw && fw[0] != '\0') {
- fw_len = strlen(fw);
- if (fw_len >= sizeof(dhdinfo->fw_path)) {
- DHD_ERROR(("fw path len exceeds max len of dhdinfo->fw_path\n"));
- return FALSE;
- }
- strncpy(dhdinfo->fw_path, fw, sizeof(dhdinfo->fw_path));
- if (dhdinfo->fw_path[fw_len-1] == '\n')
- dhdinfo->fw_path[fw_len-1] = '\0';
- }
- if (nv && nv[0] != '\0') {
- nv_len = strlen(nv);
- if (nv_len >= sizeof(dhdinfo->nv_path)) {
- DHD_ERROR(("nvram path len exceeds max len of dhdinfo->nv_path\n"));
- return FALSE;
- }
- strncpy(dhdinfo->nv_path, nv, sizeof(dhdinfo->nv_path));
- if (dhdinfo->nv_path[nv_len-1] == '\n')
- dhdinfo->nv_path[nv_len-1] = '\0';
- }
- if (conf && conf[0] != '\0') {
- conf_len = strlen(conf);
- if (conf_len >= sizeof(dhdinfo->conf_path)) {
- DHD_ERROR(("config path len exceeds max len of dhdinfo->conf_path\n"));
- return FALSE;
- }
- strncpy(dhdinfo->conf_path, conf, sizeof(dhdinfo->conf_path));
- if (dhdinfo->conf_path[conf_len-1] == '\n')
- dhdinfo->conf_path[conf_len-1] = '\0';
- }
-
-#if 0
- /* clear the path in module parameter */
- firmware_path[0] = '\0';
- nvram_path[0] = '\0';
- config_path[0] = '\0';
-#endif
-
-#ifndef BCMEMBEDIMAGE
- /* fw_path and nv_path are not mandatory for BCMEMBEDIMAGE */
- if (dhdinfo->fw_path[0] == '\0') {
- DHD_ERROR(("firmware path not found\n"));
- return FALSE;
- }
- if (dhdinfo->nv_path[0] == '\0') {
- DHD_ERROR(("nvram path not found\n"));
- return FALSE;
- }
- if (dhdinfo->conf_path[0] == '\0') {
- DHD_ERROR(("config path not found\n"));
- return FALSE;
- }
-#endif /* BCMEMBEDIMAGE */
-
- return TRUE;
-}
-
-
-#ifdef EXYNOS5433_PCIE_WAR
-extern int enum_wifi;
-#endif /* EXYNOS5433_PCIE_WAR */
-int
-dhd_bus_start(dhd_pub_t *dhdp)
-{
- int ret = -1;
- dhd_info_t *dhd = (dhd_info_t*)dhdp->info;
- unsigned long flags;
-
- ASSERT(dhd);
-
- DHD_TRACE(("Enter %s:\n", __FUNCTION__));
-
- DHD_PERIM_LOCK(dhdp);
-
- /* try to download image and nvram to the dongle */
- if (dhd->pub.busstate == DHD_BUS_DOWN && dhd_update_fw_nv_path(dhd)) {
- DHD_INFO(("%s download fw %s, nv %s, conf %s\n",
- __FUNCTION__, dhd->fw_path, dhd->nv_path, dhd->conf_path));
- ret = dhd_bus_download_firmware(dhd->pub.bus, dhd->pub.osh,
- dhd->fw_path, dhd->nv_path, dhd->conf_path);
- if (ret < 0) {
-#ifdef EXYNOS5433_PCIE_WAR
- enum_wifi = 0;
-#endif /* EXYNOS5433_PCIE_WAR */
- DHD_ERROR(("%s: failed to download firmware %s\n",
- __FUNCTION__, dhd->fw_path));
- DHD_PERIM_UNLOCK(dhdp);
- return ret;
- }
-#ifdef EXYNOS5433_PCIE_WAR
- enum_wifi = 1;
-#endif /* EXYNOS5433_PCIE_WAR */
- }
- if (dhd->pub.busstate != DHD_BUS_LOAD) {
- DHD_PERIM_UNLOCK(dhdp);
- return -ENETDOWN;
- }
-
- dhd_os_sdlock(dhdp);
-
- /* Start the watchdog timer */
- dhd->pub.tickcnt = 0;
- dhd_os_wd_timer(&dhd->pub, dhd_watchdog_ms);
-
- /* Bring up the bus */
- if ((ret = dhd_bus_init(&dhd->pub, FALSE)) != 0) {
-
- DHD_ERROR(("%s, dhd_bus_init failed %d\n", __FUNCTION__, ret));
- dhd_os_sdunlock(dhdp);
- DHD_PERIM_UNLOCK(dhdp);
- return ret;
- }
-#if defined(OOB_INTR_ONLY)
- /* Host registration for OOB interrupt */
- if (dhd_bus_oob_intr_register(dhdp)) {
- /* deactivate timer and wait for the handler to finish */
-
- DHD_GENERAL_LOCK(&dhd->pub, flags);
- dhd->wd_timer_valid = FALSE;
- DHD_GENERAL_UNLOCK(&dhd->pub, flags);
- del_timer_sync(&dhd->timer);
-
- DHD_ERROR(("%s Host failed to register for OOB\n", __FUNCTION__));
- dhd_os_sdunlock(dhdp);
- DHD_PERIM_UNLOCK(dhdp);
- DHD_OS_WD_WAKE_UNLOCK(&dhd->pub);
- return -ENODEV;
- }
-
- /* Enable oob at firmware */
- dhd_enable_oob_intr(dhd->pub.bus, TRUE);
-#endif
-#ifdef PCIE_FULL_DONGLE
- {
- uint8 txpush = 0;
- uint32 num_flowrings; /* includes H2D common rings */
- num_flowrings = dhd_bus_max_h2d_queues(dhd->pub.bus, &txpush);
- DHD_ERROR(("%s: Initializing %u flowrings\n", __FUNCTION__,
- num_flowrings));
- if ((ret = dhd_flow_rings_init(&dhd->pub, num_flowrings)) != BCME_OK) {
- dhd_os_sdunlock(dhdp);
- DHD_PERIM_UNLOCK(dhdp);
- return ret;
- }
- }
-#endif /* PCIE_FULL_DONGLE */
-
- /* Do protocol initialization necessary for IOCTL/IOVAR */
- dhd_prot_init(&dhd->pub);
-
- /* If bus is not ready, can't come up */
- if (dhd->pub.busstate != DHD_BUS_DATA) {
- DHD_GENERAL_LOCK(&dhd->pub, flags);
- dhd->wd_timer_valid = FALSE;
- DHD_GENERAL_UNLOCK(&dhd->pub, flags);
- del_timer_sync(&dhd->timer);
- DHD_ERROR(("%s failed bus is not ready\n", __FUNCTION__));
- dhd_os_sdunlock(dhdp);
- DHD_PERIM_UNLOCK(dhdp);
- DHD_OS_WD_WAKE_UNLOCK(&dhd->pub);
- return -ENODEV;
- }
-
- dhd_os_sdunlock(dhdp);
-
- /* Bus is ready, query any dongle information */
- if ((ret = dhd_sync_with_dongle(&dhd->pub)) < 0) {
- DHD_PERIM_UNLOCK(dhdp);
- return ret;
- }
-
-#ifdef ARP_OFFLOAD_SUPPORT
- if (dhd->pend_ipaddr) {
-#ifdef AOE_IP_ALIAS_SUPPORT
- aoe_update_host_ipv4_table(&dhd->pub, dhd->pend_ipaddr, TRUE, 0);
-#endif /* AOE_IP_ALIAS_SUPPORT */
- dhd->pend_ipaddr = 0;
- }
-#endif /* ARP_OFFLOAD_SUPPORT */
-
- DHD_PERIM_UNLOCK(dhdp);
- return 0;
-}
-
-#ifdef WLTDLS
-int _dhd_tdls_enable(dhd_pub_t *dhd, bool tdls_on, bool auto_on, struct ether_addr *mac)
-{
- char iovbuf[WLC_IOCTL_SMLEN];
- uint32 tdls = tdls_on;
- int ret = 0;
- uint32 tdls_auto_op = 0;
- uint32 tdls_idle_time = CUSTOM_TDLS_IDLE_MODE_SETTING;
- int32 tdls_rssi_high = CUSTOM_TDLS_RSSI_THRESHOLD_HIGH;
- int32 tdls_rssi_low = CUSTOM_TDLS_RSSI_THRESHOLD_LOW;
- BCM_REFERENCE(mac);
- if (!FW_SUPPORTED(dhd, tdls))
- return BCME_ERROR;
-
- if (dhd->tdls_enable == tdls_on)
- goto auto_mode;
- bcm_mkiovar("tdls_enable", (char *)&tdls, sizeof(tdls), iovbuf, sizeof(iovbuf));
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
- DHD_ERROR(("%s: tdls %d failed %d\n", __FUNCTION__, tdls, ret));
- goto exit;
- }
- dhd->tdls_enable = tdls_on;
-auto_mode:
-
- tdls_auto_op = auto_on;
- bcm_mkiovar("tdls_auto_op", (char *)&tdls_auto_op, sizeof(tdls_auto_op),
- iovbuf, sizeof(iovbuf));
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
- sizeof(iovbuf), TRUE, 0)) < 0) {
- DHD_ERROR(("%s: tdls_auto_op failed %d\n", __FUNCTION__, ret));
- goto exit;
- }
-
- if (tdls_auto_op) {
- bcm_mkiovar("tdls_idle_time", (char *)&tdls_idle_time,
- sizeof(tdls_idle_time), iovbuf, sizeof(iovbuf));
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
- sizeof(iovbuf), TRUE, 0)) < 0) {
- DHD_ERROR(("%s: tdls_idle_time failed %d\n", __FUNCTION__, ret));
- goto exit;
- }
- bcm_mkiovar("tdls_rssi_high", (char *)&tdls_rssi_high, 4, iovbuf, sizeof(iovbuf));
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
- sizeof(iovbuf), TRUE, 0)) < 0) {
- DHD_ERROR(("%s: tdls_rssi_high failed %d\n", __FUNCTION__, ret));
- goto exit;
- }
- bcm_mkiovar("tdls_rssi_low", (char *)&tdls_rssi_low, 4, iovbuf, sizeof(iovbuf));
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
- sizeof(iovbuf), TRUE, 0)) < 0) {
- DHD_ERROR(("%s: tdls_rssi_low failed %d\n", __FUNCTION__, ret));
- goto exit;
- }
- }
-
-exit:
- return ret;
-}
-
-int dhd_tdls_enable(struct net_device *dev, bool tdls_on, bool auto_on, struct ether_addr *mac)
-{
- dhd_info_t *dhd = DHD_DEV_INFO(dev);
- int ret = 0;
- if (dhd)
- ret = _dhd_tdls_enable(&dhd->pub, tdls_on, auto_on, mac);
- else
- ret = BCME_ERROR;
- return ret;
-}
-#ifdef PCIE_FULL_DONGLE
-void dhd_tdls_update_peer_info(struct net_device *dev, bool connect, uint8 *da)
-{
- dhd_info_t *dhd = DHD_DEV_INFO(dev);
- dhd_pub_t *dhdp = (dhd_pub_t *)&dhd->pub;
- tdls_peer_node_t *cur = dhdp->peer_tbl.node;
- tdls_peer_node_t *new = NULL, *prev = NULL;
- dhd_if_t *dhdif;
- uint8 sa[ETHER_ADDR_LEN];
- int ifidx = dhd_net2idx(dhd, dev);
-
- if (ifidx == DHD_BAD_IF)
- return;
-
- dhdif = dhd->iflist[ifidx];
- memcpy(sa, dhdif->mac_addr, ETHER_ADDR_LEN);
-
- if (connect) {
- while (cur != NULL) {
- if (!memcmp(da, cur->addr, ETHER_ADDR_LEN)) {
- DHD_ERROR(("%s: TDLS Peer exist already %d\n",
- __FUNCTION__, __LINE__));
- return;
- }
- cur = cur->next;
- }
-
- new = MALLOC(dhdp->osh, sizeof(tdls_peer_node_t));
- if (new == NULL) {
- DHD_ERROR(("%s: Failed to allocate memory\n", __FUNCTION__));
- return;
- }
- memcpy(new->addr, da, ETHER_ADDR_LEN);
- new->next = dhdp->peer_tbl.node;
- dhdp->peer_tbl.node = new;
- dhdp->peer_tbl.tdls_peer_count++;
-
- } else {
- while (cur != NULL) {
- if (!memcmp(da, cur->addr, ETHER_ADDR_LEN)) {
- dhd_flow_rings_delete_for_peer(dhdp, ifidx, da);
- if (prev)
- prev->next = cur->next;
- else
- dhdp->peer_tbl.node = cur->next;
- MFREE(dhdp->osh, cur, sizeof(tdls_peer_node_t));
- dhdp->peer_tbl.tdls_peer_count--;
- return;
- }
- prev = cur;
- cur = cur->next;
- }
- DHD_ERROR(("%s: TDLS Peer Entry Not found\n", __FUNCTION__));
- }
-}
-#endif /* PCIE_FULL_DONGLE */
-#endif
-
-bool dhd_is_concurrent_mode(dhd_pub_t *dhd)
-{
- if (!dhd)
- return FALSE;
-
- if (dhd->op_mode & DHD_FLAG_CONCURR_MULTI_CHAN_MODE)
- return TRUE;
- else if ((dhd->op_mode & DHD_FLAG_CONCURR_SINGLE_CHAN_MODE) ==
- DHD_FLAG_CONCURR_SINGLE_CHAN_MODE)
- return TRUE;
- else
- return FALSE;
-}
-#if !defined(AP) && defined(WLP2P)
-/* From Android JerryBean release, the concurrent mode is enabled by default and the firmware
- * name would be fw_bcmdhd.bin. So we need to determine whether P2P is enabled in the STA
- * firmware and accordingly enable concurrent mode (Apply P2P settings). SoftAP firmware
- * would still be named as fw_bcmdhd_apsta.
- */
-uint32
-dhd_get_concurrent_capabilites(dhd_pub_t *dhd)
-{
- int32 ret = 0;
- char buf[WLC_IOCTL_SMLEN];
- bool mchan_supported = FALSE;
- /* if dhd->op_mode is already set for HOSTAP and Manufacturing
- * test mode, that means we only will use the mode as it is
- */
- if (dhd->op_mode & (DHD_FLAG_HOSTAP_MODE | DHD_FLAG_MFG_MODE))
- return 0;
- if (FW_SUPPORTED(dhd, vsdb)) {
- mchan_supported = TRUE;
- }
- if (!FW_SUPPORTED(dhd, p2p)) {
- DHD_TRACE(("Chip does not support p2p\n"));
- return 0;
- }
- else {
- /* Chip supports p2p but ensure that p2p is really implemented in firmware or not */
- memset(buf, 0, sizeof(buf));
- bcm_mkiovar("p2p", 0, 0, buf, sizeof(buf));
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf),
- FALSE, 0)) < 0) {
- DHD_ERROR(("%s: Get P2P failed (error=%d)\n", __FUNCTION__, ret));
- return 0;
- }
- else {
- if (buf[0] == 1) {
- /* By default, chip supports single chan concurrency,
- * now lets check for mchan
- */
- ret = DHD_FLAG_CONCURR_SINGLE_CHAN_MODE;
- if (mchan_supported)
- ret |= DHD_FLAG_CONCURR_MULTI_CHAN_MODE;
-#if defined(WL_ENABLE_P2P_IF) || defined(WL_CFG80211_P2P_DEV_IF)
- /* For customer_hw4, although ICS,
- * we still support concurrent mode
- */
- return ret;
-#else
- return 0;
-#endif
- }
- }
- }
- return 0;
-}
-#endif
-#if defined(READ_CONFIG_FROM_FILE)
-#include <linux/fs.h>
-#include <linux/ctype.h>
-
-#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base))
-bool PM_control = TRUE;
-
-static int dhd_preinit_proc(dhd_pub_t *dhd, int ifidx, char *name, char *value)
-{
- int var_int;
- wl_country_t cspec = {{0}, -1, {0}};
- char *revstr;
- char *endptr = NULL;
- int iolen;
- char smbuf[WLC_IOCTL_SMLEN*2];
-
- if (!strcmp(name, "country")) {
- revstr = strchr(value, '/');
- if (revstr) {
- cspec.rev = strtoul(revstr + 1, &endptr, 10);
- memcpy(cspec.country_abbrev, value, WLC_CNTRY_BUF_SZ);
- cspec.country_abbrev[2] = '\0';
- memcpy(cspec.ccode, cspec.country_abbrev, WLC_CNTRY_BUF_SZ);
- } else {
- cspec.rev = -1;
- memcpy(cspec.country_abbrev, value, WLC_CNTRY_BUF_SZ);
- memcpy(cspec.ccode, value, WLC_CNTRY_BUF_SZ);
- get_customized_country_code(dhd->info->adapter,
- (char *)&cspec.country_abbrev, &cspec);
- }
- memset(smbuf, 0, sizeof(smbuf));
- DHD_ERROR(("config country code is country : %s, rev : %d !!\n",
- cspec.country_abbrev, cspec.rev));
- iolen = bcm_mkiovar("country", (char*)&cspec, sizeof(cspec),
- smbuf, sizeof(smbuf));
- return dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
- smbuf, iolen, TRUE, 0);
- } else if (!strcmp(name, "roam_scan_period")) {
- var_int = (int)simple_strtol(value, NULL, 0);
- return dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_SCAN_PERIOD,
- &var_int, sizeof(var_int), TRUE, 0);
- } else if (!strcmp(name, "roam_delta")) {
- struct {
- int val;
- int band;
- } x;
- x.val = (int)simple_strtol(value, NULL, 0);
- /* x.band = WLC_BAND_AUTO; */
- x.band = WLC_BAND_ALL;
- return dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_DELTA, &x, sizeof(x), TRUE, 0);
- } else if (!strcmp(name, "roam_trigger")) {
- int ret = 0;
-
- roam_trigger[0] = (int)simple_strtol(value, NULL, 0);
- roam_trigger[1] = WLC_BAND_ALL;
- ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_TRIGGER, &roam_trigger,
- sizeof(roam_trigger), TRUE, 0);
-
- return ret;
- } else if (!strcmp(name, "PM")) {
- int ret = 0;
- var_int = (int)simple_strtol(value, NULL, 0);
-
- ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_PM,
- &var_int, sizeof(var_int), TRUE, 0);
-
-#if defined(CONFIG_PM_LOCK)
- if (var_int == 0) {
- g_pm_control = TRUE;
- printk("%s var_int=%d don't control PM\n", __func__, var_int);
- } else {
- g_pm_control = FALSE;
- printk("%s var_int=%d do control PM\n", __func__, var_int);
- }
-#endif
-
- return ret;
- }
-#ifdef WLBTAMP
- else if (!strcmp(name, "btamp_chan")) {
- int btamp_chan;
- int iov_len = 0;
- char iovbuf[128];
- int ret;
-
- btamp_chan = (int)simple_strtol(value, NULL, 0);
- iov_len = bcm_mkiovar("btamp_chan", (char *)&btamp_chan, 4, iovbuf, sizeof(iovbuf));
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, 0) < 0))
- DHD_ERROR(("%s btamp_chan=%d set failed code %d\n",
- __FUNCTION__, btamp_chan, ret));
- else
- DHD_ERROR(("%s btamp_chan %d set success\n",
- __FUNCTION__, btamp_chan));
- }
-#endif /* WLBTAMP */
- else if (!strcmp(name, "band")) {
- int ret;
- if (!strcmp(value, "auto"))
- var_int = WLC_BAND_AUTO;
- else if (!strcmp(value, "a"))
- var_int = WLC_BAND_5G;
- else if (!strcmp(value, "b"))
- var_int = WLC_BAND_2G;
- else if (!strcmp(value, "all"))
- var_int = WLC_BAND_ALL;
- else {
- printk(" set band value should be one of the a or b or all\n");
- var_int = WLC_BAND_AUTO;
- }
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_BAND, &var_int,
- sizeof(var_int), TRUE, 0)) < 0)
- printk(" set band err=%d\n", ret);
- return ret;
- } else if (!strcmp(name, "cur_etheraddr")) {
- struct ether_addr ea;
- char buf[32];
- uint iovlen;
- int ret;
-
- bcm_ether_atoe(value, &ea);
-
- ret = memcmp(&ea.octet, dhd->mac.octet, ETHER_ADDR_LEN);
- if (ret == 0) {
- DHD_ERROR(("%s: Same Macaddr\n", __FUNCTION__));
- return 0;
- }
-
- DHD_ERROR(("%s: Change Macaddr = %02X:%02X:%02X:%02X:%02X:%02X\n", __FUNCTION__,
- ea.octet[0], ea.octet[1], ea.octet[2],
- ea.octet[3], ea.octet[4], ea.octet[5]));
-
- iovlen = bcm_mkiovar("cur_etheraddr", (char*)&ea, ETHER_ADDR_LEN, buf, 32);
-
- ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, iovlen, TRUE, 0);
- if (ret < 0) {
- DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret));
- return ret;
- }
- else {
- memcpy(dhd->mac.octet, (void *)&ea, ETHER_ADDR_LEN);
- return ret;
- }
- } else {
- uint iovlen;
- char iovbuf[WLC_IOCTL_SMLEN];
-
- /* wlu_iovar_setint */
- var_int = (int)simple_strtol(value, NULL, 0);
-
- /* Setup timeout bcn_timeout from dhd driver 4.217.48 */
- if (!strcmp(name, "roam_off")) {
- /* Setup timeout if Beacons are lost to report link down */
- if (var_int) {
- uint bcn_timeout = 2;
- bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4,
- iovbuf, sizeof(iovbuf));
- dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
- }
- }
- /* Setup timeout bcm_timeout from dhd driver 4.217.48 */
-
- DHD_INFO(("%s:[%s]=[%d]\n", __FUNCTION__, name, var_int));
-
- iovlen = bcm_mkiovar(name, (char *)&var_int, sizeof(var_int),
- iovbuf, sizeof(iovbuf));
- return dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
- iovbuf, iovlen, TRUE, 0);
- }
-
- return 0;
-}
-
-static int dhd_preinit_config(dhd_pub_t *dhd, int ifidx)
-{
- mm_segment_t old_fs;
- struct kstat stat;
- struct file *fp = NULL;
- unsigned int len;
- char *buf = NULL, *p, *name, *value;
- int ret = 0;
- char *config_path;
-
- config_path = CONFIG_BCMDHD_CONFIG_PATH;
-
- if (!config_path)
- {
- printk(KERN_ERR "config_path can't read. \n");
- return 0;
- }
-
- old_fs = get_fs();
- set_fs(get_ds());
- if ((ret = vfs_stat(config_path, &stat))) {
- set_fs(old_fs);
- printk(KERN_ERR "%s: Failed to get information (%d)\n",
- config_path, ret);
- return ret;
- }
- set_fs(old_fs);
-
- if (!(buf = MALLOC(dhd->osh, stat.size + 1))) {
- printk(KERN_ERR "Failed to allocate memory %llu bytes\n", stat.size);
- return -ENOMEM;
- }
-
- printk("dhd_preinit_config : config path : %s \n", config_path);
-
- if (!(fp = dhd_os_open_image(config_path)) ||
- (len = dhd_os_get_image_block(buf, stat.size, fp)) < 0)
- goto err;
-
- buf[stat.size] = '\0';
- for (p = buf; *p; p++) {
- if (isspace(*p))
- continue;
- for (name = p++; *p && !isspace(*p); p++) {
- if (*p == '=') {
- *p = '\0';
- p++;
- for (value = p; *p && !isspace(*p); p++);
- *p = '\0';
- if ((ret = dhd_preinit_proc(dhd, ifidx, name, value)) < 0) {
- printk(KERN_ERR "%s: %s=%s\n",
- bcmerrorstr(ret), name, value);
- }
- break;
- }
- }
- }
- ret = 0;
-
-out:
- if (fp)
- dhd_os_close_image(fp);
- if (buf)
- MFREE(dhd->osh, buf, stat.size+1);
- return ret;
-
-err:
- ret = -1;
- goto out;
-}
-#endif /* READ_CONFIG_FROM_FILE */
-
-int
-dhd_preinit_ioctls(dhd_pub_t *dhd)
-{
- int ret = 0;
- char eventmask[WL_EVENTING_MASK_LEN];
- char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */
- uint32 buf_key_b4_m4 = 1;
-#ifndef WL_CFG80211
- u32 up = 0;
-#endif
- uint8 msglen;
- eventmsgs_ext_t *eventmask_msg;
- char iov_buf[WLC_IOCTL_SMLEN];
- int ret2 = 0;
-#ifdef WLAIBSS
- aibss_bcn_force_config_t bcn_config;
- uint32 aibss;
-#ifdef WLAIBSS_PS
- uint32 aibss_ps;
-#endif /* WLAIBSS_PS */
-#endif /* WLAIBSS */
-#if defined(BCMSUP_4WAY_HANDSHAKE) && defined(WLAN_AKM_SUITE_FT_8021X)
- uint32 sup_wpa = 0;
-#endif
-#if defined(CUSTOM_AMPDU_BA_WSIZE) || (defined(WLAIBSS) && \
- defined(CUSTOM_IBSS_AMPDU_BA_WSIZE))
- uint32 ampdu_ba_wsize = 0;
-#endif /* CUSTOM_AMPDU_BA_WSIZE ||(WLAIBSS && CUSTOM_IBSS_AMPDU_BA_WSIZE) */
-#if defined(CUSTOM_AMPDU_MPDU)
- int32 ampdu_mpdu = 0;
-#endif
-#if defined(CUSTOM_AMPDU_RELEASE)
- int32 ampdu_release = 0;
-#endif
-
-#if defined(BCMSDIO)
-#ifdef PROP_TXSTATUS
- int wlfc_enable = TRUE;
-#ifndef DISABLE_11N
- uint32 hostreorder = 1;
- uint wl_down = 1;
-#endif /* DISABLE_11N */
-#endif /* PROP_TXSTATUS */
-#endif
-#ifdef PCIE_FULL_DONGLE
- uint32 wl_ap_isolate;
-#endif /* PCIE_FULL_DONGLE */
-
-#ifdef DHD_ENABLE_LPC
- uint32 lpc = 1;
-#endif /* DHD_ENABLE_LPC */
- uint power_mode = PM_FAST;
- uint32 dongle_align = DHD_SDALIGN;
-#if defined(BCMSDIO)
- uint32 glom = CUSTOM_GLOM_SETTING;
-#endif /* defined(BCMSDIO) */
-#if defined(CUSTOMER_HW2) && defined(USE_WL_CREDALL)
- uint32 credall = 1;
-#endif
- uint bcn_timeout = dhd->conf->bcn_timeout;
- uint retry_max = 3;
-#if defined(ARP_OFFLOAD_SUPPORT)
- int arpoe = 1;
-#endif
- int scan_assoc_time = DHD_SCAN_ASSOC_ACTIVE_TIME;
- int scan_unassoc_time = DHD_SCAN_UNASSOC_ACTIVE_TIME;
- int scan_passive_time = DHD_SCAN_PASSIVE_TIME;
- char buf[WLC_IOCTL_SMLEN];
- char *ptr;
- uint32 listen_interval = CUSTOM_LISTEN_INTERVAL; /* Default Listen Interval in Beacons */
-#ifdef ROAM_ENABLE
- uint roamvar = 0;
- int roam_trigger[2] = {CUSTOM_ROAM_TRIGGER_SETTING, WLC_BAND_ALL};
- int roam_scan_period[2] = {10, WLC_BAND_ALL};
- int roam_delta[2] = {CUSTOM_ROAM_DELTA_SETTING, WLC_BAND_ALL};
-#ifdef FULL_ROAMING_SCAN_PERIOD_60_SEC
- int roam_fullscan_period = 60;
-#else /* FULL_ROAMING_SCAN_PERIOD_60_SEC */
- int roam_fullscan_period = 120;
-#endif /* FULL_ROAMING_SCAN_PERIOD_60_SEC */
-#else
-#ifdef DISABLE_BUILTIN_ROAM
- uint roamvar = 1;
-#endif /* DISABLE_BUILTIN_ROAM */
-#endif /* ROAM_ENABLE */
-
-#if defined(SOFTAP)
- uint dtim = 1;
-#endif
-#if (defined(AP) && !defined(WLP2P)) || (!defined(AP) && defined(WL_CFG80211))
- uint32 mpc = 0; /* Turn MPC off for AP/APSTA mode */
- struct ether_addr p2p_ea;
-#endif
-#ifdef BCMCCX
- uint32 ccx = 1;
-#endif
-
-#if (defined(AP) || defined(WLP2P)) && !defined(SOFTAP_AND_GC)
- uint32 apsta = 1; /* Enable APSTA mode */
-#elif defined(SOFTAP_AND_GC)
- uint32 apsta = 0;
- int ap_mode = 1;
-#endif /* (defined(AP) || defined(WLP2P)) && !defined(SOFTAP_AND_GC) */
-#ifdef GET_CUSTOM_MAC_ENABLE
- struct ether_addr ea_addr;
-#endif /* GET_CUSTOM_MAC_ENABLE */
-
-#ifdef DISABLE_11N
- uint32 nmode = 0;
-#endif /* DISABLE_11N */
-
-#if defined(DISABLE_11AC)
- uint32 vhtmode = 0;
-#endif /* DISABLE_11AC */
-#ifdef USE_WL_TXBF
- uint32 txbf = 1;
-#endif /* USE_WL_TXBF */
-#ifdef AMPDU_VO_ENABLE
- struct ampdu_tid_control tid;
-#endif
-#ifdef USE_WL_FRAMEBURST
- uint32 frameburst = 1;
-#endif /* USE_WL_FRAMEBURST */
-#ifdef DHD_SET_FW_HIGHSPEED
- uint32 ack_ratio = 250;
- uint32 ack_ratio_depth = 64;
-#endif /* DHD_SET_FW_HIGHSPEED */
-#ifdef SUPPORT_2G_VHT
- uint32 vht_features = 0x3; /* 2G enable | rates all */
-#endif /* SUPPORT_2G_VHT */
-#ifdef CUSTOM_PSPRETEND_THR
- uint32 pspretend_thr = CUSTOM_PSPRETEND_THR;
-#endif
-#ifdef PKT_FILTER_SUPPORT
- dhd_pkt_filter_enable = TRUE;
-#endif /* PKT_FILTER_SUPPORT */
-#ifdef WLTDLS
- dhd->tdls_enable = FALSE;
-#endif /* WLTDLS */
- dhd->suspend_bcn_li_dtim = CUSTOM_SUSPEND_BCN_LI_DTIM;
- DHD_TRACE(("Enter %s\n", __FUNCTION__));
-
- dhd_conf_set_band(dhd);
-
- dhd->op_mode = 0;
- if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_MFG_MODE) ||
- (op_mode == DHD_FLAG_MFG_MODE)) {
- /* Check and adjust IOCTL response timeout for Manufactring firmware */
- dhd_os_set_ioctl_resp_timeout(MFG_IOCTL_RESP_TIMEOUT);
- DHD_ERROR(("%s : Set IOCTL response time for Manufactring Firmware\n",
- __FUNCTION__));
- }
- else {
- dhd_os_set_ioctl_resp_timeout(IOCTL_RESP_TIMEOUT);
- DHD_INFO(("%s : Set IOCTL response time.\n", __FUNCTION__));
- }
-#ifdef GET_CUSTOM_MAC_ENABLE
- ret = wifi_platform_get_mac_addr(dhd->info->adapter, ea_addr.octet);
- if (!ret) {
- memset(buf, 0, sizeof(buf));
- bcm_mkiovar("cur_etheraddr", (void *)&ea_addr, ETHER_ADDR_LEN, buf, sizeof(buf));
- ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0);
- if (ret < 0) {
- DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret));
- return BCME_NOTUP;
- }
- memcpy(dhd->mac.octet, ea_addr.octet, ETHER_ADDR_LEN);
- } else {
-#endif /* GET_CUSTOM_MAC_ENABLE */
- /* Get the default device MAC address directly from firmware */
- memset(buf, 0, sizeof(buf));
- bcm_mkiovar("cur_etheraddr", 0, 0, buf, sizeof(buf));
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf),
- FALSE, 0)) < 0) {
- DHD_ERROR(("%s: can't get MAC address , error=%d\n", __FUNCTION__, ret));
- return BCME_NOTUP;
- }
- /* Update public MAC address after reading from Firmware */
- memcpy(dhd->mac.octet, buf, ETHER_ADDR_LEN);
-
-#ifdef GET_CUSTOM_MAC_ENABLE
- }
-#endif /* GET_CUSTOM_MAC_ENABLE */
-
- /* get a capabilities from firmware */
- memset(dhd->fw_capabilities, 0, sizeof(dhd->fw_capabilities));
- bcm_mkiovar("cap", 0, 0, dhd->fw_capabilities, sizeof(dhd->fw_capabilities));
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, dhd->fw_capabilities,
- sizeof(dhd->fw_capabilities), FALSE, 0)) < 0) {
- DHD_ERROR(("%s: Get Capability failed (error=%d)\n",
- __FUNCTION__, ret));
- return 0;
- }
- if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_HOSTAP_MODE) ||
- (op_mode == DHD_FLAG_HOSTAP_MODE)) {
-#ifdef SET_RANDOM_MAC_SOFTAP
- uint rand_mac;
-#endif
- dhd->op_mode = DHD_FLAG_HOSTAP_MODE;
-#if defined(ARP_OFFLOAD_SUPPORT)
- arpoe = 0;
-#endif
-#ifdef PKT_FILTER_SUPPORT
- dhd_pkt_filter_enable = FALSE;
-#endif
-#ifdef SET_RANDOM_MAC_SOFTAP
- SRANDOM32((uint)jiffies);
- rand_mac = RANDOM32();
- iovbuf[0] = 0x02; /* locally administered bit */
- iovbuf[1] = 0x1A;
- iovbuf[2] = 0x11;
- iovbuf[3] = (unsigned char)(rand_mac & 0x0F) | 0xF0;
- iovbuf[4] = (unsigned char)(rand_mac >> 8);
- iovbuf[5] = (unsigned char)(rand_mac >> 16);
-
- bcm_mkiovar("cur_etheraddr", (void *)iovbuf, ETHER_ADDR_LEN, buf, sizeof(buf));
- ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0);
- if (ret < 0) {
- DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret));
- } else
- memcpy(dhd->mac.octet, iovbuf, ETHER_ADDR_LEN);
-#endif /* SET_RANDOM_MAC_SOFTAP */
-#if !defined(AP) && defined(WL_CFG80211)
- /* Turn off MPC in AP mode */
- bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf));
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
- sizeof(iovbuf), TRUE, 0)) < 0) {
- DHD_ERROR(("%s mpc for HostAPD failed %d\n", __FUNCTION__, ret));
- }
-#endif
- } else if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_MFG_MODE) ||
- (op_mode == DHD_FLAG_MFG_MODE)) {
-#if defined(ARP_OFFLOAD_SUPPORT)
- arpoe = 0;
-#endif /* ARP_OFFLOAD_SUPPORT */
-#ifdef PKT_FILTER_SUPPORT
- dhd_pkt_filter_enable = FALSE;
-#endif /* PKT_FILTER_SUPPORT */
- dhd->op_mode = DHD_FLAG_MFG_MODE;
- } else {
- uint32 concurrent_mode = 0;
- if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_P2P_MODE) ||
- (op_mode == DHD_FLAG_P2P_MODE)) {
-#if defined(ARP_OFFLOAD_SUPPORT)
- arpoe = 0;
-#endif
-#ifdef PKT_FILTER_SUPPORT
- dhd_pkt_filter_enable = FALSE;
-#endif
- dhd->op_mode = DHD_FLAG_P2P_MODE;
- } else if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_IBSS_MODE) ||
- (op_mode == DHD_FLAG_IBSS_MODE)) {
- dhd->op_mode = DHD_FLAG_IBSS_MODE;
- } else
- dhd->op_mode = DHD_FLAG_STA_MODE;
-#if !defined(AP) && defined(WLP2P)
- if (dhd->op_mode != DHD_FLAG_IBSS_MODE &&
- (concurrent_mode = dhd_get_concurrent_capabilites(dhd))) {
-#if defined(ARP_OFFLOAD_SUPPORT)
- arpoe = 1;
-#endif
- dhd->op_mode |= concurrent_mode;
- }
-
- /* Check if we are enabling p2p */
- if (dhd->op_mode & DHD_FLAG_P2P_MODE) {
- bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf));
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
- iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
- DHD_ERROR(("%s APSTA for P2P failed ret= %d\n", __FUNCTION__, ret));
- }
-
-#if defined(SOFTAP_AND_GC)
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_AP,
- (char *)&ap_mode, sizeof(ap_mode), TRUE, 0)) < 0) {
- DHD_ERROR(("%s WLC_SET_AP failed %d\n", __FUNCTION__, ret));
- }
-#endif
- memcpy(&p2p_ea, &dhd->mac, ETHER_ADDR_LEN);
- ETHER_SET_LOCALADDR(&p2p_ea);
- bcm_mkiovar("p2p_da_override", (char *)&p2p_ea,
- ETHER_ADDR_LEN, iovbuf, sizeof(iovbuf));
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
- iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
- DHD_ERROR(("%s p2p_da_override ret= %d\n", __FUNCTION__, ret));
- } else {
- DHD_INFO(("dhd_preinit_ioctls: p2p_da_override succeeded\n"));
- }
- }
-#else
- (void)concurrent_mode;
-#endif
- }
-
- DHD_ERROR(("Firmware up: op_mode=0x%04x, MAC="MACDBG"\n",
- dhd->op_mode, MAC2STRDBG(dhd->mac.octet)));
- /* Set Country code */
- if (dhd->dhd_cspec.ccode[0] != 0) {
- printf("Set country %s, revision %d\n", dhd->dhd_cspec.ccode, dhd->dhd_cspec.rev);
- bcm_mkiovar("country", (char *)&dhd->dhd_cspec,
- sizeof(wl_country_t), iovbuf, sizeof(iovbuf));
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
- printf("%s: country code setting failed %d\n", __FUNCTION__, ret);
- } else {
- dhd_conf_set_country(dhd);
- dhd_conf_fix_country(dhd);
- }
- dhd_conf_get_country(dhd, &dhd->dhd_cspec);
-
-#if defined(DISABLE_11AC)
- bcm_mkiovar("vhtmode", (char *)&vhtmode, 4, iovbuf, sizeof(iovbuf));
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
- DHD_ERROR(("%s wl vhtmode 0 failed %d\n", __FUNCTION__, ret));
-#endif /* DISABLE_11AC */
-
- /* Set Listen Interval */
- bcm_mkiovar("assoc_listen", (char *)&listen_interval, 4, iovbuf, sizeof(iovbuf));
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
- DHD_ERROR(("%s assoc_listen failed %d\n", __FUNCTION__, ret));
-
-#if defined(ROAM_ENABLE) || defined(DISABLE_BUILTIN_ROAM)
- /* Disable built-in roaming to allowed ext supplicant to take care of roaming */
- bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf));
- dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
-#endif /* ROAM_ENABLE || DISABLE_BUILTIN_ROAM */
-#if defined(ROAM_ENABLE)
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_TRIGGER, roam_trigger,
- sizeof(roam_trigger), TRUE, 0)) < 0)
- DHD_ERROR(("%s: roam trigger set failed %d\n", __FUNCTION__, ret));
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_SCAN_PERIOD, roam_scan_period,
- sizeof(roam_scan_period), TRUE, 0)) < 0)
- DHD_ERROR(("%s: roam scan period set failed %d\n", __FUNCTION__, ret));
- if ((dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_DELTA, roam_delta,
- sizeof(roam_delta), TRUE, 0)) < 0)
- DHD_ERROR(("%s: roam delta set failed %d\n", __FUNCTION__, ret));
- bcm_mkiovar("fullroamperiod", (char *)&roam_fullscan_period, 4, iovbuf, sizeof(iovbuf));
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
- DHD_ERROR(("%s: roam fullscan period set failed %d\n", __FUNCTION__, ret));
-#endif /* ROAM_ENABLE */
- dhd_conf_set_roam(dhd);
-
-#ifdef BCMCCX
- bcm_mkiovar("ccx_enable", (char *)&ccx, 4, iovbuf, sizeof(iovbuf));
- dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
-#endif /* BCMCCX */
-#ifdef WLTDLS
- /* by default TDLS on and auto mode off */
- _dhd_tdls_enable(dhd, true, false, NULL);
-#endif /* WLTDLS */
-
-#ifdef DHD_ENABLE_LPC
- /* Set lpc 1 */
- bcm_mkiovar("lpc", (char *)&lpc, 4, iovbuf, sizeof(iovbuf));
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
- sizeof(iovbuf), TRUE, 0)) < 0) {
- DHD_ERROR(("%s Set lpc failed %d\n", __FUNCTION__, ret));
- }
-#endif /* DHD_ENABLE_LPC */
-
- /* Set PowerSave mode */
- dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, sizeof(power_mode), TRUE, 0);
-
- /* Match Host and Dongle rx alignment */
- bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf, sizeof(iovbuf));
- dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
-
-#if defined(CUSTOMER_HW2) && defined(USE_WL_CREDALL)
- /* enable credall to reduce the chance of no bus credit happened. */
- bcm_mkiovar("bus:credall", (char *)&credall, 4, iovbuf, sizeof(iovbuf));
- dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
-#endif
-
-#if defined(BCMSDIO)
- if (glom != DEFAULT_GLOM_VALUE) {
- DHD_INFO(("%s set glom=0x%X\n", __FUNCTION__, glom));
- bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf));
- dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
- }
-#endif /* defined(BCMSDIO) */
- dhd_conf_set_glom(dhd);
-
- /* Setup timeout if Beacons are lost and roam is off to report link down */
- bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, sizeof(iovbuf));
- dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
- /* Setup assoc_retry_max count to reconnect target AP in dongle */
- bcm_mkiovar("assoc_retry_max", (char *)&retry_max, 4, iovbuf, sizeof(iovbuf));
- dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
-#if defined(AP) && !defined(WLP2P)
- /* Turn off MPC in AP mode */
- bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf));
- dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
- bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf));
- dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
-#endif /* defined(AP) && !defined(WLP2P) */
- dhd_conf_set_mimo_bw_cap(dhd);
- dhd_conf_force_wme(dhd);
- dhd_conf_set_stbc(dhd);
- dhd_conf_set_srl(dhd);
- dhd_conf_set_lrl(dhd);
- dhd_conf_set_spect(dhd);
-
-#if defined(SOFTAP)
- if (ap_fw_loaded == TRUE) {
- dhd_wl_ioctl_cmd(dhd, WLC_SET_DTIMPRD, (char *)&dtim, sizeof(dtim), TRUE, 0);
- }
-#endif
-
-#if defined(KEEP_ALIVE)
- {
- /* Set Keep Alive : be sure to use FW with -keepalive */
- int res;
-
-#if defined(SOFTAP)
- if (ap_fw_loaded == FALSE)
-#endif
- if (!(dhd->op_mode &
- (DHD_FLAG_HOSTAP_MODE | DHD_FLAG_MFG_MODE))) {
- if ((res = dhd_keep_alive_onoff(dhd)) < 0)
- DHD_ERROR(("%s set keeplive failed %d\n",
- __FUNCTION__, res));
- }
- }
-#endif /* defined(KEEP_ALIVE) */
-
-#ifdef USE_WL_TXBF
- bcm_mkiovar("txbf", (char *)&txbf, 4, iovbuf, sizeof(iovbuf));
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
- sizeof(iovbuf), TRUE, 0)) < 0) {
- DHD_ERROR(("%s Set txbf failed %d\n", __FUNCTION__, ret));
- }
-#endif /* USE_WL_TXBF */
-#ifdef USE_WL_FRAMEBURST
- /* Set frameburst to value */
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_FAKEFRAG, (char *)&frameburst,
- sizeof(frameburst), TRUE, 0)) < 0) {
- DHD_ERROR(("%s Set frameburst failed %d\n", __FUNCTION__, ret));
- }
-#endif /* USE_WL_FRAMEBURST */
-#ifdef DHD_SET_FW_HIGHSPEED
- /* Set ack_ratio */
- bcm_mkiovar("ack_ratio", (char *)&ack_ratio, 4, iovbuf, sizeof(iovbuf));
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
- sizeof(iovbuf), TRUE, 0)) < 0) {
- DHD_ERROR(("%s Set ack_ratio failed %d\n", __FUNCTION__, ret));
- }
-
- /* Set ack_ratio_depth */
- bcm_mkiovar("ack_ratio_depth", (char *)&ack_ratio_depth, 4, iovbuf, sizeof(iovbuf));
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
- sizeof(iovbuf), TRUE, 0)) < 0) {
- DHD_ERROR(("%s Set ack_ratio_depth failed %d\n", __FUNCTION__, ret));
- }
-#endif /* DHD_SET_FW_HIGHSPEED */
-#if defined(CUSTOM_AMPDU_BA_WSIZE) || (defined(WLAIBSS) && \
- defined(CUSTOM_IBSS_AMPDU_BA_WSIZE))
- /* Set ampdu ba wsize to 64 or 16 */
-#ifdef CUSTOM_AMPDU_BA_WSIZE
- ampdu_ba_wsize = CUSTOM_AMPDU_BA_WSIZE;
-#endif
-#if defined(WLAIBSS) && defined(CUSTOM_IBSS_AMPDU_BA_WSIZE)
- if (dhd->op_mode == DHD_FLAG_IBSS_MODE)
- ampdu_ba_wsize = CUSTOM_IBSS_AMPDU_BA_WSIZE;
-#endif /* WLAIBSS && CUSTOM_IBSS_AMPDU_BA_WSIZE */
- if (ampdu_ba_wsize != 0) {
- bcm_mkiovar("ampdu_ba_wsize", (char *)&ampdu_ba_wsize, 4, iovbuf, sizeof(iovbuf));
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
- sizeof(iovbuf), TRUE, 0)) < 0) {
- DHD_ERROR(("%s Set ampdu_ba_wsize to %d failed %d\n",
- __FUNCTION__, ampdu_ba_wsize, ret));
- }
- }
-#endif /* CUSTOM_AMPDU_BA_WSIZE || (WLAIBSS && CUSTOM_IBSS_AMPDU_BA_WSIZE) */
-
-#ifdef WLAIBSS
- /* Configure custom IBSS beacon transmission */
- if (dhd->op_mode & DHD_FLAG_IBSS_MODE)
- {
- aibss = 1;
- bcm_mkiovar("aibss", (char *)&aibss, 4, iovbuf, sizeof(iovbuf));
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
- sizeof(iovbuf), TRUE, 0)) < 0) {
- DHD_ERROR(("%s Set aibss to %d failed %d\n",
- __FUNCTION__, aibss, ret));
- }
-#ifdef WLAIBSS_PS
- aibss_ps = 1;
- bcm_mkiovar("aibss_ps", (char *)&aibss_ps, 4, iovbuf, sizeof(iovbuf));
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
- sizeof(iovbuf), TRUE, 0)) < 0) {
- DHD_ERROR(("%s Set aibss PS to %d failed %d\n",
- __FUNCTION__, aibss, ret));
- }
-#endif /* WLAIBSS_PS */
- }
- memset(&bcn_config, 0, sizeof(bcn_config));
- bcn_config.initial_min_bcn_dur = AIBSS_INITIAL_MIN_BCN_DUR;
- bcn_config.min_bcn_dur = AIBSS_MIN_BCN_DUR;
- bcn_config.bcn_flood_dur = AIBSS_BCN_FLOOD_DUR;
- bcn_config.version = AIBSS_BCN_FORCE_CONFIG_VER_0;
- bcn_config.len = sizeof(bcn_config);
-
- bcm_mkiovar("aibss_bcn_force_config", (char *)&bcn_config,
- sizeof(aibss_bcn_force_config_t), iov_buf, sizeof(iov_buf));
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iov_buf,
- sizeof(iov_buf), TRUE, 0)) < 0) {
- DHD_ERROR(("%s Set aibss_bcn_force_config to %d, %d, %d failed %d\n",
- __FUNCTION__, AIBSS_INITIAL_MIN_BCN_DUR, AIBSS_MIN_BCN_DUR,
- AIBSS_BCN_FLOOD_DUR, ret));
- }
-#endif /* WLAIBSS */
-
-#if defined(CUSTOM_AMPDU_MPDU)
- ampdu_mpdu = CUSTOM_AMPDU_MPDU;
- if (ampdu_mpdu != 0 && (ampdu_mpdu <= ampdu_ba_wsize)) {
- bcm_mkiovar("ampdu_mpdu", (char *)&ampdu_mpdu, 4, iovbuf, sizeof(iovbuf));
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
- sizeof(iovbuf), TRUE, 0)) < 0) {
- DHD_ERROR(("%s Set ampdu_mpdu to %d failed %d\n",
- __FUNCTION__, CUSTOM_AMPDU_MPDU, ret));
- }
- }
-#endif /* CUSTOM_AMPDU_MPDU */
- dhd_conf_set_ampdu_ba_wsize(dhd);
-
-#if defined(CUSTOM_AMPDU_RELEASE)
- ampdu_release = CUSTOM_AMPDU_RELEASE;
- if (ampdu_release != 0 && (ampdu_release <= ampdu_ba_wsize)) {
- bcm_mkiovar("ampdu_release", (char *)&ampdu_release, 4, iovbuf, sizeof(iovbuf));
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
- sizeof(iovbuf), TRUE, 0)) < 0) {
- DHD_ERROR(("%s Set ampdu_release to %d failed %d\n",
- __FUNCTION__, CUSTOM_AMPDU_RELEASE, ret));
- }
- }
-#endif /* CUSTOM_AMPDU_RELEASE */
-
-#if defined(BCMSUP_4WAY_HANDSHAKE) && defined(WLAN_AKM_SUITE_FT_8021X)
- /* Read 4-way handshake requirements */
- if (dhd_use_idsup == 1) {
- bcm_mkiovar("sup_wpa", (char *)&sup_wpa, 4, iovbuf, sizeof(iovbuf));
- ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0);
- /* sup_wpa iovar returns NOTREADY status on some platforms using modularized
- * in-dongle supplicant.
- */
- if (ret >= 0 || ret == BCME_NOTREADY)
- dhd->fw_4way_handshake = TRUE;
- DHD_TRACE(("4-way handshake mode is: %d\n", dhd->fw_4way_handshake));
- }
-#endif /* BCMSUP_4WAY_HANDSHAKE && WLAN_AKM_SUITE_FT_8021X */
-#ifdef SUPPORT_2G_VHT
- bcm_mkiovar("vht_features", (char *)&vht_features, 4, iovbuf, sizeof(iovbuf));
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
- DHD_ERROR(("%s vht_features set failed %d\n", __FUNCTION__, ret));
- }
-#endif /* SUPPORT_2G_VHT */
-#ifdef CUSTOM_PSPRETEND_THR
- /* Turn off MPC in AP mode */
- bcm_mkiovar("pspretend_threshold", (char *)&pspretend_thr, 4,
- iovbuf, sizeof(iovbuf));
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
- sizeof(iovbuf), TRUE, 0)) < 0) {
- DHD_ERROR(("%s pspretend_threshold for HostAPD failed %d\n",
- __FUNCTION__, ret));
- }
-#endif
-
- bcm_mkiovar("buf_key_b4_m4", (char *)&buf_key_b4_m4, 4, iovbuf, sizeof(iovbuf));
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
- sizeof(iovbuf), TRUE, 0)) < 0) {
- DHD_ERROR(("%s buf_key_b4_m4 set failed %d\n", __FUNCTION__, ret));
- }
-
- /* Read event_msgs mask */
- bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf));
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0)) < 0) {
- DHD_ERROR(("%s read Event mask failed %d\n", __FUNCTION__, ret));
- goto done;
- }
- bcopy(iovbuf, eventmask, WL_EVENTING_MASK_LEN);
-
- /* Setup event_msgs */
- setbit(eventmask, WLC_E_SET_SSID);
- setbit(eventmask, WLC_E_PRUNE);
- setbit(eventmask, WLC_E_AUTH);
- setbit(eventmask, WLC_E_AUTH_IND);
- setbit(eventmask, WLC_E_ASSOC);
- setbit(eventmask, WLC_E_REASSOC);
- setbit(eventmask, WLC_E_REASSOC_IND);
- setbit(eventmask, WLC_E_DEAUTH);
- setbit(eventmask, WLC_E_DEAUTH_IND);
- setbit(eventmask, WLC_E_DISASSOC_IND);
- setbit(eventmask, WLC_E_DISASSOC);
- setbit(eventmask, WLC_E_JOIN);
- setbit(eventmask, WLC_E_START);
- setbit(eventmask, WLC_E_ASSOC_IND);
- setbit(eventmask, WLC_E_PSK_SUP);
- setbit(eventmask, WLC_E_LINK);
- setbit(eventmask, WLC_E_NDIS_LINK);
- setbit(eventmask, WLC_E_MIC_ERROR);
- setbit(eventmask, WLC_E_ASSOC_REQ_IE);
- setbit(eventmask, WLC_E_ASSOC_RESP_IE);
-#ifndef WL_CFG80211
- setbit(eventmask, WLC_E_PMKID_CACHE);
- setbit(eventmask, WLC_E_TXFAIL);
-#endif
- setbit(eventmask, WLC_E_JOIN_START);
- setbit(eventmask, WLC_E_SCAN_COMPLETE);
-#ifdef WLMEDIA_HTSF
- setbit(eventmask, WLC_E_HTSFSYNC);
-#endif /* WLMEDIA_HTSF */
-#ifdef PNO_SUPPORT
- setbit(eventmask, WLC_E_PFN_NET_FOUND);
- setbit(eventmask, WLC_E_PFN_BEST_BATCHING);
- setbit(eventmask, WLC_E_PFN_BSSID_NET_FOUND);
- setbit(eventmask, WLC_E_PFN_BSSID_NET_LOST);
-#endif /* PNO_SUPPORT */
- /* enable dongle roaming event */
- setbit(eventmask, WLC_E_ROAM);
- setbit(eventmask, WLC_E_BSSID);
-#ifdef BCMCCX
- setbit(eventmask, WLC_E_ADDTS_IND);
- setbit(eventmask, WLC_E_DELTS_IND);
-#endif /* BCMCCX */
-#ifdef WLTDLS
- setbit(eventmask, WLC_E_TDLS_PEER_EVENT);
-#endif /* WLTDLS */
-#ifdef WL_CFG80211
- setbit(eventmask, WLC_E_ESCAN_RESULT);
- if (dhd->op_mode & DHD_FLAG_P2P_MODE) {
- setbit(eventmask, WLC_E_ACTION_FRAME_RX);
- setbit(eventmask, WLC_E_P2P_DISC_LISTEN_COMPLETE);
- }
-#endif /* WL_CFG80211 */
-#ifdef WLAIBSS
- setbit(eventmask, WLC_E_AIBSS_TXFAIL);
-#endif /* WLAIBSS */
- setbit(eventmask, WLC_E_TRACE);
-
- /* Write updated Event mask */
- bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf));
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
- DHD_ERROR(("%s Set Event mask failed %d\n", __FUNCTION__, ret));
- goto done;
- }
-
- /* make up event mask ext message iovar for event larger than 128 */
- msglen = ROUNDUP(WLC_E_LAST, NBBY)/NBBY + EVENTMSGS_EXT_STRUCT_SIZE;
- eventmask_msg = (eventmsgs_ext_t*)kmalloc(msglen, GFP_KERNEL);
- if (eventmask_msg == NULL) {
- DHD_ERROR(("failed to allocate %d bytes for event_msg_ext\n", msglen));
- return BCME_NOMEM;
- }
- bzero(eventmask_msg, msglen);
- eventmask_msg->ver = EVENTMSGS_VER;
- eventmask_msg->len = ROUNDUP(WLC_E_LAST, NBBY)/NBBY;
-
- /* Read event_msgs_ext mask */
- bcm_mkiovar("event_msgs_ext", (char *)eventmask_msg, msglen, iov_buf, sizeof(iov_buf));
- ret2 = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iov_buf, sizeof(iov_buf), FALSE, 0);
- if (ret2 != BCME_UNSUPPORTED)
- ret = ret2;
- if (ret2 == 0) { /* event_msgs_ext must be supported */
- bcopy(iov_buf, eventmask_msg, msglen);
-
-#ifdef BT_WIFI_HANDOVER
- setbit(eventmask_msg->mask, WLC_E_BT_WIFI_HANDOVER_REQ);
-#endif /* BT_WIFI_HANDOVER */
-
- /* Write updated Event mask */
- eventmask_msg->ver = EVENTMSGS_VER;
- eventmask_msg->command = EVENTMSGS_SET_MASK;
- eventmask_msg->len = ROUNDUP(WLC_E_LAST, NBBY)/NBBY;
- bcm_mkiovar("event_msgs_ext", (char *)eventmask_msg,
- msglen, iov_buf, sizeof(iov_buf));
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
- iov_buf, sizeof(iov_buf), TRUE, 0)) < 0) {
- DHD_ERROR(("%s write event mask ext failed %d\n", __FUNCTION__, ret));
- kfree(eventmask_msg);
- goto done;
- }
- } else if (ret2 < 0 && ret2 != BCME_UNSUPPORTED) {
- DHD_ERROR(("%s read event mask ext failed %d\n", __FUNCTION__, ret2));
- kfree(eventmask_msg);
- goto done;
- } /* unsupported is ok */
- kfree(eventmask_msg);
-
- dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_CHANNEL_TIME, (char *)&scan_assoc_time,
- sizeof(scan_assoc_time), TRUE, 0);
- dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_UNASSOC_TIME, (char *)&scan_unassoc_time,
- sizeof(scan_unassoc_time), TRUE, 0);
- dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_PASSIVE_TIME, (char *)&scan_passive_time,
- sizeof(scan_passive_time), TRUE, 0);
-
-#ifdef ARP_OFFLOAD_SUPPORT
- /* Set and enable ARP offload feature for STA only */
-#if defined(SOFTAP)
- if (arpoe && !ap_fw_loaded)
-#else
- if (arpoe)
-#endif
- {
- dhd_arp_offload_enable(dhd, TRUE);
- dhd_arp_offload_set(dhd, dhd_arp_mode);
- } else {
- dhd_arp_offload_enable(dhd, FALSE);
- dhd_arp_offload_set(dhd, 0);
- }
- dhd_arp_enable = arpoe;
-#endif /* ARP_OFFLOAD_SUPPORT */
-
-#ifdef PKT_FILTER_SUPPORT
- /* Setup default defintions for pktfilter , enable in suspend */
- dhd->pktfilter_count = 6;
- /* Setup filter to allow only unicast */
- if (dhd_master_mode) {
- dhd->pktfilter[DHD_UNICAST_FILTER_NUM] = "100 0 0 0 0x01 0x00";
- dhd->pktfilter[DHD_BROADCAST_FILTER_NUM] = NULL;
- dhd->pktfilter[DHD_MULTICAST4_FILTER_NUM] = NULL;
- dhd->pktfilter[DHD_MULTICAST6_FILTER_NUM] = NULL;
- /* Add filter to pass multicastDNS packet and NOT filter out as Broadcast */
- dhd->pktfilter[DHD_MDNS_FILTER_NUM] = "104 0 0 0 0xFFFFFFFFFFFF 0x01005E0000FB";
- /* apply APP pktfilter */
- dhd->pktfilter[DHD_ARP_FILTER_NUM] = "105 0 0 12 0xFFFF 0x0806";
- } else
- dhd_conf_discard_pkt_filter(dhd);
- dhd_conf_add_pkt_filter(dhd);
-
-#if defined(SOFTAP)
- if (ap_fw_loaded) {
- dhd_enable_packet_filter(0, dhd);
- }
-#endif /* defined(SOFTAP) */
- dhd_set_packet_filter(dhd);
-#endif /* PKT_FILTER_SUPPORT */
-#ifdef DISABLE_11N
- bcm_mkiovar("nmode", (char *)&nmode, 4, iovbuf, sizeof(iovbuf));
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
- DHD_ERROR(("%s wl nmode 0 failed %d\n", __FUNCTION__, ret));
-#endif /* DISABLE_11N */
-
-#ifdef AMPDU_VO_ENABLE
- tid.tid = PRIO_8021D_VO; /* Enable TID(6) for voice */
- tid.enable = TRUE;
- bcm_mkiovar("ampdu_tid", (char *)&tid, sizeof(tid), iovbuf, sizeof(iovbuf));
- dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
-
- tid.tid = PRIO_8021D_NC; /* Enable TID(7) for voice */
- tid.enable = TRUE;
- bcm_mkiovar("ampdu_tid", (char *)&tid, sizeof(tid), iovbuf, sizeof(iovbuf));
- dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
-#endif
-#if defined(SOFTAP_TPUT_ENHANCE)
- if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
- dhd_bus_setidletime(dhd, (int)100);
-#ifdef DHDTCPACK_SUPPRESS
- dhd->tcpack_sup_enabled = FALSE;
-#endif
-#if defined(DHD_TCP_WINSIZE_ADJUST)
- dhd_use_tcp_window_size_adjust = TRUE;
-#endif
-
- memset(buf, 0, sizeof(buf));
- bcm_mkiovar("bus:txglom_auto_control", 0, 0, buf, sizeof(buf));
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), FALSE, 0)) < 0) {
- glom = 0;
- bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf));
- dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
- }
- else {
- if (buf[0] == 0) {
- glom = 1;
- bcm_mkiovar("bus:txglom_auto_control", (char *)&glom, 4, iovbuf,
- sizeof(iovbuf));
- dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
- }
- }
- }
-#endif /* SOFTAP_TPUT_ENHANCE */
-
- /* query for 'ver' to get version info from firmware */
- memset(buf, 0, sizeof(buf));
- ptr = buf;
- bcm_mkiovar("ver", (char *)&buf, 4, buf, sizeof(buf));
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), FALSE, 0)) < 0)
- DHD_ERROR(("%s failed %d\n", __FUNCTION__, ret));
- else {
- bcmstrtok(&ptr, "\n", 0);
- /* Print fw version info */
- DHD_ERROR(("Firmware version = %s\n", buf));
-#if defined(BCMSDIO)
- dhd_set_version_info(dhd, buf);
-#endif /* defined(BCMSDIO) */
- }
-
-#if defined(BCMSDIO)
- dhd_txglom_enable(dhd, TRUE);
-#endif /* defined(BCMSDIO) */
-
-#if defined(BCMSDIO)
-#ifdef PROP_TXSTATUS
- if (disable_proptx ||
-#ifdef PROP_TXSTATUS_VSDB
- /* enable WLFC only if the firmware is VSDB when it is in STA mode */
- (dhd->op_mode != DHD_FLAG_HOSTAP_MODE &&
- dhd->op_mode != DHD_FLAG_IBSS_MODE) ||
-#endif /* PROP_TXSTATUS_VSDB */
- FALSE) {
- wlfc_enable = FALSE;
- }
-
-#ifndef DISABLE_11N
- ret = dhd_wl_ioctl_cmd(dhd, WLC_DOWN, (char *)&wl_down, sizeof(wl_down), TRUE, 0);
- bcm_mkiovar("ampdu_hostreorder", (char *)&hostreorder, 4, iovbuf, sizeof(iovbuf));
- if ((ret2 = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
- DHD_ERROR(("%s wl ampdu_hostreorder failed %d\n", __FUNCTION__, ret2));
- if (ret2 != BCME_UNSUPPORTED)
- ret = ret2;
- if (ret2 != BCME_OK)
- hostreorder = 0;
- }
-#endif /* DISABLE_11N */
-
-#ifdef READ_CONFIG_FROM_FILE
- dhd_preinit_config(dhd, 0);
-#endif /* READ_CONFIG_FROM_FILE */
-
- if (wlfc_enable)
- dhd_wlfc_init(dhd);
-#ifndef DISABLE_11N
- else if (hostreorder)
- dhd_wlfc_hostreorder_init(dhd);
-#endif /* DISABLE_11N */
-
-#endif /* PROP_TXSTATUS */
-#endif /* BCMSDIO || BCMBUS */
-#ifdef PCIE_FULL_DONGLE
- /* For FD we need all the packets at DHD to handle intra-BSS forwarding */
- if (FW_SUPPORTED(dhd, ap)) {
- wl_ap_isolate = AP_ISOLATE_SENDUP_ALL;
- bcm_mkiovar("ap_isolate", (char *)&wl_ap_isolate, 4, iovbuf, sizeof(iovbuf));
- if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
- DHD_ERROR(("%s failed %d\n", __FUNCTION__, ret));
- }
-#endif /* PCIE_FULL_DONGLE */
-#ifdef PNO_SUPPORT
- if (!dhd->pno_state) {
- dhd_pno_init(dhd);
- }
-#endif
-#ifdef WL11U
- dhd_interworking_enable(dhd);
-#endif /* WL11U */
-#ifndef WL_CFG80211
- dhd_wl_ioctl_cmd(dhd, WLC_UP, (char *)&up, sizeof(up), TRUE, 0);
-#endif
-
-done:
- return ret;
-}
-
-
-int
-dhd_iovar(dhd_pub_t *pub, int ifidx, char *name, char *cmd_buf, uint cmd_len, int set)
-{
- char buf[strlen(name) + 1 + cmd_len];
- int len = sizeof(buf);
- wl_ioctl_t ioc;
- int ret;
-
- len = bcm_mkiovar(name, cmd_buf, cmd_len, buf, len);
-
- memset(&ioc, 0, sizeof(ioc));
-
- ioc.cmd = set? WLC_SET_VAR : WLC_GET_VAR;
- ioc.buf = buf;
- ioc.len = len;
- ioc.set = set;
-
- ret = dhd_wl_ioctl(pub, ifidx, &ioc, ioc.buf, ioc.len);
- if (!set && ret >= 0)
- memcpy(cmd_buf, buf, cmd_len);
-
- return ret;
-}
-
-int dhd_change_mtu(dhd_pub_t *dhdp, int new_mtu, int ifidx)
-{
- struct dhd_info *dhd = dhdp->info;
- struct net_device *dev = NULL;
-
- ASSERT(dhd && dhd->iflist[ifidx]);
- dev = dhd->iflist[ifidx]->net;
- ASSERT(dev);
-
- if (netif_running(dev)) {
- DHD_ERROR(("%s: Must be down to change its MTU", dev->name));
- return BCME_NOTDOWN;
- }
-
-#define DHD_MIN_MTU 1500
-#define DHD_MAX_MTU 1752
-
- if ((new_mtu < DHD_MIN_MTU) || (new_mtu > DHD_MAX_MTU)) {
- DHD_ERROR(("%s: MTU size %d is invalid.\n", __FUNCTION__, new_mtu));
- return BCME_BADARG;
- }
-
- dev->mtu = new_mtu;
- return 0;
-}
-
-#ifdef ARP_OFFLOAD_SUPPORT
-/* add or remove AOE host ip(s) (up to 8 IPs on the interface) */
-void
-aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add, int idx)
-{
- u32 ipv4_buf[MAX_IPV4_ENTRIES]; /* temp save for AOE host_ip table */
- int i;
- int ret;
-
- bzero(ipv4_buf, sizeof(ipv4_buf));
-
- /* display what we've got */
- ret = dhd_arp_get_arp_hostip_table(dhd_pub, ipv4_buf, sizeof(ipv4_buf), idx);
- DHD_ARPOE(("%s: hostip table read from Dongle:\n", __FUNCTION__));
-#ifdef AOE_DBG
- dhd_print_buf(ipv4_buf, 32, 4); /* max 8 IPs 4b each */
-#endif
- /* now we saved hoste_ip table, clr it in the dongle AOE */
- dhd_aoe_hostip_clr(dhd_pub, idx);
-
- if (ret) {
- DHD_ERROR(("%s failed\n", __FUNCTION__));
- return;
- }
-
- for (i = 0; i < MAX_IPV4_ENTRIES; i++) {
- if (add && (ipv4_buf[i] == 0)) {
- ipv4_buf[i] = ipa;
- add = FALSE; /* added ipa to local table */
- DHD_ARPOE(("%s: Saved new IP in temp arp_hostip[%d]\n",
- __FUNCTION__, i));
- } else if (ipv4_buf[i] == ipa) {
- ipv4_buf[i] = 0;
- DHD_ARPOE(("%s: removed IP:%x from temp table %d\n",
- __FUNCTION__, ipa, i));
- }
-
- if (ipv4_buf[i] != 0) {
- /* add back host_ip entries from our local cache */
- dhd_arp_offload_add_ip(dhd_pub, ipv4_buf[i], idx);
- DHD_ARPOE(("%s: added IP:%x to dongle arp_hostip[%d]\n\n",
- __FUNCTION__, ipv4_buf[i], i));
- }
- }
-#ifdef AOE_DBG
- /* see the resulting hostip table */
- dhd_arp_get_arp_hostip_table(dhd_pub, ipv4_buf, sizeof(ipv4_buf), idx);
- DHD_ARPOE(("%s: read back arp_hostip table:\n", __FUNCTION__));
- dhd_print_buf(ipv4_buf, 32, 4); /* max 8 IPs 4b each */
-#endif
-}
-
-/*
- * Notification mechanism from kernel to our driver. This function is called by the Linux kernel
- * whenever there is an event related to an IP address.
- * ptr : kernel provided pointer to IP address that has changed
- */
-static int dhd_inetaddr_notifier_call(struct notifier_block *this,
- unsigned long event,
- void *ptr)
-{
- struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
-
- dhd_info_t *dhd;
- dhd_pub_t *dhd_pub;
- int idx;
-
- if (!dhd_arp_enable)
- return NOTIFY_DONE;
- if (!ifa || !(ifa->ifa_dev->dev))
- return NOTIFY_DONE;
-
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31))
- /* Filter notifications meant for non Broadcom devices */
- if ((ifa->ifa_dev->dev->netdev_ops != &dhd_ops_pri) &&
- (ifa->ifa_dev->dev->netdev_ops != &dhd_ops_virt)) {
-#if defined(WL_ENABLE_P2P_IF)
- if (!wl_cfgp2p_is_ifops(ifa->ifa_dev->dev->netdev_ops))
-#endif /* WL_ENABLE_P2P_IF */
- return NOTIFY_DONE;
- }
-#endif /* LINUX_VERSION_CODE */
-
- dhd = DHD_DEV_INFO(ifa->ifa_dev->dev);
- if (!dhd)
- return NOTIFY_DONE;
-
- dhd_pub = &dhd->pub;
-
- if (dhd_pub->arp_version == 1) {
- idx = 0;
- }
- else {
- for (idx = 0; idx < DHD_MAX_IFS; idx++) {
- if (dhd->iflist[idx] && dhd->iflist[idx]->net == ifa->ifa_dev->dev)
- break;
- }
- if (idx < DHD_MAX_IFS)
- DHD_TRACE(("ifidx : %p %s %d\n", dhd->iflist[idx]->net,
- dhd->iflist[idx]->name, dhd->iflist[idx]->idx));
- else {
- DHD_ERROR(("Cannot find ifidx for(%s) set to 0\n", ifa->ifa_label));
- idx = 0;
- }
- }
-
- switch (event) {
- case NETDEV_UP:
- DHD_ARPOE(("%s: [%s] Up IP: 0x%x\n",
- __FUNCTION__, ifa->ifa_label, ifa->ifa_address));
-
- if (dhd->pub.busstate != DHD_BUS_DATA) {
- DHD_ERROR(("%s: bus not ready, exit\n", __FUNCTION__));
- if (dhd->pend_ipaddr) {
- DHD_ERROR(("%s: overwrite pending ipaddr: 0x%x\n",
- __FUNCTION__, dhd->pend_ipaddr));
- }
- dhd->pend_ipaddr = ifa->ifa_address;
- break;
- }
-
-#ifdef AOE_IP_ALIAS_SUPPORT
- DHD_ARPOE(("%s:add aliased IP to AOE hostip cache\n",
- __FUNCTION__));
- aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, TRUE, idx);
-#endif /* AOE_IP_ALIAS_SUPPORT */
- break;
-
- case NETDEV_DOWN:
- DHD_ARPOE(("%s: [%s] Down IP: 0x%x\n",
- __FUNCTION__, ifa->ifa_label, ifa->ifa_address));
- dhd->pend_ipaddr = 0;
-#ifdef AOE_IP_ALIAS_SUPPORT
- DHD_ARPOE(("%s:interface is down, AOE clr all for this if\n",
- __FUNCTION__));
- aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, FALSE, idx);
-#else
- dhd_aoe_hostip_clr(&dhd->pub, idx);
- dhd_aoe_arp_clr(&dhd->pub, idx);
-#endif /* AOE_IP_ALIAS_SUPPORT */
- break;
-
- default:
- DHD_ARPOE(("%s: do noting for [%s] Event: %lu\n",
- __func__, ifa->ifa_label, event));
- break;
- }
- return NOTIFY_DONE;
-}
-#endif /* ARP_OFFLOAD_SUPPORT */
-
-#ifdef CONFIG_IPV6
-/* Neighbor Discovery Offload: defered handler */
-static void
-dhd_inet6_work_handler(void *dhd_info, void *event_data, u8 event)
-{
- struct ipv6_work_info_t *ndo_work = (struct ipv6_work_info_t *)event_data;
- dhd_pub_t *pub = &((dhd_info_t *)dhd_info)->pub;
- int ret;
-
- if (event != DHD_WQ_WORK_IPV6_NDO) {
- DHD_ERROR(("%s: unexpected event \n", __FUNCTION__));
- return;
- }
-
- if (!ndo_work) {
- DHD_ERROR(("%s: ipv6 work info is not initialized \n", __FUNCTION__));
- return;
- }
-
- if (!pub) {
- DHD_ERROR(("%s: dhd pub is not initialized \n", __FUNCTION__));
- return;
- }
-
- if (ndo_work->if_idx) {
- DHD_ERROR(("%s: idx %d \n", __FUNCTION__, ndo_work->if_idx));
- return;
- }
-
- switch (ndo_work->event) {
- case NETDEV_UP:
- DHD_TRACE(("%s: Enable NDO and add ipv6 into table \n ", __FUNCTION__));
- ret = dhd_ndo_enable(pub, TRUE);
- if (ret < 0) {
- DHD_ERROR(("%s: Enabling NDO Failed %d\n", __FUNCTION__, ret));
- }
-
- ret = dhd_ndo_add_ip(pub, &ndo_work->ipv6_addr[0], ndo_work->if_idx);
- if (ret < 0) {
- DHD_ERROR(("%s: Adding host ip for NDO failed %d\n",
- __FUNCTION__, ret));
- }
- break;
- case NETDEV_DOWN:
- DHD_TRACE(("%s: clear ipv6 table \n", __FUNCTION__));
- ret = dhd_ndo_remove_ip(pub, ndo_work->if_idx);
- if (ret < 0) {
- DHD_ERROR(("%s: Removing host ip for NDO failed %d\n",
- __FUNCTION__, ret));
- goto done;
- }
-
- ret = dhd_ndo_enable(pub, FALSE);
- if (ret < 0) {
- DHD_ERROR(("%s: disabling NDO Failed %d\n", __FUNCTION__, ret));
- goto done;
- }
- break;
- default:
- DHD_ERROR(("%s: unknown notifier event \n", __FUNCTION__));
- break;
- }
-done:
- /* free ndo_work. alloced while scheduling the work */
- kfree(ndo_work);
-
- return;
-}
-
-/*
- * Neighbor Discovery Offload: Called when an interface
- * is assigned with ipv6 address.
- * Handles only primary interface
- */
-static int dhd_inet6addr_notifier_call(struct notifier_block *this,
- unsigned long event,
- void *ptr)
-{
- dhd_info_t *dhd;
- dhd_pub_t *dhd_pub;
- struct inet6_ifaddr *inet6_ifa = ptr;
- struct in6_addr *ipv6_addr = &inet6_ifa->addr;
- struct ipv6_work_info_t *ndo_info;
- int idx = 0; /* REVISIT */
-
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31))
- /* Filter notifications meant for non Broadcom devices */
- if (inet6_ifa->idev->dev->netdev_ops != &dhd_ops_pri) {
- return NOTIFY_DONE;
- }
-#endif /* LINUX_VERSION_CODE */
-
- dhd = DHD_DEV_INFO(inet6_ifa->idev->dev);
- if (!dhd)
- return NOTIFY_DONE;
-
- if (dhd->iflist[idx] && dhd->iflist[idx]->net != inet6_ifa->idev->dev)
- return NOTIFY_DONE;
- dhd_pub = &dhd->pub;
- if (!FW_SUPPORTED(dhd_pub, ndoe))
- return NOTIFY_DONE;
-
- ndo_info = (struct ipv6_work_info_t *)kzalloc(sizeof(struct ipv6_work_info_t), GFP_ATOMIC);
- if (!ndo_info) {
- DHD_ERROR(("%s: ipv6 work alloc failed\n", __FUNCTION__));
- return NOTIFY_DONE;
- }
-
- ndo_info->event = event;
- ndo_info->if_idx = idx;
- memcpy(&ndo_info->ipv6_addr[0], ipv6_addr, IPV6_ADDR_LEN);
-
- /* defer the work to thread as it may block kernel */
- dhd_deferred_schedule_work(dhd->dhd_deferred_wq, (void *)ndo_info, DHD_WQ_WORK_IPV6_NDO,
- dhd_inet6_work_handler, DHD_WORK_PRIORITY_LOW);
- return NOTIFY_DONE;
-}
-#endif /* #ifdef CONFIG_IPV6 */
-
-int
-dhd_register_if(dhd_pub_t *dhdp, int ifidx, bool need_rtnl_lock)
-{
- dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
- dhd_if_t *ifp;
- struct net_device *net = NULL;
- int err = 0;
- uint8 temp_addr[ETHER_ADDR_LEN] = { 0x00, 0x90, 0x4c, 0x11, 0x22, 0x33 };
-
- DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx));
-
- ASSERT(dhd && dhd->iflist[ifidx]);
- ifp = dhd->iflist[ifidx];
- net = ifp->net;
- ASSERT(net && (ifp->idx == ifidx));
-
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31))
- ASSERT(!net->open);
- net->get_stats = dhd_get_stats;
- net->do_ioctl = dhd_ioctl_entry;
- net->hard_start_xmit = dhd_start_xmit;
- net->set_mac_address = dhd_set_mac_address;
- net->set_multicast_list = dhd_set_multicast_list;
- net->open = net->stop = NULL;
-#else
- ASSERT(!net->netdev_ops);
- net->netdev_ops = &dhd_ops_virt;
-#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */
-
- /* Ok, link into the network layer... */
- if (ifidx == 0) {
- /*
- * device functions for the primary interface only
- */
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31))
- net->open = dhd_open;
- net->stop = dhd_stop;
-#else
- net->netdev_ops = &dhd_ops_pri;
-#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */
- if (!ETHER_ISNULLADDR(dhd->pub.mac.octet))
- memcpy(temp_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN);
- } else {
- /*
- * We have to use the primary MAC for virtual interfaces
- */
- memcpy(temp_addr, ifp->mac_addr, ETHER_ADDR_LEN);
- /*
- * Android sets the locally administered bit to indicate that this is a
- * portable hotspot. This will not work in simultaneous AP/STA mode,
- * nor with P2P. Need to set the Donlge's MAC address, and then use that.
- */
- if (!memcmp(temp_addr, dhd->iflist[0]->mac_addr,
- ETHER_ADDR_LEN)) {
- DHD_ERROR(("%s interface [%s]: set locally administered bit in MAC\n",
- __func__, net->name));
- temp_addr[0] |= 0x02;
- }
- }
-
- net->hard_header_len = ETH_HLEN + dhd->pub.hdrlen;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
- net->ethtool_ops = &dhd_ethtool_ops;
-#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */
-
-#if defined(WL_WIRELESS_EXT)
-#if WIRELESS_EXT < 19
- net->get_wireless_stats = dhd_get_wireless_stats;
-#endif /* WIRELESS_EXT < 19 */
-#if WIRELESS_EXT > 12
- net->wireless_handlers = (struct iw_handler_def *)&wl_iw_handler_def;
-#endif /* WIRELESS_EXT > 12 */
-#endif /* defined(WL_WIRELESS_EXT) */
-
- dhd->pub.rxsz = DBUS_RX_BUFFER_SIZE_DHD(net);
-
- memcpy(net->dev_addr, temp_addr, ETHER_ADDR_LEN);
-
- if (ifidx == 0)
- printf("%s\n", dhd_version);
-
- if (need_rtnl_lock)
- err = register_netdev(net);
- else
- err = register_netdevice(net);
-
- if (err != 0) {
- DHD_ERROR(("couldn't register the net device [%s], err %d\n", net->name, err));
- goto fail;
- }
-
-
-
- printf("Register interface [%s] MAC: "MACDBG"\n\n", net->name,
- MAC2STRDBG(net->dev_addr));
-
-#if defined(SOFTAP) && defined(WL_WIRELESS_EXT) && !defined(WL_CFG80211)
-// wl_iw_iscan_set_scan_broadcast_prep(net, 1);
-#endif
-
-#if 1 && (defined(BCMPCIE) || (defined(BCMLXSDMMC) && (LINUX_VERSION_CODE >= \
- KERNEL_VERSION(2, 6, 27))))
- if (ifidx == 0) {
-#ifdef BCMLXSDMMC
- up(&dhd_registration_sem);
-#endif
- if (!dhd_download_fw_on_driverload) {
- dhd_net_bus_devreset(net, TRUE);
-#ifdef BCMLXSDMMC
- dhd_net_bus_suspend(net);
-#endif /* BCMLXSDMMC */
- wifi_platform_set_power(dhdp->info->adapter, FALSE, WIFI_TURNOFF_DELAY);
- }
- }
-#endif /* OEM_ANDROID && (BCMPCIE || (BCMLXSDMMC && KERNEL_VERSION >= 2.6.27)) */
- return 0;
-
-fail:
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)
- net->open = NULL;
-#else
- net->netdev_ops = NULL;
-#endif
- return err;
-}
-
-void
-dhd_bus_detach(dhd_pub_t *dhdp)
-{
- dhd_info_t *dhd;
-
- DHD_TRACE(("%s: Enter\n", __FUNCTION__));
-
- if (dhdp) {
- dhd = (dhd_info_t *)dhdp->info;
- if (dhd) {
-
- /*
- * In case of Android cfg80211 driver, the bus is down in dhd_stop,
- * calling stop again will cuase SD read/write errors.
- */
- if (dhd->pub.busstate != DHD_BUS_DOWN) {
- /* Stop the protocol module */
- dhd_prot_stop(&dhd->pub);
-
- /* Stop the bus module */
- dhd_bus_stop(dhd->pub.bus, TRUE);
- }
-
-#if defined(OOB_INTR_ONLY)
- dhd_bus_oob_intr_unregister(dhdp);
-#endif
- }
- }
-}
-
-
-void dhd_detach(dhd_pub_t *dhdp)
-{
- dhd_info_t *dhd;
- unsigned long flags;
- int timer_valid = FALSE;
-
- if (!dhdp)
- return;
-
- dhd = (dhd_info_t *)dhdp->info;
- if (!dhd)
- return;
-
- DHD_TRACE(("%s: Enter state 0x%x\n", __FUNCTION__, dhd->dhd_state));
-
- dhd->pub.up = 0;
- if (!(dhd->dhd_state & DHD_ATTACH_STATE_DONE)) {
- /* Give sufficient time for threads to start running in case
- * dhd_attach() has failed
- */
- OSL_SLEEP(100);
- }
-
- if (dhd->dhd_state & DHD_ATTACH_STATE_PROT_ATTACH) {
-#ifdef PCIE_FULL_DONGLE
- dhd_flow_rings_deinit(dhdp);
-#endif
- dhd_bus_detach(dhdp);
-
- if (dhdp->prot)
- dhd_prot_detach(dhdp);
- }
-
-#ifdef ARP_OFFLOAD_SUPPORT
- if (dhd_inetaddr_notifier_registered) {
- dhd_inetaddr_notifier_registered = FALSE;
- unregister_inetaddr_notifier(&dhd_inetaddr_notifier);
- }
-#endif /* ARP_OFFLOAD_SUPPORT */
-#ifdef CONFIG_IPV6
- if (dhd_inet6addr_notifier_registered) {
- dhd_inet6addr_notifier_registered = FALSE;
- unregister_inet6addr_notifier(&dhd_inet6addr_notifier);
- }
-#endif
-
-#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
- if (dhd->dhd_state & DHD_ATTACH_STATE_EARLYSUSPEND_DONE) {
- if (dhd->early_suspend.suspend)
- unregister_early_suspend(&dhd->early_suspend);
- }
-#endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */
-
-#if defined(WL_WIRELESS_EXT)
- if (dhd->dhd_state & DHD_ATTACH_STATE_WL_ATTACH) {
- /* Detatch and unlink in the iw */
- wl_iw_detach();
- }
-#endif /* defined(WL_WIRELESS_EXT) */
-
- /* delete all interfaces, start with virtual */
- if (dhd->dhd_state & DHD_ATTACH_STATE_ADD_IF) {
- int i = 1;
- dhd_if_t *ifp;
-
- /* Cleanup virtual interfaces */
- dhd_net_if_lock_local(dhd);
- for (i = 1; i < DHD_MAX_IFS; i++) {
- if (dhd->iflist[i])
- dhd_remove_if(&dhd->pub, i, TRUE);
- }
- dhd_net_if_unlock_local(dhd);
-
- /* delete primary interface 0 */
- ifp = dhd->iflist[0];
- ASSERT(ifp);
- ASSERT(ifp->net);
- if (ifp && ifp->net) {
-
-
-
- /* in unregister_netdev case, the interface gets freed by net->destructor
- * (which is set to free_netdev)
- */
- if (ifp->net->reg_state == NETREG_UNINITIALIZED)
- free_netdev(ifp->net);
- else
- unregister_netdev(ifp->net);
- ifp->net = NULL;
-#ifdef DHD_WMF
- dhd_wmf_cleanup(dhdp, 0);
-#endif /* DHD_WMF */
-
- dhd_if_del_sta_list(ifp);
-
- MFREE(dhd->pub.osh, ifp, sizeof(*ifp));
- dhd->iflist[0] = NULL;
- }
- }
-
- /* Clear the watchdog timer */
- DHD_GENERAL_LOCK(&dhd->pub, flags);
- timer_valid = dhd->wd_timer_valid;
- dhd->wd_timer_valid = FALSE;
- DHD_GENERAL_UNLOCK(&dhd->pub, flags);
- if (timer_valid)
- del_timer_sync(&dhd->timer);
-
- if (dhd->dhd_state & DHD_ATTACH_STATE_THREADS_CREATED) {
- if (dhd->thr_wdt_ctl.thr_pid >= 0) {
- PROC_STOP(&dhd->thr_wdt_ctl);
- }
-
- if (dhd->rxthread_enabled && dhd->thr_rxf_ctl.thr_pid >= 0) {
- PROC_STOP(&dhd->thr_rxf_ctl);
- }
-
- if (dhd->thr_dpc_ctl.thr_pid >= 0) {
- PROC_STOP(&dhd->thr_dpc_ctl);
- } else
- tasklet_kill(&dhd->tasklet);
- }
-#ifdef WL_CFG80211
- if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) {
- wl_cfg80211_detach(NULL);
- dhd_monitor_uninit();
- }
-#endif
- /* free deferred work queue */
- dhd_deferred_work_deinit(dhd->dhd_deferred_wq);
- dhd->dhd_deferred_wq = NULL;
-
-#ifdef SHOW_LOGTRACE
- if (dhd->event_data.fmts)
- kfree(dhd->event_data.fmts);
- if (dhd->event_data.raw_fmts)
- kfree(dhd->event_data.raw_fmts);
-#endif /* SHOW_LOGTRACE */
-
-#ifdef PNO_SUPPORT
- if (dhdp->pno_state)
- dhd_pno_deinit(dhdp);
-#endif
-#if defined(CONFIG_PM_SLEEP)
- if (dhd_pm_notifier_registered) {
- unregister_pm_notifier(&dhd_pm_notifier);
- dhd_pm_notifier_registered = FALSE;
- }
-#endif /* CONFIG_PM_SLEEP */
-#ifdef DEBUG_CPU_FREQ
- if (dhd->new_freq)
- free_percpu(dhd->new_freq);
- dhd->new_freq = NULL;
- cpufreq_unregister_notifier(&dhd->freq_trans, CPUFREQ_TRANSITION_NOTIFIER);
-#endif
- if (dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT) {
- DHD_TRACE(("wd wakelock count:%d\n", dhd->wakelock_wd_counter));
-#ifdef CONFIG_HAS_WAKELOCK
- dhd->wakelock_counter = 0;
- dhd->wakelock_wd_counter = 0;
- dhd->wakelock_rx_timeout_enable = 0;
- dhd->wakelock_ctrl_timeout_enable = 0;
- wake_lock_destroy(&dhd->wl_wifi);
- wake_lock_destroy(&dhd->wl_rxwake);
- wake_lock_destroy(&dhd->wl_ctrlwake);
- wake_lock_destroy(&dhd->wl_wdwake);
-#endif /* CONFIG_HAS_WAKELOCK */
- }
-
-
-
-#ifdef DHDTCPACK_SUPPRESS
- /* This will free all MEM allocated for TCPACK SUPPRESS */
- dhd_tcpack_suppress_set(&dhd->pub, TCPACK_SUP_OFF);
-#endif /* DHDTCPACK_SUPPRESS */
- dhd_conf_detach(dhdp);
-}
-
-
-void
-dhd_free(dhd_pub_t *dhdp)
-{
- dhd_info_t *dhd;
- DHD_TRACE(("%s: Enter\n", __FUNCTION__));
-
- if (dhdp) {
- int i;
- for (i = 0; i < ARRAYSIZE(dhdp->reorder_bufs); i++) {
- if (dhdp->reorder_bufs[i]) {
- reorder_info_t *ptr;
- uint32 buf_size = sizeof(struct reorder_info);
-
- ptr = dhdp->reorder_bufs[i];
-
- buf_size += ((ptr->max_idx + 1) * sizeof(void*));
- DHD_REORDER(("free flow id buf %d, maxidx is %d, buf_size %d\n",
- i, ptr->max_idx, buf_size));
-
- MFREE(dhdp->osh, dhdp->reorder_bufs[i], buf_size);
- dhdp->reorder_bufs[i] = NULL;
- }
- }
-
- dhd_sta_pool_fini(dhdp, DHD_MAX_STA);
-
- dhd = (dhd_info_t *)dhdp->info;
- /* If pointer is allocated by dhd_os_prealloc then avoid MFREE */
- if (dhd &&
- dhd != (dhd_info_t *)dhd_os_prealloc(dhdp, DHD_PREALLOC_DHD_INFO, 0, FALSE))
- MFREE(dhd->pub.osh, dhd, sizeof(*dhd));
- dhd = NULL;
- }
-}
-
-static void
-dhd_module_cleanup(void)
-{
- printk("%s: Enter\n", __FUNCTION__);
-
- dhd_bus_unregister();
-
- wl_android_exit();
-
- dhd_wifi_platform_unregister_drv();
- printk("%s: Exit\n", __FUNCTION__);
-}
-
-static void __exit
-dhd_module_exit(void)
-{
- dhd_module_cleanup();
- unregister_reboot_notifier(&dhd_reboot_notifier);
-}
-
-static int __init
-dhd_module_init(void)
-{
- int err;
- int retry = POWERUP_MAX_RETRY;
-
- printk("%s: in\n", __FUNCTION__);
-
- DHD_PERIM_RADIO_INIT();
-
- if (firmware_path[0] != '\0') {
- strncpy(fw_bak_path, firmware_path, MOD_PARAM_PATHLEN);
- fw_bak_path[MOD_PARAM_PATHLEN-1] = '\0';
- }
-
- if (nvram_path[0] != '\0') {
- strncpy(nv_bak_path, nvram_path, MOD_PARAM_PATHLEN);
- nv_bak_path[MOD_PARAM_PATHLEN-1] = '\0';
- }
-
- do {
- err = dhd_wifi_platform_register_drv();
- if (!err) {
- register_reboot_notifier(&dhd_reboot_notifier);
- break;
- }
- else {
- DHD_ERROR(("%s: Failed to load the driver, try cnt %d\n",
- __FUNCTION__, retry));
- strncpy(firmware_path, fw_bak_path, MOD_PARAM_PATHLEN);
- firmware_path[MOD_PARAM_PATHLEN-1] = '\0';
- strncpy(nvram_path, nv_bak_path, MOD_PARAM_PATHLEN);
- nvram_path[MOD_PARAM_PATHLEN-1] = '\0';
- }
- } while (retry--);
-
- if (err)
- DHD_ERROR(("%s: Failed to load driver max retry reached**\n", __FUNCTION__));
-
- printk("%s: Exit err=%d\n", __FUNCTION__, err);
- return err;
-}
-
-static int
-dhd_reboot_callback(struct notifier_block *this, unsigned long code, void *unused)
-{
- DHD_TRACE(("%s: code = %ld\n", __FUNCTION__, code));
- if (code == SYS_RESTART) {
- }
-
- return NOTIFY_DONE;
-}
-
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
-#if defined(CONFIG_DEFERRED_INITCALLS)
-deferred_module_init(dhd_module_init);
-#elif defined(USE_LATE_INITCALL_SYNC)
-late_initcall_sync(dhd_module_init);
-#else
-late_initcall(dhd_module_init);
-#endif /* USE_LATE_INITCALL_SYNC */
-#else
-module_init(dhd_module_init);
-#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */
-
-module_exit(dhd_module_exit);
-
-/*
- * OS specific functions required to implement DHD driver in OS independent way
- */
-int
-dhd_os_proto_block(dhd_pub_t *pub)
-{
- dhd_info_t * dhd = (dhd_info_t *)(pub->info);
-
- if (dhd) {
- DHD_PERIM_UNLOCK(pub);
-
- down(&dhd->proto_sem);
-
- DHD_PERIM_LOCK(pub);
- return 1;
- }
-
- return 0;
-}
-
-int
-dhd_os_proto_unblock(dhd_pub_t *pub)
-{
- dhd_info_t * dhd = (dhd_info_t *)(pub->info);
-
- if (dhd) {
- up(&dhd->proto_sem);
- return 1;
- }
-
- return 0;
-}
-
-unsigned int
-dhd_os_get_ioctl_resp_timeout(void)
-{
- return ((unsigned int)dhd_ioctl_timeout_msec);
-}
-
-void
-dhd_os_set_ioctl_resp_timeout(unsigned int timeout_msec)
-{
- dhd_ioctl_timeout_msec = (int)timeout_msec;
-}
-
-int
-dhd_os_ioctl_resp_wait(dhd_pub_t *pub, uint *condition, bool *pending)
-{
- dhd_info_t * dhd = (dhd_info_t *)(pub->info);
- int timeout;
-
- /* Convert timeout in millsecond to jiffies */
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
- timeout = msecs_to_jiffies(dhd_ioctl_timeout_msec);
-#else
- timeout = dhd_ioctl_timeout_msec * HZ / 1000;
-#endif
-
- DHD_PERIM_UNLOCK(pub);
-
- timeout = wait_event_timeout(dhd->ioctl_resp_wait, (*condition), timeout);
-
- DHD_PERIM_LOCK(pub);
-
- return timeout;
-}
-
-int
-dhd_os_ioctl_resp_wake(dhd_pub_t *pub)
-{
- dhd_info_t *dhd = (dhd_info_t *)(pub->info);
-
- wake_up(&dhd->ioctl_resp_wait);
- return 0;
-}
-
-void
-dhd_os_wd_timer_extend(void *bus, bool extend)
-{
- dhd_pub_t *pub = bus;
- dhd_info_t *dhd = (dhd_info_t *)pub->info;
-
- if (extend)
- dhd_os_wd_timer(bus, WATCHDOG_EXTEND_INTERVAL);
- else
- dhd_os_wd_timer(bus, dhd->default_wd_interval);
-}
-
-
-void
-dhd_os_wd_timer(void *bus, uint wdtick)
-{
- dhd_pub_t *pub = bus;
- dhd_info_t *dhd = (dhd_info_t *)pub->info;
- unsigned long flags;
-
- DHD_TRACE(("%s: Enter\n", __FUNCTION__));
-
- if (!dhd) {
- DHD_ERROR(("%s: dhd NULL\n", __FUNCTION__));
- return;
- }
-
- DHD_GENERAL_LOCK(pub, flags);
-
- /* don't start the wd until fw is loaded */
- if (pub->busstate == DHD_BUS_DOWN) {
- DHD_GENERAL_UNLOCK(pub, flags);
- if (!wdtick)
- DHD_OS_WD_WAKE_UNLOCK(pub);
- return;
- }
-
- /* Totally stop the timer */
- if (!wdtick && dhd->wd_timer_valid == TRUE) {
- dhd->wd_timer_valid = FALSE;
- DHD_GENERAL_UNLOCK(pub, flags);
- del_timer_sync(&dhd->timer);
- DHD_OS_WD_WAKE_UNLOCK(pub);
- return;
- }
-
- if (wdtick) {
- DHD_OS_WD_WAKE_LOCK(pub);
- dhd_watchdog_ms = (uint)wdtick;
- /* Re arm the timer, at last watchdog period */
- mod_timer(&dhd->timer, jiffies + msecs_to_jiffies(dhd_watchdog_ms));
- dhd->wd_timer_valid = TRUE;
- }
- DHD_GENERAL_UNLOCK(pub, flags);
-}
-
-void *
-dhd_os_open_image(char *filename)
-{
- struct file *fp;
-
- fp = filp_open(filename, O_RDONLY, 0);
- /*
- * 2.6.11 (FC4) supports filp_open() but later revs don't?
- * Alternative:
- * fp = open_namei(AT_FDCWD, filename, O_RD, 0);
- * ???
- */
- if (IS_ERR(fp))
- fp = NULL;
-
- return fp;
-}
-
-int
-dhd_os_get_image_block(char *buf, int len, void *image)
-{
- struct file *fp = (struct file *)image;
- int rdlen;
-
- if (!image)
- return 0;
-
- rdlen = kernel_read(fp, fp->f_pos, buf, len);
- if (rdlen > 0)
- fp->f_pos += rdlen;
-
- return rdlen;
-}
-
-void
-dhd_os_close_image(void *image)
-{
- if (image)
- filp_close((struct file *)image, NULL);
-}
-
-void
-dhd_os_sdlock(dhd_pub_t *pub)
-{
- dhd_info_t *dhd;
-
- dhd = (dhd_info_t *)(pub->info);
-
- if (dhd_dpc_prio >= 0)
- down(&dhd->sdsem);
- else
- spin_lock_bh(&dhd->sdlock);
-}
-
-void
-dhd_os_sdunlock(dhd_pub_t *pub)
-{
- dhd_info_t *dhd;
-
- dhd = (dhd_info_t *)(pub->info);
-
- if (dhd_dpc_prio >= 0)
- up(&dhd->sdsem);
- else
- spin_unlock_bh(&dhd->sdlock);
-}
-
-void
-dhd_os_sdlock_txq(dhd_pub_t *pub)
-{
- dhd_info_t *dhd;
-
- dhd = (dhd_info_t *)(pub->info);
- spin_lock_bh(&dhd->txqlock);
-}
-
-void
-dhd_os_sdunlock_txq(dhd_pub_t *pub)
-{
- dhd_info_t *dhd;
-
- dhd = (dhd_info_t *)(pub->info);
- spin_unlock_bh(&dhd->txqlock);
-}
-
-void
-dhd_os_sdlock_rxq(dhd_pub_t *pub)
-{
-}
-
-void
-dhd_os_sdunlock_rxq(dhd_pub_t *pub)
-{
-}
-
-static void
-dhd_os_rxflock(dhd_pub_t *pub)
-{
- dhd_info_t *dhd;
-
- dhd = (dhd_info_t *)(pub->info);
- spin_lock_bh(&dhd->rxf_lock);
-
-}
-
-static void
-dhd_os_rxfunlock(dhd_pub_t *pub)
-{
- dhd_info_t *dhd;
-
- dhd = (dhd_info_t *)(pub->info);
- spin_unlock_bh(&dhd->rxf_lock);
-}
-
-#ifdef DHDTCPACK_SUPPRESS
-void
-dhd_os_tcpacklock(dhd_pub_t *pub)
-{
- dhd_info_t *dhd;
-
- dhd = (dhd_info_t *)(pub->info);
- spin_lock_bh(&dhd->tcpack_lock);
-
-}
-
-void
-dhd_os_tcpackunlock(dhd_pub_t *pub)
-{
- dhd_info_t *dhd;
-
- dhd = (dhd_info_t *)(pub->info);
- spin_unlock_bh(&dhd->tcpack_lock);
-}
-#endif /* DHDTCPACK_SUPPRESS */
-
-uint8* dhd_os_prealloc(dhd_pub_t *dhdpub, int section, uint size, bool kmalloc_if_fail)
-{
- uint8* buf;
- gfp_t flags = CAN_SLEEP() ? GFP_KERNEL: GFP_ATOMIC;
-
- buf = (uint8*)wifi_platform_prealloc(dhdpub->info->adapter, section, size);
- if (buf == NULL && kmalloc_if_fail)
- buf = kmalloc(size, flags);
-
- return buf;
-}
-
-void dhd_os_prefree(dhd_pub_t *dhdpub, void *addr, uint size)
-{
-}
-
-#if defined(WL_WIRELESS_EXT)
-struct iw_statistics *
-dhd_get_wireless_stats(struct net_device *dev)
-{
- int res = 0;
- dhd_info_t *dhd = DHD_DEV_INFO(dev);
-
- if (!dhd->pub.up) {
- return NULL;
- }
-
- res = wl_iw_get_wireless_stats(dev, &dhd->iw.wstats);
-
- if (res == 0)
- return &dhd->iw.wstats;
- else
- return NULL;
-}
-#endif /* defined(WL_WIRELESS_EXT) */
-
-static int
-dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata,
- wl_event_msg_t *event, void **data)
-{
- int bcmerror = 0;
- ASSERT(dhd != NULL);
-
-#ifdef SHOW_LOGTRACE
- bcmerror = wl_host_event(&dhd->pub, ifidx, pktdata, event, data, &dhd->event_data);
-#else
- bcmerror = wl_host_event(&dhd->pub, ifidx, pktdata, event, data, NULL);
-#endif /* SHOW_LOGTRACE */
-
- if (bcmerror != BCME_OK)
- return (bcmerror);
-
-#if defined(WL_WIRELESS_EXT)
- if (event->bsscfgidx == 0) {
- /*
- * Wireless ext is on primary interface only
- */
-
- ASSERT(dhd->iflist[*ifidx] != NULL);
- ASSERT(dhd->iflist[*ifidx]->net != NULL);
-
- if (dhd->iflist[*ifidx]->net) {
- wl_iw_event(dhd->iflist[*ifidx]->net, event, *data);
- }
- }
-#endif /* defined(WL_WIRELESS_EXT) */
-
-#ifdef WL_CFG80211
- ASSERT(dhd->iflist[*ifidx] != NULL);
- ASSERT(dhd->iflist[*ifidx]->net != NULL);
- if (dhd->iflist[*ifidx]->net)
- wl_cfg80211_event(dhd->iflist[*ifidx]->net, event, *data);
-#endif /* defined(WL_CFG80211) */
-
- return (bcmerror);
-}
-
-/* send up locally generated event */
-void
-dhd_sendup_event(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data)
-{
- switch (ntoh32(event->event_type)) {
-#ifdef WLBTAMP
- /* Send up locally generated AMP HCI Events */
- case WLC_E_BTA_HCI_EVENT: {
- struct sk_buff *p, *skb;
- bcm_event_t *msg;
- wl_event_msg_t *p_bcm_event;
- char *ptr;
- uint32 len;
- uint32 pktlen;
- dhd_if_t *ifp;
- dhd_info_t *dhd;
- uchar *eth;
- int ifidx;
-
- len = ntoh32(event->datalen);
- pktlen = sizeof(bcm_event_t) + len + 2;
- dhd = dhdp->info;
- ifidx = dhd_ifname2idx(dhd, event->ifname);
-
- if ((p = PKTGET(dhdp->osh, pktlen, FALSE))) {
- ASSERT(ISALIGNED((uintptr)PKTDATA(dhdp->osh, p), sizeof(uint32)));
-
- msg = (bcm_event_t *) PKTDATA(dhdp->osh, p);
-
- bcopy(&dhdp->mac, &msg->eth.ether_dhost, ETHER_ADDR_LEN);
- bcopy(&dhdp->mac, &msg->eth.ether_shost, ETHER_ADDR_LEN);
- ETHER_TOGGLE_LOCALADDR(&msg->eth.ether_shost);
-
- msg->eth.ether_type = hton16(ETHER_TYPE_BRCM);
-
- /* BCM Vendor specific header... */
- msg->bcm_hdr.subtype = hton16(BCMILCP_SUBTYPE_VENDOR_LONG);
- msg->bcm_hdr.version = BCMILCP_BCM_SUBTYPEHDR_VERSION;
- bcopy(BRCM_OUI, &msg->bcm_hdr.oui[0], DOT11_OUI_LEN);
-
- /* vendor spec header length + pvt data length (private indication
- * hdr + actual message itself)
- */
- msg->bcm_hdr.length = hton16(BCMILCP_BCM_SUBTYPEHDR_MINLENGTH +
- BCM_MSG_LEN + sizeof(wl_event_msg_t) + (uint16)len);
- msg->bcm_hdr.usr_subtype = hton16(BCMILCP_BCM_SUBTYPE_EVENT);
-
- PKTSETLEN(dhdp->osh, p, (sizeof(bcm_event_t) + len + 2));
-
- /* copy wl_event_msg_t into sk_buf */
-
- /* pointer to wl_event_msg_t in sk_buf */
- p_bcm_event = &msg->event;
- bcopy(event, p_bcm_event, sizeof(wl_event_msg_t));
-
- /* copy hci event into sk_buf */
- bcopy(data, (p_bcm_event + 1), len);
-
- msg->bcm_hdr.length = hton16(sizeof(wl_event_msg_t) +
- ntoh16(msg->bcm_hdr.length));
- PKTSETLEN(dhdp->osh, p, (sizeof(bcm_event_t) + len + 2));
-
- ptr = (char *)(msg + 1);
- /* Last 2 bytes of the message are 0x00 0x00 to signal that there
- * are no ethertypes which are following this
- */
- ptr[len+0] = 0x00;
- ptr[len+1] = 0x00;
-
- skb = PKTTONATIVE(dhdp->osh, p);
- eth = skb->data;
- len = skb->len;
-
- ifp = dhd->iflist[ifidx];
- if (ifp == NULL)
- ifp = dhd->iflist[0];
-
- ASSERT(ifp);
- skb->dev = ifp->net;
- skb->protocol = eth_type_trans(skb, skb->dev);
-
- skb->data = eth;
- skb->len = len;
-
- /* Strip header, count, deliver upward */
- skb_pull(skb, ETH_HLEN);
-
- /* Send the packet */
- if (in_interrupt()) {
- netif_rx(skb);
- } else {
- netif_rx_ni(skb);
- }
- }
- else {
- /* Could not allocate a sk_buf */
- DHD_ERROR(("%s: unable to alloc sk_buf", __FUNCTION__));
- }
- break;
- } /* case WLC_E_BTA_HCI_EVENT */
-#endif /* WLBTAMP */
-
- default:
- break;
- }
-}
-
-#ifdef LOG_INTO_TCPDUMP
-void
-dhd_sendup_log(dhd_pub_t *dhdp, void *data, int data_len)
-{
- struct sk_buff *p, *skb;
- uint32 pktlen;
- int len;
- dhd_if_t *ifp;
- dhd_info_t *dhd;
- uchar *skb_data;
- int ifidx = 0;
- struct ether_header eth;
-
- pktlen = sizeof(eth) + data_len;
- dhd = dhdp->info;
-
- if ((p = PKTGET(dhdp->osh, pktlen, FALSE))) {
- ASSERT(ISALIGNED((uintptr)PKTDATA(dhdp->osh, p), sizeof(uint32)));
-
- bcopy(&dhdp->mac, &eth.ether_dhost, ETHER_ADDR_LEN);
- bcopy(&dhdp->mac, &eth.ether_shost, ETHER_ADDR_LEN);
- ETHER_TOGGLE_LOCALADDR(&eth.ether_shost);
- eth.ether_type = hton16(ETHER_TYPE_BRCM);
-
- bcopy((void *)&eth, PKTDATA(dhdp->osh, p), sizeof(eth));
- bcopy(data, PKTDATA(dhdp->osh, p) + sizeof(eth), data_len);
- skb = PKTTONATIVE(dhdp->osh, p);
- skb_data = skb->data;
- len = skb->len;
-
- ifidx = dhd_ifname2idx(dhd, "wlan0");
- ifp = dhd->iflist[ifidx];
- if (ifp == NULL)
- ifp = dhd->iflist[0];
-
- ASSERT(ifp);
- skb->dev = ifp->net;
- skb->protocol = eth_type_trans(skb, skb->dev);
- skb->data = skb_data;
- skb->len = len;
-
- /* Strip header, count, deliver upward */
- skb_pull(skb, ETH_HLEN);
-
- /* Send the packet */
- if (in_interrupt()) {
- netif_rx(skb);
- } else {
- netif_rx_ni(skb);
- }
- }
- else {
- /* Could not allocate a sk_buf */
- DHD_ERROR(("%s: unable to alloc sk_buf", __FUNCTION__));
- }
-}
-#endif /* LOG_INTO_TCPDUMP */
-
-void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar)
-{
-#if defined(BCMSDIO) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
- struct dhd_info *dhdinfo = dhd->info;
-
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
- int timeout = msecs_to_jiffies(IOCTL_RESP_TIMEOUT);
-#else
- int timeout = (IOCTL_RESP_TIMEOUT / 1000) * HZ;
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
-
- dhd_os_sdunlock(dhd);
- wait_event_timeout(dhdinfo->ctrl_wait, (*lockvar == FALSE), timeout);
- dhd_os_sdlock(dhd);
-#endif /* defined(BCMSDIO) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) */
- return;
-}
-
-void dhd_wait_event_wakeup(dhd_pub_t *dhd)
-{
-#if defined(BCMSDIO) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
- struct dhd_info *dhdinfo = dhd->info;
- if (waitqueue_active(&dhdinfo->ctrl_wait))
- wake_up(&dhdinfo->ctrl_wait);
-#endif
- return;
-}
-
-#if defined(BCMSDIO) || defined(BCMPCIE)
-int
-dhd_net_bus_devreset(struct net_device *dev, uint8 flag)
-{
- int ret = 0;
- dhd_info_t *dhd = DHD_DEV_INFO(dev);
-
- if (flag == TRUE) {
- /* Issue wl down command before resetting the chip */
- if (dhd_wl_ioctl_cmd(&dhd->pub, WLC_DOWN, NULL, 0, TRUE, 0) < 0) {
- DHD_TRACE(("%s: wl down failed\n", __FUNCTION__));
- }
-#ifdef PROP_TXSTATUS
- if (dhd->pub.wlfc_enabled)
- dhd_wlfc_deinit(&dhd->pub);
-#endif /* PROP_TXSTATUS */
-#ifdef PNO_SUPPORT
- if (dhd->pub.pno_state)
- dhd_pno_deinit(&dhd->pub);
-#endif
- }
-
-#ifdef BCMSDIO
- if (!flag) {
- dhd_update_fw_nv_path(dhd);
- /* update firmware and nvram path to sdio bus */
- dhd_bus_update_fw_nv_path(dhd->pub.bus,
- dhd->fw_path, dhd->nv_path, dhd->conf_path);
- }
-#endif /* BCMSDIO */
-
- ret = dhd_bus_devreset(&dhd->pub, flag);
- if (ret) {
- DHD_ERROR(("%s: dhd_bus_devreset: %d\n", __FUNCTION__, ret));
- return ret;
- }
-
- return ret;
-}
-
-#ifdef BCMSDIO
-int
-dhd_net_bus_suspend(struct net_device *dev)
-{
- dhd_info_t *dhd = DHD_DEV_INFO(dev);
- return dhd_bus_suspend(&dhd->pub);
-}
-
-int
-dhd_net_bus_resume(struct net_device *dev, uint8 stage)
-{
- dhd_info_t *dhd = DHD_DEV_INFO(dev);
- return dhd_bus_resume(&dhd->pub, stage);
-}
-
-#endif /* BCMSDIO */
-#endif /* BCMSDIO || BCMPCIE */
-
-int net_os_set_suspend_disable(struct net_device *dev, int val)
-{
- dhd_info_t *dhd = DHD_DEV_INFO(dev);
- int ret = 0;
-
- if (dhd) {
- ret = dhd->pub.suspend_disable_flag;
- dhd->pub.suspend_disable_flag = val;
- }
- return ret;
-}
-
-int net_os_set_suspend(struct net_device *dev, int val, int force)
-{
- int ret = 0;
- dhd_info_t *dhd = DHD_DEV_INFO(dev);
-
- if (dhd) {
-#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
- ret = dhd_set_suspend(val, &dhd->pub);
-#else
- ret = dhd_suspend_resume_helper(dhd, val, force);
-#endif
-#ifdef WL_CFG80211
- wl_cfg80211_update_power_mode(dev);
-#endif
- }
- return ret;
-}
-
-int net_os_set_suspend_bcn_li_dtim(struct net_device *dev, int val)
-{
- dhd_info_t *dhd = DHD_DEV_INFO(dev);
-
- if (dhd)
- dhd->pub.suspend_bcn_li_dtim = val;
-
- return 0;
-}
-
-#ifdef PKT_FILTER_SUPPORT
-int net_os_rxfilter_add_remove(struct net_device *dev, int add_remove, int num)
-{
- dhd_info_t *dhd = DHD_DEV_INFO(dev);
- char *filterp = NULL;
- int filter_id = 0;
- int ret = 0;
-
- if (!dhd_master_mode)
- add_remove = !add_remove;
-
- if (!dhd || (num == DHD_UNICAST_FILTER_NUM) ||
- (num == DHD_MDNS_FILTER_NUM))
- return ret;
- if (num >= dhd->pub.pktfilter_count)
- return -EINVAL;
- switch (num) {
- case DHD_BROADCAST_FILTER_NUM:
- filterp = "101 0 0 0 0xFFFFFFFFFFFF 0xFFFFFFFFFFFF";
- filter_id = 101;
- break;
- case DHD_MULTICAST4_FILTER_NUM:
- filterp = "102 0 0 0 0xFFFFFF 0x01005E";
- filter_id = 102;
- break;
- case DHD_MULTICAST6_FILTER_NUM:
- filterp = "103 0 0 0 0xFFFF 0x3333";
- filter_id = 103;
- break;
- default:
- return -EINVAL;
- }
-
- /* Add filter */
- if (add_remove) {
- dhd->pub.pktfilter[num] = filterp;
- dhd_pktfilter_offload_set(&dhd->pub, dhd->pub.pktfilter[num]);
- } else { /* Delete filter */
- if (dhd->pub.pktfilter[num] != NULL) {
- dhd_pktfilter_offload_delete(&dhd->pub, filter_id);
- dhd->pub.pktfilter[num] = NULL;
- }
- }
- return ret;
-}
-
-int dhd_os_enable_packet_filter(dhd_pub_t *dhdp, int val)
-
-{
- int ret = 0;
-
- /* Packet filtering is set only if we still in early-suspend and
- * we need either to turn it ON or turn it OFF
- * We can always turn it OFF in case of early-suspend, but we turn it
- * back ON only if suspend_disable_flag was not set
- */
- if (dhdp && dhdp->up) {
- if (dhdp->in_suspend) {
- if (!val || (val && !dhdp->suspend_disable_flag))
- dhd_enable_packet_filter(val, dhdp);
- }
- }
- return ret;
-}
-
-/* function to enable/disable packet for Network device */
-int net_os_enable_packet_filter(struct net_device *dev, int val)
-{
- dhd_info_t *dhd = DHD_DEV_INFO(dev);
-
- return dhd_os_enable_packet_filter(&dhd->pub, val);
-}
-#endif /* PKT_FILTER_SUPPORT */
-
-int
-dhd_dev_init_ioctl(struct net_device *dev)
-{
- dhd_info_t *dhd = DHD_DEV_INFO(dev);
- int ret;
-
- if ((ret = dhd_sync_with_dongle(&dhd->pub)) < 0)
- goto done;
-
-done:
- return ret;
-}
-
-#ifdef PNO_SUPPORT
-/* Linux wrapper to call common dhd_pno_stop_for_ssid */
-int
-dhd_dev_pno_stop_for_ssid(struct net_device *dev)
-{
- dhd_info_t *dhd = DHD_DEV_INFO(dev);
-
- return (dhd_pno_stop_for_ssid(&dhd->pub));
-}
-/* Linux wrapper to call common dhd_pno_set_for_ssid */
-int
-dhd_dev_pno_set_for_ssid(struct net_device *dev, wlc_ssid_t* ssids_local, int nssid,
- uint16 scan_fr, int pno_repeat, int pno_freq_expo_max, uint16 *channel_list, int nchan)
-{
- dhd_info_t *dhd = DHD_DEV_INFO(dev);
-
- return (dhd_pno_set_for_ssid(&dhd->pub, ssids_local, nssid, scan_fr,
- pno_repeat, pno_freq_expo_max, channel_list, nchan));
-}
-
-/* Linux wrapper to call common dhd_pno_enable */
-int
-dhd_dev_pno_enable(struct net_device *dev, int enable)
-{
- dhd_info_t *dhd = DHD_DEV_INFO(dev);
-
- return (dhd_pno_enable(&dhd->pub, enable));
-}
-
-/* Linux wrapper to call common dhd_pno_set_for_hotlist */
-int
-dhd_dev_pno_set_for_hotlist(struct net_device *dev, wl_pfn_bssid_t *p_pfn_bssid,
- struct dhd_pno_hotlist_params *hotlist_params)
-{
- dhd_info_t *dhd = DHD_DEV_INFO(dev);
- return (dhd_pno_set_for_hotlist(&dhd->pub, p_pfn_bssid, hotlist_params));
-}
-/* Linux wrapper to call common dhd_dev_pno_stop_for_batch */
-int
-dhd_dev_pno_stop_for_batch(struct net_device *dev)
-{
- dhd_info_t *dhd = DHD_DEV_INFO(dev);
- return (dhd_pno_stop_for_batch(&dhd->pub));
-}
-/* Linux wrapper to call common dhd_dev_pno_set_for_batch */
-int
-dhd_dev_pno_set_for_batch(struct net_device *dev, struct dhd_pno_batch_params *batch_params)
-{
- dhd_info_t *dhd = DHD_DEV_INFO(dev);
- return (dhd_pno_set_for_batch(&dhd->pub, batch_params));
-}
-/* Linux wrapper to call common dhd_dev_pno_get_for_batch */
-int
-dhd_dev_pno_get_for_batch(struct net_device *dev, char *buf, int bufsize)
-{
- dhd_info_t *dhd = DHD_DEV_INFO(dev);
- return (dhd_pno_get_for_batch(&dhd->pub, buf, bufsize, PNO_STATUS_NORMAL));
-}
-#endif /* PNO_SUPPORT */
-
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (1)
-static void dhd_hang_process(void *dhd_info, void *event_info, u8 event)
-{
- dhd_info_t *dhd;
- struct net_device *dev;
-
- dhd = (dhd_info_t *)dhd_info;
- dev = dhd->iflist[0]->net;
-
- if (dev) {
- rtnl_lock();
- dev_close(dev);
- rtnl_unlock();
-#if defined(WL_WIRELESS_EXT)
- wl_iw_send_priv_event(dev, "HANG");
-#endif
-#if defined(WL_CFG80211)
- wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED);
-#endif
- }
-}
-
-int dhd_os_send_hang_message(dhd_pub_t *dhdp)
-{
- int ret = 0;
- if (dhdp) {
- if (!dhdp->hang_was_sent) {
- dhdp->hang_was_sent = 1;
- dhd_deferred_schedule_work(dhdp->info->dhd_deferred_wq, (void *)dhdp,
- DHD_WQ_WORK_HANG_MSG, dhd_hang_process, DHD_WORK_PRIORITY_HIGH);
- }
- }
- return ret;
-}
-
-int net_os_send_hang_message(struct net_device *dev)
-{
- dhd_info_t *dhd = DHD_DEV_INFO(dev);
- int ret = 0;
-
- if (dhd) {
- /* Report FW problem when enabled */
- if (dhd->pub.hang_report) {
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
- ret = dhd_os_send_hang_message(&dhd->pub);
-#else
- ret = wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED);
-#endif
- } else {
- DHD_ERROR(("%s: FW HANG ignored (for testing purpose) and not sent up\n",
- __FUNCTION__));
- /* Enforce bus down to stop any future traffic */
- dhd->pub.busstate = DHD_BUS_DOWN;
- }
- }
- return ret;
-}
-#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) && OEM_ANDROID */
-
-
-int dhd_net_wifi_platform_set_power(struct net_device *dev, bool on, unsigned long delay_msec)
-{
- dhd_info_t *dhd = DHD_DEV_INFO(dev);
- return wifi_platform_set_power(dhd->adapter, on, delay_msec);
-}
-
-void dhd_get_customized_country_code(struct net_device *dev, char *country_iso_code,
- wl_country_t *cspec)
-{
- dhd_info_t *dhd = DHD_DEV_INFO(dev);
- get_customized_country_code(dhd->adapter, country_iso_code, cspec);
-}
-void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec, bool notify)
-{
- dhd_info_t *dhd = DHD_DEV_INFO(dev);
- if (dhd && dhd->pub.up) {
- memcpy(&dhd->pub.dhd_cspec, cspec, sizeof(wl_country_t));
-#ifdef WL_CFG80211
- wl_update_wiphybands(NULL, notify);
-#endif
- }
-}
-
-void dhd_bus_band_set(struct net_device *dev, uint band)
-{
- dhd_info_t *dhd = DHD_DEV_INFO(dev);
- if (dhd && dhd->pub.up) {
-#ifdef WL_CFG80211
- wl_update_wiphybands(NULL, true);
-#endif
- }
-}
-
-int dhd_net_set_fw_path(struct net_device *dev, char *fw)
-{
- dhd_info_t *dhd = DHD_DEV_INFO(dev);
-
- if (!fw || fw[0] == '\0')
- return -EINVAL;
-
- strncpy(dhd->fw_path, fw, sizeof(dhd->fw_path) - 1);
- dhd->fw_path[sizeof(dhd->fw_path)-1] = '\0';
-
-#if defined(SOFTAP)
- if (strstr(fw, "apsta") != NULL) {
- DHD_INFO(("GOT APSTA FIRMWARE\n"));
- ap_fw_loaded = TRUE;
- } else {
- DHD_INFO(("GOT STA FIRMWARE\n"));
- ap_fw_loaded = FALSE;
- }
-#endif
- return 0;
-}
-
-void dhd_net_if_lock(struct net_device *dev)
-{
- dhd_info_t *dhd = DHD_DEV_INFO(dev);
- dhd_net_if_lock_local(dhd);
-}
-
-void dhd_net_if_unlock(struct net_device *dev)
-{
- dhd_info_t *dhd = DHD_DEV_INFO(dev);
- dhd_net_if_unlock_local(dhd);
-}
-
-static void dhd_net_if_lock_local(dhd_info_t *dhd)
-{
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1
- if (dhd)
- mutex_lock(&dhd->dhd_net_if_mutex);
-#endif
-}
-
-static void dhd_net_if_unlock_local(dhd_info_t *dhd)
-{
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1
- if (dhd)
- mutex_unlock(&dhd->dhd_net_if_mutex);
-#endif
-}
-
-static void dhd_suspend_lock(dhd_pub_t *pub)
-{
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1
- dhd_info_t *dhd = (dhd_info_t *)(pub->info);
- if (dhd)
- mutex_lock(&dhd->dhd_suspend_mutex);
-#endif
-}
-
-static void dhd_suspend_unlock(dhd_pub_t *pub)
-{
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1
- dhd_info_t *dhd = (dhd_info_t *)(pub->info);
- if (dhd)
- mutex_unlock(&dhd->dhd_suspend_mutex);
-#endif
-}
-
-unsigned long dhd_os_general_spin_lock(dhd_pub_t *pub)
-{
- dhd_info_t *dhd = (dhd_info_t *)(pub->info);
- unsigned long flags = 0;
-
- if (dhd)
- spin_lock_irqsave(&dhd->dhd_lock, flags);
-
- return flags;
-}
-
-void dhd_os_general_spin_unlock(dhd_pub_t *pub, unsigned long flags)
-{
- dhd_info_t *dhd = (dhd_info_t *)(pub->info);
-
- if (dhd)
- spin_unlock_irqrestore(&dhd->dhd_lock, flags);
-}
-
-/* Linux specific multipurpose spinlock API */
-void *
-dhd_os_spin_lock_init(osl_t *osh)
-{
- /* Adding 4 bytes since the sizeof(spinlock_t) could be 0 */
- /* if CONFIG_SMP and CONFIG_DEBUG_SPINLOCK are not defined */
- /* and this results in kernel asserts in internal builds */
- spinlock_t * lock = MALLOC(osh, sizeof(spinlock_t) + 4);
- if (lock)
- spin_lock_init(lock);
- return ((void *)lock);
-}
-void
-dhd_os_spin_lock_deinit(osl_t *osh, void *lock)
-{
- MFREE(osh, lock, sizeof(spinlock_t) + 4);
-}
-unsigned long
-dhd_os_spin_lock(void *lock)
-{
- unsigned long flags = 0;
-
- if (lock)
- spin_lock_irqsave((spinlock_t *)lock, flags);
-
- return flags;
-}
-void
-dhd_os_spin_unlock(void *lock, unsigned long flags)
-{
- if (lock)
- spin_unlock_irqrestore((spinlock_t *)lock, flags);
-}
-
-static int
-dhd_get_pend_8021x_cnt(dhd_info_t *dhd)
-{
- return (atomic_read(&dhd->pend_8021x_cnt));
-}
-
-#define MAX_WAIT_FOR_8021X_TX 100
-
-int
-dhd_wait_pend8021x(struct net_device *dev)
-{
- dhd_info_t *dhd = DHD_DEV_INFO(dev);
- int timeout = msecs_to_jiffies(10);
- int ntimes = MAX_WAIT_FOR_8021X_TX;
- int pend = dhd_get_pend_8021x_cnt(dhd);
-
- while (ntimes && pend) {
- if (pend) {
- set_current_state(TASK_INTERRUPTIBLE);
- DHD_PERIM_UNLOCK(&dhd->pub);
- schedule_timeout(timeout);
- DHD_PERIM_LOCK(&dhd->pub);
- set_current_state(TASK_RUNNING);
- ntimes--;
- }
- pend = dhd_get_pend_8021x_cnt(dhd);
- }
- if (ntimes == 0)
- {
- atomic_set(&dhd->pend_8021x_cnt, 0);
- DHD_ERROR(("%s: TIMEOUT\n", __FUNCTION__));
- }
- return pend;
-}
-
-#ifdef DHD_DEBUG
-int
-write_to_file(dhd_pub_t *dhd, uint8 *buf, int size)
-{
- int ret = 0;
- struct file *fp;
- mm_segment_t old_fs;
- loff_t pos = 0;
-
- /* change to KERNEL_DS address limit */
- old_fs = get_fs();
- set_fs(KERNEL_DS);
-
- /* open file to write */
- fp = filp_open("/tmp/mem_dump", O_WRONLY|O_CREAT, 0640);
- if (!fp) {
- printf("%s: open file error\n", __FUNCTION__);
- ret = -1;
- goto exit;
- }
-
- /* Write buf to file */
- fp->f_op->write(fp, buf, size, &pos);
-
-exit:
- /* free buf before return */
- MFREE(dhd->osh, buf, size);
- /* close file before return */
- if (fp)
- filp_close(fp, current->files);
- /* restore previous address limit */
- set_fs(old_fs);
-
- return ret;
-}
-#endif /* DHD_DEBUG */
-
-int dhd_os_wake_lock_timeout(dhd_pub_t *pub)
-{
- dhd_info_t *dhd = (dhd_info_t *)(pub->info);
- unsigned long flags;
- int ret = 0;
-
- if (dhd) {
- spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
- ret = dhd->wakelock_rx_timeout_enable > dhd->wakelock_ctrl_timeout_enable ?
- dhd->wakelock_rx_timeout_enable : dhd->wakelock_ctrl_timeout_enable;
-#ifdef CONFIG_HAS_WAKELOCK
- if (dhd->wakelock_rx_timeout_enable)
- wake_lock_timeout(&dhd->wl_rxwake,
- msecs_to_jiffies(dhd->wakelock_rx_timeout_enable));
- if (dhd->wakelock_ctrl_timeout_enable)
- wake_lock_timeout(&dhd->wl_ctrlwake,
- msecs_to_jiffies(dhd->wakelock_ctrl_timeout_enable));
-#endif
- dhd->wakelock_rx_timeout_enable = 0;
- dhd->wakelock_ctrl_timeout_enable = 0;
- spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
- }
- return ret;
-}
-
-int net_os_wake_lock_timeout(struct net_device *dev)
-{
- dhd_info_t *dhd = DHD_DEV_INFO(dev);
- int ret = 0;
-
- if (dhd)
- ret = dhd_os_wake_lock_timeout(&dhd->pub);
- return ret;
-}
-
-int dhd_os_wake_lock_rx_timeout_enable(dhd_pub_t *pub, int val)
-{
- dhd_info_t *dhd = (dhd_info_t *)(pub->info);
- unsigned long flags;
-
- if (dhd) {
- spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
- if (val > dhd->wakelock_rx_timeout_enable)
- dhd->wakelock_rx_timeout_enable = val;
- spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
- }
- return 0;
-}
-
-int dhd_os_wake_lock_ctrl_timeout_enable(dhd_pub_t *pub, int val)
-{
- dhd_info_t *dhd = (dhd_info_t *)(pub->info);
- unsigned long flags;
-
- if (dhd) {
- spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
- if (val > dhd->wakelock_ctrl_timeout_enable)
- dhd->wakelock_ctrl_timeout_enable = val;
- spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
- }
- return 0;
-}
-
-int dhd_os_wake_lock_ctrl_timeout_cancel(dhd_pub_t *pub)
-{
- dhd_info_t *dhd = (dhd_info_t *)(pub->info);
- unsigned long flags;
-
- if (dhd) {
- spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
- dhd->wakelock_ctrl_timeout_enable = 0;
-#ifdef CONFIG_HAS_WAKELOCK
- if (wake_lock_active(&dhd->wl_ctrlwake))
- wake_unlock(&dhd->wl_ctrlwake);
-#endif
- spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
- }
- return 0;
-}
-
-int net_os_wake_lock_rx_timeout_enable(struct net_device *dev, int val)
-{
- dhd_info_t *dhd = DHD_DEV_INFO(dev);
- int ret = 0;
-
- if (dhd)
- ret = dhd_os_wake_lock_rx_timeout_enable(&dhd->pub, val);
- return ret;
-}
-
-int net_os_wake_lock_ctrl_timeout_enable(struct net_device *dev, int val)
-{
- dhd_info_t *dhd = DHD_DEV_INFO(dev);
- int ret = 0;
-
- if (dhd)
- ret = dhd_os_wake_lock_ctrl_timeout_enable(&dhd->pub, val);
- return ret;
-}
-
-int dhd_os_wake_lock(dhd_pub_t *pub)
-{
- dhd_info_t *dhd = (dhd_info_t *)(pub->info);
- unsigned long flags;
- int ret = 0;
-
- if (dhd) {
- spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
-
- if (dhd->wakelock_counter == 0 && !dhd->waive_wakelock) {
-#ifdef CONFIG_HAS_WAKELOCK
- wake_lock(&dhd->wl_wifi);
-#elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
- dhd_bus_dev_pm_stay_awake(pub);
-#endif
- }
- dhd->wakelock_counter++;
- ret = dhd->wakelock_counter;
- spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
- }
- return ret;
-}
-
-int net_os_wake_lock(struct net_device *dev)
-{
- dhd_info_t *dhd = DHD_DEV_INFO(dev);
- int ret = 0;
-
- if (dhd)
- ret = dhd_os_wake_lock(&dhd->pub);
- return ret;
-}
-
-int dhd_os_wake_unlock(dhd_pub_t *pub)
-{
- dhd_info_t *dhd = (dhd_info_t *)(pub->info);
- unsigned long flags;
- int ret = 0;
-
- dhd_os_wake_lock_timeout(pub);
- if (dhd) {
- spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
- if (dhd->wakelock_counter > 0) {
- dhd->wakelock_counter--;
- if (dhd->wakelock_counter == 0 && !dhd->waive_wakelock) {
-#ifdef CONFIG_HAS_WAKELOCK
- wake_unlock(&dhd->wl_wifi);
-#elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
- dhd_bus_dev_pm_relax(pub);
-#endif
- }
- ret = dhd->wakelock_counter;
- }
- spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
- }
- return ret;
-}
-
-int dhd_os_check_wakelock(dhd_pub_t *pub)
-{
-#if defined(CONFIG_HAS_WAKELOCK) || (defined(BCMSDIO) && (LINUX_VERSION_CODE > \
- KERNEL_VERSION(2, 6, 36)))
- dhd_info_t *dhd;
-
- if (!pub)
- return 0;
- dhd = (dhd_info_t *)(pub->info);
-#endif /* CONFIG_HAS_WAKELOCK || BCMSDIO */
-
-#ifdef CONFIG_HAS_WAKELOCK
- /* Indicate to the SD Host to avoid going to suspend if internal locks are up */
- if (dhd && (wake_lock_active(&dhd->wl_wifi) ||
- (wake_lock_active(&dhd->wl_wdwake))))
- return 1;
-#elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
- if (dhd && (dhd->wakelock_counter > 0) && dhd_bus_dev_pm_enabled(pub))
- return 1;
-#endif
- return 0;
-}
-int net_os_wake_unlock(struct net_device *dev)
-{
- dhd_info_t *dhd = DHD_DEV_INFO(dev);
- int ret = 0;
-
- if (dhd)
- ret = dhd_os_wake_unlock(&dhd->pub);
- return ret;
-}
-
-int dhd_os_wd_wake_lock(dhd_pub_t *pub)
-{
- dhd_info_t *dhd = (dhd_info_t *)(pub->info);
- unsigned long flags;
- int ret = 0;
-
- if (dhd) {
- spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
-#ifdef CONFIG_HAS_WAKELOCK
- /* if wakelock_wd_counter was never used : lock it at once */
- if (!dhd->wakelock_wd_counter)
- wake_lock(&dhd->wl_wdwake);
-#endif
- dhd->wakelock_wd_counter++;
- ret = dhd->wakelock_wd_counter;
- spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
- }
- return ret;
-}
-
-int dhd_os_wd_wake_unlock(dhd_pub_t *pub)
-{
- dhd_info_t *dhd = (dhd_info_t *)(pub->info);
- unsigned long flags;
- int ret = 0;
-
- if (dhd) {
- spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
- if (dhd->wakelock_wd_counter) {
- dhd->wakelock_wd_counter = 0;
-#ifdef CONFIG_HAS_WAKELOCK
- wake_unlock(&dhd->wl_wdwake);
-#endif
- }
- spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
- }
- return ret;
-}
-
-/* waive wakelocks for operations such as IOVARs in suspend function, must be closed
- * by a paired function call to dhd_wakelock_restore. returns current wakelock counter
- */
-int dhd_os_wake_lock_waive(dhd_pub_t *pub)
-{
- dhd_info_t *dhd = (dhd_info_t *)(pub->info);
- unsigned long flags;
- int ret = 0;
-
- if (dhd) {
- spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
- /* dhd_wakelock_waive/dhd_wakelock_restore must be paired */
- if (dhd->waive_wakelock == FALSE) {
- /* record current lock status */
- dhd->wakelock_before_waive = dhd->wakelock_counter;
- dhd->waive_wakelock = TRUE;
- }
- ret = dhd->wakelock_wd_counter;
- spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
- }
- return ret;
-}
-
-int dhd_os_wake_lock_restore(dhd_pub_t *pub)
-{
- dhd_info_t *dhd = (dhd_info_t *)(pub->info);
- unsigned long flags;
- int ret = 0;
-
- if (!dhd)
- return 0;
-
- spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
- /* dhd_wakelock_waive/dhd_wakelock_restore must be paired */
- if (!dhd->waive_wakelock)
- goto exit;
-
- dhd->waive_wakelock = FALSE;
- /* if somebody else acquires wakelock between dhd_wakelock_waive/dhd_wakelock_restore,
- * we need to make it up by calling wake_lock or pm_stay_awake. or if somebody releases
- * the lock in between, do the same by calling wake_unlock or pm_relax
- */
- if (dhd->wakelock_before_waive == 0 && dhd->wakelock_counter > 0) {
-#ifdef CONFIG_HAS_WAKELOCK
- wake_lock(&dhd->wl_wifi);
-#elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
- dhd_bus_dev_pm_stay_awake(&dhd->pub);
-#endif
- } else if (dhd->wakelock_before_waive > 0 && dhd->wakelock_counter == 0) {
-#ifdef CONFIG_HAS_WAKELOCK
- wake_unlock(&dhd->wl_wifi);
-#elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
- dhd_bus_dev_pm_relax(&dhd->pub);
-#endif
- }
- dhd->wakelock_before_waive = 0;
-exit:
- ret = dhd->wakelock_wd_counter;
- spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
- return ret;
-}
-
-bool dhd_os_check_if_up(dhd_pub_t *pub)
-{
- if (!pub)
- return FALSE;
- return pub->up;
-}
-
-#if defined(BCMSDIO)
-/* function to collect firmware, chip id and chip version info */
-void dhd_set_version_info(dhd_pub_t *dhdp, char *fw)
-{
- int i;
-
- i = snprintf(info_string, sizeof(info_string),
- " Driver: %s\n Firmware: %s ", EPI_VERSION_STR, fw);
- printf("%s\n", info_string);
-
- if (!dhdp)
- return;
-
- i = snprintf(&info_string[i], sizeof(info_string) - i,
- "\n Chip: %x Rev %x Pkg %x", dhd_bus_chip_id(dhdp),
- dhd_bus_chiprev_id(dhdp), dhd_bus_chippkg_id(dhdp));
-}
-#endif /* defined(BCMSDIO) */
-int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd)
-{
- int ifidx;
- int ret = 0;
- dhd_info_t *dhd = NULL;
-
- if (!net || !DEV_PRIV(net)) {
- DHD_ERROR(("%s invalid parameter\n", __FUNCTION__));
- return -EINVAL;
- }
-
- dhd = DHD_DEV_INFO(net);
- if (!dhd)
- return -EINVAL;
-
- ifidx = dhd_net2idx(dhd, net);
- if (ifidx == DHD_BAD_IF) {
- DHD_ERROR(("%s bad ifidx\n", __FUNCTION__));
- return -ENODEV;
- }
-
- DHD_OS_WAKE_LOCK(&dhd->pub);
- DHD_PERIM_LOCK(&dhd->pub);
-
- ret = dhd_wl_ioctl(&dhd->pub, ifidx, ioc, ioc->buf, ioc->len);
- dhd_check_hang(net, &dhd->pub, ret);
-
- DHD_PERIM_UNLOCK(&dhd->pub);
- DHD_OS_WAKE_UNLOCK(&dhd->pub);
-
- return ret;
-}
-
-bool dhd_os_check_hang(dhd_pub_t *dhdp, int ifidx, int ret)
-{
- struct net_device *net;
-
- net = dhd_idx2net(dhdp, ifidx);
- if (!net) {
- DHD_ERROR(("%s : Invalid index : %d\n", __FUNCTION__, ifidx));
- return -EINVAL;
- }
-
- return dhd_check_hang(net, dhdp, ret);
-}
-
-/* Return instance */
-int dhd_get_instance(dhd_pub_t *dhdp)
-{
- return dhdp->info->unit;
-}
-
-
-#ifdef PROP_TXSTATUS
-
-void dhd_wlfc_plat_init(void *dhd)
-{
- return;
-}
-
-void dhd_wlfc_plat_deinit(void *dhd)
-{
- return;
-}
-
-bool dhd_wlfc_skip_fc(void)
-{
- return FALSE;
-}
-#endif /* PROP_TXSTATUS */
-
-#ifdef BCMDBGFS
-
-#include <linux/debugfs.h>
-
-extern uint32 dhd_readregl(void *bp, uint32 addr);
-extern uint32 dhd_writeregl(void *bp, uint32 addr, uint32 data);
-
-typedef struct dhd_dbgfs {
- struct dentry *debugfs_dir;
- struct dentry *debugfs_mem;
- dhd_pub_t *dhdp;
- uint32 size;
-} dhd_dbgfs_t;
-
-dhd_dbgfs_t g_dbgfs;
-
-static int
-dhd_dbg_state_open(struct inode *inode, struct file *file)
-{
- file->private_data = inode->i_private;
- return 0;
-}
-
-static ssize_t
-dhd_dbg_state_read(struct file *file, char __user *ubuf,
- size_t count, loff_t *ppos)
-{
- ssize_t rval;
- uint32 tmp;
- loff_t pos = *ppos;
- size_t ret;
-
- if (pos < 0)
- return -EINVAL;
- if (pos >= g_dbgfs.size || !count)
- return 0;
- if (count > g_dbgfs.size - pos)
- count = g_dbgfs.size - pos;
-
- /* Basically enforce aligned 4 byte reads. It's up to the user to work out the details */
- tmp = dhd_readregl(g_dbgfs.dhdp->bus, file->f_pos & (~3));
-
- ret = copy_to_user(ubuf, &tmp, 4);
- if (ret == count)
- return -EFAULT;
-
- count -= ret;
- *ppos = pos + count;
- rval = count;
-
- return rval;
-}
-
-
-static ssize_t
-dhd_debugfs_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos)
-{
- loff_t pos = *ppos;
- size_t ret;
- uint32 buf;
-
- if (pos < 0)
- return -EINVAL;
- if (pos >= g_dbgfs.size || !count)
- return 0;
- if (count > g_dbgfs.size - pos)
- count = g_dbgfs.size - pos;
-
- ret = copy_from_user(&buf, ubuf, sizeof(uint32));
- if (ret == count)
- return -EFAULT;
-
- /* Basically enforce aligned 4 byte writes. It's up to the user to work out the details */
- dhd_writeregl(g_dbgfs.dhdp->bus, file->f_pos & (~3), buf);
-
- return count;
-}
-
-
-loff_t
-dhd_debugfs_lseek(struct file *file, loff_t off, int whence)
-{
- loff_t pos = -1;
-
- switch (whence) {
- case 0:
- pos = off;
- break;
- case 1:
- pos = file->f_pos + off;
- break;
- case 2:
- pos = g_dbgfs.size - off;
- }
- return (pos < 0 || pos > g_dbgfs.size) ? -EINVAL : (file->f_pos = pos);
-}
-
-static const struct file_operations dhd_dbg_state_ops = {
- .read = dhd_dbg_state_read,
- .write = dhd_debugfs_write,
- .open = dhd_dbg_state_open,
- .llseek = dhd_debugfs_lseek
-};
-
-static void dhd_dbg_create(void)
-{
- if (g_dbgfs.debugfs_dir) {
- g_dbgfs.debugfs_mem = debugfs_create_file("mem", 0644, g_dbgfs.debugfs_dir,
- NULL, &dhd_dbg_state_ops);
- }
-}
-
-void dhd_dbg_init(dhd_pub_t *dhdp)
-{
- int err;
-
- g_dbgfs.dhdp = dhdp;
- g_dbgfs.size = 0x20000000; /* Allow access to various cores regs */
-
- g_dbgfs.debugfs_dir = debugfs_create_dir("dhd", 0);
- if (IS_ERR(g_dbgfs.debugfs_dir)) {
- err = PTR_ERR(g_dbgfs.debugfs_dir);
- g_dbgfs.debugfs_dir = NULL;
- return;
- }
-
- dhd_dbg_create();
-
- return;
-}
-
-void dhd_dbg_remove(void)
-{
- debugfs_remove(g_dbgfs.debugfs_mem);
- debugfs_remove(g_dbgfs.debugfs_dir);
-
- bzero((unsigned char *) &g_dbgfs, sizeof(g_dbgfs));
-
-}
-#endif /* ifdef BCMDBGFS */
-
-#ifdef WLMEDIA_HTSF
-
-static
-void dhd_htsf_addtxts(dhd_pub_t *dhdp, void *pktbuf)
-{
- dhd_info_t *dhd = (dhd_info_t *)(dhdp->info);
- struct sk_buff *skb;
- uint32 htsf = 0;
- uint16 dport = 0, oldmagic = 0xACAC;
- char *p1;
- htsfts_t ts;
-
- /* timestamp packet */
-
- p1 = (char*) PKTDATA(dhdp->osh, pktbuf);
-
- if (PKTLEN(dhdp->osh, pktbuf) > HTSF_MINLEN) {
-/* memcpy(&proto, p1+26, 4); */
- memcpy(&dport, p1+40, 2);
-/* proto = ((ntoh32(proto))>> 16) & 0xFF; */
- dport = ntoh16(dport);
- }
-
- /* timestamp only if icmp or udb iperf with port 5555 */
-/* if (proto == 17 && dport == tsport) { */
- if (dport >= tsport && dport <= tsport + 20) {
-
- skb = (struct sk_buff *) pktbuf;
-
- htsf = dhd_get_htsf(dhd, 0);
- memset(skb->data + 44, 0, 2); /* clear checksum */
- memcpy(skb->data+82, &oldmagic, 2);
- memcpy(skb->data+84, &htsf, 4);
-
- memset(&ts, 0, sizeof(htsfts_t));
- ts.magic = HTSFMAGIC;
- ts.prio = PKTPRIO(pktbuf);
- ts.seqnum = htsf_seqnum++;
- ts.c10 = get_cycles();
- ts.t10 = htsf;
- ts.endmagic = HTSFENDMAGIC;
-
- memcpy(skb->data + HTSF_HOSTOFFSET, &ts, sizeof(ts));
- }
-}
-
-static void dhd_dump_htsfhisto(histo_t *his, char *s)
-{
- int pktcnt = 0, curval = 0, i;
- for (i = 0; i < (NUMBIN-2); i++) {
- curval += 500;
- printf("%d ", his->bin[i]);
- pktcnt += his->bin[i];
- }
- printf(" max: %d TotPkt: %d neg: %d [%s]\n", his->bin[NUMBIN-2], pktcnt,
- his->bin[NUMBIN-1], s);
-}
-
-static
-void sorttobin(int value, histo_t *histo)
-{
- int i, binval = 0;
-
- if (value < 0) {
- histo->bin[NUMBIN-1]++;
- return;
- }
- if (value > histo->bin[NUMBIN-2]) /* store the max value */
- histo->bin[NUMBIN-2] = value;
-
- for (i = 0; i < (NUMBIN-2); i++) {
- binval += 500; /* 500m s bins */
- if (value <= binval) {
- histo->bin[i]++;
- return;
- }
- }
- histo->bin[NUMBIN-3]++;
-}
-
-static
-void dhd_htsf_addrxts(dhd_pub_t *dhdp, void *pktbuf)
-{
- dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
- struct sk_buff *skb;
- char *p1;
- uint16 old_magic;
- int d1, d2, d3, end2end;
- htsfts_t *htsf_ts;
- uint32 htsf;
-
- skb = PKTTONATIVE(dhdp->osh, pktbuf);
- p1 = (char*)PKTDATA(dhdp->osh, pktbuf);
-
- if (PKTLEN(osh, pktbuf) > HTSF_MINLEN) {
- memcpy(&old_magic, p1+78, 2);
- htsf_ts = (htsfts_t*) (p1 + HTSF_HOSTOFFSET - 4);
- }
- else
- return;
-
- if (htsf_ts->magic == HTSFMAGIC) {
- htsf_ts->tE0 = dhd_get_htsf(dhd, 0);
- htsf_ts->cE0 = get_cycles();
- }
-
- if (old_magic == 0xACAC) {
-
- tspktcnt++;
- htsf = dhd_get_htsf(dhd, 0);
- memcpy(skb->data+92, &htsf, sizeof(uint32));
-
- memcpy(&ts[tsidx].t1, skb->data+80, 16);
-
- d1 = ts[tsidx].t2 - ts[tsidx].t1;
- d2 = ts[tsidx].t3 - ts[tsidx].t2;
- d3 = ts[tsidx].t4 - ts[tsidx].t3;
- end2end = ts[tsidx].t4 - ts[tsidx].t1;
-
- sorttobin(d1, &vi_d1);
- sorttobin(d2, &vi_d2);
- sorttobin(d3, &vi_d3);
- sorttobin(end2end, &vi_d4);
-
- if (end2end > 0 && end2end > maxdelay) {
- maxdelay = end2end;
- maxdelaypktno = tspktcnt;
- memcpy(&maxdelayts, &ts[tsidx], 16);
- }
- if (++tsidx >= TSMAX)
- tsidx = 0;
- }
-}
-
-uint32 dhd_get_htsf(dhd_info_t *dhd, int ifidx)
-{
- uint32 htsf = 0, cur_cycle, delta, delta_us;
- uint32 factor, baseval, baseval2;
- cycles_t t;
-
- t = get_cycles();
- cur_cycle = t;
-
- if (cur_cycle > dhd->htsf.last_cycle)
- delta = cur_cycle - dhd->htsf.last_cycle;
- else {
- delta = cur_cycle + (0xFFFFFFFF - dhd->htsf.last_cycle);
- }
-
- delta = delta >> 4;
-
- if (dhd->htsf.coef) {
- /* times ten to get the first digit */
- factor = (dhd->htsf.coef*10 + dhd->htsf.coefdec1);
- baseval = (delta*10)/factor;
- baseval2 = (delta*10)/(factor+1);
- delta_us = (baseval - (((baseval - baseval2) * dhd->htsf.coefdec2)) / 10);
- htsf = (delta_us << 4) + dhd->htsf.last_tsf + HTSF_BUS_DELAY;
- }
- else {
- DHD_ERROR(("-------dhd->htsf.coef = 0 -------\n"));
- }
-
- return htsf;
-}
-
-static void dhd_dump_latency(void)
-{
- int i, max = 0;
- int d1, d2, d3, d4, d5;
-
- printf("T1 T2 T3 T4 d1 d2 t4-t1 i \n");
- for (i = 0; i < TSMAX; i++) {
- d1 = ts[i].t2 - ts[i].t1;
- d2 = ts[i].t3 - ts[i].t2;
- d3 = ts[i].t4 - ts[i].t3;
- d4 = ts[i].t4 - ts[i].t1;
- d5 = ts[max].t4-ts[max].t1;
- if (d4 > d5 && d4 > 0) {
- max = i;
- }
- printf("%08X %08X %08X %08X \t%d %d %d %d i=%d\n",
- ts[i].t1, ts[i].t2, ts[i].t3, ts[i].t4,
- d1, d2, d3, d4, i);
- }
-
- printf("current idx = %d \n", tsidx);
-
- printf("Highest latency %d pkt no.%d total=%d\n", maxdelay, maxdelaypktno, tspktcnt);
- printf("%08X %08X %08X %08X \t%d %d %d %d\n",
- maxdelayts.t1, maxdelayts.t2, maxdelayts.t3, maxdelayts.t4,
- maxdelayts.t2 - maxdelayts.t1,
- maxdelayts.t3 - maxdelayts.t2,
- maxdelayts.t4 - maxdelayts.t3,
- maxdelayts.t4 - maxdelayts.t1);
-}
-
-
-static int
-dhd_ioctl_htsf_get(dhd_info_t *dhd, int ifidx)
-{
- wl_ioctl_t ioc;
- char buf[32];
- int ret;
- uint32 s1, s2;
-
- struct tsf {
- uint32 low;
- uint32 high;
- } tsf_buf;
-
- memset(&ioc, 0, sizeof(ioc));
- memset(&tsf_buf, 0, sizeof(tsf_buf));
-
- ioc.cmd = WLC_GET_VAR;
- ioc.buf = buf;
- ioc.len = (uint)sizeof(buf);
- ioc.set = FALSE;
-
- strncpy(buf, "tsf", sizeof(buf) - 1);
- buf[sizeof(buf) - 1] = '\0';
- s1 = dhd_get_htsf(dhd, 0);
- if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) {
- if (ret == -EIO) {
- DHD_ERROR(("%s: tsf is not supported by device\n",
- dhd_ifname(&dhd->pub, ifidx)));
- return -EOPNOTSUPP;
- }
- return ret;
- }
- s2 = dhd_get_htsf(dhd, 0);
-
- memcpy(&tsf_buf, buf, sizeof(tsf_buf));
- printf(" TSF_h=%04X lo=%08X Calc:htsf=%08X, coef=%d.%d%d delta=%d ",
- tsf_buf.high, tsf_buf.low, s2, dhd->htsf.coef, dhd->htsf.coefdec1,
- dhd->htsf.coefdec2, s2-tsf_buf.low);
- printf("lasttsf=%08X lastcycle=%08X\n", dhd->htsf.last_tsf, dhd->htsf.last_cycle);
- return 0;
-}
-
-void htsf_update(dhd_info_t *dhd, void *data)
-{
- static ulong cur_cycle = 0, prev_cycle = 0;
- uint32 htsf, tsf_delta = 0;
- uint32 hfactor = 0, cyc_delta, dec1 = 0, dec2, dec3, tmp;
- ulong b, a;
- cycles_t t;
-
- /* cycles_t in inlcude/mips/timex.h */
-
- t = get_cycles();
-
- prev_cycle = cur_cycle;
- cur_cycle = t;
-
- if (cur_cycle > prev_cycle)
- cyc_delta = cur_cycle - prev_cycle;
- else {
- b = cur_cycle;
- a = prev_cycle;
- cyc_delta = cur_cycle + (0xFFFFFFFF - prev_cycle);
- }
-
- if (data == NULL)
- printf(" tsf update ata point er is null \n");
-
- memcpy(&prev_tsf, &cur_tsf, sizeof(tsf_t));
- memcpy(&cur_tsf, data, sizeof(tsf_t));
-
- if (cur_tsf.low == 0) {
- DHD_INFO((" ---- 0 TSF, do not update, return\n"));
- return;
- }
-
- if (cur_tsf.low > prev_tsf.low)
- tsf_delta = (cur_tsf.low - prev_tsf.low);
- else {
- DHD_INFO((" ---- tsf low is smaller cur_tsf= %08X, prev_tsf=%08X, \n",
- cur_tsf.low, prev_tsf.low));
- if (cur_tsf.high > prev_tsf.high) {
- tsf_delta = cur_tsf.low + (0xFFFFFFFF - prev_tsf.low);
- DHD_INFO((" ---- Wrap around tsf coutner adjusted TSF=%08X\n", tsf_delta));
- }
- else
- return; /* do not update */
- }
-
- if (tsf_delta) {
- hfactor = cyc_delta / tsf_delta;
- tmp = (cyc_delta - (hfactor * tsf_delta))*10;
- dec1 = tmp/tsf_delta;
- dec2 = ((tmp - dec1*tsf_delta)*10) / tsf_delta;
- tmp = (tmp - (dec1*tsf_delta))*10;
- dec3 = ((tmp - dec2*tsf_delta)*10) / tsf_delta;
-
- if (dec3 > 4) {
- if (dec2 == 9) {
- dec2 = 0;
- if (dec1 == 9) {
- dec1 = 0;
- hfactor++;
- }
- else {
- dec1++;
- }
- }
- else
- dec2++;
- }
- }
-
- if (hfactor) {
- htsf = ((cyc_delta * 10) / (hfactor*10+dec1)) + prev_tsf.low;
- dhd->htsf.coef = hfactor;
- dhd->htsf.last_cycle = cur_cycle;
- dhd->htsf.last_tsf = cur_tsf.low;
- dhd->htsf.coefdec1 = dec1;
- dhd->htsf.coefdec2 = dec2;
- }
- else {
- htsf = prev_tsf.low;
- }
-}
-
-#endif /* WLMEDIA_HTSF */
-
-#ifdef CUSTOM_SET_CPUCORE
-void dhd_set_cpucore(dhd_pub_t *dhd, int set)
-{
- int e_dpc = 0, e_rxf = 0, retry_set = 0;
-
- if (!(dhd->chan_isvht80)) {
- DHD_ERROR(("%s: chan_status(%d) cpucore!!!\n", __FUNCTION__, dhd->chan_isvht80));
- return;
- }
-
- if (DPC_CPUCORE) {
- do {
- if (set == TRUE) {
- e_dpc = set_cpus_allowed_ptr(dhd->current_dpc,
- cpumask_of(DPC_CPUCORE));
- } else {
- e_dpc = set_cpus_allowed_ptr(dhd->current_dpc,
- cpumask_of(PRIMARY_CPUCORE));
- }
- if (retry_set++ > MAX_RETRY_SET_CPUCORE) {
- DHD_ERROR(("%s: dpc(%d) invalid cpu!\n", __FUNCTION__, e_dpc));
- return;
- }
- if (e_dpc < 0)
- OSL_SLEEP(1);
- } while (e_dpc < 0);
- }
- if (RXF_CPUCORE) {
- do {
- if (set == TRUE) {
- e_rxf = set_cpus_allowed_ptr(dhd->current_rxf,
- cpumask_of(RXF_CPUCORE));
- } else {
- e_rxf = set_cpus_allowed_ptr(dhd->current_rxf,
- cpumask_of(PRIMARY_CPUCORE));
- }
- if (retry_set++ > MAX_RETRY_SET_CPUCORE) {
- DHD_ERROR(("%s: rxf(%d) invalid cpu!\n", __FUNCTION__, e_rxf));
- return;
- }
- if (e_rxf < 0)
- OSL_SLEEP(1);
- } while (e_rxf < 0);
- }
-#ifdef DHD_OF_SUPPORT
- interrupt_set_cpucore(set);
-#endif /* DHD_OF_SUPPORT */
- DHD_TRACE(("%s: set(%d) cpucore success!\n", __FUNCTION__, set));
-
- return;
-}
-#endif /* CUSTOM_SET_CPUCORE */
-#if defined(DHD_TCP_WINSIZE_ADJUST)
-static int dhd_port_list_match(int port)
-{
- int i;
- for (i = 0; i < MAX_TARGET_PORTS; i++) {
- if (target_ports[i] == port)
- return 1;
- }
- return 0;
-}
-static void dhd_adjust_tcp_winsize(int op_mode, struct sk_buff *skb)
-{
- struct iphdr *ipheader;
- struct tcphdr *tcpheader;
- uint16 win_size;
- int32 incremental_checksum;
-
- if (!(op_mode & DHD_FLAG_HOSTAP_MODE))
- return;
- if (skb == NULL || skb->data == NULL)
- return;
-
- ipheader = (struct iphdr*)(skb->data);
-
- if (ipheader->protocol == IPPROTO_TCP) {
- tcpheader = (struct tcphdr*) skb_pull(skb, (ipheader->ihl)<<2);
- if (tcpheader) {
- win_size = ntoh16(tcpheader->window);
- if (win_size < MIN_TCP_WIN_SIZE &&
- dhd_port_list_match(ntoh16(tcpheader->dest))) {
- incremental_checksum = ntoh16(tcpheader->check);
- incremental_checksum += win_size - win_size*WIN_SIZE_SCALE_FACTOR;
- if (incremental_checksum < 0)
- --incremental_checksum;
- tcpheader->window = hton16(win_size*WIN_SIZE_SCALE_FACTOR);
- tcpheader->check = hton16((unsigned short)incremental_checksum);
- }
- }
- skb_push(skb, (ipheader->ihl)<<2);
- }
-}
-#endif /* DHD_TCP_WINSIZE_ADJUST */
-
-/* Get interface specific ap_isolate configuration */
-int dhd_get_ap_isolate(dhd_pub_t *dhdp, uint32 idx)
-{
- dhd_info_t *dhd = dhdp->info;
- dhd_if_t *ifp;
-
- ASSERT(idx < DHD_MAX_IFS);
-
- ifp = dhd->iflist[idx];
-
- return ifp->ap_isolate;
-}
-
-/* Set interface specific ap_isolate configuration */
-int dhd_set_ap_isolate(dhd_pub_t *dhdp, uint32 idx, int val)
-{
- dhd_info_t *dhd = dhdp->info;
- dhd_if_t *ifp;
-
- ASSERT(idx < DHD_MAX_IFS);
-
- ifp = dhd->iflist[idx];
-
- ifp->ap_isolate = val;
-
- return 0;
-}
-
-#ifdef DHD_WMF
-/* Returns interface specific WMF configuration */
-dhd_wmf_t* dhd_wmf_conf(dhd_pub_t *dhdp, uint32 idx)
-{
- dhd_info_t *dhd = dhdp->info;
- dhd_if_t *ifp;
-
- ASSERT(idx < DHD_MAX_IFS);
-
- ifp = dhd->iflist[idx];
- return &ifp->wmf;
-}
-#endif /* DHD_WMF */
-
-
-#ifdef DHD_UNICAST_DHCP
-static int
-dhd_get_pkt_ether_type(dhd_pub_t *pub, void *pktbuf,
- uint8 **data_ptr, int *len_ptr, uint16 *et_ptr, bool *snap_ptr)
-{
- uint8 *frame = PKTDATA(pub->osh, pktbuf);
- int length = PKTLEN(pub->osh, pktbuf);
- uint8 *pt; /* Pointer to type field */
- uint16 ethertype;
- bool snap = FALSE;
- /* Process Ethernet II or SNAP-encapsulated 802.3 frames */
- if (length < ETHER_HDR_LEN) {
- DHD_ERROR(("dhd: %s: short eth frame (%d)\n",
- __FUNCTION__, length));
- return BCME_ERROR;
- } else if (ntoh16_ua(frame + ETHER_TYPE_OFFSET) >= ETHER_TYPE_MIN) {
- /* Frame is Ethernet II */
- pt = frame + ETHER_TYPE_OFFSET;
- } else if (length >= ETHER_HDR_LEN + SNAP_HDR_LEN + ETHER_TYPE_LEN &&
- !bcmp(llc_snap_hdr, frame + ETHER_HDR_LEN, SNAP_HDR_LEN)) {
- pt = frame + ETHER_HDR_LEN + SNAP_HDR_LEN;
- snap = TRUE;
- } else {
- DHD_INFO(("DHD: %s: non-SNAP 802.3 frame\n",
- __FUNCTION__));
- return BCME_ERROR;
- }
-
- ethertype = ntoh16_ua(pt);
-
- /* Skip VLAN tag, if any */
- if (ethertype == ETHER_TYPE_8021Q) {
- pt += VLAN_TAG_LEN;
-
- if ((pt + ETHER_TYPE_LEN) > (frame + length)) {
- DHD_ERROR(("dhd: %s: short VLAN frame (%d)\n",
- __FUNCTION__, length));
- return BCME_ERROR;
- }
-
- ethertype = ntoh16_ua(pt);
- }
-
- *data_ptr = pt + ETHER_TYPE_LEN;
- *len_ptr = length - (pt + ETHER_TYPE_LEN - frame);
- *et_ptr = ethertype;
- *snap_ptr = snap;
- return BCME_OK;
-}
-
-static int
-dhd_get_pkt_ip_type(dhd_pub_t *pub, void *pktbuf,
- uint8 **data_ptr, int *len_ptr, uint8 *prot_ptr)
-{
- struct ipv4_hdr *iph; /* IP frame pointer */
- int iplen; /* IP frame length */
- uint16 ethertype, iphdrlen, ippktlen;
- uint16 iph_frag;
- uint8 prot;
- bool snap;
-
- if (dhd_get_pkt_ether_type(pub, pktbuf, (uint8 **)&iph,
- &iplen, &ethertype, &snap) != 0)
- return BCME_ERROR;
-
- if (ethertype != ETHER_TYPE_IP) {
- return BCME_ERROR;
- }
-
- /* We support IPv4 only */
- if (iplen < IPV4_OPTIONS_OFFSET || (IP_VER(iph) != IP_VER_4)) {
- return BCME_ERROR;
- }
-
- /* Header length sanity */
- iphdrlen = IPV4_HLEN(iph);
-
- /*
- * Packet length sanity; sometimes we receive eth-frame size bigger
- * than the IP content, which results in a bad tcp chksum
- */
- ippktlen = ntoh16(iph->tot_len);
- if (ippktlen < iplen) {
-
- DHD_INFO(("%s: extra frame length ignored\n",
- __FUNCTION__));
- iplen = ippktlen;
- } else if (ippktlen > iplen) {
- DHD_ERROR(("dhd: %s: truncated IP packet (%d)\n",
- __FUNCTION__, ippktlen - iplen));
- return BCME_ERROR;
- }
-
- if (iphdrlen < IPV4_OPTIONS_OFFSET || iphdrlen > iplen) {
- DHD_ERROR(("DHD: %s: IP-header-len (%d) out of range (%d-%d)\n",
- __FUNCTION__, iphdrlen, IPV4_OPTIONS_OFFSET, iplen));
- return BCME_ERROR;
- }
-
- /*
- * We don't handle fragmented IP packets. A first frag is indicated by the MF
- * (more frag) bit and a subsequent frag is indicated by a non-zero frag offset.
- */
- iph_frag = ntoh16(iph->frag);
-
- if ((iph_frag & IPV4_FRAG_MORE) || (iph_frag & IPV4_FRAG_OFFSET_MASK) != 0) {
- DHD_INFO(("DHD:%s: IP fragment not handled\n",
- __FUNCTION__));
- return BCME_ERROR;
- }
-
- prot = IPV4_PROT(iph);
-
- *data_ptr = (((uint8 *)iph) + iphdrlen);
- *len_ptr = iplen - iphdrlen;
- *prot_ptr = prot;
- return BCME_OK;
-}
-
-/** check the packet type, if it is DHCP ACK/REPLY, convert into unicast packet */
-static
-int dhd_convert_dhcp_broadcast_ack_to_unicast(dhd_pub_t *pub, void *pktbuf, int ifidx)
-{
- dhd_sta_t* stainfo;
- uint8 *eh = PKTDATA(pub->osh, pktbuf);
- uint8 *udph;
- uint8 *dhcp;
- uint8 *chaddr;
- int udpl;
- int dhcpl;
- uint16 port;
- uint8 prot;
-
- if (!ETHER_ISMULTI(eh + ETHER_DEST_OFFSET))
- return BCME_ERROR;
- if (dhd_get_pkt_ip_type(pub, pktbuf, &udph, &udpl, &prot) != 0)
- return BCME_ERROR;
- if (prot != IP_PROT_UDP)
- return BCME_ERROR;
- /* check frame length, at least UDP_HDR_LEN */
- if (udpl < UDP_HDR_LEN) {
- DHD_ERROR(("DHD: %s: short UDP frame, ignored\n",
- __FUNCTION__));
- return BCME_ERROR;
- }
- port = ntoh16_ua(udph + UDP_DEST_PORT_OFFSET);
- /* only process DHCP packets from server to client */
- if (port != DHCP_PORT_CLIENT)
- return BCME_ERROR;
-
- dhcp = udph + UDP_HDR_LEN;
- dhcpl = udpl - UDP_HDR_LEN;
-
- if (dhcpl < DHCP_CHADDR_OFFSET + ETHER_ADDR_LEN) {
- DHD_ERROR(("DHD: %s: short DHCP frame, ignored\n",
- __FUNCTION__));
- return BCME_ERROR;
- }
- /* only process DHCP reply(offer/ack) packets */
- if (*(dhcp + DHCP_TYPE_OFFSET) != DHCP_TYPE_REPLY)
- return BCME_ERROR;
- chaddr = dhcp + DHCP_CHADDR_OFFSET;
- stainfo = dhd_find_sta(pub, ifidx, chaddr);
- if (stainfo) {
- bcopy(chaddr, eh + ETHER_DEST_OFFSET, ETHER_ADDR_LEN);
- return BCME_OK;
- }
- return BCME_ERROR;
-}
-#endif /* DHD_UNICAST_DHD */
-#ifdef DHD_L2_FILTER
-/* Check if packet type is ICMP ECHO */
-static
-int dhd_l2_filter_block_ping(dhd_pub_t *pub, void *pktbuf, int ifidx)
-{
- struct bcmicmp_hdr *icmph;
- int udpl;
- uint8 prot;
-
- if (dhd_get_pkt_ip_type(pub, pktbuf, (uint8 **)&icmph, &udpl, &prot) != 0)
- return BCME_ERROR;
- if (prot == IP_PROT_ICMP) {
- if (icmph->type == ICMP_TYPE_ECHO_REQUEST)
- return BCME_OK;
- }
- return BCME_ERROR;
-}
-#endif /* DHD_L2_FILTER */
-
-void *dhd_get_pub(struct net_device *dev)
-{
- dhd_info_t *dhdinfo = *(dhd_info_t **)netdev_priv(dev);
- return (void *)&dhdinfo->pub;
-}
+/*
+ * Broadcom Dongle Host Driver (DHD), Linux-specific network interface
+ * Basically selected code segments from usb-cdc.c and usb-rndis.c
+ *
+ * $Copyright Open Broadcom Corporation$
+ *
+ * $Id: dhd_linux.c 505753 2014-10-01 01:40:15Z $
+ */
+
+#include <typedefs.h>
+#include <linuxver.h>
+#include <osl.h>
+#ifdef SHOW_LOGTRACE
+#include <linux/syscalls.h>
+#include <event_log.h>
+#endif /* SHOW_LOGTRACE */
+
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/rtnetlink.h>
+#include <linux/etherdevice.h>
+#include <linux/random.h>
+#include <linux/spinlock.h>
+#include <linux/ethtool.h>
+#include <linux/fcntl.h>
+#include <linux/fs.h>
+#include <linux/ip.h>
+#include <linux/reboot.h>
+#include <linux/notifier.h>
+#include <net/addrconf.h>
+#ifdef ENABLE_ADAPTIVE_SCHED
+#include <linux/cpufreq.h>
+#endif /* ENABLE_ADAPTIVE_SCHED */
+
+#include <asm/uaccess.h>
+#include <asm/unaligned.h>
+
+#include <epivers.h>
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include <bcmdevs.h>
+
+#include <proto/ethernet.h>
+#include <proto/bcmevent.h>
+#include <proto/vlan.h>
+#ifdef DHD_L2_FILTER
+#include <proto/bcmicmp.h>
+#endif
+#include <proto/802.3.h>
+
+#include <dngl_stats.h>
+#include <dhd_linux_wq.h>
+#include <dhd.h>
+#include <dhd_linux.h>
+#ifdef PCIE_FULL_DONGLE
+#include <dhd_flowring.h>
+#endif
+#include <dhd_bus.h>
+#include <dhd_proto.h>
+#include <dhd_config.h>
+#include <dhd_dbg.h>
+#ifdef CONFIG_HAS_WAKELOCK
+#include <linux/wakelock.h>
+#endif
+#ifdef WL_CFG80211
+#include <wl_cfg80211.h>
+#endif
+#ifdef P2PONEINT
+#include <wl_cfgp2p.h>
+#endif
+#ifdef PNO_SUPPORT
+#include <dhd_pno.h>
+#endif
+#ifdef WLBTAMP
+#include <proto/802.11_bta.h>
+#include <proto/bt_amp_hci.h>
+#include <dhd_bta.h>
+#endif
+
+#ifdef CONFIG_COMPAT
+#include <linux/compat.h>
+#endif
+
+#ifdef DHD_WMF
+#include <dhd_wmf_linux.h>
+#endif /* DHD_WMF */
+
+#ifdef AMPDU_VO_ENABLE
+#include <proto/802.1d.h>
+#endif /* AMPDU_VO_ENABLE */
+#ifdef DHDTCPACK_SUPPRESS
+#include <dhd_ip.h>
+#endif /* DHDTCPACK_SUPPRESS */
+
+#if defined(DHD_TCP_WINSIZE_ADJUST)
+#include <linux/tcp.h>
+#include <net/tcp.h>
+#endif /* DHD_TCP_WINSIZE_ADJUST */
+
+#ifdef WLMEDIA_HTSF
+#include <linux/time.h>
+#include <htsf.h>
+
+#define HTSF_MINLEN 200 /* min. packet length to timestamp */
+#define HTSF_BUS_DELAY 150 /* assume a fix propagation in us */
+#define TSMAX 1000 /* max no. of timing record kept */
+#define NUMBIN 34
+
+static uint32 tsidx = 0;
+static uint32 htsf_seqnum = 0;
+uint32 tsfsync;
+struct timeval tsync;
+static uint32 tsport = 5010;
+
+typedef struct histo_ {
+ uint32 bin[NUMBIN];
+} histo_t;
+
+#if !ISPOWEROF2(DHD_SDALIGN)
+#error DHD_SDALIGN is not a power of 2!
+#endif
+
+static histo_t vi_d1, vi_d2, vi_d3, vi_d4;
+#endif /* WLMEDIA_HTSF */
+
+#if defined(DHD_TCP_WINSIZE_ADJUST)
+#define MIN_TCP_WIN_SIZE 18000
+#define WIN_SIZE_SCALE_FACTOR 2
+#define MAX_TARGET_PORTS 5
+
+static uint target_ports[MAX_TARGET_PORTS] = {20, 0, 0, 0, 0};
+static uint dhd_use_tcp_window_size_adjust = FALSE;
+static void dhd_adjust_tcp_winsize(int op_mode, struct sk_buff *skb);
+#endif /* DHD_TCP_WINSIZE_ADJUST */
+
+
+#if defined(SOFTAP)
+extern bool ap_cfg_running;
+extern bool ap_fw_loaded;
+#endif
+
+
+#ifdef ENABLE_ADAPTIVE_SCHED
+#define DEFAULT_CPUFREQ_THRESH 1000000 /* threshold frequency : 1000000 = 1GHz */
+#ifndef CUSTOM_CPUFREQ_THRESH
+#define CUSTOM_CPUFREQ_THRESH DEFAULT_CPUFREQ_THRESH
+#endif /* CUSTOM_CPUFREQ_THRESH */
+#endif /* ENABLE_ADAPTIVE_SCHED */
+
+/* enable HOSTIP cache update from the host side when an eth0:N is up */
+#define AOE_IP_ALIAS_SUPPORT 1
+
+#ifdef BCM_FD_AGGR
+#include <bcm_rpc.h>
+#include <bcm_rpc_tp.h>
+#endif
+#ifdef PROP_TXSTATUS
+#include <wlfc_proto.h>
+#include <dhd_wlfc.h>
+#endif
+
+#include <wl_android.h>
+
+#if defined(CUSTOMER_HW20) && defined(WLANAUDIO)
+#include <sdaudio.h>
+#endif /* CUSTOMER_HW20 && WLANAUDIO */
+
+/* Maximum STA per radio */
+#define DHD_MAX_STA 32
+
+
+const uint8 wme_fifo2ac[] = { 0, 1, 2, 3, 1, 1 };
+const uint8 prio2fifo[8] = { 1, 0, 0, 1, 2, 2, 3, 3 };
+#define WME_PRIO2AC(prio) wme_fifo2ac[prio2fifo[(prio)]]
+
+#ifdef ARP_OFFLOAD_SUPPORT
+void aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add, int idx);
+static int dhd_inetaddr_notifier_call(struct notifier_block *this,
+ unsigned long event, void *ptr);
+static struct notifier_block dhd_inetaddr_notifier = {
+ .notifier_call = dhd_inetaddr_notifier_call
+};
+/* to make sure we won't register the same notifier twice, otherwise a loop is likely to be
+ * created in kernel notifier link list (with 'next' pointing to itself)
+ */
+static bool dhd_inetaddr_notifier_registered = FALSE;
+#endif /* ARP_OFFLOAD_SUPPORT */
+
+#ifdef CONFIG_IPV6
+static int dhd_inet6addr_notifier_call(struct notifier_block *this,
+ unsigned long event, void *ptr);
+static struct notifier_block dhd_inet6addr_notifier = {
+ .notifier_call = dhd_inet6addr_notifier_call
+};
+/* to make sure we won't register the same notifier twice, otherwise a loop is likely to be
+ * created in kernel notifier link list (with 'next' pointing to itself)
+ */
+static bool dhd_inet6addr_notifier_registered = FALSE;
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP)
+#include <linux/suspend.h>
+volatile bool dhd_mmc_suspend = FALSE;
+DECLARE_WAIT_QUEUE_HEAD(dhd_dpc_wait);
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */
+
+#if defined(OOB_INTR_ONLY) || defined(FORCE_WOWLAN)
+extern void dhd_enable_oob_intr(struct dhd_bus *bus, bool enable);
+#endif
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (1)
+static void dhd_hang_process(void *dhd_info, void *event_data, u8 event);
+#endif
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
+MODULE_LICENSE("GPL v2");
+#endif /* LinuxVer */
+
+#include <dhd_bus.h>
+
+#ifdef BCM_FD_AGGR
+#define DBUS_RX_BUFFER_SIZE_DHD(net) (BCM_RPC_TP_DNGL_AGG_MAX_BYTE)
+#else
+#ifndef PROP_TXSTATUS
+#define DBUS_RX_BUFFER_SIZE_DHD(net) (net->mtu + net->hard_header_len + dhd->pub.hdrlen)
+#else
+#define DBUS_RX_BUFFER_SIZE_DHD(net) (net->mtu + net->hard_header_len + dhd->pub.hdrlen + 128)
+#endif
+#endif /* BCM_FD_AGGR */
+
+#ifdef PROP_TXSTATUS
+extern bool dhd_wlfc_skip_fc(void);
+extern void dhd_wlfc_plat_init(void *dhd);
+extern void dhd_wlfc_plat_deinit(void *dhd);
+#endif /* PROP_TXSTATUS */
+
+#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15)
+const char *
+print_tainted()
+{
+ return "";
+}
+#endif /* LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15) */
+
+/* Linux wireless extension support */
+#if defined(WL_WIRELESS_EXT)
+#include <wl_iw.h>
+extern wl_iw_extra_params_t g_wl_iw_params;
+#endif /* defined(WL_WIRELESS_EXT) */
+
+#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
+#include <linux/earlysuspend.h>
+#endif /* defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) */
+
+extern int dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd);
+
+#ifdef PKT_FILTER_SUPPORT
+extern void dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg);
+extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode);
+extern void dhd_pktfilter_offload_delete(dhd_pub_t *dhd, int id);
+#endif
+
+
+#ifdef READ_MACADDR
+extern int dhd_read_macaddr(struct dhd_info *dhd);
+#else
+static inline int dhd_read_macaddr(struct dhd_info *dhd) { return 0; }
+#endif
+#ifdef WRITE_MACADDR
+extern int dhd_write_macaddr(struct ether_addr *mac);
+#else
+static inline int dhd_write_macaddr(struct ether_addr *mac) { return 0; }
+#endif
+
+
+#if defined(SOFTAP_TPUT_ENHANCE)
+extern void dhd_bus_setidletime(dhd_pub_t *dhdp, int idle_time);
+extern void dhd_bus_getidletime(dhd_pub_t *dhdp, int* idle_time);
+#endif /* SOFTAP_TPUT_ENHANCE */
+
+
+#ifdef SET_RPS_CPUS
+int custom_rps_map_set(struct netdev_rx_queue *queue, char *buf, size_t len);
+void custom_rps_map_clear(struct netdev_rx_queue *queue);
+#ifdef CONFIG_MACH_UNIVERSAL5433
+#define RPS_CPUS_MASK "10"
+#else
+#define RPS_CPUS_MASK "6"
+#endif /* CONFIG_MACH_UNIVERSAL5433 */
+#endif /* SET_RPS_CPUS */
+
+static int dhd_reboot_callback(struct notifier_block *this, unsigned long code, void *unused);
+static struct notifier_block dhd_reboot_notifier = {
+ .notifier_call = dhd_reboot_callback,
+ .priority = 1,
+};
+
+
+typedef struct dhd_if_event {
+ struct list_head list;
+ wl_event_data_if_t event;
+ char name[IFNAMSIZ+1];
+ uint8 mac[ETHER_ADDR_LEN];
+} dhd_if_event_t;
+
+/* Interface control information */
+typedef struct dhd_if {
+ struct dhd_info *info; /* back pointer to dhd_info */
+ /* OS/stack specifics */
+ struct net_device *net;
+ int idx; /* iface idx in dongle */
+ uint subunit; /* subunit */
+ uint8 mac_addr[ETHER_ADDR_LEN]; /* assigned MAC address */
+ bool set_macaddress;
+ bool set_multicast;
+ uint8 bssidx; /* bsscfg index for the interface */
+ bool attached; /* Delayed attachment when unset */
+ bool txflowcontrol; /* Per interface flow control indicator */
+ char name[IFNAMSIZ+1]; /* linux interface name */
+ struct net_device_stats stats;
+#ifdef DHD_WMF
+ dhd_wmf_t wmf; /* per bsscfg wmf setting */
+#endif /* DHD_WMF */
+#ifdef PCIE_FULL_DONGLE
+ struct list_head sta_list; /* sll of associated stations */
+#if !defined(BCM_GMAC3)
+ spinlock_t sta_list_lock; /* lock for manipulating sll */
+#endif /* ! BCM_GMAC3 */
+#endif /* PCIE_FULL_DONGLE */
+ uint32 ap_isolate; /* ap-isolation settings */
+} dhd_if_t;
+
+#ifdef WLMEDIA_HTSF
+typedef struct {
+ uint32 low;
+ uint32 high;
+} tsf_t;
+
+typedef struct {
+ uint32 last_cycle;
+ uint32 last_sec;
+ uint32 last_tsf;
+ uint32 coef; /* scaling factor */
+ uint32 coefdec1; /* first decimal */
+ uint32 coefdec2; /* second decimal */
+} htsf_t;
+
+typedef struct {
+ uint32 t1;
+ uint32 t2;
+ uint32 t3;
+ uint32 t4;
+} tstamp_t;
+
+static tstamp_t ts[TSMAX];
+static tstamp_t maxdelayts;
+static uint32 maxdelay = 0, tspktcnt = 0, maxdelaypktno = 0;
+
+#endif /* WLMEDIA_HTSF */
+
+struct ipv6_work_info_t {
+ uint8 if_idx;
+ char ipv6_addr[16];
+ unsigned long event;
+};
+
+#if defined(CUSTOMER_HW20) && defined(WLANAUDIO)
+#define MAX_WLANAUDIO_BLACKLIST 4
+
+struct wlanaudio_blacklist {
+ bool is_blacklist;
+ uint32 cnt;
+ ulong txfail_jiffies;
+ struct ether_addr blacklist_addr;
+};
+#endif /* CUSTOMER_HW20 && WLANAUDIO */
+
+/* When Perimeter locks are deployed, any blocking calls must be preceeded
+ * with a PERIM UNLOCK and followed by a PERIM LOCK.
+ * Examples of blocking calls are: schedule_timeout(), down_interruptible(),
+ * wait_event_timeout().
+ */
+
+/* Local private structure (extension of pub) */
+typedef struct dhd_info {
+#if defined(WL_WIRELESS_EXT)
+ wl_iw_t iw; /* wireless extensions state (must be first) */
+#endif /* defined(WL_WIRELESS_EXT) */
+ dhd_pub_t pub;
+ dhd_if_t *iflist[DHD_MAX_IFS]; /* for supporting multiple interfaces */
+
+ void *adapter; /* adapter information, interrupt, fw path etc. */
+ char fw_path[PATH_MAX]; /* path to firmware image */
+ char nv_path[PATH_MAX]; /* path to nvram vars file */
+ char conf_path[PATH_MAX]; /* path to config vars file */
+
+ struct semaphore proto_sem;
+#ifdef PROP_TXSTATUS
+ spinlock_t wlfc_spinlock;
+
+#endif /* PROP_TXSTATUS */
+#ifdef WLMEDIA_HTSF
+ htsf_t htsf;
+#endif
+ wait_queue_head_t ioctl_resp_wait;
+ uint32 default_wd_interval;
+
+ struct timer_list timer;
+ bool wd_timer_valid;
+ struct tasklet_struct tasklet;
+ spinlock_t sdlock;
+ spinlock_t txqlock;
+ spinlock_t dhd_lock;
+
+ struct semaphore sdsem;
+ tsk_ctl_t thr_dpc_ctl;
+ tsk_ctl_t thr_wdt_ctl;
+
+ tsk_ctl_t thr_rxf_ctl;
+ spinlock_t rxf_lock;
+ bool rxthread_enabled;
+
+ /* Wakelocks */
+#if defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
+ struct wake_lock wl_wifi; /* Wifi wakelock */
+ struct wake_lock wl_rxwake; /* Wifi rx wakelock */
+ struct wake_lock wl_ctrlwake; /* Wifi ctrl wakelock */
+ struct wake_lock wl_wdwake; /* Wifi wd wakelock */
+#ifdef BCMPCIE_OOB_HOST_WAKE
+ struct wake_lock wl_intrwake; /* Host wakeup wakelock */
+#endif /* BCMPCIE_OOB_HOST_WAKE */
+#endif /* CONFIG_HAS_WAKELOCK && LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) */
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1
+ /* net_device interface lock, prevent race conditions among net_dev interface
+ * calls and wifi_on or wifi_off
+ */
+ struct mutex dhd_net_if_mutex;
+ struct mutex dhd_suspend_mutex;
+#endif
+ spinlock_t wakelock_spinlock;
+ uint32 wakelock_counter;
+ int wakelock_wd_counter;
+ int wakelock_rx_timeout_enable;
+ int wakelock_ctrl_timeout_enable;
+ bool waive_wakelock;
+ uint32 wakelock_before_waive;
+
+ /* Thread to issue ioctl for multicast */
+ wait_queue_head_t ctrl_wait;
+ atomic_t pend_8021x_cnt;
+ dhd_attach_states_t dhd_state;
+#ifdef SHOW_LOGTRACE
+ dhd_event_log_t event_data;
+#endif /* SHOW_LOGTRACE */
+
+#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
+ struct early_suspend early_suspend;
+#endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */
+
+#ifdef ARP_OFFLOAD_SUPPORT
+ u32 pend_ipaddr;
+#endif /* ARP_OFFLOAD_SUPPORT */
+#ifdef BCM_FD_AGGR
+ void *rpc_th;
+ void *rpc_osh;
+ struct timer_list rpcth_timer;
+ bool rpcth_timer_active;
+ bool fdaggr;
+#endif
+#ifdef DHDTCPACK_SUPPRESS
+ spinlock_t tcpack_lock;
+#endif /* DHDTCPACK_SUPPRESS */
+ void *dhd_deferred_wq;
+#ifdef DEBUG_CPU_FREQ
+ struct notifier_block freq_trans;
+ int __percpu *new_freq;
+#endif
+ unsigned int unit;
+ struct notifier_block pm_notifier;
+#if defined(CUSTOMER_HW20) && defined(WLANAUDIO)
+ struct wlanaudio_blacklist wlanaudio_blist[MAX_WLANAUDIO_BLACKLIST];
+ bool is_wlanaudio_blist;
+#endif /* CUSTOMER_HW20 && WLANAUDIO */
+} dhd_info_t;
+
+#define DHDIF_FWDER(dhdif) FALSE
+
+/* Flag to indicate if we should download firmware on driver load */
+uint dhd_download_fw_on_driverload = TRUE;
+
+/* Definitions to provide path to the firmware and nvram
+ * example nvram_path[MOD_PARAM_PATHLEN]="/projects/wlan/nvram.txt"
+ */
+char firmware_path[MOD_PARAM_PATHLEN];
+char nvram_path[MOD_PARAM_PATHLEN];
+char config_path[MOD_PARAM_PATHLEN];
+
+/* backup buffer for firmware and nvram path */
+char fw_bak_path[MOD_PARAM_PATHLEN];
+char nv_bak_path[MOD_PARAM_PATHLEN];
+
+/* information string to keep firmware, chio, cheip version info visiable from log */
+char info_string[MOD_PARAM_INFOLEN];
+module_param_string(info_string, info_string, MOD_PARAM_INFOLEN, 0444);
+int op_mode = 0;
+int disable_proptx = 0;
+module_param(op_mode, int, 0644);
+extern int wl_control_wl_start(struct net_device *dev);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(BCMLXSDMMC)
+struct semaphore dhd_registration_sem;
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
+
+/* deferred handlers */
+static void dhd_ifadd_event_handler(void *handle, void *event_info, u8 event);
+static void dhd_ifdel_event_handler(void *handle, void *event_info, u8 event);
+static void dhd_set_mac_addr_handler(void *handle, void *event_info, u8 event);
+static void dhd_set_mcast_list_handler(void *handle, void *event_info, u8 event);
+#ifdef CONFIG_IPV6
+static void dhd_inet6_work_handler(void *dhd_info, void *event_data, u8 event);
+#endif
+
+#ifdef WL_CFG80211
+extern void dhd_netdev_free(struct net_device *ndev);
+#endif /* WL_CFG80211 */
+
+/* Error bits */
+module_param(dhd_msg_level, int, 0);
+#if defined(WL_WIRELESS_EXT)
+module_param(iw_msg_level, int, 0);
+#endif
+#ifdef WL_CFG80211
+module_param(wl_dbg_level, int, 0);
+#endif
+module_param(android_msg_level, int, 0);
+module_param(config_msg_level, int, 0);
+
+#ifdef ARP_OFFLOAD_SUPPORT
+/* ARP offload enable */
+uint dhd_arp_enable = TRUE;
+module_param(dhd_arp_enable, uint, 0);
+
+/* ARP offload agent mode : Enable ARP Host Auto-Reply and ARP Peer Auto-Reply */
+
+uint dhd_arp_mode = ARP_OL_AGENT | ARP_OL_PEER_AUTO_REPLY;
+
+module_param(dhd_arp_mode, uint, 0);
+#endif /* ARP_OFFLOAD_SUPPORT */
+
+/* Disable Prop tx */
+module_param(disable_proptx, int, 0644);
+/* load firmware and/or nvram values from the filesystem */
+module_param_string(firmware_path, firmware_path, MOD_PARAM_PATHLEN, 0660);
+module_param_string(nvram_path, nvram_path, MOD_PARAM_PATHLEN, 0660);
+module_param_string(config_path, config_path, MOD_PARAM_PATHLEN, 0);
+
+/* Watchdog interval */
+
+/* extend watchdog expiration to 2 seconds when DPC is running */
+#define WATCHDOG_EXTEND_INTERVAL (2000)
+
+uint dhd_watchdog_ms = CUSTOM_DHD_WATCHDOG_MS;
+module_param(dhd_watchdog_ms, uint, 0);
+
+#if defined(DHD_DEBUG)
+/* Console poll interval */
+uint dhd_console_ms = 0;
+module_param(dhd_console_ms, uint, 0644);
+#endif /* defined(DHD_DEBUG) */
+
+
+uint dhd_slpauto = TRUE;
+module_param(dhd_slpauto, uint, 0);
+
+#ifdef PKT_FILTER_SUPPORT
+/* Global Pkt filter enable control */
+uint dhd_pkt_filter_enable = TRUE;
+module_param(dhd_pkt_filter_enable, uint, 0);
+#endif
+
+/* Pkt filter init setup */
+uint dhd_pkt_filter_init = 0;
+module_param(dhd_pkt_filter_init, uint, 0);
+
+/* Pkt filter mode control */
+uint dhd_master_mode = FALSE;
+module_param(dhd_master_mode, uint, 0);
+
+int dhd_watchdog_prio = 0;
+module_param(dhd_watchdog_prio, int, 0);
+
+/* DPC thread priority */
+int dhd_dpc_prio = CUSTOM_DPC_PRIO_SETTING;
+module_param(dhd_dpc_prio, int, 0);
+
+/* RX frame thread priority */
+int dhd_rxf_prio = CUSTOM_RXF_PRIO_SETTING;
+module_param(dhd_rxf_prio, int, 0);
+
+int passive_channel_skip = 0;
+module_param(passive_channel_skip, int, (S_IRUSR|S_IWUSR));
+
+#if !defined(BCMDHDUSB)
+extern int dhd_dongle_ramsize;
+module_param(dhd_dongle_ramsize, int, 0);
+#endif /* BCMDHDUSB */
+
+/* Keep track of number of instances */
+static int dhd_found = 0;
+static int instance_base = 0; /* Starting instance number */
+module_param(instance_base, int, 0644);
+
+#if defined(CUSTOMER_HW20) && defined(WLANAUDIO)
+dhd_info_t *dhd_global = NULL;
+#endif /* CUSTOMER_HW20 && WLANAUDIO */
+
+
+
+/* DHD Perimiter lock only used in router with bypass forwarding. */
+#define DHD_PERIM_RADIO_INIT() do { /* noop */ } while (0)
+#define DHD_PERIM_LOCK_TRY(unit, flag) do { /* noop */ } while (0)
+#define DHD_PERIM_UNLOCK_TRY(unit, flag) do { /* noop */ } while (0)
+#define DHD_PERIM_LOCK_ALL() do { /* noop */ } while (0)
+#define DHD_PERIM_UNLOCK_ALL() do { /* noop */ } while (0)
+
+#ifdef PCIE_FULL_DONGLE
+#if defined(BCM_GMAC3)
+#define DHD_IF_STA_LIST_LOCK_INIT(ifp) do { /* noop */ } while (0)
+#define DHD_IF_STA_LIST_LOCK(ifp, flags) ({ BCM_REFERENCE(flags); })
+#define DHD_IF_STA_LIST_UNLOCK(ifp, flags) ({ BCM_REFERENCE(flags); })
+#else /* ! BCM_GMAC3 */
+#define DHD_IF_STA_LIST_LOCK_INIT(ifp) spin_lock_init(&(ifp)->sta_list_lock)
+#define DHD_IF_STA_LIST_LOCK(ifp, flags) \
+ spin_lock_irqsave(&(ifp)->sta_list_lock, (flags))
+#define DHD_IF_STA_LIST_UNLOCK(ifp, flags) \
+ spin_unlock_irqrestore(&(ifp)->sta_list_lock, (flags))
+#endif /* ! BCM_GMAC3 */
+#endif /* PCIE_FULL_DONGLE */
+
+/* Control fw roaming */
+#ifdef BCMCCX
+uint dhd_roam_disable = 0;
+#else
+uint dhd_roam_disable = 0;
+#endif /* BCMCCX */
+
+/* Control radio state */
+uint dhd_radio_up = 1;
+
+/* Network inteface name */
+char iface_name[IFNAMSIZ] = {'\0'};
+module_param_string(iface_name, iface_name, IFNAMSIZ, 0);
+
+/* The following are specific to the SDIO dongle */
+
+/* IOCTL response timeout */
+int dhd_ioctl_timeout_msec = IOCTL_RESP_TIMEOUT;
+
+/* Idle timeout for backplane clock */
+int dhd_idletime = DHD_IDLETIME_TICKS;
+module_param(dhd_idletime, int, 0);
+
+/* Use polling */
+uint dhd_poll = FALSE;
+module_param(dhd_poll, uint, 0);
+
+/* Use interrupts */
+uint dhd_intr = TRUE;
+module_param(dhd_intr, uint, 0);
+
+/* SDIO Drive Strength (in milliamps) */
+uint dhd_sdiod_drive_strength = 6;
+module_param(dhd_sdiod_drive_strength, uint, 0);
+
+#ifdef BCMSDIO
+/* Tx/Rx bounds */
+extern uint dhd_txbound;
+extern uint dhd_rxbound;
+module_param(dhd_txbound, uint, 0);
+module_param(dhd_rxbound, uint, 0);
+
+/* Deferred transmits */
+extern uint dhd_deferred_tx;
+module_param(dhd_deferred_tx, uint, 0);
+
+#ifdef BCMDBGFS
+extern void dhd_dbg_init(dhd_pub_t *dhdp);
+extern void dhd_dbg_remove(void);
+#endif /* BCMDBGFS */
+
+#endif /* BCMSDIO */
+
+
+#ifdef SDTEST
+/* Echo packet generator (pkts/s) */
+uint dhd_pktgen = 0;
+module_param(dhd_pktgen, uint, 0);
+
+/* Echo packet len (0 => sawtooth, max 2040) */
+uint dhd_pktgen_len = 0;
+module_param(dhd_pktgen_len, uint, 0);
+#endif /* SDTEST */
+
+#if defined(BCMSUP_4WAY_HANDSHAKE)
+/* Use in dongle supplicant for 4-way handshake */
+uint dhd_use_idsup = 0;
+module_param(dhd_use_idsup, uint, 0);
+#endif /* BCMSUP_4WAY_HANDSHAKE */
+
+extern char dhd_version[];
+
+int dhd_net_bus_devreset(struct net_device *dev, uint8 flag);
+static void dhd_net_if_lock_local(dhd_info_t *dhd);
+static void dhd_net_if_unlock_local(dhd_info_t *dhd);
+static void dhd_suspend_lock(dhd_pub_t *dhdp);
+static void dhd_suspend_unlock(dhd_pub_t *dhdp);
+
+#ifdef WLMEDIA_HTSF
+void htsf_update(dhd_info_t *dhd, void *data);
+tsf_t prev_tsf, cur_tsf;
+
+uint32 dhd_get_htsf(dhd_info_t *dhd, int ifidx);
+static int dhd_ioctl_htsf_get(dhd_info_t *dhd, int ifidx);
+static void dhd_dump_latency(void);
+static void dhd_htsf_addtxts(dhd_pub_t *dhdp, void *pktbuf);
+static void dhd_htsf_addrxts(dhd_pub_t *dhdp, void *pktbuf);
+static void dhd_dump_htsfhisto(histo_t *his, char *s);
+#endif /* WLMEDIA_HTSF */
+
+/* Monitor interface */
+int dhd_monitor_init(void *dhd_pub);
+int dhd_monitor_uninit(void);
+
+
+#if defined(WL_WIRELESS_EXT)
+struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev);
+#endif /* defined(WL_WIRELESS_EXT) */
+
+static void dhd_dpc(ulong data);
+/* forward decl */
+extern int dhd_wait_pend8021x(struct net_device *dev);
+void dhd_os_wd_timer_extend(void *bus, bool extend);
+
+#ifdef TOE
+#ifndef BDC
+#error TOE requires BDC
+#endif /* !BDC */
+static int dhd_toe_get(dhd_info_t *dhd, int idx, uint32 *toe_ol);
+static int dhd_toe_set(dhd_info_t *dhd, int idx, uint32 toe_ol);
+#endif /* TOE */
+
+static int dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata,
+ wl_event_msg_t *event_ptr, void **data_ptr);
+#ifdef DHD_UNICAST_DHCP
+static const uint8 llc_snap_hdr[SNAP_HDR_LEN] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
+static int dhd_get_pkt_ip_type(dhd_pub_t *dhd, void *skb, uint8 **data_ptr,
+ int *len_ptr, uint8 *prot_ptr);
+static int dhd_get_pkt_ether_type(dhd_pub_t *dhd, void *skb, uint8 **data_ptr,
+ int *len_ptr, uint16 *et_ptr, bool *snap_ptr);
+
+static int dhd_convert_dhcp_broadcast_ack_to_unicast(dhd_pub_t *pub, void *pktbuf, int ifidx);
+#endif /* DHD_UNICAST_DHCP */
+#ifdef DHD_L2_FILTER
+static int dhd_l2_filter_block_ping(dhd_pub_t *pub, void *pktbuf, int ifidx);
+#endif
+#if defined(CONFIG_PM_SLEEP)
+static int dhd_pm_callback(struct notifier_block *nfb, unsigned long action, void *ignored)
+{
+ int ret = NOTIFY_DONE;
+ bool suspend = FALSE;
+ dhd_info_t *dhdinfo = (dhd_info_t*)container_of(nfb, struct dhd_info, pm_notifier);
+
+ BCM_REFERENCE(dhdinfo);
+ switch (action) {
+ case PM_HIBERNATION_PREPARE:
+ case PM_SUSPEND_PREPARE:
+ suspend = TRUE;
+ break;
+ case PM_POST_HIBERNATION:
+ case PM_POST_SUSPEND:
+ suspend = FALSE;
+ break;
+ }
+
+#if defined(SUPPORT_P2P_GO_PS)
+#ifdef PROP_TXSTATUS
+ if (suspend) {
+ DHD_OS_WAKE_LOCK_WAIVE(&dhdinfo->pub);
+ dhd_wlfc_suspend(&dhdinfo->pub);
+ DHD_OS_WAKE_LOCK_RESTORE(&dhdinfo->pub);
+ } else
+ dhd_wlfc_resume(&dhdinfo->pub);
+#endif
+#endif /* defined(SUPPORT_P2P_GO_PS) */
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (LINUX_VERSION_CODE <= \
+ KERNEL_VERSION(2, 6, 39))
+ dhd_mmc_suspend = suspend;
+ smp_mb();
+#endif
+
+ return ret;
+}
+
+static struct notifier_block dhd_pm_notifier = {
+ .notifier_call = dhd_pm_callback,
+ .priority = 10
+};
+/* to make sure we won't register the same notifier twice, otherwise a loop is likely to be
+ * created in kernel notifier link list (with 'next' pointing to itself)
+ */
+static bool dhd_pm_notifier_registered = FALSE;
+
+extern int register_pm_notifier(struct notifier_block *nb);
+extern int unregister_pm_notifier(struct notifier_block *nb);
+#endif /* CONFIG_PM_SLEEP */
+
+/* Request scheduling of the bus rx frame */
+static void dhd_sched_rxf(dhd_pub_t *dhdp, void *skb);
+static void dhd_os_rxflock(dhd_pub_t *pub);
+static void dhd_os_rxfunlock(dhd_pub_t *pub);
+
+/** priv_link is the link between netdev and the dhdif and dhd_info structs. */
+typedef struct dhd_dev_priv {
+ dhd_info_t * dhd; /* cached pointer to dhd_info in netdevice priv */
+ dhd_if_t * ifp; /* cached pointer to dhd_if in netdevice priv */
+ int ifidx; /* interface index */
+} dhd_dev_priv_t;
+
+#define DHD_DEV_PRIV_SIZE (sizeof(dhd_dev_priv_t))
+#define DHD_DEV_PRIV(dev) ((dhd_dev_priv_t *)DEV_PRIV(dev))
+#define DHD_DEV_INFO(dev) (((dhd_dev_priv_t *)DEV_PRIV(dev))->dhd)
+#define DHD_DEV_IFP(dev) (((dhd_dev_priv_t *)DEV_PRIV(dev))->ifp)
+#define DHD_DEV_IFIDX(dev) (((dhd_dev_priv_t *)DEV_PRIV(dev))->ifidx)
+
+/** Clear the dhd net_device's private structure. */
+static inline void
+dhd_dev_priv_clear(struct net_device * dev)
+{
+ dhd_dev_priv_t * dev_priv;
+ ASSERT(dev != (struct net_device *)NULL);
+ dev_priv = DHD_DEV_PRIV(dev);
+ dev_priv->dhd = (dhd_info_t *)NULL;
+ dev_priv->ifp = (dhd_if_t *)NULL;
+ dev_priv->ifidx = DHD_BAD_IF;
+}
+
+/** Setup the dhd net_device's private structure. */
+static inline void
+dhd_dev_priv_save(struct net_device * dev, dhd_info_t * dhd, dhd_if_t * ifp,
+ int ifidx)
+{
+ dhd_dev_priv_t * dev_priv;
+ ASSERT(dev != (struct net_device *)NULL);
+ dev_priv = DHD_DEV_PRIV(dev);
+ dev_priv->dhd = dhd;
+ dev_priv->ifp = ifp;
+ dev_priv->ifidx = ifidx;
+}
+
+#ifdef PCIE_FULL_DONGLE
+
+/** Dummy objects are defined with state representing bad|down.
+ * Performance gains from reducing branch conditionals, instruction parallelism,
+ * dual issue, reducing load shadows, avail of larger pipelines.
+ * Use DHD_XXX_NULL instead of (dhd_xxx_t *)NULL, whenever an object pointer
+ * is accessed via the dhd_sta_t.
+ */
+
+/* Dummy dhd_info object */
+dhd_info_t dhd_info_null = {
+#if defined(BCM_GMAC3)
+ .fwdh = FWDER_NULL,
+#endif
+ .pub = {
+ .info = &dhd_info_null,
+#ifdef DHDTCPACK_SUPPRESS
+ .tcpack_sup_mode = TCPACK_SUP_REPLACE,
+#endif /* DHDTCPACK_SUPPRESS */
+ .up = FALSE, .busstate = DHD_BUS_DOWN
+ }
+};
+#define DHD_INFO_NULL (&dhd_info_null)
+#define DHD_PUB_NULL (&dhd_info_null.pub)
+
+/* Dummy netdevice object */
+struct net_device dhd_net_dev_null = {
+ .reg_state = NETREG_UNREGISTERED
+};
+#define DHD_NET_DEV_NULL (&dhd_net_dev_null)
+
+/* Dummy dhd_if object */
+dhd_if_t dhd_if_null = {
+#if defined(BCM_GMAC3)
+ .fwdh = FWDER_NULL,
+#endif
+#ifdef WMF
+ .wmf = { .wmf_enable = TRUE },
+#endif
+ .info = DHD_INFO_NULL,
+ .net = DHD_NET_DEV_NULL,
+ .idx = DHD_BAD_IF
+};
+#define DHD_IF_NULL (&dhd_if_null)
+
+#define DHD_STA_NULL ((dhd_sta_t *)NULL)
+
+/** Interface STA list management. */
+
+/** Fetch the dhd_if object, given the interface index in the dhd. */
+static inline dhd_if_t *dhd_get_ifp(dhd_pub_t *dhdp, uint32 ifidx);
+
+/** Alloc/Free a dhd_sta object from the dhd instances' sta_pool. */
+static void dhd_sta_free(dhd_pub_t *pub, dhd_sta_t *sta);
+static dhd_sta_t * dhd_sta_alloc(dhd_pub_t * dhdp);
+
+/* Delete a dhd_sta or flush all dhd_sta in an interface's sta_list. */
+static void dhd_if_del_sta_list(dhd_if_t * ifp);
+static void dhd_if_flush_sta(dhd_if_t * ifp);
+
+/* Construct/Destruct a sta pool. */
+static int dhd_sta_pool_init(dhd_pub_t *dhdp, int max_sta);
+static void dhd_sta_pool_fini(dhd_pub_t *dhdp, int max_sta);
+static void dhd_sta_pool_clear(dhd_pub_t *dhdp, int max_sta);
+
+
+/* Return interface pointer */
+static inline dhd_if_t *dhd_get_ifp(dhd_pub_t *dhdp, uint32 ifidx)
+{
+ ASSERT(ifidx < DHD_MAX_IFS);
+
+ if (ifidx >= DHD_MAX_IFS)
+ return NULL;
+
+ return dhdp->info->iflist[ifidx];
+}
+
+/** Reset a dhd_sta object and free into the dhd pool. */
+static void
+dhd_sta_free(dhd_pub_t * dhdp, dhd_sta_t * sta)
+{
+ int prio;
+
+ ASSERT((sta != DHD_STA_NULL) && (sta->idx != ID16_INVALID));
+
+ ASSERT((dhdp->staid_allocator != NULL) && (dhdp->sta_pool != NULL));
+ id16_map_free(dhdp->staid_allocator, sta->idx);
+ for (prio = 0; prio < (int)NUMPRIO; prio++)
+ sta->flowid[prio] = FLOWID_INVALID;
+ sta->ifp = DHD_IF_NULL; /* dummy dhd_if object */
+ sta->ifidx = DHD_BAD_IF;
+ bzero(sta->ea.octet, ETHER_ADDR_LEN);
+ INIT_LIST_HEAD(&sta->list);
+ sta->idx = ID16_INVALID; /* implying free */
+}
+
+/** Allocate a dhd_sta object from the dhd pool. */
+static dhd_sta_t *
+dhd_sta_alloc(dhd_pub_t * dhdp)
+{
+ uint16 idx;
+ dhd_sta_t * sta;
+ dhd_sta_pool_t * sta_pool;
+
+ ASSERT((dhdp->staid_allocator != NULL) && (dhdp->sta_pool != NULL));
+
+ idx = id16_map_alloc(dhdp->staid_allocator);
+ if (idx == ID16_INVALID) {
+ DHD_ERROR(("%s: cannot get free staid\n", __FUNCTION__));
+ return DHD_STA_NULL;
+ }
+
+ sta_pool = (dhd_sta_pool_t *)(dhdp->sta_pool);
+ sta = &sta_pool[idx];
+
+ ASSERT((sta->idx == ID16_INVALID) &&
+ (sta->ifp == DHD_IF_NULL) && (sta->ifidx == DHD_BAD_IF));
+ sta->idx = idx; /* implying allocated */
+
+ return sta;
+}
+
+/** Delete all STAs in an interface's STA list. */
+static void
+dhd_if_del_sta_list(dhd_if_t *ifp)
+{
+ dhd_sta_t *sta, *next;
+ unsigned long flags;
+
+ DHD_IF_STA_LIST_LOCK(ifp, flags);
+
+ list_for_each_entry_safe(sta, next, &ifp->sta_list, list) {
+#if defined(BCM_GMAC3)
+ if (ifp->fwdh) {
+ /* Remove sta from WOFA forwarder. */
+ fwder_deassoc(ifp->fwdh, (uint16 *)(sta->ea.octet), (wofa_t)sta);
+ }
+#endif /* BCM_GMAC3 */
+ list_del(&sta->list);
+ dhd_sta_free(&ifp->info->pub, sta);
+ }
+
+ DHD_IF_STA_LIST_UNLOCK(ifp, flags);
+
+ return;
+}
+
+/** Router/GMAC3: Flush all station entries in the forwarder's WOFA database. */
+static void
+dhd_if_flush_sta(dhd_if_t * ifp)
+{
+#if defined(BCM_GMAC3)
+
+ if (ifp && (ifp->fwdh != FWDER_NULL)) {
+ dhd_sta_t *sta, *next;
+ unsigned long flags;
+
+ DHD_IF_STA_LIST_LOCK(ifp, flags);
+
+ list_for_each_entry_safe(sta, next, &ifp->sta_list, list) {
+ /* Remove any sta entry from WOFA forwarder. */
+ fwder_flush(ifp->fwdh, (wofa_t)sta);
+ }
+
+ DHD_IF_STA_LIST_UNLOCK(ifp, flags);
+ }
+#endif /* BCM_GMAC3 */
+}
+
+/** Construct a pool of dhd_sta_t objects to be used by interfaces. */
+static int
+dhd_sta_pool_init(dhd_pub_t *dhdp, int max_sta)
+{
+ int idx, sta_pool_memsz;
+ dhd_sta_t * sta;
+ dhd_sta_pool_t * sta_pool;
+ void * staid_allocator;
+
+ ASSERT(dhdp != (dhd_pub_t *)NULL);
+ ASSERT((dhdp->staid_allocator == NULL) && (dhdp->sta_pool == NULL));
+
+ /* dhd_sta objects per radio are managed in a table. id#0 reserved. */
+ staid_allocator = id16_map_init(dhdp->osh, max_sta, 1);
+ if (staid_allocator == NULL) {
+ DHD_ERROR(("%s: sta id allocator init failure\n", __FUNCTION__));
+ return BCME_ERROR;
+ }
+
+ /* Pre allocate a pool of dhd_sta objects (one extra). */
+ sta_pool_memsz = ((max_sta + 1) * sizeof(dhd_sta_t)); /* skip idx 0 */
+ sta_pool = (dhd_sta_pool_t *)MALLOC(dhdp->osh, sta_pool_memsz);
+ if (sta_pool == NULL) {
+ DHD_ERROR(("%s: sta table alloc failure\n", __FUNCTION__));
+ id16_map_fini(dhdp->osh, staid_allocator);
+ return BCME_ERROR;
+ }
+
+ dhdp->sta_pool = sta_pool;
+ dhdp->staid_allocator = staid_allocator;
+
+ /* Initialize all sta(s) for the pre-allocated free pool. */
+ bzero((uchar *)sta_pool, sta_pool_memsz);
+ for (idx = max_sta; idx >= 1; idx--) { /* skip sta_pool[0] */
+ sta = &sta_pool[idx];
+ sta->idx = id16_map_alloc(staid_allocator);
+ ASSERT(sta->idx <= max_sta);
+ }
+ /* Now place them into the pre-allocated free pool. */
+ for (idx = 1; idx <= max_sta; idx++) {
+ sta = &sta_pool[idx];
+ dhd_sta_free(dhdp, sta);
+ }
+
+ return BCME_OK;
+}
+
+/** Destruct the pool of dhd_sta_t objects.
+ * Caller must ensure that no STA objects are currently associated with an if.
+ */
+static void
+dhd_sta_pool_fini(dhd_pub_t *dhdp, int max_sta)
+{
+ dhd_sta_pool_t * sta_pool = (dhd_sta_pool_t *)dhdp->sta_pool;
+
+ if (sta_pool) {
+ int idx;
+ int sta_pool_memsz = ((max_sta + 1) * sizeof(dhd_sta_t));
+ for (idx = 1; idx <= max_sta; idx++) {
+ ASSERT(sta_pool[idx].ifp == DHD_IF_NULL);
+ ASSERT(sta_pool[idx].idx == ID16_INVALID);
+ }
+ MFREE(dhdp->osh, dhdp->sta_pool, sta_pool_memsz);
+ dhdp->sta_pool = NULL;
+ }
+
+ id16_map_fini(dhdp->osh, dhdp->staid_allocator);
+ dhdp->staid_allocator = NULL;
+}
+
+/* Clear the pool of dhd_sta_t objects for built-in type driver */
+static void
+dhd_sta_pool_clear(dhd_pub_t *dhdp, int max_sta)
+{
+ int idx, sta_pool_memsz;
+ dhd_sta_t * sta;
+ dhd_sta_pool_t * sta_pool;
+ void *staid_allocator;
+
+ if (!dhdp) {
+ DHD_ERROR(("%s: dhdp is NULL\n", __FUNCTION__));
+ return;
+ }
+
+ sta_pool = (dhd_sta_pool_t *)dhdp->sta_pool;
+ staid_allocator = dhdp->staid_allocator;
+
+ if (!sta_pool) {
+ DHD_ERROR(("%s: sta_pool is NULL\n", __FUNCTION__));
+ return;
+ }
+
+ if (!staid_allocator) {
+ DHD_ERROR(("%s: staid_allocator is NULL\n", __FUNCTION__));
+ return;
+ }
+
+ /* clear free pool */
+ sta_pool_memsz = ((max_sta + 1) * sizeof(dhd_sta_t));
+ bzero((uchar *)sta_pool, sta_pool_memsz);
+
+ /* dhd_sta objects per radio are managed in a table. id#0 reserved. */
+ id16_map_clear(staid_allocator, max_sta, 1);
+
+ /* Initialize all sta(s) for the pre-allocated free pool. */
+ for (idx = max_sta; idx >= 1; idx--) { /* skip sta_pool[0] */
+ sta = &sta_pool[idx];
+ sta->idx = id16_map_alloc(staid_allocator);
+ ASSERT(sta->idx <= max_sta);
+ }
+ /* Now place them into the pre-allocated free pool. */
+ for (idx = 1; idx <= max_sta; idx++) {
+ sta = &sta_pool[idx];
+ dhd_sta_free(dhdp, sta);
+ }
+}
+
+/** Find STA with MAC address ea in an interface's STA list. */
+dhd_sta_t *
+dhd_find_sta(void *pub, int ifidx, void *ea)
+{
+ dhd_sta_t *sta;
+ dhd_if_t *ifp;
+ unsigned long flags;
+
+ ASSERT(ea != NULL);
+ ifp = dhd_get_ifp((dhd_pub_t *)pub, ifidx);
+ if (ifp == NULL)
+ return DHD_STA_NULL;
+
+ DHD_IF_STA_LIST_LOCK(ifp, flags);
+
+ list_for_each_entry(sta, &ifp->sta_list, list) {
+ if (!memcmp(sta->ea.octet, ea, ETHER_ADDR_LEN)) {
+ DHD_IF_STA_LIST_UNLOCK(ifp, flags);
+ return sta;
+ }
+ }
+
+ DHD_IF_STA_LIST_UNLOCK(ifp, flags);
+
+ return DHD_STA_NULL;
+}
+
+/** Add STA into the interface's STA list. */
+dhd_sta_t *
+dhd_add_sta(void *pub, int ifidx, void *ea)
+{
+ dhd_sta_t *sta;
+ dhd_if_t *ifp;
+ unsigned long flags;
+
+ ASSERT(ea != NULL);
+ ifp = dhd_get_ifp((dhd_pub_t *)pub, ifidx);
+ if (ifp == NULL)
+ return DHD_STA_NULL;
+
+ sta = dhd_sta_alloc((dhd_pub_t *)pub);
+ if (sta == DHD_STA_NULL) {
+ DHD_ERROR(("%s: Alloc failed\n", __FUNCTION__));
+ return DHD_STA_NULL;
+ }
+
+ memcpy(sta->ea.octet, ea, ETHER_ADDR_LEN);
+
+ /* link the sta and the dhd interface */
+ sta->ifp = ifp;
+ sta->ifidx = ifidx;
+ INIT_LIST_HEAD(&sta->list);
+
+ DHD_IF_STA_LIST_LOCK(ifp, flags);
+
+ list_add_tail(&sta->list, &ifp->sta_list);
+
+#if defined(BCM_GMAC3)
+ if (ifp->fwdh) {
+ ASSERT(ISALIGNED(ea, 2));
+ /* Add sta to WOFA forwarder. */
+ fwder_reassoc(ifp->fwdh, (uint16 *)ea, (wofa_t)sta);
+ }
+#endif /* BCM_GMAC3 */
+
+ DHD_IF_STA_LIST_UNLOCK(ifp, flags);
+
+ return sta;
+}
+
+/** Delete STA from the interface's STA list. */
+void
+dhd_del_sta(void *pub, int ifidx, void *ea)
+{
+ dhd_sta_t *sta, *next;
+ dhd_if_t *ifp;
+ unsigned long flags;
+
+ ASSERT(ea != NULL);
+ ifp = dhd_get_ifp((dhd_pub_t *)pub, ifidx);
+ if (ifp == NULL)
+ return;
+
+ DHD_IF_STA_LIST_LOCK(ifp, flags);
+
+ list_for_each_entry_safe(sta, next, &ifp->sta_list, list) {
+ if (!memcmp(sta->ea.octet, ea, ETHER_ADDR_LEN)) {
+#if defined(BCM_GMAC3)
+ if (ifp->fwdh) { /* Found a sta, remove from WOFA forwarder. */
+ ASSERT(ISALIGNED(ea, 2));
+ fwder_deassoc(ifp->fwdh, (uint16 *)ea, (wofa_t)sta);
+ }
+#endif /* BCM_GMAC3 */
+ list_del(&sta->list);
+ dhd_sta_free(&ifp->info->pub, sta);
+ }
+ }
+
+ DHD_IF_STA_LIST_UNLOCK(ifp, flags);
+
+ return;
+}
+
+/** Add STA if it doesn't exist. Not reentrant. */
+dhd_sta_t*
+dhd_findadd_sta(void *pub, int ifidx, void *ea)
+{
+ dhd_sta_t *sta;
+
+ sta = dhd_find_sta(pub, ifidx, ea);
+
+ if (!sta) {
+ /* Add entry */
+ sta = dhd_add_sta(pub, ifidx, ea);
+ }
+
+ return sta;
+}
+#else
+static inline void dhd_if_flush_sta(dhd_if_t * ifp) { }
+static inline void dhd_if_del_sta_list(dhd_if_t *ifp) {}
+static inline int dhd_sta_pool_init(dhd_pub_t *dhdp, int max_sta) { return BCME_OK; }
+static inline void dhd_sta_pool_fini(dhd_pub_t *dhdp, int max_sta) {}
+static inline void dhd_sta_pool_clear(dhd_pub_t *dhdp, int max_sta) {}
+dhd_sta_t *dhd_findadd_sta(void *pub, int ifidx, void *ea) { return NULL; }
+void dhd_del_sta(void *pub, int ifidx, void *ea) {}
+#endif /* PCIE_FULL_DONGLE */
+
+
+/* Returns dhd iflist index correspondig the the bssidx provided by apps */
+int dhd_bssidx2idx(dhd_pub_t *dhdp, uint32 bssidx)
+{
+ dhd_if_t *ifp;
+ dhd_info_t *dhd = dhdp->info;
+ int i;
+
+ ASSERT(bssidx < DHD_MAX_IFS);
+ ASSERT(dhdp);
+
+ for (i = 0; i < DHD_MAX_IFS; i++) {
+ ifp = dhd->iflist[i];
+ if (ifp && (ifp->bssidx == bssidx)) {
+ DHD_TRACE(("Index manipulated for %s from %d to %d\n",
+ ifp->name, bssidx, i));
+ break;
+ }
+ }
+ return i;
+}
+
+static inline int dhd_rxf_enqueue(dhd_pub_t *dhdp, void* skb)
+{
+ uint32 store_idx;
+ uint32 sent_idx;
+
+ if (!skb) {
+ DHD_ERROR(("dhd_rxf_enqueue: NULL skb!!!\n"));
+ return BCME_ERROR;
+ }
+
+ dhd_os_rxflock(dhdp);
+ store_idx = dhdp->store_idx;
+ sent_idx = dhdp->sent_idx;
+ if (dhdp->skbbuf[store_idx] != NULL) {
+ /* Make sure the previous packets are processed */
+ dhd_os_rxfunlock(dhdp);
+#ifdef RXF_DEQUEUE_ON_BUSY
+ DHD_TRACE(("dhd_rxf_enqueue: pktbuf not consumed %p, store idx %d sent idx %d\n",
+ skb, store_idx, sent_idx));
+ return BCME_BUSY;
+#else /* RXF_DEQUEUE_ON_BUSY */
+ DHD_ERROR(("dhd_rxf_enqueue: pktbuf not consumed %p, store idx %d sent idx %d\n",
+ skb, store_idx, sent_idx));
+ /* removed msleep here, should use wait_event_timeout if we
+ * want to give rx frame thread a chance to run
+ */
+#if defined(WAIT_DEQUEUE)
+ OSL_SLEEP(1);
+#endif
+ return BCME_ERROR;
+#endif /* RXF_DEQUEUE_ON_BUSY */
+ }
+ DHD_TRACE(("dhd_rxf_enqueue: Store SKB %p. idx %d -> %d\n",
+ skb, store_idx, (store_idx + 1) & (MAXSKBPEND - 1)));
+ dhdp->skbbuf[store_idx] = skb;
+ dhdp->store_idx = (store_idx + 1) & (MAXSKBPEND - 1);
+ dhd_os_rxfunlock(dhdp);
+
+ return BCME_OK;
+}
+
+static inline void* dhd_rxf_dequeue(dhd_pub_t *dhdp)
+{
+ uint32 store_idx;
+ uint32 sent_idx;
+ void *skb;
+
+ dhd_os_rxflock(dhdp);
+
+ store_idx = dhdp->store_idx;
+ sent_idx = dhdp->sent_idx;
+ skb = dhdp->skbbuf[sent_idx];
+
+ if (skb == NULL) {
+ dhd_os_rxfunlock(dhdp);
+ DHD_ERROR(("dhd_rxf_dequeue: Dequeued packet is NULL, store idx %d sent idx %d\n",
+ store_idx, sent_idx));
+ return NULL;
+ }
+
+ dhdp->skbbuf[sent_idx] = NULL;
+ dhdp->sent_idx = (sent_idx + 1) & (MAXSKBPEND - 1);
+
+ DHD_TRACE(("dhd_rxf_dequeue: netif_rx_ni(%p), sent idx %d\n",
+ skb, sent_idx));
+
+ dhd_os_rxfunlock(dhdp);
+
+ return skb;
+}
+
+int dhd_process_cid_mac(dhd_pub_t *dhdp, bool prepost)
+{
+#ifndef CUSTOMER_HW10
+ dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
+#endif /* !CUSTOMER_HW10 */
+
+ if (prepost) { /* pre process */
+ dhd_read_macaddr(dhd);
+ } else { /* post process */
+ dhd_write_macaddr(&dhd->pub.mac);
+ }
+
+ return 0;
+}
+
+#if defined(PKT_FILTER_SUPPORT) && !defined(GAN_LITE_NAT_KEEPALIVE_FILTER)
+static bool
+_turn_on_arp_filter(dhd_pub_t *dhd, int op_mode)
+{
+ bool _apply = FALSE;
+ /* In case of IBSS mode, apply arp pkt filter */
+ if (op_mode & DHD_FLAG_IBSS_MODE) {
+ _apply = TRUE;
+ goto exit;
+ }
+ /* In case of P2P GO or GC, apply pkt filter to pass arp pkt to host */
+ if ((dhd->arp_version == 1) &&
+ (op_mode & (DHD_FLAG_P2P_GC_MODE | DHD_FLAG_P2P_GO_MODE))) {
+ _apply = TRUE;
+ goto exit;
+ }
+
+exit:
+ return _apply;
+}
+#endif /* PKT_FILTER_SUPPORT && !GAN_LITE_NAT_KEEPALIVE_FILTER */
+
+#if defined(CUSTOM_PLATFORM_NV_TEGRA)
+#ifdef PKT_FILTER_SUPPORT
+void
+dhd_set_packet_filter_mode(struct net_device *dev, char *command)
+{
+ dhd_info_t *dhdi = *(dhd_info_t **)netdev_priv(dev);
+
+ dhdi->pub.pkt_filter_mode = bcm_strtoul(command, &command, 0);
+}
+
+int
+dhd_set_packet_filter_ports(struct net_device *dev, char *command)
+{
+ int i = 0, error = BCME_OK, count = 0, get_count = 0, action = 0;
+ uint16 portnum = 0, *ports = NULL, get_ports[WL_PKT_FILTER_PORTS_MAX];
+ dhd_info_t *dhdi = *(dhd_info_t **)netdev_priv(dev);
+ dhd_pub_t *dhdp = &dhdi->pub;
+ char iovbuf[WLC_IOCTL_SMLEN];
+
+ /* get action */
+ action = bcm_strtoul(command, &command, 0);
+ if (action > PKT_FILTER_PORTS_MAX)
+ return BCME_BADARG;
+
+ if (action == PKT_FILTER_PORTS_LOOPBACK) {
+ /* echo the loopback value if port filter is supported else error */
+ bcm_mkiovar("cap", NULL, 0, iovbuf, sizeof(iovbuf));
+ error = dhd_wl_ioctl_cmd(dhdp, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0);
+ if (error < 0) {
+ DHD_ERROR(("%s: Get Capability failed (error=%d)\n", __FUNCTION__, error));
+ return error;
+ }
+
+ if (strstr(iovbuf, "pktfltr2"))
+ return bcm_strtoul(command, &command, 0);
+ else {
+ DHD_ERROR(("%s: pktfltr2 is not supported\n", __FUNCTION__));
+ return BCME_UNSUPPORTED;
+ }
+ }
+
+ if (action == PKT_FILTER_PORTS_CLEAR) {
+ /* action 0 is clear all ports */
+ dhdp->pkt_filter_ports_count = 0;
+ bzero(dhdp->pkt_filter_ports, sizeof(dhdp->pkt_filter_ports));
+ }
+ else {
+ portnum = bcm_strtoul(command, &command, 0);
+ if (portnum == 0) {
+ /* no ports to add or remove */
+ return BCME_BADARG;
+ }
+
+ /* get configured ports */
+ count = dhdp->pkt_filter_ports_count;
+ ports = dhdp->pkt_filter_ports;
+
+ if (action == PKT_FILTER_PORTS_ADD) {
+ /* action 1 is add ports */
+
+ /* copy new ports */
+ while ((portnum != 0) && (count < WL_PKT_FILTER_PORTS_MAX)) {
+ for (i = 0; i < count; i++) {
+ /* duplicate port */
+ if (portnum == ports[i])
+ break;
+ }
+ if (portnum != ports[i])
+ ports[count++] = portnum;
+ portnum = bcm_strtoul(command, &command, 0);
+ }
+ } else if ((action == PKT_FILTER_PORTS_DEL) && (count > 0)) {
+ /* action 2 is remove ports */
+ bcopy(dhdp->pkt_filter_ports, get_ports, count * sizeof(uint16));
+ get_count = count;
+
+ while (portnum != 0) {
+ count = 0;
+ for (i = 0; i < get_count; i++) {
+ if (portnum != get_ports[i])
+ ports[count++] = get_ports[i];
+ }
+ get_count = count;
+ bcopy(ports, get_ports, count * sizeof(uint16));
+ portnum = bcm_strtoul(command, &command, 0);
+ }
+ }
+ dhdp->pkt_filter_ports_count = count;
+ }
+ return error;
+}
+
+static void
+dhd_enable_packet_filter_ports(dhd_pub_t *dhd, bool enable)
+{
+ int error = 0;
+ wl_pkt_filter_ports_t *portlist = NULL;
+ const uint pkt_filter_ports_buf_len = sizeof("pkt_filter_ports")
+ + WL_PKT_FILTER_PORTS_FIXED_LEN + (WL_PKT_FILTER_PORTS_MAX * sizeof(uint16));
+ char pkt_filter_ports_buf[pkt_filter_ports_buf_len];
+ char iovbuf[pkt_filter_ports_buf_len];
+
+ DHD_TRACE(("%s: enable %d, in_suspend %d, mode %d, port count %d\n", __FUNCTION__,
+ enable, dhd->in_suspend, dhd->pkt_filter_mode,
+ dhd->pkt_filter_ports_count));
+
+ bzero(pkt_filter_ports_buf, sizeof(pkt_filter_ports_buf));
+ portlist = (wl_pkt_filter_ports_t*)pkt_filter_ports_buf;
+ portlist->version = WL_PKT_FILTER_PORTS_VERSION;
+ portlist->reserved = 0;
+
+ if (enable) {
+ if (!(dhd->pkt_filter_mode & PKT_FILTER_MODE_PORTS_ONLY))
+ return;
+
+ /* enable port filter */
+ dhd_master_mode |= PKT_FILTER_MODE_PORTS_ONLY;
+ if (dhd->pkt_filter_mode & PKT_FILTER_MODE_FORWARD_ON_MATCH)
+ /* whitelist mode: FORWARD_ON_MATCH */
+ dhd_master_mode |= PKT_FILTER_MODE_FORWARD_ON_MATCH;
+ else
+ /* blacklist mode: DISCARD_ON_MATCH */
+ dhd_master_mode &= ~PKT_FILTER_MODE_FORWARD_ON_MATCH;
+
+ portlist->count = dhd->pkt_filter_ports_count;
+ bcopy(dhd->pkt_filter_ports, portlist->ports,
+ dhd->pkt_filter_ports_count * sizeof(uint16));
+ } else {
+ /* disable port filter */
+ portlist->count = 0;
+ dhd_master_mode &= ~PKT_FILTER_MODE_PORTS_ONLY;
+ dhd_master_mode |= PKT_FILTER_MODE_FORWARD_ON_MATCH;
+ }
+
+ DHD_INFO(("%s: update: mode %d, port count %d\n", __FUNCTION__, dhd_master_mode,
+ portlist->count));
+
+ /* update ports */
+ bcm_mkiovar("pkt_filter_ports",
+ (char*)portlist,
+ (WL_PKT_FILTER_PORTS_FIXED_LEN + (portlist->count * sizeof(uint16))),
+ iovbuf, sizeof(iovbuf));
+ error = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+ if (error < 0)
+ DHD_ERROR(("%s: set pkt_filter_ports failed %d\n", __FUNCTION__, error));
+
+ /* update mode */
+ bcm_mkiovar("pkt_filter_mode", (char*)&dhd_master_mode,
+ sizeof(dhd_master_mode), iovbuf, sizeof(iovbuf));
+ error = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+ if (error < 0)
+ DHD_ERROR(("%s: set pkt_filter_mode failed %d\n", __FUNCTION__, error));
+
+ return;
+}
+#endif /* PKT_FILTER_SUPPORT */
+#endif /* defined(CUSTOM_PLATFORM_NV_TEGRA) */
+
+void dhd_set_packet_filter(dhd_pub_t *dhd)
+{
+#ifdef PKT_FILTER_SUPPORT
+ int i;
+
+ DHD_TRACE(("%s: enter\n", __FUNCTION__));
+ if (dhd_pkt_filter_enable) {
+ for (i = 0; i < dhd->pktfilter_count; i++) {
+ dhd_pktfilter_offload_set(dhd, dhd->pktfilter[i]);
+ }
+ }
+#endif /* PKT_FILTER_SUPPORT */
+}
+
+void dhd_enable_packet_filter(int value, dhd_pub_t *dhd)
+{
+#ifdef PKT_FILTER_SUPPORT
+ int i;
+
+ DHD_TRACE(("%s: enter, value = %d\n", __FUNCTION__, value));
+
+#if defined(CUSTOM_PLATFORM_NV_TEGRA)
+ dhd_enable_packet_filter_ports(dhd, value);
+#endif /* defined(CUSTOM_PLATFORM_NV_TEGRA) */
+
+ /* 1 - Enable packet filter, only allow unicast packet to send up */
+ /* 0 - Disable packet filter */
+ if (dhd_pkt_filter_enable && (!value ||
+ (dhd_support_sta_mode(dhd) && !dhd->dhcp_in_progress)))
+ {
+ for (i = 0; i < dhd->pktfilter_count; i++) {
+#ifndef GAN_LITE_NAT_KEEPALIVE_FILTER
+ if (value && (i == DHD_ARP_FILTER_NUM) &&
+ !_turn_on_arp_filter(dhd, dhd->op_mode)) {
+ DHD_TRACE(("Do not turn on ARP white list pkt filter:"
+ "val %d, cnt %d, op_mode 0x%x\n",
+ value, i, dhd->op_mode));
+ continue;
+ }
+#endif /* !GAN_LITE_NAT_KEEPALIVE_FILTER */
+ dhd_pktfilter_offload_enable(dhd, dhd->pktfilter[i],
+ value, dhd_master_mode);
+ }
+ }
+#endif /* PKT_FILTER_SUPPORT */
+}
+
+static int dhd_set_suspend(int value, dhd_pub_t *dhd)
+{
+#ifndef SUPPORT_PM2_ONLY
+ int power_mode = PM_MAX;
+#endif /* SUPPORT_PM2_ONLY */
+ /* wl_pkt_filter_enable_t enable_parm; */
+ char iovbuf[32];
+ int bcn_li_dtim = 0; /* Default bcn_li_dtim in resume mode is 0 */
+ uint roamvar = dhd->conf->roam_off_suspend;
+ uint nd_ra_filter = 0;
+ int ret = 0;
+
+ if (!dhd)
+ return -ENODEV;
+
+ DHD_TRACE(("%s: enter, value = %d in_suspend=%d\n",
+ __FUNCTION__, value, dhd->in_suspend));
+
+ dhd_suspend_lock(dhd);
+
+#ifdef CUSTOM_SET_CPUCORE
+ DHD_TRACE(("%s set cpucore(suspend%d)\n", __FUNCTION__, value));
+ /* set specific cpucore */
+ dhd_set_cpucore(dhd, TRUE);
+#endif /* CUSTOM_SET_CPUCORE */
+#ifndef SUPPORT_PM2_ONLY
+ if (dhd->conf->pm >= 0)
+ power_mode = dhd->conf->pm;
+#endif /* SUPPORT_PM2_ONLY */
+ if (dhd->up) {
+ if (value && dhd->in_suspend) {
+#ifdef PKT_FILTER_SUPPORT
+ dhd->early_suspended = 1;
+#endif
+ /* Kernel suspended */
+ DHD_ERROR(("%s: force extra Suspend setting\n", __FUNCTION__));
+
+#ifndef SUPPORT_PM2_ONLY
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode,
+ sizeof(power_mode), TRUE, 0);
+#endif /* SUPPORT_PM2_ONLY */
+
+ /* Enable packet filter, only allow unicast packet to send up */
+ dhd_enable_packet_filter(1, dhd);
+
+ /* If DTIM skip is set up as default, force it to wake
+ * each third DTIM for better power savings. Note that
+ * one side effect is a chance to miss BC/MC packet.
+ */
+ bcn_li_dtim = dhd_get_suspend_bcn_li_dtim(dhd);
+ bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim,
+ 4, iovbuf, sizeof(iovbuf));
+ if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf),
+ TRUE, 0) < 0)
+ DHD_ERROR(("%s: set dtim failed\n", __FUNCTION__));
+
+ /* Disable firmware roaming during suspend */
+ bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+ if (FW_SUPPORTED(dhd, ndoe)) {
+ /* enable IPv6 RA filter in firmware during suspend */
+ nd_ra_filter = 1;
+ bcm_mkiovar("nd_ra_filter_enable", (char *)&nd_ra_filter, 4,
+ iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 0)
+ DHD_ERROR(("failed to set nd_ra_filter (%d)\n",
+ ret));
+ }
+ } else {
+#ifdef PKT_FILTER_SUPPORT
+ dhd->early_suspended = 0;
+#endif
+ /* Kernel resumed */
+ DHD_ERROR(("%s: Remove extra suspend setting\n", __FUNCTION__));
+
+#ifndef SUPPORT_PM2_ONLY
+ power_mode = PM_FAST;
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode,
+ sizeof(power_mode), TRUE, 0);
+#endif /* SUPPORT_PM2_ONLY */
+#ifdef PKT_FILTER_SUPPORT
+ /* disable pkt filter */
+ dhd_enable_packet_filter(0, dhd);
+#endif /* PKT_FILTER_SUPPORT */
+
+ /* restore pre-suspend setting for dtim_skip */
+ bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim,
+ 4, iovbuf, sizeof(iovbuf));
+
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+ roamvar = dhd_roam_disable;
+ bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+ if (FW_SUPPORTED(dhd, ndoe)) {
+ /* disable IPv6 RA filter in firmware during suspend */
+ nd_ra_filter = 0;
+ bcm_mkiovar("nd_ra_filter_enable", (char *)&nd_ra_filter, 4,
+ iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 0)
+ DHD_ERROR(("failed to set nd_ra_filter (%d)\n",
+ ret));
+ }
+ }
+ }
+ dhd_suspend_unlock(dhd);
+
+ return 0;
+}
+
+static int dhd_suspend_resume_helper(struct dhd_info *dhd, int val, int force)
+{
+ dhd_pub_t *dhdp = &dhd->pub;
+ int ret = 0;
+
+ DHD_OS_WAKE_LOCK(dhdp);
+ DHD_PERIM_LOCK(dhdp);
+
+ /* Set flag when early suspend was called */
+ dhdp->in_suspend = val;
+ if ((force || !dhdp->suspend_disable_flag) &&
+ dhd_support_sta_mode(dhdp))
+ {
+ ret = dhd_set_suspend(val, dhdp);
+ }
+
+ DHD_PERIM_UNLOCK(dhdp);
+ DHD_OS_WAKE_UNLOCK(dhdp);
+ return ret;
+}
+
+#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
+static void dhd_early_suspend(struct early_suspend *h)
+{
+ struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend);
+ DHD_TRACE_HW4(("%s: enter\n", __FUNCTION__));
+
+ if (dhd)
+ dhd_suspend_resume_helper(dhd, 1, 0);
+}
+
+static void dhd_late_resume(struct early_suspend *h)
+{
+ struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend);
+ DHD_TRACE_HW4(("%s: enter\n", __FUNCTION__));
+
+ if (dhd)
+ dhd_suspend_resume_helper(dhd, 0, 0);
+}
+#endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */
+
+/*
+ * Generalized timeout mechanism. Uses spin sleep with exponential back-off until
+ * the sleep time reaches one jiffy, then switches over to task delay. Usage:
+ *
+ * dhd_timeout_start(&tmo, usec);
+ * while (!dhd_timeout_expired(&tmo))
+ * if (poll_something())
+ * break;
+ * if (dhd_timeout_expired(&tmo))
+ * fatal();
+ */
+
+void
+dhd_timeout_start(dhd_timeout_t *tmo, uint usec)
+{
+ tmo->limit = usec;
+ tmo->increment = 0;
+ tmo->elapsed = 0;
+ tmo->tick = jiffies_to_usecs(1);
+}
+
+int
+dhd_timeout_expired(dhd_timeout_t *tmo)
+{
+ /* Does nothing the first call */
+ if (tmo->increment == 0) {
+ tmo->increment = 1;
+ return 0;
+ }
+
+ if (tmo->elapsed >= tmo->limit)
+ return 1;
+
+ /* Add the delay that's about to take place */
+ tmo->elapsed += tmo->increment;
+
+ if ((!CAN_SLEEP()) || tmo->increment < tmo->tick) {
+ OSL_DELAY(tmo->increment);
+ tmo->increment *= 2;
+ if (tmo->increment > tmo->tick)
+ tmo->increment = tmo->tick;
+ } else {
+ wait_queue_head_t delay_wait;
+ DECLARE_WAITQUEUE(wait, current);
+ init_waitqueue_head(&delay_wait);
+ add_wait_queue(&delay_wait, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+ (void)schedule_timeout(1);
+ remove_wait_queue(&delay_wait, &wait);
+ set_current_state(TASK_RUNNING);
+ }
+
+ return 0;
+}
+
+int
+dhd_net2idx(dhd_info_t *dhd, struct net_device *net)
+{
+ int i = 0;
+
+ if (!dhd) {
+ DHD_ERROR(("%s : DHD_BAD_IF return\n", __FUNCTION__));
+ return DHD_BAD_IF;
+ }
+ while (i < DHD_MAX_IFS) {
+ if (dhd->iflist[i] && dhd->iflist[i]->net && (dhd->iflist[i]->net == net))
+ return i;
+ i++;
+ }
+
+ return DHD_BAD_IF;
+}
+
+struct net_device * dhd_idx2net(void *pub, int ifidx)
+{
+ struct dhd_pub *dhd_pub = (struct dhd_pub *)pub;
+ struct dhd_info *dhd_info;
+
+ if (!dhd_pub || ifidx < 0 || ifidx >= DHD_MAX_IFS)
+ return NULL;
+ dhd_info = dhd_pub->info;
+ if (dhd_info && dhd_info->iflist[ifidx])
+ return dhd_info->iflist[ifidx]->net;
+ return NULL;
+}
+
+int
+dhd_ifname2idx(dhd_info_t *dhd, char *name)
+{
+ int i = DHD_MAX_IFS;
+
+ ASSERT(dhd);
+
+ if (name == NULL || *name == '\0')
+ return 0;
+
+ while (--i > 0)
+ if (dhd->iflist[i] && !strncmp(dhd->iflist[i]->name, name, IFNAMSIZ))
+ break;
+
+ DHD_TRACE(("%s: return idx %d for \"%s\"\n", __FUNCTION__, i, name));
+
+ return i; /* default - the primary interface */
+}
+
+int
+dhd_ifidx2hostidx(dhd_info_t *dhd, int ifidx)
+{
+ int i = DHD_MAX_IFS;
+
+ ASSERT(dhd);
+
+ while (--i > 0)
+ if (dhd->iflist[i] && (dhd->iflist[i]->idx == ifidx))
+ break;
+
+ DHD_TRACE(("%s: return hostidx %d for ifidx %d\n", __FUNCTION__, i, ifidx));
+
+ return i; /* default - the primary interface */
+}
+
+char *
+dhd_ifname(dhd_pub_t *dhdp, int ifidx)
+{
+ dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
+
+ ASSERT(dhd);
+
+ if (ifidx < 0 || ifidx >= DHD_MAX_IFS) {
+ DHD_ERROR(("%s: ifidx %d out of range\n", __FUNCTION__, ifidx));
+ return "<if_bad>";
+ }
+
+ if (dhd->iflist[ifidx] == NULL) {
+ DHD_ERROR(("%s: null i/f %d\n", __FUNCTION__, ifidx));
+ return "<if_null>";
+ }
+
+ if (dhd->iflist[ifidx]->net)
+ return dhd->iflist[ifidx]->net->name;
+
+ return "<if_none>";
+}
+
+uint8 *
+dhd_bssidx2bssid(dhd_pub_t *dhdp, int idx)
+{
+ int i;
+ dhd_info_t *dhd = (dhd_info_t *)dhdp;
+
+ ASSERT(dhd);
+ for (i = 0; i < DHD_MAX_IFS; i++)
+ if (dhd->iflist[i] && dhd->iflist[i]->bssidx == idx)
+ return dhd->iflist[i]->mac_addr;
+
+ return NULL;
+}
+
+
+static void
+_dhd_set_multicast_list(dhd_info_t *dhd, int ifidx)
+{
+ struct net_device *dev;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
+ struct netdev_hw_addr *ha;
+#else
+ struct dev_mc_list *mclist;
+#endif
+ uint32 allmulti, cnt;
+
+ wl_ioctl_t ioc;
+ char *buf, *bufp;
+ uint buflen;
+ int ret;
+
+ ASSERT(dhd && dhd->iflist[ifidx]);
+ dev = dhd->iflist[ifidx]->net;
+ if (!dev)
+ return;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
+ netif_addr_lock_bh(dev);
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
+ cnt = netdev_mc_count(dev);
+#else
+ cnt = dev->mc_count;
+#endif /* LINUX_VERSION_CODE */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
+ netif_addr_unlock_bh(dev);
+#endif
+
+ /* Determine initial value of allmulti flag */
+ allmulti = (dev->flags & IFF_ALLMULTI) ? TRUE : FALSE;
+
+ /* Send down the multicast list first. */
+
+
+ buflen = sizeof("mcast_list") + sizeof(cnt) + (cnt * ETHER_ADDR_LEN);
+ if (!(bufp = buf = MALLOC(dhd->pub.osh, buflen))) {
+ DHD_ERROR(("%s: out of memory for mcast_list, cnt %d\n",
+ dhd_ifname(&dhd->pub, ifidx), cnt));
+ return;
+ }
+
+ strncpy(bufp, "mcast_list", buflen - 1);
+ bufp[buflen - 1] = '\0';
+ bufp += strlen("mcast_list") + 1;
+
+ cnt = htol32(cnt);
+ memcpy(bufp, &cnt, sizeof(cnt));
+ bufp += sizeof(cnt);
+
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
+ netif_addr_lock_bh(dev);
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
+ netdev_for_each_mc_addr(ha, dev) {
+ if (!cnt)
+ break;
+ memcpy(bufp, ha->addr, ETHER_ADDR_LEN);
+ bufp += ETHER_ADDR_LEN;
+ cnt--;
+ }
+#else
+ for (mclist = dev->mc_list; (mclist && (cnt > 0));
+ cnt--, mclist = mclist->next) {
+ memcpy(bufp, (void *)mclist->dmi_addr, ETHER_ADDR_LEN);
+ bufp += ETHER_ADDR_LEN;
+ }
+#endif /* LINUX_VERSION_CODE */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
+ netif_addr_unlock_bh(dev);
+#endif
+
+ memset(&ioc, 0, sizeof(ioc));
+ ioc.cmd = WLC_SET_VAR;
+ ioc.buf = buf;
+ ioc.len = buflen;
+ ioc.set = TRUE;
+
+ ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len);
+ if (ret < 0) {
+ DHD_ERROR(("%s: set mcast_list failed, cnt %d\n",
+ dhd_ifname(&dhd->pub, ifidx), cnt));
+ allmulti = cnt ? TRUE : allmulti;
+ }
+
+ MFREE(dhd->pub.osh, buf, buflen);
+
+ /* Now send the allmulti setting. This is based on the setting in the
+ * net_device flags, but might be modified above to be turned on if we
+ * were trying to set some addresses and dongle rejected it...
+ */
+
+ buflen = sizeof("allmulti") + sizeof(allmulti);
+ if (!(buf = MALLOC(dhd->pub.osh, buflen))) {
+ DHD_ERROR(("%s: out of memory for allmulti\n", dhd_ifname(&dhd->pub, ifidx)));
+ return;
+ }
+ allmulti = htol32(allmulti);
+
+ if (!bcm_mkiovar("allmulti", (void*)&allmulti, sizeof(allmulti), buf, buflen)) {
+ DHD_ERROR(("%s: mkiovar failed for allmulti, datalen %d buflen %u\n",
+ dhd_ifname(&dhd->pub, ifidx), (int)sizeof(allmulti), buflen));
+ MFREE(dhd->pub.osh, buf, buflen);
+ return;
+ }
+
+
+ memset(&ioc, 0, sizeof(ioc));
+ ioc.cmd = WLC_SET_VAR;
+ ioc.buf = buf;
+ ioc.len = buflen;
+ ioc.set = TRUE;
+
+ ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len);
+ if (ret < 0) {
+ DHD_ERROR(("%s: set allmulti %d failed\n",
+ dhd_ifname(&dhd->pub, ifidx), ltoh32(allmulti)));
+ }
+
+ MFREE(dhd->pub.osh, buf, buflen);
+
+ /* Finally, pick up the PROMISC flag as well, like the NIC driver does */
+
+ allmulti = (dev->flags & IFF_PROMISC) ? TRUE : FALSE;
+
+ allmulti = htol32(allmulti);
+
+ memset(&ioc, 0, sizeof(ioc));
+ ioc.cmd = WLC_SET_PROMISC;
+ ioc.buf = &allmulti;
+ ioc.len = sizeof(allmulti);
+ ioc.set = TRUE;
+
+ ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len);
+ if (ret < 0) {
+ DHD_ERROR(("%s: set promisc %d failed\n",
+ dhd_ifname(&dhd->pub, ifidx), ltoh32(allmulti)));
+ }
+}
+
+int
+_dhd_set_mac_address(dhd_info_t *dhd, int ifidx, uint8 *addr)
+{
+ char buf[32];
+ wl_ioctl_t ioc;
+ int ret;
+
+ if (!bcm_mkiovar("cur_etheraddr", (char*)addr, ETHER_ADDR_LEN, buf, 32)) {
+ DHD_ERROR(("%s: mkiovar failed for cur_etheraddr\n", dhd_ifname(&dhd->pub, ifidx)));
+ return -1;
+ }
+ memset(&ioc, 0, sizeof(ioc));
+ ioc.cmd = WLC_SET_VAR;
+ ioc.buf = buf;
+ ioc.len = 32;
+ ioc.set = TRUE;
+
+ ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len);
+ if (ret < 0) {
+ DHD_ERROR(("%s: set cur_etheraddr failed\n", dhd_ifname(&dhd->pub, ifidx)));
+ } else {
+ memcpy(dhd->iflist[ifidx]->net->dev_addr, addr, ETHER_ADDR_LEN);
+ if (ifidx == 0)
+ memcpy(dhd->pub.mac.octet, addr, ETHER_ADDR_LEN);
+ }
+
+ return ret;
+}
+
+#ifdef SOFTAP
+extern struct net_device *ap_net_dev;
+extern tsk_ctl_t ap_eth_ctl; /* ap netdev heper thread ctl */
+#endif
+
+static void
+dhd_ifadd_event_handler(void *handle, void *event_info, u8 event)
+{
+ dhd_info_t *dhd = handle;
+ dhd_if_event_t *if_event = event_info;
+ struct net_device *ndev;
+ int ifidx, bssidx;
+ int ret;
+#if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
+ struct wireless_dev *vwdev, *primary_wdev;
+ struct net_device *primary_ndev;
+#endif /* OEM_ANDROID && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) */
+
+ if (event != DHD_WQ_WORK_IF_ADD) {
+ DHD_ERROR(("%s: unexpected event \n", __FUNCTION__));
+ return;
+ }
+
+ if (!dhd) {
+ DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__));
+ return;
+ }
+
+ if (!if_event) {
+ DHD_ERROR(("%s: event data is null \n", __FUNCTION__));
+ return;
+ }
+
+ dhd_net_if_lock_local(dhd);
+ DHD_OS_WAKE_LOCK(&dhd->pub);
+ DHD_PERIM_LOCK(&dhd->pub);
+
+ ifidx = if_event->event.ifidx;
+ bssidx = if_event->event.bssidx;
+ DHD_TRACE(("%s: registering if with ifidx %d\n", __FUNCTION__, ifidx));
+
+ ndev = dhd_allocate_if(&dhd->pub, ifidx, if_event->name,
+ if_event->mac, bssidx, TRUE);
+ if (!ndev) {
+ DHD_ERROR(("%s: net device alloc failed \n", __FUNCTION__));
+ goto done;
+ }
+
+#if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
+ vwdev = kzalloc(sizeof(*vwdev), GFP_KERNEL);
+ if (unlikely(!vwdev)) {
+ WL_ERR(("Could not allocate wireless device\n"));
+ goto done;
+ }
+ primary_ndev = dhd->pub.info->iflist[0]->net;
+ primary_wdev = ndev_to_wdev(primary_ndev);
+ vwdev->wiphy = primary_wdev->wiphy;
+ vwdev->iftype = if_event->event.role;
+ vwdev->netdev = ndev;
+ ndev->ieee80211_ptr = vwdev;
+ SET_NETDEV_DEV(ndev, wiphy_dev(vwdev->wiphy));
+ DHD_ERROR(("virtual interface(%s) is created\n", if_event->name));
+#endif /* OEM_ANDROID && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) */
+
+ DHD_PERIM_UNLOCK(&dhd->pub);
+ ret = dhd_register_if(&dhd->pub, ifidx, TRUE);
+ DHD_PERIM_LOCK(&dhd->pub);
+ if (ret != BCME_OK) {
+ DHD_ERROR(("%s: dhd_register_if failed\n", __FUNCTION__));
+ dhd_remove_if(&dhd->pub, ifidx, TRUE);
+ goto done;
+ }
+#ifdef PCIE_FULL_DONGLE
+ /* Turn on AP isolation in the firmware for interfaces operating in AP mode */
+ if (FW_SUPPORTED((&dhd->pub), ap) && !(DHD_IF_ROLE_STA(if_event->event.role))) {
+ char iovbuf[WLC_IOCTL_SMLEN];
+ uint32 var_int = 1;
+
+ memset(iovbuf, 0, sizeof(iovbuf));
+ bcm_mkiovar("ap_isolate", (char *)&var_int, 4, iovbuf, sizeof(iovbuf));
+ ret = dhd_wl_ioctl_cmd(&dhd->pub, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, ifidx);
+
+ if (ret != BCME_OK) {
+ DHD_ERROR(("%s: Failed to set ap_isolate to dongle\n", __FUNCTION__));
+ dhd_remove_if(&dhd->pub, ifidx, TRUE);
+ }
+ }
+#endif /* PCIE_FULL_DONGLE */
+done:
+ MFREE(dhd->pub.osh, if_event, sizeof(dhd_if_event_t));
+
+ DHD_PERIM_UNLOCK(&dhd->pub);
+ DHD_OS_WAKE_UNLOCK(&dhd->pub);
+ dhd_net_if_unlock_local(dhd);
+}
+
+static void
+dhd_ifdel_event_handler(void *handle, void *event_info, u8 event)
+{
+ dhd_info_t *dhd = handle;
+ int ifidx;
+ dhd_if_event_t *if_event = event_info;
+
+
+ if (event != DHD_WQ_WORK_IF_DEL) {
+ DHD_ERROR(("%s: unexpected event \n", __FUNCTION__));
+ return;
+ }
+
+ if (!dhd) {
+ DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__));
+ return;
+ }
+
+ if (!if_event) {
+ DHD_ERROR(("%s: event data is null \n", __FUNCTION__));
+ return;
+ }
+
+ dhd_net_if_lock_local(dhd);
+ DHD_OS_WAKE_LOCK(&dhd->pub);
+ DHD_PERIM_LOCK(&dhd->pub);
+
+ ifidx = if_event->event.ifidx;
+ DHD_TRACE(("Removing interface with idx %d\n", ifidx));
+
+ dhd_remove_if(&dhd->pub, ifidx, TRUE);
+
+ MFREE(dhd->pub.osh, if_event, sizeof(dhd_if_event_t));
+
+ DHD_PERIM_UNLOCK(&dhd->pub);
+ DHD_OS_WAKE_UNLOCK(&dhd->pub);
+ dhd_net_if_unlock_local(dhd);
+}
+
+static void
+dhd_set_mac_addr_handler(void *handle, void *event_info, u8 event)
+{
+ dhd_info_t *dhd = handle;
+ dhd_if_t *ifp = event_info;
+
+ if (event != DHD_WQ_WORK_SET_MAC) {
+ DHD_ERROR(("%s: unexpected event \n", __FUNCTION__));
+ }
+
+ if (!dhd) {
+ DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__));
+ return;
+ }
+
+ dhd_net_if_lock_local(dhd);
+ DHD_OS_WAKE_LOCK(&dhd->pub);
+ DHD_PERIM_LOCK(&dhd->pub);
+
+#ifdef SOFTAP
+ {
+ unsigned long flags;
+ bool in_ap = FALSE;
+ DHD_GENERAL_LOCK(&dhd->pub, flags);
+ in_ap = (ap_net_dev != NULL);
+ DHD_GENERAL_UNLOCK(&dhd->pub, flags);
+
+ if (in_ap) {
+ DHD_ERROR(("attempt to set MAC for %s in AP Mode, blocked. \n",
+ ifp->net->name));
+ goto done;
+ }
+ }
+#endif /* SOFTAP */
+
+ if (ifp == NULL || !dhd->pub.up) {
+ DHD_ERROR(("%s: interface info not available/down \n", __FUNCTION__));
+ goto done;
+ }
+
+ DHD_ERROR(("%s: MACID is overwritten\n", __FUNCTION__));
+ ifp->set_macaddress = FALSE;
+ if (_dhd_set_mac_address(dhd, ifp->idx, ifp->mac_addr) == 0)
+ DHD_INFO(("%s: MACID is overwritten\n", __FUNCTION__));
+ else
+ DHD_ERROR(("%s: _dhd_set_mac_address() failed\n", __FUNCTION__));
+
+done:
+ DHD_PERIM_UNLOCK(&dhd->pub);
+ DHD_OS_WAKE_UNLOCK(&dhd->pub);
+ dhd_net_if_unlock_local(dhd);
+}
+
+static void
+dhd_set_mcast_list_handler(void *handle, void *event_info, u8 event)
+{
+ dhd_info_t *dhd = handle;
+ dhd_if_t *ifp = event_info;
+ int ifidx;
+
+ if (event != DHD_WQ_WORK_SET_MCAST_LIST) {
+ DHD_ERROR(("%s: unexpected event \n", __FUNCTION__));
+ return;
+ }
+
+ if (!dhd) {
+ DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__));
+ return;
+ }
+
+ dhd_net_if_lock_local(dhd);
+ DHD_OS_WAKE_LOCK(&dhd->pub);
+ DHD_PERIM_LOCK(&dhd->pub);
+
+#ifdef SOFTAP
+ {
+ bool in_ap = FALSE;
+ unsigned long flags;
+ DHD_GENERAL_LOCK(&dhd->pub, flags);
+ in_ap = (ap_net_dev != NULL);
+ DHD_GENERAL_UNLOCK(&dhd->pub, flags);
+
+ if (in_ap) {
+ DHD_ERROR(("set MULTICAST list for %s in AP Mode, blocked. \n",
+ ifp->net->name));
+ ifp->set_multicast = FALSE;
+ goto done;
+ }
+ }
+#endif /* SOFTAP */
+
+ if (ifp == NULL || !dhd->pub.up) {
+ DHD_ERROR(("%s: interface info not available/down \n", __FUNCTION__));
+ goto done;
+ }
+
+ ifidx = ifp->idx;
+
+
+ _dhd_set_multicast_list(dhd, ifidx);
+ DHD_INFO(("%s: set multicast list for if %d\n", __FUNCTION__, ifidx));
+
+done:
+ DHD_PERIM_UNLOCK(&dhd->pub);
+ DHD_OS_WAKE_UNLOCK(&dhd->pub);
+ dhd_net_if_unlock_local(dhd);
+}
+
+static int
+dhd_set_mac_address(struct net_device *dev, void *addr)
+{
+ int ret = 0;
+
+ dhd_info_t *dhd = DHD_DEV_INFO(dev);
+ struct sockaddr *sa = (struct sockaddr *)addr;
+ int ifidx;
+ dhd_if_t *dhdif;
+
+ ifidx = dhd_net2idx(dhd, dev);
+ if (ifidx == DHD_BAD_IF)
+ return -1;
+
+ dhdif = dhd->iflist[ifidx];
+
+ dhd_net_if_lock_local(dhd);
+ memcpy(dhdif->mac_addr, sa->sa_data, ETHER_ADDR_LEN);
+ dhdif->set_macaddress = TRUE;
+ dhd_net_if_unlock_local(dhd);
+ dhd_deferred_schedule_work(dhd->dhd_deferred_wq, (void *)dhdif, DHD_WQ_WORK_SET_MAC,
+ dhd_set_mac_addr_handler, DHD_WORK_PRIORITY_LOW);
+ return ret;
+}
+
+static void
+dhd_set_multicast_list(struct net_device *dev)
+{
+ dhd_info_t *dhd = DHD_DEV_INFO(dev);
+ int ifidx;
+
+ ifidx = dhd_net2idx(dhd, dev);
+ if (ifidx == DHD_BAD_IF)
+ return;
+
+ dhd->iflist[ifidx]->set_multicast = TRUE;
+ dhd_deferred_schedule_work(dhd->dhd_deferred_wq, (void *)dhd->iflist[ifidx],
+ DHD_WQ_WORK_SET_MCAST_LIST, dhd_set_mcast_list_handler, DHD_WORK_PRIORITY_LOW);
+}
+
+#ifdef PROP_TXSTATUS
+int
+dhd_os_wlfc_block(dhd_pub_t *pub)
+{
+ dhd_info_t *di = (dhd_info_t *)(pub->info);
+ ASSERT(di != NULL);
+ spin_lock_bh(&di->wlfc_spinlock);
+ return 1;
+}
+
+int
+dhd_os_wlfc_unblock(dhd_pub_t *pub)
+{
+ dhd_info_t *di = (dhd_info_t *)(pub->info);
+
+ ASSERT(di != NULL);
+ spin_unlock_bh(&di->wlfc_spinlock);
+ return 1;
+}
+
+#endif /* PROP_TXSTATUS */
+
+#if defined(DHD_RX_DUMP) || defined(DHD_TX_DUMP)
+typedef struct {
+ uint16 type;
+ const char *str;
+} PKTTYPE_INFO;
+
+static const PKTTYPE_INFO packet_type_info[] =
+{
+ { ETHER_TYPE_IP, "IP" },
+ { ETHER_TYPE_ARP, "ARP" },
+ { ETHER_TYPE_BRCM, "BRCM" },
+ { ETHER_TYPE_802_1X, "802.1X" },
+ { ETHER_TYPE_WAI, "WAPI" },
+ { 0, ""}
+};
+
+static const char *_get_packet_type_str(uint16 type)
+{
+ int i;
+ int n = sizeof(packet_type_info)/sizeof(packet_type_info[1]) - 1;
+
+ for (i = 0; i < n; i++) {
+ if (packet_type_info[i].type == type)
+ return packet_type_info[i].str;
+ }
+
+ return packet_type_info[n].str;
+}
+#endif /* DHD_RX_DUMP || DHD_TX_DUMP */
+
+#if defined(DHD_TX_DUMP)
+void
+dhd_tx_dump(osl_t *osh, void *pkt)
+{
+ uint8 *dump_data;
+ uint16 protocol;
+ struct ether_header *eh;
+
+ dump_data = PKTDATA(osh, pkt);
+ eh = (struct ether_header *) dump_data;
+ protocol = ntoh16(eh->ether_type);
+
+ DHD_ERROR(("TX DUMP - %s\n", _get_packet_type_str(protocol)));
+
+ 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]));
+ }
+
+#if defined(DHD_TX_FULL_DUMP)
+ {
+ int i;
+ uint datalen;
+ datalen = PKTLEN(osh, pkt);
+
+ for (i = 0; i < datalen; i++) {
+ DHD_ERROR(("%02X ", dump_data[i]));
+ if ((i & 15) == 15)
+ printk("\n");
+ }
+ DHD_ERROR(("\n"));
+ }
+#endif /* DHD_TX_FULL_DUMP */
+}
+#endif /* DHD_TX_DUMP */
+
+int BCMFASTPATH
+dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf)
+{
+ int ret = BCME_OK;
+ dhd_info_t *dhd = (dhd_info_t *)(dhdp->info);
+ struct ether_header *eh = NULL;
+
+ /* Reject if down */
+ if (!dhdp->up || (dhdp->busstate == DHD_BUS_DOWN)) {
+ /* free the packet here since the caller won't */
+ PKTFREE(dhdp->osh, pktbuf, TRUE);
+ return -ENODEV;
+ }
+
+#ifdef PCIE_FULL_DONGLE
+ if (dhdp->busstate == DHD_BUS_SUSPEND) {
+ DHD_ERROR(("%s : pcie is still in suspend state!!\n", __FUNCTION__));
+ PKTFREE(dhdp->osh, pktbuf, TRUE);
+ return -EBUSY;
+ }
+#endif /* PCIE_FULL_DONGLE */
+
+#ifdef DHD_UNICAST_DHCP
+ /* if dhcp_unicast is enabled, we need to convert the */
+ /* broadcast DHCP ACK/REPLY packets to Unicast. */
+ if (dhdp->dhcp_unicast) {
+ dhd_convert_dhcp_broadcast_ack_to_unicast(dhdp, pktbuf, ifidx);
+ }
+#endif /* DHD_UNICAST_DHCP */
+ /* Update multicast statistic */
+ if (PKTLEN(dhdp->osh, pktbuf) >= ETHER_HDR_LEN) {
+ uint8 *pktdata = (uint8 *)PKTDATA(dhdp->osh, pktbuf);
+ eh = (struct ether_header *)pktdata;
+
+ if (ETHER_ISMULTI(eh->ether_dhost))
+ dhdp->tx_multicast++;
+ if (ntoh16(eh->ether_type) == ETHER_TYPE_802_1X)
+ atomic_inc(&dhd->pend_8021x_cnt);
+ } else {
+ PKTFREE(dhd->pub.osh, pktbuf, TRUE);
+ return BCME_ERROR;
+ }
+
+ /* Look into the packet and update the packet priority */
+#ifndef PKTPRIO_OVERRIDE
+ if (PKTPRIO(pktbuf) == 0)
+#endif
+ pktsetprio(pktbuf, FALSE);
+
+
+#if defined(PCIE_FULL_DONGLE) && !defined(PCIE_TX_DEFERRAL)
+ /*
+ * Lkup the per interface hash table, for a matching flowring. If one is not
+ * available, allocate a unique flowid and add a flowring entry.
+ * The found or newly created flowid is placed into the pktbuf's tag.
+ */
+ ret = dhd_flowid_update(dhdp, ifidx, dhdp->flow_prio_map[(PKTPRIO(pktbuf))], pktbuf);
+ if (ret != BCME_OK) {
+ PKTCFREE(dhd->pub.osh, pktbuf, TRUE);
+ return ret;
+ }
+#endif
+#if defined(DHD_TX_DUMP)
+ dhd_tx_dump(dhdp->osh, pktbuf);
+#endif
+
+ /* terence 20150901: Micky add to ajust the 802.1X priority */
+ /* Set the 802.1X packet with the highest priority 7 */
+ if (dhdp->conf->pktprio8021x >= 0)
+ pktset8021xprio(pktbuf, dhdp->conf->pktprio8021x);
+
+#ifdef PROP_TXSTATUS
+ if (dhd_wlfc_is_supported(dhdp)) {
+ /* store the interface ID */
+ DHD_PKTTAG_SETIF(PKTTAG(pktbuf), ifidx);
+
+ /* store destination MAC in the tag as well */
+ DHD_PKTTAG_SETDSTN(PKTTAG(pktbuf), eh->ether_dhost);
+
+ /* decide which FIFO this packet belongs to */
+ if (ETHER_ISMULTI(eh->ether_dhost))
+ /* one additional queue index (highest AC + 1) is used for bc/mc queue */
+ DHD_PKTTAG_SETFIFO(PKTTAG(pktbuf), AC_COUNT);
+ else
+ DHD_PKTTAG_SETFIFO(PKTTAG(pktbuf), WME_PRIO2AC(PKTPRIO(pktbuf)));
+ } else
+#endif /* PROP_TXSTATUS */
+ /* If the protocol uses a data header, apply it */
+ dhd_prot_hdrpush(dhdp, ifidx, pktbuf);
+
+ /* Use bus module to send data frame */
+#ifdef WLMEDIA_HTSF
+ dhd_htsf_addtxts(dhdp, pktbuf);
+#endif
+
+#ifdef PROP_TXSTATUS
+ {
+ if (dhd_wlfc_commit_packets(dhdp, (f_commitpkt_t)dhd_bus_txdata,
+ dhdp->bus, pktbuf, TRUE) == WLFC_UNSUPPORTED) {
+ /* non-proptxstatus way */
+#ifdef BCMPCIE
+ ret = dhd_bus_txdata(dhdp->bus, pktbuf, (uint8)ifidx);
+#else
+ ret = dhd_bus_txdata(dhdp->bus, pktbuf);
+#endif /* BCMPCIE */
+ }
+ }
+#else
+#ifdef BCMPCIE
+ ret = dhd_bus_txdata(dhdp->bus, pktbuf, (uint8)ifidx);
+#else
+ ret = dhd_bus_txdata(dhdp->bus, pktbuf);
+#endif /* BCMPCIE */
+#endif /* PROP_TXSTATUS */
+
+ return ret;
+}
+
+int BCMFASTPATH
+dhd_start_xmit(struct sk_buff *skb, struct net_device *net)
+{
+ int ret;
+ uint datalen;
+ void *pktbuf;
+ dhd_info_t *dhd = DHD_DEV_INFO(net);
+ dhd_if_t *ifp = NULL;
+ int ifidx;
+#ifdef WLMEDIA_HTSF
+ uint8 htsfdlystat_sz = dhd->pub.htsfdlystat_sz;
+#else
+ uint8 htsfdlystat_sz = 0;
+#endif
+#ifdef DHD_WMF
+ struct ether_header *eh;
+ uint8 *iph;
+#endif /* DHD_WMF */
+
+ DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+
+ DHD_OS_WAKE_LOCK(&dhd->pub);
+ DHD_PERIM_LOCK_TRY(DHD_FWDER_UNIT(dhd), TRUE);
+
+ /* Reject if down */
+ if (dhd->pub.busstate == DHD_BUS_DOWN || dhd->pub.hang_was_sent) {
+ DHD_ERROR(("%s: xmit rejected pub.up=%d busstate=%d \n",
+ __FUNCTION__, dhd->pub.up, dhd->pub.busstate));
+ netif_stop_queue(net);
+ /* Send Event when bus down detected during data session */
+ if (dhd->pub.up) {
+ DHD_ERROR(("%s: Event HANG sent up\n", __FUNCTION__));
+ net_os_send_hang_message(net);
+ }
+ DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), TRUE);
+ DHD_OS_WAKE_UNLOCK(&dhd->pub);
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20))
+ return -ENODEV;
+#else
+ return NETDEV_TX_BUSY;
+#endif
+ }
+
+ ifp = DHD_DEV_IFP(net);
+ ifidx = DHD_DEV_IFIDX(net);
+
+ ASSERT(ifidx == dhd_net2idx(dhd, net));
+ ASSERT((ifp != NULL) && (ifp == dhd->iflist[ifidx]));
+
+ if (ifidx == DHD_BAD_IF) {
+ DHD_ERROR(("%s: bad ifidx %d\n", __FUNCTION__, ifidx));
+ netif_stop_queue(net);
+ DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), TRUE);
+ DHD_OS_WAKE_UNLOCK(&dhd->pub);
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20))
+ return -ENODEV;
+#else
+ return NETDEV_TX_BUSY;
+#endif
+ }
+
+ /* re-align socket buffer if "skb->data" is odd address */
+ if (((unsigned long)(skb->data)) & 0x1) {
+ unsigned char *data = skb->data;
+ uint32 length = skb->len;
+ PKTPUSH(dhd->pub.osh, skb, 1);
+ memmove(skb->data, data, length);
+ PKTSETLEN(dhd->pub.osh, skb, length);
+ }
+
+ datalen = PKTLEN(dhd->pub.osh, skb);
+
+ /* Make sure there's enough room for any header */
+
+ if (skb_headroom(skb) < dhd->pub.hdrlen + htsfdlystat_sz) {
+ struct sk_buff *skb2;
+
+ DHD_INFO(("%s: insufficient headroom\n",
+ dhd_ifname(&dhd->pub, ifidx)));
+ dhd->pub.tx_realloc++;
+
+ skb2 = skb_realloc_headroom(skb, dhd->pub.hdrlen + htsfdlystat_sz);
+
+ dev_kfree_skb(skb);
+ if ((skb = skb2) == NULL) {
+ DHD_ERROR(("%s: skb_realloc_headroom failed\n",
+ dhd_ifname(&dhd->pub, ifidx)));
+ ret = -ENOMEM;
+ goto done;
+ }
+ }
+
+ /* Convert to packet */
+ if (!(pktbuf = PKTFRMNATIVE(dhd->pub.osh, skb))) {
+ DHD_ERROR(("%s: PKTFRMNATIVE failed\n",
+ dhd_ifname(&dhd->pub, ifidx)));
+ dev_kfree_skb_any(skb);
+ ret = -ENOMEM;
+ goto done;
+ }
+#ifdef WLMEDIA_HTSF
+ if (htsfdlystat_sz && PKTLEN(dhd->pub.osh, pktbuf) >= ETHER_ADDR_LEN) {
+ uint8 *pktdata = (uint8 *)PKTDATA(dhd->pub.osh, pktbuf);
+ struct ether_header *eh = (struct ether_header *)pktdata;
+
+ if (!ETHER_ISMULTI(eh->ether_dhost) &&
+ (ntoh16(eh->ether_type) == ETHER_TYPE_IP)) {
+ eh->ether_type = hton16(ETHER_TYPE_BRCM_PKTDLYSTATS);
+ }
+ }
+#endif
+#ifdef DHD_WMF
+ eh = (struct ether_header *)PKTDATA(dhd->pub.osh, pktbuf);
+ iph = (uint8 *)eh + ETHER_HDR_LEN;
+
+ /* WMF processing for multicast packets
+ * Only IPv4 packets are handled
+ */
+ if (ifp->wmf.wmf_enable && (ntoh16(eh->ether_type) == ETHER_TYPE_IP) &&
+ (IP_VER(iph) == IP_VER_4) && (ETHER_ISMULTI(eh->ether_dhost) ||
+ ((IPV4_PROT(iph) == IP_PROT_IGMP) && dhd->pub.wmf_ucast_igmp))) {
+#if defined(DHD_IGMP_UCQUERY) || defined(DHD_UCAST_UPNP)
+ void *sdu_clone;
+ bool ucast_convert = FALSE;
+#ifdef DHD_UCAST_UPNP
+ uint32 dest_ip;
+
+ dest_ip = ntoh32(*((uint32 *)(iph + IPV4_DEST_IP_OFFSET)));
+ ucast_convert = dhd->pub.wmf_ucast_upnp && MCAST_ADDR_UPNP_SSDP(dest_ip);
+#endif /* DHD_UCAST_UPNP */
+#ifdef DHD_IGMP_UCQUERY
+ ucast_convert |= dhd->pub.wmf_ucast_igmp_query &&
+ (IPV4_PROT(iph) == IP_PROT_IGMP) &&
+ (*(iph + IPV4_HLEN(iph)) == IGMPV2_HOST_MEMBERSHIP_QUERY);
+#endif /* DHD_IGMP_UCQUERY */
+ if (ucast_convert) {
+ dhd_sta_t *sta;
+ unsigned long flags;
+
+ DHD_IF_STA_LIST_LOCK(ifp, flags);
+
+ /* Convert upnp/igmp query to unicast for each assoc STA */
+ list_for_each_entry(sta, &ifp->sta_list, list) {
+ if ((sdu_clone = PKTDUP(dhd->pub.osh, pktbuf)) == NULL) {
+ DHD_IF_STA_LIST_UNLOCK(ifp, flags);
+ DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), TRUE);
+ DHD_OS_WAKE_UNLOCK(&dhd->pub);
+ return (WMF_NOP);
+ }
+ dhd_wmf_forward(ifp->wmf.wmfh, sdu_clone, 0, sta, 1);
+ }
+
+ DHD_IF_STA_LIST_UNLOCK(ifp, flags);
+ DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), TRUE);
+ DHD_OS_WAKE_UNLOCK(&dhd->pub);
+
+ PKTFREE(dhd->pub.osh, pktbuf, TRUE);
+ return NETDEV_TX_OK;
+ } else
+#endif /* defined(DHD_IGMP_UCQUERY) || defined(DHD_UCAST_UPNP) */
+ {
+ /* There will be no STA info if the packet is coming from LAN host
+ * Pass as NULL
+ */
+ ret = dhd_wmf_packets_handle(&dhd->pub, pktbuf, NULL, ifidx, 0);
+ switch (ret) {
+ case WMF_TAKEN:
+ case WMF_DROP:
+ /* Either taken by WMF or we should drop it.
+ * Exiting send path
+ */
+ DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), TRUE);
+ DHD_OS_WAKE_UNLOCK(&dhd->pub);
+ return NETDEV_TX_OK;
+ default:
+ /* Continue the transmit path */
+ break;
+ }
+ }
+ }
+#endif /* DHD_WMF */
+
+#ifdef DHDTCPACK_SUPPRESS
+ if (dhd->pub.tcpack_sup_mode == TCPACK_SUP_HOLD) {
+ /* If this packet has been hold or got freed, just return */
+ if (dhd_tcpack_hold(&dhd->pub, pktbuf, ifidx))
+ return 0;
+ } else {
+ /* If this packet has replaced another packet and got freed, just return */
+ if (dhd_tcpack_suppress(&dhd->pub, pktbuf))
+ return 0;
+ }
+#endif /* DHDTCPACK_SUPPRESS */
+
+ ret = dhd_sendpkt(&dhd->pub, ifidx, pktbuf);
+
+done:
+ if (ret) {
+ ifp->stats.tx_dropped++;
+ dhd->pub.tx_dropped++;
+ }
+ else {
+
+#ifdef PROP_TXSTATUS
+ /* tx_packets counter can counted only when wlfc is disabled */
+ if (!dhd_wlfc_is_supported(&dhd->pub))
+#endif
+ {
+ dhd->pub.tx_packets++;
+ ifp->stats.tx_packets++;
+ ifp->stats.tx_bytes += datalen;
+ }
+ }
+
+ DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), TRUE);
+ DHD_OS_WAKE_UNLOCK(&dhd->pub);
+
+ /* Return ok: we always eat the packet */
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20))
+ return 0;
+#else
+ return NETDEV_TX_OK;
+#endif
+}
+
+
+void
+dhd_txflowcontrol(dhd_pub_t *dhdp, int ifidx, bool state)
+{
+ struct net_device *net;
+ dhd_info_t *dhd = dhdp->info;
+ int i;
+
+ DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+
+ ASSERT(dhd);
+
+ if (ifidx == ALL_INTERFACES) {
+ /* Flow control on all active interfaces */
+ dhdp->txoff = state;
+ for (i = 0; i < DHD_MAX_IFS; i++) {
+ if (dhd->iflist[i]) {
+ net = dhd->iflist[i]->net;
+ if (state == ON)
+ netif_stop_queue(net);
+ else
+ netif_wake_queue(net);
+ }
+ }
+ }
+ else {
+ if (dhd->iflist[ifidx]) {
+ net = dhd->iflist[ifidx]->net;
+ if (state == ON)
+ netif_stop_queue(net);
+ else
+ netif_wake_queue(net);
+ }
+ }
+}
+
+
+#ifdef DHD_WMF
+bool
+dhd_is_rxthread_enabled(dhd_pub_t *dhdp)
+{
+ dhd_info_t *dhd = dhdp->info;
+
+ return dhd->rxthread_enabled;
+}
+#endif /* DHD_WMF */
+
+void
+dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan)
+{
+ dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
+ struct sk_buff *skb;
+ uchar *eth;
+ uint len;
+ void *data, *pnext = NULL;
+ int i;
+ dhd_if_t *ifp;
+ wl_event_msg_t event;
+ int tout_rx = 0;
+ int tout_ctrl = 0;
+ void *skbhead = NULL;
+ void *skbprev = NULL;
+#if defined(DHD_RX_DUMP) || defined(DHD_8021X_DUMP)
+ char *dump_data;
+ uint16 protocol;
+#endif /* DHD_RX_DUMP || DHD_8021X_DUMP */
+
+ DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+
+ for (i = 0; pktbuf && i < numpkt; i++, pktbuf = pnext) {
+ struct ether_header *eh;
+#ifdef WLBTAMP
+ struct dot11_llc_snap_header *lsh;
+#endif
+
+ pnext = PKTNEXT(dhdp->osh, pktbuf);
+ PKTSETNEXT(dhdp->osh, pktbuf, NULL);
+
+ ifp = dhd->iflist[ifidx];
+ if (ifp == NULL) {
+ DHD_ERROR(("%s: ifp is NULL. drop packet\n",
+ __FUNCTION__));
+ PKTCFREE(dhdp->osh, pktbuf, FALSE);
+ continue;
+ }
+
+ eh = (struct ether_header *)PKTDATA(dhdp->osh, pktbuf);
+
+ /* Dropping only data packets before registering net device to avoid kernel panic */
+#ifndef PROP_TXSTATUS_VSDB
+ if ((!ifp->net || ifp->net->reg_state != NETREG_REGISTERED) &&
+ (ntoh16(eh->ether_type) != ETHER_TYPE_BRCM))
+#else
+ if ((!ifp->net || ifp->net->reg_state != NETREG_REGISTERED || !dhd->pub.up) &&
+ (ntoh16(eh->ether_type) != ETHER_TYPE_BRCM))
+#endif /* PROP_TXSTATUS_VSDB */
+ {
+ DHD_ERROR(("%s: net device is NOT registered yet. drop packet\n",
+ __FUNCTION__));
+ PKTCFREE(dhdp->osh, pktbuf, FALSE);
+ continue;
+ }
+
+#ifdef WLBTAMP
+ lsh = (struct dot11_llc_snap_header *)&eh[1];
+
+ if ((ntoh16(eh->ether_type) < ETHER_TYPE_MIN) &&
+ (PKTLEN(dhdp->osh, pktbuf) >= RFC1042_HDR_LEN) &&
+ bcmp(lsh, BT_SIG_SNAP_MPROT, DOT11_LLC_SNAP_HDR_LEN - 2) == 0 &&
+ lsh->type == HTON16(BTA_PROT_L2CAP)) {
+ amp_hci_ACL_data_t *ACL_data = (amp_hci_ACL_data_t *)
+ ((uint8 *)eh + RFC1042_HDR_LEN);
+ ACL_data = NULL;
+ }
+#endif /* WLBTAMP */
+
+#ifdef PROP_TXSTATUS
+ if (dhd_wlfc_is_header_only_pkt(dhdp, pktbuf)) {
+ /* WLFC may send header only packet when
+ there is an urgent message but no packet to
+ piggy-back on
+ */
+ PKTCFREE(dhdp->osh, pktbuf, FALSE);
+ continue;
+ }
+#endif
+#ifdef DHD_L2_FILTER
+ /* If block_ping is enabled drop the ping packet */
+ if (dhdp->block_ping) {
+ if (dhd_l2_filter_block_ping(dhdp, pktbuf, ifidx) == BCME_OK) {
+ PKTFREE(dhdp->osh, pktbuf, FALSE);
+ continue;
+ }
+ }
+#endif
+#ifdef DHD_WMF
+ /* WMF processing for multicast packets */
+ if (ifp->wmf.wmf_enable && (ETHER_ISMULTI(eh->ether_dhost))) {
+ dhd_sta_t *sta;
+ int ret;
+
+ sta = dhd_find_sta(dhdp, ifidx, (void *)eh->ether_shost);
+ ret = dhd_wmf_packets_handle(dhdp, pktbuf, sta, ifidx, 1);
+ switch (ret) {
+ case WMF_TAKEN:
+ /* The packet is taken by WMF. Continue to next iteration */
+ continue;
+ case WMF_DROP:
+ /* Packet DROP decision by WMF. Toss it */
+ DHD_ERROR(("%s: WMF decides to drop packet\n",
+ __FUNCTION__));
+ PKTCFREE(dhdp->osh, pktbuf, FALSE);
+ continue;
+ default:
+ /* Continue the transmit path */
+ break;
+ }
+ }
+#endif /* DHD_WMF */
+#ifdef DHDTCPACK_SUPPRESS
+ dhd_tcpdata_info_get(dhdp, pktbuf);
+#endif
+ skb = PKTTONATIVE(dhdp->osh, pktbuf);
+
+ ifp = dhd->iflist[ifidx];
+ if (ifp == NULL)
+ ifp = dhd->iflist[0];
+
+ ASSERT(ifp);
+ skb->dev = ifp->net;
+
+#ifdef PCIE_FULL_DONGLE
+ if ((DHD_IF_ROLE_AP(dhdp, ifidx) || DHD_IF_ROLE_P2PGO(dhdp, ifidx)) &&
+ (!ifp->ap_isolate)) {
+ eh = (struct ether_header *)PKTDATA(dhdp->osh, pktbuf);
+ if (ETHER_ISUCAST(eh->ether_dhost)) {
+ if (dhd_find_sta(dhdp, ifidx, (void *)eh->ether_dhost)) {
+ dhd_sendpkt(dhdp, ifidx, pktbuf);
+ continue;
+ }
+ } else {
+ void *npktbuf = PKTDUP(dhdp->osh, pktbuf);
+ dhd_sendpkt(dhdp, ifidx, npktbuf);
+ }
+ }
+#endif /* PCIE_FULL_DONGLE */
+
+ /* Get the protocol, maintain skb around eth_type_trans()
+ * The main reason for this hack is for the limitation of
+ * Linux 2.4 where 'eth_type_trans' uses the 'net->hard_header_len'
+ * to perform skb_pull inside vs ETH_HLEN. Since to avoid
+ * coping of the packet coming from the network stack to add
+ * BDC, Hardware header etc, during network interface registration
+ * we set the 'net->hard_header_len' to ETH_HLEN + extra space required
+ * for BDC, Hardware header etc. and not just the ETH_HLEN
+ */
+ eth = skb->data;
+ len = skb->len;
+
+#if defined(DHD_RX_DUMP) || defined(DHD_8021X_DUMP)
+ dump_data = skb->data;
+ protocol = (dump_data[12] << 8) | dump_data[13];
+
+ if (protocol == ETHER_TYPE_802_1X) {
+ DHD_ERROR(("ETHER_TYPE_802_1X [RX]: "
+ "ver %d, type %d, replay %d\n",
+ dump_data[14], dump_data[15],
+ dump_data[30]));
+ }
+#endif /* DHD_RX_DUMP || DHD_8021X_DUMP */
+#if defined(DHD_RX_DUMP)
+ DHD_ERROR(("RX DUMP - %s\n", _get_packet_type_str(protocol)));
+ if (protocol != ETHER_TYPE_BRCM) {
+ if (dump_data[0] == 0xFF) {
+ DHD_ERROR(("%s: BROADCAST\n", __FUNCTION__));
+
+ if ((dump_data[12] == 8) &&
+ (dump_data[13] == 6)) {
+ DHD_ERROR(("%s: ARP %d\n",
+ __FUNCTION__, dump_data[0x15]));
+ }
+ } else if (dump_data[0] & 1) {
+ DHD_ERROR(("%s: MULTICAST: " MACDBG "\n",
+ __FUNCTION__, MAC2STRDBG(dump_data)));
+ }
+#ifdef DHD_RX_FULL_DUMP
+ {
+ int k;
+ for (k = 0; k < skb->len; k++) {
+ DHD_ERROR(("%02X ", dump_data[k]));
+ if ((k & 15) == 15)
+ DHD_ERROR(("\n"));
+ }
+ DHD_ERROR(("\n"));
+ }
+#endif /* DHD_RX_FULL_DUMP */
+ }
+#endif /* DHD_RX_DUMP */
+
+ skb->protocol = eth_type_trans(skb, skb->dev);
+
+ if (skb->pkt_type == PACKET_MULTICAST) {
+ dhd->pub.rx_multicast++;
+ ifp->stats.multicast++;
+ }
+
+ skb->data = eth;
+ skb->len = len;
+
+#ifdef WLMEDIA_HTSF
+ dhd_htsf_addrxts(dhdp, pktbuf);
+#endif
+ /* Strip header, count, deliver upward */
+ skb_pull(skb, ETH_HLEN);
+
+ /* Process special event packets and then discard them */
+ memset(&event, 0, sizeof(event));
+ if (ntoh16(skb->protocol) == ETHER_TYPE_BRCM) {
+ dhd_wl_host_event(dhd, &ifidx,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
+ skb_mac_header(skb),
+#else
+ skb->mac.raw,
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) */
+ &event,
+ &data);
+
+ wl_event_to_host_order(&event);
+ if (!tout_ctrl)
+ tout_ctrl = DHD_PACKET_TIMEOUT_MS;
+#ifdef WLBTAMP
+ if (event.event_type == WLC_E_BTA_HCI_EVENT) {
+ dhd_bta_doevt(dhdp, data, event.datalen);
+ }
+#endif /* WLBTAMP */
+
+#if defined(PNO_SUPPORT)
+ if (event.event_type == WLC_E_PFN_NET_FOUND) {
+ /* enforce custom wake lock to garantee that Kernel not suspended */
+ tout_ctrl = CUSTOM_PNO_EVENT_LOCK_xTIME * DHD_PACKET_TIMEOUT_MS;
+ }
+#endif /* PNO_SUPPORT */
+
+#ifdef DHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT
+ PKTFREE(dhdp->osh, pktbuf, FALSE);
+ continue;
+#endif /* DHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT */
+ } else {
+ tout_rx = DHD_PACKET_TIMEOUT_MS;
+
+#ifdef PROP_TXSTATUS
+ dhd_wlfc_save_rxpath_ac_time(dhdp, (uint8)PKTPRIO(skb));
+#endif /* PROP_TXSTATUS */
+ }
+
+ ASSERT(ifidx < DHD_MAX_IFS && dhd->iflist[ifidx]);
+ ifp = dhd->iflist[ifidx];
+
+ if (ifp->net)
+ ifp->net->last_rx = jiffies;
+
+ if (ntoh16(skb->protocol) != ETHER_TYPE_BRCM) {
+ dhdp->dstats.rx_bytes += skb->len;
+ dhdp->rx_packets++; /* Local count */
+ ifp->stats.rx_bytes += skb->len;
+ ifp->stats.rx_packets++;
+ }
+#if defined(DHD_TCP_WINSIZE_ADJUST)
+ if (dhd_use_tcp_window_size_adjust) {
+ if (ifidx == 0 && ntoh16(skb->protocol) == ETHER_TYPE_IP) {
+ dhd_adjust_tcp_winsize(dhdp->op_mode, skb);
+ }
+ }
+#endif /* DHD_TCP_WINSIZE_ADJUST */
+
+ if (in_interrupt()) {
+ netif_rx(skb);
+ } else {
+ if (dhd->rxthread_enabled) {
+ if (!skbhead)
+ skbhead = skb;
+ else
+ PKTSETNEXT(dhdp->osh, skbprev, skb);
+ skbprev = skb;
+ } else {
+
+ /* If the receive is not processed inside an ISR,
+ * the softirqd must be woken explicitly to service
+ * the NET_RX_SOFTIRQ. In 2.6 kernels, this is handled
+ * by netif_rx_ni(), but in earlier kernels, we need
+ * to do it manually.
+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
+ netif_rx_ni(skb);
+#else
+ ulong flags;
+ netif_rx(skb);
+ local_irq_save(flags);
+ RAISE_RX_SOFTIRQ();
+ local_irq_restore(flags);
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */
+ }
+ }
+ }
+
+ if (dhd->rxthread_enabled && skbhead)
+ dhd_sched_rxf(dhdp, skbhead);
+
+ DHD_OS_WAKE_LOCK_RX_TIMEOUT_ENABLE(dhdp, tout_rx);
+ DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(dhdp, tout_ctrl);
+}
+
+void
+dhd_event(struct dhd_info *dhd, char *evpkt, int evlen, int ifidx)
+{
+ /* Linux version has nothing to do */
+ return;
+}
+
+void
+dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success)
+{
+ dhd_info_t *dhd = (dhd_info_t *)(dhdp->info);
+ struct ether_header *eh;
+ uint16 type;
+#ifdef WLBTAMP
+ uint len;
+#endif
+
+ dhd_prot_hdrpull(dhdp, NULL, txp, NULL, NULL);
+
+ eh = (struct ether_header *)PKTDATA(dhdp->osh, txp);
+ type = ntoh16(eh->ether_type);
+
+ if (type == ETHER_TYPE_802_1X)
+ atomic_dec(&dhd->pend_8021x_cnt);
+
+#ifdef WLBTAMP
+ /* Crack open the packet and check to see if it is BT HCI ACL data packet.
+ * If yes generate packet completion event.
+ */
+ len = PKTLEN(dhdp->osh, txp);
+
+ /* Generate ACL data tx completion event locally to avoid SDIO bus transaction */
+ if ((type < ETHER_TYPE_MIN) && (len >= RFC1042_HDR_LEN)) {
+ struct dot11_llc_snap_header *lsh = (struct dot11_llc_snap_header *)&eh[1];
+
+ if (bcmp(lsh, BT_SIG_SNAP_MPROT, DOT11_LLC_SNAP_HDR_LEN - 2) == 0 &&
+ ntoh16(lsh->type) == BTA_PROT_L2CAP) {
+
+ dhd_bta_tx_hcidata_complete(dhdp, txp, success);
+ }
+ }
+#endif /* WLBTAMP */
+#ifdef PROP_TXSTATUS
+ if (dhdp->wlfc_state && (dhdp->proptxstatus_mode != WLFC_FCMODE_NONE)) {
+ dhd_if_t *ifp = dhd->iflist[DHD_PKTTAG_IF(PKTTAG(txp))];
+ uint datalen = PKTLEN(dhd->pub.osh, txp);
+
+ if (success) {
+ dhd->pub.tx_packets++;
+ ifp->stats.tx_packets++;
+ ifp->stats.tx_bytes += datalen;
+ } else {
+ ifp->stats.tx_dropped++;
+ }
+ }
+#endif
+}
+
+static struct net_device_stats *
+dhd_get_stats(struct net_device *net)
+{
+ dhd_info_t *dhd = DHD_DEV_INFO(net);
+ dhd_if_t *ifp;
+ int ifidx;
+
+ DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+
+ ifidx = dhd_net2idx(dhd, net);
+ if (ifidx == DHD_BAD_IF) {
+ DHD_ERROR(("%s: BAD_IF\n", __FUNCTION__));
+
+ memset(&net->stats, 0, sizeof(net->stats));
+ return &net->stats;
+ }
+
+ ifp = dhd->iflist[ifidx];
+ ASSERT(dhd && ifp);
+
+ if (dhd->pub.up) {
+ /* Use the protocol to get dongle stats */
+ dhd_prot_dstats(&dhd->pub);
+ }
+ return &ifp->stats;
+}
+
+static int
+dhd_watchdog_thread(void *data)
+{
+ tsk_ctl_t *tsk = (tsk_ctl_t *)data;
+ dhd_info_t *dhd = (dhd_info_t *)tsk->parent;
+ /* This thread doesn't need any user-level access,
+ * so get rid of all our resources
+ */
+ if (dhd_watchdog_prio > 0) {
+ struct sched_param param;
+ param.sched_priority = (dhd_watchdog_prio < MAX_RT_PRIO)?
+ dhd_watchdog_prio:(MAX_RT_PRIO-1);
+ setScheduler(current, SCHED_FIFO, &param);
+ }
+
+ while (1)
+ if (down_interruptible (&tsk->sema) == 0) {
+ unsigned long flags;
+ unsigned long jiffies_at_start = jiffies;
+ unsigned long time_lapse;
+
+ SMP_RD_BARRIER_DEPENDS();
+ if (tsk->terminated) {
+ break;
+ }
+
+ if (dhd->pub.dongle_reset == FALSE) {
+ DHD_TIMER(("%s:\n", __FUNCTION__));
+
+ /* Call the bus module watchdog */
+ dhd_bus_watchdog(&dhd->pub);
+
+
+ DHD_GENERAL_LOCK(&dhd->pub, flags);
+ /* Count the tick for reference */
+ dhd->pub.tickcnt++;
+ time_lapse = jiffies - jiffies_at_start;
+
+ /* Reschedule the watchdog */
+ if (dhd->wd_timer_valid)
+ mod_timer(&dhd->timer,
+ jiffies +
+ msecs_to_jiffies(dhd_watchdog_ms) -
+ min(msecs_to_jiffies(dhd_watchdog_ms), time_lapse));
+ DHD_GENERAL_UNLOCK(&dhd->pub, flags);
+ }
+ } else {
+ break;
+ }
+
+ complete_and_exit(&tsk->completed, 0);
+}
+
+static void dhd_watchdog(ulong data)
+{
+ dhd_info_t *dhd = (dhd_info_t *)data;
+ unsigned long flags;
+
+ if (dhd->pub.dongle_reset) {
+ return;
+ }
+
+ if (dhd->thr_wdt_ctl.thr_pid >= 0) {
+ up(&dhd->thr_wdt_ctl.sema);
+ return;
+ }
+
+ /* Call the bus module watchdog */
+ dhd_bus_watchdog(&dhd->pub);
+
+ DHD_GENERAL_LOCK(&dhd->pub, flags);
+ /* Count the tick for reference */
+ dhd->pub.tickcnt++;
+
+ /* Reschedule the watchdog */
+ if (dhd->wd_timer_valid)
+ mod_timer(&dhd->timer, jiffies + msecs_to_jiffies(dhd_watchdog_ms));
+ DHD_GENERAL_UNLOCK(&dhd->pub, flags);
+
+}
+
+#ifdef ENABLE_ADAPTIVE_SCHED
+static void
+dhd_sched_policy(int prio)
+{
+ struct sched_param param;
+ if (cpufreq_quick_get(0) <= CUSTOM_CPUFREQ_THRESH) {
+ param.sched_priority = 0;
+ setScheduler(current, SCHED_NORMAL, &param);
+ } else {
+ if (get_scheduler_policy(current) != SCHED_FIFO) {
+ param.sched_priority = (prio < MAX_RT_PRIO)? prio : (MAX_RT_PRIO-1);
+ setScheduler(current, SCHED_FIFO, &param);
+ }
+ }
+}
+#endif /* ENABLE_ADAPTIVE_SCHED */
+#ifdef DEBUG_CPU_FREQ
+static int dhd_cpufreq_notifier(struct notifier_block *nb, unsigned long val, void *data)
+{
+ dhd_info_t *dhd = container_of(nb, struct dhd_info, freq_trans);
+ struct cpufreq_freqs *freq = data;
+ if (dhd) {
+ if (!dhd->new_freq)
+ goto exit;
+ if (val == CPUFREQ_POSTCHANGE) {
+ DHD_ERROR(("cpu freq is changed to %u kHZ on CPU %d\n",
+ freq->new, freq->cpu));
+ *per_cpu_ptr(dhd->new_freq, freq->cpu) = freq->new;
+ }
+ }
+exit:
+ return 0;
+}
+#endif /* DEBUG_CPU_FREQ */
+static int
+dhd_dpc_thread(void *data)
+{
+ tsk_ctl_t *tsk = (tsk_ctl_t *)data;
+ dhd_info_t *dhd = (dhd_info_t *)tsk->parent;
+
+ /* This thread doesn't need any user-level access,
+ * so get rid of all our resources
+ */
+ if (dhd_dpc_prio > 0)
+ {
+ struct sched_param param;
+ param.sched_priority = (dhd_dpc_prio < MAX_RT_PRIO)?dhd_dpc_prio:(MAX_RT_PRIO-1);
+ setScheduler(current, SCHED_FIFO, &param);
+ }
+
+#ifdef CUSTOM_DPC_CPUCORE
+ set_cpus_allowed_ptr(current, cpumask_of(CUSTOM_DPC_CPUCORE));
+#else
+ if (dhd->pub.conf->dpc_cpucore >= 0) {
+ printf("%s: set dpc_cpucore %d from config.txt\n", __FUNCTION__, dhd->pub.conf->dpc_cpucore);
+ set_cpus_allowed_ptr(current, cpumask_of(dhd->pub.conf->dpc_cpucore));
+ }
+#endif
+#ifdef CUSTOM_SET_CPUCORE
+ dhd->pub.current_dpc = current;
+#endif /* CUSTOM_SET_CPUCORE */
+ /* Run until signal received */
+ while (1) {
+ if (!binary_sema_down(tsk)) {
+#ifdef ENABLE_ADAPTIVE_SCHED
+ dhd_sched_policy(dhd_dpc_prio);
+#endif /* ENABLE_ADAPTIVE_SCHED */
+ SMP_RD_BARRIER_DEPENDS();
+ if (tsk->terminated) {
+ break;
+ }
+
+ /* Call bus dpc unless it indicated down (then clean stop) */
+ if (dhd->pub.busstate != DHD_BUS_DOWN) {
+ dhd_os_wd_timer_extend(&dhd->pub, TRUE);
+ while (dhd_bus_dpc(dhd->pub.bus)) {
+ /* process all data */
+ }
+ dhd_os_wd_timer_extend(&dhd->pub, FALSE);
+ DHD_OS_WAKE_UNLOCK(&dhd->pub);
+
+ } else {
+ if (dhd->pub.up)
+ dhd_bus_stop(dhd->pub.bus, TRUE);
+ DHD_OS_WAKE_UNLOCK(&dhd->pub);
+ }
+ }
+ else
+ break;
+ }
+ complete_and_exit(&tsk->completed, 0);
+}
+
+static int
+dhd_rxf_thread(void *data)
+{
+ tsk_ctl_t *tsk = (tsk_ctl_t *)data;
+ dhd_info_t *dhd = (dhd_info_t *)tsk->parent;
+#if defined(WAIT_DEQUEUE)
+#define RXF_WATCHDOG_TIME 250 /* BARK_TIME(1000) / */
+ ulong watchdogTime = OSL_SYSUPTIME(); /* msec */
+#endif
+ dhd_pub_t *pub = &dhd->pub;
+
+ /* This thread doesn't need any user-level access,
+ * so get rid of all our resources
+ */
+ if (dhd_rxf_prio > 0)
+ {
+ struct sched_param param;
+ param.sched_priority = (dhd_rxf_prio < MAX_RT_PRIO)?dhd_rxf_prio:(MAX_RT_PRIO-1);
+ setScheduler(current, SCHED_FIFO, &param);
+ }
+
+ DAEMONIZE("dhd_rxf");
+ /* DHD_OS_WAKE_LOCK is called in dhd_sched_dpc[dhd_linux.c] down below */
+
+ /* signal: thread has started */
+ complete(&tsk->completed);
+#ifdef CUSTOM_SET_CPUCORE
+ dhd->pub.current_rxf = current;
+#endif /* CUSTOM_SET_CPUCORE */
+ /* Run until signal received */
+ while (1) {
+ if (down_interruptible(&tsk->sema) == 0) {
+ void *skb;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
+ ulong flags;
+#endif
+#ifdef ENABLE_ADAPTIVE_SCHED
+ dhd_sched_policy(dhd_rxf_prio);
+#endif /* ENABLE_ADAPTIVE_SCHED */
+
+ SMP_RD_BARRIER_DEPENDS();
+
+ if (tsk->terminated) {
+ break;
+ }
+ skb = dhd_rxf_dequeue(pub);
+
+ if (skb == NULL) {
+ continue;
+ }
+ while (skb) {
+ void *skbnext = PKTNEXT(pub->osh, skb);
+ PKTSETNEXT(pub->osh, skb, NULL);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
+ netif_rx_ni(skb);
+#else
+ netif_rx(skb);
+ local_irq_save(flags);
+ RAISE_RX_SOFTIRQ();
+ local_irq_restore(flags);
+
+#endif
+ skb = skbnext;
+ }
+#if defined(WAIT_DEQUEUE)
+ if (OSL_SYSUPTIME() - watchdogTime > RXF_WATCHDOG_TIME) {
+ OSL_SLEEP(1);
+ watchdogTime = OSL_SYSUPTIME();
+ }
+#endif
+
+ DHD_OS_WAKE_UNLOCK(pub);
+ }
+ else
+ break;
+ }
+ complete_and_exit(&tsk->completed, 0);
+}
+
+#ifdef BCMPCIE
+void dhd_dpc_kill(dhd_pub_t *dhdp)
+{
+ dhd_info_t *dhd;
+
+ if (!dhdp)
+ return;
+
+ dhd = dhdp->info;
+
+ if (!dhd)
+ return;
+
+ tasklet_kill(&dhd->tasklet);
+ DHD_ERROR(("%s: tasklet disabled\n", __FUNCTION__));
+}
+#endif /* BCMPCIE */
+
+static void
+dhd_dpc(ulong data)
+{
+ dhd_info_t *dhd;
+
+ dhd = (dhd_info_t *)data;
+
+ /* this (tasklet) can be scheduled in dhd_sched_dpc[dhd_linux.c]
+ * down below , wake lock is set,
+ * the tasklet is initialized in dhd_attach()
+ */
+ /* Call bus dpc unless it indicated down (then clean stop) */
+ if (dhd->pub.busstate != DHD_BUS_DOWN) {
+ if (dhd_bus_dpc(dhd->pub.bus))
+ tasklet_schedule(&dhd->tasklet);
+ else
+ DHD_OS_WAKE_UNLOCK(&dhd->pub);
+ } else {
+ dhd_bus_stop(dhd->pub.bus, TRUE);
+ DHD_OS_WAKE_UNLOCK(&dhd->pub);
+ }
+}
+
+void
+dhd_sched_dpc(dhd_pub_t *dhdp)
+{
+ dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
+
+ DHD_OS_WAKE_LOCK(dhdp);
+ if (dhd->thr_dpc_ctl.thr_pid >= 0) {
+ /* If the semaphore does not get up,
+ * wake unlock should be done here
+ */
+ if (!binary_sema_up(&dhd->thr_dpc_ctl))
+ DHD_OS_WAKE_UNLOCK(dhdp);
+ return;
+ } else {
+ tasklet_schedule(&dhd->tasklet);
+ }
+}
+
+static void
+dhd_sched_rxf(dhd_pub_t *dhdp, void *skb)
+{
+ dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
+#ifdef RXF_DEQUEUE_ON_BUSY
+ int ret = BCME_OK;
+ int retry = 2;
+#endif /* RXF_DEQUEUE_ON_BUSY */
+
+ DHD_OS_WAKE_LOCK(dhdp);
+
+ DHD_TRACE(("dhd_sched_rxf: Enter\n"));
+#ifdef RXF_DEQUEUE_ON_BUSY
+ do {
+ ret = dhd_rxf_enqueue(dhdp, skb);
+ if (ret == BCME_OK || ret == BCME_ERROR)
+ break;
+ else
+ OSL_SLEEP(50); /* waiting for dequeueing */
+ } while (retry-- > 0);
+
+ if (retry <= 0 && ret == BCME_BUSY) {
+ void *skbp = skb;
+
+ while (skbp) {
+ void *skbnext = PKTNEXT(dhdp->osh, skbp);
+ PKTSETNEXT(dhdp->osh, skbp, NULL);
+ netif_rx_ni(skbp);
+ skbp = skbnext;
+ }
+ DHD_ERROR(("send skb to kernel backlog without rxf_thread\n"));
+ }
+ else {
+ if (dhd->thr_rxf_ctl.thr_pid >= 0) {
+ up(&dhd->thr_rxf_ctl.sema);
+ }
+ }
+#else /* RXF_DEQUEUE_ON_BUSY */
+ do {
+ if (dhd_rxf_enqueue(dhdp, skb) == BCME_OK)
+ break;
+ } while (1);
+ if (dhd->thr_rxf_ctl.thr_pid >= 0) {
+ up(&dhd->thr_rxf_ctl.sema);
+ }
+ return;
+#endif /* RXF_DEQUEUE_ON_BUSY */
+}
+
+#ifdef TOE
+/* Retrieve current toe component enables, which are kept as a bitmap in toe_ol iovar */
+static int
+dhd_toe_get(dhd_info_t *dhd, int ifidx, uint32 *toe_ol)
+{
+ wl_ioctl_t ioc;
+ char buf[32];
+ int ret;
+
+ memset(&ioc, 0, sizeof(ioc));
+
+ ioc.cmd = WLC_GET_VAR;
+ ioc.buf = buf;
+ ioc.len = (uint)sizeof(buf);
+ ioc.set = FALSE;
+
+ strncpy(buf, "toe_ol", sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = '\0';
+ if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) {
+ /* Check for older dongle image that doesn't support toe_ol */
+ if (ret == -EIO) {
+ DHD_ERROR(("%s: toe not supported by device\n",
+ dhd_ifname(&dhd->pub, ifidx)));
+ return -EOPNOTSUPP;
+ }
+
+ DHD_INFO(("%s: could not get toe_ol: ret=%d\n", dhd_ifname(&dhd->pub, ifidx), ret));
+ return ret;
+ }
+
+ memcpy(toe_ol, buf, sizeof(uint32));
+ return 0;
+}
+
+/* Set current toe component enables in toe_ol iovar, and set toe global enable iovar */
+static int
+dhd_toe_set(dhd_info_t *dhd, int ifidx, uint32 toe_ol)
+{
+ wl_ioctl_t ioc;
+ char buf[32];
+ int toe, ret;
+
+ memset(&ioc, 0, sizeof(ioc));
+
+ ioc.cmd = WLC_SET_VAR;
+ ioc.buf = buf;
+ ioc.len = (uint)sizeof(buf);
+ ioc.set = TRUE;
+
+ /* Set toe_ol as requested */
+
+ strncpy(buf, "toe_ol", sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = '\0';
+ memcpy(&buf[sizeof("toe_ol")], &toe_ol, sizeof(uint32));
+
+ if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) {
+ DHD_ERROR(("%s: could not set toe_ol: ret=%d\n",
+ dhd_ifname(&dhd->pub, ifidx), ret));
+ return ret;
+ }
+
+ /* Enable toe globally only if any components are enabled. */
+
+ toe = (toe_ol != 0);
+
+ strcpy(buf, "toe");
+ memcpy(&buf[sizeof("toe")], &toe, sizeof(uint32));
+
+ if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) {
+ DHD_ERROR(("%s: could not set toe: ret=%d\n", dhd_ifname(&dhd->pub, ifidx), ret));
+ return ret;
+ }
+
+ return 0;
+}
+#endif /* TOE */
+
+#if defined(WL_CFG80211)
+void dhd_set_scb_probe(dhd_pub_t *dhd)
+{
+#define NUM_SCB_MAX_PROBE 3
+ int ret = 0;
+ wl_scb_probe_t scb_probe;
+ char iovbuf[WL_EVENTING_MASK_LEN + 12];
+
+ memset(&scb_probe, 0, sizeof(wl_scb_probe_t));
+
+ if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE)
+ return;
+
+ bcm_mkiovar("scb_probe", NULL, 0, iovbuf, sizeof(iovbuf));
+
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
+ DHD_ERROR(("%s: GET max_scb_probe failed\n", __FUNCTION__));
+
+ memcpy(&scb_probe, iovbuf, sizeof(wl_scb_probe_t));
+
+ scb_probe.scb_max_probe = NUM_SCB_MAX_PROBE;
+
+ bcm_mkiovar("scb_probe", (char *)&scb_probe,
+ sizeof(wl_scb_probe_t), iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
+ DHD_ERROR(("%s: max_scb_probe setting failed\n", __FUNCTION__));
+#undef NUM_SCB_MAX_PROBE
+ return;
+}
+#endif /* WL_CFG80211 */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
+static void
+dhd_ethtool_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info)
+{
+ dhd_info_t *dhd = DHD_DEV_INFO(net);
+
+ snprintf(info->driver, sizeof(info->driver), "wl");
+ snprintf(info->version, sizeof(info->version), "%lu", dhd->pub.drv_version);
+}
+
+struct ethtool_ops dhd_ethtool_ops = {
+ .get_drvinfo = dhd_ethtool_get_drvinfo
+};
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */
+
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2)
+static int
+dhd_ethtool(dhd_info_t *dhd, void *uaddr)
+{
+ struct ethtool_drvinfo info;
+ char drvname[sizeof(info.driver)];
+ uint32 cmd;
+#ifdef TOE
+ struct ethtool_value edata;
+ uint32 toe_cmpnt, csum_dir;
+ int ret;
+#endif
+
+ DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+
+ /* all ethtool calls start with a cmd word */
+ if (copy_from_user(&cmd, uaddr, sizeof (uint32)))
+ return -EFAULT;
+
+ switch (cmd) {
+ case ETHTOOL_GDRVINFO:
+ /* Copy out any request driver name */
+ if (copy_from_user(&info, uaddr, sizeof(info)))
+ return -EFAULT;
+ strncpy(drvname, info.driver, sizeof(info.driver));
+ drvname[sizeof(info.driver)-1] = '\0';
+
+ /* clear struct for return */
+ memset(&info, 0, sizeof(info));
+ info.cmd = cmd;
+
+ /* if dhd requested, identify ourselves */
+ if (strcmp(drvname, "?dhd") == 0) {
+ snprintf(info.driver, sizeof(info.driver), "dhd");
+ strncpy(info.version, EPI_VERSION_STR, sizeof(info.version) - 1);
+ info.version[sizeof(info.version) - 1] = '\0';
+ }
+
+ /* otherwise, require dongle to be up */
+ else if (!dhd->pub.up) {
+ DHD_ERROR(("%s: dongle is not up\n", __FUNCTION__));
+ return -ENODEV;
+ }
+
+ /* finally, report dongle driver type */
+ else if (dhd->pub.iswl)
+ snprintf(info.driver, sizeof(info.driver), "wl");
+ else
+ snprintf(info.driver, sizeof(info.driver), "xx");
+
+ snprintf(info.version, sizeof(info.version), "%lu", dhd->pub.drv_version);
+ if (copy_to_user(uaddr, &info, sizeof(info)))
+ return -EFAULT;
+ DHD_CTL(("%s: given %*s, returning %s\n", __FUNCTION__,
+ (int)sizeof(drvname), drvname, info.driver));
+ break;
+
+#ifdef TOE
+ /* Get toe offload components from dongle */
+ case ETHTOOL_GRXCSUM:
+ case ETHTOOL_GTXCSUM:
+ if ((ret = dhd_toe_get(dhd, 0, &toe_cmpnt)) < 0)
+ return ret;
+
+ csum_dir = (cmd == ETHTOOL_GTXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL;
+
+ edata.cmd = cmd;
+ edata.data = (toe_cmpnt & csum_dir) ? 1 : 0;
+
+ if (copy_to_user(uaddr, &edata, sizeof(edata)))
+ return -EFAULT;
+ break;
+
+ /* Set toe offload components in dongle */
+ case ETHTOOL_SRXCSUM:
+ case ETHTOOL_STXCSUM:
+ if (copy_from_user(&edata, uaddr, sizeof(edata)))
+ return -EFAULT;
+
+ /* Read the current settings, update and write back */
+ if ((ret = dhd_toe_get(dhd, 0, &toe_cmpnt)) < 0)
+ return ret;
+
+ csum_dir = (cmd == ETHTOOL_STXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL;
+
+ if (edata.data != 0)
+ toe_cmpnt |= csum_dir;
+ else
+ toe_cmpnt &= ~csum_dir;
+
+ if ((ret = dhd_toe_set(dhd, 0, toe_cmpnt)) < 0)
+ return ret;
+
+ /* If setting TX checksum mode, tell Linux the new mode */
+ if (cmd == ETHTOOL_STXCSUM) {
+ if (edata.data)
+ dhd->iflist[0]->net->features |= NETIF_F_IP_CSUM;
+ else
+ dhd->iflist[0]->net->features &= ~NETIF_F_IP_CSUM;
+ }
+
+ break;
+#endif /* TOE */
+
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) */
+
+static bool dhd_check_hang(struct net_device *net, dhd_pub_t *dhdp, int error)
+{
+ dhd_info_t *dhd;
+
+ if (!dhdp) {
+ DHD_ERROR(("%s: dhdp is NULL\n", __FUNCTION__));
+ return FALSE;
+ }
+
+ if (!dhdp->up)
+ return FALSE;
+
+ dhd = (dhd_info_t *)dhdp->info;
+#if !defined(BCMPCIE)
+ if (dhd->thr_dpc_ctl.thr_pid < 0) {
+ DHD_ERROR(("%s : skipped due to negative pid - unloading?\n", __FUNCTION__));
+ return FALSE;
+ }
+#endif
+
+#ifdef CONFIG_MACH_UNIVERSAL5433
+ /* old revision does not send hang message */
+ if ((check_rev() && (error == -ETIMEDOUT)) || (error == -EREMOTEIO) ||
+#else
+ if ((error == -ETIMEDOUT) || (error == -EREMOTEIO) ||
+#endif /* CONFIG_MACH_UNIVERSAL5433 */
+ ((dhdp->busstate == DHD_BUS_DOWN) && (!dhdp->dongle_reset))) {
+ DHD_ERROR(("%s: Event HANG send up due to re=%d te=%d e=%d s=%d\n", __FUNCTION__,
+ dhdp->rxcnt_timeout, dhdp->txcnt_timeout, error, dhdp->busstate));
+ net_os_send_hang_message(net);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+int dhd_ioctl_process(dhd_pub_t *pub, int ifidx, dhd_ioctl_t *ioc, void *data_buf)
+{
+ int bcmerror = BCME_OK;
+ int buflen = 0;
+ struct net_device *net;
+
+ net = dhd_idx2net(pub, ifidx);
+ if (!net) {
+ bcmerror = BCME_BADARG;
+ goto done;
+ }
+
+ if (data_buf)
+ buflen = MIN(ioc->len, DHD_IOCTL_MAXLEN);
+
+ /* check for local dhd ioctl and handle it */
+ if (ioc->driver == DHD_IOCTL_MAGIC) {
+ bcmerror = dhd_ioctl((void *)pub, ioc, data_buf, buflen);
+ if (bcmerror)
+ pub->bcmerror = bcmerror;
+ goto done;
+ }
+
+ /* send to dongle (must be up, and wl). */
+ if (pub->busstate != DHD_BUS_DATA) {
+ bcmerror = BCME_DONGLE_DOWN;
+ goto done;
+ }
+
+ if (!pub->iswl) {
+ bcmerror = BCME_DONGLE_DOWN;
+ goto done;
+ }
+
+ /*
+ * Flush the TX queue if required for proper message serialization:
+ * Intercept WLC_SET_KEY IOCTL - serialize M4 send and set key IOCTL to
+ * prevent M4 encryption and
+ * intercept WLC_DISASSOC IOCTL - serialize WPS-DONE and WLC_DISASSOC IOCTL to
+ * prevent disassoc frame being sent before WPS-DONE frame.
+ */
+ if (ioc->cmd == WLC_SET_KEY ||
+ (ioc->cmd == WLC_SET_VAR && data_buf != NULL &&
+ strncmp("wsec_key", data_buf, 9) == 0) ||
+ (ioc->cmd == WLC_SET_VAR && data_buf != NULL &&
+ strncmp("bsscfg:wsec_key", data_buf, 15) == 0) ||
+ ioc->cmd == WLC_DISASSOC)
+ dhd_wait_pend8021x(net);
+
+#ifdef WLMEDIA_HTSF
+ if (data_buf) {
+ /* short cut wl ioctl calls here */
+ if (strcmp("htsf", data_buf) == 0) {
+ dhd_ioctl_htsf_get(dhd, 0);
+ return BCME_OK;
+ }
+
+ if (strcmp("htsflate", data_buf) == 0) {
+ if (ioc->set) {
+ memset(ts, 0, sizeof(tstamp_t)*TSMAX);
+ memset(&maxdelayts, 0, sizeof(tstamp_t));
+ maxdelay = 0;
+ tspktcnt = 0;
+ maxdelaypktno = 0;
+ memset(&vi_d1.bin, 0, sizeof(uint32)*NUMBIN);
+ memset(&vi_d2.bin, 0, sizeof(uint32)*NUMBIN);
+ memset(&vi_d3.bin, 0, sizeof(uint32)*NUMBIN);
+ memset(&vi_d4.bin, 0, sizeof(uint32)*NUMBIN);
+ } else {
+ dhd_dump_latency();
+ }
+ return BCME_OK;
+ }
+ if (strcmp("htsfclear", data_buf) == 0) {
+ memset(&vi_d1.bin, 0, sizeof(uint32)*NUMBIN);
+ memset(&vi_d2.bin, 0, sizeof(uint32)*NUMBIN);
+ memset(&vi_d3.bin, 0, sizeof(uint32)*NUMBIN);
+ memset(&vi_d4.bin, 0, sizeof(uint32)*NUMBIN);
+ htsf_seqnum = 0;
+ return BCME_OK;
+ }
+ if (strcmp("htsfhis", data_buf) == 0) {
+ dhd_dump_htsfhisto(&vi_d1, "H to D");
+ dhd_dump_htsfhisto(&vi_d2, "D to D");
+ dhd_dump_htsfhisto(&vi_d3, "D to H");
+ dhd_dump_htsfhisto(&vi_d4, "H to H");
+ return BCME_OK;
+ }
+ if (strcmp("tsport", data_buf) == 0) {
+ if (ioc->set) {
+ memcpy(&tsport, data_buf + 7, 4);
+ } else {
+ DHD_ERROR(("current timestamp port: %d \n", tsport));
+ }
+ return BCME_OK;
+ }
+ }
+#endif /* WLMEDIA_HTSF */
+
+ if ((ioc->cmd == WLC_SET_VAR || ioc->cmd == WLC_GET_VAR) &&
+ data_buf != NULL && strncmp("rpc_", data_buf, 4) == 0) {
+#ifdef BCM_FD_AGGR
+ bcmerror = dhd_fdaggr_ioctl(pub, ifidx, (wl_ioctl_t *)ioc, data_buf, buflen);
+#else
+ bcmerror = BCME_UNSUPPORTED;
+#endif
+ goto done;
+ }
+ bcmerror = dhd_wl_ioctl(pub, ifidx, (wl_ioctl_t *)ioc, data_buf, buflen);
+
+done:
+ dhd_check_hang(net, pub, bcmerror);
+
+ return bcmerror;
+}
+
+static int
+dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd)
+{
+ dhd_info_t *dhd = DHD_DEV_INFO(net);
+ dhd_ioctl_t ioc;
+ int bcmerror = 0;
+ int ifidx;
+ int ret;
+ void *local_buf = NULL;
+ u16 buflen = 0;
+
+ DHD_OS_WAKE_LOCK(&dhd->pub);
+ DHD_PERIM_LOCK(&dhd->pub);
+
+ /* Interface up check for built-in type */
+ if (!dhd_download_fw_on_driverload && dhd->pub.up == 0) {
+ DHD_ERROR(("%s: Interface is down \n", __FUNCTION__));
+ DHD_PERIM_UNLOCK(&dhd->pub);
+ DHD_OS_WAKE_UNLOCK(&dhd->pub);
+ return BCME_NOTUP;
+ }
+
+ /* send to dongle only if we are not waiting for reload already */
+ if (dhd->pub.hang_was_sent) {
+ DHD_ERROR(("%s: HANG was sent up earlier\n", __FUNCTION__));
+ DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(&dhd->pub, DHD_EVENT_TIMEOUT_MS);
+ DHD_OS_WAKE_UNLOCK(&dhd->pub);
+ return OSL_ERROR(BCME_DONGLE_DOWN);
+ }
+
+ ifidx = dhd_net2idx(dhd, net);
+ DHD_TRACE(("%s: ifidx %d, cmd 0x%04x\n", __FUNCTION__, ifidx, cmd));
+
+ if (ifidx == DHD_BAD_IF) {
+ DHD_ERROR(("%s: BAD IF\n", __FUNCTION__));
+ DHD_PERIM_UNLOCK(&dhd->pub);
+ DHD_OS_WAKE_UNLOCK(&dhd->pub);
+ return -1;
+ }
+
+#if defined(WL_WIRELESS_EXT)
+ /* linux wireless extensions */
+ if ((cmd >= SIOCIWFIRST) && (cmd <= SIOCIWLAST)) {
+ /* may recurse, do NOT lock */
+ ret = wl_iw_ioctl(net, ifr, cmd);
+ DHD_PERIM_UNLOCK(&dhd->pub);
+ DHD_OS_WAKE_UNLOCK(&dhd->pub);
+ return ret;
+ }
+#endif /* defined(WL_WIRELESS_EXT) */
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2)
+ if (cmd == SIOCETHTOOL) {
+ ret = dhd_ethtool(dhd, (void*)ifr->ifr_data);
+ DHD_PERIM_UNLOCK(&dhd->pub);
+ DHD_OS_WAKE_UNLOCK(&dhd->pub);
+ return ret;
+ }
+#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) */
+
+ if (cmd == SIOCDEVPRIVATE+1) {
+ ret = wl_android_priv_cmd(net, ifr, cmd);
+ dhd_check_hang(net, &dhd->pub, ret);
+ DHD_OS_WAKE_UNLOCK(&dhd->pub);
+ return ret;
+ }
+
+ if (cmd != SIOCDEVPRIVATE) {
+ DHD_PERIM_UNLOCK(&dhd->pub);
+ DHD_OS_WAKE_UNLOCK(&dhd->pub);
+ return -EOPNOTSUPP;
+ }
+
+ memset(&ioc, 0, sizeof(ioc));
+
+#ifdef CONFIG_COMPAT
+ if (is_compat_task()) {
+ compat_wl_ioctl_t compat_ioc;
+ if (copy_from_user(&compat_ioc, ifr->ifr_data, sizeof(compat_wl_ioctl_t))) {
+ bcmerror = BCME_BADADDR;
+ goto done;
+ }
+ ioc.cmd = compat_ioc.cmd;
+ ioc.buf = compat_ptr(compat_ioc.buf);
+ ioc.len = compat_ioc.len;
+ ioc.set = compat_ioc.set;
+ ioc.used = compat_ioc.used;
+ ioc.needed = compat_ioc.needed;
+ /* To differentiate between wl and dhd read 4 more byes */
+ if ((copy_from_user(&ioc.driver, (char *)ifr->ifr_data + sizeof(compat_wl_ioctl_t),
+ sizeof(uint)) != 0)) {
+ bcmerror = BCME_BADADDR;
+ goto done;
+ }
+ } else
+#endif /* CONFIG_COMPAT */
+ {
+ /* Copy the ioc control structure part of ioctl request */
+ if (copy_from_user(&ioc, ifr->ifr_data, sizeof(wl_ioctl_t))) {
+ bcmerror = BCME_BADADDR;
+ goto done;
+ }
+
+ /* To differentiate between wl and dhd read 4 more byes */
+ if ((copy_from_user(&ioc.driver, (char *)ifr->ifr_data + sizeof(wl_ioctl_t),
+ sizeof(uint)) != 0)) {
+ bcmerror = BCME_BADADDR;
+ goto done;
+ }
+ }
+
+ if (!capable(CAP_NET_ADMIN)) {
+ bcmerror = BCME_EPERM;
+ goto done;
+ }
+
+ if (ioc.len > 0) {
+ buflen = MIN(ioc.len, DHD_IOCTL_MAXLEN);
+ if (!(local_buf = MALLOC(dhd->pub.osh, buflen+1))) {
+ bcmerror = BCME_NOMEM;
+ goto done;
+ }
+
+ DHD_PERIM_UNLOCK(&dhd->pub);
+ if (copy_from_user(local_buf, ioc.buf, buflen)) {
+ DHD_PERIM_LOCK(&dhd->pub);
+ bcmerror = BCME_BADADDR;
+ goto done;
+ }
+ DHD_PERIM_LOCK(&dhd->pub);
+
+ *(char *)(local_buf + buflen) = '\0';
+ }
+
+ bcmerror = dhd_ioctl_process(&dhd->pub, ifidx, &ioc, local_buf);
+
+ if (!bcmerror && buflen && local_buf && ioc.buf) {
+ DHD_PERIM_UNLOCK(&dhd->pub);
+ if (copy_to_user(ioc.buf, local_buf, buflen))
+ bcmerror = -EFAULT;
+ DHD_PERIM_LOCK(&dhd->pub);
+ }
+
+done:
+ if (local_buf)
+ MFREE(dhd->pub.osh, local_buf, buflen+1);
+
+ DHD_PERIM_UNLOCK(&dhd->pub);
+ DHD_OS_WAKE_UNLOCK(&dhd->pub);
+
+ return OSL_ERROR(bcmerror);
+}
+
+#define MAX_TRY_CNT 5 /* Number of tries to disable deepsleep */
+int dhd_deepsleep(dhd_info_t *dhd, int flag)
+{
+ char iovbuf[20];
+ uint powervar = 0;
+ dhd_pub_t *dhdp;
+ int cnt = 0;
+ int ret = 0;
+
+ dhdp = &dhd->pub;
+
+ switch (flag) {
+ case 1 : /* Deepsleep on */
+ DHD_ERROR(("dhd_deepsleep: ON\n"));
+ /* give some time to sysioc_work before deepsleep */
+ OSL_SLEEP(200);
+#ifdef PKT_FILTER_SUPPORT
+ /* disable pkt filter */
+ dhd_enable_packet_filter(0, dhdp);
+#endif /* PKT_FILTER_SUPPORT */
+ /* Disable MPC */
+ powervar = 0;
+ memset(iovbuf, 0, sizeof(iovbuf));
+ bcm_mkiovar("mpc", (char *)&powervar, 4, iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+
+ /* Enable Deepsleep */
+ powervar = 1;
+ memset(iovbuf, 0, sizeof(iovbuf));
+ bcm_mkiovar("deepsleep", (char *)&powervar, 4, iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+ break;
+
+ case 0: /* Deepsleep Off */
+ DHD_ERROR(("dhd_deepsleep: OFF\n"));
+
+ /* Disable Deepsleep */
+ for (cnt = 0; cnt < MAX_TRY_CNT; cnt++) {
+ powervar = 0;
+ memset(iovbuf, 0, sizeof(iovbuf));
+ bcm_mkiovar("deepsleep", (char *)&powervar, 4,
+ iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0);
+
+ memset(iovbuf, 0, sizeof(iovbuf));
+ bcm_mkiovar("deepsleep", (char *)&powervar, 4,
+ iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhdp, WLC_GET_VAR, iovbuf,
+ sizeof(iovbuf), FALSE, 0)) < 0) {
+ DHD_ERROR(("the error of dhd deepsleep status"
+ " ret value :%d\n", ret));
+ } else {
+ if (!(*(int *)iovbuf)) {
+ DHD_ERROR(("deepsleep mode is 0,"
+ " count: %d\n", cnt));
+ break;
+ }
+ }
+ }
+
+ /* Enable MPC */
+ powervar = 1;
+ memset(iovbuf, 0, sizeof(iovbuf));
+ bcm_mkiovar("mpc", (char *)&powervar, 4, iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+ break;
+ }
+
+ return 0;
+}
+
+static int
+dhd_stop(struct net_device *net)
+{
+ int ifidx = 0;
+ dhd_info_t *dhd = DHD_DEV_INFO(net);
+ DHD_OS_WAKE_LOCK(&dhd->pub);
+ DHD_PERIM_LOCK(&dhd->pub);
+ printf("%s: Enter %p\n", __FUNCTION__, net);
+ if (dhd->pub.up == 0) {
+ goto exit;
+ }
+
+ dhd_if_flush_sta(DHD_DEV_IFP(net));
+
+
+ ifidx = dhd_net2idx(dhd, net);
+ BCM_REFERENCE(ifidx);
+
+ /* Set state and stop OS transmissions */
+ netif_stop_queue(net);
+ dhd->pub.up = 0;
+
+#ifdef WL_CFG80211
+ if (ifidx == 0) {
+ wl_cfg80211_down(NULL);
+
+ /*
+ * For CFG80211: Clean up all the left over virtual interfaces
+ * when the primary Interface is brought down. [ifconfig wlan0 down]
+ */
+ if (!dhd_download_fw_on_driverload) {
+ if ((dhd->dhd_state & DHD_ATTACH_STATE_ADD_IF) &&
+ (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211)) {
+ int i;
+
+ dhd_net_if_lock_local(dhd);
+ for (i = 1; i < DHD_MAX_IFS; i++)
+ dhd_remove_if(&dhd->pub, i, FALSE);
+ dhd_net_if_unlock_local(dhd);
+ }
+ }
+ }
+#endif /* WL_CFG80211 */
+
+#ifdef PROP_TXSTATUS
+ dhd_wlfc_cleanup(&dhd->pub, NULL, 0);
+#endif
+ /* Stop the protocol module */
+ dhd_prot_stop(&dhd->pub);
+
+ OLD_MOD_DEC_USE_COUNT;
+exit:
+ if (ifidx == 0 && !dhd_download_fw_on_driverload)
+ wl_android_wifi_off(net);
+ else {
+ if (dhd->pub.conf->deepsleep)
+ dhd_deepsleep(dhd, 1);
+ }
+ dhd->pub.rxcnt_timeout = 0;
+ dhd->pub.txcnt_timeout = 0;
+
+ dhd->pub.hang_was_sent = 0;
+
+ /* Clear country spec for for built-in type driver */
+ if (!dhd_download_fw_on_driverload) {
+ dhd->pub.dhd_cspec.country_abbrev[0] = 0x00;
+ dhd->pub.dhd_cspec.rev = 0;
+ dhd->pub.dhd_cspec.ccode[0] = 0x00;
+ }
+
+ printf("%s: Exit\n", __FUNCTION__);
+ DHD_PERIM_UNLOCK(&dhd->pub);
+ DHD_OS_WAKE_UNLOCK(&dhd->pub);
+ return 0;
+}
+
+#if defined(WL_CFG80211) && defined(USE_INITIAL_SHORT_DWELL_TIME)
+extern bool g_first_broadcast_scan;
+#endif
+
+#ifdef WL11U
+static int dhd_interworking_enable(dhd_pub_t *dhd)
+{
+ char iovbuf[WLC_IOCTL_SMLEN];
+ uint32 enable = true;
+ int ret = BCME_OK;
+
+ bcm_mkiovar("interworking", (char *)&enable, sizeof(enable), iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s: enableing interworking failed, ret=%d\n", __FUNCTION__, ret));
+ }
+
+ if (ret == BCME_OK) {
+ /* basic capabilities for HS20 REL2 */
+ uint32 cap = WL_WNM_BSSTRANS | WL_WNM_NOTIF;
+ bcm_mkiovar("wnm", (char *)&cap, sizeof(cap), iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
+ iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s: failed to set WNM info, ret=%d\n", __FUNCTION__, ret));
+ }
+ }
+
+ return ret;
+}
+#endif /* WL11u */
+
+static int
+dhd_open(struct net_device *net)
+{
+ dhd_info_t *dhd = DHD_DEV_INFO(net);
+#ifdef TOE
+ uint32 toe_ol;
+#endif
+ int ifidx;
+ int32 ret = 0;
+
+ printf("%s: Enter %p\n", __FUNCTION__, net);
+#if defined(MULTIPLE_SUPPLICANT)
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1
+ if (mutex_is_locked(&_dhd_sdio_mutex_lock_) != 0) {
+ DHD_ERROR(("%s : dhd_open: call dev open before insmod complete!\n", __FUNCTION__));
+ }
+ mutex_lock(&_dhd_sdio_mutex_lock_);
+#endif
+#endif /* MULTIPLE_SUPPLICANT */
+
+ DHD_OS_WAKE_LOCK(&dhd->pub);
+ DHD_PERIM_LOCK(&dhd->pub);
+ dhd->pub.dongle_trap_occured = 0;
+ dhd->pub.hang_was_sent = 0;
+
+#if 0
+ /*
+ * Force start if ifconfig_up gets called before START command
+ * We keep WEXT's wl_control_wl_start to provide backward compatibility
+ * This should be removed in the future
+ */
+ ret = wl_control_wl_start(net);
+ if (ret != 0) {
+ DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret));
+ ret = -1;
+ goto exit;
+ }
+#endif
+
+ ifidx = dhd_net2idx(dhd, net);
+ DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx));
+
+ if (ifidx < 0) {
+ DHD_ERROR(("%s: Error: called with invalid IF\n", __FUNCTION__));
+ ret = -1;
+ goto exit;
+ }
+
+ if (!dhd->iflist[ifidx]) {
+ DHD_ERROR(("%s: Error: called when IF already deleted\n", __FUNCTION__));
+ ret = -1;
+ goto exit;
+ }
+
+ if (ifidx == 0) {
+ atomic_set(&dhd->pend_8021x_cnt, 0);
+ if (!dhd_download_fw_on_driverload) {
+ DHD_ERROR(("\n%s\n", dhd_version));
+#if defined(USE_INITIAL_SHORT_DWELL_TIME)
+ g_first_broadcast_scan = TRUE;
+#endif
+ ret = wl_android_wifi_on(net);
+ if (ret != 0) {
+ DHD_ERROR(("%s : wl_android_wifi_on failed (%d)\n",
+ __FUNCTION__, ret));
+ ret = -1;
+ goto exit;
+ }
+ }
+
+ if (dhd->pub.busstate != DHD_BUS_DATA) {
+
+ /* try to bring up bus */
+ DHD_PERIM_UNLOCK(&dhd->pub);
+ ret = dhd_bus_start(&dhd->pub);
+ DHD_PERIM_LOCK(&dhd->pub);
+ if (ret) {
+ DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret));
+ ret = -1;
+ goto exit;
+ }
+
+ }
+ if (dhd_download_fw_on_driverload) {
+ if (dhd->pub.conf->deepsleep)
+ dhd_deepsleep(dhd, 0);
+ }
+
+ /* dhd_sync_with_dongle has been called in dhd_bus_start or wl_android_wifi_on */
+ memcpy(net->dev_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN);
+
+#ifdef TOE
+ /* Get current TOE mode from dongle */
+ if (dhd_toe_get(dhd, ifidx, &toe_ol) >= 0 && (toe_ol & TOE_TX_CSUM_OL) != 0)
+ dhd->iflist[ifidx]->net->features |= NETIF_F_IP_CSUM;
+ else
+ dhd->iflist[ifidx]->net->features &= ~NETIF_F_IP_CSUM;
+#endif /* TOE */
+
+#if defined(WL_CFG80211)
+ if (unlikely(wl_cfg80211_up(NULL))) {
+ DHD_ERROR(("%s: failed to bring up cfg80211\n", __FUNCTION__));
+ ret = -1;
+ goto exit;
+ }
+ dhd_set_scb_probe(&dhd->pub);
+#endif /* WL_CFG80211 */
+ }
+
+ /* Allow transmit calls */
+ netif_start_queue(net);
+ dhd->pub.up = 1;
+
+#ifdef BCMDBGFS
+ dhd_dbg_init(&dhd->pub);
+#endif
+
+ OLD_MOD_INC_USE_COUNT;
+exit:
+ if (ret)
+ dhd_stop(net);
+
+ DHD_PERIM_UNLOCK(&dhd->pub);
+ DHD_OS_WAKE_UNLOCK(&dhd->pub);
+
+#if defined(MULTIPLE_SUPPLICANT)
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1
+ mutex_unlock(&_dhd_sdio_mutex_lock_);
+#endif
+#endif /* MULTIPLE_SUPPLICANT */
+
+ printf("%s: Exit ret=%d\n", __FUNCTION__, ret);
+ return ret;
+}
+
+int dhd_do_driver_init(struct net_device *net)
+{
+ dhd_info_t *dhd = NULL;
+
+ if (!net) {
+ DHD_ERROR(("Primary Interface not initialized \n"));
+ return -EINVAL;
+ }
+
+#ifdef MULTIPLE_SUPPLICANT
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 && defined(BCMSDIO)
+ if (mutex_is_locked(&_dhd_sdio_mutex_lock_) != 0) {
+ DHD_ERROR(("%s : dhdsdio_probe is already running!\n", __FUNCTION__));
+ return 0;
+ }
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
+#endif /* MULTIPLE_SUPPLICANT */
+
+ /* && defined(OEM_ANDROID) && defined(BCMSDIO) */
+ dhd = DHD_DEV_INFO(net);
+
+ /* If driver is already initialized, do nothing
+ */
+ if (dhd->pub.busstate == DHD_BUS_DATA) {
+ DHD_TRACE(("Driver already Inititalized. Nothing to do"));
+ return 0;
+ }
+
+ if (dhd_open(net) < 0) {
+ DHD_ERROR(("Driver Init Failed \n"));
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+dhd_event_ifadd(dhd_info_t *dhdinfo, wl_event_data_if_t *ifevent, char *name, uint8 *mac)
+{
+
+#ifdef WL_CFG80211
+ if (wl_cfg80211_notify_ifadd(ifevent->ifidx, name, mac, ifevent->bssidx) == BCME_OK)
+ return BCME_OK;
+#endif
+
+ /* handle IF event caused by wl commands, SoftAP, WEXT and
+ * anything else. This has to be done asynchronously otherwise
+ * DPC will be blocked (and iovars will timeout as DPC has no chance
+ * to read the response back)
+ */
+ if (ifevent->ifidx > 0) {
+ dhd_if_event_t *if_event = MALLOC(dhdinfo->pub.osh, sizeof(dhd_if_event_t));
+
+ memcpy(&if_event->event, ifevent, sizeof(if_event->event));
+ memcpy(if_event->mac, mac, ETHER_ADDR_LEN);
+ strncpy(if_event->name, name, IFNAMSIZ);
+ if_event->name[IFNAMSIZ - 1] = '\0';
+ dhd_deferred_schedule_work(dhdinfo->dhd_deferred_wq, (void *)if_event,
+ DHD_WQ_WORK_IF_ADD, dhd_ifadd_event_handler, DHD_WORK_PRIORITY_LOW);
+ }
+
+ return BCME_OK;
+}
+
+int
+dhd_event_ifdel(dhd_info_t *dhdinfo, wl_event_data_if_t *ifevent, char *name, uint8 *mac)
+{
+ dhd_if_event_t *if_event;
+
+#if defined(WL_CFG80211) && !defined(P2PONEINT)
+ if (wl_cfg80211_notify_ifdel(ifevent->ifidx, name, mac, ifevent->bssidx) == BCME_OK)
+ return BCME_OK;
+#endif /* WL_CFG80211 */
+
+ /* handle IF event caused by wl commands, SoftAP, WEXT and
+ * anything else
+ */
+ if_event = MALLOC(dhdinfo->pub.osh, sizeof(dhd_if_event_t));
+ memcpy(&if_event->event, ifevent, sizeof(if_event->event));
+ memcpy(if_event->mac, mac, ETHER_ADDR_LEN);
+ strncpy(if_event->name, name, IFNAMSIZ);
+ if_event->name[IFNAMSIZ - 1] = '\0';
+ dhd_deferred_schedule_work(dhdinfo->dhd_deferred_wq, (void *)if_event, DHD_WQ_WORK_IF_DEL,
+ dhd_ifdel_event_handler, DHD_WORK_PRIORITY_LOW);
+
+ return BCME_OK;
+}
+
+/* unregister and free the existing net_device interface (if any) in iflist and
+ * allocate a new one. the slot is reused. this function does NOT register the
+ * new interface to linux kernel. dhd_register_if does the job
+ */
+struct net_device*
+dhd_allocate_if(dhd_pub_t *dhdpub, int ifidx, char *name,
+ uint8 *mac, uint8 bssidx, bool need_rtnl_lock)
+{
+ dhd_info_t *dhdinfo = (dhd_info_t *)dhdpub->info;
+ dhd_if_t *ifp;
+
+ ASSERT(dhdinfo && (ifidx < DHD_MAX_IFS));
+ ifp = dhdinfo->iflist[ifidx];
+
+ if (ifp != NULL) {
+ if (ifp->net != NULL) {
+ DHD_ERROR(("%s: free existing IF %s\n", __FUNCTION__, ifp->net->name));
+
+ dhd_dev_priv_clear(ifp->net); /* clear net_device private */
+
+ /* in unregister_netdev case, the interface gets freed by net->destructor
+ * (which is set to free_netdev)
+ */
+ if (ifp->net->reg_state == NETREG_UNINITIALIZED) {
+ free_netdev(ifp->net);
+ } else {
+ netif_stop_queue(ifp->net);
+ if (need_rtnl_lock)
+ unregister_netdev(ifp->net);
+ else
+ unregister_netdevice(ifp->net);
+ }
+ ifp->net = NULL;
+ }
+ } else {
+ ifp = MALLOC(dhdinfo->pub.osh, sizeof(dhd_if_t));
+ if (ifp == NULL) {
+ DHD_ERROR(("%s: OOM - dhd_if_t(%zu)\n", __FUNCTION__, sizeof(dhd_if_t)));
+ return NULL;
+ }
+ }
+
+ memset(ifp, 0, sizeof(dhd_if_t));
+ ifp->info = dhdinfo;
+ ifp->idx = ifidx;
+ ifp->bssidx = bssidx;
+ if (mac != NULL)
+ memcpy(&ifp->mac_addr, mac, ETHER_ADDR_LEN);
+
+ /* Allocate etherdev, including space for private structure */
+ ifp->net = alloc_etherdev(DHD_DEV_PRIV_SIZE);
+ if (ifp->net == NULL) {
+ DHD_ERROR(("%s: OOM - alloc_etherdev(%zu)\n", __FUNCTION__, sizeof(dhdinfo)));
+ goto fail;
+ }
+
+ /* Setup the dhd interface's netdevice private structure. */
+ dhd_dev_priv_save(ifp->net, dhdinfo, ifp, ifidx);
+
+ if (name && name[0]) {
+ strncpy(ifp->net->name, name, IFNAMSIZ);
+ ifp->net->name[IFNAMSIZ - 1] = '\0';
+ }
+#ifdef WL_CFG80211
+ if (ifidx == 0)
+ ifp->net->destructor = free_netdev;
+ else
+ ifp->net->destructor = dhd_netdev_free;
+#else
+ ifp->net->destructor = free_netdev;
+#endif /* WL_CFG80211 */
+ strncpy(ifp->name, ifp->net->name, IFNAMSIZ);
+ ifp->name[IFNAMSIZ - 1] = '\0';
+ dhdinfo->iflist[ifidx] = ifp;
+
+#ifdef PCIE_FULL_DONGLE
+ /* Initialize STA info list */
+ INIT_LIST_HEAD(&ifp->sta_list);
+ DHD_IF_STA_LIST_LOCK_INIT(ifp);
+#endif /* PCIE_FULL_DONGLE */
+
+ return ifp->net;
+
+fail:
+ if (ifp != NULL) {
+ if (ifp->net != NULL) {
+ dhd_dev_priv_clear(ifp->net);
+ free_netdev(ifp->net);
+ ifp->net = NULL;
+ }
+ MFREE(dhdinfo->pub.osh, ifp, sizeof(*ifp));
+ ifp = NULL;
+ }
+ dhdinfo->iflist[ifidx] = NULL;
+ return NULL;
+}
+
+/* unregister and free the the net_device interface associated with the indexed
+ * slot, also free the slot memory and set the slot pointer to NULL
+ */
+int
+dhd_remove_if(dhd_pub_t *dhdpub, int ifidx, bool need_rtnl_lock)
+{
+ dhd_info_t *dhdinfo = (dhd_info_t *)dhdpub->info;
+ dhd_if_t *ifp;
+
+ ifp = dhdinfo->iflist[ifidx];
+ if (ifp != NULL) {
+ if (ifp->net != NULL) {
+ DHD_ERROR(("deleting interface '%s' idx %d\n", ifp->net->name, ifp->idx));
+
+ /* in unregister_netdev case, the interface gets freed by net->destructor
+ * (which is set to free_netdev)
+ */
+ if (ifp->net->reg_state == NETREG_UNINITIALIZED) {
+ free_netdev(ifp->net);
+ } else {
+ netif_stop_queue(ifp->net);
+
+
+
+#ifdef SET_RPS_CPUS
+ custom_rps_map_clear(ifp->net->_rx);
+#endif /* SET_RPS_CPUS */
+ if (need_rtnl_lock)
+ unregister_netdev(ifp->net);
+ else
+ unregister_netdevice(ifp->net);
+ }
+ ifp->net = NULL;
+ }
+#ifdef DHD_WMF
+ dhd_wmf_cleanup(dhdpub, ifidx);
+#endif /* DHD_WMF */
+
+ dhd_if_del_sta_list(ifp);
+
+ dhdinfo->iflist[ifidx] = NULL;
+ MFREE(dhdinfo->pub.osh, ifp, sizeof(*ifp));
+
+ }
+
+ return BCME_OK;
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31))
+static struct net_device_ops dhd_ops_pri = {
+ .ndo_open = dhd_open,
+ .ndo_stop = dhd_stop,
+ .ndo_get_stats = dhd_get_stats,
+ .ndo_do_ioctl = dhd_ioctl_entry,
+ .ndo_start_xmit = dhd_start_xmit,
+ .ndo_set_mac_address = dhd_set_mac_address,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
+ .ndo_set_rx_mode = dhd_set_multicast_list,
+#else
+ .ndo_set_multicast_list = dhd_set_multicast_list,
+#endif
+};
+
+static struct net_device_ops dhd_ops_virt = {
+ .ndo_get_stats = dhd_get_stats,
+ .ndo_do_ioctl = dhd_ioctl_entry,
+ .ndo_start_xmit = dhd_start_xmit,
+ .ndo_set_mac_address = dhd_set_mac_address,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
+ .ndo_set_rx_mode = dhd_set_multicast_list,
+#else
+ .ndo_set_multicast_list = dhd_set_multicast_list,
+#endif
+};
+
+#ifdef P2PONEINT
+extern int wl_cfgp2p_if_open(struct net_device *net);
+extern int wl_cfgp2p_if_stop(struct net_device *net);
+
+static struct net_device_ops dhd_cfgp2p_ops_virt = {
+ .ndo_open = wl_cfgp2p_if_open,
+ .ndo_stop = wl_cfgp2p_if_stop,
+ .ndo_get_stats = dhd_get_stats,
+ .ndo_do_ioctl = dhd_ioctl_entry,
+ .ndo_start_xmit = dhd_start_xmit,
+ .ndo_set_mac_address = dhd_set_mac_address,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
+ .ndo_set_rx_mode = dhd_set_multicast_list,
+#else
+ .ndo_set_multicast_list = dhd_set_multicast_list,
+#endif
+};
+#endif /* P2PONEINT */
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) */
+
+#ifdef DEBUGGER
+extern void debugger_init(void *bus_handle);
+#endif
+
+
+#ifdef SHOW_LOGTRACE
+static char *logstrs_path = "/root/logstrs.bin";
+module_param(logstrs_path, charp, S_IRUGO);
+
+int
+dhd_init_logstrs_array(dhd_event_log_t *temp)
+{
+ struct file *filep = NULL;
+ struct kstat stat;
+ mm_segment_t fs;
+ char *raw_fmts = NULL;
+ int logstrs_size = 0;
+
+ logstr_header_t *hdr = NULL;
+ uint32 *lognums = NULL;
+ char *logstrs = NULL;
+ int ram_index = 0;
+ char **fmts;
+ int num_fmts = 0;
+ uint32 i = 0;
+ int error = 0;
+ set_fs(KERNEL_DS);
+ fs = get_fs();
+ filep = filp_open(logstrs_path, O_RDONLY, 0);
+ if (IS_ERR(filep)) {
+ DHD_ERROR(("Failed to open the file logstrs.bin in %s\n", __FUNCTION__));
+ goto fail;
+ }
+ error = vfs_stat(logstrs_path, &stat);
+ if (error) {
+ DHD_ERROR(("Failed in %s to find file stat\n", __FUNCTION__));
+ goto fail;
+ }
+ logstrs_size = (int) stat.size;
+
+ raw_fmts = kmalloc(logstrs_size, GFP_KERNEL);
+ if (raw_fmts == NULL) {
+ DHD_ERROR(("Failed to allocate raw_fmts memory\n"));
+ goto fail;
+ }
+ if (vfs_read(filep, raw_fmts, logstrs_size, &filep->f_pos) != logstrs_size) {
+ DHD_ERROR(("Error: Log strings file read failed\n"));
+ goto fail;
+ }
+
+ /* Remember header from the logstrs.bin file */
+ hdr = (logstr_header_t *) (raw_fmts + logstrs_size -
+ sizeof(logstr_header_t));
+
+ if (hdr->log_magic == LOGSTRS_MAGIC) {
+ /*
+ * logstrs.bin start with header.
+ */
+ num_fmts = hdr->rom_logstrs_offset / sizeof(uint32);
+ ram_index = (hdr->ram_lognums_offset -
+ hdr->rom_lognums_offset) / sizeof(uint32);
+ lognums = (uint32 *) &raw_fmts[hdr->rom_lognums_offset];
+ logstrs = (char *) &raw_fmts[hdr->rom_logstrs_offset];
+ } else {
+ /*
+ * Legacy logstrs.bin format without header.
+ */
+ num_fmts = *((uint32 *) (raw_fmts)) / sizeof(uint32);
+ if (num_fmts == 0) {
+ /* Legacy ROM/RAM logstrs.bin format:
+ * - ROM 'lognums' section
+ * - RAM 'lognums' section
+ * - ROM 'logstrs' section.
+ * - RAM 'logstrs' section.
+ *
+ * 'lognums' is an array of indexes for the strings in the
+ * 'logstrs' section. The first uint32 is 0 (index of first
+ * string in ROM 'logstrs' section).
+ *
+ * The 4324b5 is the only ROM that uses this legacy format. Use the
+ * fixed number of ROM fmtnums to find the start of the RAM
+ * 'lognums' section. Use the fixed first ROM string ("Con\n") to
+ * find the ROM 'logstrs' section.
+ */
+ #define NUM_4324B5_ROM_FMTS 186
+ #define FIRST_4324B5_ROM_LOGSTR "Con\n"
+ ram_index = NUM_4324B5_ROM_FMTS;
+ lognums = (uint32 *) raw_fmts;
+ num_fmts = ram_index;
+ logstrs = (char *) &raw_fmts[num_fmts << 2];
+ while (strncmp(FIRST_4324B5_ROM_LOGSTR, logstrs, 4)) {
+ num_fmts++;
+ logstrs = (char *) &raw_fmts[num_fmts << 2];
+ }
+ } else {
+ /* Legacy RAM-only logstrs.bin format:
+ * - RAM 'lognums' section
+ * - RAM 'logstrs' section.
+ *
+ * 'lognums' is an array of indexes for the strings in the
+ * 'logstrs' section. The first uint32 is an index to the
+ * start of 'logstrs'. Therefore, if this index is divided
+ * by 'sizeof(uint32)' it provides the number of logstr
+ * entries.
+ */
+ ram_index = 0;
+ lognums = (uint32 *) raw_fmts;
+ logstrs = (char *) &raw_fmts[num_fmts << 2];
+ }
+ }
+ fmts = kmalloc(num_fmts * sizeof(char *), GFP_KERNEL);
+ if (fmts == NULL) {
+ DHD_ERROR(("Failed to allocate fmts memory\n"));
+ goto fail;
+ }
+
+ for (i = 0; i < num_fmts; i++) {
+ /* ROM lognums index into logstrs using 'rom_logstrs_offset' as a base
+ * (they are 0-indexed relative to 'rom_logstrs_offset').
+ *
+ * RAM lognums are already indexed to point to the correct RAM logstrs (they
+ * are 0-indexed relative to the start of the logstrs.bin file).
+ */
+ if (i == ram_index) {
+ logstrs = raw_fmts;
+ }
+ fmts[i] = &logstrs[lognums[i]];
+ }
+ temp->fmts = fmts;
+ temp->raw_fmts = raw_fmts;
+ temp->num_fmts = num_fmts;
+ filp_close(filep, NULL);
+ set_fs(fs);
+ return 0;
+fail:
+ if (raw_fmts) {
+ kfree(raw_fmts);
+ raw_fmts = NULL;
+ }
+ if (!IS_ERR(filep))
+ filp_close(filep, NULL);
+ set_fs(fs);
+ temp->fmts = NULL;
+ return -1;
+}
+#endif /* SHOW_LOGTRACE */
+
+
+dhd_pub_t *
+dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen)
+{
+ dhd_info_t *dhd = NULL;
+ struct net_device *net = NULL;
+ char if_name[IFNAMSIZ] = {'\0'};
+ uint32 bus_type = -1;
+ uint32 bus_num = -1;
+ uint32 slot_num = -1;
+ wifi_adapter_info_t *adapter = NULL;
+
+ dhd_attach_states_t dhd_state = DHD_ATTACH_STATE_INIT;
+ DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+
+ /* will implement get_ids for DBUS later */
+#if defined(BCMSDIO)
+ dhd_bus_get_ids(bus, &bus_type, &bus_num, &slot_num);
+#endif
+ adapter = dhd_wifi_platform_get_adapter(bus_type, bus_num, slot_num);
+
+ /* Allocate primary dhd_info */
+ dhd = wifi_platform_prealloc(adapter, DHD_PREALLOC_DHD_INFO, sizeof(dhd_info_t));
+ if (dhd == NULL) {
+ dhd = MALLOC(osh, sizeof(dhd_info_t));
+ if (dhd == NULL) {
+ DHD_ERROR(("%s: OOM - alloc dhd_info\n", __FUNCTION__));
+ goto fail;
+ }
+ }
+ memset(dhd, 0, sizeof(dhd_info_t));
+ dhd_state |= DHD_ATTACH_STATE_DHD_ALLOC;
+
+ dhd->unit = dhd_found + instance_base; /* do not increment dhd_found, yet */
+
+ dhd->pub.osh = osh;
+ dhd->adapter = adapter;
+
+#ifdef GET_CUSTOM_MAC_ENABLE
+ wifi_platform_get_mac_addr(dhd->adapter, dhd->pub.mac.octet);
+#endif /* GET_CUSTOM_MAC_ENABLE */
+ dhd->thr_dpc_ctl.thr_pid = DHD_PID_KT_TL_INVALID;
+ dhd->thr_wdt_ctl.thr_pid = DHD_PID_KT_INVALID;
+
+ /* Initialize thread based operation and lock */
+ sema_init(&dhd->sdsem, 1);
+
+ /* Link to info module */
+ dhd->pub.info = dhd;
+
+
+ /* Link to bus module */
+ dhd->pub.bus = bus;
+ dhd->pub.hdrlen = bus_hdrlen;
+
+ /* dhd_conf must be attached after linking dhd to dhd->pub.info,
+ * because dhd_detech will check .info is NULL or not.
+ */
+ if (dhd_conf_attach(&dhd->pub) != 0) {
+ DHD_ERROR(("dhd_conf_attach failed\n"));
+ goto fail;
+ }
+ dhd_conf_reset(&dhd->pub);
+ dhd_conf_set_chiprev(&dhd->pub, dhd_bus_chip(bus), dhd_bus_chiprev(bus));
+ dhd_conf_preinit(&dhd->pub);
+
+ /* Some DHD modules (e.g. cfg80211) configures operation mode based on firmware name.
+ * This is indeed a hack but we have to make it work properly before we have a better
+ * solution
+ */
+ dhd_update_fw_nv_path(dhd);
+#ifndef BUILD_IN_KERNEL
+ dhd_conf_read_config(&dhd->pub, dhd->conf_path);
+#endif
+
+ /* Set network interface name if it was provided as module parameter */
+ if (iface_name[0]) {
+ int len;
+ char ch;
+ strncpy(if_name, iface_name, IFNAMSIZ);
+ if_name[IFNAMSIZ - 1] = 0;
+ len = strlen(if_name);
+ ch = if_name[len - 1];
+ if ((ch > '9' || ch < '0') && (len < IFNAMSIZ - 2))
+ strcat(if_name, "%d");
+ }
+ net = dhd_allocate_if(&dhd->pub, 0, if_name, NULL, 0, TRUE);
+ if (net == NULL)
+ goto fail;
+ dhd_state |= DHD_ATTACH_STATE_ADD_IF;
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31))
+ net->open = NULL;
+#else
+ net->netdev_ops = NULL;
+#endif
+
+ sema_init(&dhd->proto_sem, 1);
+
+#ifdef PROP_TXSTATUS
+ spin_lock_init(&dhd->wlfc_spinlock);
+
+ dhd->pub.skip_fc = dhd_wlfc_skip_fc;
+ dhd->pub.plat_init = dhd_wlfc_plat_init;
+ dhd->pub.plat_deinit = dhd_wlfc_plat_deinit;
+#endif /* PROP_TXSTATUS */
+
+ /* Initialize other structure content */
+ init_waitqueue_head(&dhd->ioctl_resp_wait);
+ init_waitqueue_head(&dhd->ctrl_wait);
+
+ /* Initialize the spinlocks */
+ spin_lock_init(&dhd->sdlock);
+ spin_lock_init(&dhd->txqlock);
+ spin_lock_init(&dhd->dhd_lock);
+ spin_lock_init(&dhd->rxf_lock);
+#if defined(RXFRAME_THREAD)
+ dhd->rxthread_enabled = TRUE;
+#endif /* defined(RXFRAME_THREAD) */
+
+#ifdef DHDTCPACK_SUPPRESS
+ spin_lock_init(&dhd->tcpack_lock);
+#endif /* DHDTCPACK_SUPPRESS */
+
+ /* Initialize Wakelock stuff */
+ spin_lock_init(&dhd->wakelock_spinlock);
+ dhd->wakelock_counter = 0;
+ dhd->wakelock_wd_counter = 0;
+ dhd->wakelock_rx_timeout_enable = 0;
+ dhd->wakelock_ctrl_timeout_enable = 0;
+#ifdef CONFIG_HAS_WAKELOCK
+ wake_lock_init(&dhd->wl_wifi, WAKE_LOCK_SUSPEND, "wlan_wake");
+ wake_lock_init(&dhd->wl_rxwake, WAKE_LOCK_SUSPEND, "wlan_rx_wake");
+ wake_lock_init(&dhd->wl_ctrlwake, WAKE_LOCK_SUSPEND, "wlan_ctrl_wake");
+ wake_lock_init(&dhd->wl_wdwake, WAKE_LOCK_SUSPEND, "wlan_wd_wake");
+#ifdef BCMPCIE_OOB_HOST_WAKE
+ wake_lock_init(&dhd->wl_intrwake, WAKE_LOCK_SUSPEND, "wlan_oob_irq_wake");
+#endif /* BCMPCIE_OOB_HOST_WAKE */
+#endif /* CONFIG_HAS_WAKELOCK */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1
+ mutex_init(&dhd->dhd_net_if_mutex);
+ mutex_init(&dhd->dhd_suspend_mutex);
+#endif
+ dhd_state |= DHD_ATTACH_STATE_WAKELOCKS_INIT;
+
+ /* Attach and link in the protocol */
+ if (dhd_prot_attach(&dhd->pub) != 0) {
+ DHD_ERROR(("dhd_prot_attach failed\n"));
+ goto fail;
+ }
+ dhd_state |= DHD_ATTACH_STATE_PROT_ATTACH;
+
+#ifdef WL_CFG80211
+ /* Attach and link in the cfg80211 */
+ if (unlikely(wl_cfg80211_attach(net, &dhd->pub))) {
+ DHD_ERROR(("wl_cfg80211_attach failed\n"));
+ goto fail;
+ }
+
+ dhd_monitor_init(&dhd->pub);
+ dhd_state |= DHD_ATTACH_STATE_CFG80211;
+#endif
+#if defined(WL_WIRELESS_EXT)
+ /* Attach and link in the iw */
+ if (!(dhd_state & DHD_ATTACH_STATE_CFG80211)) {
+ if (wl_iw_attach(net, (void *)&dhd->pub) != 0) {
+ DHD_ERROR(("wl_iw_attach failed\n"));
+ goto fail;
+ }
+ dhd_state |= DHD_ATTACH_STATE_WL_ATTACH;
+ }
+#endif /* defined(WL_WIRELESS_EXT) */
+
+#ifdef SHOW_LOGTRACE
+ dhd_init_logstrs_array(&dhd->event_data);
+#endif /* SHOW_LOGTRACE */
+
+ if (dhd_sta_pool_init(&dhd->pub, DHD_MAX_STA) != BCME_OK) {
+ DHD_ERROR(("%s: Initializing %u sta\n", __FUNCTION__, DHD_MAX_STA));
+ goto fail;
+ }
+
+
+ /* Set up the watchdog timer */
+ init_timer(&dhd->timer);
+ dhd->timer.data = (ulong)dhd;
+ dhd->timer.function = dhd_watchdog;
+ dhd->default_wd_interval = dhd_watchdog_ms;
+
+ if (dhd_watchdog_prio >= 0) {
+ /* Initialize watchdog thread */
+ PROC_START(dhd_watchdog_thread, dhd, &dhd->thr_wdt_ctl, 0, "dhd_watchdog_thread");
+
+ } else {
+ dhd->thr_wdt_ctl.thr_pid = -1;
+ }
+
+#ifdef DEBUGGER
+ debugger_init((void *) bus);
+#endif
+
+ /* Set up the bottom half handler */
+ if (dhd_dpc_prio >= 0) {
+ /* Initialize DPC thread */
+ PROC_START(dhd_dpc_thread, dhd, &dhd->thr_dpc_ctl, 0, "dhd_dpc");
+ } else {
+ /* use tasklet for dpc */
+ tasklet_init(&dhd->tasklet, dhd_dpc, (ulong)dhd);
+ dhd->thr_dpc_ctl.thr_pid = -1;
+ }
+
+ if (dhd->rxthread_enabled) {
+ bzero(&dhd->pub.skbbuf[0], sizeof(void *) * MAXSKBPEND);
+ /* Initialize RXF thread */
+ PROC_START(dhd_rxf_thread, dhd, &dhd->thr_rxf_ctl, 0, "dhd_rxf");
+ }
+
+ dhd_state |= DHD_ATTACH_STATE_THREADS_CREATED;
+
+#if defined(CONFIG_PM_SLEEP)
+ if (!dhd_pm_notifier_registered) {
+ dhd_pm_notifier_registered = TRUE;
+ register_pm_notifier(&dhd_pm_notifier);
+ }
+#endif /* CONFIG_PM_SLEEP */
+
+#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
+ dhd->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 20;
+ dhd->early_suspend.suspend = dhd_early_suspend;
+ dhd->early_suspend.resume = dhd_late_resume;
+ register_early_suspend(&dhd->early_suspend);
+ dhd_state |= DHD_ATTACH_STATE_EARLYSUSPEND_DONE;
+#endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */
+
+#ifdef ARP_OFFLOAD_SUPPORT
+ dhd->pend_ipaddr = 0;
+ if (!dhd_inetaddr_notifier_registered) {
+ dhd_inetaddr_notifier_registered = TRUE;
+ register_inetaddr_notifier(&dhd_inetaddr_notifier);
+ }
+#endif /* ARP_OFFLOAD_SUPPORT */
+#ifdef CONFIG_IPV6
+ if (!dhd_inet6addr_notifier_registered) {
+ dhd_inet6addr_notifier_registered = TRUE;
+ register_inet6addr_notifier(&dhd_inet6addr_notifier);
+ }
+#endif
+ dhd->dhd_deferred_wq = dhd_deferred_work_init((void *)dhd);
+#ifdef DEBUG_CPU_FREQ
+ dhd->new_freq = alloc_percpu(int);
+ dhd->freq_trans.notifier_call = dhd_cpufreq_notifier;
+ cpufreq_register_notifier(&dhd->freq_trans, CPUFREQ_TRANSITION_NOTIFIER);
+#endif
+#ifdef DHDTCPACK_SUPPRESS
+#ifdef BCMSDIO
+ dhd_tcpack_suppress_set(&dhd->pub, TCPACK_SUP_DELAYTX);
+#elif defined(BCMPCIE)
+ dhd_tcpack_suppress_set(&dhd->pub, TCPACK_SUP_HOLD);
+#else
+ dhd_tcpack_suppress_set(&dhd->pub, TCPACK_SUP_OFF);
+#endif /* BCMSDIO */
+#endif /* DHDTCPACK_SUPPRESS */
+
+ dhd_state |= DHD_ATTACH_STATE_DONE;
+ dhd->dhd_state = dhd_state;
+
+ dhd_found++;
+#if defined(CUSTOMER_HW20) && defined(WLANAUDIO)
+ dhd_global = dhd;
+#endif /* CUSTOMER_HW20 && WLANAUDIO */
+ return &dhd->pub;
+
+fail:
+ if (dhd_state >= DHD_ATTACH_STATE_DHD_ALLOC) {
+ DHD_TRACE(("%s: Calling dhd_detach dhd_state 0x%x &dhd->pub %p\n",
+ __FUNCTION__, dhd_state, &dhd->pub));
+ dhd->dhd_state = dhd_state;
+ dhd_detach(&dhd->pub);
+ dhd_free(&dhd->pub);
+ }
+
+ return NULL;
+}
+
+int dhd_get_fw_mode(dhd_info_t *dhdinfo)
+{
+ if (strstr(dhdinfo->fw_path, "_apsta") != NULL)
+ return DHD_FLAG_HOSTAP_MODE;
+ if (strstr(dhdinfo->fw_path, "_p2p") != NULL)
+ return DHD_FLAG_P2P_MODE;
+ if (strstr(dhdinfo->fw_path, "_ibss") != NULL)
+ return DHD_FLAG_IBSS_MODE;
+ if (strstr(dhdinfo->fw_path, "_mfg") != NULL)
+ return DHD_FLAG_MFG_MODE;
+
+ return DHD_FLAG_STA_MODE;
+}
+
+bool dhd_update_fw_nv_path(dhd_info_t *dhdinfo)
+{
+ int fw_len;
+ int nv_len;
+ int conf_len;
+ const char *fw = NULL;
+ const char *nv = NULL;
+ const char *conf = NULL;
+ wifi_adapter_info_t *adapter = dhdinfo->adapter;
+
+
+ /* Update firmware and nvram path. The path may be from adapter info or module parameter
+ * The path from adapter info is used for initialization only (as it won't change).
+ *
+ * The firmware_path/nvram_path module parameter may be changed by the system at run
+ * time. When it changes we need to copy it to dhdinfo->fw_path. Also Android private
+ * command may change dhdinfo->fw_path. As such we need to clear the path info in
+ * module parameter after it is copied. We won't update the path until the module parameter
+ * is changed again (first character is not '\0')
+ */
+
+ /* set default firmware and nvram path for built-in type driver */
+// if (!dhd_download_fw_on_driverload) {
+#ifdef CONFIG_BCMDHD_FW_PATH
+ fw = CONFIG_BCMDHD_FW_PATH;
+#endif /* CONFIG_BCMDHD_FW_PATH */
+#ifdef CONFIG_BCMDHD_NVRAM_PATH
+ nv = CONFIG_BCMDHD_NVRAM_PATH;
+#endif /* CONFIG_BCMDHD_NVRAM_PATH */
+// }
+
+ /* check if we need to initialize the path */
+ if (dhdinfo->fw_path[0] == '\0') {
+ if (adapter && adapter->fw_path && adapter->fw_path[0] != '\0')
+ fw = adapter->fw_path;
+
+ }
+ if (dhdinfo->nv_path[0] == '\0') {
+ if (adapter && adapter->nv_path && adapter->nv_path[0] != '\0')
+ nv = adapter->nv_path;
+ }
+ if (dhdinfo->conf_path[0] == '\0') {
+ if (adapter && adapter->conf_path && adapter->conf_path[0] != '\0')
+ conf = adapter->conf_path;
+ }
+
+ /* Use module parameter if it is valid, EVEN IF the path has not been initialized
+ *
+ * TODO: need a solution for multi-chip, can't use the same firmware for all chips
+ */
+ if (firmware_path[0] != '\0')
+ fw = firmware_path;
+ if (nvram_path[0] != '\0')
+ nv = nvram_path;
+ if (config_path[0] != '\0')
+ conf = config_path;
+
+ if (fw && fw[0] != '\0') {
+ fw_len = strlen(fw);
+ if (fw_len >= sizeof(dhdinfo->fw_path)) {
+ DHD_ERROR(("fw path len exceeds max len of dhdinfo->fw_path\n"));
+ return FALSE;
+ }
+ strncpy(dhdinfo->fw_path, fw, sizeof(dhdinfo->fw_path));
+ if (dhdinfo->fw_path[fw_len-1] == '\n')
+ dhdinfo->fw_path[fw_len-1] = '\0';
+ }
+ if (nv && nv[0] != '\0') {
+ nv_len = strlen(nv);
+ if (nv_len >= sizeof(dhdinfo->nv_path)) {
+ DHD_ERROR(("nvram path len exceeds max len of dhdinfo->nv_path\n"));
+ return FALSE;
+ }
+ strncpy(dhdinfo->nv_path, nv, sizeof(dhdinfo->nv_path));
+ if (dhdinfo->nv_path[nv_len-1] == '\n')
+ dhdinfo->nv_path[nv_len-1] = '\0';
+ }
+ if (conf && conf[0] != '\0') {
+ conf_len = strlen(conf);
+ if (conf_len >= sizeof(dhdinfo->conf_path)) {
+ DHD_ERROR(("config path len exceeds max len of dhdinfo->conf_path\n"));
+ return FALSE;
+ }
+ strncpy(dhdinfo->conf_path, conf, sizeof(dhdinfo->conf_path));
+ if (dhdinfo->conf_path[conf_len-1] == '\n')
+ dhdinfo->conf_path[conf_len-1] = '\0';
+ }
+
+#if 0
+ /* clear the path in module parameter */
+ firmware_path[0] = '\0';
+ nvram_path[0] = '\0';
+ config_path[0] = '\0';
+#endif
+
+#ifndef BCMEMBEDIMAGE
+ /* fw_path and nv_path are not mandatory for BCMEMBEDIMAGE */
+ if (dhdinfo->fw_path[0] == '\0') {
+ DHD_ERROR(("firmware path not found\n"));
+ return FALSE;
+ }
+ if (dhdinfo->nv_path[0] == '\0') {
+ DHD_ERROR(("nvram path not found\n"));
+ return FALSE;
+ }
+ if (dhdinfo->conf_path[0] == '\0') {
+ dhd_conf_set_conf_path_by_nv_path(&dhdinfo->pub, dhdinfo->conf_path, dhdinfo->nv_path);
+ }
+#ifdef CONFIG_PATH_AUTO_SELECT
+ dhd_conf_set_conf_name_by_chip(&dhdinfo->pub, dhdinfo->conf_path);
+#endif
+#endif /* BCMEMBEDIMAGE */
+
+ return TRUE;
+}
+
+
+int
+dhd_bus_start(dhd_pub_t *dhdp)
+{
+ int ret = -1;
+ dhd_info_t *dhd = (dhd_info_t*)dhdp->info;
+ unsigned long flags;
+
+ ASSERT(dhd);
+
+ DHD_TRACE(("Enter %s:\n", __FUNCTION__));
+
+ DHD_PERIM_LOCK(dhdp);
+
+ /* try to download image and nvram to the dongle */
+ if (dhd->pub.busstate == DHD_BUS_DOWN && dhd_update_fw_nv_path(dhd)) {
+ DHD_INFO(("%s download fw %s, nv %s, conf %s\n",
+ __FUNCTION__, dhd->fw_path, dhd->nv_path, dhd->conf_path));
+ ret = dhd_bus_download_firmware(dhd->pub.bus, dhd->pub.osh,
+ dhd->fw_path, dhd->nv_path, dhd->conf_path);
+ if (ret < 0) {
+ DHD_ERROR(("%s: failed to download firmware %s\n",
+ __FUNCTION__, dhd->fw_path));
+ DHD_PERIM_UNLOCK(dhdp);
+ return ret;
+ }
+ }
+ if (dhd->pub.busstate != DHD_BUS_LOAD) {
+ DHD_PERIM_UNLOCK(dhdp);
+ return -ENETDOWN;
+ }
+
+ dhd_os_sdlock(dhdp);
+
+ /* Start the watchdog timer */
+ dhd->pub.tickcnt = 0;
+ dhd_os_wd_timer(&dhd->pub, dhd_watchdog_ms);
+
+ /* Bring up the bus */
+ if ((ret = dhd_bus_init(&dhd->pub, FALSE)) != 0) {
+
+ DHD_ERROR(("%s, dhd_bus_init failed %d\n", __FUNCTION__, ret));
+ dhd_os_sdunlock(dhdp);
+ DHD_PERIM_UNLOCK(dhdp);
+ return ret;
+ }
+#if defined(OOB_INTR_ONLY) || defined(BCMPCIE_OOB_HOST_WAKE)
+#if defined(BCMPCIE_OOB_HOST_WAKE)
+ dhd_os_sdunlock(dhdp);
+#endif /* BCMPCIE_OOB_HOST_WAKE */
+ /* Host registration for OOB interrupt */
+ if (dhd_bus_oob_intr_register(dhdp)) {
+ /* deactivate timer and wait for the handler to finish */
+#if !defined(BCMPCIE_OOB_HOST_WAKE)
+ DHD_GENERAL_LOCK(&dhd->pub, flags);
+ dhd->wd_timer_valid = FALSE;
+ DHD_GENERAL_UNLOCK(&dhd->pub, flags);
+ del_timer_sync(&dhd->timer);
+
+ dhd_os_sdunlock(dhdp);
+#endif /* BCMPCIE_OOB_HOST_WAKE */
+ DHD_PERIM_UNLOCK(dhdp);
+ DHD_OS_WD_WAKE_UNLOCK(&dhd->pub);
+ DHD_ERROR(("%s Host failed to register for OOB\n", __FUNCTION__));
+ return -ENODEV;
+ }
+
+#if defined(BCMPCIE_OOB_HOST_WAKE)
+ dhd_os_sdlock(dhdp);
+ dhd_bus_oob_intr_set(dhdp, TRUE);
+#else
+ /* Enable oob at firmware */
+ dhd_enable_oob_intr(dhd->pub.bus, TRUE);
+#endif /* BCMPCIE_OOB_HOST_WAKE */
+#elif defined(FORCE_WOWLAN)
+ /* Enable oob at firmware */
+ dhd_enable_oob_intr(dhd->pub.bus, TRUE);
+#endif
+#ifdef PCIE_FULL_DONGLE
+ {
+ uint8 txpush = 0;
+ uint32 num_flowrings; /* includes H2D common rings */
+ num_flowrings = dhd_bus_max_h2d_queues(dhd->pub.bus, &txpush);
+ DHD_ERROR(("%s: Initializing %u flowrings\n", __FUNCTION__,
+ num_flowrings));
+ if ((ret = dhd_flow_rings_init(&dhd->pub, num_flowrings)) != BCME_OK) {
+ dhd_os_sdunlock(dhdp);
+ DHD_PERIM_UNLOCK(dhdp);
+ return ret;
+ }
+ }
+#endif /* PCIE_FULL_DONGLE */
+
+ /* Do protocol initialization necessary for IOCTL/IOVAR */
+ dhd_prot_init(&dhd->pub);
+
+ /* If bus is not ready, can't come up */
+ if (dhd->pub.busstate != DHD_BUS_DATA) {
+ DHD_GENERAL_LOCK(&dhd->pub, flags);
+ dhd->wd_timer_valid = FALSE;
+ DHD_GENERAL_UNLOCK(&dhd->pub, flags);
+ del_timer_sync(&dhd->timer);
+ DHD_ERROR(("%s failed bus is not ready\n", __FUNCTION__));
+ dhd_os_sdunlock(dhdp);
+ DHD_PERIM_UNLOCK(dhdp);
+ DHD_OS_WD_WAKE_UNLOCK(&dhd->pub);
+ return -ENODEV;
+ }
+
+ dhd_os_sdunlock(dhdp);
+
+ /* Bus is ready, query any dongle information */
+ if ((ret = dhd_sync_with_dongle(&dhd->pub)) < 0) {
+ DHD_PERIM_UNLOCK(dhdp);
+ return ret;
+ }
+
+#ifdef ARP_OFFLOAD_SUPPORT
+ if (dhd->pend_ipaddr) {
+#ifdef AOE_IP_ALIAS_SUPPORT
+ aoe_update_host_ipv4_table(&dhd->pub, dhd->pend_ipaddr, TRUE, 0);
+#endif /* AOE_IP_ALIAS_SUPPORT */
+ dhd->pend_ipaddr = 0;
+ }
+#endif /* ARP_OFFLOAD_SUPPORT */
+
+ DHD_PERIM_UNLOCK(dhdp);
+ return 0;
+}
+
+#ifdef WLTDLS
+int _dhd_tdls_enable(dhd_pub_t *dhd, bool tdls_on, bool auto_on, struct ether_addr *mac)
+{
+ char iovbuf[WLC_IOCTL_SMLEN];
+ uint32 tdls = tdls_on;
+ int ret = 0;
+ uint32 tdls_auto_op = 0;
+ uint32 tdls_idle_time = CUSTOM_TDLS_IDLE_MODE_SETTING;
+ int32 tdls_rssi_high = CUSTOM_TDLS_RSSI_THRESHOLD_HIGH;
+ int32 tdls_rssi_low = CUSTOM_TDLS_RSSI_THRESHOLD_LOW;
+ BCM_REFERENCE(mac);
+ if (!FW_SUPPORTED(dhd, tdls))
+ return BCME_ERROR;
+
+ if (dhd->tdls_enable == tdls_on)
+ goto auto_mode;
+ bcm_mkiovar("tdls_enable", (char *)&tdls, sizeof(tdls), iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s: tdls %d failed %d\n", __FUNCTION__, tdls, ret));
+ goto exit;
+ }
+ dhd->tdls_enable = tdls_on;
+auto_mode:
+
+ tdls_auto_op = auto_on;
+ bcm_mkiovar("tdls_auto_op", (char *)&tdls_auto_op, sizeof(tdls_auto_op),
+ iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s: tdls_auto_op failed %d\n", __FUNCTION__, ret));
+ goto exit;
+ }
+
+ if (tdls_auto_op) {
+ bcm_mkiovar("tdls_idle_time", (char *)&tdls_idle_time,
+ sizeof(tdls_idle_time), iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s: tdls_idle_time failed %d\n", __FUNCTION__, ret));
+ goto exit;
+ }
+ bcm_mkiovar("tdls_rssi_high", (char *)&tdls_rssi_high, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s: tdls_rssi_high failed %d\n", __FUNCTION__, ret));
+ goto exit;
+ }
+ bcm_mkiovar("tdls_rssi_low", (char *)&tdls_rssi_low, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s: tdls_rssi_low failed %d\n", __FUNCTION__, ret));
+ goto exit;
+ }
+ }
+
+exit:
+ return ret;
+}
+
+int dhd_tdls_enable(struct net_device *dev, bool tdls_on, bool auto_on, struct ether_addr *mac)
+{
+ dhd_info_t *dhd = DHD_DEV_INFO(dev);
+ int ret = 0;
+ if (dhd)
+ ret = _dhd_tdls_enable(&dhd->pub, tdls_on, auto_on, mac);
+ else
+ ret = BCME_ERROR;
+ return ret;
+}
+#ifdef PCIE_FULL_DONGLE
+void dhd_tdls_update_peer_info(struct net_device *dev, bool connect, uint8 *da)
+{
+ dhd_info_t *dhd = DHD_DEV_INFO(dev);
+ dhd_pub_t *dhdp = (dhd_pub_t *)&dhd->pub;
+ tdls_peer_node_t *cur = dhdp->peer_tbl.node;
+ tdls_peer_node_t *new = NULL, *prev = NULL;
+ dhd_if_t *dhdif;
+ uint8 sa[ETHER_ADDR_LEN];
+ int ifidx = dhd_net2idx(dhd, dev);
+
+ if (ifidx == DHD_BAD_IF)
+ return;
+
+ dhdif = dhd->iflist[ifidx];
+ memcpy(sa, dhdif->mac_addr, ETHER_ADDR_LEN);
+
+ if (connect) {
+ while (cur != NULL) {
+ if (!memcmp(da, cur->addr, ETHER_ADDR_LEN)) {
+ DHD_ERROR(("%s: TDLS Peer exist already %d\n",
+ __FUNCTION__, __LINE__));
+ return;
+ }
+ cur = cur->next;
+ }
+
+ new = MALLOC(dhdp->osh, sizeof(tdls_peer_node_t));
+ if (new == NULL) {
+ DHD_ERROR(("%s: Failed to allocate memory\n", __FUNCTION__));
+ return;
+ }
+ memcpy(new->addr, da, ETHER_ADDR_LEN);
+ new->next = dhdp->peer_tbl.node;
+ dhdp->peer_tbl.node = new;
+ dhdp->peer_tbl.tdls_peer_count++;
+
+ } else {
+ while (cur != NULL) {
+ if (!memcmp(da, cur->addr, ETHER_ADDR_LEN)) {
+ dhd_flow_rings_delete_for_peer(dhdp, ifidx, da);
+ if (prev)
+ prev->next = cur->next;
+ else
+ dhdp->peer_tbl.node = cur->next;
+ MFREE(dhdp->osh, cur, sizeof(tdls_peer_node_t));
+ dhdp->peer_tbl.tdls_peer_count--;
+ return;
+ }
+ prev = cur;
+ cur = cur->next;
+ }
+ DHD_ERROR(("%s: TDLS Peer Entry Not found\n", __FUNCTION__));
+ }
+}
+#endif /* PCIE_FULL_DONGLE */
+#endif
+
+bool dhd_is_concurrent_mode(dhd_pub_t *dhd)
+{
+ if (!dhd)
+ return FALSE;
+
+ if (dhd->op_mode & DHD_FLAG_CONCURR_MULTI_CHAN_MODE)
+ return TRUE;
+ else if ((dhd->op_mode & DHD_FLAG_CONCURR_SINGLE_CHAN_MODE) ==
+ DHD_FLAG_CONCURR_SINGLE_CHAN_MODE)
+ return TRUE;
+ else
+ return FALSE;
+}
+#if !defined(AP) && defined(WLP2P)
+/* From Android JerryBean release, the concurrent mode is enabled by default and the firmware
+ * name would be fw_bcmdhd.bin. So we need to determine whether P2P is enabled in the STA
+ * firmware and accordingly enable concurrent mode (Apply P2P settings). SoftAP firmware
+ * would still be named as fw_bcmdhd_apsta.
+ */
+uint32
+dhd_get_concurrent_capabilites(dhd_pub_t *dhd)
+{
+ int32 ret = 0;
+ char buf[WLC_IOCTL_SMLEN];
+ bool mchan_supported = FALSE;
+ /* if dhd->op_mode is already set for HOSTAP and Manufacturing
+ * test mode, that means we only will use the mode as it is
+ */
+ if (dhd->op_mode & (DHD_FLAG_HOSTAP_MODE | DHD_FLAG_MFG_MODE))
+ return 0;
+ if (FW_SUPPORTED(dhd, vsdb)) {
+ mchan_supported = TRUE;
+ }
+ if (!FW_SUPPORTED(dhd, p2p)) {
+ DHD_TRACE(("Chip does not support p2p\n"));
+ return 0;
+ }
+ else {
+ /* Chip supports p2p but ensure that p2p is really implemented in firmware or not */
+ memset(buf, 0, sizeof(buf));
+ bcm_mkiovar("p2p", 0, 0, buf, sizeof(buf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf),
+ FALSE, 0)) < 0) {
+ DHD_ERROR(("%s: Get P2P failed (error=%d)\n", __FUNCTION__, ret));
+ return 0;
+ }
+ else {
+ if (buf[0] == 1) {
+ /* By default, chip supports single chan concurrency,
+ * now lets check for mchan
+ */
+ ret = DHD_FLAG_CONCURR_SINGLE_CHAN_MODE;
+ if (mchan_supported)
+ ret |= DHD_FLAG_CONCURR_MULTI_CHAN_MODE;
+#if defined(WL_ENABLE_P2P_IF) || defined(WL_CFG80211_P2P_DEV_IF)
+ /* For customer_hw4, although ICS,
+ * we still support concurrent mode
+ */
+ return ret;
+#else
+ return 0;
+#endif
+ }
+ }
+ }
+ return 0;
+}
+#endif
+
+#ifdef SUPPORT_AP_POWERSAVE
+#define RXCHAIN_PWRSAVE_PPS 10
+#define RXCHAIN_PWRSAVE_QUIET_TIME 10
+#define RXCHAIN_PWRSAVE_STAS_ASSOC_CHECK 0
+int dhd_set_ap_powersave(dhd_pub_t *dhdp, int ifidx, int enable)
+{
+ char iovbuf[128];
+ int32 pps = RXCHAIN_PWRSAVE_PPS;
+ int32 quiet_time = RXCHAIN_PWRSAVE_QUIET_TIME;
+ int32 stas_assoc_check = RXCHAIN_PWRSAVE_STAS_ASSOC_CHECK;
+
+ if (enable) {
+ bcm_mkiovar("rxchain_pwrsave_enable", (char *)&enable, 4, iovbuf, sizeof(iovbuf));
+ if (dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR,
+ iovbuf, sizeof(iovbuf), TRUE, 0) != BCME_OK) {
+ DHD_ERROR(("Failed to enable AP power save\n"));
+ }
+ bcm_mkiovar("rxchain_pwrsave_pps", (char *)&pps, 4, iovbuf, sizeof(iovbuf));
+ if (dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR,
+ iovbuf, sizeof(iovbuf), TRUE, 0) != BCME_OK) {
+ DHD_ERROR(("Failed to set pps\n"));
+ }
+ bcm_mkiovar("rxchain_pwrsave_quiet_time", (char *)&quiet_time,
+ 4, iovbuf, sizeof(iovbuf));
+ if (dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR,
+ iovbuf, sizeof(iovbuf), TRUE, 0) != BCME_OK) {
+ DHD_ERROR(("Failed to set quiet time\n"));
+ }
+ bcm_mkiovar("rxchain_pwrsave_stas_assoc_check", (char *)&stas_assoc_check,
+ 4, iovbuf, sizeof(iovbuf));
+ if (dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR,
+ iovbuf, sizeof(iovbuf), TRUE, 0) != BCME_OK) {
+ DHD_ERROR(("Failed to set stas assoc check\n"));
+ }
+ } else {
+ bcm_mkiovar("rxchain_pwrsave_enable", (char *)&enable, 4, iovbuf, sizeof(iovbuf));
+ if (dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR,
+ iovbuf, sizeof(iovbuf), TRUE, 0) != BCME_OK) {
+ DHD_ERROR(("Failed to disable AP power save\n"));
+ }
+ }
+
+ return 0;
+}
+#endif /* SUPPORT_AP_POWERSAVE */
+
+
+#if defined(READ_CONFIG_FROM_FILE)
+#include <linux/fs.h>
+#include <linux/ctype.h>
+
+#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base))
+bool PM_control = TRUE;
+
+static int dhd_preinit_proc(dhd_pub_t *dhd, int ifidx, char *name, char *value)
+{
+ int var_int;
+ wl_country_t cspec = {{0}, -1, {0}};
+ char *revstr;
+ char *endptr = NULL;
+ int iolen;
+ char smbuf[WLC_IOCTL_SMLEN*2];
+
+ if (!strcmp(name, "country")) {
+ revstr = strchr(value, '/');
+ if (revstr) {
+ cspec.rev = strtoul(revstr + 1, &endptr, 10);
+ memcpy(cspec.country_abbrev, value, WLC_CNTRY_BUF_SZ);
+ cspec.country_abbrev[2] = '\0';
+ memcpy(cspec.ccode, cspec.country_abbrev, WLC_CNTRY_BUF_SZ);
+ } else {
+ cspec.rev = -1;
+ memcpy(cspec.country_abbrev, value, WLC_CNTRY_BUF_SZ);
+ memcpy(cspec.ccode, value, WLC_CNTRY_BUF_SZ);
+ get_customized_country_code(dhd->info->adapter,
+ (char *)&cspec.country_abbrev, &cspec);
+ }
+ memset(smbuf, 0, sizeof(smbuf));
+ DHD_ERROR(("config country code is country : %s, rev : %d !!\n",
+ cspec.country_abbrev, cspec.rev));
+ iolen = bcm_mkiovar("country", (char*)&cspec, sizeof(cspec),
+ smbuf, sizeof(smbuf));
+ return dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
+ smbuf, iolen, TRUE, 0);
+ } else if (!strcmp(name, "roam_scan_period")) {
+ var_int = (int)simple_strtol(value, NULL, 0);
+ return dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_SCAN_PERIOD,
+ &var_int, sizeof(var_int), TRUE, 0);
+ } else if (!strcmp(name, "roam_delta")) {
+ struct {
+ int val;
+ int band;
+ } x;
+ x.val = (int)simple_strtol(value, NULL, 0);
+ /* x.band = WLC_BAND_AUTO; */
+ x.band = WLC_BAND_ALL;
+ return dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_DELTA, &x, sizeof(x), TRUE, 0);
+ } else if (!strcmp(name, "roam_trigger")) {
+ int ret = 0;
+
+ roam_trigger[0] = (int)simple_strtol(value, NULL, 0);
+ roam_trigger[1] = WLC_BAND_ALL;
+ ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_TRIGGER, &roam_trigger,
+ sizeof(roam_trigger), TRUE, 0);
+
+ return ret;
+ } else if (!strcmp(name, "PM")) {
+ int ret = 0;
+ var_int = (int)simple_strtol(value, NULL, 0);
+
+ ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_PM,
+ &var_int, sizeof(var_int), TRUE, 0);
+
+#if defined(CONFIG_PM_LOCK)
+ if (var_int == 0) {
+ g_pm_control = TRUE;
+ printk("%s var_int=%d don't control PM\n", __func__, var_int);
+ } else {
+ g_pm_control = FALSE;
+ printk("%s var_int=%d do control PM\n", __func__, var_int);
+ }
+#endif
+
+ return ret;
+ }
+#ifdef WLBTAMP
+ else if (!strcmp(name, "btamp_chan")) {
+ int btamp_chan;
+ int iov_len = 0;
+ char iovbuf[128];
+ int ret;
+
+ btamp_chan = (int)simple_strtol(value, NULL, 0);
+ iov_len = bcm_mkiovar("btamp_chan", (char *)&btamp_chan, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, 0) < 0))
+ DHD_ERROR(("%s btamp_chan=%d set failed code %d\n",
+ __FUNCTION__, btamp_chan, ret));
+ else
+ DHD_ERROR(("%s btamp_chan %d set success\n",
+ __FUNCTION__, btamp_chan));
+ }
+#endif /* WLBTAMP */
+ else if (!strcmp(name, "band")) {
+ int ret;
+ if (!strcmp(value, "auto"))
+ var_int = WLC_BAND_AUTO;
+ else if (!strcmp(value, "a"))
+ var_int = WLC_BAND_5G;
+ else if (!strcmp(value, "b"))
+ var_int = WLC_BAND_2G;
+ else if (!strcmp(value, "all"))
+ var_int = WLC_BAND_ALL;
+ else {
+ printk(" set band value should be one of the a or b or all\n");
+ var_int = WLC_BAND_AUTO;
+ }
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_BAND, &var_int,
+ sizeof(var_int), TRUE, 0)) < 0)
+ printk(" set band err=%d\n", ret);
+ return ret;
+ } else if (!strcmp(name, "cur_etheraddr")) {
+ struct ether_addr ea;
+ char buf[32];
+ uint iovlen;
+ int ret;
+
+ bcm_ether_atoe(value, &ea);
+
+ ret = memcmp(&ea.octet, dhd->mac.octet, ETHER_ADDR_LEN);
+ if (ret == 0) {
+ DHD_ERROR(("%s: Same Macaddr\n", __FUNCTION__));
+ return 0;
+ }
+
+ DHD_ERROR(("%s: Change Macaddr = %02X:%02X:%02X:%02X:%02X:%02X\n", __FUNCTION__,
+ ea.octet[0], ea.octet[1], ea.octet[2],
+ ea.octet[3], ea.octet[4], ea.octet[5]));
+
+ iovlen = bcm_mkiovar("cur_etheraddr", (char*)&ea, ETHER_ADDR_LEN, buf, 32);
+
+ ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, iovlen, TRUE, 0);
+ if (ret < 0) {
+ DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret));
+ return ret;
+ }
+ else {
+ memcpy(dhd->mac.octet, (void *)&ea, ETHER_ADDR_LEN);
+ return ret;
+ }
+ } else if (!strcmp(name, "lpc")) {
+ int ret = 0;
+ char buf[32];
+ uint iovlen;
+ var_int = (int)simple_strtol(value, NULL, 0);
+ if (dhd_wl_ioctl_cmd(dhd, WLC_DOWN, NULL, 0, TRUE, 0) < 0) {
+ DHD_ERROR(("%s: wl down failed\n", __FUNCTION__));
+ }
+ iovlen = bcm_mkiovar("lpc", (char *)&var_int, 4, buf, sizeof(buf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, iovlen, TRUE, 0)) < 0) {
+ DHD_ERROR(("%s Set lpc failed %d\n", __FUNCTION__, ret));
+ }
+ if (dhd_wl_ioctl_cmd(dhd, WLC_UP, NULL, 0, TRUE, 0) < 0) {
+ DHD_ERROR(("%s: wl up failed\n", __FUNCTION__));
+ }
+ return ret;
+ } else if (!strcmp(name, "vht_features")) {
+ int ret = 0;
+ char buf[32];
+ uint iovlen;
+ var_int = (int)simple_strtol(value, NULL, 0);
+
+ if (dhd_wl_ioctl_cmd(dhd, WLC_DOWN, NULL, 0, TRUE, 0) < 0) {
+ DHD_ERROR(("%s: wl down failed\n", __FUNCTION__));
+ }
+ iovlen = bcm_mkiovar("vht_features", (char *)&var_int, 4, buf, sizeof(buf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, iovlen, TRUE, 0)) < 0) {
+ DHD_ERROR(("%s Set vht_features failed %d\n", __FUNCTION__, ret));
+ }
+ if (dhd_wl_ioctl_cmd(dhd, WLC_UP, NULL, 0, TRUE, 0) < 0) {
+ DHD_ERROR(("%s: wl up failed\n", __FUNCTION__));
+ }
+ return ret;
+ } else {
+ uint iovlen;
+ char iovbuf[WLC_IOCTL_SMLEN];
+
+ /* wlu_iovar_setint */
+ var_int = (int)simple_strtol(value, NULL, 0);
+
+ /* Setup timeout bcn_timeout from dhd driver 4.217.48 */
+ if (!strcmp(name, "roam_off")) {
+ /* Setup timeout if Beacons are lost to report link down */
+ if (var_int) {
+ uint bcn_timeout = 2;
+ bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4,
+ iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+ }
+ }
+ /* Setup timeout bcm_timeout from dhd driver 4.217.48 */
+
+ DHD_INFO(("%s:[%s]=[%d]\n", __FUNCTION__, name, var_int));
+
+ iovlen = bcm_mkiovar(name, (char *)&var_int, sizeof(var_int),
+ iovbuf, sizeof(iovbuf));
+ return dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
+ iovbuf, iovlen, TRUE, 0);
+ }
+
+ return 0;
+}
+
+static int dhd_preinit_config(dhd_pub_t *dhd, int ifidx)
+{
+ mm_segment_t old_fs;
+ struct kstat stat;
+ struct file *fp = NULL;
+ unsigned int len;
+ char *buf = NULL, *p, *name, *value;
+ int ret = 0;
+ char *config_path;
+
+ config_path = CONFIG_BCMDHD_CONFIG_PATH;
+
+ if (!config_path)
+ {
+ printk(KERN_ERR "config_path can't read. \n");
+ return 0;
+ }
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+ if ((ret = vfs_stat(config_path, &stat))) {
+ set_fs(old_fs);
+ printk(KERN_ERR "%s: Failed to get information (%d)\n",
+ config_path, ret);
+ return ret;
+ }
+ set_fs(old_fs);
+
+ if (!(buf = MALLOC(dhd->osh, stat.size + 1))) {
+ printk(KERN_ERR "Failed to allocate memory %llu bytes\n", stat.size);
+ return -ENOMEM;
+ }
+
+ printk("dhd_preinit_config : config path : %s \n", config_path);
+
+ if (!(fp = dhd_os_open_image(config_path)) ||
+ (len = dhd_os_get_image_block(buf, stat.size, fp)) < 0)
+ goto err;
+
+ buf[stat.size] = '\0';
+ for (p = buf; *p; p++) {
+ if (isspace(*p))
+ continue;
+ for (name = p++; *p && !isspace(*p); p++) {
+ if (*p == '=') {
+ *p = '\0';
+ p++;
+ for (value = p; *p && !isspace(*p); p++);
+ *p = '\0';
+ if ((ret = dhd_preinit_proc(dhd, ifidx, name, value)) < 0) {
+ printk(KERN_ERR "%s: %s=%s\n",
+ bcmerrorstr(ret), name, value);
+ }
+ break;
+ }
+ }
+ }
+ ret = 0;
+
+out:
+ if (fp)
+ dhd_os_close_image(fp);
+ if (buf)
+ MFREE(dhd->osh, buf, stat.size+1);
+ return ret;
+
+err:
+ ret = -1;
+ goto out;
+}
+#endif /* READ_CONFIG_FROM_FILE */
+
+int
+dhd_preinit_ioctls(dhd_pub_t *dhd)
+{
+ int ret = 0;
+ char eventmask[WL_EVENTING_MASK_LEN];
+ char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */
+ uint32 buf_key_b4_m4 = 1;
+#ifndef WL_CFG80211
+ u32 up = 0;
+#endif
+ uint8 msglen;
+ eventmsgs_ext_t *eventmask_msg = NULL;
+ char* iov_buf = NULL;
+ int ret2 = 0;
+#ifdef WLAIBSS
+ aibss_bcn_force_config_t bcn_config;
+ uint32 aibss;
+#ifdef WLAIBSS_PS
+ uint32 aibss_ps;
+#endif /* WLAIBSS_PS */
+#endif /* WLAIBSS */
+#if defined(BCMSUP_4WAY_HANDSHAKE) && defined(WLAN_AKM_SUITE_FT_8021X)
+ uint32 sup_wpa = 0;
+#endif
+#if defined(CUSTOM_AMPDU_BA_WSIZE) || (defined(WLAIBSS) && \
+ defined(CUSTOM_IBSS_AMPDU_BA_WSIZE))
+ uint32 ampdu_ba_wsize = 0;
+#endif /* CUSTOM_AMPDU_BA_WSIZE ||(WLAIBSS && CUSTOM_IBSS_AMPDU_BA_WSIZE) */
+#if defined(CUSTOM_AMPDU_MPDU)
+ int32 ampdu_mpdu = 0;
+#endif
+#if defined(CUSTOM_AMPDU_RELEASE)
+ int32 ampdu_release = 0;
+#endif
+#if defined(CUSTOM_AMSDU_AGGSF)
+ int32 amsdu_aggsf = 0;
+#endif
+
+#if defined(BCMSDIO)
+#ifdef PROP_TXSTATUS
+ int wlfc_enable = TRUE;
+#ifndef DISABLE_11N
+ uint32 hostreorder = 1;
+ uint wl_down = 1;
+#endif /* DISABLE_11N */
+#endif /* PROP_TXSTATUS */
+#endif
+#ifdef PCIE_FULL_DONGLE
+ uint32 wl_ap_isolate;
+#endif /* PCIE_FULL_DONGLE */
+
+#ifdef DHD_ENABLE_LPC
+ uint32 lpc = 1;
+#endif /* DHD_ENABLE_LPC */
+ uint power_mode = PM_FAST;
+ uint32 dongle_align = DHD_SDALIGN;
+#if defined(BCMSDIO)
+ uint32 glom = CUSTOM_GLOM_SETTING;
+#endif /* defined(BCMSDIO) */
+#if defined(CUSTOMER_HW2) && defined(USE_WL_CREDALL)
+ uint32 credall = 1;
+#endif
+ uint bcn_timeout = dhd->conf->bcn_timeout;
+ uint retry_max = 3;
+#if defined(ARP_OFFLOAD_SUPPORT)
+ int arpoe = 1;
+#endif
+ int scan_assoc_time = DHD_SCAN_ASSOC_ACTIVE_TIME;
+ int scan_unassoc_time = DHD_SCAN_UNASSOC_ACTIVE_TIME;
+ int scan_passive_time = DHD_SCAN_PASSIVE_TIME;
+ char buf[WLC_IOCTL_SMLEN];
+ char *ptr;
+ uint32 listen_interval = CUSTOM_LISTEN_INTERVAL; /* Default Listen Interval in Beacons */
+#ifdef ROAM_ENABLE
+ uint roamvar = 0;
+ int roam_trigger[2] = {CUSTOM_ROAM_TRIGGER_SETTING, WLC_BAND_ALL};
+ int roam_scan_period[2] = {10, WLC_BAND_ALL};
+ int roam_delta[2] = {CUSTOM_ROAM_DELTA_SETTING, WLC_BAND_ALL};
+#ifdef FULL_ROAMING_SCAN_PERIOD_60_SEC
+ int roam_fullscan_period = 60;
+#else /* FULL_ROAMING_SCAN_PERIOD_60_SEC */
+ int roam_fullscan_period = 120;
+#endif /* FULL_ROAMING_SCAN_PERIOD_60_SEC */
+#else
+#ifdef DISABLE_BUILTIN_ROAM
+ uint roamvar = 1;
+#endif /* DISABLE_BUILTIN_ROAM */
+#endif /* ROAM_ENABLE */
+
+#if defined(SOFTAP)
+ uint dtim = 1;
+#endif
+#if (defined(AP) && !defined(WLP2P)) || (!defined(AP) && defined(WL_CFG80211))
+ uint32 mpc = 0; /* Turn MPC off for AP/APSTA mode */
+ struct ether_addr p2p_ea;
+#endif
+#ifdef BCMCCX
+ uint32 ccx = 1;
+#endif
+#ifdef SOFTAP_UAPSD_OFF
+ uint32 wme_apsd = 0;
+#endif /* SOFTAP_UAPSD_OFF */
+#if (defined(AP) || defined(WLP2P)) && !defined(SOFTAP_AND_GC)
+ uint32 apsta = 1; /* Enable APSTA mode */
+#elif defined(SOFTAP_AND_GC)
+ uint32 apsta = 0;
+ int ap_mode = 1;
+#endif /* (defined(AP) || defined(WLP2P)) && !defined(SOFTAP_AND_GC) */
+#ifdef GET_CUSTOM_MAC_ENABLE
+ struct ether_addr ea_addr;
+#endif /* GET_CUSTOM_MAC_ENABLE */
+
+#ifdef DISABLE_11N
+ uint32 nmode = 0;
+#endif /* DISABLE_11N */
+
+#if defined(DISABLE_11AC)
+ uint32 vhtmode = 0;
+#endif /* DISABLE_11AC */
+#ifdef USE_WL_TXBF
+ uint32 txbf = 1;
+#endif /* USE_WL_TXBF */
+#ifdef AMPDU_VO_ENABLE
+ struct ampdu_tid_control tid;
+#endif
+#ifdef USE_WL_FRAMEBURST
+ uint32 frameburst = 1;
+#endif /* USE_WL_FRAMEBURST */
+#ifdef DHD_SET_FW_HIGHSPEED
+ uint32 ack_ratio = 250;
+ uint32 ack_ratio_depth = 64;
+#endif /* DHD_SET_FW_HIGHSPEED */
+#ifdef SUPPORT_2G_VHT
+ uint32 vht_features = 0x3; /* 2G enable | rates all */
+#endif /* SUPPORT_2G_VHT */
+#ifdef CUSTOM_PSPRETEND_THR
+ uint32 pspretend_thr = CUSTOM_PSPRETEND_THR;
+#endif
+#ifdef PKT_FILTER_SUPPORT
+ dhd_pkt_filter_enable = TRUE;
+#endif /* PKT_FILTER_SUPPORT */
+#ifdef WLTDLS
+ dhd->tdls_enable = FALSE;
+#endif /* WLTDLS */
+ dhd->suspend_bcn_li_dtim = CUSTOM_SUSPEND_BCN_LI_DTIM;
+ DHD_TRACE(("Enter %s\n", __FUNCTION__));
+
+ dhd_conf_set_fw_int_cmd(dhd, "WLC_SET_BAND", WLC_SET_BAND, dhd->conf->band, 0, FALSE);
+#ifdef DHDTCPACK_SUPPRESS
+ printf("%s: Set tcpack_sup_mode %d\n", __FUNCTION__, dhd->conf->tcpack_sup_mode);
+ dhd_tcpack_suppress_set(dhd, dhd->conf->tcpack_sup_mode);
+#endif
+
+ dhd->op_mode = 0;
+ if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_MFG_MODE) ||
+ (op_mode == DHD_FLAG_MFG_MODE)) {
+ /* Check and adjust IOCTL response timeout for Manufactring firmware */
+ dhd_os_set_ioctl_resp_timeout(MFG_IOCTL_RESP_TIMEOUT);
+ DHD_ERROR(("%s : Set IOCTL response time for Manufactring Firmware\n",
+ __FUNCTION__));
+ }
+ else {
+ dhd_os_set_ioctl_resp_timeout(IOCTL_RESP_TIMEOUT);
+ DHD_INFO(("%s : Set IOCTL response time.\n", __FUNCTION__));
+ }
+#ifdef GET_CUSTOM_MAC_ENABLE
+ ret = wifi_platform_get_mac_addr(dhd->info->adapter, ea_addr.octet);
+ if (!ret) {
+ memset(buf, 0, sizeof(buf));
+ bcm_mkiovar("cur_etheraddr", (void *)&ea_addr, ETHER_ADDR_LEN, buf, sizeof(buf));
+ ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0);
+ if (ret < 0) {
+ DHD_ERROR(("%s: can't set MAC address MAC="MACDBG", error=%d\n",
+ __FUNCTION__, MAC2STRDBG(ea_addr.octet), ret));
+ ret = BCME_NOTUP;
+ goto done;
+ }
+ memcpy(dhd->mac.octet, ea_addr.octet, ETHER_ADDR_LEN);
+ } else {
+#endif /* GET_CUSTOM_MAC_ENABLE */
+ /* Get the default device MAC address directly from firmware */
+ memset(buf, 0, sizeof(buf));
+ bcm_mkiovar("cur_etheraddr", 0, 0, buf, sizeof(buf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf),
+ FALSE, 0)) < 0) {
+ DHD_ERROR(("%s: can't get MAC address , error=%d\n", __FUNCTION__, ret));
+ ret = BCME_NOTUP;
+ goto done;
+ }
+ /* Update public MAC address after reading from Firmware */
+ memcpy(dhd->mac.octet, buf, ETHER_ADDR_LEN);
+
+#ifdef GET_CUSTOM_MAC_ENABLE
+ }
+#endif /* GET_CUSTOM_MAC_ENABLE */
+
+ /* get a capabilities from firmware */
+ memset(dhd->fw_capabilities, 0, sizeof(dhd->fw_capabilities));
+ bcm_mkiovar("cap", 0, 0, dhd->fw_capabilities, sizeof(dhd->fw_capabilities));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, dhd->fw_capabilities,
+ sizeof(dhd->fw_capabilities), FALSE, 0)) < 0) {
+ DHD_ERROR(("%s: Get Capability failed (error=%d)\n",
+ __FUNCTION__, ret));
+ goto done;
+ }
+ if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_HOSTAP_MODE) ||
+ (op_mode == DHD_FLAG_HOSTAP_MODE)) {
+#ifdef SET_RANDOM_MAC_SOFTAP
+ uint rand_mac;
+#endif
+ dhd->op_mode = DHD_FLAG_HOSTAP_MODE;
+#if defined(ARP_OFFLOAD_SUPPORT)
+ arpoe = 0;
+#endif
+#ifdef PKT_FILTER_SUPPORT
+ dhd_pkt_filter_enable = FALSE;
+#endif
+#ifdef SET_RANDOM_MAC_SOFTAP
+ SRANDOM32((uint)jiffies);
+ rand_mac = RANDOM32();
+ iovbuf[0] = 0x02; /* locally administered bit */
+ iovbuf[1] = 0x1A;
+ iovbuf[2] = 0x11;
+ iovbuf[3] = (unsigned char)(rand_mac & 0x0F) | 0xF0;
+ iovbuf[4] = (unsigned char)(rand_mac >> 8);
+ iovbuf[5] = (unsigned char)(rand_mac >> 16);
+
+ bcm_mkiovar("cur_etheraddr", (void *)iovbuf, ETHER_ADDR_LEN, buf, sizeof(buf));
+ ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0);
+ if (ret < 0) {
+ DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret));
+ } else
+ memcpy(dhd->mac.octet, iovbuf, ETHER_ADDR_LEN);
+#endif /* SET_RANDOM_MAC_SOFTAP */
+#if !defined(AP) && defined(WL_CFG80211)
+ /* Turn off MPC in AP mode */
+ bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s mpc for HostAPD failed %d\n", __FUNCTION__, ret));
+ }
+#endif
+#ifdef SUPPORT_AP_POWERSAVE
+ dhd_set_ap_powersave(dhd, 0, TRUE);
+#endif
+#ifdef SOFTAP_UAPSD_OFF
+ bcm_mkiovar("wme_apsd", (char *)&wme_apsd, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
+ DHD_ERROR(("%s: set wme_apsd 0 fail (error=%d)\n", __FUNCTION__, ret));
+#endif /* SOFTAP_UAPSD_OFF */
+ } else if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_MFG_MODE) ||
+ (op_mode == DHD_FLAG_MFG_MODE)) {
+#if defined(ARP_OFFLOAD_SUPPORT)
+ arpoe = 0;
+#endif /* ARP_OFFLOAD_SUPPORT */
+#ifdef PKT_FILTER_SUPPORT
+ dhd_pkt_filter_enable = FALSE;
+#endif /* PKT_FILTER_SUPPORT */
+ dhd->op_mode = DHD_FLAG_MFG_MODE;
+ } else {
+ uint32 concurrent_mode = 0;
+ if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_P2P_MODE) ||
+ (op_mode == DHD_FLAG_P2P_MODE)) {
+#if defined(ARP_OFFLOAD_SUPPORT)
+ arpoe = 0;
+#endif
+#ifdef PKT_FILTER_SUPPORT
+ dhd_pkt_filter_enable = FALSE;
+#endif
+ dhd->op_mode = DHD_FLAG_P2P_MODE;
+ } else if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_IBSS_MODE) ||
+ (op_mode == DHD_FLAG_IBSS_MODE)) {
+ dhd->op_mode = DHD_FLAG_IBSS_MODE;
+ } else
+ dhd->op_mode = DHD_FLAG_STA_MODE;
+#if !defined(AP) && defined(WLP2P)
+ if (dhd->op_mode != DHD_FLAG_IBSS_MODE &&
+ (concurrent_mode = dhd_get_concurrent_capabilites(dhd))) {
+#if defined(ARP_OFFLOAD_SUPPORT)
+ arpoe = 1;
+#endif
+ dhd->op_mode |= concurrent_mode;
+ }
+
+ /* Check if we are enabling p2p */
+ if (dhd->op_mode & DHD_FLAG_P2P_MODE) {
+ bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
+ iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s APSTA for P2P failed ret= %d\n", __FUNCTION__, ret));
+ }
+
+#if defined(SOFTAP_AND_GC)
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_AP,
+ (char *)&ap_mode, sizeof(ap_mode), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s WLC_SET_AP failed %d\n", __FUNCTION__, ret));
+ }
+#endif
+ memcpy(&p2p_ea, &dhd->mac, ETHER_ADDR_LEN);
+ ETHER_SET_LOCALADDR(&p2p_ea);
+ bcm_mkiovar("p2p_da_override", (char *)&p2p_ea,
+ ETHER_ADDR_LEN, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
+ iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s p2p_da_override ret= %d\n", __FUNCTION__, ret));
+ } else {
+ DHD_INFO(("dhd_preinit_ioctls: p2p_da_override succeeded\n"));
+ }
+ }
+#else
+ (void)concurrent_mode;
+#endif
+ }
+
+ DHD_ERROR(("Firmware up: op_mode=0x%04x, MAC="MACDBG"\n",
+ dhd->op_mode, MAC2STRDBG(dhd->mac.octet)));
+ /* Set Country code */
+ if (dhd->dhd_cspec.ccode[0] != 0) {
+ printf("Set country %s, revision %d\n", dhd->dhd_cspec.ccode, dhd->dhd_cspec.rev);
+ bcm_mkiovar("country", (char *)&dhd->dhd_cspec,
+ sizeof(wl_country_t), iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
+ printf("%s: country code setting failed %d\n", __FUNCTION__, ret);
+ } else {
+ dhd_conf_set_country(dhd);
+ dhd_conf_fix_country(dhd);
+ }
+ dhd_conf_get_country(dhd, &dhd->dhd_cspec);
+
+#if defined(DISABLE_11AC)
+ bcm_mkiovar("vhtmode", (char *)&vhtmode, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
+ DHD_ERROR(("%s wl vhtmode 0 failed %d\n", __FUNCTION__, ret));
+#endif /* DISABLE_11AC */
+ dhd_conf_set_fw_string_cmd(dhd, "vhtmode", dhd->conf->vhtmode, 0, TRUE);
+
+ /* Set Listen Interval */
+ bcm_mkiovar("assoc_listen", (char *)&listen_interval, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
+ DHD_ERROR(("%s assoc_listen failed %d\n", __FUNCTION__, ret));
+
+#if defined(ROAM_ENABLE) || defined(DISABLE_BUILTIN_ROAM)
+ /* Disable built-in roaming to allowed ext supplicant to take care of roaming */
+ bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+#endif /* ROAM_ENABLE || DISABLE_BUILTIN_ROAM */
+#if defined(ROAM_ENABLE)
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_TRIGGER, roam_trigger,
+ sizeof(roam_trigger), TRUE, 0)) < 0)
+ DHD_ERROR(("%s: roam trigger set failed %d\n", __FUNCTION__, ret));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_SCAN_PERIOD, roam_scan_period,
+ sizeof(roam_scan_period), TRUE, 0)) < 0)
+ DHD_ERROR(("%s: roam scan period set failed %d\n", __FUNCTION__, ret));
+ if ((dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_DELTA, roam_delta,
+ sizeof(roam_delta), TRUE, 0)) < 0)
+ DHD_ERROR(("%s: roam delta set failed %d\n", __FUNCTION__, ret));
+ bcm_mkiovar("fullroamperiod", (char *)&roam_fullscan_period, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
+ DHD_ERROR(("%s: roam fullscan period set failed %d\n", __FUNCTION__, ret));
+#endif /* ROAM_ENABLE */
+ dhd_conf_set_roam(dhd);
+
+#ifdef BCMCCX
+ bcm_mkiovar("ccx_enable", (char *)&ccx, 4, iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+#endif /* BCMCCX */
+#ifdef WLTDLS
+ /* by default TDLS on and auto mode off */
+ _dhd_tdls_enable(dhd, true, false, NULL);
+#endif /* WLTDLS */
+
+#ifdef DHD_ENABLE_LPC
+ /* Set lpc 1 */
+ bcm_mkiovar("lpc", (char *)&lpc, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s Set lpc failed %d\n", __FUNCTION__, ret));
+ }
+#endif /* DHD_ENABLE_LPC */
+ dhd_conf_set_fw_string_cmd(dhd, "lpc", dhd->conf->lpc, 0, FALSE);
+
+ /* Set PowerSave mode */
+ if (dhd->conf->pm >= 0)
+ power_mode = dhd->conf->pm;
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, sizeof(power_mode), TRUE, 0);
+
+ /* Match Host and Dongle rx alignment */
+ bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+
+#if defined(CUSTOMER_HW2) && defined(USE_WL_CREDALL)
+ /* enable credall to reduce the chance of no bus credit happened. */
+ bcm_mkiovar("bus:credall", (char *)&credall, 4, iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+#endif
+
+#if defined(BCMSDIO)
+ if (glom != DEFAULT_GLOM_VALUE) {
+ DHD_INFO(("%s set glom=0x%X\n", __FUNCTION__, glom));
+ bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+ }
+#endif /* defined(BCMSDIO) */
+
+ /* Setup timeout if Beacons are lost and roam is off to report link down */
+ bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+ /* Setup assoc_retry_max count to reconnect target AP in dongle */
+ bcm_mkiovar("assoc_retry_max", (char *)&retry_max, 4, iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+#if defined(AP) && !defined(WLP2P)
+ /* Turn off MPC in AP mode */
+ bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+ bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+#endif /* defined(AP) && !defined(WLP2P) */
+ /* 0:HT20 in ALL, 1:HT40 in ALL, 2: HT20 in 2G HT40 in 5G */
+ dhd_conf_set_fw_string_cmd(dhd, "mimo_bw_cap", dhd->conf->mimo_bw_cap, 1, TRUE);
+ dhd_conf_set_fw_string_cmd(dhd, "force_wme_ac", dhd->conf->force_wme_ac, 1, FALSE);
+ dhd_conf_set_fw_string_cmd(dhd, "stbc_tx", dhd->conf->stbc, 0, FALSE);
+ dhd_conf_set_fw_string_cmd(dhd, "stbc_rx", dhd->conf->stbc, 0, FALSE);
+ dhd_conf_set_fw_int_cmd(dhd, "WLC_SET_SRL", WLC_SET_SRL, dhd->conf->srl, 0, TRUE);
+ dhd_conf_set_fw_int_cmd(dhd, "WLC_SET_LRL", WLC_SET_LRL, dhd->conf->lrl, 0, FALSE);
+ dhd_conf_set_fw_int_cmd(dhd, "WLC_SET_SPECT_MANAGMENT", WLC_SET_SPECT_MANAGMENT, dhd->conf->spect, 0, FALSE);
+ dhd_conf_set_fw_string_cmd(dhd, "rsdb_mode", dhd->conf->rsdb_mode, -1, TRUE);
+
+#if defined(SOFTAP)
+ if (ap_fw_loaded == TRUE) {
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_DTIMPRD, (char *)&dtim, sizeof(dtim), TRUE, 0);
+ }
+#endif
+
+#if defined(KEEP_ALIVE)
+ {
+ /* Set Keep Alive : be sure to use FW with -keepalive */
+ int res;
+
+#if defined(SOFTAP)
+ if (ap_fw_loaded == FALSE)
+#endif
+ if (!(dhd->op_mode &
+ (DHD_FLAG_HOSTAP_MODE | DHD_FLAG_MFG_MODE))) {
+ if ((res = dhd_keep_alive_onoff(dhd)) < 0)
+ DHD_ERROR(("%s set keeplive failed %d\n",
+ __FUNCTION__, res));
+ }
+ }
+#endif /* defined(KEEP_ALIVE) */
+
+#ifdef USE_WL_TXBF
+ bcm_mkiovar("txbf", (char *)&txbf, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s Set txbf failed %d\n", __FUNCTION__, ret));
+ }
+#endif /* USE_WL_TXBF */
+ dhd_conf_set_fw_string_cmd(dhd, "txbf", dhd->conf->txbf, 0, FALSE);
+#ifdef USE_WL_FRAMEBURST
+ /* Set frameburst to value */
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_FAKEFRAG, (char *)&frameburst,
+ sizeof(frameburst), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s Set frameburst failed %d\n", __FUNCTION__, ret));
+ }
+#endif /* USE_WL_FRAMEBURST */
+ dhd_conf_set_fw_string_cmd(dhd, "frameburst", dhd->conf->frameburst, 0, FALSE);
+#ifdef DHD_SET_FW_HIGHSPEED
+ /* Set ack_ratio */
+ bcm_mkiovar("ack_ratio", (char *)&ack_ratio, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s Set ack_ratio failed %d\n", __FUNCTION__, ret));
+ }
+
+ /* Set ack_ratio_depth */
+ bcm_mkiovar("ack_ratio_depth", (char *)&ack_ratio_depth, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s Set ack_ratio_depth failed %d\n", __FUNCTION__, ret));
+ }
+#endif /* DHD_SET_FW_HIGHSPEED */
+#if defined(CUSTOM_AMPDU_BA_WSIZE) || (defined(WLAIBSS) && \
+ defined(CUSTOM_IBSS_AMPDU_BA_WSIZE))
+ /* Set ampdu ba wsize to 64 or 16 */
+#ifdef CUSTOM_AMPDU_BA_WSIZE
+ ampdu_ba_wsize = CUSTOM_AMPDU_BA_WSIZE;
+#endif
+#if defined(WLAIBSS) && defined(CUSTOM_IBSS_AMPDU_BA_WSIZE)
+ if (dhd->op_mode == DHD_FLAG_IBSS_MODE)
+ ampdu_ba_wsize = CUSTOM_IBSS_AMPDU_BA_WSIZE;
+#endif /* WLAIBSS && CUSTOM_IBSS_AMPDU_BA_WSIZE */
+ if (ampdu_ba_wsize != 0) {
+ bcm_mkiovar("ampdu_ba_wsize", (char *)&ampdu_ba_wsize, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s Set ampdu_ba_wsize to %d failed %d\n",
+ __FUNCTION__, ampdu_ba_wsize, ret));
+ }
+ }
+#endif /* CUSTOM_AMPDU_BA_WSIZE || (WLAIBSS && CUSTOM_IBSS_AMPDU_BA_WSIZE) */
+ dhd_conf_set_fw_string_cmd(dhd, "ampdu_ba_wsize", dhd->conf->ampdu_ba_wsize, 1, FALSE);
+
+ iov_buf = (char*)kmalloc(WLC_IOCTL_SMLEN, GFP_KERNEL);
+ if (iov_buf == NULL) {
+ DHD_ERROR(("failed to allocate %d bytes for iov_buf\n", WLC_IOCTL_SMLEN));
+ ret = BCME_NOMEM;
+ goto done;
+ }
+#ifdef WLAIBSS
+ /* Configure custom IBSS beacon transmission */
+ if (dhd->op_mode & DHD_FLAG_IBSS_MODE)
+ {
+ aibss = 1;
+ bcm_mkiovar("aibss", (char *)&aibss, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s Set aibss to %d failed %d\n",
+ __FUNCTION__, aibss, ret));
+ }
+#ifdef WLAIBSS_PS
+ aibss_ps = 1;
+ bcm_mkiovar("aibss_ps", (char *)&aibss_ps, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s Set aibss PS to %d failed %d\n",
+ __FUNCTION__, aibss, ret));
+ }
+#endif /* WLAIBSS_PS */
+ }
+ memset(&bcn_config, 0, sizeof(bcn_config));
+ bcn_config.initial_min_bcn_dur = AIBSS_INITIAL_MIN_BCN_DUR;
+ bcn_config.min_bcn_dur = AIBSS_MIN_BCN_DUR;
+ bcn_config.bcn_flood_dur = AIBSS_BCN_FLOOD_DUR;
+ bcn_config.version = AIBSS_BCN_FORCE_CONFIG_VER_0;
+ bcn_config.len = sizeof(bcn_config);
+
+ bcm_mkiovar("aibss_bcn_force_config", (char *)&bcn_config,
+ sizeof(aibss_bcn_force_config_t), iov_buf, WLC_IOCTL_SMLEN);
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iov_buf,
+ WLC_IOCTL_SMLEN, TRUE, 0)) < 0) {
+ DHD_ERROR(("%s Set aibss_bcn_force_config to %d, %d, %d failed %d\n",
+ __FUNCTION__, AIBSS_INITIAL_MIN_BCN_DUR, AIBSS_MIN_BCN_DUR,
+ AIBSS_BCN_FLOOD_DUR, ret));
+ }
+#endif /* WLAIBSS */
+
+#if defined(CUSTOM_AMPDU_MPDU)
+ ampdu_mpdu = CUSTOM_AMPDU_MPDU;
+ if (ampdu_mpdu != 0 && (ampdu_mpdu <= ampdu_ba_wsize)) {
+ bcm_mkiovar("ampdu_mpdu", (char *)&ampdu_mpdu, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s Set ampdu_mpdu to %d failed %d\n",
+ __FUNCTION__, CUSTOM_AMPDU_MPDU, ret));
+ }
+ }
+#endif /* CUSTOM_AMPDU_MPDU */
+
+#if defined(CUSTOM_AMPDU_RELEASE)
+ ampdu_release = CUSTOM_AMPDU_RELEASE;
+ if (ampdu_release != 0 && (ampdu_release <= ampdu_ba_wsize)) {
+ bcm_mkiovar("ampdu_release", (char *)&ampdu_release, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s Set ampdu_release to %d failed %d\n",
+ __FUNCTION__, CUSTOM_AMPDU_RELEASE, ret));
+ }
+ }
+#endif /* CUSTOM_AMPDU_RELEASE */
+
+#if defined(CUSTOM_AMSDU_AGGSF)
+ amsdu_aggsf = CUSTOM_AMSDU_AGGSF;
+ if (amsdu_aggsf != 0) {
+ bcm_mkiovar("amsdu_aggsf", (char *)&amsdu_aggsf, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s Set amsdu_aggsf to %d failed %d\n",
+ __FUNCTION__, CUSTOM_AMSDU_AGGSF, ret));
+ }
+ }
+#endif /* CUSTOM_AMSDU_AGGSF */
+
+#if defined(BCMSUP_4WAY_HANDSHAKE) && defined(WLAN_AKM_SUITE_FT_8021X)
+ /* Read 4-way handshake requirements */
+ if (dhd_use_idsup == 1) {
+ bcm_mkiovar("sup_wpa", (char *)&sup_wpa, 4, iovbuf, sizeof(iovbuf));
+ ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0);
+ /* sup_wpa iovar returns NOTREADY status on some platforms using modularized
+ * in-dongle supplicant.
+ */
+ if (ret >= 0 || ret == BCME_NOTREADY)
+ dhd->fw_4way_handshake = TRUE;
+ DHD_TRACE(("4-way handshake mode is: %d\n", dhd->fw_4way_handshake));
+ }
+#endif /* BCMSUP_4WAY_HANDSHAKE && WLAN_AKM_SUITE_FT_8021X */
+#ifdef SUPPORT_2G_VHT
+ bcm_mkiovar("vht_features", (char *)&vht_features, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s vht_features set failed %d\n", __FUNCTION__, ret));
+ }
+#endif /* SUPPORT_2G_VHT */
+#ifdef CUSTOM_PSPRETEND_THR
+ /* Turn off MPC in AP mode */
+ bcm_mkiovar("pspretend_threshold", (char *)&pspretend_thr, 4,
+ iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s pspretend_threshold for HostAPD failed %d\n",
+ __FUNCTION__, ret));
+ }
+#endif
+
+ bcm_mkiovar("buf_key_b4_m4", (char *)&buf_key_b4_m4, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s buf_key_b4_m4 set failed %d\n", __FUNCTION__, ret));
+ }
+
+ /* Read event_msgs mask */
+ bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0)) < 0) {
+ DHD_ERROR(("%s read Event mask failed %d\n", __FUNCTION__, ret));
+ goto done;
+ }
+ bcopy(iovbuf, eventmask, WL_EVENTING_MASK_LEN);
+
+ /* Setup event_msgs */
+ setbit(eventmask, WLC_E_SET_SSID);
+ setbit(eventmask, WLC_E_PRUNE);
+ setbit(eventmask, WLC_E_AUTH);
+ setbit(eventmask, WLC_E_AUTH_IND);
+ setbit(eventmask, WLC_E_ASSOC);
+ setbit(eventmask, WLC_E_REASSOC);
+ setbit(eventmask, WLC_E_REASSOC_IND);
+ setbit(eventmask, WLC_E_DEAUTH);
+ setbit(eventmask, WLC_E_DEAUTH_IND);
+ setbit(eventmask, WLC_E_DISASSOC_IND);
+ setbit(eventmask, WLC_E_DISASSOC);
+ setbit(eventmask, WLC_E_JOIN);
+ setbit(eventmask, WLC_E_START);
+ setbit(eventmask, WLC_E_ASSOC_IND);
+ setbit(eventmask, WLC_E_PSK_SUP);
+ setbit(eventmask, WLC_E_LINK);
+ setbit(eventmask, WLC_E_NDIS_LINK);
+ setbit(eventmask, WLC_E_MIC_ERROR);
+ setbit(eventmask, WLC_E_ASSOC_REQ_IE);
+ setbit(eventmask, WLC_E_ASSOC_RESP_IE);
+#ifndef WL_CFG80211
+ setbit(eventmask, WLC_E_PMKID_CACHE);
+ setbit(eventmask, WLC_E_TXFAIL);
+#endif
+ setbit(eventmask, WLC_E_JOIN_START);
+// setbit(eventmask, WLC_E_SCAN_COMPLETE); // terence 20150628: remove redundant event
+#ifdef WLMEDIA_HTSF
+ setbit(eventmask, WLC_E_HTSFSYNC);
+#endif /* WLMEDIA_HTSF */
+#ifdef PNO_SUPPORT
+ setbit(eventmask, WLC_E_PFN_NET_FOUND);
+ setbit(eventmask, WLC_E_PFN_BEST_BATCHING);
+ setbit(eventmask, WLC_E_PFN_BSSID_NET_FOUND);
+ setbit(eventmask, WLC_E_PFN_BSSID_NET_LOST);
+#endif /* PNO_SUPPORT */
+ /* enable dongle roaming event */
+ setbit(eventmask, WLC_E_ROAM);
+ setbit(eventmask, WLC_E_BSSID);
+#ifdef BCMCCX
+ setbit(eventmask, WLC_E_ADDTS_IND);
+ setbit(eventmask, WLC_E_DELTS_IND);
+#endif /* BCMCCX */
+#ifdef WLTDLS
+ setbit(eventmask, WLC_E_TDLS_PEER_EVENT);
+#endif /* WLTDLS */
+#ifdef WL_CFG80211
+ setbit(eventmask, WLC_E_ESCAN_RESULT);
+ if (dhd->op_mode & DHD_FLAG_P2P_MODE) {
+ setbit(eventmask, WLC_E_ACTION_FRAME_RX);
+ setbit(eventmask, WLC_E_P2P_DISC_LISTEN_COMPLETE);
+ }
+#endif /* WL_CFG80211 */
+#ifdef WLAIBSS
+ setbit(eventmask, WLC_E_AIBSS_TXFAIL);
+#endif /* WLAIBSS */
+#ifdef CUSTOMER_HW10
+ clrbit(eventmask, WLC_E_TRACE);
+#else
+ setbit(eventmask, WLC_E_TRACE);
+#endif
+ /* Write updated Event mask */
+ bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s Set Event mask failed %d\n", __FUNCTION__, ret));
+ goto done;
+ }
+
+ /* make up event mask ext message iovar for event larger than 128 */
+ msglen = ROUNDUP(WLC_E_LAST, NBBY)/NBBY + EVENTMSGS_EXT_STRUCT_SIZE;
+ eventmask_msg = (eventmsgs_ext_t*)kmalloc(msglen, GFP_KERNEL);
+ if (eventmask_msg == NULL) {
+ DHD_ERROR(("failed to allocate %d bytes for event_msg_ext\n", msglen));
+ ret = BCME_NOMEM;
+ goto done;
+ }
+ bzero(eventmask_msg, msglen);
+ eventmask_msg->ver = EVENTMSGS_VER;
+ eventmask_msg->len = ROUNDUP(WLC_E_LAST, NBBY)/NBBY;
+
+ /* Read event_msgs_ext mask */
+ bcm_mkiovar("event_msgs_ext", (char *)eventmask_msg, msglen, iov_buf, WLC_IOCTL_SMLEN);
+ ret2 = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iov_buf, WLC_IOCTL_SMLEN, FALSE, 0);
+ if (ret2 != BCME_UNSUPPORTED)
+ ret = ret2;
+ if (ret2 == 0) { /* event_msgs_ext must be supported */
+ bcopy(iov_buf, eventmask_msg, msglen);
+
+#ifdef BT_WIFI_HANDOVER
+ setbit(eventmask_msg->mask, WLC_E_BT_WIFI_HANDOVER_REQ);
+#endif /* BT_WIFI_HANDOVER */
+
+ /* Write updated Event mask */
+ eventmask_msg->ver = EVENTMSGS_VER;
+ eventmask_msg->command = EVENTMSGS_SET_MASK;
+ eventmask_msg->len = ROUNDUP(WLC_E_LAST, NBBY)/NBBY;
+ bcm_mkiovar("event_msgs_ext", (char *)eventmask_msg,
+ msglen, iov_buf, WLC_IOCTL_SMLEN);
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
+ iov_buf, WLC_IOCTL_SMLEN, TRUE, 0)) < 0) {
+ DHD_ERROR(("%s write event mask ext failed %d\n", __FUNCTION__, ret));
+ goto done;
+ }
+ } else if (ret2 < 0 && ret2 != BCME_UNSUPPORTED) {
+ DHD_ERROR(("%s read event mask ext failed %d\n", __FUNCTION__, ret2));
+ goto done;
+ } /* unsupported is ok */
+
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_CHANNEL_TIME, (char *)&scan_assoc_time,
+ sizeof(scan_assoc_time), TRUE, 0);
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_UNASSOC_TIME, (char *)&scan_unassoc_time,
+ sizeof(scan_unassoc_time), TRUE, 0);
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_PASSIVE_TIME, (char *)&scan_passive_time,
+ sizeof(scan_passive_time), TRUE, 0);
+
+#ifdef ARP_OFFLOAD_SUPPORT
+ /* Set and enable ARP offload feature for STA only */
+#if defined(SOFTAP)
+ if (arpoe && !ap_fw_loaded)
+#else
+ if (arpoe)
+#endif
+ {
+ dhd_arp_offload_enable(dhd, TRUE);
+ dhd_arp_offload_set(dhd, dhd_arp_mode);
+ } else {
+ dhd_arp_offload_enable(dhd, FALSE);
+ dhd_arp_offload_set(dhd, 0);
+ }
+ dhd_arp_enable = arpoe;
+#endif /* ARP_OFFLOAD_SUPPORT */
+
+#ifdef PKT_FILTER_SUPPORT
+ /* Setup default defintions for pktfilter , enable in suspend */
+ dhd->pktfilter_count = 6;
+ /* Setup filter to allow only unicast */
+ if (dhd_master_mode) {
+ dhd->pktfilter[DHD_UNICAST_FILTER_NUM] = "100 0 0 0 0x01 0x00";
+ dhd->pktfilter[DHD_BROADCAST_FILTER_NUM] = NULL;
+ dhd->pktfilter[DHD_MULTICAST4_FILTER_NUM] = NULL;
+ dhd->pktfilter[DHD_MULTICAST6_FILTER_NUM] = NULL;
+ /* Add filter to pass multicastDNS packet and NOT filter out as Broadcast */
+ dhd->pktfilter[DHD_MDNS_FILTER_NUM] = "104 0 0 0 0xFFFFFFFFFFFF 0x01005E0000FB";
+ /* apply APP pktfilter */
+ dhd->pktfilter[DHD_ARP_FILTER_NUM] = "105 0 0 12 0xFFFF 0x0806";
+ } else
+ dhd_conf_discard_pkt_filter(dhd);
+ dhd_conf_add_pkt_filter(dhd);
+
+#if defined(SOFTAP)
+ if (ap_fw_loaded) {
+ dhd_enable_packet_filter(0, dhd);
+ }
+#endif /* defined(SOFTAP) */
+ dhd_set_packet_filter(dhd);
+#endif /* PKT_FILTER_SUPPORT */
+#ifdef DISABLE_11N
+ bcm_mkiovar("nmode", (char *)&nmode, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
+ DHD_ERROR(("%s wl nmode 0 failed %d\n", __FUNCTION__, ret));
+#endif /* DISABLE_11N */
+
+#ifdef AMPDU_VO_ENABLE
+ tid.tid = PRIO_8021D_VO; /* Enable TID(6) for voice */
+ tid.enable = TRUE;
+ bcm_mkiovar("ampdu_tid", (char *)&tid, sizeof(tid), iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+
+ tid.tid = PRIO_8021D_NC; /* Enable TID(7) for voice */
+ tid.enable = TRUE;
+ bcm_mkiovar("ampdu_tid", (char *)&tid, sizeof(tid), iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+#endif
+#if defined(SOFTAP_TPUT_ENHANCE)
+ if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
+ dhd_bus_setidletime(dhd, (int)100);
+#ifdef DHDTCPACK_SUPPRESS
+ dhd->tcpack_sup_enabled = FALSE;
+#endif
+#if defined(DHD_TCP_WINSIZE_ADJUST)
+ dhd_use_tcp_window_size_adjust = TRUE;
+#endif
+
+ memset(buf, 0, sizeof(buf));
+ bcm_mkiovar("bus:txglom_auto_control", 0, 0, buf, sizeof(buf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), FALSE, 0)) < 0) {
+ glom = 0;
+ bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+ }
+ else {
+ if (buf[0] == 0) {
+ glom = 1;
+ bcm_mkiovar("bus:txglom_auto_control", (char *)&glom, 4, iovbuf,
+ sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+ }
+ }
+ }
+#endif /* SOFTAP_TPUT_ENHANCE */
+
+ /* query for 'ver' to get version info from firmware */
+ memset(buf, 0, sizeof(buf));
+ ptr = buf;
+ bcm_mkiovar("ver", (char *)&buf, 4, buf, sizeof(buf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), FALSE, 0)) < 0)
+ DHD_ERROR(("%s failed %d\n", __FUNCTION__, ret));
+ else {
+ bcmstrtok(&ptr, "\n", 0);
+ /* Print fw version info */
+ DHD_ERROR(("Firmware version = %s\n", buf));
+ dhd_set_version_info(dhd, buf);
+ }
+
+#if defined(BCMSDIO)
+ dhd_txglom_enable(dhd, dhd->conf->bus_rxglom);
+ // terence 20151210: set bus:txglom after dhd_txglom_enable since it's possible changed in dhd_conf_set_txglom_params
+ dhd_conf_set_fw_string_cmd(dhd, "bus:txglom", dhd->conf->bus_txglom, 1, FALSE);
+#endif /* defined(BCMSDIO) */
+
+ dhd_conf_set_disable_proptx(dhd);
+#if defined(BCMSDIO)
+#ifdef PROP_TXSTATUS
+ if (disable_proptx ||
+#ifdef PROP_TXSTATUS_VSDB
+ /* enable WLFC only if the firmware is VSDB when it is in STA mode */
+ (dhd->op_mode != DHD_FLAG_HOSTAP_MODE &&
+ dhd->op_mode != DHD_FLAG_IBSS_MODE) ||
+#endif /* PROP_TXSTATUS_VSDB */
+ FALSE) {
+ wlfc_enable = FALSE;
+ }
+
+#ifndef DISABLE_11N
+ ret = dhd_wl_ioctl_cmd(dhd, WLC_DOWN, (char *)&wl_down, sizeof(wl_down), TRUE, 0);
+ bcm_mkiovar("ampdu_hostreorder", (char *)&hostreorder, 4, iovbuf, sizeof(iovbuf));
+ if ((ret2 = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s wl ampdu_hostreorder failed %d\n", __FUNCTION__, ret2));
+ if (ret2 != BCME_UNSUPPORTED)
+ ret = ret2;
+ if (ret2 != BCME_OK)
+ hostreorder = 0;
+ }
+#endif /* DISABLE_11N */
+
+#ifdef READ_CONFIG_FROM_FILE
+ dhd_preinit_config(dhd, 0);
+#endif /* READ_CONFIG_FROM_FILE */
+
+ if (wlfc_enable)
+ dhd_wlfc_init(dhd);
+#ifndef DISABLE_11N
+ else if (hostreorder)
+ dhd_wlfc_hostreorder_init(dhd);
+#endif /* DISABLE_11N */
+
+#endif /* PROP_TXSTATUS */
+#endif /* BCMSDIO || BCMBUS */
+#ifdef PCIE_FULL_DONGLE
+ /* For FD we need all the packets at DHD to handle intra-BSS forwarding */
+ if (FW_SUPPORTED(dhd, ap)) {
+ wl_ap_isolate = AP_ISOLATE_SENDUP_ALL;
+ bcm_mkiovar("ap_isolate", (char *)&wl_ap_isolate, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
+ DHD_ERROR(("%s failed %d\n", __FUNCTION__, ret));
+ }
+#endif /* PCIE_FULL_DONGLE */
+#ifdef PNO_SUPPORT
+ if (!dhd->pno_state) {
+ dhd_pno_init(dhd);
+ }
+#endif
+#ifdef WL11U
+ dhd_interworking_enable(dhd);
+#endif /* WL11U */
+#ifndef WL_CFG80211
+ dhd_wl_ioctl_cmd(dhd, WLC_UP, (char *)&up, sizeof(up), TRUE, 0);
+#endif
+
+done:
+
+ if (eventmask_msg)
+ kfree(eventmask_msg);
+ if (iov_buf)
+ kfree(iov_buf);
+
+ return ret;
+}
+
+
+int
+dhd_iovar(dhd_pub_t *pub, int ifidx, char *name, char *cmd_buf, uint cmd_len, int set)
+{
+ char buf[strlen(name) + 1 + cmd_len];
+ int len = sizeof(buf);
+ wl_ioctl_t ioc;
+ int ret;
+
+ len = bcm_mkiovar(name, cmd_buf, cmd_len, buf, len);
+
+ memset(&ioc, 0, sizeof(ioc));
+
+ ioc.cmd = set? WLC_SET_VAR : WLC_GET_VAR;
+ ioc.buf = buf;
+ ioc.len = len;
+ ioc.set = set;
+
+ ret = dhd_wl_ioctl(pub, ifidx, &ioc, ioc.buf, ioc.len);
+ if (!set && ret >= 0)
+ memcpy(cmd_buf, buf, cmd_len);
+
+ return ret;
+}
+
+int dhd_change_mtu(dhd_pub_t *dhdp, int new_mtu, int ifidx)
+{
+ struct dhd_info *dhd = dhdp->info;
+ struct net_device *dev = NULL;
+
+ ASSERT(dhd && dhd->iflist[ifidx]);
+ dev = dhd->iflist[ifidx]->net;
+ ASSERT(dev);
+
+ if (netif_running(dev)) {
+ DHD_ERROR(("%s: Must be down to change its MTU\n", dev->name));
+ return BCME_NOTDOWN;
+ }
+
+#define DHD_MIN_MTU 1500
+#define DHD_MAX_MTU 1752
+
+ if ((new_mtu < DHD_MIN_MTU) || (new_mtu > DHD_MAX_MTU)) {
+ DHD_ERROR(("%s: MTU size %d is invalid.\n", __FUNCTION__, new_mtu));
+ return BCME_BADARG;
+ }
+
+ dev->mtu = new_mtu;
+ return 0;
+}
+
+#ifdef ARP_OFFLOAD_SUPPORT
+/* add or remove AOE host ip(s) (up to 8 IPs on the interface) */
+void
+aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add, int idx)
+{
+ u32 ipv4_buf[MAX_IPV4_ENTRIES]; /* temp save for AOE host_ip table */
+ int i;
+ int ret;
+
+ bzero(ipv4_buf, sizeof(ipv4_buf));
+
+ /* display what we've got */
+ ret = dhd_arp_get_arp_hostip_table(dhd_pub, ipv4_buf, sizeof(ipv4_buf), idx);
+ DHD_ARPOE(("%s: hostip table read from Dongle:\n", __FUNCTION__));
+#ifdef AOE_DBG
+ dhd_print_buf(ipv4_buf, 32, 4); /* max 8 IPs 4b each */
+#endif
+ /* now we saved hoste_ip table, clr it in the dongle AOE */
+ dhd_aoe_hostip_clr(dhd_pub, idx);
+
+ if (ret) {
+ DHD_ERROR(("%s failed\n", __FUNCTION__));
+ return;
+ }
+
+ for (i = 0; i < MAX_IPV4_ENTRIES; i++) {
+ if (add && (ipv4_buf[i] == 0)) {
+ ipv4_buf[i] = ipa;
+ add = FALSE; /* added ipa to local table */
+ DHD_ARPOE(("%s: Saved new IP in temp arp_hostip[%d]\n",
+ __FUNCTION__, i));
+ } else if (ipv4_buf[i] == ipa) {
+ ipv4_buf[i] = 0;
+ DHD_ARPOE(("%s: removed IP:%x from temp table %d\n",
+ __FUNCTION__, ipa, i));
+ }
+
+ if (ipv4_buf[i] != 0) {
+ /* add back host_ip entries from our local cache */
+ dhd_arp_offload_add_ip(dhd_pub, ipv4_buf[i], idx);
+ DHD_ARPOE(("%s: added IP:%x to dongle arp_hostip[%d]\n\n",
+ __FUNCTION__, ipv4_buf[i], i));
+ }
+ }
+#ifdef AOE_DBG
+ /* see the resulting hostip table */
+ dhd_arp_get_arp_hostip_table(dhd_pub, ipv4_buf, sizeof(ipv4_buf), idx);
+ DHD_ARPOE(("%s: read back arp_hostip table:\n", __FUNCTION__));
+ dhd_print_buf(ipv4_buf, 32, 4); /* max 8 IPs 4b each */
+#endif
+}
+
+/*
+ * Notification mechanism from kernel to our driver. This function is called by the Linux kernel
+ * whenever there is an event related to an IP address.
+ * ptr : kernel provided pointer to IP address that has changed
+ */
+static int dhd_inetaddr_notifier_call(struct notifier_block *this,
+ unsigned long event,
+ void *ptr)
+{
+ struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
+
+ dhd_info_t *dhd;
+ dhd_pub_t *dhd_pub;
+ int idx;
+
+ if (!dhd_arp_enable)
+ return NOTIFY_DONE;
+ if (!ifa || !(ifa->ifa_dev->dev))
+ return NOTIFY_DONE;
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31))
+ /* Filter notifications meant for non Broadcom devices */
+ if ((ifa->ifa_dev->dev->netdev_ops != &dhd_ops_pri) &&
+ (ifa->ifa_dev->dev->netdev_ops != &dhd_ops_virt)) {
+#if defined(WL_ENABLE_P2P_IF)
+ if (!wl_cfgp2p_is_ifops(ifa->ifa_dev->dev->netdev_ops))
+#endif /* WL_ENABLE_P2P_IF */
+ return NOTIFY_DONE;
+ }
+#endif /* LINUX_VERSION_CODE */
+
+ dhd = DHD_DEV_INFO(ifa->ifa_dev->dev);
+ if (!dhd)
+ return NOTIFY_DONE;
+
+ dhd_pub = &dhd->pub;
+
+ if (dhd_pub->arp_version == 1) {
+ idx = 0;
+ }
+ else {
+ for (idx = 0; idx < DHD_MAX_IFS; idx++) {
+ if (dhd->iflist[idx] && dhd->iflist[idx]->net == ifa->ifa_dev->dev)
+ break;
+ }
+ if (idx < DHD_MAX_IFS)
+ DHD_TRACE(("ifidx : %p %s %d\n", dhd->iflist[idx]->net,
+ dhd->iflist[idx]->name, dhd->iflist[idx]->idx));
+ else {
+ DHD_ERROR(("Cannot find ifidx for(%s) set to 0\n", ifa->ifa_label));
+ idx = 0;
+ }
+ }
+
+ switch (event) {
+ case NETDEV_UP:
+ DHD_ARPOE(("%s: [%s] Up IP: 0x%x\n",
+ __FUNCTION__, ifa->ifa_label, ifa->ifa_address));
+
+ if (dhd->pub.busstate != DHD_BUS_DATA) {
+ DHD_ERROR(("%s: bus not ready, exit\n", __FUNCTION__));
+ if (dhd->pend_ipaddr) {
+ DHD_ERROR(("%s: overwrite pending ipaddr: 0x%x\n",
+ __FUNCTION__, dhd->pend_ipaddr));
+ }
+ dhd->pend_ipaddr = ifa->ifa_address;
+ break;
+ }
+
+#ifdef AOE_IP_ALIAS_SUPPORT
+ DHD_ARPOE(("%s:add aliased IP to AOE hostip cache\n",
+ __FUNCTION__));
+ aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, TRUE, idx);
+#endif /* AOE_IP_ALIAS_SUPPORT */
+ break;
+
+ case NETDEV_DOWN:
+ DHD_ARPOE(("%s: [%s] Down IP: 0x%x\n",
+ __FUNCTION__, ifa->ifa_label, ifa->ifa_address));
+ dhd->pend_ipaddr = 0;
+#ifdef AOE_IP_ALIAS_SUPPORT
+ DHD_ARPOE(("%s:interface is down, AOE clr all for this if\n",
+ __FUNCTION__));
+ aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, FALSE, idx);
+#else
+ dhd_aoe_hostip_clr(&dhd->pub, idx);
+ dhd_aoe_arp_clr(&dhd->pub, idx);
+#endif /* AOE_IP_ALIAS_SUPPORT */
+ break;
+
+ default:
+ DHD_ARPOE(("%s: do noting for [%s] Event: %lu\n",
+ __func__, ifa->ifa_label, event));
+ break;
+ }
+ return NOTIFY_DONE;
+}
+#endif /* ARP_OFFLOAD_SUPPORT */
+
+#ifdef CONFIG_IPV6
+/* Neighbor Discovery Offload: defered handler */
+static void
+dhd_inet6_work_handler(void *dhd_info, void *event_data, u8 event)
+{
+ struct ipv6_work_info_t *ndo_work = (struct ipv6_work_info_t *)event_data;
+ dhd_pub_t *pub = &((dhd_info_t *)dhd_info)->pub;
+ int ret;
+
+ if (event != DHD_WQ_WORK_IPV6_NDO) {
+ DHD_ERROR(("%s: unexpected event \n", __FUNCTION__));
+ return;
+ }
+
+ if (!ndo_work) {
+ DHD_ERROR(("%s: ipv6 work info is not initialized \n", __FUNCTION__));
+ return;
+ }
+
+ if (!pub) {
+ DHD_ERROR(("%s: dhd pub is not initialized \n", __FUNCTION__));
+ return;
+ }
+
+ if (ndo_work->if_idx) {
+ DHD_ERROR(("%s: idx %d \n", __FUNCTION__, ndo_work->if_idx));
+ return;
+ }
+
+ switch (ndo_work->event) {
+ case NETDEV_UP:
+ DHD_TRACE(("%s: Enable NDO and add ipv6 into table \n", __FUNCTION__));
+ ret = dhd_ndo_enable(pub, TRUE);
+ if (ret < 0) {
+ DHD_ERROR(("%s: Enabling NDO Failed %d\n", __FUNCTION__, ret));
+ }
+
+ ret = dhd_ndo_add_ip(pub, &ndo_work->ipv6_addr[0], ndo_work->if_idx);
+ if (ret < 0) {
+ DHD_ERROR(("%s: Adding host ip for NDO failed %d\n",
+ __FUNCTION__, ret));
+ }
+ break;
+ case NETDEV_DOWN:
+ DHD_TRACE(("%s: clear ipv6 table \n", __FUNCTION__));
+ ret = dhd_ndo_remove_ip(pub, ndo_work->if_idx);
+ if (ret < 0) {
+ DHD_ERROR(("%s: Removing host ip for NDO failed %d\n",
+ __FUNCTION__, ret));
+ goto done;
+ }
+
+ ret = dhd_ndo_enable(pub, FALSE);
+ if (ret < 0) {
+ DHD_ERROR(("%s: disabling NDO Failed %d\n", __FUNCTION__, ret));
+ goto done;
+ }
+ break;
+ default:
+ DHD_ERROR(("%s: unknown notifier event \n", __FUNCTION__));
+ break;
+ }
+done:
+ /* free ndo_work. alloced while scheduling the work */
+ kfree(ndo_work);
+
+ return;
+}
+
+/*
+ * Neighbor Discovery Offload: Called when an interface
+ * is assigned with ipv6 address.
+ * Handles only primary interface
+ */
+static int dhd_inet6addr_notifier_call(struct notifier_block *this,
+ unsigned long event,
+ void *ptr)
+{
+ dhd_info_t *dhd;
+ dhd_pub_t *dhd_pub;
+ struct inet6_ifaddr *inet6_ifa = ptr;
+ struct in6_addr *ipv6_addr = &inet6_ifa->addr;
+ struct ipv6_work_info_t *ndo_info;
+ int idx = 0; /* REVISIT */
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31))
+ /* Filter notifications meant for non Broadcom devices */
+ if (inet6_ifa->idev->dev->netdev_ops != &dhd_ops_pri) {
+ return NOTIFY_DONE;
+ }
+#endif /* LINUX_VERSION_CODE */
+
+ dhd = DHD_DEV_INFO(inet6_ifa->idev->dev);
+ if (!dhd)
+ return NOTIFY_DONE;
+
+ if (dhd->iflist[idx] && dhd->iflist[idx]->net != inet6_ifa->idev->dev)
+ return NOTIFY_DONE;
+ dhd_pub = &dhd->pub;
+ if (!FW_SUPPORTED(dhd_pub, ndoe))
+ return NOTIFY_DONE;
+
+ ndo_info = (struct ipv6_work_info_t *)kzalloc(sizeof(struct ipv6_work_info_t), GFP_ATOMIC);
+ if (!ndo_info) {
+ DHD_ERROR(("%s: ipv6 work alloc failed\n", __FUNCTION__));
+ return NOTIFY_DONE;
+ }
+
+ ndo_info->event = event;
+ ndo_info->if_idx = idx;
+ memcpy(&ndo_info->ipv6_addr[0], ipv6_addr, IPV6_ADDR_LEN);
+
+ /* defer the work to thread as it may block kernel */
+ dhd_deferred_schedule_work(dhd->dhd_deferred_wq, (void *)ndo_info, DHD_WQ_WORK_IPV6_NDO,
+ dhd_inet6_work_handler, DHD_WORK_PRIORITY_LOW);
+ return NOTIFY_DONE;
+}
+#endif /* #ifdef CONFIG_IPV6 */
+
+int
+dhd_register_if(dhd_pub_t *dhdp, int ifidx, bool need_rtnl_lock)
+{
+ dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
+ dhd_if_t *ifp;
+ struct net_device *net = NULL;
+ int err = 0;
+ uint8 temp_addr[ETHER_ADDR_LEN] = { 0x00, 0x90, 0x4c, 0x11, 0x22, 0x33 };
+
+ DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx));
+
+ ASSERT(dhd && dhd->iflist[ifidx]);
+ ifp = dhd->iflist[ifidx];
+ net = ifp->net;
+ ASSERT(net && (ifp->idx == ifidx));
+
+#ifndef P2PONEINT
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31))
+ ASSERT(!net->open);
+ net->get_stats = dhd_get_stats;
+ net->do_ioctl = dhd_ioctl_entry;
+ net->hard_start_xmit = dhd_start_xmit;
+ net->set_mac_address = dhd_set_mac_address;
+ net->set_multicast_list = dhd_set_multicast_list;
+ net->open = net->stop = NULL;
+#else
+ ASSERT(!net->netdev_ops);
+ net->netdev_ops = &dhd_ops_virt;
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */
+#else
+ net->netdev_ops = &dhd_cfgp2p_ops_virt;
+#endif /* P2PONEINT */
+
+ /* Ok, link into the network layer... */
+ if (ifidx == 0) {
+ /*
+ * device functions for the primary interface only
+ */
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31))
+ net->open = dhd_open;
+ net->stop = dhd_stop;
+#else
+ net->netdev_ops = &dhd_ops_pri;
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */
+ if (!ETHER_ISNULLADDR(dhd->pub.mac.octet))
+ memcpy(temp_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN);
+ } else {
+ /*
+ * We have to use the primary MAC for virtual interfaces
+ */
+ memcpy(temp_addr, ifp->mac_addr, ETHER_ADDR_LEN);
+ /*
+ * Android sets the locally administered bit to indicate that this is a
+ * portable hotspot. This will not work in simultaneous AP/STA mode,
+ * nor with P2P. Need to set the Donlge's MAC address, and then use that.
+ */
+ if (!memcmp(temp_addr, dhd->iflist[0]->mac_addr,
+ ETHER_ADDR_LEN)) {
+ DHD_ERROR(("%s interface [%s]: set locally administered bit in MAC\n",
+ __func__, net->name));
+ temp_addr[0] |= 0x02;
+ }
+ }
+
+ net->hard_header_len = ETH_HLEN + dhd->pub.hdrlen;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
+ net->ethtool_ops = &dhd_ethtool_ops;
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */
+
+#if defined(WL_WIRELESS_EXT)
+#if WIRELESS_EXT < 19
+ net->get_wireless_stats = dhd_get_wireless_stats;
+#endif /* WIRELESS_EXT < 19 */
+#if WIRELESS_EXT > 12
+ net->wireless_handlers = (struct iw_handler_def *)&wl_iw_handler_def;
+#endif /* WIRELESS_EXT > 12 */
+#endif /* defined(WL_WIRELESS_EXT) */
+
+ dhd->pub.rxsz = DBUS_RX_BUFFER_SIZE_DHD(net);
+
+ memcpy(net->dev_addr, temp_addr, ETHER_ADDR_LEN);
+
+ if (ifidx == 0)
+ printf("%s\n", dhd_version);
+
+ if (need_rtnl_lock)
+ err = register_netdev(net);
+ else
+ err = register_netdevice(net);
+
+ if (err != 0) {
+ DHD_ERROR(("couldn't register the net device [%s], err %d\n", net->name, err));
+ goto fail;
+ }
+
+#ifdef SET_RPS_CPUS
+ err = custom_rps_map_set(net->_rx, RPS_CPUS_MASK, strlen(RPS_CPUS_MASK));
+ if (err < 0)
+ DHD_ERROR(("%s : custom_rps_map_set done. error : %d\n", __FUNCTION__, err));
+#endif /* SET_RPS_CPUS */
+
+
+
+ printf("Register interface [%s] MAC: "MACDBG"\n\n", net->name,
+ MAC2STRDBG(net->dev_addr));
+
+#if defined(SOFTAP) && defined(WL_WIRELESS_EXT) && !defined(WL_CFG80211)
+// wl_iw_iscan_set_scan_broadcast_prep(net, 1);
+#endif
+
+#if 1 && (defined(BCMPCIE) || (defined(BCMLXSDMMC) && (LINUX_VERSION_CODE >= \
+ KERNEL_VERSION(2, 6, 27))))
+ if (ifidx == 0) {
+#ifdef BCMLXSDMMC
+ up(&dhd_registration_sem);
+#endif
+ if (!dhd_download_fw_on_driverload) {
+ dhd_net_bus_devreset(net, TRUE);
+#ifdef BCMLXSDMMC
+ dhd_net_bus_suspend(net);
+#endif /* BCMLXSDMMC */
+ wifi_platform_set_power(dhdp->info->adapter, FALSE, WIFI_TURNOFF_DELAY);
+ }
+ }
+#endif /* OEM_ANDROID && (BCMPCIE || (BCMLXSDMMC && KERNEL_VERSION >= 2.6.27)) */
+ return 0;
+
+fail:
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)
+ net->open = NULL;
+#else
+ net->netdev_ops = NULL;
+#endif
+ return err;
+}
+
+void
+dhd_bus_detach(dhd_pub_t *dhdp)
+{
+ dhd_info_t *dhd;
+
+ DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+
+ if (dhdp) {
+ dhd = (dhd_info_t *)dhdp->info;
+ if (dhd) {
+
+ /*
+ * In case of Android cfg80211 driver, the bus is down in dhd_stop,
+ * calling stop again will cuase SD read/write errors.
+ */
+ if (dhd->pub.busstate != DHD_BUS_DOWN) {
+ /* Stop the protocol module */
+ dhd_prot_stop(&dhd->pub);
+
+ /* Stop the bus module */
+ dhd_bus_stop(dhd->pub.bus, TRUE);
+ }
+
+#if defined(OOB_INTR_ONLY) || defined(BCMPCIE_OOB_HOST_WAKE)
+ dhd_bus_oob_intr_unregister(dhdp);
+#endif
+ }
+ }
+}
+
+
+void dhd_detach(dhd_pub_t *dhdp)
+{
+ dhd_info_t *dhd;
+ unsigned long flags;
+ int timer_valid = FALSE;
+
+ if (!dhdp)
+ return;
+
+ dhd = (dhd_info_t *)dhdp->info;
+ if (!dhd)
+ return;
+
+#if defined(CUSTOMER_HW20) && defined(WLANAUDIO)
+ dhd_global = NULL;
+#endif /* CUSTOMER_HW20 && WLANAUDIO */
+
+ DHD_TRACE(("%s: Enter state 0x%x\n", __FUNCTION__, dhd->dhd_state));
+
+ dhd->pub.up = 0;
+ if (!(dhd->dhd_state & DHD_ATTACH_STATE_DONE)) {
+ /* Give sufficient time for threads to start running in case
+ * dhd_attach() has failed
+ */
+ OSL_SLEEP(100);
+ }
+
+ if (dhd->dhd_state & DHD_ATTACH_STATE_PROT_ATTACH) {
+ dhd_bus_detach(dhdp);
+#ifdef PCIE_FULL_DONGLE
+ dhd_flow_rings_deinit(dhdp);
+#endif
+
+ if (dhdp->prot)
+ dhd_prot_detach(dhdp);
+ }
+
+#ifdef ARP_OFFLOAD_SUPPORT
+ if (dhd_inetaddr_notifier_registered) {
+ dhd_inetaddr_notifier_registered = FALSE;
+ unregister_inetaddr_notifier(&dhd_inetaddr_notifier);
+ }
+#endif /* ARP_OFFLOAD_SUPPORT */
+#ifdef CONFIG_IPV6
+ if (dhd_inet6addr_notifier_registered) {
+ dhd_inet6addr_notifier_registered = FALSE;
+ unregister_inet6addr_notifier(&dhd_inet6addr_notifier);
+ }
+#endif
+
+#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
+ if (dhd->dhd_state & DHD_ATTACH_STATE_EARLYSUSPEND_DONE) {
+ if (dhd->early_suspend.suspend)
+ unregister_early_suspend(&dhd->early_suspend);
+ }
+#endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */
+
+#if defined(WL_WIRELESS_EXT)
+ if (dhd->dhd_state & DHD_ATTACH_STATE_WL_ATTACH) {
+ /* Detatch and unlink in the iw */
+ wl_iw_detach();
+ }
+#endif /* defined(WL_WIRELESS_EXT) */
+
+ /* delete all interfaces, start with virtual */
+ if (dhd->dhd_state & DHD_ATTACH_STATE_ADD_IF) {
+ int i = 1;
+ dhd_if_t *ifp;
+
+ /* Cleanup virtual interfaces */
+ dhd_net_if_lock_local(dhd);
+ for (i = 1; i < DHD_MAX_IFS; i++) {
+ if (dhd->iflist[i])
+ dhd_remove_if(&dhd->pub, i, TRUE);
+ }
+ dhd_net_if_unlock_local(dhd);
+
+ /* delete primary interface 0 */
+ ifp = dhd->iflist[0];
+ ASSERT(ifp);
+ ASSERT(ifp->net);
+ if (ifp && ifp->net) {
+
+
+
+ /* in unregister_netdev case, the interface gets freed by net->destructor
+ * (which is set to free_netdev)
+ */
+ if (ifp->net->reg_state == NETREG_UNINITIALIZED)
+ free_netdev(ifp->net);
+ else {
+#ifdef SET_RPS_CPUS
+ custom_rps_map_clear(ifp->net->_rx);
+#endif /* SET_RPS_CPUS */
+ unregister_netdev(ifp->net);
+ }
+ ifp->net = NULL;
+#ifdef DHD_WMF
+ dhd_wmf_cleanup(dhdp, 0);
+#endif /* DHD_WMF */
+
+ dhd_if_del_sta_list(ifp);
+
+ MFREE(dhd->pub.osh, ifp, sizeof(*ifp));
+ dhd->iflist[0] = NULL;
+ }
+ }
+
+ /* Clear the watchdog timer */
+ DHD_GENERAL_LOCK(&dhd->pub, flags);
+ timer_valid = dhd->wd_timer_valid;
+ dhd->wd_timer_valid = FALSE;
+ DHD_GENERAL_UNLOCK(&dhd->pub, flags);
+ if (timer_valid)
+ del_timer_sync(&dhd->timer);
+
+ if (dhd->dhd_state & DHD_ATTACH_STATE_THREADS_CREATED) {
+ if (dhd->thr_wdt_ctl.thr_pid >= 0) {
+ PROC_STOP(&dhd->thr_wdt_ctl);
+ }
+
+ if (dhd->rxthread_enabled && dhd->thr_rxf_ctl.thr_pid >= 0) {
+ PROC_STOP(&dhd->thr_rxf_ctl);
+ }
+
+ if (dhd->thr_dpc_ctl.thr_pid >= 0) {
+ PROC_STOP(&dhd->thr_dpc_ctl);
+ } else
+ tasklet_kill(&dhd->tasklet);
+ }
+#ifdef WL_CFG80211
+ if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) {
+ wl_cfg80211_detach(NULL);
+ dhd_monitor_uninit();
+ }
+#endif
+ /* free deferred work queue */
+ dhd_deferred_work_deinit(dhd->dhd_deferred_wq);
+ dhd->dhd_deferred_wq = NULL;
+
+#ifdef SHOW_LOGTRACE
+ if (dhd->event_data.fmts)
+ kfree(dhd->event_data.fmts);
+ if (dhd->event_data.raw_fmts)
+ kfree(dhd->event_data.raw_fmts);
+#endif /* SHOW_LOGTRACE */
+
+#ifdef PNO_SUPPORT
+ if (dhdp->pno_state)
+ dhd_pno_deinit(dhdp);
+#endif
+#if defined(CONFIG_PM_SLEEP)
+ if (dhd_pm_notifier_registered) {
+ unregister_pm_notifier(&dhd_pm_notifier);
+ dhd_pm_notifier_registered = FALSE;
+ }
+#endif /* CONFIG_PM_SLEEP */
+#ifdef DEBUG_CPU_FREQ
+ if (dhd->new_freq)
+ free_percpu(dhd->new_freq);
+ dhd->new_freq = NULL;
+ cpufreq_unregister_notifier(&dhd->freq_trans, CPUFREQ_TRANSITION_NOTIFIER);
+#endif
+ if (dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT) {
+ DHD_TRACE(("wd wakelock count:%d\n", dhd->wakelock_wd_counter));
+#ifdef CONFIG_HAS_WAKELOCK
+ dhd->wakelock_counter = 0;
+ dhd->wakelock_wd_counter = 0;
+ dhd->wakelock_rx_timeout_enable = 0;
+ dhd->wakelock_ctrl_timeout_enable = 0;
+ wake_lock_destroy(&dhd->wl_wifi);
+ wake_lock_destroy(&dhd->wl_rxwake);
+ wake_lock_destroy(&dhd->wl_ctrlwake);
+ wake_lock_destroy(&dhd->wl_wdwake);
+#ifdef BCMPCIE_OOB_HOST_WAKE
+ wake_lock_destroy(&dhd->wl_intrwake);
+#endif /* BCMPCIE_OOB_HOST_WAKE */
+#endif /* CONFIG_HAS_WAKELOCK */
+ }
+
+
+
+
+#ifdef DHDTCPACK_SUPPRESS
+ /* This will free all MEM allocated for TCPACK SUPPRESS */
+ dhd_tcpack_suppress_set(&dhd->pub, TCPACK_SUP_OFF);
+#endif /* DHDTCPACK_SUPPRESS */
+ dhd_conf_detach(dhdp);
+}
+
+
+void
+dhd_free(dhd_pub_t *dhdp)
+{
+ dhd_info_t *dhd;
+ DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+
+ if (dhdp) {
+ int i;
+ for (i = 0; i < ARRAYSIZE(dhdp->reorder_bufs); i++) {
+ if (dhdp->reorder_bufs[i]) {
+ reorder_info_t *ptr;
+ uint32 buf_size = sizeof(struct reorder_info);
+
+ ptr = dhdp->reorder_bufs[i];
+
+ buf_size += ((ptr->max_idx + 1) * sizeof(void*));
+ DHD_REORDER(("free flow id buf %d, maxidx is %d, buf_size %d\n",
+ i, ptr->max_idx, buf_size));
+
+ MFREE(dhdp->osh, dhdp->reorder_bufs[i], buf_size);
+ dhdp->reorder_bufs[i] = NULL;
+ }
+ }
+
+ dhd_sta_pool_fini(dhdp, DHD_MAX_STA);
+
+ dhd = (dhd_info_t *)dhdp->info;
+ /* If pointer is allocated by dhd_os_prealloc then avoid MFREE */
+ if (dhd &&
+ dhd != (dhd_info_t *)dhd_os_prealloc(dhdp, DHD_PREALLOC_DHD_INFO, 0, FALSE))
+ MFREE(dhd->pub.osh, dhd, sizeof(*dhd));
+ dhd = NULL;
+ }
+}
+
+void
+dhd_clear(dhd_pub_t *dhdp)
+{
+ DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+
+ if (dhdp) {
+ int i;
+ for (i = 0; i < ARRAYSIZE(dhdp->reorder_bufs); i++) {
+ if (dhdp->reorder_bufs[i]) {
+ reorder_info_t *ptr;
+ uint32 buf_size = sizeof(struct reorder_info);
+
+ ptr = dhdp->reorder_bufs[i];
+
+ buf_size += ((ptr->max_idx + 1) * sizeof(void*));
+ DHD_REORDER(("free flow id buf %d, maxidx is %d, buf_size %d\n",
+ i, ptr->max_idx, buf_size));
+
+ MFREE(dhdp->osh, dhdp->reorder_bufs[i], buf_size);
+ dhdp->reorder_bufs[i] = NULL;
+ }
+ }
+
+ dhd_sta_pool_clear(dhdp, DHD_MAX_STA);
+ }
+}
+
+static void
+dhd_module_cleanup(void)
+{
+ printf("%s: Enter\n", __FUNCTION__);
+
+ dhd_bus_unregister();
+
+ wl_android_exit();
+
+ dhd_wifi_platform_unregister_drv();
+ printf("%s: Exit\n", __FUNCTION__);
+}
+
+static void __exit
+dhd_module_exit(void)
+{
+ dhd_module_cleanup();
+ unregister_reboot_notifier(&dhd_reboot_notifier);
+}
+
+static int __init
+dhd_module_init(void)
+{
+ int err;
+ int retry = POWERUP_MAX_RETRY;
+
+ printf("%s: in\n", __FUNCTION__);
+
+ DHD_PERIM_RADIO_INIT();
+
+ if (firmware_path[0] != '\0') {
+ strncpy(fw_bak_path, firmware_path, MOD_PARAM_PATHLEN);
+ fw_bak_path[MOD_PARAM_PATHLEN-1] = '\0';
+ }
+
+ if (nvram_path[0] != '\0') {
+ strncpy(nv_bak_path, nvram_path, MOD_PARAM_PATHLEN);
+ nv_bak_path[MOD_PARAM_PATHLEN-1] = '\0';
+ }
+
+ do {
+ err = dhd_wifi_platform_register_drv();
+ if (!err) {
+ register_reboot_notifier(&dhd_reboot_notifier);
+ break;
+ }
+ else {
+ DHD_ERROR(("%s: Failed to load the driver, try cnt %d\n",
+ __FUNCTION__, retry));
+ strncpy(firmware_path, fw_bak_path, MOD_PARAM_PATHLEN);
+ firmware_path[MOD_PARAM_PATHLEN-1] = '\0';
+ strncpy(nvram_path, nv_bak_path, MOD_PARAM_PATHLEN);
+ nvram_path[MOD_PARAM_PATHLEN-1] = '\0';
+ }
+ } while (retry--);
+
+ if (err) {
+ DHD_ERROR(("%s: Failed to load driver max retry reached**\n", __FUNCTION__));
+ }
+
+ printf("%s: Exit err=%d\n", __FUNCTION__, err);
+ return err;
+}
+
+static int
+dhd_reboot_callback(struct notifier_block *this, unsigned long code, void *unused)
+{
+ DHD_TRACE(("%s: code = %ld\n", __FUNCTION__, code));
+ if (code == SYS_RESTART) {
+ }
+
+ return NOTIFY_DONE;
+}
+
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
+#if defined(CONFIG_DEFERRED_INITCALLS)
+deferred_module_init(dhd_module_init);
+#elif defined(USE_LATE_INITCALL_SYNC)
+late_initcall_sync(dhd_module_init);
+#else
+late_initcall(dhd_module_init);
+#endif /* USE_LATE_INITCALL_SYNC */
+#else
+module_init(dhd_module_init);
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */
+
+module_exit(dhd_module_exit);
+
+/*
+ * OS specific functions required to implement DHD driver in OS independent way
+ */
+int
+dhd_os_proto_block(dhd_pub_t *pub)
+{
+ dhd_info_t * dhd = (dhd_info_t *)(pub->info);
+
+ if (dhd) {
+ DHD_PERIM_UNLOCK(pub);
+
+ down(&dhd->proto_sem);
+
+ DHD_PERIM_LOCK(pub);
+ return 1;
+ }
+
+ return 0;
+}
+
+int
+dhd_os_proto_unblock(dhd_pub_t *pub)
+{
+ dhd_info_t * dhd = (dhd_info_t *)(pub->info);
+
+ if (dhd) {
+ up(&dhd->proto_sem);
+ return 1;
+ }
+
+ return 0;
+}
+
+unsigned int
+dhd_os_get_ioctl_resp_timeout(void)
+{
+ return ((unsigned int)dhd_ioctl_timeout_msec);
+}
+
+void
+dhd_os_set_ioctl_resp_timeout(unsigned int timeout_msec)
+{
+ dhd_ioctl_timeout_msec = (int)timeout_msec;
+}
+
+int
+dhd_os_ioctl_resp_wait(dhd_pub_t *pub, uint *condition, bool *pending)
+{
+ dhd_info_t * dhd = (dhd_info_t *)(pub->info);
+ int timeout;
+
+ /* Convert timeout in millsecond to jiffies */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
+ timeout = msecs_to_jiffies(dhd_ioctl_timeout_msec);
+#else
+ timeout = dhd_ioctl_timeout_msec * HZ / 1000;
+#endif
+
+ DHD_PERIM_UNLOCK(pub);
+
+ timeout = wait_event_timeout(dhd->ioctl_resp_wait, (*condition), timeout);
+
+ DHD_PERIM_LOCK(pub);
+
+ return timeout;
+}
+
+int
+dhd_os_ioctl_resp_wake(dhd_pub_t *pub)
+{
+ dhd_info_t *dhd = (dhd_info_t *)(pub->info);
+
+ wake_up(&dhd->ioctl_resp_wait);
+ return 0;
+}
+
+void
+dhd_os_wd_timer_extend(void *bus, bool extend)
+{
+ dhd_pub_t *pub = bus;
+ dhd_info_t *dhd = (dhd_info_t *)pub->info;
+
+ if (extend)
+ dhd_os_wd_timer(bus, WATCHDOG_EXTEND_INTERVAL);
+ else
+ dhd_os_wd_timer(bus, dhd->default_wd_interval);
+}
+
+
+void
+dhd_os_wd_timer(void *bus, uint wdtick)
+{
+ dhd_pub_t *pub = bus;
+ dhd_info_t *dhd = (dhd_info_t *)pub->info;
+ unsigned long flags;
+
+ DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+
+ if (!dhd) {
+ DHD_ERROR(("%s: dhd NULL\n", __FUNCTION__));
+ return;
+ }
+
+ DHD_GENERAL_LOCK(pub, flags);
+
+ /* don't start the wd until fw is loaded */
+ if (pub->busstate == DHD_BUS_DOWN) {
+ DHD_GENERAL_UNLOCK(pub, flags);
+ if (!wdtick)
+ DHD_OS_WD_WAKE_UNLOCK(pub);
+ return;
+ }
+
+ /* Totally stop the timer */
+ if (!wdtick && dhd->wd_timer_valid == TRUE) {
+ dhd->wd_timer_valid = FALSE;
+ DHD_GENERAL_UNLOCK(pub, flags);
+ del_timer_sync(&dhd->timer);
+ DHD_OS_WD_WAKE_UNLOCK(pub);
+ return;
+ }
+
+ if (wdtick) {
+ DHD_OS_WD_WAKE_LOCK(pub);
+ dhd_watchdog_ms = (uint)wdtick;
+ /* Re arm the timer, at last watchdog period */
+ mod_timer(&dhd->timer, jiffies + msecs_to_jiffies(dhd_watchdog_ms));
+ dhd->wd_timer_valid = TRUE;
+ }
+ DHD_GENERAL_UNLOCK(pub, flags);
+}
+
+void *
+dhd_os_open_image(char *filename)
+{
+ struct file *fp;
+
+ fp = filp_open(filename, O_RDONLY, 0);
+ /*
+ * 2.6.11 (FC4) supports filp_open() but later revs don't?
+ * Alternative:
+ * fp = open_namei(AT_FDCWD, filename, O_RD, 0);
+ * ???
+ */
+ if (IS_ERR(fp))
+ fp = NULL;
+
+ return fp;
+}
+
+int
+dhd_os_get_image_block(char *buf, int len, void *image)
+{
+ struct file *fp = (struct file *)image;
+ int rdlen;
+
+ if (!image)
+ return 0;
+
+ rdlen = kernel_read(fp, fp->f_pos, buf, len);
+ if (rdlen > 0)
+ fp->f_pos += rdlen;
+
+ return rdlen;
+}
+
+void
+dhd_os_close_image(void *image)
+{
+ if (image)
+ filp_close((struct file *)image, NULL);
+}
+
+void
+dhd_os_sdlock(dhd_pub_t *pub)
+{
+ dhd_info_t *dhd;
+
+ dhd = (dhd_info_t *)(pub->info);
+
+ if (dhd_dpc_prio >= 0)
+ down(&dhd->sdsem);
+ else
+ spin_lock_bh(&dhd->sdlock);
+}
+
+void
+dhd_os_sdunlock(dhd_pub_t *pub)
+{
+ dhd_info_t *dhd;
+
+ dhd = (dhd_info_t *)(pub->info);
+
+ if (dhd_dpc_prio >= 0)
+ up(&dhd->sdsem);
+ else
+ spin_unlock_bh(&dhd->sdlock);
+}
+
+void
+dhd_os_sdlock_txq(dhd_pub_t *pub)
+{
+ dhd_info_t *dhd;
+
+ dhd = (dhd_info_t *)(pub->info);
+ spin_lock_bh(&dhd->txqlock);
+}
+
+void
+dhd_os_sdunlock_txq(dhd_pub_t *pub)
+{
+ dhd_info_t *dhd;
+
+ dhd = (dhd_info_t *)(pub->info);
+ spin_unlock_bh(&dhd->txqlock);
+}
+
+void
+dhd_os_sdlock_rxq(dhd_pub_t *pub)
+{
+}
+
+void
+dhd_os_sdunlock_rxq(dhd_pub_t *pub)
+{
+}
+
+static void
+dhd_os_rxflock(dhd_pub_t *pub)
+{
+ dhd_info_t *dhd;
+
+ dhd = (dhd_info_t *)(pub->info);
+ spin_lock_bh(&dhd->rxf_lock);
+
+}
+
+static void
+dhd_os_rxfunlock(dhd_pub_t *pub)
+{
+ dhd_info_t *dhd;
+
+ dhd = (dhd_info_t *)(pub->info);
+ spin_unlock_bh(&dhd->rxf_lock);
+}
+
+#ifdef DHDTCPACK_SUPPRESS
+void
+dhd_os_tcpacklock(dhd_pub_t *pub)
+{
+ dhd_info_t *dhd;
+
+ dhd = (dhd_info_t *)(pub->info);
+ spin_lock_bh(&dhd->tcpack_lock);
+
+}
+
+void
+dhd_os_tcpackunlock(dhd_pub_t *pub)
+{
+ dhd_info_t *dhd;
+
+ dhd = (dhd_info_t *)(pub->info);
+ spin_unlock_bh(&dhd->tcpack_lock);
+}
+#endif /* DHDTCPACK_SUPPRESS */
+
+uint8* dhd_os_prealloc(dhd_pub_t *dhdpub, int section, uint size, bool kmalloc_if_fail)
+{
+ uint8* buf;
+ gfp_t flags = CAN_SLEEP() ? GFP_KERNEL: GFP_ATOMIC;
+
+ buf = (uint8*)wifi_platform_prealloc(dhdpub->info->adapter, section, size);
+ if (buf == NULL) {
+ DHD_ERROR(("%s: failed to alloc memory, section: %d,"
+ " size: %dbytes\n", __FUNCTION__, section, size));
+ if (kmalloc_if_fail)
+ buf = kmalloc(size, flags);
+ }
+
+ return buf;
+}
+
+void dhd_os_prefree(dhd_pub_t *dhdpub, void *addr, uint size)
+{
+}
+
+#if defined(WL_WIRELESS_EXT)
+struct iw_statistics *
+dhd_get_wireless_stats(struct net_device *dev)
+{
+ int res = 0;
+ dhd_info_t *dhd = DHD_DEV_INFO(dev);
+
+ if (!dhd->pub.up) {
+ return NULL;
+ }
+
+ res = wl_iw_get_wireless_stats(dev, &dhd->iw.wstats);
+
+ if (res == 0)
+ return &dhd->iw.wstats;
+ else
+ return NULL;
+}
+#endif /* defined(WL_WIRELESS_EXT) */
+
+#if defined(CUSTOMER_HW20) && defined(WLANAUDIO)
+static int
+dhd_wlanaudio_event(dhd_info_t *dhd, int *ifidx, void *pktdata,
+ wl_event_msg_t *event, void **data)
+{
+ int cnt;
+ char eabuf[ETHER_ADDR_STR_LEN];
+ struct ether_addr *addr = &event->addr;
+ uint32 type = ntoh32_ua((void *)&event->event_type);
+
+ switch (type) {
+ case WLC_E_TXFAIL:
+ if (addr != NULL)
+ bcm_ether_ntoa(addr, eabuf);
+ else
+ return (BCME_ERROR);
+
+ for (cnt = 0; cnt < MAX_WLANAUDIO_BLACKLIST; cnt++) {
+ if (dhd->wlanaudio_blist[cnt].is_blacklist)
+ break;
+
+ if (!bcmp(&dhd->wlanaudio_blist[cnt].blacklist_addr,
+ addr, ETHER_ADDR_LEN)) {
+ /* Mac address is Same */
+ dhd->wlanaudio_blist[cnt].cnt++;
+
+ if (dhd->wlanaudio_blist[cnt].cnt < 15) {
+ /* black list is false */
+ if ((dhd->wlanaudio_blist[cnt].cnt > 10) &&
+ (jiffies - dhd->wlanaudio_blist[cnt].txfail_jiffies
+ < 100)) {
+ dhd->wlanaudio_blist[cnt].is_blacklist = true;
+ dhd->is_wlanaudio_blist = true;
+ }
+ } else {
+ if ((!dhd->wlanaudio_blist[cnt].is_blacklist) &&
+ (jiffies - dhd->wlanaudio_blist[cnt].txfail_jiffies
+ > 100)) {
+
+ bzero(&dhd->wlanaudio_blist[cnt],
+ sizeof(struct wlanaudio_blacklist));
+ }
+ }
+ break;
+ } else if ((!dhd->wlanaudio_blist[cnt].is_blacklist) &&
+ (!dhd->wlanaudio_blist[cnt].cnt)) {
+ bcopy(addr,
+ (char*)&dhd->wlanaudio_blist[cnt].blacklist_addr,
+ ETHER_ADDR_LEN);
+ dhd->wlanaudio_blist[cnt].cnt++;
+ dhd->wlanaudio_blist[cnt].txfail_jiffies = jiffies;
+
+ bcm_ether_ntoa(&dhd->wlanaudio_blist[cnt].blacklist_addr, eabuf);
+ break;
+ }
+ }
+ break;
+ case WLC_E_AUTH :
+ case WLC_E_AUTH_IND :
+ case WLC_E_DEAUTH :
+ case WLC_E_DEAUTH_IND :
+ case WLC_E_ASSOC:
+ case WLC_E_ASSOC_IND:
+ case WLC_E_REASSOC:
+ case WLC_E_REASSOC_IND:
+ case WLC_E_DISASSOC:
+ case WLC_E_DISASSOC_IND:
+ {
+ int bl_cnt = 0;
+
+ if (addr != NULL)
+ bcm_ether_ntoa(addr, eabuf);
+ else
+ return (BCME_ERROR);
+
+ for (cnt = 0; cnt < MAX_WLANAUDIO_BLACKLIST; cnt++) {
+ if (!bcmp(&dhd->wlanaudio_blist[cnt].blacklist_addr,
+ addr, ETHER_ADDR_LEN)) {
+ /* Mac address is Same */
+ if (dhd->wlanaudio_blist[cnt].is_blacklist) {
+ /* black list is true */
+ bzero(&dhd->wlanaudio_blist[cnt],
+ sizeof(struct wlanaudio_blacklist));
+ }
+ }
+ }
+
+ for (cnt = 0; cnt < MAX_WLANAUDIO_BLACKLIST; cnt++) {
+ if (dhd->wlanaudio_blist[cnt].is_blacklist)
+ bl_cnt++;
+ }
+
+ if (!bl_cnt)
+ {
+ dhd->is_wlanaudio_blist = false;
+ }
+
+ break;
+ }
+ }
+ return BCME_OK;
+}
+#endif /* CUSTOMER_HW20 && WLANAUDIO */
+static int
+dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata,
+ wl_event_msg_t *event, void **data)
+{
+ int bcmerror = 0;
+
+ ASSERT(dhd != NULL);
+
+#if defined(CUSTOMER_HW20) && defined(WLANAUDIO)
+ bcmerror = dhd_wlanaudio_event(dhd, ifidx, pktdata, event, data);
+
+ if (bcmerror != BCME_OK)
+ return (bcmerror);
+#endif /* CUSTOMER_HW20 && WLANAUDIO */
+
+#ifdef SHOW_LOGTRACE
+ bcmerror = wl_host_event(&dhd->pub, ifidx, pktdata, event, data, &dhd->event_data);
+#else
+ bcmerror = wl_host_event(&dhd->pub, ifidx, pktdata, event, data, NULL);
+#endif /* SHOW_LOGTRACE */
+
+ if (bcmerror != BCME_OK)
+ return (bcmerror);
+
+#if defined(WL_WIRELESS_EXT)
+ if (event->bsscfgidx == 0) {
+ /*
+ * Wireless ext is on primary interface only
+ */
+
+ ASSERT(dhd->iflist[*ifidx] != NULL);
+ ASSERT(dhd->iflist[*ifidx]->net != NULL);
+
+ if (dhd->iflist[*ifidx]->net) {
+ wl_iw_event(dhd->iflist[*ifidx]->net, event, *data);
+ }
+ }
+#endif /* defined(WL_WIRELESS_EXT) */
+
+#ifdef WL_CFG80211
+ ASSERT(dhd->iflist[*ifidx] != NULL);
+ ASSERT(dhd->iflist[*ifidx]->net != NULL);
+ if (dhd->iflist[*ifidx]->net)
+ wl_cfg80211_event(dhd->iflist[*ifidx]->net, event, *data);
+#endif /* defined(WL_CFG80211) */
+
+ return (bcmerror);
+}
+
+/* send up locally generated event */
+void
+dhd_sendup_event(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data)
+{
+ switch (ntoh32(event->event_type)) {
+#ifdef WLBTAMP
+ /* Send up locally generated AMP HCI Events */
+ case WLC_E_BTA_HCI_EVENT: {
+ struct sk_buff *p, *skb;
+ bcm_event_t *msg;
+ wl_event_msg_t *p_bcm_event;
+ char *ptr;
+ uint32 len;
+ uint32 pktlen;
+ dhd_if_t *ifp;
+ dhd_info_t *dhd;
+ uchar *eth;
+ int ifidx;
+
+ len = ntoh32(event->datalen);
+ pktlen = sizeof(bcm_event_t) + len + 2;
+ dhd = dhdp->info;
+ ifidx = dhd_ifname2idx(dhd, event->ifname);
+
+ if ((p = PKTGET(dhdp->osh, pktlen, FALSE))) {
+ ASSERT(ISALIGNED((uintptr)PKTDATA(dhdp->osh, p), sizeof(uint32)));
+
+ msg = (bcm_event_t *) PKTDATA(dhdp->osh, p);
+
+ bcopy(&dhdp->mac, &msg->eth.ether_dhost, ETHER_ADDR_LEN);
+ bcopy(&dhdp->mac, &msg->eth.ether_shost, ETHER_ADDR_LEN);
+ ETHER_TOGGLE_LOCALADDR(&msg->eth.ether_shost);
+
+ msg->eth.ether_type = hton16(ETHER_TYPE_BRCM);
+
+ /* BCM Vendor specific header... */
+ msg->bcm_hdr.subtype = hton16(BCMILCP_SUBTYPE_VENDOR_LONG);
+ msg->bcm_hdr.version = BCMILCP_BCM_SUBTYPEHDR_VERSION;
+ bcopy(BRCM_OUI, &msg->bcm_hdr.oui[0], DOT11_OUI_LEN);
+
+ /* vendor spec header length + pvt data length (private indication
+ * hdr + actual message itself)
+ */
+ msg->bcm_hdr.length = hton16(BCMILCP_BCM_SUBTYPEHDR_MINLENGTH +
+ BCM_MSG_LEN + sizeof(wl_event_msg_t) + (uint16)len);
+ msg->bcm_hdr.usr_subtype = hton16(BCMILCP_BCM_SUBTYPE_EVENT);
+
+ PKTSETLEN(dhdp->osh, p, (sizeof(bcm_event_t) + len + 2));
+
+ /* copy wl_event_msg_t into sk_buf */
+
+ /* pointer to wl_event_msg_t in sk_buf */
+ p_bcm_event = &msg->event;
+ bcopy(event, p_bcm_event, sizeof(wl_event_msg_t));
+
+ /* copy hci event into sk_buf */
+ bcopy(data, (p_bcm_event + 1), len);
+
+ msg->bcm_hdr.length = hton16(sizeof(wl_event_msg_t) +
+ ntoh16(msg->bcm_hdr.length));
+ PKTSETLEN(dhdp->osh, p, (sizeof(bcm_event_t) + len + 2));
+
+ ptr = (char *)(msg + 1);
+ /* Last 2 bytes of the message are 0x00 0x00 to signal that there
+ * are no ethertypes which are following this
+ */
+ ptr[len+0] = 0x00;
+ ptr[len+1] = 0x00;
+
+ skb = PKTTONATIVE(dhdp->osh, p);
+ eth = skb->data;
+ len = skb->len;
+
+ ifp = dhd->iflist[ifidx];
+ if (ifp == NULL)
+ ifp = dhd->iflist[0];
+
+ ASSERT(ifp);
+ skb->dev = ifp->net;
+ skb->protocol = eth_type_trans(skb, skb->dev);
+
+ skb->data = eth;
+ skb->len = len;
+
+ /* Strip header, count, deliver upward */
+ skb_pull(skb, ETH_HLEN);
+
+ /* Send the packet */
+ if (in_interrupt()) {
+ netif_rx(skb);
+ } else {
+ netif_rx_ni(skb);
+ }
+ }
+ else {
+ /* Could not allocate a sk_buf */
+ DHD_ERROR(("%s: unable to alloc sk_buf\n", __FUNCTION__));
+ }
+ break;
+ } /* case WLC_E_BTA_HCI_EVENT */
+#endif /* WLBTAMP */
+
+ default:
+ break;
+ }
+}
+
+#ifdef LOG_INTO_TCPDUMP
+void
+dhd_sendup_log(dhd_pub_t *dhdp, void *data, int data_len)
+{
+ struct sk_buff *p, *skb;
+ uint32 pktlen;
+ int len;
+ dhd_if_t *ifp;
+ dhd_info_t *dhd;
+ uchar *skb_data;
+ int ifidx = 0;
+ struct ether_header eth;
+
+ pktlen = sizeof(eth) + data_len;
+ dhd = dhdp->info;
+
+ if ((p = PKTGET(dhdp->osh, pktlen, FALSE))) {
+ ASSERT(ISALIGNED((uintptr)PKTDATA(dhdp->osh, p), sizeof(uint32)));
+
+ bcopy(&dhdp->mac, &eth.ether_dhost, ETHER_ADDR_LEN);
+ bcopy(&dhdp->mac, &eth.ether_shost, ETHER_ADDR_LEN);
+ ETHER_TOGGLE_LOCALADDR(&eth.ether_shost);
+ eth.ether_type = hton16(ETHER_TYPE_BRCM);
+
+ bcopy((void *)&eth, PKTDATA(dhdp->osh, p), sizeof(eth));
+ bcopy(data, PKTDATA(dhdp->osh, p) + sizeof(eth), data_len);
+ skb = PKTTONATIVE(dhdp->osh, p);
+ skb_data = skb->data;
+ len = skb->len;
+
+ ifidx = dhd_ifname2idx(dhd, "wlan0");
+ ifp = dhd->iflist[ifidx];
+ if (ifp == NULL)
+ ifp = dhd->iflist[0];
+
+ ASSERT(ifp);
+ skb->dev = ifp->net;
+ skb->protocol = eth_type_trans(skb, skb->dev);
+ skb->data = skb_data;
+ skb->len = len;
+
+ /* Strip header, count, deliver upward */
+ skb_pull(skb, ETH_HLEN);
+
+ /* Send the packet */
+ if (in_interrupt()) {
+ netif_rx(skb);
+ } else {
+ netif_rx_ni(skb);
+ }
+ }
+ else {
+ /* Could not allocate a sk_buf */
+ DHD_ERROR(("%s: unable to alloc sk_buf\n", __FUNCTION__));
+ }
+}
+#endif /* LOG_INTO_TCPDUMP */
+
+void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar)
+{
+#if defined(BCMSDIO) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
+ struct dhd_info *dhdinfo = dhd->info;
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
+ int timeout = msecs_to_jiffies(IOCTL_RESP_TIMEOUT);
+#else
+ int timeout = (IOCTL_RESP_TIMEOUT / 1000) * HZ;
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
+
+ dhd_os_sdunlock(dhd);
+ wait_event_timeout(dhdinfo->ctrl_wait, (*lockvar == FALSE), timeout);
+ dhd_os_sdlock(dhd);
+#endif /* defined(BCMSDIO) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) */
+ return;
+}
+
+void dhd_wait_event_wakeup(dhd_pub_t *dhd)
+{
+#if defined(BCMSDIO) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
+ struct dhd_info *dhdinfo = dhd->info;
+ if (waitqueue_active(&dhdinfo->ctrl_wait))
+ wake_up(&dhdinfo->ctrl_wait);
+#endif
+ return;
+}
+
+#if defined(BCMSDIO) || defined(BCMPCIE)
+int
+dhd_net_bus_devreset(struct net_device *dev, uint8 flag)
+{
+ int ret = 0;
+ dhd_info_t *dhd = DHD_DEV_INFO(dev);
+
+ if (flag == TRUE) {
+ /* Issue wl down command before resetting the chip */
+ if (dhd_wl_ioctl_cmd(&dhd->pub, WLC_DOWN, NULL, 0, TRUE, 0) < 0) {
+ DHD_TRACE(("%s: wl down failed\n", __FUNCTION__));
+ }
+#ifdef PROP_TXSTATUS
+ if (dhd->pub.wlfc_enabled)
+ dhd_wlfc_deinit(&dhd->pub);
+#endif /* PROP_TXSTATUS */
+#ifdef PNO_SUPPORT
+ if (dhd->pub.pno_state)
+ dhd_pno_deinit(&dhd->pub);
+#endif
+ }
+
+#ifdef BCMSDIO
+ if (!flag) {
+ dhd_update_fw_nv_path(dhd);
+ /* update firmware and nvram path to sdio bus */
+ dhd_bus_update_fw_nv_path(dhd->pub.bus,
+ dhd->fw_path, dhd->nv_path, dhd->conf_path);
+ }
+#endif /* BCMSDIO */
+
+ ret = dhd_bus_devreset(&dhd->pub, flag);
+ if (ret) {
+ DHD_ERROR(("%s: dhd_bus_devreset: %d\n", __FUNCTION__, ret));
+ return ret;
+ }
+
+ return ret;
+}
+
+#ifdef BCMSDIO
+int
+dhd_net_bus_suspend(struct net_device *dev)
+{
+ dhd_info_t *dhd = DHD_DEV_INFO(dev);
+ return dhd_bus_suspend(&dhd->pub);
+}
+
+int
+dhd_net_bus_resume(struct net_device *dev, uint8 stage)
+{
+ dhd_info_t *dhd = DHD_DEV_INFO(dev);
+ return dhd_bus_resume(&dhd->pub, stage);
+}
+
+#endif /* BCMSDIO */
+#endif /* BCMSDIO || BCMPCIE */
+
+int net_os_set_suspend_disable(struct net_device *dev, int val)
+{
+ dhd_info_t *dhd = DHD_DEV_INFO(dev);
+ int ret = 0;
+
+ if (dhd) {
+ ret = dhd->pub.suspend_disable_flag;
+ dhd->pub.suspend_disable_flag = val;
+ }
+ return ret;
+}
+
+int net_os_set_suspend(struct net_device *dev, int val, int force)
+{
+ int ret = 0;
+ dhd_info_t *dhd = DHD_DEV_INFO(dev);
+
+ if (dhd) {
+#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
+ ret = dhd_set_suspend(val, &dhd->pub);
+#else
+ ret = dhd_suspend_resume_helper(dhd, val, force);
+#endif
+#ifdef WL_CFG80211
+ wl_cfg80211_update_power_mode(dev);
+#endif
+ }
+ return ret;
+}
+
+int net_os_set_suspend_bcn_li_dtim(struct net_device *dev, int val)
+{
+ dhd_info_t *dhd = DHD_DEV_INFO(dev);
+
+ if (dhd)
+ dhd->pub.suspend_bcn_li_dtim = val;
+
+ return 0;
+}
+
+#ifdef PKT_FILTER_SUPPORT
+int net_os_rxfilter_add_remove(struct net_device *dev, int add_remove, int num)
+{
+ dhd_info_t *dhd = DHD_DEV_INFO(dev);
+ char *filterp = NULL;
+ int filter_id = 0;
+ int ret = 0;
+
+ if (!dhd_master_mode)
+ add_remove = !add_remove;
+
+ if (!dhd || (num == DHD_UNICAST_FILTER_NUM) ||
+ (num == DHD_MDNS_FILTER_NUM))
+ return ret;
+ if (num >= dhd->pub.pktfilter_count)
+ return -EINVAL;
+ switch (num) {
+ case DHD_BROADCAST_FILTER_NUM:
+ filterp = "101 0 0 0 0xFFFFFFFFFFFF 0xFFFFFFFFFFFF";
+ filter_id = 101;
+ break;
+ case DHD_MULTICAST4_FILTER_NUM:
+ filterp = "102 0 0 0 0xFFFFFF 0x01005E";
+ filter_id = 102;
+ break;
+ case DHD_MULTICAST6_FILTER_NUM:
+ filterp = "103 0 0 0 0xFFFF 0x3333";
+ filter_id = 103;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Add filter */
+ if (add_remove) {
+ dhd->pub.pktfilter[num] = filterp;
+ dhd_pktfilter_offload_set(&dhd->pub, dhd->pub.pktfilter[num]);
+ } else { /* Delete filter */
+ if (dhd->pub.pktfilter[num] != NULL) {
+ dhd_pktfilter_offload_delete(&dhd->pub, filter_id);
+ dhd->pub.pktfilter[num] = NULL;
+ }
+ }
+ return ret;
+}
+
+int dhd_os_enable_packet_filter(dhd_pub_t *dhdp, int val)
+
+{
+ int ret = 0;
+
+ /* Packet filtering is set only if we still in early-suspend and
+ * we need either to turn it ON or turn it OFF
+ * We can always turn it OFF in case of early-suspend, but we turn it
+ * back ON only if suspend_disable_flag was not set
+ */
+ if (dhdp && dhdp->up) {
+ if (dhdp->in_suspend) {
+ if (!val || (val && !dhdp->suspend_disable_flag))
+ dhd_enable_packet_filter(val, dhdp);
+ }
+ }
+ return ret;
+}
+
+/* function to enable/disable packet for Network device */
+int net_os_enable_packet_filter(struct net_device *dev, int val)
+{
+ dhd_info_t *dhd = DHD_DEV_INFO(dev);
+
+ return dhd_os_enable_packet_filter(&dhd->pub, val);
+}
+#endif /* PKT_FILTER_SUPPORT */
+
+int
+dhd_dev_init_ioctl(struct net_device *dev)
+{
+ dhd_info_t *dhd = DHD_DEV_INFO(dev);
+ int ret;
+
+ if ((ret = dhd_sync_with_dongle(&dhd->pub)) < 0)
+ goto done;
+
+done:
+ return ret;
+}
+
+#ifdef PNO_SUPPORT
+/* Linux wrapper to call common dhd_pno_stop_for_ssid */
+int
+dhd_dev_pno_stop_for_ssid(struct net_device *dev)
+{
+ dhd_info_t *dhd = DHD_DEV_INFO(dev);
+
+ return (dhd_pno_stop_for_ssid(&dhd->pub));
+}
+/* Linux wrapper to call common dhd_pno_set_for_ssid */
+int
+dhd_dev_pno_set_for_ssid(struct net_device *dev, wlc_ssid_t* ssids_local, int nssid,
+ uint16 scan_fr, int pno_repeat, int pno_freq_expo_max, uint16 *channel_list, int nchan)
+{
+ dhd_info_t *dhd = DHD_DEV_INFO(dev);
+
+ return (dhd_pno_set_for_ssid(&dhd->pub, ssids_local, nssid, scan_fr,
+ pno_repeat, pno_freq_expo_max, channel_list, nchan));
+}
+
+/* Linux wrapper to call common dhd_pno_enable */
+int
+dhd_dev_pno_enable(struct net_device *dev, int enable)
+{
+ dhd_info_t *dhd = DHD_DEV_INFO(dev);
+
+ return (dhd_pno_enable(&dhd->pub, enable));
+}
+
+/* Linux wrapper to call common dhd_pno_set_for_hotlist */
+int
+dhd_dev_pno_set_for_hotlist(struct net_device *dev, wl_pfn_bssid_t *p_pfn_bssid,
+ struct dhd_pno_hotlist_params *hotlist_params)
+{
+ dhd_info_t *dhd = DHD_DEV_INFO(dev);
+ return (dhd_pno_set_for_hotlist(&dhd->pub, p_pfn_bssid, hotlist_params));
+}
+/* Linux wrapper to call common dhd_dev_pno_stop_for_batch */
+int
+dhd_dev_pno_stop_for_batch(struct net_device *dev)
+{
+ dhd_info_t *dhd = DHD_DEV_INFO(dev);
+ return (dhd_pno_stop_for_batch(&dhd->pub));
+}
+/* Linux wrapper to call common dhd_dev_pno_set_for_batch */
+int
+dhd_dev_pno_set_for_batch(struct net_device *dev, struct dhd_pno_batch_params *batch_params)
+{
+ dhd_info_t *dhd = DHD_DEV_INFO(dev);
+ return (dhd_pno_set_for_batch(&dhd->pub, batch_params));
+}
+/* Linux wrapper to call common dhd_dev_pno_get_for_batch */
+int
+dhd_dev_pno_get_for_batch(struct net_device *dev, char *buf, int bufsize)
+{
+ dhd_info_t *dhd = DHD_DEV_INFO(dev);
+ return (dhd_pno_get_for_batch(&dhd->pub, buf, bufsize, PNO_STATUS_NORMAL));
+}
+#endif /* PNO_SUPPORT */
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (1)
+static void dhd_hang_process(void *dhd_info, void *event_info, u8 event)
+{
+ dhd_info_t *dhd;
+ struct net_device *dev;
+
+ dhd = (dhd_info_t *)dhd_info;
+ dev = dhd->iflist[0]->net;
+
+ if (dev) {
+ rtnl_lock();
+ dev_close(dev);
+ rtnl_unlock();
+#if defined(WL_WIRELESS_EXT)
+ wl_iw_send_priv_event(dev, "HANG");
+#endif
+#if defined(WL_CFG80211)
+ wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED);
+#endif
+ }
+}
+
+
+int dhd_os_send_hang_message(dhd_pub_t *dhdp)
+{
+ int ret = 0;
+ if (dhdp) {
+ if (!dhdp->hang_was_sent) {
+ dhdp->hang_was_sent = 1;
+ dhd_deferred_schedule_work(dhdp->info->dhd_deferred_wq, (void *)dhdp,
+ DHD_WQ_WORK_HANG_MSG, dhd_hang_process, DHD_WORK_PRIORITY_HIGH);
+ }
+ }
+ return ret;
+}
+
+int net_os_send_hang_message(struct net_device *dev)
+{
+ dhd_info_t *dhd = DHD_DEV_INFO(dev);
+ int ret = 0;
+
+ if (dhd) {
+ /* Report FW problem when enabled */
+ if (dhd->pub.hang_report) {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
+ ret = dhd_os_send_hang_message(&dhd->pub);
+#else
+ ret = wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED);
+#endif
+ } else {
+ DHD_ERROR(("%s: FW HANG ignored (for testing purpose) and not sent up\n",
+ __FUNCTION__));
+ /* Enforce bus down to stop any future traffic */
+ dhd->pub.busstate = DHD_BUS_DOWN;
+ }
+ }
+ return ret;
+}
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) && OEM_ANDROID */
+
+
+int dhd_net_wifi_platform_set_power(struct net_device *dev, bool on, unsigned long delay_msec)
+{
+ dhd_info_t *dhd = DHD_DEV_INFO(dev);
+ return wifi_platform_set_power(dhd->adapter, on, delay_msec);
+}
+
+void dhd_get_customized_country_code(struct net_device *dev, char *country_iso_code,
+ wl_country_t *cspec)
+{
+ dhd_info_t *dhd = DHD_DEV_INFO(dev);
+ get_customized_country_code(dhd->adapter, country_iso_code, cspec);
+}
+void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec, bool notify)
+{
+ dhd_info_t *dhd = DHD_DEV_INFO(dev);
+ if (dhd && dhd->pub.up) {
+ memcpy(&dhd->pub.dhd_cspec, cspec, sizeof(wl_country_t));
+#ifdef WL_CFG80211
+ wl_update_wiphybands(NULL, notify);
+#endif
+ }
+}
+
+void dhd_bus_band_set(struct net_device *dev, uint band)
+{
+ dhd_info_t *dhd = DHD_DEV_INFO(dev);
+ if (dhd && dhd->pub.up) {
+#ifdef WL_CFG80211
+ wl_update_wiphybands(NULL, true);
+#endif
+ }
+}
+
+int dhd_net_set_fw_path(struct net_device *dev, char *fw)
+{
+ dhd_info_t *dhd = DHD_DEV_INFO(dev);
+
+ if (!fw || fw[0] == '\0')
+ return -EINVAL;
+
+ strncpy(dhd->fw_path, fw, sizeof(dhd->fw_path) - 1);
+ dhd->fw_path[sizeof(dhd->fw_path)-1] = '\0';
+
+#if defined(SOFTAP)
+ if (strstr(fw, "apsta") != NULL) {
+ DHD_INFO(("GOT APSTA FIRMWARE\n"));
+ ap_fw_loaded = TRUE;
+ } else {
+ DHD_INFO(("GOT STA FIRMWARE\n"));
+ ap_fw_loaded = FALSE;
+ }
+#endif
+ return 0;
+}
+
+void dhd_net_if_lock(struct net_device *dev)
+{
+ dhd_info_t *dhd = DHD_DEV_INFO(dev);
+ dhd_net_if_lock_local(dhd);
+}
+
+void dhd_net_if_unlock(struct net_device *dev)
+{
+ dhd_info_t *dhd = DHD_DEV_INFO(dev);
+ dhd_net_if_unlock_local(dhd);
+}
+
+static void dhd_net_if_lock_local(dhd_info_t *dhd)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1
+ if (dhd)
+ mutex_lock(&dhd->dhd_net_if_mutex);
+#endif
+}
+
+static void dhd_net_if_unlock_local(dhd_info_t *dhd)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1
+ if (dhd)
+ mutex_unlock(&dhd->dhd_net_if_mutex);
+#endif
+}
+
+static void dhd_suspend_lock(dhd_pub_t *pub)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1
+ dhd_info_t *dhd = (dhd_info_t *)(pub->info);
+ if (dhd)
+ mutex_lock(&dhd->dhd_suspend_mutex);
+#endif
+}
+
+static void dhd_suspend_unlock(dhd_pub_t *pub)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1
+ dhd_info_t *dhd = (dhd_info_t *)(pub->info);
+ if (dhd)
+ mutex_unlock(&dhd->dhd_suspend_mutex);
+#endif
+}
+
+unsigned long dhd_os_general_spin_lock(dhd_pub_t *pub)
+{
+ dhd_info_t *dhd = (dhd_info_t *)(pub->info);
+ unsigned long flags = 0;
+
+ if (dhd)
+ spin_lock_irqsave(&dhd->dhd_lock, flags);
+
+ return flags;
+}
+
+void dhd_os_general_spin_unlock(dhd_pub_t *pub, unsigned long flags)
+{
+ dhd_info_t *dhd = (dhd_info_t *)(pub->info);
+
+ if (dhd)
+ spin_unlock_irqrestore(&dhd->dhd_lock, flags);
+}
+
+/* Linux specific multipurpose spinlock API */
+void *
+dhd_os_spin_lock_init(osl_t *osh)
+{
+ /* Adding 4 bytes since the sizeof(spinlock_t) could be 0 */
+ /* if CONFIG_SMP and CONFIG_DEBUG_SPINLOCK are not defined */
+ /* and this results in kernel asserts in internal builds */
+ spinlock_t * lock = MALLOC(osh, sizeof(spinlock_t) + 4);
+ if (lock)
+ spin_lock_init(lock);
+ return ((void *)lock);
+}
+void
+dhd_os_spin_lock_deinit(osl_t *osh, void *lock)
+{
+ MFREE(osh, lock, sizeof(spinlock_t) + 4);
+}
+unsigned long
+dhd_os_spin_lock(void *lock)
+{
+ unsigned long flags = 0;
+
+ if (lock)
+ spin_lock_irqsave((spinlock_t *)lock, flags);
+
+ return flags;
+}
+void
+dhd_os_spin_unlock(void *lock, unsigned long flags)
+{
+ if (lock)
+ spin_unlock_irqrestore((spinlock_t *)lock, flags);
+}
+
+static int
+dhd_get_pend_8021x_cnt(dhd_info_t *dhd)
+{
+ return (atomic_read(&dhd->pend_8021x_cnt));
+}
+
+#define MAX_WAIT_FOR_8021X_TX 100
+
+int
+dhd_wait_pend8021x(struct net_device *dev)
+{
+ dhd_info_t *dhd = DHD_DEV_INFO(dev);
+ int timeout = msecs_to_jiffies(10);
+ int ntimes = MAX_WAIT_FOR_8021X_TX;
+ int pend = dhd_get_pend_8021x_cnt(dhd);
+
+ while (ntimes && pend) {
+ if (pend) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ DHD_PERIM_UNLOCK(&dhd->pub);
+ schedule_timeout(timeout);
+ DHD_PERIM_LOCK(&dhd->pub);
+ set_current_state(TASK_RUNNING);
+ ntimes--;
+ }
+ pend = dhd_get_pend_8021x_cnt(dhd);
+ }
+ if (ntimes == 0)
+ {
+ atomic_set(&dhd->pend_8021x_cnt, 0);
+ DHD_ERROR(("%s: TIMEOUT\n", __FUNCTION__));
+ }
+ return pend;
+}
+
+#ifdef DHD_DEBUG
+int
+write_to_file(dhd_pub_t *dhd, uint8 *buf, int size)
+{
+ int ret = 0;
+ struct file *fp;
+ mm_segment_t old_fs;
+ loff_t pos = 0;
+
+ /* change to KERNEL_DS address limit */
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+
+ /* open file to write */
+ fp = filp_open("/tmp/mem_dump", O_WRONLY|O_CREAT, 0640);
+ if (!fp) {
+ printf("%s: open file error\n", __FUNCTION__);
+ ret = -1;
+ goto exit;
+ }
+
+ /* Write buf to file */
+ fp->f_op->write(fp, buf, size, &pos);
+
+exit:
+ /* free buf before return */
+ MFREE(dhd->osh, buf, size);
+ /* close file before return */
+ if (fp)
+ filp_close(fp, current->files);
+ /* restore previous address limit */
+ set_fs(old_fs);
+
+ return ret;
+}
+#endif /* DHD_DEBUG */
+
+int dhd_os_wake_lock_timeout(dhd_pub_t *pub)
+{
+ dhd_info_t *dhd = (dhd_info_t *)(pub->info);
+ unsigned long flags;
+ int ret = 0;
+
+ if (dhd) {
+ spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
+ ret = dhd->wakelock_rx_timeout_enable > dhd->wakelock_ctrl_timeout_enable ?
+ dhd->wakelock_rx_timeout_enable : dhd->wakelock_ctrl_timeout_enable;
+#ifdef CONFIG_HAS_WAKELOCK
+ if (dhd->wakelock_rx_timeout_enable)
+ wake_lock_timeout(&dhd->wl_rxwake,
+ msecs_to_jiffies(dhd->wakelock_rx_timeout_enable));
+ if (dhd->wakelock_ctrl_timeout_enable)
+ wake_lock_timeout(&dhd->wl_ctrlwake,
+ msecs_to_jiffies(dhd->wakelock_ctrl_timeout_enable));
+#endif
+ dhd->wakelock_rx_timeout_enable = 0;
+ dhd->wakelock_ctrl_timeout_enable = 0;
+ spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
+ }
+ return ret;
+}
+
+int net_os_wake_lock_timeout(struct net_device *dev)
+{
+ dhd_info_t *dhd = DHD_DEV_INFO(dev);
+ int ret = 0;
+
+ if (dhd)
+ ret = dhd_os_wake_lock_timeout(&dhd->pub);
+ return ret;
+}
+
+int dhd_os_wake_lock_rx_timeout_enable(dhd_pub_t *pub, int val)
+{
+ dhd_info_t *dhd = (dhd_info_t *)(pub->info);
+ unsigned long flags;
+
+ if (dhd) {
+ spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
+ if (val > dhd->wakelock_rx_timeout_enable)
+ dhd->wakelock_rx_timeout_enable = val;
+ spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
+ }
+ return 0;
+}
+
+int dhd_os_wake_lock_ctrl_timeout_enable(dhd_pub_t *pub, int val)
+{
+ dhd_info_t *dhd = (dhd_info_t *)(pub->info);
+ unsigned long flags;
+
+ if (dhd) {
+ spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
+ if (val > dhd->wakelock_ctrl_timeout_enable)
+ dhd->wakelock_ctrl_timeout_enable = val;
+ spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
+ }
+ return 0;
+}
+
+int dhd_os_wake_lock_ctrl_timeout_cancel(dhd_pub_t *pub)
+{
+ dhd_info_t *dhd = (dhd_info_t *)(pub->info);
+ unsigned long flags;
+
+ if (dhd) {
+ spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
+ dhd->wakelock_ctrl_timeout_enable = 0;
+#ifdef CONFIG_HAS_WAKELOCK
+ if (wake_lock_active(&dhd->wl_ctrlwake))
+ wake_unlock(&dhd->wl_ctrlwake);
+#endif
+ spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
+ }
+ return 0;
+}
+
+int net_os_wake_lock_rx_timeout_enable(struct net_device *dev, int val)
+{
+ dhd_info_t *dhd = DHD_DEV_INFO(dev);
+ int ret = 0;
+
+ if (dhd)
+ ret = dhd_os_wake_lock_rx_timeout_enable(&dhd->pub, val);
+ return ret;
+}
+
+int net_os_wake_lock_ctrl_timeout_enable(struct net_device *dev, int val)
+{
+ dhd_info_t *dhd = DHD_DEV_INFO(dev);
+ int ret = 0;
+
+ if (dhd)
+ ret = dhd_os_wake_lock_ctrl_timeout_enable(&dhd->pub, val);
+ return ret;
+}
+
+int dhd_os_wake_lock(dhd_pub_t *pub)
+{
+ dhd_info_t *dhd = (dhd_info_t *)(pub->info);
+ unsigned long flags;
+ int ret = 0;
+
+ if (dhd) {
+ spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
+
+ if (dhd->wakelock_counter == 0 && !dhd->waive_wakelock) {
+#ifdef CONFIG_HAS_WAKELOCK
+ wake_lock(&dhd->wl_wifi);
+#elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
+ dhd_bus_dev_pm_stay_awake(pub);
+#endif
+ }
+ dhd->wakelock_counter++;
+ ret = dhd->wakelock_counter;
+ spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
+ }
+ return ret;
+}
+
+int net_os_wake_lock(struct net_device *dev)
+{
+ dhd_info_t *dhd = DHD_DEV_INFO(dev);
+ int ret = 0;
+
+ if (dhd)
+ ret = dhd_os_wake_lock(&dhd->pub);
+ return ret;
+}
+
+int dhd_os_wake_unlock(dhd_pub_t *pub)
+{
+ dhd_info_t *dhd = (dhd_info_t *)(pub->info);
+ unsigned long flags;
+ int ret = 0;
+
+ dhd_os_wake_lock_timeout(pub);
+ if (dhd) {
+ spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
+ if (dhd->wakelock_counter > 0) {
+ dhd->wakelock_counter--;
+ if (dhd->wakelock_counter == 0 && !dhd->waive_wakelock) {
+#ifdef CONFIG_HAS_WAKELOCK
+ wake_unlock(&dhd->wl_wifi);
+#elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
+ dhd_bus_dev_pm_relax(pub);
+#endif
+ }
+ ret = dhd->wakelock_counter;
+ }
+ spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
+ }
+ return ret;
+}
+
+int dhd_os_check_wakelock(dhd_pub_t *pub)
+{
+#if defined(CONFIG_HAS_WAKELOCK) || (defined(BCMSDIO) && (LINUX_VERSION_CODE > \
+ KERNEL_VERSION(2, 6, 36)))
+ dhd_info_t *dhd;
+
+ if (!pub)
+ return 0;
+ dhd = (dhd_info_t *)(pub->info);
+#endif /* CONFIG_HAS_WAKELOCK || BCMSDIO */
+
+#ifdef CONFIG_HAS_WAKELOCK
+ /* Indicate to the SD Host to avoid going to suspend if internal locks are up */
+ if (dhd && (wake_lock_active(&dhd->wl_wifi) ||
+ (wake_lock_active(&dhd->wl_wdwake))))
+ return 1;
+#elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
+ if (dhd && (dhd->wakelock_counter > 0) && dhd_bus_dev_pm_enabled(pub))
+ return 1;
+#endif
+ return 0;
+}
+
+int dhd_os_check_wakelock_all(dhd_pub_t *pub)
+{
+#if defined(CONFIG_HAS_WAKELOCK) || (defined(BCMSDIO) && (LINUX_VERSION_CODE > \
+ KERNEL_VERSION(2, 6, 36)))
+ dhd_info_t *dhd;
+
+ if (!pub)
+ return 0;
+ dhd = (dhd_info_t *)(pub->info);
+#endif /* CONFIG_HAS_WAKELOCK || BCMSDIO */
+
+#ifdef CONFIG_HAS_WAKELOCK
+ /* Indicate to the SD Host to avoid going to suspend if internal locks are up */
+ if (dhd && (wake_lock_active(&dhd->wl_wifi) ||
+ wake_lock_active(&dhd->wl_wdwake) ||
+ wake_lock_active(&dhd->wl_rxwake) ||
+ wake_lock_active(&dhd->wl_ctrlwake))) {
+ return 1;
+ }
+#elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
+ if (dhd && (dhd->wakelock_counter > 0) && dhd_bus_dev_pm_enabled(pub))
+ return 1;
+#endif
+ return 0;
+}
+
+int net_os_wake_unlock(struct net_device *dev)
+{
+ dhd_info_t *dhd = DHD_DEV_INFO(dev);
+ int ret = 0;
+
+ if (dhd)
+ ret = dhd_os_wake_unlock(&dhd->pub);
+ return ret;
+}
+
+int dhd_os_wd_wake_lock(dhd_pub_t *pub)
+{
+ dhd_info_t *dhd = (dhd_info_t *)(pub->info);
+ unsigned long flags;
+ int ret = 0;
+
+ if (dhd) {
+ spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
+#ifdef CONFIG_HAS_WAKELOCK
+ /* if wakelock_wd_counter was never used : lock it at once */
+ if (!dhd->wakelock_wd_counter)
+ wake_lock(&dhd->wl_wdwake);
+#endif
+ dhd->wakelock_wd_counter++;
+ ret = dhd->wakelock_wd_counter;
+ spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
+ }
+ return ret;
+}
+
+int dhd_os_wd_wake_unlock(dhd_pub_t *pub)
+{
+ dhd_info_t *dhd = (dhd_info_t *)(pub->info);
+ unsigned long flags;
+ int ret = 0;
+
+ if (dhd) {
+ spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
+ if (dhd->wakelock_wd_counter) {
+ dhd->wakelock_wd_counter = 0;
+#ifdef CONFIG_HAS_WAKELOCK
+ wake_unlock(&dhd->wl_wdwake);
+#endif
+ }
+ spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
+ }
+ return ret;
+}
+
+#ifdef BCMPCIE_OOB_HOST_WAKE
+int dhd_os_oob_irq_wake_lock_timeout(dhd_pub_t *pub, int val)
+{
+ dhd_info_t *dhd = (dhd_info_t *)(pub->info);
+ int ret = 0;
+
+ if (dhd) {
+#ifdef CONFIG_HAS_WAKELOCK
+ wake_lock_timeout(&dhd->wl_intrwake, msecs_to_jiffies(val));
+#endif
+ }
+ return ret;
+}
+
+int dhd_os_oob_irq_wake_unlock(dhd_pub_t *pub)
+{
+ dhd_info_t *dhd = (dhd_info_t *)(pub->info);
+ int ret = 0;
+
+ if (dhd) {
+#ifdef CONFIG_HAS_WAKELOCK
+ /* if wl_intrwake is active, unlock it */
+ if (wake_lock_active(&dhd->wl_intrwake)) {
+ wake_unlock(&dhd->wl_intrwake);
+ }
+#endif
+ }
+ return ret;
+}
+#endif /* BCMPCIE_OOB_HOST_WAKE */
+
+/* waive wakelocks for operations such as IOVARs in suspend function, must be closed
+ * by a paired function call to dhd_wakelock_restore. returns current wakelock counter
+ */
+int dhd_os_wake_lock_waive(dhd_pub_t *pub)
+{
+ dhd_info_t *dhd = (dhd_info_t *)(pub->info);
+ unsigned long flags;
+ int ret = 0;
+
+ if (dhd) {
+ spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
+ /* dhd_wakelock_waive/dhd_wakelock_restore must be paired */
+ if (dhd->waive_wakelock == FALSE) {
+ /* record current lock status */
+ dhd->wakelock_before_waive = dhd->wakelock_counter;
+ dhd->waive_wakelock = TRUE;
+ }
+ ret = dhd->wakelock_wd_counter;
+ spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
+ }
+ return ret;
+}
+
+int dhd_os_wake_lock_restore(dhd_pub_t *pub)
+{
+ dhd_info_t *dhd = (dhd_info_t *)(pub->info);
+ unsigned long flags;
+ int ret = 0;
+
+ if (!dhd)
+ return 0;
+
+ spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
+ /* dhd_wakelock_waive/dhd_wakelock_restore must be paired */
+ if (!dhd->waive_wakelock)
+ goto exit;
+
+ dhd->waive_wakelock = FALSE;
+ /* if somebody else acquires wakelock between dhd_wakelock_waive/dhd_wakelock_restore,
+ * we need to make it up by calling wake_lock or pm_stay_awake. or if somebody releases
+ * the lock in between, do the same by calling wake_unlock or pm_relax
+ */
+ if (dhd->wakelock_before_waive == 0 && dhd->wakelock_counter > 0) {
+#ifdef CONFIG_HAS_WAKELOCK
+ wake_lock(&dhd->wl_wifi);
+#elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
+ dhd_bus_dev_pm_stay_awake(&dhd->pub);
+#endif
+ } else if (dhd->wakelock_before_waive > 0 && dhd->wakelock_counter == 0) {
+#ifdef CONFIG_HAS_WAKELOCK
+ wake_unlock(&dhd->wl_wifi);
+#elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
+ dhd_bus_dev_pm_relax(&dhd->pub);
+#endif
+ }
+ dhd->wakelock_before_waive = 0;
+exit:
+ ret = dhd->wakelock_wd_counter;
+ spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
+ return ret;
+}
+
+bool dhd_os_check_if_up(dhd_pub_t *pub)
+{
+ if (!pub)
+ return FALSE;
+ return pub->up;
+}
+
+/* function to collect firmware, chip id and chip version info */
+void dhd_set_version_info(dhd_pub_t *dhdp, char *fw)
+{
+ int i;
+
+ i = snprintf(info_string, sizeof(info_string),
+ " Driver: %s\n Firmware: %s ", EPI_VERSION_STR, fw);
+ printf("%s\n", info_string);
+
+ if (!dhdp)
+ return;
+
+ i = snprintf(&info_string[i], sizeof(info_string) - i,
+ "\n Chip: %x Rev %x Pkg %x", dhd_bus_chip_id(dhdp),
+ dhd_bus_chiprev_id(dhdp), dhd_bus_chippkg_id(dhdp));
+}
+
+int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd)
+{
+ int ifidx;
+ int ret = 0;
+ dhd_info_t *dhd = NULL;
+
+ if (!net || !DEV_PRIV(net)) {
+ DHD_ERROR(("%s invalid parameter\n", __FUNCTION__));
+ return -EINVAL;
+ }
+
+ dhd = DHD_DEV_INFO(net);
+ if (!dhd)
+ return -EINVAL;
+
+ ifidx = dhd_net2idx(dhd, net);
+ if (ifidx == DHD_BAD_IF) {
+ DHD_ERROR(("%s bad ifidx\n", __FUNCTION__));
+ return -ENODEV;
+ }
+
+ DHD_OS_WAKE_LOCK(&dhd->pub);
+ DHD_PERIM_LOCK(&dhd->pub);
+
+ ret = dhd_wl_ioctl(&dhd->pub, ifidx, ioc, ioc->buf, ioc->len);
+ dhd_check_hang(net, &dhd->pub, ret);
+
+ DHD_PERIM_UNLOCK(&dhd->pub);
+ DHD_OS_WAKE_UNLOCK(&dhd->pub);
+
+ return ret;
+}
+
+bool dhd_os_check_hang(dhd_pub_t *dhdp, int ifidx, int ret)
+{
+ struct net_device *net;
+
+ net = dhd_idx2net(dhdp, ifidx);
+ if (!net) {
+ DHD_ERROR(("%s : Invalid index : %d\n", __FUNCTION__, ifidx));
+ return -EINVAL;
+ }
+
+ return dhd_check_hang(net, dhdp, ret);
+}
+
+/* Return instance */
+int dhd_get_instance(dhd_pub_t *dhdp)
+{
+ return dhdp->info->unit;
+}
+
+
+#ifdef PROP_TXSTATUS
+
+void dhd_wlfc_plat_init(void *dhd)
+{
+ return;
+}
+
+void dhd_wlfc_plat_deinit(void *dhd)
+{
+ return;
+}
+
+bool dhd_wlfc_skip_fc(void)
+{
+ return FALSE;
+}
+#endif /* PROP_TXSTATUS */
+
+#ifdef BCMDBGFS
+
+#include <linux/debugfs.h>
+
+extern uint32 dhd_readregl(void *bp, uint32 addr);
+extern uint32 dhd_writeregl(void *bp, uint32 addr, uint32 data);
+
+typedef struct dhd_dbgfs {
+ struct dentry *debugfs_dir;
+ struct dentry *debugfs_mem;
+ dhd_pub_t *dhdp;
+ uint32 size;
+} dhd_dbgfs_t;
+
+dhd_dbgfs_t g_dbgfs;
+
+static int
+dhd_dbg_state_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static ssize_t
+dhd_dbg_state_read(struct file *file, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ ssize_t rval;
+ uint32 tmp;
+ loff_t pos = *ppos;
+ size_t ret;
+
+ if (pos < 0)
+ return -EINVAL;
+ if (pos >= g_dbgfs.size || !count)
+ return 0;
+ if (count > g_dbgfs.size - pos)
+ count = g_dbgfs.size - pos;
+
+ /* Basically enforce aligned 4 byte reads. It's up to the user to work out the details */
+ tmp = dhd_readregl(g_dbgfs.dhdp->bus, file->f_pos & (~3));
+
+ ret = copy_to_user(ubuf, &tmp, 4);
+ if (ret == count)
+ return -EFAULT;
+
+ count -= ret;
+ *ppos = pos + count;
+ rval = count;
+
+ return rval;
+}
+
+
+static ssize_t
+dhd_debugfs_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos)
+{
+ loff_t pos = *ppos;
+ size_t ret;
+ uint32 buf;
+
+ if (pos < 0)
+ return -EINVAL;
+ if (pos >= g_dbgfs.size || !count)
+ return 0;
+ if (count > g_dbgfs.size - pos)
+ count = g_dbgfs.size - pos;
+
+ ret = copy_from_user(&buf, ubuf, sizeof(uint32));
+ if (ret == count)
+ return -EFAULT;
+
+ /* Basically enforce aligned 4 byte writes. It's up to the user to work out the details */
+ dhd_writeregl(g_dbgfs.dhdp->bus, file->f_pos & (~3), buf);
+
+ return count;
+}
+
+
+loff_t
+dhd_debugfs_lseek(struct file *file, loff_t off, int whence)
+{
+ loff_t pos = -1;
+
+ switch (whence) {
+ case 0:
+ pos = off;
+ break;
+ case 1:
+ pos = file->f_pos + off;
+ break;
+ case 2:
+ pos = g_dbgfs.size - off;
+ }
+ return (pos < 0 || pos > g_dbgfs.size) ? -EINVAL : (file->f_pos = pos);
+}
+
+static const struct file_operations dhd_dbg_state_ops = {
+ .read = dhd_dbg_state_read,
+ .write = dhd_debugfs_write,
+ .open = dhd_dbg_state_open,
+ .llseek = dhd_debugfs_lseek
+};
+
+static void dhd_dbg_create(void)
+{
+ if (g_dbgfs.debugfs_dir) {
+ g_dbgfs.debugfs_mem = debugfs_create_file("mem", 0644, g_dbgfs.debugfs_dir,
+ NULL, &dhd_dbg_state_ops);
+ }
+}
+
+void dhd_dbg_init(dhd_pub_t *dhdp)
+{
+ int err;
+
+ g_dbgfs.dhdp = dhdp;
+ g_dbgfs.size = 0x20000000; /* Allow access to various cores regs */
+
+ g_dbgfs.debugfs_dir = debugfs_create_dir("dhd", 0);
+ if (IS_ERR(g_dbgfs.debugfs_dir)) {
+ err = PTR_ERR(g_dbgfs.debugfs_dir);
+ g_dbgfs.debugfs_dir = NULL;
+ return;
+ }
+
+ dhd_dbg_create();
+
+ return;
+}
+
+void dhd_dbg_remove(void)
+{
+ debugfs_remove(g_dbgfs.debugfs_mem);
+ debugfs_remove(g_dbgfs.debugfs_dir);
+
+ bzero((unsigned char *) &g_dbgfs, sizeof(g_dbgfs));
+
+}
+#endif /* ifdef BCMDBGFS */
+
+#ifdef WLMEDIA_HTSF
+
+static
+void dhd_htsf_addtxts(dhd_pub_t *dhdp, void *pktbuf)
+{
+ dhd_info_t *dhd = (dhd_info_t *)(dhdp->info);
+ struct sk_buff *skb;
+ uint32 htsf = 0;
+ uint16 dport = 0, oldmagic = 0xACAC;
+ char *p1;
+ htsfts_t ts;
+
+ /* timestamp packet */
+
+ p1 = (char*) PKTDATA(dhdp->osh, pktbuf);
+
+ if (PKTLEN(dhdp->osh, pktbuf) > HTSF_MINLEN) {
+/* memcpy(&proto, p1+26, 4); */
+ memcpy(&dport, p1+40, 2);
+/* proto = ((ntoh32(proto))>> 16) & 0xFF; */
+ dport = ntoh16(dport);
+ }
+
+ /* timestamp only if icmp or udb iperf with port 5555 */
+/* if (proto == 17 && dport == tsport) { */
+ if (dport >= tsport && dport <= tsport + 20) {
+
+ skb = (struct sk_buff *) pktbuf;
+
+ htsf = dhd_get_htsf(dhd, 0);
+ memset(skb->data + 44, 0, 2); /* clear checksum */
+ memcpy(skb->data+82, &oldmagic, 2);
+ memcpy(skb->data+84, &htsf, 4);
+
+ memset(&ts, 0, sizeof(htsfts_t));
+ ts.magic = HTSFMAGIC;
+ ts.prio = PKTPRIO(pktbuf);
+ ts.seqnum = htsf_seqnum++;
+ ts.c10 = get_cycles();
+ ts.t10 = htsf;
+ ts.endmagic = HTSFENDMAGIC;
+
+ memcpy(skb->data + HTSF_HOSTOFFSET, &ts, sizeof(ts));
+ }
+}
+
+static void dhd_dump_htsfhisto(histo_t *his, char *s)
+{
+ int pktcnt = 0, curval = 0, i;
+ for (i = 0; i < (NUMBIN-2); i++) {
+ curval += 500;
+ printf("%d ", his->bin[i]);
+ pktcnt += his->bin[i];
+ }
+ printf(" max: %d TotPkt: %d neg: %d [%s]\n", his->bin[NUMBIN-2], pktcnt,
+ his->bin[NUMBIN-1], s);
+}
+
+static
+void sorttobin(int value, histo_t *histo)
+{
+ int i, binval = 0;
+
+ if (value < 0) {
+ histo->bin[NUMBIN-1]++;
+ return;
+ }
+ if (value > histo->bin[NUMBIN-2]) /* store the max value */
+ histo->bin[NUMBIN-2] = value;
+
+ for (i = 0; i < (NUMBIN-2); i++) {
+ binval += 500; /* 500m s bins */
+ if (value <= binval) {
+ histo->bin[i]++;
+ return;
+ }
+ }
+ histo->bin[NUMBIN-3]++;
+}
+
+static
+void dhd_htsf_addrxts(dhd_pub_t *dhdp, void *pktbuf)
+{
+ dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
+ struct sk_buff *skb;
+ char *p1;
+ uint16 old_magic;
+ int d1, d2, d3, end2end;
+ htsfts_t *htsf_ts;
+ uint32 htsf;
+
+ skb = PKTTONATIVE(dhdp->osh, pktbuf);
+ p1 = (char*)PKTDATA(dhdp->osh, pktbuf);
+
+ if (PKTLEN(osh, pktbuf) > HTSF_MINLEN) {
+ memcpy(&old_magic, p1+78, 2);
+ htsf_ts = (htsfts_t*) (p1 + HTSF_HOSTOFFSET - 4);
+ }
+ else
+ return;
+
+ if (htsf_ts->magic == HTSFMAGIC) {
+ htsf_ts->tE0 = dhd_get_htsf(dhd, 0);
+ htsf_ts->cE0 = get_cycles();
+ }
+
+ if (old_magic == 0xACAC) {
+
+ tspktcnt++;
+ htsf = dhd_get_htsf(dhd, 0);
+ memcpy(skb->data+92, &htsf, sizeof(uint32));
+
+ memcpy(&ts[tsidx].t1, skb->data+80, 16);
+
+ d1 = ts[tsidx].t2 - ts[tsidx].t1;
+ d2 = ts[tsidx].t3 - ts[tsidx].t2;
+ d3 = ts[tsidx].t4 - ts[tsidx].t3;
+ end2end = ts[tsidx].t4 - ts[tsidx].t1;
+
+ sorttobin(d1, &vi_d1);
+ sorttobin(d2, &vi_d2);
+ sorttobin(d3, &vi_d3);
+ sorttobin(end2end, &vi_d4);
+
+ if (end2end > 0 && end2end > maxdelay) {
+ maxdelay = end2end;
+ maxdelaypktno = tspktcnt;
+ memcpy(&maxdelayts, &ts[tsidx], 16);
+ }
+ if (++tsidx >= TSMAX)
+ tsidx = 0;
+ }
+}
+
+uint32 dhd_get_htsf(dhd_info_t *dhd, int ifidx)
+{
+ uint32 htsf = 0, cur_cycle, delta, delta_us;
+ uint32 factor, baseval, baseval2;
+ cycles_t t;
+
+ t = get_cycles();
+ cur_cycle = t;
+
+ if (cur_cycle > dhd->htsf.last_cycle)
+ delta = cur_cycle - dhd->htsf.last_cycle;
+ else {
+ delta = cur_cycle + (0xFFFFFFFF - dhd->htsf.last_cycle);
+ }
+
+ delta = delta >> 4;
+
+ if (dhd->htsf.coef) {
+ /* times ten to get the first digit */
+ factor = (dhd->htsf.coef*10 + dhd->htsf.coefdec1);
+ baseval = (delta*10)/factor;
+ baseval2 = (delta*10)/(factor+1);
+ delta_us = (baseval - (((baseval - baseval2) * dhd->htsf.coefdec2)) / 10);
+ htsf = (delta_us << 4) + dhd->htsf.last_tsf + HTSF_BUS_DELAY;
+ }
+ else {
+ DHD_ERROR(("-------dhd->htsf.coef = 0 -------\n"));
+ }
+
+ return htsf;
+}
+
+static void dhd_dump_latency(void)
+{
+ int i, max = 0;
+ int d1, d2, d3, d4, d5;
+
+ printf("T1 T2 T3 T4 d1 d2 t4-t1 i \n");
+ for (i = 0; i < TSMAX; i++) {
+ d1 = ts[i].t2 - ts[i].t1;
+ d2 = ts[i].t3 - ts[i].t2;
+ d3 = ts[i].t4 - ts[i].t3;
+ d4 = ts[i].t4 - ts[i].t1;
+ d5 = ts[max].t4-ts[max].t1;
+ if (d4 > d5 && d4 > 0) {
+ max = i;
+ }
+ printf("%08X %08X %08X %08X \t%d %d %d %d i=%d\n",
+ ts[i].t1, ts[i].t2, ts[i].t3, ts[i].t4,
+ d1, d2, d3, d4, i);
+ }
+
+ printf("current idx = %d \n", tsidx);
+
+ printf("Highest latency %d pkt no.%d total=%d\n", maxdelay, maxdelaypktno, tspktcnt);
+ printf("%08X %08X %08X %08X \t%d %d %d %d\n",
+ maxdelayts.t1, maxdelayts.t2, maxdelayts.t3, maxdelayts.t4,
+ maxdelayts.t2 - maxdelayts.t1,
+ maxdelayts.t3 - maxdelayts.t2,
+ maxdelayts.t4 - maxdelayts.t3,
+ maxdelayts.t4 - maxdelayts.t1);
+}
+
+
+static int
+dhd_ioctl_htsf_get(dhd_info_t *dhd, int ifidx)
+{
+ wl_ioctl_t ioc;
+ char buf[32];
+ int ret;
+ uint32 s1, s2;
+
+ struct tsf {
+ uint32 low;
+ uint32 high;
+ } tsf_buf;
+
+ memset(&ioc, 0, sizeof(ioc));
+ memset(&tsf_buf, 0, sizeof(tsf_buf));
+
+ ioc.cmd = WLC_GET_VAR;
+ ioc.buf = buf;
+ ioc.len = (uint)sizeof(buf);
+ ioc.set = FALSE;
+
+ strncpy(buf, "tsf", sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = '\0';
+ s1 = dhd_get_htsf(dhd, 0);
+ if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) {
+ if (ret == -EIO) {
+ DHD_ERROR(("%s: tsf is not supported by device\n",
+ dhd_ifname(&dhd->pub, ifidx)));
+ return -EOPNOTSUPP;
+ }
+ return ret;
+ }
+ s2 = dhd_get_htsf(dhd, 0);
+
+ memcpy(&tsf_buf, buf, sizeof(tsf_buf));
+ printf(" TSF_h=%04X lo=%08X Calc:htsf=%08X, coef=%d.%d%d delta=%d ",
+ tsf_buf.high, tsf_buf.low, s2, dhd->htsf.coef, dhd->htsf.coefdec1,
+ dhd->htsf.coefdec2, s2-tsf_buf.low);
+ printf("lasttsf=%08X lastcycle=%08X\n", dhd->htsf.last_tsf, dhd->htsf.last_cycle);
+ return 0;
+}
+
+void htsf_update(dhd_info_t *dhd, void *data)
+{
+ static ulong cur_cycle = 0, prev_cycle = 0;
+ uint32 htsf, tsf_delta = 0;
+ uint32 hfactor = 0, cyc_delta, dec1 = 0, dec2, dec3, tmp;
+ ulong b, a;
+ cycles_t t;
+
+ /* cycles_t in inlcude/mips/timex.h */
+
+ t = get_cycles();
+
+ prev_cycle = cur_cycle;
+ cur_cycle = t;
+
+ if (cur_cycle > prev_cycle)
+ cyc_delta = cur_cycle - prev_cycle;
+ else {
+ b = cur_cycle;
+ a = prev_cycle;
+ cyc_delta = cur_cycle + (0xFFFFFFFF - prev_cycle);
+ }
+
+ if (data == NULL)
+ printf(" tsf update ata point er is null \n");
+
+ memcpy(&prev_tsf, &cur_tsf, sizeof(tsf_t));
+ memcpy(&cur_tsf, data, sizeof(tsf_t));
+
+ if (cur_tsf.low == 0) {
+ DHD_INFO((" ---- 0 TSF, do not update, return\n"));
+ return;
+ }
+
+ if (cur_tsf.low > prev_tsf.low)
+ tsf_delta = (cur_tsf.low - prev_tsf.low);
+ else {
+ DHD_INFO((" ---- tsf low is smaller cur_tsf= %08X, prev_tsf=%08X, \n",
+ cur_tsf.low, prev_tsf.low));
+ if (cur_tsf.high > prev_tsf.high) {
+ tsf_delta = cur_tsf.low + (0xFFFFFFFF - prev_tsf.low);
+ DHD_INFO((" ---- Wrap around tsf coutner adjusted TSF=%08X\n", tsf_delta));
+ }
+ else
+ return; /* do not update */
+ }
+
+ if (tsf_delta) {
+ hfactor = cyc_delta / tsf_delta;
+ tmp = (cyc_delta - (hfactor * tsf_delta))*10;
+ dec1 = tmp/tsf_delta;
+ dec2 = ((tmp - dec1*tsf_delta)*10) / tsf_delta;
+ tmp = (tmp - (dec1*tsf_delta))*10;
+ dec3 = ((tmp - dec2*tsf_delta)*10) / tsf_delta;
+
+ if (dec3 > 4) {
+ if (dec2 == 9) {
+ dec2 = 0;
+ if (dec1 == 9) {
+ dec1 = 0;
+ hfactor++;
+ }
+ else {
+ dec1++;
+ }
+ }
+ else
+ dec2++;
+ }
+ }
+
+ if (hfactor) {
+ htsf = ((cyc_delta * 10) / (hfactor*10+dec1)) + prev_tsf.low;
+ dhd->htsf.coef = hfactor;
+ dhd->htsf.last_cycle = cur_cycle;
+ dhd->htsf.last_tsf = cur_tsf.low;
+ dhd->htsf.coefdec1 = dec1;
+ dhd->htsf.coefdec2 = dec2;
+ }
+ else {
+ htsf = prev_tsf.low;
+ }
+}
+
+#endif /* WLMEDIA_HTSF */
+
+#ifdef CUSTOM_SET_CPUCORE
+void dhd_set_cpucore(dhd_pub_t *dhd, int set)
+{
+ int e_dpc = 0, e_rxf = 0, retry_set = 0;
+
+ if (!(dhd->chan_isvht80)) {
+ DHD_ERROR(("%s: chan_status(%d) cpucore!!!\n", __FUNCTION__, dhd->chan_isvht80));
+ return;
+ }
+
+ if (DPC_CPUCORE) {
+ do {
+ if (set == TRUE) {
+ e_dpc = set_cpus_allowed_ptr(dhd->current_dpc,
+ cpumask_of(DPC_CPUCORE));
+ } else {
+ e_dpc = set_cpus_allowed_ptr(dhd->current_dpc,
+ cpumask_of(PRIMARY_CPUCORE));
+ }
+ if (retry_set++ > MAX_RETRY_SET_CPUCORE) {
+ DHD_ERROR(("%s: dpc(%d) invalid cpu!\n", __FUNCTION__, e_dpc));
+ return;
+ }
+ if (e_dpc < 0)
+ OSL_SLEEP(1);
+ } while (e_dpc < 0);
+ }
+ if (RXF_CPUCORE) {
+ do {
+ if (set == TRUE) {
+ e_rxf = set_cpus_allowed_ptr(dhd->current_rxf,
+ cpumask_of(RXF_CPUCORE));
+ } else {
+ e_rxf = set_cpus_allowed_ptr(dhd->current_rxf,
+ cpumask_of(PRIMARY_CPUCORE));
+ }
+ if (retry_set++ > MAX_RETRY_SET_CPUCORE) {
+ DHD_ERROR(("%s: rxf(%d) invalid cpu!\n", __FUNCTION__, e_rxf));
+ return;
+ }
+ if (e_rxf < 0)
+ OSL_SLEEP(1);
+ } while (e_rxf < 0);
+ }
+#ifdef DHD_OF_SUPPORT
+ interrupt_set_cpucore(set);
+#endif /* DHD_OF_SUPPORT */
+ DHD_TRACE(("%s: set(%d) cpucore success!\n", __FUNCTION__, set));
+
+ return;
+}
+#endif /* CUSTOM_SET_CPUCORE */
+#if defined(DHD_TCP_WINSIZE_ADJUST)
+static int dhd_port_list_match(int port)
+{
+ int i;
+ for (i = 0; i < MAX_TARGET_PORTS; i++) {
+ if (target_ports[i] == port)
+ return 1;
+ }
+ return 0;
+}
+static void dhd_adjust_tcp_winsize(int op_mode, struct sk_buff *skb)
+{
+ struct iphdr *ipheader;
+ struct tcphdr *tcpheader;
+ uint16 win_size;
+ int32 incremental_checksum;
+
+ if (!(op_mode & DHD_FLAG_HOSTAP_MODE))
+ return;
+ if (skb == NULL || skb->data == NULL)
+ return;
+
+ ipheader = (struct iphdr*)(skb->data);
+
+ if (ipheader->protocol == IPPROTO_TCP) {
+ tcpheader = (struct tcphdr*) skb_pull(skb, (ipheader->ihl)<<2);
+ if (tcpheader) {
+ win_size = ntoh16(tcpheader->window);
+ if (win_size < MIN_TCP_WIN_SIZE &&
+ dhd_port_list_match(ntoh16(tcpheader->dest))) {
+ incremental_checksum = ntoh16(tcpheader->check);
+ incremental_checksum += win_size - win_size*WIN_SIZE_SCALE_FACTOR;
+ if (incremental_checksum < 0)
+ --incremental_checksum;
+ tcpheader->window = hton16(win_size*WIN_SIZE_SCALE_FACTOR);
+ tcpheader->check = hton16((unsigned short)incremental_checksum);
+ }
+ }
+ skb_push(skb, (ipheader->ihl)<<2);
+ }
+}
+#endif /* DHD_TCP_WINSIZE_ADJUST */
+
+/* Get interface specific ap_isolate configuration */
+int dhd_get_ap_isolate(dhd_pub_t *dhdp, uint32 idx)
+{
+ dhd_info_t *dhd = dhdp->info;
+ dhd_if_t *ifp;
+
+ ASSERT(idx < DHD_MAX_IFS);
+
+ ifp = dhd->iflist[idx];
+
+ return ifp->ap_isolate;
+}
+
+/* Set interface specific ap_isolate configuration */
+int dhd_set_ap_isolate(dhd_pub_t *dhdp, uint32 idx, int val)
+{
+ dhd_info_t *dhd = dhdp->info;
+ dhd_if_t *ifp;
+
+ ASSERT(idx < DHD_MAX_IFS);
+
+ ifp = dhd->iflist[idx];
+
+ ifp->ap_isolate = val;
+
+ return 0;
+}
+
+#ifdef DHD_WMF
+/* Returns interface specific WMF configuration */
+dhd_wmf_t* dhd_wmf_conf(dhd_pub_t *dhdp, uint32 idx)
+{
+ dhd_info_t *dhd = dhdp->info;
+ dhd_if_t *ifp;
+
+ ASSERT(idx < DHD_MAX_IFS);
+
+ ifp = dhd->iflist[idx];
+ return &ifp->wmf;
+}
+#endif /* DHD_WMF */
+
+
+#ifdef DHD_UNICAST_DHCP
+static int
+dhd_get_pkt_ether_type(dhd_pub_t *pub, void *pktbuf,
+ uint8 **data_ptr, int *len_ptr, uint16 *et_ptr, bool *snap_ptr)
+{
+ uint8 *frame = PKTDATA(pub->osh, pktbuf);
+ int length = PKTLEN(pub->osh, pktbuf);
+ uint8 *pt; /* Pointer to type field */
+ uint16 ethertype;
+ bool snap = FALSE;
+ /* Process Ethernet II or SNAP-encapsulated 802.3 frames */
+ if (length < ETHER_HDR_LEN) {
+ DHD_ERROR(("dhd: %s: short eth frame (%d)\n",
+ __FUNCTION__, length));
+ return BCME_ERROR;
+ } else if (ntoh16_ua(frame + ETHER_TYPE_OFFSET) >= ETHER_TYPE_MIN) {
+ /* Frame is Ethernet II */
+ pt = frame + ETHER_TYPE_OFFSET;
+ } else if (length >= ETHER_HDR_LEN + SNAP_HDR_LEN + ETHER_TYPE_LEN &&
+ !bcmp(llc_snap_hdr, frame + ETHER_HDR_LEN, SNAP_HDR_LEN)) {
+ pt = frame + ETHER_HDR_LEN + SNAP_HDR_LEN;
+ snap = TRUE;
+ } else {
+ DHD_INFO(("DHD: %s: non-SNAP 802.3 frame\n",
+ __FUNCTION__));
+ return BCME_ERROR;
+ }
+
+ ethertype = ntoh16_ua(pt);
+
+ /* Skip VLAN tag, if any */
+ if (ethertype == ETHER_TYPE_8021Q) {
+ pt += VLAN_TAG_LEN;
+
+ if ((pt + ETHER_TYPE_LEN) > (frame + length)) {
+ DHD_ERROR(("dhd: %s: short VLAN frame (%d)\n",
+ __FUNCTION__, length));
+ return BCME_ERROR;
+ }
+
+ ethertype = ntoh16_ua(pt);
+ }
+
+ *data_ptr = pt + ETHER_TYPE_LEN;
+ *len_ptr = length - (pt + ETHER_TYPE_LEN - frame);
+ *et_ptr = ethertype;
+ *snap_ptr = snap;
+ return BCME_OK;
+}
+
+static int
+dhd_get_pkt_ip_type(dhd_pub_t *pub, void *pktbuf,
+ uint8 **data_ptr, int *len_ptr, uint8 *prot_ptr)
+{
+ struct ipv4_hdr *iph; /* IP frame pointer */
+ int iplen; /* IP frame length */
+ uint16 ethertype, iphdrlen, ippktlen;
+ uint16 iph_frag;
+ uint8 prot;
+ bool snap;
+
+ if (dhd_get_pkt_ether_type(pub, pktbuf, (uint8 **)&iph,
+ &iplen, &ethertype, &snap) != 0)
+ return BCME_ERROR;
+
+ if (ethertype != ETHER_TYPE_IP) {
+ return BCME_ERROR;
+ }
+
+ /* We support IPv4 only */
+ if (iplen < IPV4_OPTIONS_OFFSET || (IP_VER(iph) != IP_VER_4)) {
+ return BCME_ERROR;
+ }
+
+ /* Header length sanity */
+ iphdrlen = IPV4_HLEN(iph);
+
+ /*
+ * Packet length sanity; sometimes we receive eth-frame size bigger
+ * than the IP content, which results in a bad tcp chksum
+ */
+ ippktlen = ntoh16(iph->tot_len);
+ if (ippktlen < iplen) {
+
+ DHD_INFO(("%s: extra frame length ignored\n",
+ __FUNCTION__));
+ iplen = ippktlen;
+ } else if (ippktlen > iplen) {
+ DHD_ERROR(("dhd: %s: truncated IP packet (%d)\n",
+ __FUNCTION__, ippktlen - iplen));
+ return BCME_ERROR;
+ }
+
+ if (iphdrlen < IPV4_OPTIONS_OFFSET || iphdrlen > iplen) {
+ DHD_ERROR(("DHD: %s: IP-header-len (%d) out of range (%d-%d)\n",
+ __FUNCTION__, iphdrlen, IPV4_OPTIONS_OFFSET, iplen));
+ return BCME_ERROR;
+ }
+
+ /*
+ * We don't handle fragmented IP packets. A first frag is indicated by the MF
+ * (more frag) bit and a subsequent frag is indicated by a non-zero frag offset.
+ */
+ iph_frag = ntoh16(iph->frag);
+
+ if ((iph_frag & IPV4_FRAG_MORE) || (iph_frag & IPV4_FRAG_OFFSET_MASK) != 0) {
+ DHD_INFO(("DHD:%s: IP fragment not handled\n",
+ __FUNCTION__));
+ return BCME_ERROR;
+ }
+
+ prot = IPV4_PROT(iph);
+
+ *data_ptr = (((uint8 *)iph) + iphdrlen);
+ *len_ptr = iplen - iphdrlen;
+ *prot_ptr = prot;
+ return BCME_OK;
+}
+
+/** check the packet type, if it is DHCP ACK/REPLY, convert into unicast packet */
+static
+int dhd_convert_dhcp_broadcast_ack_to_unicast(dhd_pub_t *pub, void *pktbuf, int ifidx)
+{
+ dhd_sta_t* stainfo;
+ uint8 *eh = PKTDATA(pub->osh, pktbuf);
+ uint8 *udph;
+ uint8 *dhcp;
+ uint8 *chaddr;
+ int udpl;
+ int dhcpl;
+ uint16 port;
+ uint8 prot;
+
+ if (!ETHER_ISMULTI(eh + ETHER_DEST_OFFSET))
+ return BCME_ERROR;
+ if (dhd_get_pkt_ip_type(pub, pktbuf, &udph, &udpl, &prot) != 0)
+ return BCME_ERROR;
+ if (prot != IP_PROT_UDP)
+ return BCME_ERROR;
+ /* check frame length, at least UDP_HDR_LEN */
+ if (udpl < UDP_HDR_LEN) {
+ DHD_ERROR(("DHD: %s: short UDP frame, ignored\n",
+ __FUNCTION__));
+ return BCME_ERROR;
+ }
+ port = ntoh16_ua(udph + UDP_DEST_PORT_OFFSET);
+ /* only process DHCP packets from server to client */
+ if (port != DHCP_PORT_CLIENT)
+ return BCME_ERROR;
+
+ dhcp = udph + UDP_HDR_LEN;
+ dhcpl = udpl - UDP_HDR_LEN;
+
+ if (dhcpl < DHCP_CHADDR_OFFSET + ETHER_ADDR_LEN) {
+ DHD_ERROR(("DHD: %s: short DHCP frame, ignored\n",
+ __FUNCTION__));
+ return BCME_ERROR;
+ }
+ /* only process DHCP reply(offer/ack) packets */
+ if (*(dhcp + DHCP_TYPE_OFFSET) != DHCP_TYPE_REPLY)
+ return BCME_ERROR;
+ chaddr = dhcp + DHCP_CHADDR_OFFSET;
+ stainfo = dhd_find_sta(pub, ifidx, chaddr);
+ if (stainfo) {
+ bcopy(chaddr, eh + ETHER_DEST_OFFSET, ETHER_ADDR_LEN);
+ return BCME_OK;
+ }
+ return BCME_ERROR;
+}
+#endif /* DHD_UNICAST_DHD */
+#ifdef DHD_L2_FILTER
+/* Check if packet type is ICMP ECHO */
+static
+int dhd_l2_filter_block_ping(dhd_pub_t *pub, void *pktbuf, int ifidx)
+{
+ struct bcmicmp_hdr *icmph;
+ int udpl;
+ uint8 prot;
+
+ if (dhd_get_pkt_ip_type(pub, pktbuf, (uint8 **)&icmph, &udpl, &prot) != 0)
+ return BCME_ERROR;
+ if (prot == IP_PROT_ICMP) {
+ if (icmph->type == ICMP_TYPE_ECHO_REQUEST)
+ return BCME_OK;
+ }
+ return BCME_ERROR;
+}
+#endif /* DHD_L2_FILTER */
+
+#ifdef SET_RPS_CPUS
+int custom_rps_map_set(struct netdev_rx_queue *queue, char *buf, size_t len)
+{
+ struct rps_map *old_map, *map;
+ cpumask_var_t mask;
+ int err, cpu, i;
+ static DEFINE_SPINLOCK(rps_map_lock);
+
+ DHD_INFO(("%s : Entered.\n", __FUNCTION__));
+
+ if (!alloc_cpumask_var(&mask, GFP_KERNEL)) {
+ DHD_ERROR(("%s : alloc_cpumask_var fail.\n", __FUNCTION__));
+ return -ENOMEM;
+ }
+
+ err = bitmap_parse(buf, len, cpumask_bits(mask), nr_cpumask_bits);
+ if (err) {
+ free_cpumask_var(mask);
+ DHD_ERROR(("%s : bitmap_parse fail.\n", __FUNCTION__));
+ return err;
+ }
+
+ map = kzalloc(max_t(unsigned int,
+ RPS_MAP_SIZE(cpumask_weight(mask)), L1_CACHE_BYTES),
+ GFP_KERNEL);
+ if (!map) {
+ free_cpumask_var(mask);
+ DHD_ERROR(("%s : map malloc fail.\n", __FUNCTION__));
+ return -ENOMEM;
+ }
+
+ i = 0;
+ for_each_cpu(cpu, mask)
+ map->cpus[i++] = cpu;
+
+ if (i)
+ map->len = i;
+ else {
+ kfree(map);
+ DHD_ERROR(("%s : mapping cpu fail.\n", __FUNCTION__));
+ map = NULL;
+ }
+
+ spin_lock(&rps_map_lock);
+ old_map = rcu_dereference_protected(queue->rps_map,
+ lockdep_is_held(&rps_map_lock));
+ rcu_assign_pointer(queue->rps_map, map);
+ spin_unlock(&rps_map_lock);
+
+ if (map)
+ static_key_slow_inc(&rps_needed);
+ if (old_map) {
+ kfree_rcu(old_map, rcu);
+ static_key_slow_dec(&rps_needed);
+ }
+ free_cpumask_var(mask);
+
+ DHD_INFO(("%s : Done. mapping cpu nummber : %d\n", __FUNCTION__, map->len));
+ return map->len;
+}
+
+void custom_rps_map_clear(struct netdev_rx_queue *queue)
+{
+ struct rps_map *map;
+
+ DHD_INFO(("%s : Entered.\n", __FUNCTION__));
+
+ map = rcu_dereference_protected(queue->rps_map, 1);
+ if (map) {
+ RCU_INIT_POINTER(queue->rps_map, NULL);
+ kfree_rcu(map, rcu);
+ DHD_INFO(("%s : rps_cpus map clear.\n", __FUNCTION__));
+ }
+}
+#endif /* SET_RPS_CPUS */
+
+#if defined(CUSTOMER_HW20) && defined(WLANAUDIO)
+void
+SDA_setSharedMemory4Send(unsigned int buffer_id,
+ unsigned char *buffer, unsigned int buffer_size,
+ unsigned int packet_size, unsigned int headroom_size)
+{
+ dhd_info_t *dhd = dhd_global;
+
+ sda_packet_length = packet_size;
+
+ ASSERT(dhd);
+ if (dhd == NULL)
+ return;
+}
+
+void
+SDA_registerCallback4SendDone(SDA_SendDoneCallBack packet_cb)
+{
+ dhd_info_t *dhd = dhd_global;
+
+ ASSERT(dhd);
+ if (dhd == NULL)
+ return;
+}
+
+
+unsigned long long
+SDA_getTsf(unsigned char vif_id)
+{
+ dhd_info_t *dhd = dhd_global;
+ uint64 tsf_val;
+ char buf[WLC_IOCTL_SMLEN];
+ int ifidx = 0;
+
+ struct tsf {
+ uint32 low;
+ uint32 high;
+ } tsf_buf;
+
+ memset(buf, 0, sizeof(buf));
+
+ if (vif_id == 0) /* wlan0 tsf */
+ ifidx = dhd_ifname2idx(dhd, "wlan0");
+ else if (vif_id == 1) /* p2p0 tsf */
+ ifidx = dhd_ifname2idx(dhd, "p2p0");
+
+ bcm_mkiovar("tsf_bss", 0, 0, buf, sizeof(buf));
+
+ if (dhd_wl_ioctl_cmd(&dhd->pub, WLC_GET_VAR, buf, sizeof(buf), FALSE, ifidx) < 0) {
+ DHD_ERROR(("%s wl ioctl error\n", __FUNCTION__));
+ return 0;
+ }
+
+ memcpy(&tsf_buf, buf, sizeof(tsf_buf));
+ tsf_val = (uint64)tsf_buf.high;
+ DHD_TRACE(("%s tsf high 0x%08x, low 0x%08x\n",
+ __FUNCTION__, tsf_buf.high, tsf_buf.low));
+
+ return ((tsf_val << 32) | tsf_buf.low);
+}
+EXPORT_SYMBOL(SDA_getTsf);
+
+unsigned int
+SDA_syncTsf(void)
+{
+ dhd_info_t *dhd = dhd_global;
+ int tsf_sync = 1;
+ char iovbuf[WLC_IOCTL_SMLEN];
+
+ bcm_mkiovar("wa_tsf_sync", (char *)&tsf_sync, 4, iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(&dhd->pub, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+
+ DHD_TRACE(("%s\n", __FUNCTION__));
+ return 0;
+}
+
+extern struct net_device *wl0dot1_dev;
+
+void
+BCMFASTPATH SDA_function4Send(uint buffer_id, void *packet, uint packet_size)
+{
+ struct sk_buff *skb;
+ sda_packet_t *shm_packet = packet;
+ dhd_info_t *dhd = dhd_global;
+ int cnt;
+
+ static unsigned int cnt_t = 1;
+
+ ASSERT(dhd);
+ if (dhd == NULL)
+ return;
+
+ if (dhd->is_wlanaudio_blist) {
+ for (cnt = 0; cnt < MAX_WLANAUDIO_BLACKLIST; cnt++) {
+ if (dhd->wlanaudio_blist[cnt].is_blacklist == true) {
+ if (!bcmp(dhd->wlanaudio_blist[cnt].blacklist_addr.octet,
+ shm_packet->headroom.ether_dhost, ETHER_ADDR_LEN))
+ return;
+ }
+ }
+ }
+
+ if ((cnt_t % 10000) == 0)
+ cnt_t = 0;
+
+ cnt_t++;
+
+ /* packet_size may be smaller than SDA_SHM_PKT_SIZE, remaining will be garbage */
+#define TXOFF 26
+ skb = __dev_alloc_skb(TXOFF + sda_packet_length - SDA_PKT_HEADER_SIZE, GFP_ATOMIC);
+
+ skb_reserve(skb, TXOFF - SDA_HEADROOM_SIZE);
+ skb_put(skb, sda_packet_length - SDA_PKT_HEADER_SIZE + SDA_HEADROOM_SIZE);
+ skb->priority = PRIO_8021D_VO; /* PRIO_8021D_VO or PRIO_8021D_VI */
+
+ /* p2p_net */
+ skb->dev = wl0dot1_dev;
+ shm_packet->txTsf = 0x0;
+ shm_packet->rxTsf = 0x0;
+ memcpy(skb->data, &shm_packet->headroom,
+ sda_packet_length - OFFSETOF(sda_packet_t, headroom));
+ shm_packet->desc.ready_to_copy = 0;
+
+ dhd_start_xmit(skb, skb->dev);
+}
+
+void
+SDA_registerCallback4Recv(unsigned char *pBufferTotal,
+ unsigned int BufferTotalSize)
+{
+ dhd_info_t *dhd = dhd_global;
+
+ ASSERT(dhd);
+ if (dhd == NULL)
+ return;
+}
+
+
+void
+SDA_setSharedMemory4Recv(unsigned char *pBufferTotal,
+ unsigned int BufferTotalSize,
+ unsigned int BufferUnitSize,
+ unsigned int Headroomsize)
+{
+ dhd_info_t *dhd = dhd_global;
+
+ ASSERT(dhd);
+ if (dhd == NULL)
+ return;
+}
+
+
+void
+SDA_function4RecvDone(unsigned char * pBuffer, unsigned int BufferSize)
+{
+ dhd_info_t *dhd = dhd_global;
+
+ ASSERT(dhd);
+ if (dhd == NULL)
+ return;
+}
+
+EXPORT_SYMBOL(SDA_setSharedMemory4Send);
+EXPORT_SYMBOL(SDA_registerCallback4SendDone);
+EXPORT_SYMBOL(SDA_syncTsf);
+EXPORT_SYMBOL(SDA_function4Send);
+EXPORT_SYMBOL(SDA_registerCallback4Recv);
+EXPORT_SYMBOL(SDA_setSharedMemory4Recv);
+EXPORT_SYMBOL(SDA_function4RecvDone);
+
+#endif /* CUSTOMER_HW20 && WLANAUDIO */
+
+void *dhd_get_pub(struct net_device *dev)
+{
+ dhd_info_t *dhdinfo = *(dhd_info_t **)netdev_priv(dev);
+ if (dhdinfo)
+ return (void *)&dhdinfo->pub;
+ else
+ return NULL;
+}
+
+bool dhd_os_wd_timer_enabled(void *bus)
+{
+ dhd_pub_t *pub = bus;
+ dhd_info_t *dhd = (dhd_info_t *)pub->info;
+
+ DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+ if (!dhd) {
+ DHD_ERROR(("%s: dhd NULL\n", __FUNCTION__));
+ return FALSE;
+ }
+ return dhd->wd_timer_valid;
+}
diff -Nur a/drivers/net/wireless/bcmdhd/dhd_linux.h c/drivers/net/wireless/bcmdhd/dhd_linux.h
--- a/drivers/net/wireless/bcmdhd/dhd_linux.h 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/dhd_linux.h 2016-05-13 09:48:20.000000000 +0200
@@ -32,6 +32,16 @@
#define DHD_REGISTRATION_TIMEOUT 12000 /* msec : allowed time to finished dhd registration */
+#if defined(CUSTOMER_HW)
+struct wifi_platform_data {
+ int (*set_power)(bool val);
+ int (*set_carddetect)(bool val);
+ void *(*mem_prealloc)(int section, unsigned long size);
+ int (*get_mac_addr)(unsigned char *buf);
+ void *(*get_country_code)(char *ccode);
+};
+#endif
+
typedef struct wifi_adapter_info {
const char *name;
uint irq_num;
diff -Nur a/drivers/net/wireless/bcmdhd/dhd_linux_platdev.c c/drivers/net/wireless/bcmdhd/dhd_linux_platdev.c
--- a/drivers/net/wireless/bcmdhd/dhd_linux_platdev.c 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/dhd_linux_platdev.c 2016-09-30 00:19:04.817804108 +0200
@@ -26,7 +26,7 @@
#include<linux/of_gpio.h>
#endif /* CONFIG_DTS */
-#ifdef CUSTOMER_HW
+#if defined(CUSTOMER_HW)
#if defined(CUSTOMER_OOB)
extern uint bcm_wlan_get_oob_irq(void);
extern uint bcm_wlan_get_oob_irq_flags(void);
@@ -34,14 +34,6 @@
extern int bcm_wlan_set_plat_data(void);
#endif /* CUSTOMER_HW */
-struct wifi_platform_data {
- int (*set_power)(bool val);
- int (*set_carddetect)(bool val);
- void *(*mem_prealloc)(int section, unsigned long size);
- int (*get_mac_addr)(unsigned char *buf);
- void *(*get_country_code)(char *ccode);
-};
-
#define WIFI_PLAT_NAME "bcmdhd_wlan"
#define WIFI_PLAT_NAME2 "bcm4329_wlan"
#define WIFI_PLAT_EXT "bcmdhd_wifi_platform"
@@ -57,13 +49,14 @@
#if !defined(CONFIG_DTS)
#if defined(DHD_OF_SUPPORT)
static bool dts_enabled = TRUE;
-extern struct resource dhd_wlan_resources;
extern struct wifi_platform_data dhd_wlan_control;
#else
static bool dts_enabled = FALSE;
struct resource dhd_wlan_resources = {0};
+#ifdef CUSTOMER_HW
struct wifi_platform_data dhd_wlan_control = {0};
-#endif /* CONFIG_OF && !defined(CONFIG_ARCH_MSM) */
+#endif
+#endif /* !defind(DHD_OF_SUPPORT) */
#endif /* !defind(CONFIG_DTS) */
static int dhd_wifi_platform_load(void);
@@ -239,6 +232,7 @@
return NULL;
}
+#ifndef CUSTOMER_HW
static int wifi_plat_dev_drv_probe(struct platform_device *pdev)
{
struct resource *resource;
@@ -346,6 +340,7 @@
{},
};
#endif /* CONFIG_DTS */
+
static struct platform_driver wifi_platform_dev_driver = {
.probe = wifi_plat_dev_drv_probe,
.remove = wifi_plat_dev_drv_remove,
@@ -381,17 +376,20 @@
return FALSE;
}
+#endif
static int wifi_ctrlfunc_register_drv(void)
{
- int err = 0;
- struct device *dev1, *dev2;
wifi_adapter_info_t *adapter;
+#ifndef CUSTOMER_HW
+ int err = 0;
+ struct device *dev1, *dev2;
dev1 = bus_find_device(&platform_bus_type, NULL, WIFI_PLAT_NAME, wifi_platdev_match);
dev2 = bus_find_device(&platform_bus_type, NULL, WIFI_PLAT_NAME2, wifi_platdev_match);
+#endif
-#if !defined(CONFIG_DTS)
+#if !defined(CONFIG_DTS) && !defined(CUSTOMER_HW)
if (!dts_enabled) {
if (dev1 == NULL && dev2 == NULL) {
DHD_ERROR(("no wifi platform data, skip\n"));
@@ -415,6 +413,7 @@
dhd_wifi_platdata->num_adapters = 1;
dhd_wifi_platdata->adapters = adapter;
+#ifndef CUSTOMER_HW
if (dev1) {
err = platform_driver_register(&wifi_platform_dev_driver);
if (err) {
@@ -431,11 +430,12 @@
return err;
}
}
+#endif
#if !defined(CONFIG_DTS)
if (dts_enabled) {
- adapter->wifi_plat_data = (void *)&dhd_wlan_control;
#ifdef CUSTOMER_HW
+ adapter->wifi_plat_data = (void *)&dhd_wlan_control;
bcm_wlan_set_plat_data();
#ifdef CUSTOMER_OOB
adapter->irq_num = bcm_wlan_get_oob_irq();
@@ -452,7 +452,7 @@
#endif /* !defined(CONFIG_DTS) */
-#ifdef CONFIG_DTS
+#if defined(CONFIG_DTS) && !defined(CUSTOMER_HW)
wifi_plat_dev_probe_ret = platform_driver_register(&wifi_platform_dev_driver);
#endif /* CONFIG_DTS */
@@ -462,23 +462,26 @@
void wifi_ctrlfunc_unregister_drv(void)
{
- struct device *dev1, *dev2;
-#ifdef CONFIG_DTS
+#if defined(CONFIG_DTS) && !defined(CUSTOMER_HW)
DHD_ERROR(("unregister wifi platform drivers\n"));
platform_driver_unregister(&wifi_platform_dev_driver);
#else
+#ifndef CUSTOMER_HW
+ struct device *dev1, *dev2;
dev1 = bus_find_device(&platform_bus_type, NULL, WIFI_PLAT_NAME, wifi_platdev_match);
dev2 = bus_find_device(&platform_bus_type, NULL, WIFI_PLAT_NAME2, wifi_platdev_match);
if (!dts_enabled)
if (dev1 == NULL && dev2 == NULL)
return;
-
+#endif
DHD_ERROR(("unregister wifi platform drivers\n"));
+#ifndef CUSTOMER_HW
if (dev1)
platform_driver_unregister(&wifi_platform_dev_driver);
if (dev2)
platform_driver_unregister(&wifi_platform_dev_driver_legacy);
+#endif
if (dts_enabled) {
wifi_adapter_info_t *adapter;
adapter = &dhd_wifi_platdata->adapters[0];
@@ -496,6 +499,7 @@
dhd_wifi_platdata = NULL;
}
+#ifndef CUSTOMER_HW
static int bcmdhd_wifi_plat_dev_drv_probe(struct platform_device *pdev)
{
dhd_wifi_platdata = (bcmdhd_wifi_platdata_t *)(pdev->dev.platform_data);
@@ -525,10 +529,12 @@
.name = WIFI_PLAT_EXT,
}
};
+#endif
int dhd_wifi_platform_register_drv(void)
{
int err = 0;
+#ifndef CUSTOMER_HW
struct device *dev;
/* register Broadcom wifi platform data driver if multi-chip is enabled,
@@ -545,7 +551,9 @@
return -ENXIO;
}
err = platform_driver_register(&dhd_wifi_platform_dev_driver);
- } else {
+ } else
+#endif
+ {
err = wifi_ctrlfunc_register_drv();
/* no wifi ctrl func either, load bus directly and ignore this error */
@@ -650,9 +658,11 @@
void dhd_wifi_platform_unregister_drv(void)
{
+#ifndef CUSTOMER_HW
if (cfg_multichip)
platform_driver_unregister(&dhd_wifi_platform_dev_driver);
else
+#endif
wifi_ctrlfunc_unregister_drv();
}
@@ -661,7 +671,7 @@
extern uint dhd_deferred_tx;
#if defined(BCMLXSDMMC)
extern struct semaphore dhd_registration_sem;
-#endif
+#endif
#ifdef BCMSDIO
static int dhd_wifi_platform_load_sdio(void)
@@ -702,6 +712,7 @@
adapter->bus_type, adapter->bus_num, adapter->slot_num));
do {
+#ifndef CONFIG_ARCH_SUNXI
sema_init(&dhd_chipup_sem, 0);
err = dhd_bus_reg_sdio_notify(&dhd_chipup_sem);
if (err) {
@@ -709,6 +720,7 @@
__FUNCTION__, err));
return err;
}
+#endif
err = wifi_platform_set_power(adapter, TRUE, WIFI_TURNON_DELAY);
if (err) {
/* WL_REG_ON state unknown, Power off forcely */
@@ -718,6 +730,15 @@
wifi_platform_bus_enumerate(adapter, TRUE);
err = 0;
}
+#ifdef CONFIG_ARCH_SUNXI
+ sema_init(&dhd_chipup_sem, 0);
+ err = dhd_bus_reg_sdio_notify(&dhd_chipup_sem);
+ if (err) {
+ DHD_ERROR(("%s dhd_bus_reg_sdio_notify fail(%d)\n\n",
+ __FUNCTION__, err));
+ return err;
+ }
+#endif
if (down_timeout(&dhd_chipup_sem, msecs_to_jiffies(POWERUP_WAIT_MS)) == 0) {
dhd_bus_unreg_sdio_notify();
@@ -772,7 +793,7 @@
/* x86 bring-up PC needs no power-up operations */
err = dhd_bus_register();
-#endif
+#endif
return err;
}
@@ -805,8 +826,10 @@
end:
if (err)
wl_android_exit();
+#if !defined(MULTIPLE_SUPPLICANT)
else
wl_android_post_init();
+#endif
return err;
}
diff -Nur a/drivers/net/wireless/bcmdhd/dhd_msgbuf.c c/drivers/net/wireless/bcmdhd/dhd_msgbuf.c
--- a/drivers/net/wireless/bcmdhd/dhd_msgbuf.c 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/dhd_msgbuf.c 2016-05-13 09:48:20.000000000 +0200
@@ -6,7 +6,7 @@
*
* $Copyright Open Broadcom Corporation$
*
- * $Id: dhd_msgbuf.c 490973 2014-07-14 12:32:56Z $
+ * $Id: dhd_msgbuf.c 504484 2014-09-24 10:11:20Z $
*/
#include <typedefs.h>
#include <osl.h>
@@ -33,6 +33,26 @@
#include <pcie_core.h>
#include <bcmpcie.h>
+#include <dhd_pcie.h>
+#include <dhd_ip.h>
+
+/*
+ * PCIE D2H DMA Complete Sync Modes
+ *
+ * Firmware may interrupt the host, prior to the D2H Mem2Mem DMA completes into
+ * Host system memory. A WAR using one of 3 approaches is needed:
+ * 1. Dongle places ia modulo-253 seqnum in last word of each D2H message
+ * 2. XOR Checksum, with epoch# in each work item. Dongle builds an XOR checksum
+ * writes in the last word of each work item. Each work item has a seqnum
+ * number = sequence num % 253.
+ * 3. Read Barrier: Dongle does a host memory read access prior to posting an
+ * interrupt.
+ * Host does not participate with option #3, other than reserving a host system
+ * memory location for the dongle to read.
+ */
+#define PCIE_D2H_SYNC
+#define PCIE_D2H_SYNC_WAIT_TRIES 1024
+#define PCIE_D2H_SYNC_BZERO /* bzero a message before updating the RD offset */
#define RETRIES 2 /* # of retries to retrieve matching ioctl response */
#define IOCTL_HDR_LEN 12
@@ -89,8 +109,17 @@
#endif /* TXP_FLUSH_NITEMS */
ring_mem_t *ringmem;
ring_state_t *ringstate;
+#if defined(PCIE_D2H_SYNC)
+ uint32 seqnum;
+#endif /* PCIE_D2H_SYNC */
+ void *secdma;
} msgbuf_ring_t;
+#if defined(PCIE_D2H_SYNC)
+/* Custom callback attached based upon D2H DMA Sync mode used in dongle. */
+typedef uint8 (* d2h_sync_cb_t)(dhd_pub_t *dhd, msgbuf_ring_t *ring,
+ volatile cmn_msg_hdr_t *msg, int msglen);
+#endif /* PCIE_D2H_SYNC */
typedef struct dhd_prot {
osl_t *osh; /* OSL handle */
@@ -133,6 +162,11 @@
uint32 d2h_dma_readindx_buf_len; /* For holding dma ringupd buf - completion read */
dhd_mem_map_t d2h_dma_readindx_buf; /* For holding dma ringupd buf - completion read */
+#if defined(PCIE_D2H_SYNC)
+ d2h_sync_cb_t d2h_sync_cb; /* Sync on D2H DMA done: SEQNUM or XORCSUM */
+ ulong d2h_sync_wait_max; /* max number of wait loops to receive one msg */
+ ulong d2h_sync_wait_tot; /* total wait loops */
+#endif /* PCIE_D2H_SYNC */
dhd_dmaxfer_t dmaxfer;
bool dmaxfer_in_progress;
@@ -159,6 +193,7 @@
static int dhd_prot_process_msgtype(dhd_pub_t *dhd, msgbuf_ring_t *ring, uint8* buf, uint16 len);
static int dhd_process_msgtype(dhd_pub_t *dhd, msgbuf_ring_t *ring, uint8* buf, uint16 len);
+static void dhd_prot_noop(dhd_pub_t *dhd, void * buf, uint16 msglen);
static void dhd_prot_txstatus_process(dhd_pub_t *dhd, void * buf, uint16 msglen);
static void dhd_prot_ioctcmplt_process(dhd_pub_t *dhd, void * buf, uint16 msglen);
static void dhd_prot_ioctack_process(dhd_pub_t *dhd, void * buf, uint16 msglen);
@@ -217,7 +252,7 @@
typedef void (*dhd_msgbuf_func_t)(dhd_pub_t *dhd, void * buf, uint16 msglen);
static dhd_msgbuf_func_t table_lookup[DHD_PROT_FUNCS] = {
- NULL,
+ dhd_prot_noop, /* 0 is invalid message type */
dhd_prot_genstatus_process, /* MSG_TYPE_GEN_STATUS */
dhd_prot_ringstatus_process, /* MSG_TYPE_RING_STATUS */
NULL,
@@ -241,6 +276,145 @@
NULL,
};
+
+#if defined(PCIE_D2H_SYNC)
+
+/*
+ * D2H DMA to completion callback handlers. Based on the mode advertised by the
+ * dongle through the PCIE shared region, the appropriate callback will be
+ * registered in the proto layer to be invoked prior to precessing any message
+ * from a D2H DMA ring. If the dongle uses a read barrier or another mode that
+ * does not require host participation, then a noop callback handler will be
+ * bound that simply returns the msgtype.
+ */
+static void dhd_prot_d2h_sync_livelock(dhd_pub_t *dhd, uint32 seqnum,
+ uint32 tries, uchar *msg, int msglen);
+static uint8 dhd_prot_d2h_sync_seqnum(dhd_pub_t *dhd, msgbuf_ring_t *ring,
+ volatile cmn_msg_hdr_t *msg, int msglen);
+static uint8 dhd_prot_d2h_sync_xorcsum(dhd_pub_t *dhd, msgbuf_ring_t *ring,
+ volatile cmn_msg_hdr_t *msg, int msglen);
+static uint8 dhd_prot_d2h_sync_none(dhd_pub_t *dhd, msgbuf_ring_t *ring,
+ volatile cmn_msg_hdr_t *msg, int msglen);
+static void dhd_prot_d2h_sync_init(dhd_pub_t *dhd, dhd_prot_t * prot);
+
+/* Debug print a livelock avert by dropping a D2H message */
+static void
+dhd_prot_d2h_sync_livelock(dhd_pub_t *dhd, uint32 seqnum, uint32 tries,
+ uchar *msg, int msglen)
+{
+ DHD_ERROR(("LIVELOCK DHD<%p> seqnum<%u:%u> tries<%u> max<%lu> tot<%lu>\n",
+ dhd, seqnum, seqnum% D2H_EPOCH_MODULO, tries,
+ dhd->prot->d2h_sync_wait_max, dhd->prot->d2h_sync_wait_tot));
+ prhex("D2H MsgBuf Failure", (uchar *)msg, msglen);
+}
+
+/* Sync on a D2H DMA to complete using SEQNUM mode */
+static uint8 BCMFASTPATH
+dhd_prot_d2h_sync_seqnum(dhd_pub_t *dhd, msgbuf_ring_t *ring,
+ volatile cmn_msg_hdr_t *msg, int msglen)
+{
+ uint32 tries;
+ uint32 ring_seqnum = ring->seqnum % D2H_EPOCH_MODULO;
+ int num_words = msglen / sizeof(uint32); /* num of 32bit words */
+ volatile uint32 *marker = (uint32 *)msg + (num_words - 1); /* last word */
+ dhd_prot_t *prot = dhd->prot;
+
+ ASSERT(msglen == RING_LEN_ITEMS(ring));
+
+ for (tries = 0; tries < PCIE_D2H_SYNC_WAIT_TRIES; tries++) {
+ uint32 msg_seqnum = *marker;
+ if (ltoh32(msg_seqnum) == ring_seqnum) { /* dma upto last word done */
+ ring->seqnum++; /* next expected sequence number */
+ goto dma_completed;
+ }
+
+ if (tries > prot->d2h_sync_wait_max)
+ prot->d2h_sync_wait_max = tries;
+
+ OSL_CACHE_INV(msg, msglen); /* invalidate and try again */
+
+ } /* for PCIE_D2H_SYNC_WAIT_TRIES */
+
+ dhd_prot_d2h_sync_livelock(dhd, ring->seqnum, tries, (uchar *)msg, msglen);
+
+ ring->seqnum++; /* skip this message ... leak of a pktid */
+ return 0; /* invalid msgtype 0 -> noop callback */
+
+dma_completed:
+
+ prot->d2h_sync_wait_tot += tries;
+ return msg->msg_type;
+}
+
+/* Sync on a D2H DMA to complete using XORCSUM mode */
+static uint8 BCMFASTPATH
+dhd_prot_d2h_sync_xorcsum(dhd_pub_t *dhd, msgbuf_ring_t *ring,
+ volatile cmn_msg_hdr_t *msg, int msglen)
+{
+ uint32 tries;
+ uint32 prot_checksum = 0; /* computed checksum */
+ int num_words = msglen / sizeof(uint32); /* num of 32bit words */
+ uint8 ring_seqnum = ring->seqnum % D2H_EPOCH_MODULO;
+ dhd_prot_t *prot = dhd->prot;
+
+ ASSERT(msglen == RING_LEN_ITEMS(ring));
+
+ for (tries = 0; tries < PCIE_D2H_SYNC_WAIT_TRIES; tries++) {
+ prot_checksum = bcm_compute_xor32((volatile uint32 *)msg, num_words);
+ if (prot_checksum == 0U) { /* checksum is OK */
+ if (msg->epoch == ring_seqnum) {
+ ring->seqnum++; /* next expected sequence number */
+ goto dma_completed;
+ }
+ }
+
+ if (tries > prot->d2h_sync_wait_max)
+ prot->d2h_sync_wait_max = tries;
+
+ OSL_CACHE_INV(msg, msglen); /* invalidate and try again */
+
+ } /* for PCIE_D2H_SYNC_WAIT_TRIES */
+
+ dhd_prot_d2h_sync_livelock(dhd, ring->seqnum, tries, (uchar *)msg, msglen);
+
+ ring->seqnum++; /* skip this message ... leak of a pktid */
+ return 0; /* invalid msgtype 0 -> noop callback */
+
+dma_completed:
+
+ prot->d2h_sync_wait_tot += tries;
+ return msg->msg_type;
+}
+
+/* Do not sync on a D2H DMA */
+static uint8 BCMFASTPATH
+dhd_prot_d2h_sync_none(dhd_pub_t *dhd, msgbuf_ring_t *ring,
+ volatile cmn_msg_hdr_t *msg, int msglen)
+{
+ return msg->msg_type;
+}
+
+/* Initialize the D2H DMA Sync mode, per D2H ring seqnum and dhd stats */
+static void
+dhd_prot_d2h_sync_init(dhd_pub_t *dhd, dhd_prot_t * prot)
+{
+ prot->d2h_sync_wait_max = 0UL;
+ prot->d2h_sync_wait_tot = 0UL;
+
+ prot->d2hring_tx_cpln->seqnum = D2H_EPOCH_INIT_VAL;
+ prot->d2hring_rx_cpln->seqnum = D2H_EPOCH_INIT_VAL;
+ prot->d2hring_ctrl_cpln->seqnum = D2H_EPOCH_INIT_VAL;
+
+ if (dhd->d2h_sync_mode & PCIE_SHARED_D2H_SYNC_SEQNUM)
+ prot->d2h_sync_cb = dhd_prot_d2h_sync_seqnum;
+ else if (dhd->d2h_sync_mode & PCIE_SHARED_D2H_SYNC_XORCSUM)
+ prot->d2h_sync_cb = dhd_prot_d2h_sync_xorcsum;
+ else
+ prot->d2h_sync_cb = dhd_prot_d2h_sync_none;
+}
+
+#endif /* PCIE_D2H_SYNC */
+
/*
* +---------------------------------------------------------------------------+
* PktId Map: Provides a native packet pointer to unique 32bit PktId mapping.
@@ -250,7 +424,7 @@
* and the metadata may be retrieved using the previously allocated packet id.
* +---------------------------------------------------------------------------+
*/
-#define MAX_PKTID_ITEMS (3072) /* Maximum number of pktids supported */
+#define MAX_PKTID_ITEMS (8192) /* Maximum number of pktids supported */
typedef void * dhd_pktid_map_handle_t; /* opaque handle to a pktid map */
@@ -267,13 +441,13 @@
static INLINE uint32 dhd_pktid_map_reserve(dhd_pktid_map_handle_t *handle,
void *pkt);
static INLINE void dhd_pktid_map_save(dhd_pktid_map_handle_t *handle, void *pkt,
- uint32 nkey, dmaaddr_t physaddr, uint32 len, uint8 dma);
+ uint32 nkey, dmaaddr_t physaddr, uint32 len, uint8 dma, void *secdma);
static uint32 dhd_pktid_map_alloc(dhd_pktid_map_handle_t *map, void *pkt,
- dmaaddr_t physaddr, uint32 len, uint8 dma);
+ dmaaddr_t physaddr, uint32 len, uint8 dma, void *secdma);
/* Return an allocated pktid, retrieving previously saved pkt and metadata */
static void *dhd_pktid_map_free(dhd_pktid_map_handle_t *map, uint32 id,
- dmaaddr_t *physaddr, uint32 *len);
+ dmaaddr_t *physaddr, uint32 *len, void **secdma);
/* Packet metadata saved in packet id mapper */
typedef struct dhd_pktid_item {
@@ -282,6 +456,7 @@
uint16 len; /* length of mapped packet's buffer */
void *pkt; /* opaque native pointer to a packet */
dmaaddr_t physaddr; /* physical address of mapped packet's buffer */
+ void *secdma;
} dhd_pktid_item_t;
typedef struct dhd_pktid_map {
@@ -312,17 +487,24 @@
#define NATIVE_TO_PKTID_CLEAR(map) dhd_pktid_map_clear(map)
#define NATIVE_TO_PKTID_RSV(map, pkt) dhd_pktid_map_reserve((map), (pkt))
-#define NATIVE_TO_PKTID_SAVE(map, pkt, nkey, pa, len, dma) \
- dhd_pktid_map_save((map), (void *)(pkt), (nkey), (pa), (uint32)(len), (uint8)dma)
-#define NATIVE_TO_PKTID(map, pkt, pa, len, dma) \
- dhd_pktid_map_alloc((map), (void *)(pkt), (pa), (uint32)(len), (uint8)dma)
+#define NATIVE_TO_PKTID_SAVE(map, pkt, nkey, pa, len, dma, secdma) \
+ dhd_pktid_map_save((map), (void *)(pkt), (nkey), (pa), (uint32)(len), (uint8)dma, \
+ (void *)(secdma))
+#define NATIVE_TO_PKTID(map, pkt, pa, len, dma, secdma) \
+ dhd_pktid_map_alloc((map), (void *)(pkt), (pa), (uint32)(len), (uint8)dma, (void *)(secdma))
-#define PKTID_TO_NATIVE(map, pktid, pa, len) \
+#define PKTID_TO_NATIVE(map, pktid, pa, len, secdma) \
dhd_pktid_map_free((map), (uint32)(pktid), \
- (dmaaddr_t *)&(pa), (uint32 *)&(len))
+ (dmaaddr_t *)&(pa), (uint32 *)&(len), (void **) &secdma)
#define PKTID_AVAIL(map) dhd_pktid_map_avail_cnt(map)
+#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_FLOWRING)
+#define FLOWRING_NAME "h2dflr"
+#define RING_IS_FLOWRING(ring) \
+ ((strncmp(ring->name, FLOWRING_NAME, sizeof(FLOWRING_NAME))) == (0))
+#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_FLOWRING */
+
/*
* +---------------------------------------------------------------------------+
* Packet to Packet Id mapper using a <numbered_key, locker> paradigm.
@@ -495,7 +677,7 @@
static INLINE void
dhd_pktid_map_save(dhd_pktid_map_handle_t *handle, void *pkt, uint32 nkey,
- dmaaddr_t physaddr, uint32 len, uint8 dma)
+ dmaaddr_t physaddr, uint32 len, uint8 dma, void *secdma)
{
dhd_pktid_map_t *map;
dhd_pktid_item_t *locker;
@@ -511,15 +693,16 @@
locker->dma = dma; /* store contents in locker */
locker->physaddr = physaddr;
locker->len = (uint16)len; /* 16bit len */
+ locker->secdma = secdma;
}
static uint32 BCMFASTPATH
dhd_pktid_map_alloc(dhd_pktid_map_handle_t *handle, void *pkt,
- dmaaddr_t physaddr, uint32 len, uint8 dma)
+ dmaaddr_t physaddr, uint32 len, uint8 dma, void *secdma)
{
uint32 nkey = dhd_pktid_map_reserve(handle, pkt);
if (nkey != DHD_PKTID_INVALID) {
- dhd_pktid_map_save(handle, pkt, nkey, physaddr, len, dma);
+ dhd_pktid_map_save(handle, pkt, nkey, physaddr, len, dma, secdma);
}
return nkey;
}
@@ -532,7 +715,7 @@
*/
static void * BCMFASTPATH
dhd_pktid_map_free(dhd_pktid_map_handle_t *handle, uint32 nkey,
- dmaaddr_t *physaddr, uint32 *len)
+ dmaaddr_t *physaddr, uint32 *len, void **secdma)
{
dhd_pktid_map_t *map;
dhd_pktid_item_t *locker;
@@ -557,6 +740,7 @@
*physaddr = locker->physaddr; /* return contents of locker */
*len = (uint32)locker->len;
+ *secdma = locker->secdma;
return locker->pkt;
}
@@ -687,6 +871,10 @@
return BCME_NOMEM;
}
+#if defined(PCIE_D2H_SYNC)
+ dhd_prot_d2h_sync_init(dhd, prot);
+#endif /* PCIE_D2H_SYNC */
+
prot->dmaxfer.srcmem.va = NULL;
prot->dmaxfer.destmem.va = NULL;
prot->dmaxfer_in_progress = FALSE;
@@ -718,7 +906,7 @@
uint32 dma_block_size = 4 * length;
if (prot == NULL) {
- DHD_ERROR(("prot is not inited\n"));
+ DHD_ERROR(("%s: prot is not inited\n", __FUNCTION__));
return BCME_ERROR;
}
@@ -738,8 +926,8 @@
ASSERT(ISALIGNED(prot->h2d_dma_writeindx_buf.va, 4));
bzero(prot->h2d_dma_writeindx_buf.va, dma_block_size);
OSL_CACHE_FLUSH((void *)prot->h2d_dma_writeindx_buf.va, dma_block_size);
- DHD_ERROR(("H2D_WRITEINDX_ARRAY_HOST: %d-bytes "
- "inited for dma'ing h2d-w indices\n",
+ DHD_ERROR(("%s: H2D_WRITEINDX_ARRAY_HOST: %d-bytes "
+ "inited for dma'ing h2d-w indices\n", __FUNCTION__,
prot->h2d_dma_writeindx_buf_len));
break;
@@ -757,8 +945,8 @@
ASSERT(ISALIGNED(prot->h2d_dma_readindx_buf.va, 4));
bzero(prot->h2d_dma_readindx_buf.va, dma_block_size);
OSL_CACHE_FLUSH((void *)prot->h2d_dma_readindx_buf.va, dma_block_size);
- DHD_ERROR(("H2D_READINDX_ARRAY_HOST %d-bytes "
- "inited for dma'ing h2d-r indices\n",
+ DHD_ERROR(("%s: H2D_READINDX_ARRAY_HOST %d-bytes "
+ "inited for dma'ing h2d-r indices\n", __FUNCTION__,
prot->h2d_dma_readindx_buf_len));
break;
@@ -777,8 +965,8 @@
ASSERT(ISALIGNED(prot->d2h_dma_writeindx_buf.va, 4));
bzero(prot->d2h_dma_writeindx_buf.va, dma_block_size);
OSL_CACHE_FLUSH((void *)prot->d2h_dma_writeindx_buf.va, dma_block_size);
- DHD_ERROR(("D2H_WRITEINDX_ARRAY_HOST %d-bytes "
- "inited for dma'ing d2h-w indices\n",
+ DHD_ERROR(("%s: D2H_WRITEINDX_ARRAY_HOST %d-bytes "
+ "inited for dma'ing d2h-w indices\n", __FUNCTION__,
prot->d2h_dma_writeindx_buf_len));
break;
@@ -797,8 +985,8 @@
ASSERT(ISALIGNED(prot->d2h_dma_readindx_buf.va, 4));
bzero(prot->d2h_dma_readindx_buf.va, dma_block_size);
OSL_CACHE_FLUSH((void *)prot->d2h_dma_readindx_buf.va, dma_block_size);
- DHD_ERROR(("D2H_READINDX_ARRAY_HOST %d-bytes "
- "inited for dma'ing d2h-r indices\n",
+ DHD_ERROR(("%s: D2H_READINDX_ARRAY_HOST %d-bytes "
+ "inited for dma'ing d2h-r indices\n", __FUNCTION__,
prot->d2h_dma_readindx_buf_len));
break;
@@ -916,6 +1104,10 @@
/* Post event buffer after shim layer is attached */
ret = dhd_msgbuf_rxbuf_post_event_bufs(dhd);
+ if (ret <= 0) {
+ DHD_ERROR(("%s : Post event buffer fail. ret = %d\n", __FUNCTION__, ret));
+ return ret;
+ }
/* Get the device rev info */
@@ -1096,10 +1288,16 @@
void *PKTBUF;
dmaaddr_t pa;
uint32 pa_len;
- PKTBUF = PKTID_TO_NATIVE(dhd->prot->pktid_map_handle, pktid, pa, pa_len);
+ void *secdma;
+ PKTBUF = PKTID_TO_NATIVE(dhd->prot->pktid_map_handle, pktid, pa, pa_len, secdma);
if (PKTBUF) {
- DMA_UNMAP(dhd->osh, pa, (uint) pa_len, DMA_TX, 0, 0);
+ {
+ if (SECURE_DMA_ENAB(dhd->osh)) {
+ SECURE_DMA_UNMAP(dhd->osh, pa, (uint) pa_len, DMA_TX, 0, 0, secdma, 0);
+ } else
+ DMA_UNMAP(dhd->osh, pa, (uint) pa_len, DMA_TX, 0, 0);
+ }
PKTFREE(dhd->osh, PKTBUF, FALSE);
}
return;
@@ -1111,8 +1309,12 @@
void *PKTBUF;
dmaaddr_t pa;
uint32 pa_len;
- PKTBUF = PKTID_TO_NATIVE(dhd->prot->pktid_map_handle, pktid, pa, pa_len);
+ void *secdma;
+ PKTBUF = PKTID_TO_NATIVE(dhd->prot->pktid_map_handle, pktid, pa, pa_len, secdma);
if (PKTBUF) {
+ if (SECURE_DMA_ENAB(dhd->osh))
+ SECURE_DMA_UNMAP(dhd->osh, pa, (uint) pa_len, DMA_RX, 0, 0, secdma, 0);
+ else
DMA_UNMAP(dhd->osh, pa, (uint) pa_len, DMA_RX, 0, 0);
}
@@ -1132,8 +1334,8 @@
cnt--;
if (cnt == 0) {
/* find a better way to reschedule rx buf post if space not available */
- DHD_ERROR(("h2d rx post ring not available to post host buffers \n"));
- DHD_ERROR(("Current posted host buf count %d \n", prot->rxbufpost));
+ DHD_ERROR(("%s: h2d rx post ring not available to post host buffers\n", __FUNCTION__));
+ DHD_ERROR(("%s: Current posted host buf count %d \n", __FUNCTION__, prot->rxbufpost));
break;
}
@@ -1194,20 +1396,29 @@
/* Create a rx buffer */
if ((p = PKTGET(dhd->osh, pktsz, FALSE)) == NULL) {
DHD_ERROR(("%s:%d: PKTGET for rxbuf failed\n", __FUNCTION__, __LINE__));
- return -1;
+ break;
}
pktlen = PKTLEN(dhd->osh, p);
+ if (SECURE_DMA_ENAB(dhd->osh)) {
+ DHD_GENERAL_LOCK(dhd, flags);
+ physaddr = SECURE_DMA_MAP(dhd->osh, PKTDATA(dhd->osh, p), pktlen, DMA_RX, p, 0,
+ ring->secdma, 0);
+ DHD_GENERAL_UNLOCK(dhd, flags);
+ } else
physaddr = DMA_MAP(dhd->osh, PKTDATA(dhd->osh, p), pktlen, DMA_RX, p, 0);
+
if (PHYSADDRISZERO(physaddr)) {
- if (RING_WRITE_PTR(ring) < alloced - i)
- RING_WRITE_PTR(ring) = RING_MAX_ITEM(ring) - alloced + i;
- else
- RING_WRITE_PTR(ring) -= alloced - i;
- alloced = i;
+ if (SECURE_DMA_ENAB(dhd->osh)) {
+ DHD_GENERAL_LOCK(dhd, flags);
+ SECURE_DMA_UNMAP(dhd->osh, physaddr, pktlen, DMA_RX, 0, 0,
+ ring->secdma, 0);
+ DHD_GENERAL_UNLOCK(dhd, flags);
+ } else
DMA_UNMAP(dhd->osh, physaddr, pktlen, DMA_RX, 0, 0);
+
PKTFREE(dhd->osh, p, FALSE);
- DHD_ERROR(("Invalid phyaddr 0\n"));
+ DHD_ERROR(("%s: Invalid phyaddr 0\n", __FUNCTION__));
ASSERT(0);
break;
}
@@ -1224,20 +1435,22 @@
rxbuf_post->cmn_hdr.request_id =
htol32(NATIVE_TO_PKTID(dhd->prot->pktid_map_handle, p, physaddr,
- pktlen, DMA_RX));
+ pktlen, DMA_RX, ring->secdma));
/* free lock */
DHD_GENERAL_UNLOCK(dhd, flags);
if (rxbuf_post->cmn_hdr.request_id == DHD_PKTID_INVALID) {
- if (RING_WRITE_PTR(ring) < alloced - i)
- RING_WRITE_PTR(ring) = RING_MAX_ITEM(ring) - alloced + i;
- else
- RING_WRITE_PTR(ring) -= alloced - i;
- alloced = i;
+ if (SECURE_DMA_ENAB(dhd->osh)) {
+ DHD_GENERAL_LOCK(dhd, flags);
+ SECURE_DMA_UNMAP(dhd->osh, physaddr, pktlen, DMA_RX, 0, 0,
+ ring->secdma, 0);
+ DHD_GENERAL_UNLOCK(dhd, flags);
+ } else
DMA_UNMAP(dhd->osh, physaddr, pktlen, DMA_RX, 0, 0);
+
PKTFREE(dhd->osh, p, FALSE);
- DHD_ERROR(("Pktid pool depleted.\n"));
+ DHD_ERROR(("%s: Pktid pool depleted.\n", __FUNCTION__));
break;
}
@@ -1259,6 +1472,16 @@
/* Move rxbuf_post_tmp to next item */
rxbuf_post_tmp = rxbuf_post_tmp + RING_LEN_ITEMS(ring);
}
+
+ if (i < alloced) {
+ if (RING_WRITE_PTR(ring) < (alloced - i))
+ RING_WRITE_PTR(ring) = RING_MAX_ITEM(ring) - (alloced - i);
+ else
+ RING_WRITE_PTR(ring) -= (alloced - i);
+
+ alloced = i;
+ }
+
/* Update the write pointer in TCM & ring bell */
if (alloced > 0)
prot_ring_write_complete(dhd, prot->h2dring_rxp_subn, msg_start, alloced);
@@ -1278,6 +1501,11 @@
uint16 alloced = 0;
unsigned long flags;
+ if (dhd->busstate == DHD_BUS_DOWN) {
+ DHD_ERROR(("%s: bus is already down.\n", __FUNCTION__));
+ return -1;
+ }
+
if (event_buf) {
/* Allocate packet for event buffer post */
pktsz = DHD_FLOWRING_RX_BUFPOST_PKTSZ;
@@ -1287,15 +1515,24 @@
}
if ((p = PKTGET(dhd->osh, pktsz, FALSE)) == NULL) {
- DHD_ERROR(("%s:%d: PKTGET for ctrl rxbuf failed\n", __FUNCTION__, __LINE__));
+ DHD_ERROR(("%s:%d: PKTGET for %s rxbuf failed\n",
+ __FUNCTION__, __LINE__, event_buf ?
+ "event" : "ioctl"));
return -1;
}
pktlen = PKTLEN(dhd->osh, p);
+ if (SECURE_DMA_ENAB(dhd->osh)) {
+ DHD_GENERAL_LOCK(dhd, flags);
+ physaddr = SECURE_DMA_MAP(dhd->osh, PKTDATA(dhd->osh, p), pktlen,
+ DMA_RX, p, 0, prot->h2dring_ctrl_subn->secdma, 0);
+ DHD_GENERAL_UNLOCK(dhd, flags);
+ } else
physaddr = DMA_MAP(dhd->osh, PKTDATA(dhd->osh, p), pktlen, DMA_RX, p, 0);
+
if (PHYSADDRISZERO(physaddr)) {
- DHD_ERROR(("Invalid phyaddr 0\n"));
+ DHD_ERROR(("%s: Invalid phyaddr 0\n", __FUNCTION__));
ASSERT(0);
goto free_pkt_return;
}
@@ -1305,9 +1542,17 @@
prot->h2dring_ctrl_subn, DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D, &alloced);
if (rxbuf_post == NULL) {
DHD_GENERAL_UNLOCK(dhd, flags);
- DHD_ERROR(("%s:%d: Ctrl submit Msgbuf Not available to post buffer \n",
- __FUNCTION__, __LINE__));
+ DHD_ERROR(("%s:%d: Ctrl submit Msgbuf Not available to post buffer"
+ " for %s\n", __FUNCTION__, __LINE__, event_buf ? "event" :
+ "ioctl"));
+ if (SECURE_DMA_ENAB(dhd->osh)) {
+ DHD_GENERAL_LOCK(dhd, flags);
+ SECURE_DMA_UNMAP(dhd->osh, physaddr, pktlen, DMA_RX, 0, 0,
+ prot->h2dring_ctrl_subn->secdma, 0);
+ DHD_GENERAL_UNLOCK(dhd, flags);
+ } else
DMA_UNMAP(dhd->osh, physaddr, pktlen, DMA_RX, 0, 0);
+
goto free_pkt_return;
}
@@ -1319,7 +1564,8 @@
rxbuf_post->cmn_hdr.if_id = 0;
rxbuf_post->cmn_hdr.request_id =
- htol32(NATIVE_TO_PKTID(dhd->prot->pktid_map_handle, p, physaddr, pktlen, DMA_RX));
+ htol32(NATIVE_TO_PKTID(dhd->prot->pktid_map_handle, p, physaddr, pktlen, DMA_RX,
+ prot->h2dring_ctrl_subn->secdma));
if (rxbuf_post->cmn_hdr.request_id == DHD_PKTID_INVALID) {
if (RING_WRITE_PTR(prot->h2dring_ctrl_subn) == 0)
@@ -1328,7 +1574,14 @@
else
RING_WRITE_PTR(prot->h2dring_ctrl_subn)--;
DHD_GENERAL_UNLOCK(dhd, flags);
+ if (SECURE_DMA_ENAB(dhd->osh)) {
+ DHD_GENERAL_LOCK(dhd, flags);
+ SECURE_DMA_UNMAP(dhd->osh, physaddr, pktlen, DMA_RX, 0, 0,
+ prot->h2dring_ctrl_subn->secdma, 0);
+ DHD_GENERAL_UNLOCK(dhd, flags);
+ } else
DMA_UNMAP(dhd->osh, physaddr, pktlen, DMA_RX, 0, 0);
+
goto free_pkt_return;
}
@@ -1356,14 +1609,20 @@
uint32 i = 0;
int32 ret_val;
- DHD_INFO(("max to post %d, event %d \n", max_to_post, event_buf));
+ DHD_INFO(("%s: max to post %d, event %d\n", __FUNCTION__, max_to_post, event_buf));
+
+ if (dhd->busstate == DHD_BUS_DOWN) {
+ DHD_ERROR(("%s: bus is already down.\n", __FUNCTION__));
+ return 0;
+ }
+
while (i < max_to_post) {
ret_val = dhd_prot_rxbufpost_ctrl(dhd, event_buf);
if (ret_val < 0)
break;
i++;
}
- DHD_INFO(("posted %d buffers to event_pool/ioctl_resp_pool %d\n", i, event_buf));
+ DHD_INFO(("%s: posted %d buffers to event_pool/ioctl_resp_pool %d\n", __FUNCTION__, i, event_buf));
return (uint16)i;
}
@@ -1373,26 +1632,43 @@
dhd_prot_t *prot = dhd->prot;
uint16 retcnt = 0;
- DHD_INFO(("ioctl resp buf post\n"));
+ DHD_INFO(("%s: ioctl resp buf post\n", __FUNCTION__));
+
+ if (dhd->busstate == DHD_BUS_DOWN) {
+ DHD_ERROR(("%s: bus is already down.\n", __FUNCTION__));
+ return 0;
+ }
+
retcnt = dhd_msgbuf_rxbuf_post_ctrlpath(dhd, FALSE,
prot->max_ioctlrespbufpost - prot->cur_ioctlresp_bufs_posted);
prot->cur_ioctlresp_bufs_posted += retcnt;
- return 0;
+ return retcnt;
}
static int
dhd_msgbuf_rxbuf_post_event_bufs(dhd_pub_t *dhd)
{
dhd_prot_t *prot = dhd->prot;
- prot->cur_event_bufs_posted += dhd_msgbuf_rxbuf_post_ctrlpath(dhd, TRUE,
+ uint16 retcnt = 0;
+
+ if (dhd->busstate == DHD_BUS_DOWN) {
+ DHD_ERROR(("%s: bus is already down.\n", __FUNCTION__));
+ return 0;
+ }
+
+ retcnt = dhd_msgbuf_rxbuf_post_ctrlpath(dhd, TRUE,
prot->max_eventbufpost - prot->cur_event_bufs_posted);
- return 0;
+
+ prot->cur_event_bufs_posted += retcnt;
+ return retcnt;
}
-int BCMFASTPATH
-dhd_prot_process_msgbuf_rxcpl(dhd_pub_t *dhd)
+bool BCMFASTPATH
+dhd_prot_process_msgbuf_rxcpl(dhd_pub_t *dhd, uint bound)
{
dhd_prot_t *prot = dhd->prot;
+ bool more = TRUE;
+ uint n = 0;
/* Process all the messages - DTOH direction */
while (TRUE) {
@@ -1405,8 +1681,10 @@
/* Get the message from ring */
src_addr = prot_get_src_addr(dhd, prot->d2hring_rx_cpln, &src_len);
- if (src_addr == NULL)
+ if (src_addr == NULL) {
+ more = FALSE;
break;
+ }
/* Prefetch data to populate the cache */
OSL_PREFETCH(src_addr);
@@ -1417,9 +1695,15 @@
DHD_ERROR(("%s: Error at process rxpl msgbuf of len %d\n",
__FUNCTION__, src_len));
}
+
+ /* After batch processing, check RX bound */
+ n += src_len/RING_LEN_ITEMS(prot->d2hring_rx_cpln);
+ if (n >= bound) {
+ break;
+ }
}
- return 0;
+ return more;
}
void
@@ -1434,7 +1718,7 @@
ring->ringstate->r_offset = r_index;
}
- DHD_TRACE(("flow %d, write %d read %d \n\n", flow_id, RING_WRITE_PTR(ring),
+ DHD_TRACE(("%s: flow %d, write %d read %d \n\n", __FUNCTION__, flow_id, RING_WRITE_PTR(ring),
RING_READ_PTR(ring)));
/* Need more logic here, but for now use it directly */
@@ -1442,10 +1726,12 @@
}
-int BCMFASTPATH
-dhd_prot_process_msgbuf_txcpl(dhd_pub_t *dhd)
+bool BCMFASTPATH
+dhd_prot_process_msgbuf_txcpl(dhd_pub_t *dhd, uint bound)
{
dhd_prot_t *prot = dhd->prot;
+ bool more = TRUE;
+ uint n = 0;
/* Process all the messages - DTOH direction */
while (TRUE) {
@@ -1453,8 +1739,10 @@
uint16 src_len;
src_addr = prot_get_src_addr(dhd, prot->d2hring_tx_cpln, &src_len);
- if (src_addr == NULL)
+ if (src_addr == NULL) {
+ more = FALSE;
break;
+ }
/* Prefetch data to populate the cache */
OSL_PREFETCH(src_addr);
@@ -1467,9 +1755,15 @@
/* Write to dngl rd ptr */
prot_upd_read_idx(dhd, prot->d2hring_tx_cpln);
+
+ /* After batch processing, check bound */
+ n += src_len/RING_LEN_ITEMS(prot->d2hring_tx_cpln);
+ if (n >= bound) {
+ break;
+ }
}
- return 0;
+ return more;
}
int BCMFASTPATH
@@ -1534,26 +1828,6 @@
return ret;
}
-#define PCIE_M2M_D2H_DMA_WAIT_TRIES 256
-#define PCIE_D2H_RESET_MARK 0xdeadbeef
-void dhd_msgbuf_d2h_check_cmplt(msgbuf_ring_t *ring, void *msg)
-{
- uint32 tries;
- uint32 *marker = (uint32 *)msg + RING_LEN_ITEMS(ring) / sizeof(uint32) - 1;
-
- for (tries = 0; tries < PCIE_M2M_D2H_DMA_WAIT_TRIES; tries++) {
- if (*(volatile uint32 *)marker != PCIE_D2H_RESET_MARK)
- return;
- OSL_CACHE_INV(msg, RING_LEN_ITEMS(ring));
- }
-
- /* only print error for data ring */
- if (ring->idx == BCMPCIE_D2H_MSGRING_TX_COMPLETE ||
- ring->idx == BCMPCIE_D2H_MSGRING_RX_COMPLETE)
- DHD_ERROR(("%s: stale msgbuf content after %d retries\n",
- __FUNCTION__, tries));
-}
-
static int BCMFASTPATH
dhd_process_msgtype(dhd_pub_t *dhd, msgbuf_ring_t *ring, uint8* buf, uint16 len)
{
@@ -1562,7 +1836,10 @@
uint8 msgtype;
cmn_msg_hdr_t *msg = NULL;
int ret = BCME_OK;
+
+#if defined(PCIE_D2H_SYNC_BZERO)
uint8 *buf_head = buf;
+#endif /* PCIE_D2H_SYNC_BZERO */
ASSERT(ring && ring->ringmem);
msglen = RING_LEN_ITEMS(ring);
@@ -1575,21 +1852,28 @@
while (pktlen > 0) {
msg = (cmn_msg_hdr_t *)buf;
- dhd_msgbuf_d2h_check_cmplt(ring, msg);
-
+#if defined(PCIE_D2H_SYNC)
+ /* Wait until DMA completes, then fetch msgtype */
+ msgtype = dhd->prot->d2h_sync_cb(dhd, ring, msg, msglen);
+#else
msgtype = msg->msg_type;
+#endif /* !PCIE_D2H_SYNC */
- /* Prefetch data to populate the cache */
- OSL_PREFETCH(buf + msglen);
-
- DHD_INFO(("msgtype %d, msglen is %d, pktlen is %d \n",
+ DHD_INFO(("%s: msgtype %d, msglen is %d, pktlen is %d\n", __FUNCTION__,
msgtype, msglen, pktlen));
if (msgtype == MSG_TYPE_LOOPBACK) {
bcm_print_bytes("LPBK RESP: ", (uint8 *)msg, msglen);
- DHD_ERROR((" MSG_TYPE_LOOPBACK, len %d\n", msglen));
+ DHD_ERROR(("%s: MSG_TYPE_LOOPBACK, len %d\n", __FUNCTION__, msglen));
+ }
+
+
+ if (msgtype >= DHD_PROT_FUNCS) {
+ DHD_ERROR(("%s: msgtype %d, msglen is %d, pktlen is %d \n",
+ __FUNCTION__, msgtype, msglen, pktlen));
+ ret = BCME_ERROR;
+ goto done;
}
- ASSERT(msgtype < DHD_PROT_FUNCS);
if (table_lookup[msgtype]) {
table_lookup[msgtype](dhd, buf, msglen);
}
@@ -1601,12 +1885,14 @@
pktlen = pktlen - msglen;
buf = buf + msglen;
- if (msgtype == MSG_TYPE_RX_CMPLT)
- prot_early_upd_rxcpln_read_idx(dhd,
- dhd->prot->d2hring_rx_cpln);
+ if (ring->idx == BCMPCIE_D2H_MSGRING_RX_COMPLETE)
+ prot_early_upd_rxcpln_read_idx(dhd, ring);
}
done:
- OSL_CACHE_FLUSH(buf_head, len - pktlen);
+
+#if defined(PCIE_D2H_SYNC_BZERO)
+ OSL_CACHE_FLUSH(buf_head, len - pktlen); /* Flush the bzeroed msg */
+#endif /* PCIE_D2H_SYNC_BZERO */
#ifdef DHD_RX_CHAINING
dhd_rxchain_commit(dhd);
@@ -1616,10 +1902,17 @@
}
static void
+dhd_prot_noop(dhd_pub_t *dhd, void * buf, uint16 msglen)
+{
+ return;
+}
+
+static void
dhd_prot_ringstatus_process(dhd_pub_t *dhd, void * buf, uint16 msglen)
{
pcie_ring_status_t * ring_status = (pcie_ring_status_t *)buf;
- DHD_ERROR(("ring status: request_id %d, status 0x%04x, flow ring %d, w_offset %d \n",
+ DHD_ERROR(("%s: ring status: request_id %d, status 0x%04x, flow ring %d, w_offset %d \n",
+ __FUNCTION__,
ring_status->cmn_hdr.request_id, ring_status->compl_hdr.status,
ring_status->compl_hdr.flow_ring_id, ring_status->write_idx));
/* How do we track this to pair it with ??? */
@@ -1630,7 +1923,8 @@
dhd_prot_genstatus_process(dhd_pub_t *dhd, void * buf, uint16 msglen)
{
pcie_gen_status_t * gen_status = (pcie_gen_status_t *)buf;
- DHD_ERROR(("gen status: request_id %d, status 0x%04x, flow ring %d \n",
+ DHD_ERROR(("%s: gen status: request_id %d, status 0x%04x, flow ring %d \n",
+ __FUNCTION__,
gen_status->cmn_hdr.request_id, gen_status->compl_hdr.status,
gen_status->compl_hdr.flow_ring_id));
@@ -1643,16 +1937,20 @@
{
ioctl_req_ack_msg_t * ioct_ack = (ioctl_req_ack_msg_t *)buf;
- DHD_CTL(("ioctl req ack: request_id %d, status 0x%04x, flow ring %d \n",
+ DHD_CTL(("%s: ioctl req ack: request_id %d, status 0x%04x, flow ring %d \n",
+ __FUNCTION__,
ioct_ack->cmn_hdr.request_id, ioct_ack->compl_hdr.status,
ioct_ack->compl_hdr.flow_ring_id));
if (ioct_ack->compl_hdr.status != 0) {
- DHD_ERROR(("got an error status for the ioctl request...need to handle that\n"));
+ DHD_ERROR(("%s: got an error status for the ioctl request...need to handle that\n",
+ __FUNCTION__));
}
+#if defined(PCIE_D2H_SYNC_BZERO)
memset(buf, 0, msglen);
- ioct_ack->marker = PCIE_D2H_RESET_MARK;
+#endif /* PCIE_D2H_SYNC_BZERO */
}
+
static void
dhd_prot_ioctcmplt_process(dhd_pub_t *dhd, void * buf, uint16 msglen)
{
@@ -1666,10 +1964,11 @@
pkt_id = ltoh32(ioct_resp->cmn_hdr.request_id);
status = ioct_resp->compl_hdr.status;
+#if defined(PCIE_D2H_SYNC_BZERO)
memset(buf, 0, msglen);
- ioct_resp->marker = PCIE_D2H_RESET_MARK;
+#endif /* PCIE_D2H_SYNC_BZERO */
- DHD_CTL(("IOCTL_COMPLETE: pktid %x xtid %d status %x resplen %d\n",
+ DHD_CTL(("%s: IOCTL_COMPLETE: pktid %x xtid %d status %x resplen %d\n", __FUNCTION__,
pkt_id, xt_id, status, resp_len));
dhd_bus_update_retlen(dhd->bus, sizeof(ioctl_comp_resp_msg_t), pkt_id, status, resp_len);
@@ -1684,25 +1983,39 @@
unsigned long flags;
uint32 pktid;
void *pkt;
-
+ ulong pa;
+ uint32 pa_len;
+ void *secdma;
/* locks required to protect circular buffer accesses */
DHD_GENERAL_LOCK(dhd, flags);
txstatus = (host_txbuf_cmpl_t *)buf;
pktid = ltoh32(txstatus->cmn_hdr.request_id);
- DHD_INFO(("txstatus for pktid 0x%04x\n", pktid));
+ DHD_INFO(("%s: txstatus for pktid 0x%04x\n", __FUNCTION__, pktid));
if (prot->active_tx_count)
prot->active_tx_count--;
else
- DHD_ERROR(("Extra packets are freed\n"));
+ DHD_ERROR(("%s: Extra packets are freed\n", __FUNCTION__));
ASSERT(pktid != 0);
- pkt = dhd_prot_packet_get(dhd, pktid);
+ pkt = PKTID_TO_NATIVE(dhd->prot->pktid_map_handle, pktid, pa, pa_len, secdma);
if (pkt) {
+ if (SECURE_DMA_ENAB(dhd->osh)) {
+ int offset = 0;
+ BCM_REFERENCE(offset);
+
+ if (dhd->prot->tx_metadata_offset)
+ offset = dhd->prot->tx_metadata_offset + ETHER_HDR_LEN;
+ SECURE_DMA_UNMAP(dhd->osh, (uint) pa,
+ (uint) dhd->prot->tx_metadata_offset, DMA_RX, 0, 0,
+ secdma, offset);
+ } else
+ DMA_UNMAP(dhd->osh, pa, (uint) pa_len, DMA_RX, 0, dmah);
+
#if defined(BCMPCIE)
dhd_txcomplete(dhd, pkt, true);
-#endif
+#endif
#if DHD_DBG_SHOW_METADATA
if (dhd->prot->tx_metadata_offset && txstatus->metadata_len) {
@@ -1719,8 +2032,9 @@
PKTFREE(dhd->osh, pkt, TRUE);
}
+#if defined(PCIE_D2H_SYNC_BZERO)
memset(buf, 0, msglen);
- txstatus->marker = PCIE_D2H_RESET_MARK;
+#endif /* PCIE_D2H_SYNC_BZERO */
DHD_GENERAL_UNLOCK(dhd, flags);
@@ -1737,6 +2051,8 @@
void* pkt;
unsigned long flags;
dhd_prot_t *prot = dhd->prot;
+ int post_cnt = 0;
+ bool zero_posted = FALSE;
/* Event complete header */
evnt = (wlevent_req_msg_t *)buf;
@@ -1748,10 +2064,18 @@
/* Post another rxbuf to the device */
if (prot->cur_event_bufs_posted)
prot->cur_event_bufs_posted--;
- dhd_msgbuf_rxbuf_post_event_bufs(dhd);
+ else
+ zero_posted = TRUE;
+
+ post_cnt = dhd_msgbuf_rxbuf_post_event_bufs(dhd);
+ if (zero_posted && (post_cnt <= 0)) {
+ return;
+ }
+
+#if defined(PCIE_D2H_SYNC_BZERO)
memset(buf, 0, len);
- evnt->marker = PCIE_D2H_RESET_MARK;
+#endif /* PCIE_D2H_SYNC_BZERO */
/* locks required to protect pktid_map */
DHD_GENERAL_LOCK(dhd, flags);
@@ -1797,7 +2121,8 @@
return;
}
- DHD_INFO(("id 0x%04x, offset %d, len %d, idx %d, phase 0x%02x, pktdata %p, metalen %d\n",
+ DHD_INFO(("%s: id 0x%04x, offset %d, len %d, idx %d, phase 0x%02x, pktdata %p, metalen %d\n",
+ __FUNCTION__,
ltoh32(rxcmplt_h->cmn_hdr.request_id), data_offset, ltoh16(rxcmplt_h->data_len),
rxcmplt_h->cmn_hdr.if_id, rxcmplt_h->cmn_hdr.flags, PKTDATA(dhd->osh, pkt),
ltoh16(rxcmplt_h->metadata_len)));
@@ -1816,7 +2141,7 @@
current_phase = rxcmplt_h->cmn_hdr.flags;
}
if (rxcmplt_h->flags & BCMPCIE_PKT_FLAGS_FRAME_802_11)
- DHD_INFO(("D11 frame rxed \n"));
+ DHD_INFO(("%s: D11 frame rxed\n", __FUNCTION__));
/* data_offset from buf start */
if (data_offset) {
/* data offset given from dongle after split rx */
@@ -1830,8 +2155,10 @@
PKTSETLEN(dhd->osh, pkt, ltoh16(rxcmplt_h->data_len));
ifidx = rxcmplt_h->cmn_hdr.if_id;
+
+#if defined(PCIE_D2H_SYNC_BZERO)
memset(buf, 0, msglen);
- rxcmplt_h->marker = PCIE_D2H_RESET_MARK;
+#endif /* PCIE_D2H_SYNC_BZERO */
#ifdef DHD_RX_CHAINING
/* Chain the packets */
@@ -1875,7 +2202,7 @@
host_txbuf_post_t *txdesc = NULL;
dmaaddr_t physaddr, meta_physaddr;
uint8 *pktdata;
- uint16 pktlen;
+ uint32 pktlen;
uint32 pktid;
uint8 prio;
uint16 flowid = 0;
@@ -1883,6 +2210,10 @@
uint16 headroom;
msgbuf_ring_t *msg_ring;
+ uint8 dhcp_pkt;
+
+ if (!dhd->flow_ring_table)
+ return BCME_NORESOURCE;
if (!dhd_bus_is_txmode_push(dhd->bus)) {
flow_ring_table_t *flow_ring_table;
@@ -1905,7 +2236,7 @@
/* Create a unique 32-bit packet id */
pktid = NATIVE_TO_PKTID_RSV(dhd->prot->pktid_map_handle, PKTBUF);
if (pktid == DHD_PKTID_INVALID) {
- DHD_ERROR(("Pktid pool depleted.\n"));
+ DHD_ERROR(("%s: Pktid pool depleted.\n", __FUNCTION__));
/*
* If we return error here, the caller would queue the packet
* again. So we'll just free the skb allocated in DMA Zone.
@@ -1919,17 +2250,24 @@
txdesc = (host_txbuf_post_t *)dhd_alloc_ring_space(dhd,
msg_ring, DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D, &alloced);
if (txdesc == NULL) {
+ void *secdma;
DHD_INFO(("%s:%d: HTOD Msgbuf Not available TxCount = %d\n",
__FUNCTION__, __LINE__, prot->active_tx_count));
/* Free up the PKTID */
PKTID_TO_NATIVE(dhd->prot->pktid_map_handle, pktid, physaddr,
- pktlen);
+ pktlen, secdma);
goto err_no_res_pktfree;
}
+ /* test if dhcp pkt */
+ dhcp_pkt = pkt_is_dhcp(dhd->osh, PKTBUF);
+ txdesc->flag2 = (txdesc->flag2 & ~(BCMPCIE_PKT_FLAGS2_FORCELOWRATE_MASK <<
+ BCMPCIE_PKT_FLAGS2_FORCELOWRATE_SHIFT)) | ((dhcp_pkt &
+ BCMPCIE_PKT_FLAGS2_FORCELOWRATE_MASK) << BCMPCIE_PKT_FLAGS2_FORCELOWRATE_SHIFT);
+
/* Extract the data pointer and length information */
pktdata = PKTDATA(dhd->osh, PKTBUF);
- pktlen = (uint16)PKTLEN(dhd->osh, PKTBUF);
+ pktlen = PKTLEN(dhd->osh, PKTBUF);
/* Ethernet header: Copy before we cache flush packet using DMA_MAP */
bcopy(pktdata, txdesc->txhdr, ETHER_HDR_LEN);
@@ -1939,15 +2277,27 @@
pktlen -= ETHER_HDR_LEN;
/* Map the data pointer to a DMA-able address */
+ if (SECURE_DMA_ENAB(dhd->osh)) {
+
+ int offset = 0;
+ BCM_REFERENCE(offset);
+
+ if (prot->tx_metadata_offset)
+ offset = prot->tx_metadata_offset + ETHER_HDR_LEN;
+
+ physaddr = SECURE_DMA_MAP(dhd->osh, PKTDATA(dhd->osh, PKTBUF), pktlen,
+ DMA_TX, PKTBUF, 0, msg_ring->secdma, offset);
+ } else
physaddr = DMA_MAP(dhd->osh, PKTDATA(dhd->osh, PKTBUF), pktlen, DMA_TX, PKTBUF, 0);
+
if ((PHYSADDRHI(physaddr) == 0) && (PHYSADDRLO(physaddr) == 0)) {
- DHD_ERROR(("Something really bad, unless 0 is a valid phyaddr\n"));
+ DHD_ERROR(("%s: Something really bad, unless 0 is a valid phyaddr\n", __FUNCTION__));
ASSERT(0);
}
/* No need to lock. Save the rest of the packet's metadata */
NATIVE_TO_PKTID_SAVE(dhd->prot->pktid_map_handle, PKTBUF, pktid,
- physaddr, pktlen, DMA_TX);
+ physaddr, pktlen, DMA_TX, msg_ring->secdma);
#ifdef TXP_FLUSH_NITEMS
if (msg_ring->pend_items_count == 0)
@@ -1968,7 +2318,7 @@
txdesc->flags |= (prio & 0x7) << BCMPCIE_PKT_FLAGS_PRIO_SHIFT;
txdesc->seg_cnt = 1;
- txdesc->data_len = htol16(pktlen);
+ txdesc->data_len = htol16((uint16)pktlen);
txdesc->data_buf_addr.high_addr = htol32(PHYSADDRHI(physaddr));
txdesc->data_buf_addr.low_addr = htol32(PHYSADDRLO(physaddr));
@@ -1978,18 +2328,24 @@
/* Handle Tx metadata */
headroom = (uint16)PKTHEADROOM(dhd->osh, PKTBUF);
if (prot->tx_metadata_offset && (headroom < prot->tx_metadata_offset))
- DHD_ERROR(("No headroom for Metadata tx %d %d\n",
+ DHD_ERROR(("%s: No headroom for Metadata tx %d %d\n", __FUNCTION__,
prot->tx_metadata_offset, headroom));
if (prot->tx_metadata_offset && (headroom >= prot->tx_metadata_offset)) {
- DHD_TRACE(("Metadata in tx %d\n", prot->tx_metadata_offset));
+ DHD_TRACE(("%s: Metadata in tx %d\n", __FUNCTION__, prot->tx_metadata_offset));
/* Adjust the data pointer to account for meta data in DMA_MAP */
PKTPUSH(dhd->osh, PKTBUF, prot->tx_metadata_offset);
+ if (SECURE_DMA_ENAB(dhd->osh)) {
+ meta_physaddr = SECURE_DMA_MAP_TXMETA(dhd->osh, PKTDATA(dhd->osh, PKTBUF),
+ prot->tx_metadata_offset + ETHER_HDR_LEN, DMA_RX, PKTBUF,
+ 0, msg_ring->secdma);
+ } else
meta_physaddr = DMA_MAP(dhd->osh, PKTDATA(dhd->osh, PKTBUF),
prot->tx_metadata_offset, DMA_RX, PKTBUF, 0);
+
if (PHYSADDRISZERO(meta_physaddr)) {
- DHD_ERROR(("Something really bad, unless 0 is a valid phyaddr\n"));
+ DHD_ERROR(("%s: Something really bad, unless 0 is a valid phyaddr\n", __FUNCTION__));
ASSERT(0);
}
@@ -2007,7 +2363,7 @@
}
- DHD_TRACE(("txpost: data_len %d, pktid 0x%04x\n", txdesc->data_len,
+ DHD_TRACE(("%s: txpost: data_len %d, pktid 0x%04x\n", __FUNCTION__, txdesc->data_len,
txdesc->cmn_hdr.request_id));
/* Update the write pointer in TCM & ring bell */
@@ -2047,6 +2403,8 @@
flow_ring_node_t *flow_ring_node;
msgbuf_ring_t *msg_ring;
+ if (!dhd->flow_ring_table)
+ return;
if (!in_lock) {
DHD_GENERAL_LOCK(dhd, flags);
@@ -2122,7 +2480,8 @@
goto done;
if (prot->pending == TRUE) {
- DHD_ERROR(("packet is pending!!!! cmd=0x%x (%lu) lastcmd=0x%x (%lu)\n",
+ DHD_ERROR(("%s: packet is pending!!!! cmd=0x%x (%lu) lastcmd=0x%x (%lu)\n",
+ __FUNCTION__,
ioc->cmd, (unsigned long)ioc->cmd, prot->lastcmd,
(unsigned long)prot->lastcmd));
if ((ioc->cmd == WLC_SET_VAR) || (ioc->cmd == WLC_GET_VAR)) {
@@ -2298,7 +2657,7 @@
prot->dmaxfer.destmem.va, prot->dmaxfer.len);
}
else {
- DHD_INFO(("DMA successful\n"));
+ DHD_INFO(("%s: DMA successful\n", __FUNCTION__));
}
}
dmaxfer_free_dmaaddr(dhd, &prot->dmaxfer);
@@ -2317,7 +2676,7 @@
uint16 alloced = 0;
if (prot->dmaxfer_in_progress) {
- DHD_ERROR(("DMA is in progress...\n"));
+ DHD_ERROR(("%s: DMA is in progress...\n", __FUNCTION__));
return ret;
}
prot->dmaxfer_in_progress = TRUE;
@@ -2361,7 +2720,7 @@
DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D);
DHD_GENERAL_UNLOCK(dhd, flags);
- DHD_ERROR(("DMA Started...\n"));
+ DHD_ERROR(("%s: DMA Started...\n", __FUNCTION__));
return BCME_OK;
}
@@ -2391,8 +2750,12 @@
}
ret = dhd_fillup_ioct_reqst_ptrbased(dhd, (uint16)len, cmd, buf, ifidx);
+ if (ret < 0) {
+ DHD_ERROR(("%s : dhd_fillup_ioct_reqst_ptrbased error : %d\n", __FUNCTION__, ret));
+ return ret;
+ }
- DHD_INFO(("ACTION %d ifdix %d cmd %d len %d \n",
+ DHD_INFO(("%s: ACTION %d ifdix %d cmd %d len %d \n", __FUNCTION__,
action, ifidx, cmd, len));
/* wait for interrupt and get first fragment */
@@ -2409,21 +2772,34 @@
void* pkt;
int retlen;
int msgbuf_len = 0;
+ int post_cnt = 0;
unsigned long flags;
+ bool zero_posted = FALSE;
DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+ if (dhd->busstate == DHD_BUS_DOWN) {
+ DHD_ERROR(("%s: bus is already down.\n", __FUNCTION__));
+ return -1;
+ }
if (prot->cur_ioctlresp_bufs_posted)
prot->cur_ioctlresp_bufs_posted--;
+ else
+ zero_posted = TRUE;
+
+ post_cnt = dhd_msgbuf_rxbuf_post_ioctlresp_bufs(dhd);
+ if (zero_posted && (post_cnt <= 0)) {
+ return -1;
+ }
- dhd_msgbuf_rxbuf_post_ioctlresp_bufs(dhd);
+ memset(&ioct_resp, 0, sizeof(ioctl_comp_resp_msg_t));
retlen = dhd_bus_rxctl(dhd->bus, (uchar*)&ioct_resp, msgbuf_len);
if (retlen <= 0) {
- DHD_ERROR(("IOCTL request failed with error code %d\n", retlen));
+ DHD_ERROR(("%s: IOCTL request failed with error code %d\n", __FUNCTION__, retlen));
return retlen;
}
- DHD_INFO(("ioctl resp retlen %d status %d, resp_len %d, pktid %d\n",
+ DHD_INFO(("%s: ioctl resp retlen %d status %d, resp_len %d, pktid %d\n", __FUNCTION__,
retlen, ioct_resp.compl_hdr.status, ioct_resp.resp_len,
ioct_resp.cmn_hdr.request_id));
if (ioct_resp.resp_len != 0) {
@@ -2431,7 +2807,7 @@
pkt = dhd_prot_packet_get(dhd, ioct_resp.cmn_hdr.request_id);
DHD_GENERAL_UNLOCK(dhd, flags);
- DHD_INFO(("ioctl ret buf %p retlen %d status %x \n", pkt, retlen,
+ DHD_INFO(("%s: ioctl ret buf %p retlen %d status %x\n", __FUNCTION__, pkt, retlen,
ioct_resp.compl_hdr.status));
/* get ret buf */
if ((buf) && (pkt)) {
@@ -2474,8 +2850,12 @@
/* Fill up msgbuf for ioctl req */
ret = dhd_fillup_ioct_reqst_ptrbased(dhd, (uint16)len, cmd, buf, ifidx);
+ if (ret < 0) {
+ DHD_ERROR(("%s : dhd_fillup_ioct_reqst_ptrbased error : %d\n", __FUNCTION__, ret));
+ return ret;
+ }
- DHD_INFO(("ACTIOn %d ifdix %d cmd %d len %d \n",
+ DHD_INFO(("%s: ACTIOn %d ifdix %d cmd %d len %d \n", __FUNCTION__,
action, ifidx, cmd, len));
ret = dhdmsgbuf_cmplt(dhd, prot->reqid, len, buf, prot->retbuf.va);
@@ -2498,7 +2878,16 @@
/* Add prot dump output to a buffer */
void dhd_prot_dump(dhd_pub_t *dhd, struct bcmstrbuf *strbuf)
{
-
+#if defined(PCIE_D2H_SYNC)
+ if (dhd->d2h_sync_mode & PCIE_SHARED_D2H_SYNC_SEQNUM)
+ bcm_bprintf(strbuf, "\nd2h_sync: SEQNUM:");
+ else if (dhd->d2h_sync_mode & PCIE_SHARED_D2H_SYNC_XORCSUM)
+ bcm_bprintf(strbuf, "\nd2h_sync: XORCSUM:");
+ else
+ bcm_bprintf(strbuf, "\nd2h_sync: NONE:");
+ bcm_bprintf(strbuf, " d2h_sync_wait max<%lu> tot<%lu>\n",
+ dhd->prot->d2h_sync_wait_max, dhd->prot->d2h_sync_wait_tot);
+#endif /* PCIE_D2H_SYNC */
}
/* Update local copy of dongle statistics */
@@ -2571,7 +2960,10 @@
ret_buf = prot_get_ring_space(ring, nitems, alloced);
if (ret_buf == NULL) {
- DHD_INFO(("%s: Ring space not available \n", ring->name));
+ DHD_INFO(("%s: RING space not available on ring %s for %d items \n", __FUNCTION__,
+ ring->name, nitems));
+ DHD_INFO(("%s: write %d read %d \n\n", __FUNCTION__, RING_WRITE_PTR(ring),
+ RING_READ_PTR(ring)));
return NULL;
}
}
@@ -2610,7 +3002,7 @@
ioct_rqst = (ioctl_req_msg_t*)dhd_alloc_ring_space(dhd, prot->h2dring_ctrl_subn,
DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D, &alloced);
if (ioct_rqst == NULL) {
- DHD_ERROR(("couldn't allocate space on msgring to send ioctl request\n"));
+ DHD_ERROR(("%s: couldn't allocate space on msgring to send ioctl request\n", __FUNCTION__));
DHD_GENERAL_UNLOCK(dhd, flags);
return -1;
}
@@ -2638,9 +3030,10 @@
OSL_CACHE_FLUSH((void *) prot->ioctbuf.va, len);
if ((ulong)ioct_buf % DMA_ALIGN_LEN)
- DHD_ERROR(("host ioct address unaligned !!!!! \n"));
+ DHD_ERROR(("%s: host ioct address unaligned !!!!! \n", __FUNCTION__));
- DHD_CTL(("submitted IOCTL request request_id %d, cmd %d, output_buf_len %d, tx_id %d\n",
+ DHD_CTL(("%s: submitted IOCTL request request_id %d, cmd %d, output_buf_len %d, tx_id %d\n",
+ __FUNCTION__,
ioct_rqst->cmn_hdr.request_id, cmd, ioct_rqst->output_buf_len,
ioct_rqst->trans_id));
@@ -2791,8 +3184,7 @@
uint alloced = 0;
msgbuf_ring_t *ring;
dmaaddr_t physaddr;
- uint16 size, cnt;
- uint32 *marker;
+ uint16 size;
ASSERT(name);
BCM_REFERENCE(physaddr);
@@ -2822,6 +3214,13 @@
size = max_item * len_item;
/* Ring Memmory allocation */
+#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_FLOWRING)
+ if (RING_IS_FLOWRING(ring)) {
+ ring->ring_base.va = DMA_ALLOC_CONSISTENT_STATIC(prot->osh,
+ size, DMA_ALIGN_LEN, &alloced, &ring->ring_base.pa,
+ &ring->ring_base.dmah, ringid);
+ } else
+#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_FLOWRING */
ring->ring_base.va = DMA_ALLOC_CONSISTENT(prot->osh, size, DMA_ALIGN_LEN,
&alloced, &ring->ring_base.pa, &ring->ring_base.dmah);
@@ -2832,11 +3231,7 @@
ASSERT(MODX((unsigned long)ring->ring_base.va, DMA_ALIGN_LEN) == 0);
bzero(ring->ring_base.va, size);
- for (cnt = 0; cnt < max_item; cnt++) {
- marker = (uint32 *)ring->ring_base.va +
- (cnt + 1) * len_item / sizeof(uint32) - 1;
- *marker = PCIE_D2H_RESET_MARK;
- }
+
OSL_CACHE_FLUSH((void *) ring->ring_base.va, size);
/* Ring state init */
@@ -2845,19 +3240,30 @@
goto fail;
bzero(ring->ringstate, sizeof(*ring->ringstate));
- DHD_INFO(("RING_ATTACH : %s Max item %d len item %d total size %d "
- "ring start %p buf phys addr %x:%x \n",
+#ifdef BCM_SECURE_DMA
+ if (SECURE_DMA_ENAB(prot->osh)) {
+ ring->secdma = MALLOC(prot->osh, sizeof(sec_cma_info_t));
+ bzero(ring->secdma, sizeof(sec_cma_info_t));
+ if (ring->secdma == NULL) {
+ DHD_ERROR(("%s: MALLOC failure for secdma\n", __FUNCTION__));
+ goto fail;
+ }
+ }
+#endif
+ DHD_INFO(("%s: RING_ATTACH : %s Max item %d len item %d total size %d "
+ "ring start %p buf phys addr %x:%x \n", __FUNCTION__,
ring->name, ring->ringmem->max_item, ring->ringmem->len_items,
size, ring->ring_base.va, ring->ringmem->base_addr.high_addr,
ring->ringmem->base_addr.low_addr));
return ring;
fail:
- if (ring->ring_base.va)
+ if (ring->ring_base.va && ring->ringmem) {
PHYSADDRHISET(physaddr, ring->ringmem->base_addr.high_addr);
PHYSADDRLOSET(physaddr, ring->ringmem->base_addr.low_addr);
size = ring->ringmem->max_item * ring->ringmem->len_items;
DMA_FREE_CONSISTENT(prot->osh, ring->ring_base.va, size, ring->ring_base.pa, NULL);
ring->ring_base.va = NULL;
+ }
if (ring->ringmem)
MFREE(prot->osh, ring->ringmem, sizeof(ring_mem_t));
MFREE(prot->osh, ring, sizeof(msgbuf_ring_t));
@@ -2907,6 +3313,12 @@
size = ring->ringmem->max_item * ring->ringmem->len_items;
/* Free up ring */
if (ring->ring_base.va) {
+#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_FLOWRING)
+ if (RING_IS_FLOWRING(ring)) {
+ DMA_FREE_CONSISTENT_STATIC(prot->osh, ring->ring_base.va, size,
+ ring->ring_base.pa, ring->ring_base.dmah, ring->idx);
+ } else
+#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_FLOWRING */
DMA_FREE_CONSISTENT(prot->osh, ring->ring_base.va, size, ring->ring_base.pa,
ring->ring_base.dmah);
ring->ring_base.va = NULL;
@@ -2923,6 +3335,13 @@
MFREE(prot->osh, ring->ringstate, sizeof(ring_state_t));
ring->ringstate = NULL;
}
+#ifdef BCM_SECURE_DMA
+ if (SECURE_DMA_ENAB(prot->osh)) {
+ DHD_ERROR(("%s:free secdma\n", __FUNCTION__));
+ SECURE_DMA_UNMAP_ALL(prot->osh, ring->secdma);
+ MFREE(prot->osh, ring->secdma, sizeof(sec_cma_info_t));
+ }
+#endif
/* free up ring info */
MFREE(prot->osh, ring, sizeof(msgbuf_ring_t));
@@ -2940,10 +3359,6 @@
RING_MAX_ITEM(ring));
if (ring_avail_cnt == 0) {
- DHD_INFO(("RING space not available on ring %s for %d items \n",
- ring->name, nitems));
- DHD_INFO(("write %d read %d \n\n", RING_WRITE_PTR(ring),
- RING_READ_PTR(ring)));
return NULL;
}
*alloced = MIN(nitems, ring_avail_cnt);
@@ -3161,7 +3576,11 @@
if (*available_len == 0)
return NULL;
- ASSERT(*available_len <= ring->ringmem->max_item);
+ if (*available_len > ring->ringmem->max_item) {
+ DHD_ERROR(("%s: *available_len %d, ring->ringmem->max_item %d\n",
+ __FUNCTION__, *available_len, ring->ringmem->max_item));
+ return NULL;
+ }
/* if space available, calculate address to be read */
ret_addr = (char*)ring->ring_base.va + (r_ptr * ring->ringmem->len_items);
@@ -3177,6 +3596,9 @@
/* convert index to bytes */
*available_len = *available_len * ring->ringmem->len_items;
+ /* Cache invalidate */
+ OSL_CACHE_INV((void *) ret_addr, *available_len);
+
/* return read address */
return ret_addr;
}
@@ -3365,6 +3787,7 @@
dhd_prot_t *prot = dhd->prot;
uint16 msglen = sizeof(tx_flowring_delete_request_t);
unsigned long flags;
+ char eabuf[ETHER_ADDR_STR_LEN];
uint16 alloced = 0;
/* align it to 4 bytes, so that all start addr form cbuf is 4 byte aligned */
@@ -3390,7 +3813,11 @@
flow_delete_rqst->flow_ring_id = htol16((uint16)flow_ring_node->flowid);
flow_delete_rqst->reason = htol16(BCME_OK);
- DHD_ERROR(("%s sending FLOW RING Delete req msglen %d \n", __FUNCTION__, msglen));
+ bcm_ether_ntoa((struct ether_addr *)flow_ring_node->flow_info.da, eabuf);
+ DHD_ERROR(("%s sending FLOW RING ID %d for peer %s prio %d ifindex %d"
+ " Delete req msglen %d\n", __FUNCTION__,
+ flow_ring_node->flowid, eabuf, flow_ring_node->flow_info.tid,
+ flow_ring_node->flow_info.ifindex, msglen));
/* upd wrt ptr and raise interrupt */
prot_ring_write_complete(dhd, prot->h2dring_ctrl_subn, flow_delete_rqst,
@@ -3408,8 +3835,18 @@
DHD_INFO(("%s Flow Delete Response status = %d \n", __FUNCTION__,
flow_delete_resp->cmplt.status));
+#ifdef PCIE_TX_DEFERRAL
+ if (flow_delete_resp->cmplt.status != BCME_OK) {
+ DHD_ERROR(("%s Flow Delete Response failure error status = %d \n",
+ __FUNCTION__, flow_delete_resp->cmplt.status));
+ return;
+ }
+ set_bit(flow_delete_resp->cmplt.flow_ring_id, dhd->bus->delete_flow_map);
+ queue_work(dhd->bus->tx_wq, &dhd->bus->delete_flow_work);
+#else
dhd_bus_flow_ring_delete_response(dhd->bus, flow_delete_resp->cmplt.flow_ring_id,
flow_delete_resp->cmplt.status);
+#endif /* PCIE_TX_DEFERRAL */
}
int
diff -Nur a/drivers/net/wireless/bcmdhd/dhd_pcie.c c/drivers/net/wireless/bcmdhd/dhd_pcie.c
--- a/drivers/net/wireless/bcmdhd/dhd_pcie.c 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/dhd_pcie.c 2016-05-13 09:48:20.000000000 +0200
@@ -3,7 +3,7 @@
*
* $Copyright Open Broadcom Corporation$
*
- * $Id: dhd_pcie.c 491657 2014-07-17 06:29:40Z $
+ * $Id: dhd_pcie.c 506043 2014-10-02 12:29:45Z $
*/
@@ -36,6 +36,7 @@
#ifdef DHDTCPACK_SUPPRESS
#include <dhd_ip.h>
#endif /* DHDTCPACK_SUPPRESS */
+#include <dhd_config.h>
#ifdef BCMEMBEDIMAGE
#include BCMEMBEDIMAGE
@@ -48,6 +49,10 @@
#define ARMCR4REG_BANKPDA (0x4C/sizeof(uint32))
/* Temporary war to fix precommit till sync issue between trunk & precommit branch is resolved */
+#if defined(SUPPORT_MULTIPLE_BOARD_REV)
+ extern unsigned int system_rev;
+#endif /* SUPPORT_MULTIPLE_BOARD_REV */
+
int dhd_dongle_memsize;
int dhd_dongle_ramsize;
#ifdef DHD_DEBUG
@@ -65,8 +70,8 @@
static int _dhdpcie_download_firmware(struct dhd_bus *bus);
static int dhdpcie_download_firmware(dhd_bus_t *bus, osl_t *osh);
static int dhdpcie_bus_write_vars(dhd_bus_t *bus);
-static void dhdpcie_bus_process_mailbox_intr(dhd_bus_t *bus, uint32 intstatus);
-static void dhdpci_bus_read_frames(dhd_bus_t *bus);
+static bool dhdpcie_bus_process_mailbox_intr(dhd_bus_t *bus, uint32 intstatus);
+static bool dhdpci_bus_read_frames(dhd_bus_t *bus);
static int dhdpcie_readshared(dhd_bus_t *bus);
static void dhdpcie_init_shared_addr(dhd_bus_t *bus);
static bool dhdpcie_dongle_attach(dhd_bus_t *bus);
@@ -85,6 +90,10 @@
static void dhdpcie_bus_wtcm64(dhd_bus_t *bus, ulong offset, uint64 data);
static uint64 dhdpcie_bus_rtcm64(dhd_bus_t *bus, ulong offset);
static void dhdpcie_bus_cfg_set_bar0_win(dhd_bus_t *bus, uint32 data);
+#ifdef CONFIG_ARCH_MSM8994
+static void dhdpcie_bus_cfg_set_bar1_win(dhd_bus_t *bus, uint32 data);
+static ulong dhd_bus_cmn_check_offset(dhd_bus_t *bus, ulong offset);
+#endif
static void dhdpcie_bus_reg_unmap(osl_t *osh, ulong addr, int size);
static int dhdpcie_cc_nvmshadow(dhd_bus_t *bus, struct bcmstrbuf *b);
static void dhdpcie_send_mb_data(dhd_bus_t *bus, uint32 h2d_mb_data);
@@ -130,7 +139,9 @@
IOV_DUMP_RINGUPD_BLOCK,
IOV_DMA_RINGINDICES,
IOV_DB1_FOR_MB,
- IOV_FLOW_PRIO_MAP
+ IOV_FLOW_PRIO_MAP,
+ IOV_RXBOUND,
+ IOV_TXBOUND
};
@@ -164,11 +175,22 @@
{"txp_thresh", IOV_TXP_THRESHOLD, 0, IOVT_UINT32, 0 },
{"buzzz_dump", IOV_BUZZZ_DUMP, 0, IOVT_UINT32, 0 },
{"flow_prio_map", IOV_FLOW_PRIO_MAP, 0, IOVT_UINT32, 0 },
+ {"rxbound", IOV_RXBOUND, 0, IOVT_UINT32, 0 },
+ {"txbound", IOV_TXBOUND, 0, IOVT_UINT32, 0 },
{NULL, 0, 0, 0, 0 }
};
#define MAX_READ_TIMEOUT 5 * 1000 * 1000
+#ifndef DHD_RXBOUND
+#define DHD_RXBOUND 64
+#endif
+#ifndef DHD_TXBOUND
+#define DHD_TXBOUND 64
+#endif
+uint dhd_rxbound = DHD_RXBOUND;
+uint dhd_txbound = DHD_TXBOUND;
+
/* Register/Unregister functions are called by the main DHD entry
* point (e.g. module insertion) to link with the bus driver, in
* order to look for or await the device.
@@ -213,7 +235,7 @@
*
* 'tcm' is the *host* virtual address at which tcm is mapped.
*/
-dhd_bus_t* dhdpcie_bus_attach(osl_t *osh, volatile char* regs, volatile char* tcm)
+dhd_bus_t* dhdpcie_bus_attach(osl_t *osh, volatile char* regs, volatile char* tcm, uint32 tcm_size)
{
dhd_bus_t *bus;
@@ -227,15 +249,19 @@
bzero(bus, sizeof(dhd_bus_t));
bus->regs = regs;
bus->tcm = tcm;
+ bus->tcm_size = tcm_size;
bus->osh = osh;
dll_init(&bus->const_flowring);
/* Attach pcie shared structure */
bus->pcie_sh = MALLOC(osh, sizeof(pciedev_shared_t));
+ if (!bus->pcie_sh) {
+ DHD_ERROR(("%s: MALLOC of bus->pcie_sh failed\n", __FUNCTION__));
+ break;
+ }
/* dhd_common_init(osh); */
-
if (dhdpcie_dongle_attach(bus)) {
DHD_ERROR(("%s: dhdpcie_probe_attach failed\n", __FUNCTION__));
break;
@@ -259,6 +285,12 @@
DHD_TRACE(("%s: EXIT FAILURE\n", __FUNCTION__));
+ if (bus && bus->pcie_sh)
+ MFREE(osh, bus->pcie_sh, sizeof(pciedev_shared_t));
+
+ if (bus)
+ MFREE(osh, bus, sizeof(dhd_bus_t));
+
return NULL;
}
@@ -349,7 +381,7 @@
}
if (bus->dhd->busstate == DHD_BUS_DOWN) {
- DHD_ERROR(("%s : bus is down. we have nothing to do\n",
+ DHD_TRACE(("%s : bus is down. we have nothing to do\n",
__FUNCTION__));
break;
}
@@ -402,12 +434,19 @@
DHD_TRACE(("%s: ENTER\n",
__FUNCTION__));
+
bus->alp_only = TRUE;
bus->sih = NULL;
/* Set bar0 window to si_enum_base */
dhdpcie_bus_cfg_set_bar0_win(bus, SI_ENUM_BASE);
+#ifdef CONFIG_ARCH_MSM8994
+ /* Read bar1 window */
+ bus->bar1_win_base = OSL_PCI_READ_CONFIG(bus->osh, PCI_BAR1_WIN, 4);
+ DHD_ERROR(("%s: PCI_BAR1_WIN = %x\n", __FUNCTION__, bus->bar1_win_base));
+#endif
+
/* si_attach() will provide an SI handle and scan the backplane */
if (!(bus->sih = si_attach((uint)devid, osh, regsva, PCI_BUS, bus,
&bus->vars, &bus->varsz))) {
@@ -422,6 +461,10 @@
/* WAR where the BAR1 window may not be sized properly */
W_REG(osh, &sbpcieregs->configaddr, 0x4e0);
val = R_REG(osh, &sbpcieregs->configdata);
+#ifdef CONFIG_ARCH_MSM8994
+ bus->bar1_win_mask = 0xffffffff - (bus->tcm_size - 1);
+ DHD_ERROR(("%s: BAR1 window val=%d mask=%x\n", __FUNCTION__, val, bus->bar1_win_mask));
+#endif
W_REG(osh, &sbpcieregs->configdata, val);
/* Get info on the ARM and SOCRAM cores... */
@@ -465,7 +508,8 @@
bus->dongle_ram_base = CR4_4360_RAM_BASE;
break;
case BCM4345_CHIP_ID:
- bus->dongle_ram_base = CR4_4345_RAM_BASE;
+ bus->dongle_ram_base = (bus->sih->chiprev < 6) /* changed at 4345C0 */
+ ? CR4_4345_LT_C0_RAM_BASE : CR4_4345_GE_C0_RAM_BASE;
break;
case BCM43602_CHIP_ID:
bus->dongle_ram_base = CR4_43602_RAM_BASE;
@@ -495,6 +539,7 @@
bus->intr = (bool)dhd_intr;
bus->wait_for_d3_ack = 1;
+ bus->suspended = FALSE;
DHD_TRACE(("%s: EXIT: SUCCESS\n",
__FUNCTION__));
return 0;
@@ -523,7 +568,7 @@
void
dhdpcie_bus_intr_enable(dhd_bus_t *bus)
{
- DHD_TRACE(("enable interrupts\n"));
+ DHD_TRACE(("%s: enable interrupts\n", __FUNCTION__));
if (!bus || !bus->sih)
return;
@@ -559,6 +604,24 @@
DHD_TRACE(("%s Exit\n", __FUNCTION__));
}
+void
+dhdpcie_bus_remove_prep(dhd_bus_t *bus)
+{
+ DHD_TRACE(("%s Enter\n", __FUNCTION__));
+
+ dhd_os_sdlock(bus->dhd);
+
+ bus->dhd->busstate = DHD_BUS_DOWN;
+ dhdpcie_bus_intr_disable(bus);
+ // terence 20150406: fix for null pointer handle
+ if (bus->sih)
+ pcie_watchdog_reset(bus->osh, bus->sih, (sbpcieregs_t *)(bus->regs));
+
+ dhd_os_sdunlock(bus->dhd);
+
+ DHD_TRACE(("%s Exit\n", __FUNCTION__));
+}
+
/* Detach and free everything */
void
@@ -576,12 +639,11 @@
if (bus->dhd) {
dongle_isolation = bus->dhd->dongle_isolation;
- dhd_detach(bus->dhd);
-
if (bus->intr) {
dhdpcie_bus_intr_disable(bus);
dhdpcie_free_irq(bus);
}
+ dhd_detach(bus->dhd);
dhdpcie_bus_release_dongle(bus, osh, dongle_isolation, TRUE);
dhd_free(bus->dhd);
bus->dhd = NULL;
@@ -593,7 +655,7 @@
bus->regs = NULL;
}
if (bus->tcm) {
- dhdpcie_bus_reg_unmap(osh, (ulong)bus->tcm, DONGLE_TCM_MAP_SIZE);
+ dhdpcie_bus_reg_unmap(osh, (ulong)bus->tcm, bus->tcm_size);
bus->tcm = NULL;
}
@@ -623,8 +685,6 @@
dhdpcie_bus_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation, bool reset_flag)
{
- DHD_TRACE(("%s Enter\n", __FUNCTION__));
-
DHD_TRACE(("%s: Enter bus->dhd %p bus->dhd->dongle_reset %d \n", __FUNCTION__,
bus->dhd, bus->dhd->dongle_reset));
@@ -643,6 +703,8 @@
OFFSETOF(sbpcieregs_t, u.pcie2.ltr_state), ~0, 0);
}
si_detach(bus->sih);
+ // terence 20150420: fix for sih incorrectly handled in other function
+ bus->sih = NULL;
if (bus->vars && bus->varsz)
MFREE(osh, bus->vars, bus->varsz);
bus->vars = NULL;
@@ -671,6 +733,14 @@
OSL_PCI_WRITE_CONFIG(bus->osh, PCI_BAR0_WIN, 4, data);
}
+#ifdef CONFIG_ARCH_MSM8994
+void
+dhdpcie_bus_cfg_set_bar1_win(dhd_bus_t *bus, uint32 data)
+{
+ OSL_PCI_WRITE_CONFIG(bus->osh, PCI_BAR1_WIN, 4, data);
+}
+#endif
+
void
dhdpcie_bus_dongle_setmemsize(struct dhd_bus *bus, int mem_size)
{
@@ -760,12 +830,13 @@
/* Download firmware image and nvram image */
int
dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh,
- char *pfw_path, char *pnv_path)
+ char *pfw_path, char *pnv_path, char *pconf_path)
{
int ret;
bus->fw_path = pfw_path;
bus->nv_path = pnv_path;
+ bus->dhd->conf_path = pconf_path;
ret = dhdpcie_download_firmware(bus, osh);
@@ -782,6 +853,16 @@
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);
+ dhd_conf_set_nv_name_by_chip(bus->dhd, bus->nv_path);
+
+ printf("Final fw_path=%s\n", bus->fw_path);
+ printf("Final nv_path=%s\n", bus->nv_path);
+ printf("Final conf_path=%s\n", bus->dhd->conf_path);
+
ret = _dhdpcie_download_firmware(bus);
DHD_OS_WAKE_UNLOCK(bus->dhd);
@@ -803,8 +884,10 @@
* entry or in module param.
*/
image = dhd_os_open_image(pfw_path);
- if (image == NULL)
+ if (image == NULL) {
+ printf("%s: Open firmware file failed %s\n", __FUNCTION__, pfw_path);
goto err;
+ }
memptr = memblock = MALLOC(bus->dhd->osh, MEMBLOCK + DHD_SDALIGN);
if (memblock == NULL) {
@@ -872,8 +955,10 @@
if (nvram_file_exists) {
image = dhd_os_open_image(pnv_path);
- if (image == NULL)
+ if (image == NULL) {
+ printf("%s: Open nvram file failed %s\n", __FUNCTION__, pnv_path);
goto err;
+ }
}
memblock = MALLOC(bus->dhd->osh, MAX_NVRAMBUF_SIZE);
@@ -1139,31 +1224,26 @@
/* Wait until control frame is available */
timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->rxlen, &pending);
- if (timeleft == 0) {
- DHD_ERROR(("%s: resumed on timeout\n", __FUNCTION__));
- bus->ioct_resp.cmn_hdr.request_id = 0;
- bus->ioct_resp.compl_hdr.status = 0xffff;
- bus->rxlen = 0;
- }
rxlen = bus->rxlen;
- bcopy(&bus->ioct_resp, msg, sizeof(ioctl_comp_resp_msg_t));
+ bcopy(&bus->ioct_resp, msg, MIN(rxlen, sizeof(ioctl_comp_resp_msg_t)));
bus->rxlen = 0;
if (rxlen) {
DHD_CTL(("%s: resumed on rxctl frame, got %d\n", __FUNCTION__, rxlen));
} else if (timeleft == 0) {
DHD_ERROR(("%s: resumed on timeout\n", __FUNCTION__));
+ bus->ioct_resp.cmn_hdr.request_id = 0;
+ bus->ioct_resp.compl_hdr.status = 0xffff;
+ bus->dhd->rxcnt_timeout++;
+ DHD_ERROR(("%s: rxcnt_timeout=%d\n", __FUNCTION__, bus->dhd->rxcnt_timeout));
} else if (pending == TRUE) {
DHD_CTL(("%s: canceled\n", __FUNCTION__));
return -ERESTARTSYS;
} else {
DHD_CTL(("%s: resumed for unknown reason?\n", __FUNCTION__));
}
- if (timeleft == 0) {
- bus->dhd->rxcnt_timeout++;
- DHD_ERROR(("%s: rxcnt_timeout=%d\n", __FUNCTION__, bus->dhd->rxcnt_timeout));
- }
- else
+
+ if (timeleft != 0)
bus->dhd->rxcnt_timeout = 0;
if (rxlen)
@@ -1448,10 +1528,17 @@
uint dsize;
int detect_endian_flag = 0x01;
bool little_endian;
+#ifdef CONFIG_ARCH_MSM8994
+ bool is_64bit_unaligned;
+#endif
/* Detect endianness. */
little_endian = *(char *)&detect_endian_flag;
+#ifdef CONFIG_ARCH_MSM8994
+ /* Check 64bit aligned or not. */
+ is_64bit_unaligned = (address & 0x7);
+#endif
/* In remap mode, adjust address beyond socram and redirect
* to devram at SOCDEVRAM_BP_ADDR since remap address > orig_ramsize
* is not backplane accessible
@@ -1463,9 +1550,22 @@
/* Do the transfer(s) */
if (write) {
while (size) {
- if (size >= sizeof(uint64) && little_endian)
+ if (size >= sizeof(uint64) && little_endian) {
+#ifdef CONFIG_ARCH_MSM8994
+ if (is_64bit_unaligned) {
+ DHD_INFO(("%s: write unaligned %lx\n",
+ __FUNCTION__, address));
+ dhdpcie_bus_wtcm32(bus, address, *((uint32 *)data));
+ data += 4;
+ size -= 4;
+ address += 4;
+ is_64bit_unaligned = (address & 0x7);
+ continue;
+ }
+ else
+#endif
dhdpcie_bus_wtcm64(bus, address, *((uint64 *)data));
- else {
+ } else {
dsize = sizeof(uint8);
dhdpcie_bus_wtcm8(bus, address, *data);
}
@@ -1478,9 +1578,22 @@
}
} else {
while (size) {
- if (size >= sizeof(uint64) && little_endian)
+ if (size >= sizeof(uint64) && little_endian) {
+#ifdef CONFIG_ARCH_MSM8994
+ if (is_64bit_unaligned) {
+ DHD_INFO(("%s: read unaligned %lx\n",
+ __FUNCTION__, address));
+ *(uint32 *)data = dhdpcie_bus_rtcm32(bus, address);
+ data += 4;
+ size -= 4;
+ address += 4;
+ is_64bit_unaligned = (address & 0x7);
+ continue;
+ }
+ else
+#endif
*(uint64 *)data = dhdpcie_bus_rtcm64(bus, address);
- else {
+ } else {
dsize = sizeof(uint8);
*data = dhdpcie_bus_rtcm8(bus, address);
}
@@ -1518,13 +1631,20 @@
queue = &flow_ring_node->queue; /* queue associated with flow ring */
- DHD_QUEUE_LOCK(queue->lock, flags);
+ DHD_FLOWRING_LOCK(flow_ring_node->lock, flags);
+
+ if (flow_ring_node->status != FLOW_RING_STATUS_OPEN) {
+ DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags);
+ return BCME_NOTREADY;
+ }
while ((txp = dhd_flow_queue_dequeue(bus->dhd, queue)) != NULL) {
PKTORPHAN(txp);
#ifdef DHDTCPACK_SUPPRESS
- dhd_tcpack_check_xmit(bus->dhd, txp);
+ if (bus->dhd->tcpack_sup_mode != TCPACK_SUP_HOLD) {
+ dhd_tcpack_check_xmit(bus->dhd, txp);
+ }
#endif /* DHDTCPACK_SUPPRESS */
/* Attempt to transfer packet over flow ring */
@@ -1534,7 +1654,7 @@
dhd_prot_txdata_write_flush(bus->dhd, flow_id, FALSE);
/* reinsert at head */
dhd_flow_queue_reinsert(bus->dhd, queue, txp);
- DHD_QUEUE_UNLOCK(queue->lock, flags);
+ DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags);
/* If we are able to requeue back, return success */
return BCME_OK;
@@ -1543,12 +1663,13 @@
dhd_prot_txdata_write_flush(bus->dhd, flow_id, FALSE);
- DHD_QUEUE_UNLOCK(queue->lock, flags);
+ DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags);
}
return ret;
}
+#ifndef PCIE_TX_DEFERRAL
/* Send a data frame to the dongle. Callee disposes of txp. */
int BCMFASTPATH
dhd_bus_txdata(struct dhd_bus *bus, void *txp, uint8 ifidx)
@@ -1585,12 +1706,12 @@
queue = &flow_ring_node->queue; /* queue associated with flow ring */
- DHD_QUEUE_LOCK(queue->lock, flags);
+ DHD_FLOWRING_LOCK(flow_ring_node->lock, flags);
if ((ret = dhd_flow_queue_enqueue(bus->dhd, queue, txp)) != BCME_OK)
txp_pend = txp;
- DHD_QUEUE_UNLOCK(queue->lock, flags);
+ DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags);
if (flow_ring_node->status) {
DHD_INFO(("%s: Enq pkt flowid %d, status %d active %d\n",
@@ -1606,15 +1727,15 @@
/* If we have anything pending, try to push into q */
if (txp_pend) {
- DHD_QUEUE_LOCK(queue->lock, flags);
+ DHD_FLOWRING_LOCK(flow_ring_node->lock, flags);
if ((ret = dhd_flow_queue_enqueue(bus->dhd, queue, txp_pend)) != BCME_OK) {
- DHD_QUEUE_UNLOCK(queue->lock, flags);
+ DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags);
txp = txp_pend;
goto toss;
}
- DHD_QUEUE_UNLOCK(queue->lock, flags);
+ DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags);
}
return ret;
@@ -1628,6 +1749,78 @@
PKTCFREE(bus->dhd->osh, txp, TRUE);
return ret;
}
+#else /* PCIE_TX_DEFERRAL */
+int BCMFASTPATH
+dhd_bus_txdata(struct dhd_bus *bus, void *txp, uint8 ifidx)
+{
+ unsigned long flags;
+ int ret = BCME_OK;
+ uint16 flowid;
+ flow_queue_t *queue;
+ flow_ring_node_t *flow_ring_node;
+ uint8 *pktdata = (uint8 *)PKTDATA(bus->dhd->osh, txp);
+ struct ether_header *eh = (struct ether_header *)pktdata;
+
+ if (!bus->dhd->flowid_allocator) {
+ DHD_ERROR(("%s: Flow ring not intited yet \n", __FUNCTION__));
+ goto toss;
+ }
+
+ flowid = dhd_flowid_find(bus->dhd, ifidx,
+ bus->dhd->flow_prio_map[(PKTPRIO(txp))],
+ eh->ether_shost, eh->ether_dhost);
+ if (flowid == FLOWID_INVALID) {
+ DHD_PKTTAG_SET_FLOWID((dhd_pkttag_fr_t *)PKTTAG(txp), ifidx);
+ skb_queue_tail(&bus->orphan_list, txp);
+ queue_work(bus->tx_wq, &bus->create_flow_work);
+ return BCME_OK;
+ }
+
+ DHD_PKTTAG_SET_FLOWID((dhd_pkttag_fr_t *)PKTTAG(txp), flowid);
+ flow_ring_node = DHD_FLOW_RING(bus->dhd, flowid);
+ queue = &flow_ring_node->queue; /* queue associated with flow ring */
+
+ DHD_DATA(("%s: pkt flowid %d, status %d active %d\n",
+ __FUNCTION__, flowid, flow_ring_node->status,
+ flow_ring_node->active));
+
+ DHD_FLOWRING_LOCK(flow_ring_node->lock, flags);
+ if ((flowid >= bus->dhd->num_flow_rings) ||
+ (!flow_ring_node->active) ||
+ (flow_ring_node->status == FLOW_RING_STATUS_DELETE_PENDING)) {
+ DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags);
+ DHD_DATA(("%s: Dropping pkt flowid %d, status %d active %d\n",
+ __FUNCTION__, flowid, flow_ring_node->status,
+ flow_ring_node->active));
+ ret = BCME_ERROR;
+ goto toss;
+ }
+
+ if (flow_ring_node->status == FLOW_RING_STATUS_PENDING) {
+ DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags);
+ DHD_PKTTAG_SET_FLOWID((dhd_pkttag_fr_t *)PKTTAG(txp), ifidx);
+ skb_queue_tail(&bus->orphan_list, txp);
+ queue_work(bus->tx_wq, &bus->create_flow_work);
+ return BCME_OK;
+ }
+
+ if ((ret = dhd_flow_queue_enqueue(bus->dhd, queue, txp)) != BCME_OK) {
+ DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags);
+ goto toss;
+ }
+
+ DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags);
+
+ ret = dhd_bus_schedule_queue(bus, flowid, FALSE);
+
+ return ret;
+
+toss:
+ DHD_DATA(("%s: Toss %d\n", __FUNCTION__, ret));
+ PKTCFREE(bus->dhd->osh, txp, TRUE);
+ return ret;
+}
+#endif /* !PCIE_TX_DEFERRAL */
void
@@ -1702,86 +1895,74 @@
dhd_rx_frame(bus->dhd, ifidx, pkt, pkt_count, 0);
}
+#ifdef CONFIG_ARCH_MSM8994
+static ulong dhd_bus_cmn_check_offset(dhd_bus_t *bus, ulong offset)
+{
+ uint new_bar1_wbase = 0;
+ ulong address = 0;
+
+ new_bar1_wbase = (uint)offset & bus->bar1_win_mask;
+ if (bus->bar1_win_base != new_bar1_wbase) {
+ bus->bar1_win_base = new_bar1_wbase;
+ dhdpcie_bus_cfg_set_bar1_win(bus, bus->bar1_win_base);
+ DHD_ERROR(("%s: offset=%lx, switch bar1_win_base to %x\n",
+ __FUNCTION__, offset, bus->bar1_win_base));
+ }
+
+ address = offset - bus->bar1_win_base;
+
+ return address;
+}
+#else
+#define dhd_bus_cmn_check_offset(x, y) y
+#endif /* CONFIG_ARCH_MSM8994 */
+
/** 'offset' is a backplane address */
void
dhdpcie_bus_wtcm8(dhd_bus_t *bus, ulong offset, uint8 data)
{
-#ifdef EXYNOS5433_PCIE_WAR
- exynos_pcie_set_l1_exit();
-#endif /* EXYNOS5433_PCIE_WAR */
- *(volatile uint8 *)(bus->tcm + offset) = (uint8)data;
-#ifdef EXYNOS5433_PCIE_WAR
- exynos_pcie_clear_l1_exit();
-#endif /* EXYNOS5433_PCIE_WAR */
+ *(volatile uint8 *)(bus->tcm + dhd_bus_cmn_check_offset(bus, offset)) = (uint8)data;
}
uint8
dhdpcie_bus_rtcm8(dhd_bus_t *bus, ulong offset)
{
volatile uint8 data;
-#ifdef EXYNOS5433_PCIE_WAR
- exynos_pcie_set_l1_exit();
-#endif /* EXYNOS5433_PCIE_WAR */
#ifdef BCM47XX_ACP_WAR
- data = R_REG(bus->dhd->osh, (volatile uint8 *)(bus->tcm + offset));
+ data = R_REG(bus->dhd->osh,
+ (volatile uint8 *)(bus->tcm + dhd_bus_cmn_check_offset(bus, offset)));
#else
- data = *(volatile uint8 *)(bus->tcm + offset);
+ data = *(volatile uint8 *)(bus->tcm + dhd_bus_cmn_check_offset(bus, offset));
#endif
-#ifdef EXYNOS5433_PCIE_WAR
- exynos_pcie_clear_l1_exit();
-#endif /* EXYNOS5433_PCIE_WAR */
return data;
}
void
dhdpcie_bus_wtcm32(dhd_bus_t *bus, ulong offset, uint32 data)
{
-#ifdef EXYNOS5433_PCIE_WAR
- exynos_pcie_set_l1_exit();
-#endif /* EXYNOS5433_PCIE_WAR */
- *(volatile uint32 *)(bus->tcm + offset) = (uint32)data;
-#ifdef EXYNOS5433_PCIE_WAR
- exynos_pcie_clear_l1_exit();
-#endif /* EXYNOS5433_PCIE_WAR */
+ *(volatile uint32 *)(bus->tcm + dhd_bus_cmn_check_offset(bus, offset)) = (uint32)data;
}
void
dhdpcie_bus_wtcm16(dhd_bus_t *bus, ulong offset, uint16 data)
{
-#ifdef EXYNOS5433_PCIE_WAR
- exynos_pcie_set_l1_exit();
-#endif /* EXYNOS5433_PCIE_WAR */
- *(volatile uint16 *)(bus->tcm + offset) = (uint16)data;
-#ifdef EXYNOS5433_PCIE_WAR
- exynos_pcie_clear_l1_exit();
-#endif /* EXYNOS5433_PCIE_WAR */
+ *(volatile uint16 *)(bus->tcm + dhd_bus_cmn_check_offset(bus, offset)) = (uint16)data;
}
void
dhdpcie_bus_wtcm64(dhd_bus_t *bus, ulong offset, uint64 data)
{
-#ifdef EXYNOS5433_PCIE_WAR
- exynos_pcie_set_l1_exit();
-#endif /* EXYNOS5433_PCIE_WAR */
- *(volatile uint64 *)(bus->tcm + offset) = (uint64)data;
-#ifdef EXYNOS5433_PCIE_WAR
- exynos_pcie_clear_l1_exit();
-#endif /* EXYNOS5433_PCIE_WAR */
+ *(volatile uint64 *)(bus->tcm + dhd_bus_cmn_check_offset(bus, offset)) = (uint64)data;
}
uint16
dhdpcie_bus_rtcm16(dhd_bus_t *bus, ulong offset)
{
volatile uint16 data;
-#ifdef EXYNOS5433_PCIE_WAR
- exynos_pcie_set_l1_exit();
-#endif /* EXYNOS5433_PCIE_WAR */
#ifdef BCM47XX_ACP_WAR
- data = R_REG(bus->dhd->osh, (volatile uint16 *)(bus->tcm + offset));
+ data = R_REG(bus->dhd->osh,
+ (volatile uint16 *)(bus->tcm + dhd_bus_cmn_check_offset(bus, offset)));
#else
- data = *(volatile uint16 *)(bus->tcm + offset);
+ data = *(volatile uint16 *)(bus->tcm + dhd_bus_cmn_check_offset(bus, offset));
#endif
-#ifdef EXYNOS5433_PCIE_WAR
- exynos_pcie_clear_l1_exit();
-#endif /* EXYNOS5433_PCIE_WAR */
return data;
}
@@ -1789,17 +1970,12 @@
dhdpcie_bus_rtcm32(dhd_bus_t *bus, ulong offset)
{
volatile uint32 data;
-#ifdef EXYNOS5433_PCIE_WAR
- exynos_pcie_set_l1_exit();
-#endif /* EXYNOS5433_PCIE_WAR */
#ifdef BCM47XX_ACP_WAR
- data = R_REG(bus->dhd->osh, (volatile uint32 *)(bus->tcm + offset));
+ data = R_REG(bus->dhd->osh,
+ (volatile uint32 *)(bus->tcm + dhd_bus_cmn_check_offset(bus, offset)));
#else
- data = *(volatile uint32 *)(bus->tcm + offset);
+ data = *(volatile uint32 *)(bus->tcm + dhd_bus_cmn_check_offset(bus, offset));
#endif
-#ifdef EXYNOS5433_PCIE_WAR
- exynos_pcie_clear_l1_exit();
-#endif /* EXYNOS5433_PCIE_WAR */
return data;
}
@@ -1807,17 +1983,12 @@
dhdpcie_bus_rtcm64(dhd_bus_t *bus, ulong offset)
{
volatile uint64 data;
-#ifdef EXYNOS5433_PCIE_WAR
- exynos_pcie_set_l1_exit();
-#endif /* EXYNOS5433_PCIE_WAR */
#ifdef BCM47XX_ACP_WAR
- data = R_REG(bus->dhd->osh, (volatile uint64 *)(bus->tcm + offset));
+ data = R_REG(bus->dhd->osh,
+ (volatile uint64 *)(bus->tcm + dhd_bus_cmn_check_offset(bus, offset)));
#else
- data = *(volatile uint64 *)(bus->tcm + offset);
+ data = *(volatile uint64 *)(bus->tcm + dhd_bus_cmn_check_offset(bus, offset));
#endif
-#ifdef EXYNOS5433_PCIE_WAR
- exynos_pcie_clear_l1_exit();
-#endif /* EXYNOS5433_PCIE_WAR */
return data;
}
@@ -2172,7 +2343,7 @@
break;
}
default:
- printf("Maximum one argument supported\n");
+ printf("%s: Maximum one argument supported\n", __FUNCTION__);
break;
}
bytes += sprintf(p + bytes, "\n");
@@ -2202,10 +2373,10 @@
}
if (total == 0U) {
- printf("buzzz_dump total<%u> done\n", total);
+ printf("%s: buzzz_dump total<%u> done\n", __FUNCTION__, total);
return;
} else {
- printf("buzzz_dump total<%u> : part2<%u> + part1<%u>\n",
+ printf("%s: buzzz_dump total<%u> : part2<%u> + part1<%u>\n", __FUNCTION__,
total, part2, part1);
}
@@ -2227,7 +2398,7 @@
log = (void*)((size_t)log + buzzz_p->log_sz);
}
- printf("buzzz_dump done.\n");
+ printf("%s: buzzz_dump done.\n", __FUNCTION__);
}
int dhd_buzzz_dump_dngl(dhd_bus_t *bus)
@@ -2242,11 +2413,11 @@
return BCME_UNSUPPORTED;
}
if ((page_p = (char *)MALLOC(bus->dhd->osh, 4096)) == NULL) {
- printf("Page memory allocation failure\n");
+ printf("%s: Page memory allocation failure\n", __FUNCTION__);
goto done;
}
if ((buzzz_p = MALLOC(bus->dhd->osh, sizeof(buzzz_t))) == NULL) {
- printf("Buzzz memory allocation failure\n");
+ printf("%s: Buzzz memory allocation failure\n", __FUNCTION__);
goto done;
}
@@ -2264,26 +2435,26 @@
dhdpcie_bus_membytes(bus, FALSE, (ulong)sh->buzzz,
(uint8 *)buzzz_p, sizeof(buzzz_t));
if (buzzz_p->count == 0) {
- printf("Empty dongle BUZZZ trace\n\n");
+ printf("%s: Empty dongle BUZZZ trace\n\n", __FUNCTION__);
goto done;
}
if (buzzz_p->counters != 3) { /* 3 counters for CR4 */
- printf("Counters<%u> mismatch\n", buzzz_p->counters);
+ printf("%s: Counters<%u> mismatch\n", __FUNCTION__, buzzz_p->counters);
goto done;
}
/* Allocate memory for trace buffer and format strings */
buffer_p = MALLOC(bus->dhd->osh, buzzz_p->buffer_sz);
if (buffer_p == NULL) {
- printf("Buffer memory allocation failure\n");
+ printf("%s: Buffer memory allocation failure\n", __FUNCTION__);
goto done;
}
/* Fetch the trace and format strings */
dhdpcie_bus_membytes(bus, FALSE, (uint32)buzzz_p->log, /* Trace */
(uint8 *)buffer_p, buzzz_p->buffer_sz);
/* Process and display the trace using formatted output */
- printf("<#cycle> <#instruction> <#ctr3> <event information>\n");
+ printf("%s: <#cycle> <#instruction> <#ctr3> <event information>\n", __FUNCTION__);
dhd_buzzz_dump(buzzz_p, buffer_p, page_p);
- printf("----- End of dongle BUZZZ Trace -----\n\n");
+ printf("%s: ----- End of dongle BUZZZ Trace -----\n\n", __FUNCTION__);
MFREE(bus->dhd->osh, buffer_p, buzzz_p->buffer_sz); buffer_p = NULL;
}
@@ -2325,7 +2496,7 @@
}
if (i >= pcie_serdes_spinwait) {
- DHD_ERROR(("pcie_mdiosetblock: timed out\n"));
+ DHD_ERROR(("%s: pcie_mdiosetblock: timed out\n", __FUNCTION__));
return FALSE;
}
@@ -2396,12 +2567,20 @@
DHD_ERROR(("%s: == Power OFF ==\n", __FUNCTION__));
bus->dhd->up = FALSE;
if (bus->dhd->busstate != DHD_BUS_DOWN) {
- dhd_prot_clear(dhdp);
+#ifdef BCMPCIE_OOB_HOST_WAKE
+ /* Clean up any pending host wake IRQ */
+ dhd_bus_oob_intr_set(bus->dhd, FALSE);
+ dhd_bus_oob_intr_unregister(bus->dhd);
+#endif /* BCMPCIE_OOB_HOST_WAKE */
dhd_os_wd_timer(dhdp, 0);
dhd_bus_stop(bus, TRUE);
-#ifdef CONFIG_ARCH_MSM
+ if (bus->intr) {
+ dhdpcie_bus_intr_disable(bus);
+ dhdpcie_free_irq(bus);
+ }
+ dhd_prot_clear(dhdp);
+ dhd_clear(dhdp);
dhd_bus_release_dongle(bus);
-#endif /* CONFIG_ARCH_MSM */
dhdpcie_bus_free_resource(bus);
bcmerror = dhdpcie_bus_disable_device(bus);
if (bcmerror) {
@@ -2419,10 +2598,18 @@
#endif /* CONFIG_ARCH_MSM */
bus->dhd->busstate = DHD_BUS_DOWN;
} else {
+ if (bus->intr) {
+ dhdpcie_bus_intr_disable(bus);
+ dhdpcie_free_irq(bus);
+ }
+#ifdef BCMPCIE_OOB_HOST_WAKE
+ /* Clean up any pending host wake IRQ */
+ dhd_bus_oob_intr_set(bus->dhd, FALSE);
+ dhd_bus_oob_intr_unregister(bus->dhd);
+#endif /* BCMPCIE_OOB_HOST_WAKE */
dhd_prot_clear(dhdp);
-#ifdef CONFIG_ARCH_MSM
+ dhd_clear(dhdp);
dhd_bus_release_dongle(bus);
-#endif /* CONFIG_ARCH_MSM */
dhdpcie_bus_free_resource(bus);
bcmerror = dhdpcie_bus_disable_device(bus);
if (bcmerror) {
@@ -2438,7 +2625,7 @@
__FUNCTION__, bcmerror));
goto done;
}
-#endif /* CONFIG_ARCH_MSM */
+#endif /* CONFIG_ARCH_MSM */
}
bus->dhd->dongle_reset = TRUE;
@@ -2449,7 +2636,7 @@
/* Powering On */
DHD_ERROR(("%s: == Power ON ==\n", __FUNCTION__));
#ifdef CONFIG_ARCH_MSM
- while (retry--) {
+ while (--retry) {
bcmerror = dhdpcie_bus_clock_start(bus);
if (!bcmerror) {
DHD_ERROR(("%s: dhdpcie_bus_clock_start OK\n",
@@ -2482,7 +2669,14 @@
bcmerror = dhdpcie_bus_dongle_attach(bus);
if (bcmerror) {
- DHD_ERROR(("%s: dhdpcie_bus_dongle_attach: %d\n",
+ DHD_ERROR(("%s: dhdpcie_bus_dongle_attach failed: %d\n",
+ __FUNCTION__, bcmerror));
+ goto done;
+ }
+
+ bcmerror = dhd_bus_request_irq(bus);
+ if (bcmerror) {
+ DHD_ERROR(("%s: dhd_bus_request_irq failed: %d\n",
__FUNCTION__, bcmerror));
goto done;
}
@@ -2639,7 +2833,7 @@
{
uint val;
if (!PCIE_GEN2(bus->sih)) {
- DHD_ERROR(("supported only in pcie gen2\n"));
+ DHD_ERROR(("%s: supported only in pcie gen2\n", __FUNCTION__));
bcmerror = BCME_ERROR;
break;
}
@@ -2647,19 +2841,19 @@
bcopy(&val, arg, sizeof(int32));
}
else {
- DHD_ERROR(("pcie2_mdioop failed.\n"));
+ DHD_ERROR(("%s: pcie2_mdioop failed.\n", __FUNCTION__));
bcmerror = BCME_ERROR;
}
break;
}
case IOV_SVAL(IOV_PCIESERDESREG):
if (!PCIE_GEN2(bus->sih)) {
- DHD_ERROR(("supported only in pcie gen2\n"));
+ DHD_ERROR(("%s: supported only in pcie gen2\n", __FUNCTION__));
bcmerror = BCME_ERROR;
break;
}
if (pcie2_mdioop(bus, int_val, int_val2, TRUE, &int_val3, FALSE)) {
- DHD_ERROR(("pcie2_mdioop failed.\n"));
+ DHD_ERROR(("%s: pcie2_mdioop failed.\n", __FUNCTION__));
bcmerror = BCME_ERROR;
}
break;
@@ -2860,7 +3054,7 @@
/* Can change it only during initialization/FW download */
if (bus->dhd->busstate == DHD_BUS_DOWN) {
if ((int_val > 3) || (int_val < 0)) {
- DHD_ERROR(("Bad argument. Possible values: 0, 1, 2 & 3\n"));
+ DHD_ERROR(("%s: Bad argument. Possible values: 0, 1, 2 & 3\n", __FUNCTION__));
bcmerror = BCME_BADARG;
} else {
bus->dhd->dma_d2h_ring_upd_support = (int_val & 1) ? TRUE : FALSE;
@@ -2933,6 +3127,24 @@
bcopy(&int_val, arg, val_size);
break;
+ case IOV_GVAL(IOV_TXBOUND):
+ int_val = (int32)dhd_txbound;
+ bcopy(&int_val, arg, val_size);
+ break;
+
+ case IOV_SVAL(IOV_TXBOUND):
+ dhd_txbound = (uint)int_val;
+ break;
+
+ case IOV_GVAL(IOV_RXBOUND):
+ int_val = (int32)dhd_rxbound;
+ bcopy(&int_val, arg, val_size);
+ break;
+
+ case IOV_SVAL(IOV_RXBOUND):
+ dhd_rxbound = (uint)int_val;
+ break;
+
default:
bcmerror = BCME_UNSUPPORTED;
break;
@@ -2947,15 +3159,15 @@
dhdpcie_bus_lpback_req(struct dhd_bus *bus, uint32 len)
{
if (bus->dhd == NULL) {
- DHD_ERROR(("bus not inited\n"));
+ DHD_ERROR(("%s: bus not inited\n", __FUNCTION__));
return 0;
}
if (bus->dhd->prot == NULL) {
- DHD_ERROR(("prot is not inited\n"));
+ DHD_ERROR(("%s: prot is not inited\n", __FUNCTION__));
return 0;
}
if (bus->dhd->busstate != DHD_BUS_DATA) {
- DHD_ERROR(("not in a readystate to LPBK is not inited\n"));
+ DHD_ERROR(("%s: not in a readystate to LPBK is not inited\n", __FUNCTION__));
return 0;
}
dhdmsgbuf_lpbk_req(bus->dhd, len);
@@ -2972,7 +3184,7 @@
}
int
-dhdpcie_bus_suspend(struct dhd_bus *bus, bool state)
+dhdpcie_bus_suspend(struct dhd_bus *bus, bool state)
{
int timeleft;
@@ -2980,54 +3192,77 @@
int rc = 0;
if (bus->dhd == NULL) {
- DHD_ERROR(("bus not inited\n"));
+ DHD_ERROR(("%s: bus not inited\n", __FUNCTION__));
return BCME_ERROR;
}
if (bus->dhd->prot == NULL) {
- DHD_ERROR(("prot is not inited\n"));
+ DHD_ERROR(("%s: prot is not inited\n", __FUNCTION__));
return BCME_ERROR;
}
if (bus->dhd->busstate != DHD_BUS_DATA && bus->dhd->busstate != DHD_BUS_SUSPEND) {
- DHD_ERROR(("not in a readystate to LPBK is not inited\n"));
+ DHD_ERROR(("%s: not in a readystate to LPBK is not inited\n", __FUNCTION__));
return BCME_ERROR;
}
if (bus->dhd->dongle_reset)
return -EIO;
- if (state == (bus->dhd->busstate == DHD_BUS_SUSPEND)) /* Set to same state */
+ if (bus->suspended == state) /* Set to same state */
return BCME_OK;
if (state) {
-#ifdef EXYNOS5433_PCIE_WAR
- exynos_pcie_set_l1_exit();
-#endif /* EXYNOS5433_PCIE_WAR */
bus->wait_for_d3_ack = 0;
+ bus->suspended = TRUE;
+ bus->dhd->busstate = DHD_BUS_SUSPEND;
DHD_OS_WAKE_LOCK_WAIVE(bus->dhd);
+ dhd_os_set_ioctl_resp_timeout(DEFAULT_IOCTL_RESP_TIMEOUT);
dhdpcie_send_mb_data(bus, H2D_HOST_D3_INFORM);
timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->wait_for_d3_ack, &pending);
+ dhd_os_set_ioctl_resp_timeout(IOCTL_RESP_TIMEOUT);
DHD_OS_WAKE_LOCK_RESTORE(bus->dhd);
if (bus->wait_for_d3_ack) {
/* Got D3 Ack. Suspend the bus */
- rc = dhdpcie_pci_suspend_resume(bus->dev, state);
- bus->dhd->busstate = DHD_BUS_SUSPEND;
+ if (dhd_os_check_wakelock_all(bus->dhd)) {
+ DHD_ERROR(("%s: Suspend failed because of wakelock\n", __FUNCTION__));
+ bus->dev->current_state = PCI_D3hot;
+ pci_set_master(bus->dev);
+ rc = pci_set_power_state(bus->dev, PCI_D0);
+ if (rc) {
+ DHD_ERROR(("%s: pci_set_power_state failed:"
+ " current_state[%d], ret[%d]\n",
+ __FUNCTION__, bus->dev->current_state, rc));
+ }
+ bus->suspended = FALSE;
+ bus->dhd->busstate = DHD_BUS_DATA;
+ rc = BCME_ERROR;
+ } else {
+ dhdpcie_bus_intr_disable(bus);
+ rc = dhdpcie_pci_suspend_resume(bus, state);
+ }
} else if (timeleft == 0) {
DHD_ERROR(("%s: resumed on timeout\n", __FUNCTION__));
-#ifdef EXYNOS5433_PCIE_WAR
- exynos_pcie_clear_l1_exit();
-#endif /* EXYNOS5433_PCIE_WAR */
- return -ETIMEDOUT;
+ bus->dev->current_state = PCI_D3hot;
+ pci_set_master(bus->dev);
+ rc = pci_set_power_state(bus->dev, PCI_D0);
+ if (rc) {
+ DHD_ERROR(("%s: pci_set_power_state failed:"
+ " current_state[%d], ret[%d]\n",
+ __FUNCTION__, bus->dev->current_state, rc));
+ }
+ bus->suspended = FALSE;
+ bus->dhd->busstate = DHD_BUS_DATA;
+ rc = -ETIMEDOUT;
}
bus->wait_for_d3_ack = 1;
- }
- else {
+ } else {
/* Resume */
- rc = dhdpcie_pci_suspend_resume(bus->dev, state);
+#ifdef BCMPCIE_OOB_HOST_WAKE
+ DHD_OS_OOB_IRQ_WAKE_UNLOCK(bus->dhd);
+#endif /* BCMPCIE_OOB_HOST_WAKE */
+ rc = dhdpcie_pci_suspend_resume(bus, state);
+ bus->suspended = FALSE;
bus->dhd->busstate = DHD_BUS_DATA;
-
+ dhdpcie_bus_intr_enable(bus);
}
-#ifdef EXYNOS5433_PCIE_WAR
- exynos_pcie_clear_l1_exit();
-#endif /* EXYNOS5433_PCIE_WAR */
return rc;
}
@@ -3036,20 +3271,20 @@
dhdpcie_bus_dmaxfer_req(struct dhd_bus *bus, uint32 len, uint32 srcdelay, uint32 destdelay)
{
if (bus->dhd == NULL) {
- DHD_ERROR(("bus not inited\n"));
+ DHD_ERROR(("%s: bus not inited\n", __FUNCTION__));
return BCME_ERROR;
}
if (bus->dhd->prot == NULL) {
- DHD_ERROR(("prot is not inited\n"));
+ DHD_ERROR(("%s: prot is not inited\n", __FUNCTION__));
return BCME_ERROR;
}
if (bus->dhd->busstate != DHD_BUS_DATA) {
- DHD_ERROR(("not in a readystate to LPBK is not inited\n"));
+ DHD_ERROR(("%s: not in a readystate to LPBK is not inited\n", __FUNCTION__));
return BCME_ERROR;
}
if (len < 5 || len > 4194296) {
- DHD_ERROR(("len is too small or too large\n"));
+ DHD_ERROR(("%s: len is too small or too large\n", __FUNCTION__));
return BCME_ERROR;
}
return dhdmsgbuf_dmaxfer_req(bus->dhd, len, srcdelay, destdelay);
@@ -3236,7 +3471,7 @@
/* Implement read back and verify later */
#ifdef DHD_DEBUG
/* Verify NVRAM bytes */
- DHD_INFO(("Compare NVRAM dl & ul; varsize=%d\n", varsize));
+ DHD_INFO(("%s: Compare NVRAM dl & ul; varsize=%d\n", __FUNCTION__, varsize));
nvram_ularray = (uint8*)MALLOC(bus->dhd->osh, varsize);
if (!nvram_ularray)
return BCME_NOMEM;
@@ -3269,9 +3504,9 @@
phys_size += bus->dongle_ram_base;
/* adjust to the user specified RAM */
- DHD_INFO(("Physical memory size: %d, usable memory size: %d\n",
+ DHD_INFO(("%s: Physical memory size: %d, usable memory size: %d\n", __FUNCTION__,
phys_size, bus->ramsize));
- DHD_INFO(("Vars are at %d, orig varsize is %d\n",
+ DHD_INFO(("%s: Vars are at %d, orig varsize is %d\n", __FUNCTION__,
varaddr, varsize));
varsize = ((phys_size - 4) - varaddr);
@@ -3289,7 +3524,7 @@
varsizew = htol32(varsizew);
}
- DHD_INFO(("New varsize is %d, length token=0x%08x\n", varsize, varsizew));
+ DHD_INFO(("%s: New varsize is %d, length token=0x%08x\n", __FUNCTION__, varsize, varsizew));
/* Write the length token to the last word */
bcmerror = dhdpcie_bus_membytes(bus, TRUE, (phys_size - 4),
@@ -3332,6 +3567,77 @@
return bcmerror;
}
+#ifndef BCMPCIE_OOB_HOST_WAKE
+/* loop through the capability list and see if the pcie capabilty exists */
+uint8
+dhdpcie_find_pci_capability(osl_t *osh, uint8 req_cap_id)
+{
+ uint8 cap_id;
+ uint8 cap_ptr = 0;
+ uint8 byte_val;
+
+ /* check for Header type 0 */
+ byte_val = read_pci_cfg_byte(PCI_CFG_HDR);
+ if ((byte_val & 0x7f) != PCI_HEADER_NORMAL) {
+ DHD_ERROR(("%s : PCI config header not normal.\n", __FUNCTION__));
+ goto end;
+ }
+
+ /* check if the capability pointer field exists */
+ byte_val = read_pci_cfg_byte(PCI_CFG_STAT);
+ if (!(byte_val & PCI_CAPPTR_PRESENT)) {
+ DHD_ERROR(("%s : PCI CAP pointer not present.\n", __FUNCTION__));
+ goto end;
+ }
+
+ cap_ptr = read_pci_cfg_byte(PCI_CFG_CAPPTR);
+ /* check if the capability pointer is 0x00 */
+ if (cap_ptr == 0x00) {
+ DHD_ERROR(("%s : PCI CAP pointer is 0x00.\n", __FUNCTION__));
+ goto end;
+ }
+
+ /* loop thr'u the capability list and see if the pcie capabilty exists */
+
+ cap_id = read_pci_cfg_byte(cap_ptr);
+
+ while (cap_id != req_cap_id) {
+ cap_ptr = read_pci_cfg_byte((cap_ptr + 1));
+ if (cap_ptr == 0x00) break;
+ cap_id = read_pci_cfg_byte(cap_ptr);
+ }
+
+end:
+ return cap_ptr;
+}
+
+void
+dhdpcie_pme_active(osl_t *osh, bool enable)
+{
+ uint8 cap_ptr;
+ uint32 pme_csr;
+
+ cap_ptr = dhdpcie_find_pci_capability(osh, PCI_CAP_POWERMGMTCAP_ID);
+
+ if (!cap_ptr) {
+ DHD_ERROR(("%s : Power Management Capability not present\n", __FUNCTION__));
+ return;
+ }
+
+ pme_csr = OSL_PCI_READ_CONFIG(osh, cap_ptr + PME_CSR_OFFSET, sizeof(uint32));
+ DHD_ERROR(("%s : pme_sts_ctrl 0x%x\n", __FUNCTION__, pme_csr));
+
+ pme_csr |= PME_CSR_PME_STAT;
+ if (enable) {
+ pme_csr |= PME_CSR_PME_EN;
+ } else {
+ pme_csr &= ~PME_CSR_PME_EN;
+ }
+
+ OSL_PCI_WRITE_CONFIG(osh, cap_ptr + PME_CSR_OFFSET, sizeof(uint32), pme_csr);
+}
+#endif /* BCMPCIE_OOB_HOST_WAKE */
+
/* Add bus dump output to a buffer */
void dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf)
{
@@ -3362,7 +3668,6 @@
next = dll_next_p(item);
flow_ring_node = dhd_constlist_to_flowring(item);
- ASSERT(flow_ring_node->active);
dhd_prot_update_txflowring(dhd, flow_ring_node->flowid, flow_ring_node->prot_info);
}
}
@@ -3374,16 +3679,16 @@
{
if ((bus->sih->buscorerev == 2) || (bus->sih->buscorerev == 6) ||
(bus->sih->buscorerev == 4)) {
- DHD_ERROR(("mailbox communication not supported\n"));
+ DHD_ERROR(("%s: mailbox communication not supported\n", __FUNCTION__));
return;
}
if (bus->db1_for_mb) {
/* this is a pcie core register, not the config regsiter */
- DHD_INFO(("writing a mail box interrupt to the device, through doorbell 1\n"));
+ DHD_INFO(("%s: writing a mail box interrupt to the device, through doorbell 1\n", __FUNCTION__));
si_corereg(bus->sih, bus->sih->buscoreidx, PCIH2D_DB1, ~0, 0x12345678);
}
else {
- DHD_INFO(("writing a mail box interrupt to the device, through config space\n"));
+ DHD_INFO(("%s: writing a mail box interrupt to the device, through config space\n", __FUNCTION__));
dhdpcie_bus_cfg_write_dword(bus, PCISBMbx, 4, (1 << 0));
dhdpcie_bus_cfg_write_dword(bus, PCISBMbx, 4, (1 << 0));
}
@@ -3398,7 +3703,7 @@
si_corereg(bus->sih, bus->sih->buscoreidx, PCIMailBoxInt, PCIE_INTB, PCIE_INTB);
} else {
/* this is a pcie core register, not the config regsiter */
- DHD_INFO(("writing a door bell to the device\n"));
+ DHD_INFO(("%s: writing a door bell to the device\n", __FUNCTION__));
si_corereg(bus->sih, bus->sih->buscoreidx, PCIH2D_MailBox, ~0, 0x12345678);
}
}
@@ -3454,13 +3759,6 @@
return 0;
}
- if (bus->dhd->busstate == DHD_BUS_SUSPEND) {
- resched = TRUE;
- DHD_ERROR(("%s : pcie is still in suspend state!!!\n", __FUNCTION__));
- OSL_DELAY(20 * 1000); /* 20ms */
- return resched;
- }
-
intstatus = bus->intstatus;
if ((bus->sih->buscorerev == 6) || (bus->sih->buscorerev == 4) ||
@@ -3471,20 +3769,25 @@
intstatus |= newstatus;
bus->intstatus = 0;
if (intstatus & I_MB) {
- dhdpcie_bus_process_mailbox_intr(bus, intstatus);
+ resched = dhdpcie_bus_process_mailbox_intr(bus, intstatus);
}
} else {
/* this is a PCIE core register..not a config register... */
newstatus = si_corereg(bus->sih, bus->sih->buscoreidx, PCIMailBoxInt, 0, 0);
intstatus |= (newstatus & bus->def_intmask);
- si_corereg(bus->sih, bus->sih->buscoreidx, PCIMailBoxInt, intstatus, intstatus);
+ si_corereg(bus->sih, bus->sih->buscoreidx, PCIMailBoxInt, newstatus, newstatus);
if (intstatus & bus->def_intmask) {
- dhdpcie_bus_process_mailbox_intr(bus, intstatus);
+ resched = dhdpcie_bus_process_mailbox_intr(bus, intstatus);
intstatus &= ~bus->def_intmask;
}
}
- dhdpcie_bus_intr_enable(bus);
+ if (!resched) {
+ // terence 20150420: no need to enable interrupt if busstate is down
+ if (bus->dhd->busstate) {
+ dhdpcie_bus_intr_enable(bus);
+ }
+ }
return resched;
}
@@ -3499,13 +3802,13 @@
if (cur_h2d_mb_data != 0) {
uint32 i = 0;
- DHD_INFO(("GRRRRRRR: MB transaction is already pending 0x%04x\n", cur_h2d_mb_data));
+ DHD_INFO(("%s: GRRRRRRR: MB transaction is already pending 0x%04x\n", __FUNCTION__, cur_h2d_mb_data));
while ((i++ < 100) && cur_h2d_mb_data) {
OSL_DELAY(10);
dhd_bus_cmn_readshared(bus, &cur_h2d_mb_data, HTOD_MB_DATA, 0);
}
if (i >= 100)
- DHD_ERROR(("waited 1ms for the dngl to ack the previous mb transaction\n"));
+ DHD_ERROR(("%s: waited 1ms for the dngl to ack the previous mb transaction\n", __FUNCTION__));
}
dhd_bus_cmn_writeshared(bus, &h2d_mb_data, sizeof(uint32), HTOD_MB_DATA, 0);
@@ -3526,16 +3829,16 @@
dhd_bus_cmn_writeshared(bus, &zero, sizeof(uint32), DTOH_MB_DATA, 0);
- DHD_INFO(("D2H_MB_DATA: 0x%04x\n", d2h_mb_data));
+ DHD_INFO(("%s: D2H_MB_DATA: 0x%04x\n", __FUNCTION__, d2h_mb_data));
if (d2h_mb_data & D2H_DEV_DS_ENTER_REQ) {
/* what should we do */
- DHD_INFO(("D2H_MB_DATA: DEEP SLEEP REQ\n"));
+ DHD_INFO(("%s: D2H_MB_DATA: DEEP SLEEP REQ\n", __FUNCTION__));
dhdpcie_send_mb_data(bus, H2D_HOST_DS_ACK);
- DHD_INFO(("D2H_MB_DATA: sent DEEP SLEEP ACK\n"));
+ DHD_INFO(("%s: D2H_MB_DATA: sent DEEP SLEEP ACK\n", __FUNCTION__));
}
if (d2h_mb_data & D2H_DEV_DS_EXIT_NOTE) {
/* what should we do */
- DHD_INFO(("D2H_MB_DATA: DEEP SLEEP EXIT\n"));
+ DHD_INFO(("%s: D2H_MB_DATA: DEEP SLEEP EXIT\n", __FUNCTION__));
}
if (d2h_mb_data & D2H_DEV_D3_ACK) {
/* what should we do */
@@ -3546,7 +3849,7 @@
}
}
if (d2h_mb_data & D2H_DEV_FWHALT) {
- DHD_INFO(("FW trap has happened\n"));
+ DHD_INFO(("%s: FW trap has happened\n", __FUNCTION__));
#ifdef DHD_DEBUG
dhdpcie_checkdied(bus, NULL, 0);
#endif
@@ -3554,15 +3857,16 @@
}
}
-static void
+static bool
dhdpcie_bus_process_mailbox_intr(dhd_bus_t *bus, uint32 intstatus)
{
+ bool resched = FALSE;
if ((bus->sih->buscorerev == 2) || (bus->sih->buscorerev == 6) ||
(bus->sih->buscorerev == 4)) {
/* Msg stream interrupt */
if (intstatus & I_BIT1) {
- dhdpci_bus_read_frames(bus);
+ resched = dhdpci_bus_read_frames(bus);
} else if (intstatus & I_BIT0) {
/* do nothing for Now */
}
@@ -3570,29 +3874,47 @@
else {
if (intstatus & (PCIE_MB_TOPCIE_FN0_0 | PCIE_MB_TOPCIE_FN0_1))
dhdpcie_handle_mb_data(bus);
+
+ if (bus->dhd->busstate == DHD_BUS_SUSPEND) {
+ goto exit;
+ }
+
if (intstatus & PCIE_MB_D2H_MB_MASK) {
- dhdpci_bus_read_frames(bus);
+ resched = dhdpci_bus_read_frames(bus);
}
}
+exit:
+ return resched;
}
/* Decode dongle to host message stream */
-static void
+static bool
dhdpci_bus_read_frames(dhd_bus_t *bus)
{
+ bool more = FALSE;
+
/* There may be frames in both ctrl buf and data buf; check ctrl buf first */
DHD_PERIM_LOCK(bus->dhd); /* Take the perimeter lock */
-
dhd_prot_process_ctrlbuf(bus->dhd);
+ /* Unlock to give chance for resp to be handled */
+ DHD_PERIM_UNLOCK(bus->dhd); /* Release the perimeter lock */
+ DHD_PERIM_LOCK(bus->dhd); /* Take the perimeter lock */
/* update the flow ring cpls */
dhd_update_txflowrings(bus->dhd);
- dhd_prot_process_msgbuf_txcpl(bus->dhd);
-
- dhd_prot_process_msgbuf_rxcpl(bus->dhd);
+ /* With heavy TX traffic, we could get a lot of TxStatus
+ * so add bound
+ */
+ more |= dhd_prot_process_msgbuf_txcpl(bus->dhd, dhd_txbound);
+ /* With heavy RX traffic, this routine potentially could spend some time
+ * processing RX frames without RX bound
+ */
+ more |= dhd_prot_process_msgbuf_rxcpl(bus->dhd, dhd_rxbound);
DHD_PERIM_UNLOCK(bus->dhd); /* Release the perimeter lock */
+
+ return more;
}
static int
@@ -3617,19 +3939,19 @@
(addr > shaddr)) {
DHD_ERROR(("%s: address (0x%08x) of pciedev_shared invalid\n",
__FUNCTION__, addr));
- DHD_ERROR(("Waited %u usec, dongle is not ready\n", tmo.elapsed));
+ DHD_ERROR(("%s: Waited %u usec, dongle is not ready\n", __FUNCTION__, tmo.elapsed));
return BCME_ERROR;
} else {
bus->shared_addr = (ulong)addr;
- DHD_ERROR(("PCIe shared addr read took %u usec "
- "before dongle is ready\n", tmo.elapsed));
+ DHD_ERROR(("%s: PCIe shared addr read took %u usec "
+ "before dongle is ready\n", __FUNCTION__, tmo.elapsed));
}
/* Read hndrte_shared structure */
if ((rv = dhdpcie_bus_membytes(bus, FALSE, addr, (uint8 *)sh,
sizeof(pciedev_shared_t))) < 0) {
- DHD_ERROR(("Failed to read PCIe shared struct,"
- "size read %d < %d\n", rv, (int)sizeof(pciedev_shared_t)));
+ DHD_ERROR(("%s: Failed to read PCIe shared struct,"
+ "size read %d < %d\n", __FUNCTION__, rv, (int)sizeof(pciedev_shared_t)));
return rv;
}
@@ -3653,7 +3975,7 @@
bus->dma_rxoffset = bus->pcie_sh->dma_rxoffset;
dhd_prot_rx_dataoffset(bus->dhd, bus->dma_rxoffset);
- DHD_ERROR(("DMA RX offset from shared Area %d\n", bus->dma_rxoffset));
+ DHD_ERROR(("%s: DMA RX offset from shared Area %d\n", __FUNCTION__, bus->dma_rxoffset));
if ((sh->flags & PCIE_SHARED_VERSION_MASK) > PCIE_SHARED_VERSION) {
DHD_ERROR(("%s: pcie_shared version %d in dhd "
@@ -3672,7 +3994,7 @@
} else
bus->txmode_push = FALSE;
}
- DHD_ERROR(("bus->txmode_push is set to %d\n", bus->txmode_push));
+ DHD_ERROR(("%s: bus->txmode_push is set to %d\n", __FUNCTION__, bus->txmode_push));
/* Does the FW support DMA'ing r/w indices */
if (sh->flags & PCIE_SHARED_DMA_INDEX) {
@@ -3750,14 +4072,18 @@
dhd_fillup_ring_sharedptr_info(bus, &ring_info);
bcm_print_bytes("ring_info_raw", (uchar *)&ring_info, sizeof(ring_info_t));
- DHD_INFO(("ring_info\n"));
+ DHD_INFO(("%s: ring_info\n", __FUNCTION__));
- DHD_ERROR(("max H2D queues %d\n", ltoh16(ring_info.max_sub_queues)));
+ DHD_ERROR(("%s: max H2D queues %d\n", __FUNCTION__, ltoh16(ring_info.max_sub_queues)));
- DHD_INFO(("mail box address\n"));
- DHD_INFO(("h2d_mb_data_ptr_addr 0x%04x\n", bus->h2d_mb_data_ptr_addr));
- DHD_INFO(("d2h_mb_data_ptr_addr 0x%04x\n", bus->d2h_mb_data_ptr_addr));
+ DHD_INFO(("%s: mail box address\n", __FUNCTION__));
+ DHD_INFO(("%s: h2d_mb_data_ptr_addr 0x%04x\n", __FUNCTION__, bus->h2d_mb_data_ptr_addr));
+ DHD_INFO(("%s: d2h_mb_data_ptr_addr 0x%04x\n", __FUNCTION__, bus->d2h_mb_data_ptr_addr));
}
+
+ bus->dhd->d2h_sync_mode = sh->flags & PCIE_SHARED_D2H_SYNC_MODE_MASK;
+ DHD_INFO(("%s: d2h_sync_mode 0x%08x\n", __FUNCTION__, bus->dhd->d2h_sync_mode));
+
return BCME_OK;
}
/* Read ring mem and ring state ptr info from shared are in TCM */
@@ -3788,14 +4114,14 @@
bus->ring_sh[i].ring_mem_addr = tcm_memloc;
/* Update mem block */
tcm_memloc = tcm_memloc + sizeof(ring_mem_t);
- DHD_INFO(("ring id %d ring mem addr 0x%04x \n",
+ DHD_INFO(("%s: ring id %d ring mem addr 0x%04x \n", __FUNCTION__,
i, bus->ring_sh[i].ring_mem_addr));
}
/* Tx flow Ring */
if (bus->txmode_push) {
bus->ring_sh[i].ring_mem_addr = tcm_memloc;
- DHD_INFO(("TX ring ring id %d ring mem addr 0x%04x \n",
+ DHD_INFO(("%s: TX ring ring id %d ring mem addr 0x%04x \n", __FUNCTION__,
i, bus->ring_sh[i].ring_mem_addr));
}
}
@@ -3815,7 +4141,7 @@
h2d_w_idx_ptr = h2d_w_idx_ptr + sizeof(uint32);
h2d_r_idx_ptr = h2d_r_idx_ptr + sizeof(uint32);
- DHD_INFO(("h2d w/r : idx %d write %x read %x \n", i,
+ DHD_INFO(("%s: h2d w/r : idx %d write %x read %x \n", __FUNCTION__, i,
bus->ring_sh[i].ring_state_w, bus->ring_sh[i].ring_state_r));
}
/* Store d2h common ring write/read pointers */
@@ -3827,7 +4153,7 @@
d2h_w_idx_ptr = d2h_w_idx_ptr + sizeof(uint32);
d2h_r_idx_ptr = d2h_r_idx_ptr + sizeof(uint32);
- DHD_INFO(("d2h w/r : idx %d write %x read %x \n", i,
+ DHD_INFO(("%s: d2h w/r : idx %d write %x read %x \n", __FUNCTION__, i,
bus->ring_sh[i].ring_state_w, bus->ring_sh[i].ring_state_r));
}
@@ -3836,7 +4162,7 @@
bus->ring_sh[i].ring_state_w = h2d_w_idx_ptr;
bus->ring_sh[i].ring_state_r = h2d_r_idx_ptr;
- DHD_INFO(("txflow : idx %d write %x read %x \n", i,
+ DHD_INFO(("%s: txflow : idx %d write %x read %x \n", __FUNCTION__, i,
bus->ring_sh[i].ring_state_w, bus->ring_sh[i].ring_state_r));
} else {
for (j = 0; j < (bus->max_sub_queues - BCMPCIE_H2D_COMMON_MSGRINGS);
@@ -3849,13 +4175,15 @@
h2d_w_idx_ptr = h2d_w_idx_ptr + sizeof(uint32);
h2d_r_idx_ptr = h2d_r_idx_ptr + sizeof(uint32);
- DHD_INFO(("FLOW Rings h2d w/r : idx %d write %x read %x \n", i,
+ DHD_INFO(("%s: FLOW Rings h2d w/r : idx %d write %x read %x \n",
+ __FUNCTION__, i,
bus->ring_sh[i].ring_state_w,
bus->ring_sh[i].ring_state_r));
}
}
}
}
+
/* Initialize bus module: prepare for communication w/dongle */
int dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex)
{
@@ -4106,43 +4434,42 @@
return bus->txmode_push;
}
-void dhd_bus_clean_flow_ring(dhd_bus_t *bus, uint16 flowid)
+void dhd_bus_clean_flow_ring(dhd_bus_t *bus, void *node)
{
void *pkt;
flow_queue_t *queue;
- flow_ring_node_t *flow_ring_node;
+ flow_ring_node_t *flow_ring_node = (flow_ring_node_t *)node;
unsigned long flags;
- flow_ring_node = DHD_FLOW_RING(bus->dhd, flowid);
- ASSERT(flow_ring_node->flowid == flowid);
-
queue = &flow_ring_node->queue;
- /* Call Flow ring clean up */
- dhd_prot_clean_flow_ring(bus->dhd, flow_ring_node->prot_info);
- dhd_flowid_free(bus->dhd, flow_ring_node->flow_info.ifindex,
- flow_ring_node->flowid);
-
- /* clean up BUS level info */
- DHD_QUEUE_LOCK(queue->lock, flags);
-
#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 */
+
+ /* clean up BUS level info */
+ DHD_FLOWRING_LOCK(flow_ring_node->lock, flags);
+
/* Flush all pending packets in the queue, if any */
while ((pkt = dhd_flow_queue_dequeue(bus->dhd, queue)) != NULL) {
PKTFREE(bus->dhd->osh, pkt, TRUE);
}
ASSERT(flow_queue_empty(queue));
- DHD_QUEUE_UNLOCK(queue->lock, flags);
-
+ flow_ring_node->status = FLOW_RING_STATUS_CLOSED;
flow_ring_node->active = FALSE;
-
dll_delete(&flow_ring_node->list);
+
+ DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags);
+
+ /* Call Flow ring clean up */
+ dhd_prot_clean_flow_ring(bus->dhd, flow_ring_node->prot_info);
+ dhd_flowid_free(bus->dhd, flow_ring_node->flow_info.ifindex,
+ flow_ring_node->flowid);
+
}
/*
@@ -4158,11 +4485,8 @@
DHD_INFO(("%s :Flow create\n", __FUNCTION__));
/* Send Msg to device about flow ring creation */
- dhd_prot_flow_ring_create(bus->dhd, flow_ring_node);
-
- flow_ring_node->status = FLOW_RING_STATUS_PENDING;
-
- dll_prepend(&bus->const_flowring, &flow_ring_node->list);
+ if (dhd_prot_flow_ring_create(bus->dhd, flow_ring_node) != BCME_OK)
+ return BCME_NOMEM;
return BCME_OK;
}
@@ -4171,6 +4495,7 @@
dhd_bus_flow_ring_create_response(dhd_bus_t *bus, uint16 flowid, int32 status)
{
flow_ring_node_t *flow_ring_node;
+ unsigned long flags;
DHD_INFO(("%s :Flow Response %d \n", __FUNCTION__, flowid));
@@ -4181,11 +4506,13 @@
DHD_ERROR(("%s Flow create Response failure error status = %d \n",
__FUNCTION__, status));
/* Call Flow clean up */
- dhd_bus_clean_flow_ring(bus, flowid);
+ dhd_bus_clean_flow_ring(bus, flow_ring_node);
return;
}
+ DHD_FLOWRING_LOCK(flow_ring_node->lock, flags);
flow_ring_node->status = FLOW_RING_STATUS_OPEN;
+ DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags);
dhd_bus_schedule_queue(bus, flowid, FALSE);
@@ -4204,15 +4531,16 @@
flow_ring_node = (flow_ring_node_t *)arg;
+ DHD_FLOWRING_LOCK(flow_ring_node->lock, flags);
if (flow_ring_node->status & FLOW_RING_STATUS_DELETE_PENDING) {
+ DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags);
DHD_ERROR(("%s :Delete Pending\n", __FUNCTION__));
return BCME_ERROR;
}
+ flow_ring_node->status = FLOW_RING_STATUS_DELETE_PENDING;
queue = &flow_ring_node->queue; /* queue associated with flow ring */
- DHD_QUEUE_LOCK(queue->lock, flags);
-
#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.
@@ -4225,12 +4553,11 @@
}
ASSERT(flow_queue_empty(queue));
- DHD_QUEUE_UNLOCK(queue->lock, flags);
+ DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags);
/* Send Msg to device about flow ring deletion */
dhd_prot_flow_ring_delete(bus->dhd, flow_ring_node);
- flow_ring_node->status = FLOW_RING_STATUS_DELETE_PENDING;
return BCME_OK;
}
@@ -4250,10 +4577,8 @@
return;
}
/* Call Flow clean up */
- dhd_bus_clean_flow_ring(bus, flowid);
+ dhd_bus_clean_flow_ring(bus, flow_ring_node);
- flow_ring_node->status = FLOW_RING_STATUS_OPEN;
- flow_ring_node->active = FALSE;
return;
}
@@ -4270,7 +4595,7 @@
flow_ring_node = (flow_ring_node_t *)arg;
queue = &flow_ring_node->queue; /* queue associated with flow ring */
- DHD_QUEUE_LOCK(queue->lock, flags);
+ DHD_FLOWRING_LOCK(flow_ring_node->lock, flags);
#ifdef DHDTCPACK_SUPPRESS
/* Clean tcp_ack_info_tbl in order to prevent access to flushed pkt,
@@ -4284,7 +4609,7 @@
}
ASSERT(flow_queue_empty(queue));
- DHD_QUEUE_UNLOCK(queue->lock, flags);
+ DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags);
/* Send Msg to device about flow ring flush */
dhd_prot_flow_ring_flush(bus->dhd, flow_ring_node);
@@ -4357,6 +4682,12 @@
dhdpcie_free_resource(bus);
}
+int
+dhd_bus_request_irq(struct dhd_bus *bus)
+{
+ return dhdpcie_bus_request_irq(bus);
+}
+
bool
dhdpcie_bus_dongle_attach(struct dhd_bus *bus)
{
@@ -4383,3 +4714,20 @@
return 0;
}
+
+#ifdef BCMPCIE_OOB_HOST_WAKE
+int dhd_bus_oob_intr_register(dhd_pub_t *dhdp)
+{
+ return dhdpcie_oob_intr_register(dhdp->bus);
+}
+
+void dhd_bus_oob_intr_unregister(dhd_pub_t *dhdp)
+{
+ dhdpcie_oob_intr_unregister(dhdp->bus);
+}
+
+void dhd_bus_oob_intr_set(dhd_pub_t *dhdp, bool enable)
+{
+ dhdpcie_oob_intr_set(dhdp->bus, enable);
+}
+#endif /* BCMPCIE_OOB_HOST_WAKE */
diff -Nur a/drivers/net/wireless/bcmdhd/dhd_pcie.h c/drivers/net/wireless/bcmdhd/dhd_pcie.h
--- a/drivers/net/wireless/bcmdhd/dhd_pcie.h 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/dhd_pcie.h 2016-05-13 09:48:20.000000000 +0200
@@ -3,7 +3,7 @@
*
* $Copyright Open Broadcom Corporation$
*
- * $Id: dhd_pcie.h 491657 2014-07-17 06:29:40Z $
+ * $Id: dhd_pcie.h 506084 2014-10-02 15:34:59Z $
*/
@@ -12,6 +12,15 @@
#include <bcmpcie.h>
#include <hnd_cons.h>
+#ifdef SUPPORT_LINKDOWN_RECOVERY
+#ifdef CONFIG_ARCH_MSM
+#ifdef CONFIG_ARCH_MSM8994
+#include <linux/msm_pcie.h>
+#else
+#include <mach/msm_pcie.h>
+#endif
+#endif /* CONFIG_ARCH_MSM */
+#endif /* SUPPORT_LINKDOWN_RECOVERY */
/* defines */
@@ -110,6 +119,11 @@
uint32 dma_rxoffset;
volatile char *regs; /* pci device memory va */
volatile char *tcm; /* pci device memory va */
+ uint32 tcm_size;
+#ifdef CONFIG_ARCH_MSM8994
+ uint32 bar1_win_base;
+ uint32 bar1_win_mask;
+#endif
osl_t *osh;
uint32 nvram_csm; /* Nvram checksum */
uint16 pollrate;
@@ -138,7 +152,21 @@
uint8 txmode_push;
uint32 max_sub_queues;
bool db1_for_mb;
-
+ bool suspended;
+#ifdef SUPPORT_LINKDOWN_RECOVERY
+#ifdef CONFIG_ARCH_MSM
+ struct msm_pcie_register_event pcie_event;
+ bool islinkdown;
+#endif /* CONFIG_ARCH_MSM */
+#endif /* SUPPORT_LINKDOWN_RECOVERY */
+#ifdef PCIE_TX_DEFERRAL
+ struct workqueue_struct *tx_wq;
+ struct work_struct create_flow_work;
+ struct work_struct delete_flow_work;
+ unsigned long *delete_flow_map;
+ struct sk_buff_head orphan_list;
+#endif /* PCIE_TX_DEFERRAL */
+ bool irq_registered;
} dhd_bus_t;
/* function declarations */
@@ -148,21 +176,32 @@
extern void dhdpcie_bus_unregister(void);
extern bool dhdpcie_chipmatch(uint16 vendor, uint16 device);
-extern struct dhd_bus* dhdpcie_bus_attach(osl_t *osh, volatile char* regs, volatile char* tcm);
+extern struct dhd_bus* dhdpcie_bus_attach(osl_t *osh, volatile char* regs,
+ volatile char* tcm, uint32 tcm_size);
extern uint32 dhdpcie_bus_cfg_read_dword(struct dhd_bus *bus, uint32 addr, uint32 size);
extern void dhdpcie_bus_cfg_write_dword(struct dhd_bus *bus, uint32 addr, uint32 size, uint32 data);
extern void dhdpcie_bus_intr_disable(struct dhd_bus *bus);
+extern void dhdpcie_bus_remove_prep(struct dhd_bus *bus);
extern void dhdpcie_bus_release(struct dhd_bus *bus);
extern int32 dhdpcie_bus_isr(struct dhd_bus *bus);
extern void dhdpcie_free_irq(dhd_bus_t *bus);
extern int dhdpcie_bus_suspend(struct dhd_bus *bus, bool state);
-extern int dhdpcie_pci_suspend_resume(struct pci_dev *dev, bool state);
+extern int dhdpcie_pci_suspend_resume(struct dhd_bus *bus, bool state);
+#ifndef BCMPCIE_OOB_HOST_WAKE
+extern void dhdpcie_pme_active(osl_t *osh, bool enable);
+#endif /* !BCMPCIE_OOB_HOST_WAKE */
extern int dhdpcie_start_host_pcieclock(dhd_bus_t *bus);
extern int dhdpcie_stop_host_pcieclock(dhd_bus_t *bus);
extern int dhdpcie_disable_device(dhd_bus_t *bus);
extern int dhdpcie_enable_device(dhd_bus_t *bus);
extern int dhdpcie_alloc_resource(dhd_bus_t *bus);
extern void dhdpcie_free_resource(dhd_bus_t *bus);
+extern int dhdpcie_bus_request_irq(struct dhd_bus *bus);
+#ifdef BCMPCIE_OOB_HOST_WAKE
+extern int dhdpcie_oob_intr_register(dhd_bus_t *bus);
+extern void dhdpcie_oob_intr_unregister(dhd_bus_t *bus);
+extern void dhdpcie_oob_intr_set(dhd_bus_t *bus, bool enable);
+#endif /* BCMPCIE_OOB_HOST_WAKE */
extern int dhd_buzzz_dump_dngl(dhd_bus_t *bus);
#endif /* dhd_pcie_h */
diff -Nur a/drivers/net/wireless/bcmdhd/dhd_pcie_linux.c c/drivers/net/wireless/bcmdhd/dhd_pcie_linux.c
--- a/drivers/net/wireless/bcmdhd/dhd_pcie_linux.c 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/dhd_pcie_linux.c 2016-05-13 09:48:20.000000000 +0200
@@ -3,7 +3,7 @@
*
* $Copyright Open Broadcom Corporation$
*
- * $Id: dhd_pcie_linux.c 491657 2014-07-17 06:29:40Z $
+ * $Id: dhd_pcie_linux.c 506043 2014-10-02 12:29:45Z $
*/
@@ -31,8 +31,12 @@
#include <dhd_pcie.h>
#include <dhd_linux.h>
#ifdef CONFIG_ARCH_MSM
+#ifdef CONFIG_ARCH_MSM8994
+#include <linux/msm_pcie.h>
+#else
#include <mach/msm_pcie.h>
#endif
+#endif /* CONFIG_ARCH_MSM */
#define PCI_CFG_RETRY 10
#define OS_HANDLE_MAGIC 0x1234abcd /* Magic # to recognize osh */
@@ -73,6 +77,9 @@
int irq;
char pciname[32];
struct pci_saved_state* state;
+#ifdef BCMPCIE_OOB_HOST_WAKE
+ void *os_cxt; /* Pointer to per-OS private data */
+#endif /* BCMPCIE_OOB_HOST_WAKE */
} dhdpcie_info_t;
@@ -86,6 +93,17 @@
struct tasklet_struct tuning_tasklet;
};
+#ifdef BCMPCIE_OOB_HOST_WAKE
+typedef struct dhdpcie_os_info {
+ int oob_irq_num; /* valid when hardware or software oob in use */
+ unsigned long oob_irq_flags; /* valid when hardware or software oob in use */
+ bool oob_irq_registered;
+ bool oob_irq_enabled;
+ bool oob_irq_wake_enabled;
+ spinlock_t oob_irq_spinlock;
+ void *dev; /* handle to the underlying device */
+} dhdpcie_os_info_t;
+#endif /* BCMPCIE_OOB_HOST_WAKE */
/* function declarations */
static int __devinit
@@ -96,6 +114,12 @@
static irqreturn_t dhdpcie_isr(int irq, void *arg);
/* OS Routine functions for PCI suspend/resume */
+#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
+
static int dhdpcie_pci_suspend(struct pci_dev *dev, pm_message_t state);
static int dhdpcie_set_suspend_resume(struct pci_dev *dev, bool state);
static int dhdpcie_pci_resume(struct pci_dev *dev);
@@ -129,19 +153,6 @@
int dhdpcie_init_succeeded = FALSE;
-static void dhdpcie_pme_active(struct pci_dev *pdev, bool enable)
-{
- uint16 pmcsr;
-
- pci_read_config_word(pdev, pdev->pm_cap + PCI_PM_CTRL, &pmcsr);
- /* Clear PME Status by writing 1 to it and enable PME# */
- pmcsr |= PCI_PM_CTRL_PME_STATUS | PCI_PM_CTRL_PME_ENABLE;
- if (!enable)
- pmcsr &= ~PCI_PM_CTRL_PME_ENABLE;
-
- pci_write_config_word(pdev, pdev->pm_cap + PCI_PM_CTRL, pmcsr);
-}
-
static int dhdpcie_set_suspend_resume(struct pci_dev *pdev, bool state)
{
int ret = 0;
@@ -155,13 +166,20 @@
/* When firmware is not loaded do the PCI bus */
/* suspend/resume only */
if (bus && (bus->dhd->busstate == DHD_BUS_DOWN) &&
- !bus->dhd->dongle_reset) {
- ret = dhdpcie_pci_suspend_resume(bus->dev, state);
- return ret;
- }
+#ifdef CONFIG_MACH_UNIVERSAL5433
+ /* RB:34285 check_rev() : return 1 - new rev., 0 - old rev. */
+ (!check_rev() || (check_rev() && !bus->dhd->dongle_reset)))
+#else
+ !bus->dhd->dongle_reset)
+#endif /* CONFIG_MACH_UNIVERSAL5433 */
+ {
+ ret = dhdpcie_pci_suspend_resume(bus, state);
+ return ret;
+ }
if (bus && ((bus->dhd->busstate == DHD_BUS_SUSPEND)||
- (bus->dhd->busstate == DHD_BUS_DATA))) {
+ (bus->dhd->busstate == DHD_BUS_DATA)) &&
+ (bus->suspended != state)) {
ret = dhdpcie_bus_suspend(bus, state);
}
@@ -183,7 +201,6 @@
{
int ret;
DHD_TRACE_HW4(("%s: Enter\n", __FUNCTION__));
- dhdpcie_pme_active(dev, TRUE);
pci_save_state(dev);
pci_enable_wake(dev, PCI_D0, TRUE);
pci_disable_device(dev);
@@ -211,18 +228,25 @@
printf("%s:pci_set_power_state error %d \n", __FUNCTION__, err);
return err;
}
- dhdpcie_pme_active(dev, FALSE);
return err;
}
-int dhdpcie_pci_suspend_resume(struct pci_dev *dev, bool state)
+int dhdpcie_pci_suspend_resume(struct dhd_bus *bus, bool state)
{
int rc;
+ struct pci_dev *dev = bus->dev;
- if (state)
+ if (state) {
+#ifndef BCMPCIE_OOB_HOST_WAKE
+ dhdpcie_pme_active(bus->osh, state);
+#endif /* BCMPCIE_OOB_HOST_WAKE */
rc = dhdpcie_suspend_dev(dev);
- else
+ } else {
rc = dhdpcie_resume_dev(dev);
+#ifndef BCMPCIE_OOB_HOST_WAKE
+ dhdpcie_pme_active(bus->osh, state);
+#endif /* BCMPCIE_OOB_HOST_WAKE */
+ }
return rc;
}
@@ -300,6 +324,11 @@
return -ENODEV;
}
+#ifdef BCMPCIE_DISABLE_ASYNC_SUSPEND
+ /* disable async suspend */
+ device_disable_async_suspend(&pdev->dev);
+#endif /* BCMPCIE_DISABLE_ASYNC_SUSPEND */
+
DHD_TRACE(("%s: PCIe Enumeration done!!\n", __FUNCTION__));
return 0;
}
@@ -325,14 +354,52 @@
osl_t *osh = NULL;
dhdpcie_info_t *pch = NULL;
dhd_bus_t *bus = NULL;
+#ifdef PCIE_TX_DEFERRAL
+ struct sk_buff *skb;
+#endif
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__));
+ }
+ else {
+ DHD_ERROR(("%s : mutex is locked!. wait for unlocking\n", __FUNCTION__));
+ }
+ mutex_lock(&_dhd_sdio_mutex_lock_);
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
+#endif
+
pch = pci_get_drvdata(pdev);
bus = pch->bus;
osh = pch->osh;
+#ifdef PCIE_TX_DEFERRAL
+ if (bus->tx_wq)
+ destroy_workqueue(bus->tx_wq);
+ skb = skb_dequeue(&bus->orphan_list);
+ while (skb) {
+ PKTCFREE(osh, skb, TRUE);
+ skb = skb_dequeue(&bus->orphan_list);
+ }
+#endif
+
+#ifdef SUPPORT_LINKDOWN_RECOVERY
+#ifdef CONFIG_ARCH_MSM
+ if (bus)
+ msm_pcie_deregister_event(&bus->pcie_event);
+#endif /* CONFIG_ARCH_MSM */
+#endif /* SUPPORT_LINKDOWN_RECOVERY */
+
+ dhdpcie_bus_remove_prep(bus);
dhdpcie_bus_release(bus);
pci_disable_device(pdev);
+#ifdef BCMPCIE_OOB_HOST_WAKE
+ /* pcie os info detach */
+ MFREE(osh, pch->os_cxt, sizeof(dhdpcie_os_info_t));
+#endif /* BCMPCIE_OOB_HOST_WAKE */
/* pcie info detach */
dhdpcie_detach(pch);
/* osl detach */
@@ -340,6 +407,13 @@
dhdpcie_init_succeeded = FALSE;
+#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 Exit\n", __FUNCTION__));
return;
@@ -359,6 +433,7 @@
DHD_ERROR(("%s: request_irq() failed\n", __FUNCTION__));
return -1;
}
+ bus->irq_registered = TRUE;
DHD_TRACE(("%s %s\n", __FUNCTION__, dhdpcie_info->pciname));
@@ -416,8 +491,9 @@
}
dhdpcie_info->regs = (volatile char *) REG_MAP(bar0_addr, DONGLE_REG_MAP_SIZE);
- dhdpcie_info->tcm = (volatile char *) REG_MAP(bar1_addr, DONGLE_TCM_MAP_SIZE);
- dhdpcie_info->tcm_size = DONGLE_TCM_MAP_SIZE;
+ dhdpcie_info->tcm_size =
+ (bar1_size < DONGLE_TCM_MAP_SIZE) ? bar1_size : DONGLE_TCM_MAP_SIZE;
+ dhdpcie_info->tcm = (volatile char *) REG_MAP(bar1_addr, dhdpcie_info->tcm_size);
if (!dhdpcie_info->regs || !dhdpcie_info->tcm) {
DHD_ERROR(("%s:ioremap() failed\n", __FUNCTION__));
@@ -478,6 +554,103 @@
}
+#ifdef SUPPORT_LINKDOWN_RECOVERY
+#ifdef CONFIG_ARCH_MSM
+void dhdpcie_linkdown_cb(struct msm_pcie_notify *noti)
+{
+ struct pci_dev *pdev = (struct pci_dev *)noti->user;
+ dhdpcie_info_t *pch = NULL;
+
+ if (pdev) {
+ pch = pci_get_drvdata(pdev);
+ if (pch) {
+ dhd_bus_t *bus = pch->bus;
+ if (bus) {
+ dhd_pub_t *dhd = bus->dhd;
+ if (dhd) {
+ DHD_ERROR(("%s: Event HANG send up "
+ "due to PCIe linkdown\n",
+ __FUNCTION__));
+ bus->islinkdown = TRUE;
+ DHD_OS_WAKE_LOCK(dhd);
+ dhd_os_check_hang(dhd, 0, -ETIMEDOUT);
+ }
+ }
+ }
+ }
+
+}
+#endif /* CONFIG_ARCH_MSM */
+#endif /* SUPPORT_LINKDOWN_RECOVERY */
+
+#ifdef PCIE_TX_DEFERRAL
+static void dhd_pcie_create_flow_worker(struct work_struct *worker)
+{
+ dhd_bus_t *bus;
+ struct sk_buff *skb;
+ uint16 ifidx, flowid;
+ flow_queue_t *queue;
+ flow_ring_node_t *flow_ring_node;
+ unsigned long flags;
+
+ bus = container_of(worker, dhd_bus_t, create_flow_work);
+ skb = skb_dequeue(&bus->orphan_list);
+ while (skb) {
+ ifidx = DHD_PKTTAG_FLOWID((dhd_pkttag_fr_t*)PKTTAG(skb));
+ if (BCME_OK != dhd_flowid_update(bus->dhd, ifidx,
+ bus->dhd->flow_prio_map[(PKTPRIO(skb))], skb)) {
+ PKTCFREE(bus->dhd->osh, skb, TRUE);
+ skb = skb_dequeue(&bus->orphan_list);
+ continue;
+ }
+ flowid = DHD_PKTTAG_FLOWID((dhd_pkttag_fr_t*)PKTTAG(skb));
+ flow_ring_node = DHD_FLOW_RING(bus->dhd, flowid);
+ queue = &flow_ring_node->queue;
+ DHD_FLOWRING_LOCK(flow_ring_node->lock, flags);
+ if ((flowid >= bus->dhd->num_flow_rings) ||
+ (!flow_ring_node->active) ||
+ (flow_ring_node->status == FLOW_RING_STATUS_DELETE_PENDING)) {
+ DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags);
+ DHD_ERROR(("%s: Dropping pkt flowid %d, status %d active %d\n",
+ __FUNCTION__, flowid, flow_ring_node->status,
+ flow_ring_node->active));
+ PKTCFREE(bus->dhd->osh, skb, TRUE);
+ skb = skb_dequeue(&bus->orphan_list);
+ continue;
+ }
+ if (BCME_OK != dhd_flow_queue_enqueue(bus->dhd, queue, skb)) {
+ DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags);
+ PKTCFREE(bus->dhd->osh, skb, TRUE);
+ skb = skb_dequeue(&bus->orphan_list);
+ continue;
+ }
+ DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags);
+
+ if (flow_ring_node->status == FLOW_RING_STATUS_OPEN)
+ dhd_bus_schedule_queue(bus, flowid, FALSE);
+
+ skb = skb_dequeue(&bus->orphan_list);
+ }
+}
+
+static void dhd_pcie_delete_flow_worker(struct work_struct *worker)
+{
+ dhd_bus_t *bus;
+ uint16 flowid;
+
+ bus = container_of(worker, dhd_bus_t, delete_flow_work);
+ for_each_set_bit(flowid, bus->delete_flow_map, bus->dhd->num_flow_rings) {
+ clear_bit(flowid, bus->delete_flow_map);
+ dhd_bus_flow_ring_delete_response(bus, flowid, BCME_OK);
+ }
+}
+
+#endif /* PCIE_TX_DEFERRAL */
+
+#if defined(MULTIPLE_SUPPLICANT)
+extern void wl_android_post_init(void); // terence 20120530: fix critical section in dhd_open and dhdsdio_probe
+#endif
+
int dhdpcie_init(struct pci_dev *pdev)
{
@@ -485,6 +658,21 @@
dhd_bus_t *bus = NULL;
dhdpcie_info_t *dhdpcie_info = NULL;
wifi_adapter_info_t *adapter = NULL;
+#ifdef BCMPCIE_OOB_HOST_WAKE
+ dhdpcie_os_info_t *dhdpcie_osinfo = NULL;
+#endif /* BCMPCIE_OOB_HOST_WAKE */
+
+#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__));
+ }
+ else {
+ DHD_ERROR(("%s : mutex is locked!. wait for unlocking\n", __FUNCTION__));
+ }
+ mutex_lock(&_dhd_sdio_mutex_lock_);
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
+#endif
do {
/* osl attach */
@@ -511,6 +699,27 @@
dhdpcie_info->osh = osh;
dhdpcie_info->dev = pdev;
+#ifdef BCMPCIE_OOB_HOST_WAKE
+ /* allocate OS speicific structure */
+ dhdpcie_osinfo = MALLOC(osh, sizeof(dhdpcie_os_info_t));
+ if (dhdpcie_osinfo == NULL) {
+ DHD_ERROR(("%s: MALLOC of dhdpcie_os_info_t failed\n",
+ __FUNCTION__));
+ break;
+ }
+ bzero(dhdpcie_osinfo, sizeof(dhdpcie_os_info_t));
+ dhdpcie_info->os_cxt = (void *)dhdpcie_osinfo;
+
+ /* Initialize host wake IRQ */
+ spin_lock_init(&dhdpcie_osinfo->oob_irq_spinlock);
+ /* Get customer specific host wake IRQ parametres: IRQ number as IRQ type */
+ dhdpcie_osinfo->oob_irq_num = wifi_platform_get_irq_number(adapter,
+ &dhdpcie_osinfo->oob_irq_flags);
+ if (dhdpcie_osinfo->oob_irq_num < 0) {
+ DHD_ERROR(("%s: Host OOB irq is not defined\n", __FUNCTION__));
+ }
+#endif /* BCMPCIE_OOB_HOST_WAKE */
+
/* Find the PCI resources, verify the */
/* vendor and device ID, map BAR regions and irq, update in structures */
if (dhdpcie_scan_resource(dhdpcie_info)) {
@@ -520,7 +729,8 @@
}
/* Bus initialization */
- bus = dhdpcie_bus_attach(osh, dhdpcie_info->regs, dhdpcie_info->tcm);
+ bus = dhdpcie_bus_attach(osh, dhdpcie_info->regs,
+ dhdpcie_info->tcm, dhdpcie_info->tcm_size);
if (!bus) {
DHD_ERROR(("%s:dhdpcie_bus_attach() failed\n", __FUNCTION__));
break;
@@ -529,6 +739,18 @@
dhdpcie_info->bus = bus;
dhdpcie_info->bus->dev = pdev;
+#ifdef SUPPORT_LINKDOWN_RECOVERY
+#ifdef CONFIG_ARCH_MSM
+ bus->pcie_event.events = MSM_PCIE_EVENT_LINKDOWN;
+ bus->pcie_event.user = pdev;
+ bus->pcie_event.mode = MSM_PCIE_TRIGGER_CALLBACK;
+ bus->pcie_event.callback = dhdpcie_linkdown_cb;
+ bus->pcie_event.options = MSM_PCIE_CONFIG_NO_RECOVERY;
+ msm_pcie_register_event(&bus->pcie_event);
+ bus->islinkdown = FALSE;
+#endif /* CONFIG_ARCH_MSM */
+#endif /* SUPPORT_LINKDOWN_RECOVERY */
+
if (bus->intr) {
/* Register interrupt callback, but mask it (not operational yet). */
DHD_INTR(("%s: Registering and masking interrupts\n", __FUNCTION__));
@@ -544,16 +766,29 @@
"due to polling mode\n", __FUNCTION__));
}
+#if 0 // terence 20150325: fix for WPA/WPA2 4-way handshake fail in hostapd
if (dhd_download_fw_on_driverload) {
if (dhd_bus_start(bus->dhd)) {
DHD_ERROR(("%s: dhd_bud_start() failed\n", __FUNCTION__));
break;
}
}
+#endif
/* set private data for pci_dev */
pci_set_drvdata(pdev, dhdpcie_info);
+#ifdef PCIE_TX_DEFERRAL
+ bus->tx_wq = create_singlethread_workqueue("bcmdhd_tx");
+ if (bus->tx_wq == NULL) {
+ DHD_ERROR(("%s workqueue creation failed\n", __FUNCTION__));
+ break;
+ }
+ INIT_WORK(&bus->create_flow_work, dhd_pcie_create_flow_worker);
+ INIT_WORK(&bus->delete_flow_work, dhd_pcie_delete_flow_worker);
+ skb_queue_head_init(&bus->orphan_list);
+#endif /* PCIE_TX_DEFERRAL */
+
/* Attach to the OS network interface */
DHD_TRACE(("%s(): Calling dhd_register_if() \n", __FUNCTION__));
if (dhd_register_if(bus->dhd, 0, TRUE)) {
@@ -563,6 +798,14 @@
dhdpcie_init_succeeded = TRUE;
+#if defined(MULTIPLE_SUPPLICANT)
+ wl_android_post_init(); // terence 20120530: fix critical section in dhd_open and dhdsdio_probe
+#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
+
DHD_TRACE(("%s:Exit - SUCCESS \n", __FUNCTION__));
return 0; /* return SUCCESS */
@@ -572,6 +815,11 @@
if (bus)
dhdpcie_bus_release(bus);
+#ifdef BCMPCIE_OOB_HOST_WAKE
+ if (dhdpcie_osinfo)
+ MFREE(osh, dhdpcie_osinfo, sizeof(dhdpcie_os_info_t));
+#endif /* BCMPCIE_OOB_HOST_WAKE */
+
if (dhdpcie_info)
dhdpcie_detach(dhdpcie_info);
pci_disable_device(pdev);
@@ -579,6 +827,12 @@
osl_detach(osh);
dhdpcie_init_succeeded = FALSE;
+#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
DHD_TRACE(("%s:Exit - FAILURE \n", __FUNCTION__));
@@ -592,9 +846,10 @@
struct pci_dev *pdev = NULL;
DHD_TRACE(("%s: freeing up the IRQ\n", __FUNCTION__));
- if (bus) {
+ if (bus && bus->irq_registered) {
pdev = bus->dev;
free_irq(pdev->irq, bus);
+ bus->irq_registered = FALSE;
}
DHD_TRACE(("%s: Exit\n", __FUNCTION__));
return;
@@ -633,9 +888,11 @@
dhdpcie_start_host_pcieclock(dhd_bus_t *bus)
{
int ret = 0;
+#ifdef CONFIG_ARCH_MSM
#ifdef SUPPORT_LINKDOWN_RECOVERY
int options = 0;
#endif /* SUPPORT_LINKDOWN_RECOVERY */
+#endif /* CONFIG_ARCH_MSM */
DHD_TRACE(("%s Enter:\n", __FUNCTION__));
if (bus == NULL)
@@ -644,13 +901,13 @@
if (bus->dev == NULL)
return BCME_ERROR;
-#if defined(CONFIG_ARCH_MSM)
+#ifdef CONFIG_ARCH_MSM
#ifdef SUPPORT_LINKDOWN_RECOVERY
if (bus->islinkdown) {
options = MSM_PCIE_CONFIG_NO_CFG_RESTORE;
}
ret = msm_pcie_pm_control(MSM_PCIE_RESUME, bus->dev->bus->number,
- NULL, NULL, options);
+ bus->dev, NULL, options);
if (bus->islinkdown && !ret) {
msm_pcie_recover_config(bus->dev);
if (bus->dhd)
@@ -659,7 +916,7 @@
}
#else
ret = msm_pcie_pm_control(MSM_PCIE_RESUME, bus->dev->bus->number,
- NULL, NULL, 0);
+ bus->dev, NULL, 0);
#endif /* SUPPORT_LINKDOWN_RECOVERY */
if (ret) {
DHD_ERROR(("%s Failed to bring up PCIe link\n", __FUNCTION__));
@@ -677,9 +934,11 @@
{
int ret = 0;
+#ifdef CONFIG_ARCH_MSM
#ifdef SUPPORT_LINKDOWN_RECOVERY
int options = 0;
-#endif
+#endif /* SUPPORT_LINKDOWN_RECOVERY */
+#endif /* CONFIG_ARCH_MSM */
DHD_TRACE(("%s Enter:\n", __FUNCTION__));
if (bus == NULL)
@@ -688,16 +947,16 @@
if (bus->dev == NULL)
return BCME_ERROR;
-#if defined(CONFIG_ARCH_MSM)
+#ifdef CONFIG_ARCH_MSM
#ifdef SUPPORT_LINKDOWN_RECOVERY
if (bus->islinkdown)
options = MSM_PCIE_CONFIG_NO_CFG_RESTORE | MSM_PCIE_CONFIG_LINKDOWN;
ret = msm_pcie_pm_control(MSM_PCIE_SUSPEND, bus->dev->bus->number,
- NULL, NULL, options);
+ bus->dev, NULL, options);
#else
ret = msm_pcie_pm_control(MSM_PCIE_SUSPEND, bus->dev->bus->number,
- NULL, NULL, 0);
+ bus->dev, NULL, 0);
#endif /* SUPPORT_LINKDOWN_RECOVERY */
if (ret) {
DHD_ERROR(("Failed to stop PCIe link\n"));
@@ -741,18 +1000,33 @@
if (pch == NULL)
return BCME_ERROR;
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
+ /* Updated with pci_load_and_free_saved_state to compatible
+ * with kernel 3.14 or higher
+ */
+ if (pci_load_and_free_saved_state(bus->dev, &pch->state))
+ pci_disable_device(bus->dev);
+ else
+#elif ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \
+ (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)))
if (pci_load_saved_state(bus->dev, pch->state))
pci_disable_device(bus->dev);
- else {
-#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) */
+ else
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) and
+ * (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \
+ * (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)
+ */
+ {
pci_restore_state(bus->dev);
ret = pci_enable_device(bus->dev);
if (!ret)
pci_set_master(bus->dev);
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))
}
-#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) */
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) and
+ * (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \
+ * (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)
+ */
if (ret)
pci_disable_device(bus->dev);
@@ -804,8 +1078,9 @@
}
bus->regs = dhdpcie_info->regs;
- dhdpcie_info->tcm = (volatile char *) REG_MAP(bar1_addr, DONGLE_TCM_MAP_SIZE);
- dhdpcie_info->tcm_size = DONGLE_TCM_MAP_SIZE;
+ dhdpcie_info->tcm_size =
+ (bar1_size < DONGLE_TCM_MAP_SIZE) ? bar1_size : DONGLE_TCM_MAP_SIZE;
+ dhdpcie_info->tcm = (volatile char *) REG_MAP(bar1_addr, dhdpcie_info->tcm_size);
if (!dhdpcie_info->tcm) {
DHD_ERROR(("%s: ioremap() for regs is failed\n", __FUNCTION__));
REG_UNMAP(dhdpcie_info->regs);
@@ -814,6 +1089,7 @@
}
bus->tcm = dhdpcie_info->tcm;
+ bus->tcm_size = dhdpcie_info->tcm_size;
DHD_TRACE(("%s:Phys addr : reg space = %p base addr 0x"PRINTF_RESOURCE" \n",
__FUNCTION__, dhdpcie_info->regs, bar0_addr));
@@ -857,3 +1133,183 @@
bus->tcm = NULL;
}
}
+
+int
+dhdpcie_bus_request_irq(struct dhd_bus *bus)
+{
+ dhdpcie_info_t *dhdpcie_info;
+ int ret = 0;
+
+ if (bus == NULL) {
+ DHD_ERROR(("%s: bus is NULL\n", __FUNCTION__));
+ return BCME_ERROR;
+ }
+
+ if (bus->dev == NULL) {
+ DHD_ERROR(("%s: bus->dev is NULL\n", __FUNCTION__));
+ return BCME_ERROR;
+ }
+
+ dhdpcie_info = pci_get_drvdata(bus->dev);
+ if (dhdpcie_info == NULL) {
+ DHD_ERROR(("%s: dhdpcie_info is NULL\n", __FUNCTION__));
+ return BCME_ERROR;
+ }
+
+ if (bus->intr) {
+ /* Register interrupt callback, but mask it (not operational yet). */
+ DHD_INTR(("%s: Registering and masking interrupts\n", __FUNCTION__));
+ dhdpcie_bus_intr_disable(bus);
+ ret = dhdpcie_request_irq(dhdpcie_info);
+ if (ret) {
+ DHD_ERROR(("%s: request_irq() failed, ret=%d\n",
+ __FUNCTION__, ret));
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+#ifdef BCMPCIE_OOB_HOST_WAKE
+void dhdpcie_oob_intr_set(dhd_bus_t *bus, bool enable)
+{
+ unsigned long flags;
+ dhdpcie_info_t *pch;
+ dhdpcie_os_info_t *dhdpcie_osinfo;
+
+ if (bus == NULL) {
+ DHD_ERROR(("%s: bus is NULL\n", __FUNCTION__));
+ return;
+ }
+
+ if (bus->dev == NULL) {
+ DHD_ERROR(("%s: bus->dev is NULL\n", __FUNCTION__));
+ return;
+ }
+
+ pch = pci_get_drvdata(bus->dev);
+ if (pch == NULL) {
+ DHD_ERROR(("%s: pch is NULL\n", __FUNCTION__));
+ return;
+ }
+
+ dhdpcie_osinfo = (dhdpcie_os_info_t *)pch->os_cxt;
+ spin_lock_irqsave(&dhdpcie_osinfo->oob_irq_spinlock, flags);
+ if ((dhdpcie_osinfo->oob_irq_enabled != enable) &&
+ (dhdpcie_osinfo->oob_irq_num > 0)) {
+ if (enable)
+ enable_irq(dhdpcie_osinfo->oob_irq_num);
+ else
+ disable_irq_nosync(dhdpcie_osinfo->oob_irq_num);
+ dhdpcie_osinfo->oob_irq_enabled = enable;
+ }
+ spin_unlock_irqrestore(&dhdpcie_osinfo->oob_irq_spinlock, flags);
+}
+
+static irqreturn_t wlan_oob_irq(int irq, void *data)
+{
+ dhd_bus_t *bus;
+ DHD_TRACE(("%s: IRQ Triggered\n", __FUNCTION__));
+ bus = (dhd_bus_t *)data;
+ if (bus->dhd->up && bus->suspended) {
+ DHD_OS_OOB_IRQ_WAKE_LOCK_TIMEOUT(bus->dhd, OOB_WAKE_LOCK_TIMEOUT);
+ }
+ return IRQ_HANDLED;
+}
+
+int dhdpcie_oob_intr_register(dhd_bus_t *bus)
+{
+ int err = 0;
+ dhdpcie_info_t *pch;
+ dhdpcie_os_info_t *dhdpcie_osinfo;
+
+ DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+ if (bus == NULL) {
+ DHD_ERROR(("%s: bus is NULL\n", __FUNCTION__));
+ return -EINVAL;
+ }
+
+ if (bus->dev == NULL) {
+ DHD_ERROR(("%s: bus->dev is NULL\n", __FUNCTION__));
+ return -EINVAL;
+ }
+
+ pch = pci_get_drvdata(bus->dev);
+ if (pch == NULL) {
+ DHD_ERROR(("%s: pch is NULL\n", __FUNCTION__));
+ return -EINVAL;
+ }
+
+ dhdpcie_osinfo = (dhdpcie_os_info_t *)pch->os_cxt;
+ if (dhdpcie_osinfo->oob_irq_registered) {
+ DHD_ERROR(("%s: irq is already registered\n", __FUNCTION__));
+ return -EBUSY;
+ }
+
+ if (dhdpcie_osinfo->oob_irq_num > 0) {
+ DHD_INFO_HW4(("%s OOB irq=%d flags=%X \n", __FUNCTION__,
+ (int)dhdpcie_osinfo->oob_irq_num,
+ (int)dhdpcie_osinfo->oob_irq_flags));
+ err = request_irq(dhdpcie_osinfo->oob_irq_num, wlan_oob_irq,
+ dhdpcie_osinfo->oob_irq_flags, "dhdpcie_host_wake",
+ bus);
+ if (err) {
+ DHD_ERROR(("%s: request_irq failed with %d\n",
+ __FUNCTION__, err));
+ return err;
+ }
+ err = enable_irq_wake(dhdpcie_osinfo->oob_irq_num);
+ if (!err)
+ dhdpcie_osinfo->oob_irq_wake_enabled = TRUE;
+ dhdpcie_osinfo->oob_irq_enabled = TRUE;
+ }
+
+ dhdpcie_osinfo->oob_irq_registered = TRUE;
+
+ return err;
+}
+
+void dhdpcie_oob_intr_unregister(dhd_bus_t *bus)
+{
+ int err = 0;
+ dhdpcie_info_t *pch;
+ dhdpcie_os_info_t *dhdpcie_osinfo;
+
+ DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+ if (bus == NULL) {
+ DHD_ERROR(("%s: bus is NULL\n", __FUNCTION__));
+ return;
+ }
+
+ if (bus->dev == NULL) {
+ DHD_ERROR(("%s: bus->dev is NULL\n", __FUNCTION__));
+ return;
+ }
+
+ pch = pci_get_drvdata(bus->dev);
+ if (pch == NULL) {
+ DHD_ERROR(("%s: pch is NULL\n", __FUNCTION__));
+ return;
+ }
+
+ dhdpcie_osinfo = (dhdpcie_os_info_t *)pch->os_cxt;
+ if (!dhdpcie_osinfo->oob_irq_registered) {
+ DHD_ERROR(("%s: irq is not registered\n", __FUNCTION__));
+ return;
+ }
+ if (dhdpcie_osinfo->oob_irq_num > 0) {
+ if (dhdpcie_osinfo->oob_irq_wake_enabled) {
+ err = disable_irq_wake(dhdpcie_osinfo->oob_irq_num);
+ if (!err)
+ dhdpcie_osinfo->oob_irq_wake_enabled = FALSE;
+ }
+ if (dhdpcie_osinfo->oob_irq_enabled) {
+ disable_irq(dhdpcie_osinfo->oob_irq_num);
+ dhdpcie_osinfo->oob_irq_enabled = FALSE;
+ }
+ free_irq(dhdpcie_osinfo->oob_irq_num, bus);
+ }
+ dhdpcie_osinfo->oob_irq_registered = FALSE;
+}
+#endif /* BCMPCIE_OOB_HOST_WAKE */
diff -Nur a/drivers/net/wireless/bcmdhd/dhd_pno.h c/drivers/net/wireless/bcmdhd/dhd_pno.h
--- a/drivers/net/wireless/bcmdhd/dhd_pno.h 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/dhd_pno.h 2016-05-13 09:48:20.000000000 +0200
@@ -230,14 +230,18 @@
extern int dhd_pno_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data);
extern int dhd_pno_init(dhd_pub_t *dhd);
extern int dhd_pno_deinit(dhd_pub_t *dhd);
-#endif
+#endif
-#if (defined(NDISVER) && (NDISVER >= 0x0630)) && defined(PNO_SUPPORT)
+#if defined(NDISVER)
+#if defined(PNO_SUPPORT)
+#if (NDISVER >= 0x0630)
extern int dhd_pno_cfg(dhd_pub_t *dhd, wl_pfn_cfg_t *pcfg);
extern int dhd_pno_suspend(dhd_pub_t *dhd, int pfn_suspend);
extern int dhd_pno_set_add(dhd_pub_t *dhd, wl_pfn_t *netinfo, int nssid, ushort scan_fr,
ushort slowscan_fr, uint8 pno_repeat, uint8 pno_freq_expo_max, int16 flags);
extern int dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled);
extern int dhd_pno_clean(dhd_pub_t *dhd);
-#endif /* (defined(NDISVER) && (NDISVER >= 0x0630)) && defined(PNO_SUPPORT) */
+#endif /* #if (NDISVER >= 0x0630) */
+#endif /* #if defined(PNO_SUPPORT) */
+#endif /* #if defined(NDISVER) */
#endif /* __DHD_PNO_H__ */
diff -Nur a/drivers/net/wireless/bcmdhd/dhd_proto.h c/drivers/net/wireless/bcmdhd/dhd_proto.h
--- a/drivers/net/wireless/bcmdhd/dhd_proto.h 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/dhd_proto.h 2016-05-13 09:48:20.000000000 +0200
@@ -6,7 +6,7 @@
*
* $Copyright Open Broadcom Corporation$
*
- * $Id: dhd_proto.h 490409 2014-07-10 16:34:27Z $
+ * $Id: dhd_proto.h 499674 2014-08-29 21:56:23Z $
*/
#ifndef _dhd_proto_h_
@@ -18,8 +18,10 @@
#include <dhd_flowring.h>
#endif
+#define DEFAULT_IOCTL_RESP_TIMEOUT 2000
#ifndef IOCTL_RESP_TIMEOUT
-#define IOCTL_RESP_TIMEOUT 2000 /* In milli second default value for Production FW */
+/* In milli second default value for Production FW */
+#define IOCTL_RESP_TIMEOUT DEFAULT_IOCTL_RESP_TIMEOUT
#endif /* IOCTL_RESP_TIMEOUT */
#ifndef MFG_IOCTL_RESP_TIMEOUT
@@ -83,8 +85,8 @@
uint reorder_info_len, void **pkt, uint32 *free_buf_count);
#ifdef BCMPCIE
-extern int dhd_prot_process_msgbuf_txcpl(dhd_pub_t *dhd);
-extern int dhd_prot_process_msgbuf_rxcpl(dhd_pub_t *dhd);
+extern bool dhd_prot_process_msgbuf_txcpl(dhd_pub_t *dhd, uint bound);
+extern bool dhd_prot_process_msgbuf_rxcpl(dhd_pub_t *dhd, uint bound);
extern int dhd_prot_process_ctrlbuf(dhd_pub_t * dhd);
extern bool dhd_prot_dtohsplit(dhd_pub_t * dhd);
extern int dhd_post_dummy_msg(dhd_pub_t *dhd);
diff -Nur a/drivers/net/wireless/bcmdhd/dhd_sdio.c c/drivers/net/wireless/bcmdhd/dhd_sdio.c
--- a/drivers/net/wireless/bcmdhd/dhd_sdio.c 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/dhd_sdio.c 2016-09-30 01:21:10.137991163 +0200
@@ -3,7 +3,7 @@
*
* $Copyright Open Broadcom Corporation$
*
- * $Id: dhd_sdio.c 489913 2014-07-08 18:57:48Z $
+ * $Id: dhd_sdio.c 506046 2014-10-02 12:40:12Z $
*/
#include <typedefs.h>
@@ -83,7 +83,7 @@
#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_NVRAMBUF_SIZE (16 * 1024) /* max nvram buf size */
#define MAX_DATA_BUF (64 * 1024) /* Must be large enough to hold biggest possible glom */
#ifndef DHD_FIRSTREAD
@@ -145,13 +145,18 @@
*/
#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)
#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
+#endif
#ifdef DHD_DEBUG
/* Device console log buffer state */
@@ -367,6 +372,8 @@
#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 */
} dhd_bus_t;
/* clkstate */
@@ -423,7 +430,7 @@
#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
@@ -448,10 +455,27 @@
/* 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) \
@@ -459,8 +483,12 @@
(((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! */
@@ -568,7 +596,11 @@
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);
@@ -713,9 +745,11 @@
(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 == BCM4371_CHIP_ID) ||
(BCM4349_CHIP(bus->sih->chip)) ||
(bus->sih->chip == BCM4350_CHIP_ID)) {
core_capext = TRUE;
@@ -733,9 +767,11 @@
(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 == BCM4371_CHIP_ID) ||
(bus->sih->chip == BCM4350_CHIP_ID)) {
uint32 enabval = 0;
addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr);
@@ -745,9 +781,11 @@
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))
+ (bus->sih->chip == BCM4358_CHIP_ID) ||
+ (bus->sih->chip == BCM4371_CHIP_ID))
enabval &= CC_CHIPCTRL3_SR_ENG_ENABLE;
if (enabval)
@@ -792,9 +830,13 @@
1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT, &err);
val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, NULL);
+#ifdef USE_CMD14
/* Add CMD14 Support */
dhdsdio_devcap_set(bus,
(SDIOD_CCCR_BRCM_CARDCAP_CMD14_SUPPORT | SDIOD_CCCR_BRCM_CARDCAP_CMD14_EXT));
+#endif /* USE_CMD14 */
+
+ dhdsdio_devcap_set(bus, SDIOD_CCCR_BRCM_CARDCAP_CMD_NODEC);
bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1,
SBSDIO_FUNC1_CHIPCLKCSR, SBSDIO_FORCE_HT, &err);
@@ -1521,12 +1563,11 @@
return err;
}
-
-#if defined(OOB_INTR_ONLY)
+#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;
@@ -1551,7 +1592,7 @@
dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
#endif /* !defined(HW_OOB) */
}
-#endif
+#endif
int
dhd_bus_txdata(struct dhd_bus *bus, void *pkt)
@@ -1559,10 +1600,6 @@
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 */
DHD_TRACE(("%s: Enter\n", __FUNCTION__));
@@ -1585,31 +1622,6 @@
BCM_REFERENCE(datalen);
#endif /* SDTEST */
-#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 (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 */
-
-#if defined(DHD_TX_DUMP) && defined(DHD_TX_FULL_DUMP)
- {
- int i;
- DHD_ERROR(("TX DUMP\n"));
-
- 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 */
-
prec = PRIO2PREC((PKTPRIO(pkt) & PRIOMASK));
/* Check for existing queue, current flow-control, pending event, or pending clock */
@@ -1669,8 +1681,20 @@
/* 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;
@@ -1720,7 +1744,11 @@
*/
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;
@@ -1732,6 +1760,9 @@
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;
@@ -1761,6 +1792,34 @@
}
}
#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)]++;
@@ -1901,6 +1960,10 @@
* 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;
@@ -1909,13 +1972,43 @@
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));
@@ -1976,6 +2069,615 @@
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
+ }
+
+ if (ret)
+ bus->dhd->tx_errors++;
+ else
+ bus->dhd->dstats.tx_bytes += datalen;
+
+ /* In poll mode, need to check for other events */
+ if (!bus->intr && cnt)
+ {
+ /* Check device status, signal pending interrupt */
+ R_SDREG(intstatus, &regs->intstatus, retries);
+ bus->f2txdata++;
+ if (bcmsdh_regfail(bus->sdh))
+ break;
+ 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);
+
+ return cnt;
+}
+#endif
+
static int dhdsdio_txpkt(dhd_bus_t *bus, uint chan, void** pkts, int num_pkt, bool free_pkt)
{
int i;
@@ -2009,7 +2711,11 @@
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) {
@@ -2049,6 +2755,12 @@
* 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)
@@ -2144,9 +2856,24 @@
break;
if (dhdsdio_txpkt(bus, SDPCM_DATA_CHANNEL, pkts, i, TRUE) != BCME_OK)
dhd->tx_errors++;
- else
+ else {
dhd->dstats.tx_bytes += datalen;
+ bus->txglomframes++;
+ 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)
@@ -2197,6 +2924,13 @@
*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);
@@ -2334,6 +3068,16 @@
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);
if (ret == BCME_OK)
@@ -2645,6 +3389,11 @@
#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);
+ dhd_dump_pct(strbuf, "Tx: glom pct", (100 * bus->txglompkts), bus->dhd->tx_packets);
+ dhd_dump_pct(strbuf, ", pkts/glom", bus->txglompkts, bus->txglomframes);
+ bcm_bprintf(strbuf, "\n");
+ bcm_bprintf(strbuf, "txglomframes %u, txglompkts %u\n", bus->txglomframes, bus->txglompkts);
+ bcm_bprintf(strbuf, "\n");
}
void
@@ -2661,6 +3410,7 @@
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;
+ bus->txglomframes = bus->txglompkts = 0;
}
#ifdef SDTEST
@@ -3229,7 +3979,7 @@
return (int_val & uart_enab);
}
-#endif
+#endif
static int
dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const char *name,
@@ -3703,7 +4453,7 @@
bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_MESBUSYCTRL,
((uint8)mesbusyctrl | 0x80), NULL);
break;
-#endif
+#endif
case IOV_GVAL(IOV_DONGLEISOLATION):
@@ -3818,6 +4568,13 @@
varsize = bus->varsz ? ROUNDUP(bus->varsz, 4) : 0;
varaddr = (bus->ramsize - 4) - varsize;
+ // terence 20150412: fix for nvram failed to download
+ if (bus->dhd->conf->chip == BCM43340_CHIP_ID ||
+ bus->dhd->conf->chip == BCM43341_CHIP_ID) {
+ varsize = varsize ? ROUNDUP(varsize, 64) : 0;
+ varaddr = (bus->ramsize - 64) - varsize;
+ }
+
varaddr += bus->dongle_ram_base;
if (bus->vars) {
@@ -4203,9 +4960,6 @@
BUS_WAKE(bus);
- /* Change our idea of bus state */
- bus->dhd->busstate = DHD_BUS_DOWN;
-
if (KSO_ENAB(bus)) {
/* Enable clock for device interrupts */
@@ -4240,6 +4994,9 @@
/* 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
@@ -4318,7 +5075,8 @@
} else
#endif /* BCMSDIOH_TXGLOM */
bus->txglom_enable = FALSE;
- printk("%s: enable %d\n", __FUNCTION__, bus->txglom_enable);
+ printf("%s: enable %d\n", __FUNCTION__, bus->txglom_enable);
+ dhd_conf_set_txglom_params(bus->dhd, bus->txglom_enable);
}
int
@@ -5130,7 +5888,13 @@
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
@@ -5667,6 +6431,15 @@
dhd_os_sdunlock(bus->dhd);
dhd_rx_frame(bus->dhd, ifidx, pkt, pkt_count, chan);
dhd_os_sdlock(bus->dhd);
+#if defined(SDIO_ISR_THREAD)
+ /* terence 20150615: fix for below error due to bussleep in watchdog after dhd_os_sdunlock here,
+ * so call BUS_WAKE to wake up bus again
+ * dhd_bcmsdh_recv_buf: Device asleep
+ * dhdsdio_readframes: RXHEADER FAILED: -40
+ * dhdsdio_rxfail: abort command, terminate frame, send NAK
+ */
+ BUS_WAKE(bus);
+#endif
}
rxcount = maxframes - rxleft;
#ifdef DHD_DEBUG
@@ -6009,12 +6782,24 @@
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 */
@@ -6119,7 +6904,7 @@
#if defined(SDIO_ISR_THREAD)
DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__));
DHD_OS_WAKE_LOCK(bus->dhd);
- /* terence 20150209: dpc should be scheded again if dpc_sched is TRUE or dhd_bus_txdata can
+ /* terence 20150209: dpc should be scheded again if dpc_sched is TRUE or dhd_bus_txdata can
not schedule anymore because dpc_sched is TRUE now.
*/
if (dhdsdio_dpc(bus)) {
@@ -6138,6 +6923,28 @@
}
+#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)
@@ -6542,6 +7349,11 @@
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) {
@@ -6581,7 +7393,7 @@
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
@@ -6596,7 +7408,7 @@
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
@@ -6751,6 +7563,8 @@
return TRUE;
if (chipid == BCM4345_CHIP_ID)
return TRUE;
+ if (chipid == BCM43454_CHIP_ID)
+ return TRUE;
if (chipid == BCM4350_CHIP_ID)
return TRUE;
if (chipid == BCM4354_CHIP_ID)
@@ -6759,6 +7573,8 @@
return TRUE;
if (chipid == BCM4358_CHIP_ID)
return TRUE;
+ if (chipid == BCM4371_CHIP_ID)
+ return TRUE;
if (chipid == BCM43430_CHIP_ID)
return TRUE;
if (BCM4349_CHIP(chipid))
@@ -6766,13 +7582,19 @@
return FALSE;
}
+#if defined(MULTIPLE_SUPPLICANT)
+extern void wl_android_post_init(void); // terence 20120530: fix critical section in dhd_open and dhdsdio_probe
+#endif
+
static void *
dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot,
uint16 func, uint bustype, void *regsva, osl_t * osh, void *sdh)
{
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))
@@ -6784,7 +7606,7 @@
}
mutex_lock(&_dhd_sdio_mutex_lock_);
#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
-#endif
+#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
@@ -6888,14 +7710,6 @@
goto fail;
}
-#ifdef PROP_TXSTATUS
- // terence 20131215: disable_proptx should be set before dhd_attach
- if ((bus->sih->chip == BCM43362_CHIP_ID) || (bus->sih->chip == BCM4330_CHIP_ID)) {
- printf("%s: Disable prop_txstatus\n", __FUNCTION__);
- disable_proptx = 1;
- }
-#endif
-
/* Attach to the dhd/OS/network interface */
if (!(bus->dhd = dhd_attach(osh, bus, SDPCM_RESERVE))) {
DHD_ERROR(("%s: dhd_attach failed\n", __FUNCTION__));
@@ -6932,21 +7746,16 @@
/* if firmware path present try to download and bring up bus */
bus->dhd->hang_report = TRUE;
+#if 1 // terence 20150325: fix for WPA/WPA2 4-way handshake fail in hostapd
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;
}
}
+#endif
-#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);
- }
-#else
+#ifdef GET_OTP_MAC_ENABLE
if (dhd_conf_get_mac(bus->dhd, sdh, ea_addr.octet)) {
DHD_TRACE(("%s: Can not read MAC address\n", __FUNCTION__));
} else
@@ -6961,11 +7770,12 @@
#if defined(MULTIPLE_SUPPLICANT)
+ wl_android_post_init(); // terence 20120530: fix critical section in dhd_open and dhdsdio_probe
#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
+#endif
init_waitqueue_head(&bus->bus_sleep);
@@ -6980,7 +7790,7 @@
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
+#endif
return NULL;
}
@@ -7281,7 +8091,7 @@
#if defined(DHD_DEBUG)
DHD_ERROR(("F1 signature read @0x18000000=0x%4x\n",
bcmsdh_reg_read(bus->sdh, SI_ENUM_BASE, 4)));
-#endif
+#endif
/* Force PLL off until si_attach() programs PLL control regs */
@@ -7414,13 +8224,16 @@
case BCM4354_CHIP_ID:
case BCM4356_CHIP_ID:
case BCM4358_CHIP_ID:
+ case BCM4371_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;
+ 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;
@@ -7614,6 +8427,10 @@
/* TX first in dhdsdio_readframes() */
bus->dotxinrx = TRUE;
+#ifdef PKT_STATICS
+ memset((uint8*) &tx_statics, 0, sizeof(pkt_statics_t));
+#endif
+
return TRUE;
}
@@ -7638,7 +8455,6 @@
{
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);
@@ -7648,16 +8464,30 @@
/* External conf takes precedence if specified */
dhd_conf_preinit(bus->dhd);
- dhd_conf_read_config(bus->dhd);
+ dhd_conf_read_config(bus->dhd, bus->dhd->conf_path);
dhd_conf_set_fw_name_by_chip(bus->dhd, bus->fw_path);
- dhd_conf_set_fw_path(bus->dhd, bus->fw_path);
- dhd_conf_set_nv_path(bus->dhd, bus->nv_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);
-
- printk("Final fw_path=%s\n", bus->fw_path);
- printk("Final nv_path=%s\n", bus->nv_path);
- printk("Final conf_path=%s\n", bus->dhd->conf_path);
+ if (bus->dhd->conf->dhd_poll >= 0) {
+ printf("%s: set polling mode %d\n", __FUNCTION__, bus->dhd->conf->dhd_poll);
+ bus->poll = bus->dhd->conf->dhd_poll;
+ 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);
+ printf("Final conf_path=%s\n", bus->dhd->conf_path);
ret = _dhdsdio_download_firmware(bus);
@@ -7788,7 +8618,7 @@
}
mutex_lock(&_dhd_sdio_mutex_lock_);
#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */
-#endif
+#endif
if (bus) {
@@ -7838,7 +8668,7 @@
if (dhd_os_check_if_up(bus->dhd))
bcmsdh_oob_intr_set(bus->sdh, TRUE);
-#endif
+#endif
return 0;
}
@@ -7988,7 +8818,7 @@
image = dhd_os_open_image(pfw_path);
if (image == NULL) {
- printk("%s: Open firmware file failed %s\n", __FUNCTION__, pfw_path);
+ printf("%s: Open firmware file failed %s\n", __FUNCTION__, pfw_path);
goto err;
}
@@ -8009,6 +8839,14 @@
/* Download image */
while ((len = dhd_os_get_image_block((char*)memptr, MEMBLOCK, image))) {
+ // 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 < 0) {
DHD_ERROR(("%s: dhd_os_get_image_block failed (%d)\n", __FUNCTION__, len));
bcmerror = BCME_ERROR;
@@ -8102,7 +8940,7 @@
if (nvram_file_exists) {
image = dhd_os_open_image(pnv_path);
if (image == NULL) {
- printk("%s: Open nvram file failed %s\n", __FUNCTION__, pnv_path);
+ printf("%s: Open nvram file failed %s\n", __FUNCTION__, pnv_path);
goto err;
}
}
@@ -8370,7 +9208,7 @@
dhd_enable_oob_intr(bus, FALSE);
bcmsdh_oob_intr_set(bus->sdh, FALSE);
bcmsdh_oob_intr_unregister(bus->sdh);
-#endif
+#endif
/* Clean tx/rx buffer pointers, detach from the dongle */
dhdsdio_release_dongle(bus, bus->dhd->osh, TRUE, TRUE);
@@ -8380,14 +9218,14 @@
dhd_txglom_enable(dhdp, FALSE);
dhd_os_sdunlock(dhdp);
- printk("%s: WLAN OFF DONE\n", __FUNCTION__);
+ printf("%s: WLAN OFF DONE\n", __FUNCTION__);
/* App can now remove power from device */
} else
bcmerror = BCME_SDIO_ERROR;
} else {
/* App must have restored power to device before calling */
- printk("\n\n%s: == WLAN ON ==\n", __FUNCTION__);
+ printf("\n\n%s: == WLAN ON ==\n", __FUNCTION__);
if (bus->dhd->dongle_reset) {
/* Turn on WLAN */
@@ -8411,7 +9249,9 @@
bcmsdh_oob_intr_register(bus->sdh,
dhdsdio_isr, bus);
bcmsdh_oob_intr_set(bus->sdh, TRUE);
-#endif
+#elif defined(FORCE_WOWLAN)
+ dhd_enable_oob_intr(bus, TRUE);
+#endif
bus->dhd->dongle_reset = FALSE;
bus->dhd->up = TRUE;
@@ -8419,7 +9259,7 @@
#if !defined(IGNORE_ETH0_DOWN)
/* Restore flow control */
dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF);
-#endif
+#endif
dhd_os_wd_timer(dhdp, dhd_watchdog_ms);
DHD_TRACE(("%s: WLAN ON DONE\n", __FUNCTION__));
@@ -8436,11 +9276,11 @@
dhd_os_sdunlock(dhdp);
} else {
bcmerror = BCME_SDIO_ERROR;
- printk("%s called when dongle is not in reset\n",
+ printf("%s called when dongle is not in reset\n",
__FUNCTION__);
- printk("Will call dhd_bus_start instead\n");
+ 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)
@@ -8448,6 +9288,10 @@
__FUNCTION__, bcmerror));
}
}
+
+#ifdef PKT_STATICS
+ memset((uint8*) &tx_statics, 0, sizeof(pkt_statics_t));
+#endif
return bcmerror;
}
diff -Nur a/drivers/net/wireless/bcmdhd/dhd_static_buf.c c/drivers/net/wireless/bcmdhd/dhd_static_buf.c
--- a/drivers/net/wireless/bcmdhd/dhd_static_buf.c 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/dhd_static_buf.c 2016-05-13 09:48:20.000000000 +0200
@@ -1,171 +1,179 @@
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/skbuff.h>
-#include <linux/wlan_plat.h>
-
-#define CONFIG_BROADCOM_WIFI_RESERVED_MEM
-
-#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM
-
-#define WLAN_STATIC_PKT_BUF 4
-#define WLAN_STATIC_SCAN_BUF0 5
-#define WLAN_STATIC_SCAN_BUF1 6
-#define WLAN_STATIC_DHD_INFO 7
-#define PREALLOC_WLAN_SEC_NUM 5
-#define PREALLOC_WLAN_BUF_NUM 160
-#define PREALLOC_WLAN_SECTION_HEADER 24
-
-#define WLAN_SECTION_SIZE_0 (PREALLOC_WLAN_BUF_NUM * 128)
-#define WLAN_SECTION_SIZE_1 (PREALLOC_WLAN_BUF_NUM * 128)
-#define WLAN_SECTION_SIZE_2 (PREALLOC_WLAN_BUF_NUM * 512)
-#define WLAN_SECTION_SIZE_3 (PREALLOC_WLAN_BUF_NUM * 1024)
-#define WLAN_SECTION_SIZE_7 (PREALLOC_WLAN_BUF_NUM * 128)
-
-#define DHD_SKB_HDRSIZE 336
-#define DHD_SKB_1PAGE_BUFSIZE ((PAGE_SIZE*1)-DHD_SKB_HDRSIZE)
-#define DHD_SKB_2PAGE_BUFSIZE ((PAGE_SIZE*2)-DHD_SKB_HDRSIZE)
-#define DHD_SKB_4PAGE_BUFSIZE ((PAGE_SIZE*4)-DHD_SKB_HDRSIZE)
-
-#define WLAN_SKB_BUF_NUM 17
-
-static struct sk_buff *wlan_static_skb[WLAN_SKB_BUF_NUM];
-
-struct wlan_mem_prealloc {
- void *mem_ptr;
- unsigned long size;
-};
-
-static struct wlan_mem_prealloc wlan_mem_array[PREALLOC_WLAN_SEC_NUM] = {
- {NULL, (WLAN_SECTION_SIZE_0 + PREALLOC_WLAN_SECTION_HEADER)},
- {NULL, (WLAN_SECTION_SIZE_1 + PREALLOC_WLAN_SECTION_HEADER)},
- {NULL, (WLAN_SECTION_SIZE_2 + PREALLOC_WLAN_SECTION_HEADER)},
- {NULL, (WLAN_SECTION_SIZE_3 + PREALLOC_WLAN_SECTION_HEADER)},
- {NULL, (WLAN_SECTION_SIZE_7 + PREALLOC_WLAN_SECTION_HEADER)}
-};
-
-void *wlan_static_scan_buf0;
-void *wlan_static_scan_buf1;
-void *bcmdhd_mem_prealloc(int section, unsigned long size)
-{
- if (section == WLAN_STATIC_PKT_BUF) {
- printk("1 %s: section=%d, wlan_static_skb=%p\n",
- __FUNCTION__, section, wlan_static_skb);
- return wlan_static_skb;
- }
- if (section == WLAN_STATIC_SCAN_BUF0) {
- printk("2 %s: section=%d, wlan_static_scan_buf0=%p\n",
- __FUNCTION__, section, wlan_static_scan_buf0);
- return wlan_static_scan_buf0;
- }
- if (section == WLAN_STATIC_SCAN_BUF1) {
- printk("3 %s: section=%d, wlan_static_scan_buf1=%p\n",
- __FUNCTION__, section, wlan_static_scan_buf1);
- return wlan_static_scan_buf1;
- }
- if (section == WLAN_STATIC_DHD_INFO) {
- printk("4 %s: section=%d, wlan_mem_array[4]=%p\n",
- __FUNCTION__, section, wlan_mem_array[4].mem_ptr);
- return wlan_mem_array[4].mem_ptr;
- }
- if ((section < 0) || (section > PREALLOC_WLAN_SEC_NUM)) {
- printk("5 %s: out of section %d\n", __FUNCTION__, section);
- return NULL;
- }
-
- if (wlan_mem_array[section].size < size) {
- printk("6 %s: wlan_mem_array[section].size=%lu, size=%lu\n",
- __FUNCTION__, wlan_mem_array[section].size, size);
- return NULL;
- }
- printk("7 %s: wlan_mem_array[section].mem_ptr=%p, size=%lu\n",
- __FUNCTION__, &wlan_mem_array[section], size);
-
- return wlan_mem_array[section].mem_ptr;
-}
-
-EXPORT_SYMBOL(bcmdhd_mem_prealloc);
-
-int bcmdhd_init_wlan_mem(void)
-{
- int i;
- int j;
-
- for (i=0; i<8; i++) {
- wlan_static_skb[i] = dev_alloc_skb(DHD_SKB_1PAGE_BUFSIZE);
- if (!wlan_static_skb[i])
- goto err_skb_alloc;
- printk("1 %s: wlan_static_skb[%d]=%p, size=%lu\n",
- __FUNCTION__, i, wlan_static_skb[i], DHD_SKB_1PAGE_BUFSIZE);
- }
-
- for (; i<16; i++) {
- wlan_static_skb[i] = dev_alloc_skb(DHD_SKB_2PAGE_BUFSIZE);
- if (!wlan_static_skb[i])
- goto err_skb_alloc;
- printk("2 %s: wlan_static_skb[%d]=%p, size=%lu\n",
- __FUNCTION__, i, wlan_static_skb[i], DHD_SKB_2PAGE_BUFSIZE);
- }
-
- wlan_static_skb[i] = dev_alloc_skb(DHD_SKB_4PAGE_BUFSIZE);
- if (!wlan_static_skb[i])
- goto err_skb_alloc;
- printk("3 %s: wlan_static_skb[%d]=%p, size=%lu\n",
- __FUNCTION__, i, wlan_static_skb[i], DHD_SKB_4PAGE_BUFSIZE);
-
- for (i=0; i<PREALLOC_WLAN_SEC_NUM; i++) {
- wlan_mem_array[i].mem_ptr =
- kmalloc(wlan_mem_array[i].size, GFP_KERNEL);
-
- if (!wlan_mem_array[i].mem_ptr)
- goto err_mem_alloc;
- printk("4 %s: wlan_mem_array[%d]=%p, size=%lu\n",
- __FUNCTION__, i, wlan_static_skb[i], wlan_mem_array[i].size);
- }
-
- wlan_static_scan_buf0 = kmalloc (65536, GFP_KERNEL);
- if(!wlan_static_scan_buf0)
- goto err_mem_alloc;
- printk("5 %s: wlan_static_scan_buf0=%p, size=%d\n",
- __FUNCTION__, wlan_static_scan_buf0, 65536);
-
- wlan_static_scan_buf1 = kmalloc (65536, GFP_KERNEL);
- if(!wlan_static_scan_buf1)
- goto err_mem_alloc;
- printk("6 %s: wlan_static_scan_buf1=%p, size=%d\n",
- __FUNCTION__, wlan_static_scan_buf1, 65536);
-
- printk("%s: WIFI MEM Allocated\n", __FUNCTION__);
- return 0;
-
-err_mem_alloc:
- pr_err("Failed to mem_alloc for WLAN\n");
- for (j=0; j<i; j++)
- kfree(wlan_mem_array[j].mem_ptr);
-
- i = WLAN_SKB_BUF_NUM;
-
-err_skb_alloc:
- pr_err("Failed to skb_alloc for WLAN\n");
- for (j=0; j<i; j++)
- dev_kfree_skb(wlan_static_skb[j]);
-
- return -ENOMEM;
-}
-#endif /* CONFIG_BROADCOM_WIFI_RESERVED_MEM */
-
-static int __init bcmdhd_wlan_init(void)
-{
- printk("%s()\n", __FUNCTION__);
-
-#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM
- bcmdhd_init_wlan_mem();
-#endif
-
- return 0;
-}
-
-__initcall(bcmdhd_wlan_init);
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/skbuff.h>
+#include <linux/wlan_plat.h>
+
+#define CONFIG_BROADCOM_WIFI_RESERVED_MEM
+
+#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM
+
+#define WLAN_STATIC_PKT_BUF 4
+#define WLAN_STATIC_SCAN_BUF0 5
+#define WLAN_STATIC_SCAN_BUF1 6
+#define WLAN_STATIC_DHD_INFO 7
+#define WLAN_STATIC_DHD_WLFC_INFO 8
+#define PREALLOC_WLAN_SEC_NUM 6
+#define PREALLOC_WLAN_BUF_NUM 160
+#define PREALLOC_WLAN_SECTION_HEADER 24
+
+#define WLAN_SECTION_SIZE_0 (PREALLOC_WLAN_BUF_NUM * 128)
+#define WLAN_SECTION_SIZE_1 (PREALLOC_WLAN_BUF_NUM * 128)
+#define WLAN_SECTION_SIZE_2 (PREALLOC_WLAN_BUF_NUM * 512)
+#define WLAN_SECTION_SIZE_3 (PREALLOC_WLAN_BUF_NUM * 1024)
+#define WLAN_SECTION_SIZE_7 (PREALLOC_WLAN_BUF_NUM * 128)
+#define WLAN_SECTION_SIZE_8 (PREALLOC_WLAN_BUF_NUM * 512)
+
+#define DHD_SKB_HDRSIZE 336
+#define DHD_SKB_1PAGE_BUFSIZE ((PAGE_SIZE*1)-DHD_SKB_HDRSIZE)
+#define DHD_SKB_2PAGE_BUFSIZE ((PAGE_SIZE*2)-DHD_SKB_HDRSIZE)
+#define DHD_SKB_4PAGE_BUFSIZE ((PAGE_SIZE*4)-DHD_SKB_HDRSIZE)
+
+#define WLAN_SKB_BUF_NUM 17
+
+static struct sk_buff *wlan_static_skb[WLAN_SKB_BUF_NUM];
+
+struct wlan_mem_prealloc {
+ void *mem_ptr;
+ unsigned long size;
+};
+
+static struct wlan_mem_prealloc wlan_mem_array[PREALLOC_WLAN_SEC_NUM] = {
+ {NULL, (WLAN_SECTION_SIZE_0 + PREALLOC_WLAN_SECTION_HEADER)},
+ {NULL, (WLAN_SECTION_SIZE_1 + PREALLOC_WLAN_SECTION_HEADER)},
+ {NULL, (WLAN_SECTION_SIZE_2 + PREALLOC_WLAN_SECTION_HEADER)},
+ {NULL, (WLAN_SECTION_SIZE_3 + PREALLOC_WLAN_SECTION_HEADER)},
+ {NULL, (WLAN_SECTION_SIZE_7 + PREALLOC_WLAN_SECTION_HEADER)},
+ {NULL, (WLAN_SECTION_SIZE_8 + PREALLOC_WLAN_SECTION_HEADER)}
+};
+
+void *wlan_static_scan_buf0;
+void *wlan_static_scan_buf1;
+void *bcmdhd_mem_prealloc(int section, unsigned long size)
+{
+ if (section == WLAN_STATIC_PKT_BUF) {
+ printk("1 %s: section=%d, wlan_static_skb=%p\n",
+ __FUNCTION__, section, wlan_static_skb);
+ return wlan_static_skb;
+ }
+ if (section == WLAN_STATIC_SCAN_BUF0) {
+ printk("2 %s: section=%d, wlan_static_scan_buf0=%p\n",
+ __FUNCTION__, section, wlan_static_scan_buf0);
+ return wlan_static_scan_buf0;
+ }
+ if (section == WLAN_STATIC_SCAN_BUF1) {
+ printk("3 %s: section=%d, wlan_static_scan_buf1=%p\n",
+ __FUNCTION__, section, wlan_static_scan_buf1);
+ return wlan_static_scan_buf1;
+ }
+ if (section == WLAN_STATIC_DHD_INFO) {
+ printk("4 %s: section=%d, wlan_mem_array[4]=%p\n",
+ __FUNCTION__, section, wlan_mem_array[4].mem_ptr);
+ return wlan_mem_array[4].mem_ptr;
+ }
+ if (section == WLAN_STATIC_DHD_WLFC_INFO) {
+ printk("5 %s: section=%d, wlan_mem_array[5]=%p\n",
+ __FUNCTION__, section, wlan_mem_array[5].mem_ptr);
+ return wlan_mem_array[5].mem_ptr;
+ }
+ if ((section < 0) || (section > PREALLOC_WLAN_SEC_NUM)) {
+ printk("6 %s: out of section %d\n", __FUNCTION__, section);
+ return NULL;
+ }
+
+ if (wlan_mem_array[section].size < size) {
+ printk("7 %s: wlan_mem_array[section].size=%lu, size=%lu\n",
+ __FUNCTION__, wlan_mem_array[section].size, size);
+ return NULL;
+ }
+ printk("8 %s: wlan_mem_array[section].mem_ptr=%p, size=%lu\n",
+ __FUNCTION__, &wlan_mem_array[section], size);
+
+ return wlan_mem_array[section].mem_ptr;
+}
+
+EXPORT_SYMBOL(bcmdhd_mem_prealloc);
+
+int bcmdhd_init_wlan_mem(void)
+{
+ int i;
+ int j;
+
+ for (i=0; i<8; i++) {
+ wlan_static_skb[i] = dev_alloc_skb(DHD_SKB_1PAGE_BUFSIZE);
+ if (!wlan_static_skb[i])
+ goto err_skb_alloc;
+ printk("1 %s: wlan_static_skb[%d]=%p, size=%lu\n",
+ __FUNCTION__, i, wlan_static_skb[i], DHD_SKB_1PAGE_BUFSIZE);
+ }
+
+ for (; i<16; i++) {
+ wlan_static_skb[i] = dev_alloc_skb(DHD_SKB_2PAGE_BUFSIZE);
+ if (!wlan_static_skb[i])
+ goto err_skb_alloc;
+ printk("2 %s: wlan_static_skb[%d]=%p, size=%lu\n",
+ __FUNCTION__, i, wlan_static_skb[i], DHD_SKB_2PAGE_BUFSIZE);
+ }
+
+ wlan_static_skb[i] = dev_alloc_skb(DHD_SKB_4PAGE_BUFSIZE);
+ if (!wlan_static_skb[i])
+ goto err_skb_alloc;
+ printk("3 %s: wlan_static_skb[%d]=%p, size=%lu\n",
+ __FUNCTION__, i, wlan_static_skb[i], DHD_SKB_4PAGE_BUFSIZE);
+
+ for (i=0; i<PREALLOC_WLAN_SEC_NUM; i++) {
+ wlan_mem_array[i].mem_ptr =
+ kmalloc(wlan_mem_array[i].size, GFP_KERNEL);
+
+ if (!wlan_mem_array[i].mem_ptr)
+ goto err_mem_alloc;
+ printk("4 %s: wlan_mem_array[%d]=%p, size=%lu\n",
+ __FUNCTION__, i, wlan_static_skb[i], wlan_mem_array[i].size);
+ }
+
+ wlan_static_scan_buf0 = kmalloc (65536, GFP_KERNEL);
+ if (!wlan_static_scan_buf0)
+ goto err_mem_alloc;
+ printk("5 %s: wlan_static_scan_buf0=%p, size=%d\n",
+ __FUNCTION__, wlan_static_scan_buf0, 65536);
+
+ wlan_static_scan_buf1 = kmalloc (65536, GFP_KERNEL);
+ if (!wlan_static_scan_buf1)
+ goto err_mem_alloc;
+ printk("6 %s: wlan_static_scan_buf1=%p, size=%d\n",
+ __FUNCTION__, wlan_static_scan_buf1, 65536);
+
+ printk("%s: WIFI MEM Allocated\n", __FUNCTION__);
+ return 0;
+
+err_mem_alloc:
+ pr_err("Failed to mem_alloc for WLAN\n");
+ for (j=0; j<i; j++)
+ kfree(wlan_mem_array[j].mem_ptr);
+
+ i = WLAN_SKB_BUF_NUM;
+
+err_skb_alloc:
+ pr_err("Failed to skb_alloc for WLAN\n");
+ for (j=0; j<i; j++)
+ dev_kfree_skb(wlan_static_skb[j]);
+
+ return -ENOMEM;
+}
+#endif /* CONFIG_BROADCOM_WIFI_RESERVED_MEM */
+
+static int __init bcmdhd_wlan_init(void)
+{
+ printk("%s()\n", __FUNCTION__);
+
+#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM
+ bcmdhd_init_wlan_mem();
+#endif
+
+ return 0;
+}
+
+__initcall(bcmdhd_wlan_init);
diff -Nur a/drivers/net/wireless/bcmdhd/dhd_wlfc.c c/drivers/net/wireless/bcmdhd/dhd_wlfc.c
--- a/drivers/net/wireless/bcmdhd/dhd_wlfc.c 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/dhd_wlfc.c 2016-05-13 09:48:20.000000000 +0200
@@ -3,7 +3,7 @@
*
* $Copyright Open Broadcom Corporation$
*
- * $Id: dhd_wlfc.c 490028 2014-07-09 05:58:25Z $
+ * $Id: dhd_wlfc.c 501046 2014-09-06 01:25:16Z $
*
*/
@@ -23,9 +23,7 @@
#include <wlfc_proto.h>
#include <dhd_wlfc.h>
#endif
-#ifdef DHDTCPACK_SUPPRESS
#include <dhd_ip.h>
-#endif /* DHDTCPACK_SUPPRESS */
/*
@@ -444,7 +442,7 @@
}
static int
-_dhd_wlfc_pushheader(athost_wl_status_info_t* ctx, void* p, bool tim_signal,
+_dhd_wlfc_pushheader(athost_wl_status_info_t* ctx, void** packet, bool tim_signal,
uint8 tim_bmp, uint8 mac_handle, uint32 htodtag, uint16 htodseq, bool skip_wlfc_hdr)
{
uint32 wl_pktinfo = 0;
@@ -455,6 +453,7 @@
dhd_pub_t *dhdp = (dhd_pub_t *)ctx->dhdp;
struct bdc_header *h;
+ void *p = *packet;
if (skip_wlfc_hdr)
goto push_bdc_hdr;
@@ -512,6 +511,7 @@
h->flags2 = 0;
h->dataOffset = dataOffset >> 2;
BDC_SET_IF_IDX(h, DHD_PKTTAG_IF(PKTTAG(p)));
+ *packet = p;
return BCME_OK;
}
@@ -559,8 +559,7 @@
* STA/GC gets the Mac Entry for TDLS destinations, TDLS destinations
* have their own entry.
*/
- if ((iftype == WLC_E_IF_ROLE_STA || ETHER_ISMULTI(dstn) ||
- iftype == WLC_E_IF_ROLE_P2P_CLIENT) &&
+ if ((DHD_IF_ROLE_STA(iftype) || ETHER_ISMULTI(dstn)) &&
(ctx->destination_entries.interfaces[ifid].occupied)) {
entry = &ctx->destination_entries.interfaces[ifid];
}
@@ -612,7 +611,7 @@
/* pkt in delayed q, so fake push BDC header for
* dhd_tcpack_check_xmit() and dhd_txcomplete().
*/
- _dhd_wlfc_pushheader(ctx, p, FALSE, 0, 0, 0, 0, TRUE);
+ _dhd_wlfc_pushheader(ctx, &p, FALSE, 0, 0, 0, 0, TRUE);
/* This packet is about to be freed, so remove it from tcp_ack_info_tbl
* This must be one of...
@@ -877,7 +876,7 @@
if (p) {
PKTPULL(ctx->osh, p, dummylen);
DHD_PKTTAG_SET_H2DTAG(PKTTAG(p), 0);
- _dhd_wlfc_pushheader(ctx, p, TRUE, ta_bmp, entry->mac_handle, 0, 0, FALSE);
+ _dhd_wlfc_pushheader(ctx, &p, TRUE, ta_bmp, entry->mac_handle, 0, 0, FALSE);
DHD_PKTTAG_SETSIGNALONLY(PKTTAG(p), 1);
DHD_PKTTAG_WLFCPKT_SET(PKTTAG(p), 1);
#ifdef PROP_TXSTATUS_DEBUG
@@ -974,16 +973,17 @@
static int
_dhd_wlfc_pretx_pktprocess(athost_wl_status_info_t* ctx,
- wlfc_mac_descriptor_t* entry, void* p, int header_needed, uint32* slot)
+ wlfc_mac_descriptor_t* entry, void** packet, int header_needed, uint32* slot)
{
int rc = BCME_OK;
int hslot = WLFC_HANGER_MAXITEMS;
bool send_tim_update = FALSE;
uint32 htod = 0;
uint16 htodseq = 0;
- uint8 free_ctr;
+ uint8 free_ctr, flags = 0;
int gen = 0xff;
dhd_pub_t *dhdp = (dhd_pub_t *)ctx->dhdp;
+ void * p = *packet;
*slot = hslot;
@@ -1035,24 +1035,26 @@
return BCME_ERROR;
}
- WL_TXSTATUS_SET_FREERUNCTR(htod, free_ctr);
- WL_TXSTATUS_SET_HSLOT(htod, hslot);
- WL_TXSTATUS_SET_FIFO(htod, DHD_PKTTAG_FIFO(PKTTAG(p)));
- WL_TXSTATUS_SET_FLAGS(htod, WLFC_PKTFLAG_PKTFROMHOST);
- WL_TXSTATUS_SET_GENERATION(htod, gen);
- DHD_PKTTAG_SETPKTDIR(PKTTAG(p), 1);
-
+ flags = WLFC_PKTFLAG_PKTFROMHOST;
if (!DHD_PKTTAG_CREDITCHECK(PKTTAG(p))) {
/*
Indicate that this packet is being sent in response to an
explicit request from the firmware side.
*/
- WLFC_PKTFLAG_SET_PKTREQUESTED(htod);
- } else {
- WLFC_PKTFLAG_CLR_PKTREQUESTED(htod);
+ flags |= WLFC_PKTFLAG_PKT_REQUESTED;
+ }
+ if (pkt_is_dhcp(ctx->osh, p)) {
+ flags |= WLFC_PKTFLAG_PKT_FORCELOWRATE;
}
- rc = _dhd_wlfc_pushheader(ctx, p, send_tim_update,
+ WL_TXSTATUS_SET_FREERUNCTR(htod, free_ctr);
+ WL_TXSTATUS_SET_HSLOT(htod, hslot);
+ WL_TXSTATUS_SET_FIFO(htod, DHD_PKTTAG_FIFO(PKTTAG(p)));
+ WL_TXSTATUS_SET_FLAGS(htod, flags);
+ WL_TXSTATUS_SET_GENERATION(htod, gen);
+ DHD_PKTTAG_SETPKTDIR(PKTTAG(p), 1);
+
+ rc = _dhd_wlfc_pushheader(ctx, &p, send_tim_update,
entry->traffic_lastreported_bmp, entry->mac_handle, htod, htodseq, FALSE);
if (rc == BCME_OK) {
DHD_PKTTAG_SET_H2DTAG(PKTTAG(p), htod);
@@ -1081,6 +1083,7 @@
}
}
*slot = hslot;
+ *packet = p;
return rc;
}
@@ -1147,6 +1150,11 @@
}
ASSERT(entry);
+ if (entry->transit_count < 0) {
+ DHD_ERROR(("Error: %s():%d transit_count %d < 0\n",
+ __FUNCTION__, __LINE__, entry->transit_count));
+ continue;
+ }
if (entry->occupied && _dhd_wlfc_is_destination_open(ctx, entry, prec) &&
(entry->transit_count < WL_TXSTATUS_FREERUNCTR_MASK) &&
!(WLFC_GET_REORDERSUPP(dhdp->wlfc_mode) && entry->suppressed)) {
@@ -1346,7 +1354,9 @@
} else {
if (item->pkt_state & WLFC_HANGER_PKT_STATE_TXSTATUS) {
/* free slot */
- ASSERT(item->state != WLFC_HANGER_ITEM_STATE_FREE);
+ if (item->state == WLFC_HANGER_ITEM_STATE_FREE)
+ DHD_ERROR(("Error: %s():%d get multi TXSTATUS for one packet???\n",
+ __FUNCTION__, __LINE__));
item->state = WLFC_HANGER_ITEM_STATE_FREE;
}
}
@@ -1393,7 +1403,7 @@
/* pkt in delayed q, so fake push BDC header for
* dhd_tcpack_check_xmit() and dhd_txcomplete().
*/
- _dhd_wlfc_pushheader(ctx, p, FALSE, 0, 0,
+ _dhd_wlfc_pushheader(ctx, &p, FALSE, 0, 0,
0, 0, TRUE);
#ifdef DHDTCPACK_SUPPRESS
if (dhd_tcpack_check_xmit(dhdp, p) == BCME_ERROR) {
@@ -1636,6 +1646,18 @@
memcpy(&entry->ea[0], ea, ETHER_ADDR_LEN);
if (action == eWLFC_MAC_ENTRY_ACTION_ADD) {
+ entry->suppressed = FALSE;
+ entry->transit_count = 0;
+ entry->suppr_transit_count = 0;
+ }
+
+#ifdef P2PONEINT
+ if ((action == eWLFC_MAC_ENTRY_ACTION_ADD) ||
+ ((action == eWLFC_MAC_ENTRY_ACTION_UPDATE) && (entry->psq.num_prec == 0)))
+#else
+ if (action == eWLFC_MAC_ENTRY_ACTION_ADD)
+#endif
+ {
dhd_pub_t *dhdp = (dhd_pub_t *)(ctx->dhdp);
pktq_init(&entry->psq, WLFC_PSQ_PREC_COUNT, WLFC_PSQ_LEN);
if (WLFC_GET_AFQ(dhdp->wlfc_mode)) {
@@ -1669,11 +1691,7 @@
_dhd_wlfc_flow_control_check(ctx, &entry->psq, ifid);
entry->occupied = 0;
- entry->suppressed = 0;
entry->state = WLFC_STATE_CLOSE;
- entry->requested_credit = 0;
- entry->transit_count = 0;
- entry->suppr_transit_count = 0;
memset(&entry->ea[0], 0, ETHER_ADDR_LEN);
if (entry->next) {
@@ -1826,7 +1844,7 @@
credit count.
*/
DHD_PKTTAG_SETCREDITCHECK(PKTTAG(commit_info->p), commit_info->ac_fifo_credit_spent);
- rc = _dhd_wlfc_pretx_pktprocess(ctx, commit_info->mac_entry, commit_info->p,
+ rc = _dhd_wlfc_pretx_pktprocess(ctx, commit_info->mac_entry, &commit_info->p,
commit_info->needs_hdr, &hslot);
if (rc == BCME_OK) {
@@ -2505,7 +2523,8 @@
}
/* allocate space to track txstatus propagated from firmware */
- dhd->wlfc_state = MALLOC(dhd->osh, sizeof(athost_wl_status_info_t));
+ dhd->wlfc_state = DHD_OS_PREALLOC(dhd, DHD_PREALLOC_DHD_WLFC_INFO,
+ sizeof(athost_wl_status_info_t));
if (dhd->wlfc_state == NULL) {
rc = BCME_NOMEM;
goto exit;
@@ -2522,7 +2541,8 @@
if (!WLFC_GET_AFQ(dhd->wlfc_mode)) {
wlfc->hanger = _dhd_wlfc_hanger_create(dhd->osh, WLFC_HANGER_MAXITEMS);
if (wlfc->hanger == NULL) {
- MFREE(dhd->osh, dhd->wlfc_state, sizeof(athost_wl_status_info_t));
+ DHD_OS_PREFREE(dhd, dhd->wlfc_state,
+ sizeof(athost_wl_status_info_t));
dhd->wlfc_state = NULL;
rc = BCME_NOMEM;
goto exit;
@@ -2780,7 +2800,7 @@
if (pktbuf) {
uint32 htod = 0;
WL_TXSTATUS_SET_FLAGS(htod, WLFC_PKTFLAG_PKTFROMHOST);
- _dhd_wlfc_pushheader(ctx, pktbuf, FALSE, 0, 0, htod, 0, FALSE);
+ _dhd_wlfc_pushheader(ctx, &pktbuf, FALSE, 0, 0, htod, 0, FALSE);
if (fcommit(commit_ctx, pktbuf))
PKTFREE(ctx->osh, pktbuf, TRUE);
rc = BCME_OK;
@@ -3351,7 +3371,8 @@
/* free top structure */
- MFREE(dhd->osh, dhd->wlfc_state, sizeof(athost_wl_status_info_t));
+ DHD_OS_PREFREE(dhd, dhd->wlfc_state,
+ sizeof(athost_wl_status_info_t));
dhd->wlfc_state = NULL;
dhd->proptxstatus_mode = hostreorder ?
WLFC_ONLY_AMPDU_HOSTREORDER : WLFC_FCMODE_NONE;
diff -Nur a/drivers/net/wireless/bcmdhd/dhd_wlfc.h c/drivers/net/wireless/bcmdhd/dhd_wlfc.h
--- a/drivers/net/wireless/bcmdhd/dhd_wlfc.h 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/dhd_wlfc.h 2016-05-13 09:48:20.000000000 +0200
@@ -1,6 +1,6 @@
/*
* $Copyright Open 2009 Broadcom Corporation$
-* $Id: dhd_wlfc.h 490028 2014-07-09 05:58:25Z $
+* $Id: dhd_wlfc.h 501046 2014-09-06 01:25:16Z $
*
*/
#ifndef __wlfc_host_driver_definitions_h__
@@ -115,9 +115,9 @@
uint8 send_tim_signal;
uint8 mac_handle;
/* Number of packets at dongle for this entry. */
- uint transit_count;
+ int transit_count;
/* Numbe of suppression to wait before evict from delayQ */
- uint suppr_transit_count;
+ int suppr_transit_count;
/* flag. TRUE when in suppress state */
uint8 suppressed;
diff -Nur a/drivers/net/wireless/bcmdhd/hnd_pktq.c c/drivers/net/wireless/bcmdhd/hnd_pktq.c
--- a/drivers/net/wireless/bcmdhd/hnd_pktq.c 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/hnd_pktq.c 2016-05-13 09:48:20.000000000 +0200
@@ -573,6 +573,12 @@
q->len--;
+ // terence 20150308: fix for non-null pointer of skb->prev sent from ndo_start_xmit
+ if (q->len == 0) {
+ q->head = NULL;
+ q->tail = NULL;
+ }
+
if (prec_out)
*prec_out = prec;
diff -Nur a/drivers/net/wireless/bcmdhd/include/bcmdefs.h c/drivers/net/wireless/bcmdhd/include/bcmdefs.h
--- a/drivers/net/wireless/bcmdhd/include/bcmdefs.h 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/include/bcmdefs.h 2016-05-13 09:48:20.000000000 +0200
@@ -230,7 +230,7 @@
#if defined(BCMASSERT_LOG)
#define BCMASSERT_SUPPORT
-#endif
+#endif
/* Macros for doing definition and get/set of bitfields
* Usage example, e.g. a three-bit field (bits 4-6):
diff -Nur a/drivers/net/wireless/bcmdhd/include/bcmdevs.h c/drivers/net/wireless/bcmdhd/include/bcmdevs.h
--- a/drivers/net/wireless/bcmdhd/include/bcmdevs.h 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/include/bcmdevs.h 2016-05-13 09:48:20.000000000 +0200
@@ -352,6 +352,7 @@
#define BCM43569_CHIP_ID 0xAA31 /* 43569 chipcommon chipid */
#define BCM43570_CHIP_ID 0xAA32 /* 43570 chipcommon chipid */
#define BCM4358_CHIP_ID 0x4358 /* 4358 chipcommon chipid */
+#define BCM4371_CHIP_ID 0x4371 /* 4371 chipcommon chipid */
#define BCM4350_CHIP(chipid) ((CHIPID(chipid) == BCM4350_CHIP_ID) || \
(CHIPID(chipid) == BCM4354_CHIP_ID) || \
(CHIPID(chipid) == BCM4356_CHIP_ID) || \
@@ -364,6 +365,7 @@
(CHIPID(chipid) == BCM43570_CHIP_ID) || \
(CHIPID(chipid) == BCM4358_CHIP_ID)) /* 4350 variations */
#define BCM4345_CHIP_ID 0x4345 /* 4345 chipcommon chipid */
+#define BCM43454_CHIP_ID 43454 /* 43454 chipcommon chipid */
#define BCM43430_CHIP_ID 43430 /* 43430 chipcommon chipid */
#define BCM4349_CHIP_ID 0x4349 /* 4349 chipcommon chipid */
#define BCM4355_CHIP_ID 0x4355 /* 4355 chipcommon chipid */
diff -Nur a/drivers/net/wireless/bcmdhd/include/bcmmsgbuf.h c/drivers/net/wireless/bcmdhd/include/bcmmsgbuf.h
--- a/drivers/net/wireless/bcmdhd/include/bcmmsgbuf.h 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/include/bcmmsgbuf.h 2016-05-13 09:48:20.000000000 +0200
@@ -6,7 +6,7 @@
*
* $Copyright Open Broadcom Corporation$
*
- * $Id: bcmmsgbuf.h 490808 2014-07-12 00:33:13Z $
+ * $Id: bcmmsgbuf.h 499474 2014-08-28 21:30:10Z $
*/
#ifndef _bcmmsgbuf_h_
#define _bcmmsgbuf_h_
@@ -479,7 +479,7 @@
uint16 metadata_buf_len;
/* provided data buffer len to receive data */
uint16 data_len;
- uint32 rsvd;
+ uint32 flag2;
} host_txbuf_post_t;
#define BCMPCIE_PKT_FLAGS_FRAME_802_3 0x01
@@ -498,6 +498,9 @@
#define BCMPCIE_TXPOST_FLAGS_PRIO_SHIFT BCMPCIE_PKT_FLAGS_PRIO_SHIFT
#define BCMPCIE_TXPOST_FLAGS_PRIO_MASK BCMPCIE_PKT_FLAGS_PRIO_MASK
+#define BCMPCIE_PKT_FLAGS2_FORCELOWRATE_MASK 0x01
+#define BCMPCIE_PKT_FLAGS2_FORCELOWRATE_SHIFT 0
+
/* H2D Txpost ring work items */
typedef union txbuf_submit_item {
host_txbuf_post_t txpost;
diff -Nur a/drivers/net/wireless/bcmdhd/include/bcmpcie.h c/drivers/net/wireless/bcmdhd/include/bcmpcie.h
--- a/drivers/net/wireless/bcmdhd/include/bcmpcie.h 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/include/bcmpcie.h 2016-05-13 09:48:20.000000000 +0200
@@ -4,7 +4,7 @@
* Explains the shared area between host and dongle
* $Copyright Open 2005 Broadcom Corporation$
*
- * $Id: bcmpcie.h 490808 2014-07-12 00:33:13Z $
+ * $Id: bcmpcie.h 497456 2014-08-19 15:06:33Z $
*/
#ifndef _bcmpcie_h_
@@ -46,6 +46,12 @@
#define PCIE_SHARED_EVT_SEQNUM 0x08000
#define PCIE_SHARED_DMA_INDEX 0x10000
+/* D2H M2M DMA Complete Sync mechanism: Modulo-253-SeqNum or XORCSUM */
+#define PCIE_SHARED_D2H_SYNC_SEQNUM 0x20000
+#define PCIE_SHARED_D2H_SYNC_XORCSUM 0x40000
+#define PCIE_SHARED_D2H_SYNC_MODE_MASK \
+ (PCIE_SHARED_D2H_SYNC_SEQNUM | PCIE_SHARED_D2H_SYNC_XORCSUM)
+
#define BCMPCIE_H2D_MSGRING_CONTROL_SUBMIT 0
#define BCMPCIE_H2D_MSGRING_RXPOST_SUBMIT 1
#define BCMPCIE_D2H_MSGRING_CONTROL_COMPLETE 2
diff -Nur a/drivers/net/wireless/bcmdhd/include/bcmsdbus.h c/drivers/net/wireless/bcmdhd/include/bcmsdbus.h
--- a/drivers/net/wireless/bcmdhd/include/bcmsdbus.h 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/include/bcmsdbus.h 2016-05-13 09:48:20.000000000 +0200
@@ -122,4 +122,14 @@
extern SDIOH_API_RC sdioh_gpioouten(sdioh_info_t *sd, uint32 gpio);
extern SDIOH_API_RC sdioh_gpioout(sdioh_info_t *sd, uint32 gpio, bool enab);
+extern uint sdioh_set_mode(sdioh_info_t *sd, uint mode);
+#if defined(SWTXGLOM)
+/* read or write any buffer using cmd53 */
+extern SDIOH_API_RC sdioh_request_swtxglom_buffer(sdioh_info_t *si, uint pio_dma, uint fix_inc,
+ uint rw, uint fnc_num, uint32 addr, uint regwidth, uint32 buflen, uint8 *buffer,
+ void *pkt);
+extern void sdioh_glom_post(sdioh_info_t *sd, uint8 *frame, void *pkt, uint len);
+extern void sdioh_glom_clear(sdioh_info_t *sd);
+#endif
+
#endif /* _sdio_api_h_ */
diff -Nur a/drivers/net/wireless/bcmdhd/include/bcmsdh.h c/drivers/net/wireless/bcmdhd/include/bcmsdh.h
--- a/drivers/net/wireless/bcmdhd/include/bcmsdh.h 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/include/bcmsdh.h 2016-05-13 09:48:20.000000000 +0200
@@ -49,7 +49,7 @@
uint32 sbwad; /* Save backplane window address */
void *os_cxt; /* Pointer to per-OS private data */
};
-#endif
+#endif
/* Detach - freeup resources allocated in attach */
extern int bcmsdh_detach(osl_t *osh, void *sdh);
@@ -132,6 +132,11 @@
extern int bcmsdh_recv_buf(void *sdh, uint32 addr, uint fn, uint flags,
uint8 *buf, uint nbytes, void *pkt,
bcmsdh_cmplt_fn_t complete_fn, void *handle);
+#if defined(SWTXGLOM)
+extern int bcmsdh_send_swtxglom_buf(void *sdh, uint32 addr, uint fn, uint flags,
+ uint8 *buf, uint nbytes, void *pkt,
+ bcmsdh_cmplt_fn_t complete_fn, void *handle);
+#endif
extern void bcmsdh_glom_post(void *sdh, uint8 *frame, void *pkt, uint len);
extern void bcmsdh_glom_clear(void *sdh);
diff -Nur a/drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h c/drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h
--- a/drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h 2016-05-13 09:48:20.000000000 +0200
@@ -2,13 +2,13 @@
* BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel
*
* 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
* 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
@@ -16,12 +16,12 @@
* 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: bcmsdh_sdmmc.h 408158 2013-06-17 22:15:35Z $
+ * $Id: bcmsdh_sdmmc.h 496576 2014-08-13 15:04:56Z $
*/
#ifndef __BCMSDH_SDMMC_H__
@@ -33,6 +33,7 @@
#define sd_debug(x) do { if (sd_msglevel & SDH_DEBUG_VAL) printf x; } while (0)
#define sd_data(x) do { if (sd_msglevel & SDH_DATA_VAL) printf x; } while (0)
#define sd_ctrl(x) do { if (sd_msglevel & SDH_CTRL_VAL) printf x; } while (0)
+#define sd_cost(x) do { if (sd_msglevel & SDH_COST_VAL) printf x; } while (0)
#define sd_sync_dma(sd, read, nbytes)
@@ -57,7 +58,15 @@
/* private bus modes */
#define SDIOH_MODE_SD4 2
#define CLIENT_INTR 0x100 /* Get rid of this! */
-#define SDIOH_SDMMC_MAX_SG_ENTRIES 32
+#define SDIOH_SDMMC_MAX_SG_ENTRIES (SDPCM_MAXGLOM_SIZE+2)
+
+#if defined(SWTXGLOM)
+typedef struct glom_buf {
+ void *glom_pkt_head;
+ void *glom_pkt_tail;
+ uint32 count; /* Total number of pkts queued */
+} glom_buf_t;
+#endif /* SWTXGLOM */
struct sdioh_info {
osl_t *osh; /* osh handler */
@@ -83,6 +92,10 @@
struct sdio_func fake_func0;
struct sdio_func *func[SDIOD_MAX_IOFUNCS];
+ uint txglom_mode; /* Txglom mode: 0 - copy, 1 - multi-descriptor */
+#if defined(SWTXGLOM)
+ glom_buf_t glom_info; /* pkt information used for glomming */
+#endif
};
/************************************************************
@@ -115,8 +128,11 @@
extern sdioh_info_t *sdioh_attach(osl_t *osh, struct sdio_func *func);
extern SDIOH_API_RC sdioh_detach(osl_t *osh, sdioh_info_t *sd);
+#ifdef GLOBAL_SDMMC_INSTANCE
typedef struct _BCMSDH_SDMMC_INSTANCE {
sdioh_info_t *sd;
struct sdio_func *func[SDIOD_MAX_IOFUNCS];
} BCMSDH_SDMMC_INSTANCE, *PBCMSDH_SDMMC_INSTANCE;
+#endif
+
#endif /* __BCMSDH_SDMMC_H__ */
diff -Nur a/drivers/net/wireless/bcmdhd/include/bcmutils.h c/drivers/net/wireless/bcmdhd/include/bcmutils.h
--- a/drivers/net/wireless/bcmdhd/include/bcmutils.h 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/include/bcmutils.h 2016-05-13 09:48:20.000000000 +0200
@@ -3,7 +3,7 @@
*
* $Copyright Open Broadcom Corporation$
*
- * $Id: bcmutils.h 490808 2014-07-12 00:33:13Z $
+ * $Id: bcmutils.h 504037 2014-09-22 19:03:15Z $
*/
#ifndef _bcmutils_h_
@@ -174,6 +174,8 @@
extern uint pktsegcnt_war(osl_t *osh, void *p);
extern uint8 *pktdataoffset(osl_t *osh, void *p, uint offset);
extern void *pktoffset(osl_t *osh, void *p, uint offset);
+/* Add to adjust 802.1x priority */
+extern void pktset8021xprio(void *pkt, int prio);
/* Get priority from a packet and pass it back in scb (or equiv) */
#define PKTPRIO_VDSCP 0x100 /* DSCP prio found after VLAN tag */
@@ -286,7 +288,7 @@
#if defined(WLTINYDUMP) || defined(WLMSG_INFORM) || defined(WLMSG_ASSOC) || \
defined(WLMSG_PRPKT) || defined(WLMSG_WSEC)
extern int bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len);
-#endif
+#endif
#endif /* BCMDRIVER */
/* Base type definitions */
@@ -651,6 +653,16 @@
/* buffer length for ethernet address from bcm_ether_ntoa() */
#define ETHER_ADDR_STR_LEN 18 /* 18-bytes of Ethernet address buffer length */
+static INLINE uint32 /* 32bit word aligned xor-32 */
+bcm_compute_xor32(volatile uint32 *u32, int num_u32)
+{
+ int i;
+ uint32 xor32 = 0;
+ for (i = 0; i < num_u32; i++)
+ xor32 ^= *(u32 + i);
+ return xor32;
+}
+
/* crypto utility function */
/* 128-bit xor: *dst = *src1 xor *src2. dst1, src1 and src2 may have any alignment */
static INLINE void
@@ -895,7 +907,7 @@
return zeros;
#else /* C equivalent */
return C_bcm_count_leading_zeros(u32);
-#endif /* C equivalent */
+#endif /* C equivalent */
}
/* INTERFACE: Multiword bitmap based small id allocator. */
@@ -944,6 +956,7 @@
*/
extern void * id16_map_init(osl_t *osh, uint16 total_ids, uint16 start_val16);
extern void * id16_map_fini(osl_t *osh, void * id16_map_hndl);
+extern void id16_map_clear(void * id16_map_hndl, uint16 total_ids, uint16 start_val16);
/* Allocate a unique 16bit id */
extern uint16 id16_map_alloc(void * id16_map_hndl);
@@ -1055,7 +1068,7 @@
static INLINE dll_t *
dll_prev_p(dll_t *node_p)
{
- return (node_p)->next_p;
+ return (node_p)->prev_p;
}
@@ -1103,7 +1116,7 @@
node_p->prev_p->next_p = node_p->next_p;
node_p->next_p->prev_p = node_p->prev_p;
}
-#endif /* ! defined(_dll_t_) */
+#endif /* ! defined(_dll_t_) */
/* Elements managed in a double linked list */
diff -Nur a/drivers/net/wireless/bcmdhd/include/devctrl_if/wlioctl_defs.h c/drivers/net/wireless/bcmdhd/include/devctrl_if/wlioctl_defs.h
--- a/drivers/net/wireless/bcmdhd/include/devctrl_if/wlioctl_defs.h 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/include/devctrl_if/wlioctl_defs.h 2016-05-13 09:48:20.000000000 +0200
@@ -68,11 +68,10 @@
#define HIGHEST_SINGLE_STREAM_MCS 7 /* MCS values greater than this enable multiple streams */
-/* given a proprietary MCS, get number of spatial streams */
-#define GET_PROPRIETARY_11N_MCS_NSS(mcs) (1 + ((mcs) - 85) / 8)
+#define GET_PRO_PRIETARY_11N_MCS_NSS(mcs) (1 + ((mcs) - 85) / 8)
#define GET_11N_MCS_NSS(mcs) ((mcs) < 32 ? (1 + ((mcs) / 8)) \
- : ((mcs) == 32 ? 1 : GET_PROPRIETARY_11N_MCS_NSS(mcs)))
+ : ((mcs) == 32 ? 1 : GET_PRO_PRIETARY_11N_MCS_NSS(mcs)))
#define MAX_CCA_CHANNELS 38 /* Max number of 20 Mhz wide channels */
#define MAX_CCA_SECS 60 /* CCA keeps this many seconds history */
diff -Nur a/drivers/net/wireless/bcmdhd/include/epivers.h c/drivers/net/wireless/bcmdhd/include/epivers.h
--- a/drivers/net/wireless/bcmdhd/include/epivers.h 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/include/epivers.h 2016-05-13 09:48:20.000000000 +0200
@@ -12,19 +12,19 @@
#define EPI_MINOR_VERSION 201
-#define EPI_RC_NUMBER 34
+#define EPI_RC_NUMBER 59
#define EPI_INCREMENTAL_NUMBER 0
#define EPI_BUILD_NUMBER 0
-#define EPI_VERSION 1, 201, 34, 0
+#define EPI_VERSION 1, 201, 59, 0
-#define EPI_VERSION_NUM 0x01c92200
+#define EPI_VERSION_NUM 0x01c93b00
-#define EPI_VERSION_DEV 1.201.34
+#define EPI_VERSION_DEV 1.201.59
/* Driver Version String, ASCII, 32 chars max */
-#define EPI_VERSION_STR "1.201.34.2 (r491657)"
+#define EPI_VERSION_STR "1.201.59.6 (r506368)"
#endif /* _epivers_h_ */
diff -Nur a/drivers/net/wireless/bcmdhd/include/epivers.sh c/drivers/net/wireless/bcmdhd/include/epivers.sh
--- a/drivers/net/wireless/bcmdhd/include/epivers.sh 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/include/epivers.sh 2016-05-13 09:48:20.000000000 +0200
@@ -57,7 +57,7 @@
fi
# Following SVNURL should be expanded on checkout
- SVNURL='$HeadURL: http://svn.sj.broadcom.com/svn/wlansvn/proj/tags/DHD/DHD_REL_1_201_34/src/include/epivers.sh $'
+ SVNURL='$HeadURL: http://svn.sj.broadcom.com/svn/wlansvn/proj/tags/DHD/DHD_REL_1_201_59/src/include/epivers.sh $'
# .gclient_info is created by gclient checkout/sync steps
# and contains "DEPS='<deps-url1> <deps-url2> ..." entry
diff -Nur a/drivers/net/wireless/bcmdhd/include/event_log.h c/drivers/net/wireless/bcmdhd/include/event_log.h
--- a/drivers/net/wireless/bcmdhd/include/event_log.h 1970-01-01 01:00:00.000000000 +0100
+++ c/drivers/net/wireless/bcmdhd/include/event_log.h 2016-05-13 09:48:20.000000000 +0200
@@ -0,0 +1,293 @@
+/*
+ * EVENT_LOG system definitions
+ *
+ * $Copyright Open Broadcom Corporation$
+ *
+ * $Id: event_log.h 241182 2011-02-17 21:50:03Z $
+ */
+
+#ifndef _EVENT_LOG_H_
+#define _EVENT_LOG_H_
+
+#include <typedefs.h>
+
+/* Set a maximum number of sets here. It is not dynamic for
+ * efficiency of the EVENT_LOG calls.
+ */
+#define NUM_EVENT_LOG_SETS 4
+#define EVENT_LOG_SET_BUS 0
+#define EVENT_LOG_SET_WL 1
+#define EVENT_LOG_SET_PSM 2
+#define EVENT_LOG_SET_DBG 3
+
+/* Define new event log tags here */
+#define EVENT_LOG_TAG_NULL 0 /* Special null tag */
+#define EVENT_LOG_TAG_TS 1 /* Special timestamp tag */
+#define EVENT_LOG_TAG_BUS_OOB 2
+#define EVENT_LOG_TAG_BUS_STATE 3
+#define EVENT_LOG_TAG_BUS_PROTO 4
+#define EVENT_LOG_TAG_BUS_CTL 5
+#define EVENT_LOG_TAG_BUS_EVENT 6
+#define EVENT_LOG_TAG_BUS_PKT 7
+#define EVENT_LOG_TAG_BUS_FRAME 8
+#define EVENT_LOG_TAG_BUS_DESC 9
+#define EVENT_LOG_TAG_BUS_SETUP 10
+#define EVENT_LOG_TAG_BUS_MISC 11
+#define EVENT_LOG_TAG_SRSCAN 22
+#define EVENT_LOG_TAG_PWRSTATS_INFO 23
+#define EVENT_LOG_TAG_UCODE_WATCHDOG 26
+#define EVENT_LOG_TAG_UCODE_FIFO 27
+#define EVENT_LOG_TAG_SCAN_TRACE_LOW 28
+#define EVENT_LOG_TAG_SCAN_TRACE_HIGH 29
+#define EVENT_LOG_TAG_SCAN_ERROR 30
+#define EVENT_LOG_TAG_SCAN_WARN 31
+#define EVENT_LOG_TAG_MPF_ERR 32
+#define EVENT_LOG_TAG_MPF_WARN 33
+#define EVENT_LOG_TAG_MPF_INFO 34
+#define EVENT_LOG_TAG_MPF_DEBUG 35
+#define EVENT_LOG_TAG_EVENT_INFO 36
+#define EVENT_LOG_TAG_EVENT_ERR 37
+#define EVENT_LOG_TAG_PWRSTATS_ERROR 38
+#define EVENT_LOG_TAG_EXCESS_PM_ERROR 39
+#define EVENT_LOG_TAG_IOCTL_LOG 40
+#define EVENT_LOG_TAG_PFN_ERR 41
+#define EVENT_LOG_TAG_PFN_WARN 42
+#define EVENT_LOG_TAG_PFN_INFO 43
+#define EVENT_LOG_TAG_PFN_DEBUG 44
+#define EVENT_LOG_TAG_BEACON_LOG 45
+#define EVENT_LOG_TAG_WNM_BSSTRANS_INFO 46
+#define EVENT_LOG_TAG_TRACE_CHANSW 47
+#define EVENT_LOG_TAG_PCI_ERROR 48
+#define EVENT_LOG_TAG_PCI_TRACE 49
+#define EVENT_LOG_TAG_PCI_WARN 50
+#define EVENT_LOG_TAG_PCI_INFO 51
+#define EVENT_LOG_TAG_PCI_DBG 52
+#define EVENT_LOG_TAG_PCI_DATA 53
+#define EVENT_LOG_TAG_PCI_RING 54
+#define EVENT_LOG_TAG_MAX 55 /* Set to the same value of last tag, not last tag + 1 */
+/* Note: New event should be added/reserved in trunk before adding it to branches */
+
+/* Flags for tag control */
+#define EVENT_LOG_TAG_FLAG_NONE 0
+#define EVENT_LOG_TAG_FLAG_LOG 0x80
+#define EVENT_LOG_TAG_FLAG_PRINT 0x40
+#define EVENT_LOG_TAG_FLAG_MASK 0x3f
+
+/* logstrs header */
+#define LOGSTRS_MAGIC 0x4C4F4753
+#define LOGSTRS_VERSION 0x1
+
+/* We make sure that the block size will fit in a single packet
+ * (allowing for a bit of overhead on each packet
+ */
+#define EVENT_LOG_MAX_BLOCK_SIZE 1400
+#define EVENT_LOG_PSM_BLOCK 0x200
+#define EVENT_LOG_BUS_BLOCK 0x200
+#define EVENT_LOG_DBG_BLOCK 0x100
+
+/*
+ * There are multiple levels of objects define here:
+ * event_log_set - a set of buffers
+ * event log groups - every event log call is part of just one. All
+ * event log calls in a group are handled the
+ * same way. Each event log group is associated
+ * with an event log set or is off.
+ */
+
+#ifndef __ASSEMBLER__
+
+/* On the external system where the dumper is we need to make sure
+ * that these types are the same size as they are on the ARM the
+ * produced them
+ */
+#ifdef EVENT_LOG_DUMPER
+#define _EL_BLOCK_PTR uint32
+#define _EL_TYPE_PTR uint32
+#define _EL_SET_PTR uint32
+#define _EL_TOP_PTR uint32
+#else
+#define _EL_BLOCK_PTR struct event_log_block *
+#define _EL_TYPE_PTR uint32 *
+#define _EL_SET_PTR struct event_log_set **
+#define _EL_TOP_PTR struct event_log_top *
+#endif /* EVENT_LOG_DUMPER */
+
+/* Each event log entry has a type. The type is the LAST word of the
+ * event log. The printing code walks the event entries in reverse
+ * order to find the first entry.
+ */
+typedef union event_log_hdr {
+ struct {
+ uint8 tag; /* Event_log entry tag */
+ uint8 count; /* Count of 4-byte entries */
+ uint16 fmt_num; /* Format number */
+ };
+ uint32 t; /* Type cheat */
+} event_log_hdr_t;
+
+/* Event log sets (a logical circurlar buffer) consist of one or more
+ * event_log_blocks. The blocks themselves form a logical circular
+ * list. The log entries are placed in each event_log_block until it
+ * is full. Logging continues with the next event_log_block in the
+ * event_set until the last event_log_block is reached and then
+ * logging starts over with the first event_log_block in the
+ * event_set.
+ */
+typedef struct event_log_block {
+ _EL_BLOCK_PTR next_block;
+ _EL_BLOCK_PTR prev_block;
+ _EL_TYPE_PTR end_ptr;
+
+ /* Start of packet sent for log tracing */
+ uint16 pktlen; /* Size of rest of block */
+ uint16 count; /* Logtrace counter */
+ uint32 timestamp; /* Timestamp at start of use */
+ uint32 event_logs;
+} event_log_block_t;
+
+/* There can be multiple event_sets with each logging a set of
+ * associated events (i.e, "fast" and "slow" events).
+ */
+typedef struct event_log_set {
+ _EL_BLOCK_PTR first_block; /* Pointer to first event_log block */
+ _EL_BLOCK_PTR last_block; /* Pointer to last event_log block */
+ _EL_BLOCK_PTR logtrace_block; /* next block traced */
+ _EL_BLOCK_PTR cur_block; /* Pointer to current event_log block */
+ _EL_TYPE_PTR cur_ptr; /* Current event_log pointer */
+ uint32 blockcount; /* Number of blocks */
+ uint16 logtrace_count; /* Last count for logtrace */
+ uint16 blockfill_count; /* Fill count for logtrace */
+ uint32 timestamp; /* Last timestamp event */
+ uint32 cyclecount; /* Cycles at last timestamp event */
+} event_log_set_t;
+
+/* Top data structure for access to everything else */
+typedef struct event_log_top {
+ uint32 magic;
+#define EVENT_LOG_TOP_MAGIC 0x474C8669 /* 'EVLG' */
+ uint32 version;
+#define EVENT_LOG_VERSION 1
+ uint32 num_sets;
+ uint32 logstrs_size; /* Size of lognums + logstrs area */
+ uint32 timestamp; /* Last timestamp event */
+ uint32 cyclecount; /* Cycles at last timestamp event */
+ _EL_SET_PTR sets; /* Ptr to array of <num_sets> set ptrs */
+} event_log_top_t;
+
+/* Data structure of Keeping the Header from logstrs.bin */
+typedef struct {
+ uint32 logstrs_size; /* Size of the file */
+ uint32 rom_lognums_offset; /* Offset to the ROM lognum */
+ uint32 ram_lognums_offset; /* Offset to the RAM lognum */
+ uint32 rom_logstrs_offset; /* Offset to the ROM logstr */
+ uint32 ram_logstrs_offset; /* Offset to the RAM logstr */
+ /* Keep version and magic last since "header" is appended to the end of logstrs file. */
+ uint32 version; /* Header version */
+ uint32 log_magic; /* MAGIC number for verification 'LOGS' */
+} logstr_header_t;
+
+
+#ifndef EVENT_LOG_DUMPER
+
+#ifndef EVENT_LOG_COMPILE
+
+/* Null define if no tracing */
+#define EVENT_LOG(format, ...)
+
+#else /* EVENT_LOG_COMPILE */
+
+/* The first few are special because they can be done more efficiently
+ * this way and they are the common case. Once there are too many
+ * parameters the code size starts to be an issue and a loop is better
+ */
+#define _EVENT_LOG0(tag, fmt_num) \
+ event_log0(tag, fmt_num)
+#define _EVENT_LOG1(tag, fmt_num, t1) \
+ event_log1(tag, fmt_num, t1)
+#define _EVENT_LOG2(tag, fmt_num, t1, t2) \
+ event_log2(tag, fmt_num, t1, t2)
+#define _EVENT_LOG3(tag, fmt_num, t1, t2, t3) \
+ event_log3(tag, fmt_num, t1, t2, t3)
+#define _EVENT_LOG4(tag, fmt_num, t1, t2, t3, t4) \
+ event_log4(tag, fmt_num, t1, t2, t3, t4)
+
+/* The rest call the generic routine that takes a count */
+#define _EVENT_LOG5(tag, fmt_num, ...) event_logn(5, tag, fmt_num, __VA_ARGS__)
+#define _EVENT_LOG6(tag, fmt_num, ...) event_logn(6, tag, fmt_num, __VA_ARGS__)
+#define _EVENT_LOG7(tag, fmt_num, ...) event_logn(7, tag, fmt_num, __VA_ARGS__)
+#define _EVENT_LOG8(tag, fmt_num, ...) event_logn(8, tag, fmt_num, __VA_ARGS__)
+#define _EVENT_LOG9(tag, fmt_num, ...) event_logn(9, tag, fmt_num, __VA_ARGS__)
+#define _EVENT_LOGA(tag, fmt_num, ...) event_logn(10, tag, fmt_num, __VA_ARGS__)
+#define _EVENT_LOGB(tag, fmt_num, ...) event_logn(11, tag, fmt_num, __VA_ARGS__)
+#define _EVENT_LOGC(tag, fmt_num, ...) event_logn(12, tag, fmt_num, __VA_ARGS__)
+#define _EVENT_LOGD(tag, fmt_num, ...) event_logn(13, tag, fmt_num, __VA_ARGS__)
+#define _EVENT_LOGE(tag, fmt_num, ...) event_logn(14, tag, fmt_num, __VA_ARGS__)
+#define _EVENT_LOGF(tag, fmt_num, ...) event_logn(15, tag, fmt_num, __VA_ARGS__)
+
+/* Hack to make the proper routine call when variadic macros get
+ * passed. Note the max of 15 arguments. More than that can't be
+ * handled by the event_log entries anyways so best to catch it at compile
+ * time
+ */
+
+#define _EVENT_LOG_VA_NUM_ARGS(F, _1, _2, _3, _4, _5, _6, _7, _8, _9, \
+ _A, _B, _C, _D, _E, _F, N, ...) F ## N
+
+#define _EVENT_LOG(tag, fmt, ...) \
+ static char logstr[] __attribute__ ((section(".logstrs"))) = fmt; \
+ static uint32 fmtnum __attribute__ ((section(".lognums"))) = (uint32) &logstr; \
+ _EVENT_LOG_VA_NUM_ARGS(_EVENT_LOG, ##__VA_ARGS__, \
+ F, E, D, C, B, A, 9, 8, \
+ 7, 6, 5, 4, 3, 2, 1, 0) \
+ (tag, (int) &fmtnum , ## __VA_ARGS__); \
+
+
+#define EVENT_LOG_FAST(tag, fmt, ...) \
+ if (event_log_tag_sets != NULL) { \
+ uint8 tag_flag = *(event_log_tag_sets + tag); \
+ if (tag_flag != 0) { \
+ _EVENT_LOG(tag, fmt , ## __VA_ARGS__); \
+ } \
+ }
+
+#define EVENT_LOG_COMPACT(tag, fmt, ...) \
+ if (1) { \
+ _EVENT_LOG(tag, fmt , ## __VA_ARGS__); \
+ }
+
+#define EVENT_LOG(tag, fmt, ...) EVENT_LOG_COMPACT(tag, fmt , ## __VA_ARGS__)
+
+#define EVENT_LOG_IS_LOG_ON(tag) (*(event_log_tag_sets + (tag)) & EVENT_LOG_TAG_FLAG_LOG)
+
+#define EVENT_DUMP event_log_buffer
+
+extern uint8 *event_log_tag_sets;
+
+#include <siutils.h>
+
+extern int event_log_init(si_t *sih);
+extern int event_log_set_init(si_t *sih, int set_num, int size);
+extern int event_log_set_expand(si_t *sih, int set_num, int size);
+extern int event_log_set_shrink(si_t *sih, int set_num, int size);
+extern int event_log_tag_start(int tag, int set_num, int flags);
+extern int event_log_tag_stop(int tag);
+extern int event_log_get(int set_num, int buflen, void *buf);
+extern uint8 * event_log_next_logtrace(int set_num);
+
+extern void event_log0(int tag, int fmtNum);
+extern void event_log1(int tag, int fmtNum, uint32 t1);
+extern void event_log2(int tag, int fmtNum, uint32 t1, uint32 t2);
+extern void event_log3(int tag, int fmtNum, uint32 t1, uint32 t2, uint32 t3);
+extern void event_log4(int tag, int fmtNum, uint32 t1, uint32 t2, uint32 t3, uint32 t4);
+extern void event_logn(int num_args, int tag, int fmtNum, ...);
+
+extern void event_log_time_sync(void);
+extern void event_log_buffer(int tag, uint8 *buf, int size);
+
+#endif /* EVENT_LOG_DUMPER */
+
+#endif /* EVENT_LOG_COMPILE */
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* _EVENT_LOG_H */
diff -Nur a/drivers/net/wireless/bcmdhd/include/hndrte_armtrap.h c/drivers/net/wireless/bcmdhd/include/hndrte_armtrap.h
--- a/drivers/net/wireless/bcmdhd/include/hndrte_armtrap.h 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/include/hndrte_armtrap.h 1970-01-01 01:00:00.000000000 +0100
@@ -1,70 +0,0 @@
-/*
- * HNDRTE arm trap handling.
- *
- * $Copyright Open Broadcom Corporation$
- *
- * $Id: hndrte_armtrap.h 261365 2011-05-24 20:42:23Z $
- */
-
-#ifndef _hndrte_armtrap_h
-#define _hndrte_armtrap_h
-
-
-/* ARM trap handling */
-
-/* Trap types defined by ARM (see arminc.h) */
-
-/* Trap locations in lo memory */
-#define TRAP_STRIDE 4
-#define FIRST_TRAP TR_RST
-#define LAST_TRAP (TR_FIQ * TRAP_STRIDE)
-
-#if defined(__ARM_ARCH_4T__)
-#define MAX_TRAP_TYPE (TR_FIQ + 1)
-#elif defined(__ARM_ARCH_7M__)
-#define MAX_TRAP_TYPE (TR_ISR + ARMCM3_NUMINTS)
-#endif /* __ARM_ARCH_7M__ */
-
-/* The trap structure is defined here as offsets for assembly */
-#define TR_TYPE 0x00
-#define TR_EPC 0x04
-#define TR_CPSR 0x08
-#define TR_SPSR 0x0c
-#define TR_REGS 0x10
-#define TR_REG(n) (TR_REGS + (n) * 4)
-#define TR_SP TR_REG(13)
-#define TR_LR TR_REG(14)
-#define TR_PC TR_REG(15)
-
-#define TRAP_T_SIZE 80
-
-#ifndef _LANGUAGE_ASSEMBLY
-
-#include <typedefs.h>
-
-typedef struct _trap_struct {
- uint32 type;
- uint32 epc;
- uint32 cpsr;
- uint32 spsr;
- uint32 r0; /* a1 */
- uint32 r1; /* a2 */
- uint32 r2; /* a3 */
- uint32 r3; /* a4 */
- uint32 r4; /* v1 */
- uint32 r5; /* v2 */
- uint32 r6; /* v3 */
- uint32 r7; /* v4 */
- uint32 r8; /* v5 */
- uint32 r9; /* sb/v6 */
- uint32 r10; /* sl/v7 */
- uint32 r11; /* fp/v8 */
- uint32 r12; /* ip */
- uint32 r13; /* sp */
- uint32 r14; /* lr */
- uint32 pc; /* r15 */
-} trap_t;
-
-#endif /* !_LANGUAGE_ASSEMBLY */
-
-#endif /* _hndrte_armtrap_h */
diff -Nur a/drivers/net/wireless/bcmdhd/include/hndrte_cons.h c/drivers/net/wireless/bcmdhd/include/hndrte_cons.h
--- a/drivers/net/wireless/bcmdhd/include/hndrte_cons.h 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/include/hndrte_cons.h 1970-01-01 01:00:00.000000000 +0100
@@ -1,51 +0,0 @@
-/*
- * Console support for hndrte.
- *
- * $Copyright Open Broadcom Corporation$
- *
- * $Id: hndrte_cons.h 383834 2013-02-07 23:21:51Z $
- */
-#ifndef _HNDRTE_CONS_H
-#define _HNDRTE_CONS_H
-
-#include <typedefs.h>
-
-#define CBUF_LEN (128)
-
-#define LOG_BUF_LEN 1024
-
-typedef struct {
- uint32 buf; /* Can't be pointer on (64-bit) hosts */
- uint buf_size;
- uint idx;
- char *_buf_compat; /* redundant pointer for backward compat. */
-} hndrte_log_t;
-
-typedef struct {
- /* Virtual UART
- * When there is no UART (e.g. Quickturn), the host should write a complete
- * input line directly into cbuf and then write the length into vcons_in.
- * This may also be used when there is a real UART (at risk of conflicting with
- * the real UART). vcons_out is currently unused.
- */
- volatile uint vcons_in;
- volatile uint vcons_out;
-
- /* Output (logging) buffer
- * Console output is written to a ring buffer log_buf at index log_idx.
- * The host may read the output when it sees log_idx advance.
- * Output will be lost if the output wraps around faster than the host polls.
- */
- hndrte_log_t log;
-
- /* Console input line buffer
- * Characters are read one at a time into cbuf until <CR> is received, then
- * the buffer is processed as a command line. Also used for virtual UART.
- */
- uint cbuf_idx;
- char cbuf[CBUF_LEN];
-} hndrte_cons_t;
-
-hndrte_cons_t *hndrte_get_active_cons_state(void);
-
-#endif /* _HNDRTE_CONS_H */
diff -Nur a/drivers/net/wireless/bcmdhd/include/linux_osl.h c/drivers/net/wireless/bcmdhd/include/linux_osl.h
--- a/drivers/net/wireless/bcmdhd/include/linux_osl.h 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/include/linux_osl.h 2016-05-13 09:48:20.000000000 +0200
@@ -3,7 +3,7 @@
*
* $Copyright Open Broadcom Corporation$
*
- * $Id: linux_osl.h 491170 2014-07-15 06:23:58Z $
+ * $Id: linux_osl.h 503131 2014-09-17 12:16:08Z $
*/
#ifndef _linux_osl_h_
@@ -33,10 +33,6 @@
extern int osl_static_mem_deinit(osl_t *osh, void *adapter);
extern void osl_set_bus_handle(osl_t *osh, void *bus_handle);
extern void* osl_get_bus_handle(osl_t *osh);
-#ifdef EXYNOS5433_PCIE_WAR
-extern void exynos_pcie_set_l1_exit(void);
-extern void exynos_pcie_clear_l1_exit(void);
-#endif /* EXYNOS5433_PCIE_WAR */
/* Global ASSERT type */
extern uint32 g_assert_type;
@@ -57,7 +53,7 @@
#define ASSERT(exp)
#endif /* GCC_VERSION > 30100 */
#endif /* __GNUC__ */
-#endif
+#endif
/* bcm_prefetch_32B */
static inline void bcm_prefetch_32B(const uint8 *addr, const int cachelines_32B)
@@ -69,7 +65,7 @@
case 2: __asm__ __volatile__("pld\t%a0" :: "p"(addr + 32) : "cc");
case 1: __asm__ __volatile__("pld\t%a0" :: "p"(addr + 0) : "cc");
}
-#endif
+#endif
}
/* microsecond delay */
@@ -154,6 +150,20 @@
#define DMA_FREE_CONSISTENT_FORCE32(osh, va, size, pa, dmah) \
osl_dma_free_consistent((osh), (void*)(va), (size), (pa))
+#if defined(BCMPCIE)
+#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_FLOWRING)
+#define DMA_ALLOC_CONSISTENT_STATIC(osh, size, align, tot, pap, dmah, idx) \
+ osl_dma_alloc_consistent_static((osh), (size), (align), (tot), (pap), (idx))
+#define DMA_FREE_CONSISTENT_STATIC(osh, va, size, pa, dmah, idx) \
+ osl_dma_free_consistent_static((osh), (void*)(va), (size), (pa), (idx))
+
+extern void *osl_dma_alloc_consistent_static(osl_t *osh, uint size, uint16 align,
+ uint *tot, dmaaddr_t *pap, uint16 idx);
+extern void osl_dma_free_consistent_static(osl_t *osh, void *va, uint size, dmaaddr_t pa,
+ uint16 idx);
+#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_FLOWRING */
+#endif /* BCMPCIE */
+
extern uint osl_dma_consistent_align(void);
extern void *osl_dma_alloc_consistent(osl_t *osh, uint size, uint16 align,
uint *tot, dmaaddr_t *pap);
@@ -192,7 +202,7 @@
#define OSL_PREFETCH(ptr) BCM_REFERENCE(ptr)
#define OSL_ARCH_IS_COHERENT() NULL
-#endif
+#endif
/* register access macros */
#if defined(BCMSDIO)
@@ -210,7 +220,7 @@
osl_pcie_rreg(osh, (uintptr)(r), (void *)&__osl_v, sizeof(*(r))); \
__osl_v; \
})
-#endif
+#endif
#if defined(BCM47XX_ACP_WAR)
#define SELECT_BUS_WRITE(osh, mmap_op, bus_op) ({BCM_REFERENCE(osh); mmap_op;})
@@ -225,7 +235,7 @@
#else
#define SELECT_BUS_WRITE(osh, mmap_op, bus_op) ({BCM_REFERENCE(osh); mmap_op;})
#define SELECT_BUS_READ(osh, mmap_op, bus_op) ({BCM_REFERENCE(osh); mmap_op;})
-#endif
+#endif
#endif /* BCM47XX_ACP_WAR */
#define OSL_ERROR(bcmerror) osl_error(bcmerror)
@@ -258,26 +268,6 @@
/* register access macros */
-#ifdef EXYNOS5433_PCIE_WAR
-#define R_REG(osh, r) (\
- SELECT_BUS_READ(osh, \
- ({ \
- __typeof(*(r)) __osl_v; \
- exynos_pcie_set_l1_exit(); \
- switch (sizeof(*(r))) { \
- case sizeof(uint8): __osl_v = \
- readb((volatile uint8*)(r)); break; \
- case sizeof(uint16): __osl_v = \
- readw((volatile uint16*)(r)); break; \
- case sizeof(uint32): __osl_v = \
- readl((volatile uint32*)(r)); break; \
- } \
- exynos_pcie_clear_l1_exit(); \
- __osl_v; \
- }), \
- OSL_READ_REG(osh, r)) \
-)
-#else
#define R_REG(osh, r) (\
SELECT_BUS_READ(osh, \
({ \
@@ -294,21 +284,7 @@
}), \
OSL_READ_REG(osh, r)) \
)
-#endif /* EXYNOS5433_PCIE_WAR */
-#ifdef EXYNOS5433_PCIE_WAR
-#define W_REG(osh, r, v) do { \
- exynos_pcie_set_l1_exit(); \
- SELECT_BUS_WRITE(osh, \
- switch (sizeof(*(r))) { \
- case sizeof(uint8): writeb((uint8)(v), (volatile uint8*)(r)); break; \
- case sizeof(uint16): writew((uint16)(v), (volatile uint16*)(r)); break; \
- case sizeof(uint32): writel((uint32)(v), (volatile uint32*)(r)); break; \
- }, \
- (OSL_WRITE_REG(osh, r, v))); \
- exynos_pcie_clear_l1_exit(); \
- } while (0)
-#else
#define W_REG(osh, r, v) do { \
SELECT_BUS_WRITE(osh, \
switch (sizeof(*(r))) { \
@@ -318,7 +294,6 @@
}, \
(OSL_WRITE_REG(osh, r, v))); \
} while (0)
-#endif /* EXYNOS5433_PCIE_WAR */
#define AND_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) & (v))
#define OR_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) | (v))
@@ -340,7 +315,7 @@
#define OSL_GETCYCLES(x) rdtscl((x))
#else
#define OSL_GETCYCLES(x) ((x) = 0)
-#endif
+#endif
/* dereference an address that may cause a bus exception */
#define BUSPROBE(val, addr) ({ (val) = R_REG(NULL, (addr)); 0; })
@@ -689,7 +664,7 @@
extern void osl_pkt_frmfwder(osl_t *osh, void *skbs, int skb_cnt);
#define PKTFRMFWDER(osh, skbs, skb_cnt) \
osl_pkt_frmfwder(((osl_t *)osh), (void *)(skbs), (skb_cnt))
-#endif
+#endif
/** GMAC Forwarded packet tagging for reduced cache flush/invalidate.
@@ -982,4 +957,64 @@
extern void bzero(void *b, size_t len);
#endif /* ! BCMDRIVER */
+typedef struct sec_cma_info {
+ struct sec_mem_elem *sec_alloc_list;
+ struct sec_mem_elem *sec_alloc_list_tail;
+} sec_cma_info_t;
+
+#ifdef BCM_SECURE_DMA
+
+#define SECURE_DMA_MAP(osh, va, size, direction, p, dmah, pcma, offset) \
+ osl_sec_dma_map((osh), (va), (size), (direction), (p), (dmah), (pcma), (offset))
+#define SECURE_DMA_DD_MAP(osh, va, size, direction, p, dmah) \
+ osl_sec_dma_dd_map((osh), (va), (size), (direction), (p), (dmah))
+#define SECURE_DMA_MAP_TXMETA(osh, va, size, direction, p, dmah, pcma) \
+ osl_sec_dma_map_txmeta((osh), (va), (size), (direction), (p), (dmah), (pcma))
+#define SECURE_DMA_UNMAP(osh, pa, size, direction, p, dmah, pcma, offset) \
+ osl_sec_dma_unmap((osh), (pa), (size), (direction), (p), (dmah), (pcma), (offset))
+#define SECURE_DMA_UNMAP_ALL(osh, pcma) \
+osl_sec_dma_unmap_all((osh), (pcma))
+
+#if defined(__ARM_ARCH_7A__)
+#define ACP_WAR_ENAB() 0
+#define ACP_WIN_LIMIT 0
+#define arch_is_coherent() 0
+
+#define CMA_BUFSIZE_4K 4096
+#define CMA_BUFSIZE_2K 2048
+#define CMA_BUFSIZE_512 512
+
+#define CMA_BUFNUM 2048
+#define SEC_CMA_COHERENT_BLK 0x8000 /* 32768 */
+#define SEC_CMA_COHERENT_MAX 32
+#define CMA_DMA_DESC_MEMBLOCK (SEC_CMA_COHERENT_BLK * SEC_CMA_COHERENT_MAX)
+#define CMA_DMA_DATA_MEMBLOCK (CMA_BUFSIZE_4K*CMA_BUFNUM)
+#define CMA_MEMBLOCK (CMA_DMA_DESC_MEMBLOCK + CMA_DMA_DATA_MEMBLOCK)
+#define CONT_ARMREGION 0x02 /* Region CMA */
+#else
+#define CONT_MIPREGION 0x00 /* To access the MIPs mem, Not yet... */
+#endif /* !defined __ARM_ARCH_7A__ */
+
+#define SEC_DMA_ALIGN (1<<16)
+typedef struct sec_mem_elem {
+ size_t size;
+ int direction;
+ phys_addr_t pa_cma; /* physical address */
+ void *va; /* virtual address of driver pkt */
+ dma_addr_t dma_handle; /* bus address assign by linux */
+ void *vac; /* virtual address of cma buffer */
+ struct sec_mem_elem *next;
+} sec_mem_elem_t;
+
+extern dma_addr_t osl_sec_dma_map(osl_t *osh, void *va, uint size, int direction, void *p,
+ hnddma_seg_map_t *dmah, void *ptr_cma_info, uint offset);
+extern dma_addr_t osl_sec_dma_dd_map(osl_t *osh, void *va, uint size, int direction, void *p,
+ hnddma_seg_map_t *dmah);
+extern dma_addr_t osl_sec_dma_map_txmeta(osl_t *osh, void *va, uint size,
+ int direction, void *p, hnddma_seg_map_t *dmah, void *ptr_cma_info);
+extern void osl_sec_dma_unmap(osl_t *osh, dma_addr_t dma_handle, uint size, int direction,
+ void *p, hnddma_seg_map_t *map, void *ptr_cma_info, uint offset);
+extern void osl_sec_dma_unmap_all(osl_t *osh, void *ptr_cma_info);
+
+#endif /* BCM_SECURE_DMA */
#endif /* _linux_osl_h_ */
diff -Nur a/drivers/net/wireless/bcmdhd/include/linuxver.h c/drivers/net/wireless/bcmdhd/include/linuxver.h
--- a/drivers/net/wireless/bcmdhd/include/linuxver.h 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/include/linuxver.h 2016-05-13 09:48:20.000000000 +0200
@@ -686,7 +686,7 @@
#define WL_ISR(i, d, p) wl_isr((i), (d))
#else
#define WL_ISR(i, d, p) wl_isr((i), (d), (p))
-#endif /* < 2.6.20 */
+#endif /* < 2.6.20 */
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
#define netdev_priv(dev) dev->priv
diff -Nur a/drivers/net/wireless/bcmdhd/include/miniopt.h c/drivers/net/wireless/bcmdhd/include/miniopt.h
--- a/drivers/net/wireless/bcmdhd/include/miniopt.h 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/include/miniopt.h 2016-05-13 09:48:20.000000000 +0200
@@ -58,4 +58,4 @@
}
#endif
-#endif /* MINI_OPT_H */
+#endif /* MINI_OPT_H */
diff -Nur a/drivers/net/wireless/bcmdhd/include/osl.h c/drivers/net/wireless/bcmdhd/include/osl.h
--- a/drivers/net/wireless/bcmdhd/include/osl.h 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/include/osl.h 2016-05-13 09:48:20.000000000 +0200
@@ -3,7 +3,7 @@
*
* $Copyright Open Broadcom Corporation$
*
- * $Id: osl.h 474639 2014-05-01 23:52:31Z $
+ * $Id: osl.h 503131 2014-09-17 12:16:08Z $
*/
#ifndef _osl_h_
@@ -38,11 +38,11 @@
#ifndef AND_REG
#define AND_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) & (v))
-#endif /* !AND_REG */
+#endif /* !AND_REG */
#ifndef OR_REG
#define OR_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) | (v))
-#endif /* !OR_REG */
+#endif /* !OR_REG */
#if !defined(OSL_SYSUPTIME)
#define OSL_SYSUPTIME() (0)
@@ -127,5 +127,17 @@
#define PKTFRAGISCHAINED(osh, i) (0)
/* TRIM Tail bytes from lfrag */
#define PKTFRAG_TRIM_TAILBYTES(osh, p, len) PKTSETLEN(osh, p, PKTLEN(osh, p) - len)
+#ifdef BCM_SECURE_DMA
+#define SECURE_DMA_ENAB(osh) (1)
+#else
+
+#define SECURE_DMA_ENAB(osh) (0)
+#define SECURE_DMA_MAP(osh, va, size, direction, p, dmah, pcma, offset) ((dmaaddr_t) {(0)})
+#define SECURE_DMA_DD_MAP(osh, va, size, direction, p, dmah) 0
+#define SECURE_DMA_MAP_TXMETA(osh, va, size, direction, p, dmah, pcma) ((dmaaddr_t) {(0)})
+#define SECURE_DMA_UNMAP(osh, pa, size, direction, p, dmah, pcma, offset)
+#define SECURE_DMA_UNMAP_ALL(osh, pcma)
+
+#endif
#endif /* _osl_h_ */
diff -Nur a/drivers/net/wireless/bcmdhd/include/pcicfg.h c/drivers/net/wireless/bcmdhd/include/pcicfg.h
--- a/drivers/net/wireless/bcmdhd/include/pcicfg.h 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/include/pcicfg.h 2016-05-13 09:48:20.000000000 +0200
@@ -3,7 +3,7 @@
*
* $Copyright Open Broadcom Corporation$
*
- * $Id: pcicfg.h 465082 2014-03-26 17:37:28Z $
+ * $Id: pcicfg.h 506084 2014-10-02 15:34:59Z $
*/
#ifndef _h_pcicfg_
@@ -92,10 +92,6 @@
#define PCIBAR_PREFETCH 0x8
#define PCIBAR_MEM32_MASK 0xFFFFFF80
-/* pci config status reg has a bit to indicate that capability ptr is present */
-
-#define PCI_CAPPTR_PRESENT 0x0010
-
typedef struct _pci_config_regs {
uint16 vendor;
uint16 device;
@@ -126,6 +122,11 @@
#define MINSZPCR 64 /* offsetof (dev_dep[0] */
#endif /* !LINUX_POSTMOGRIFY_REMOVAL */
+
+/* pci config status reg has a bit to indicate that capability ptr is present */
+
+#define PCI_CAPPTR_PRESENT 0x0010
+
/* A structure for the config registers is nice, but in most
* systems the config space is not memory mapped, so we need
* field offsetts. :-(
@@ -315,16 +316,6 @@
PCI_XOR_OTHER = 0x80
} pci_xor_subclasses;
-/* Header types */
-#define PCI_HEADER_MULTI 0x80
-#define PCI_HEADER_MASK 0x7f
-typedef enum {
- PCI_HEADER_NORMAL,
- PCI_HEADER_BRIDGE,
- PCI_HEADER_CARDBUS
-} pci_header_types;
-
-
/* Overlay for a PCI-to-PCI bridge */
#define PPB_RSVDA_MAX 2
@@ -372,6 +363,16 @@
uint8 dev_dep[192];
} ppb_config_regs;
+/* Everything below is BRCM HND proprietary */
+
+
+/* Brcm PCI configuration registers */
+#define cap_list rsvd_a[0]
+#define bar0_window dev_dep[0x80 - 0x40]
+#define bar1_window dev_dep[0x84 - 0x40]
+#define sprom_control dev_dep[0x88 - 0x40]
+#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+
/* PCI CAPABILITY DEFINES */
#define PCI_CAP_POWERMGMTCAP_ID 0x01
@@ -461,15 +462,6 @@
} pcie_enhanced_caphdr;
-/* Everything below is BRCM HND proprietary */
-
-
-/* Brcm PCI configuration registers */
-#define cap_list rsvd_a[0]
-#define bar0_window dev_dep[0x80 - 0x40]
-#define bar1_window dev_dep[0x84 - 0x40]
-#define sprom_control dev_dep[0x88 - 0x40]
-#endif /* LINUX_POSTMOGRIFY_REMOVAL */
#define PCI_BAR0_WIN 0x80 /* backplane addres space accessed by BAR0 */
#define PCI_BAR1_WIN 0x84 /* backplane addres space accessed by BAR1 */
#define PCI_SPROM_CONTROL 0x88 /* sprom property control */
@@ -484,7 +476,11 @@
#define PCI_GPIO_IN 0xb0 /* pci config space gpio input (>=rev3) */
#define PCI_GPIO_OUT 0xb4 /* pci config space gpio output (>=rev3) */
#define PCI_GPIO_OUTEN 0xb8 /* pci config space gpio output enable (>=rev3) */
-#define PCI_L1SS_CTRL2 0x24c /* The L1 PM Substates Control register */
+#define PCI_LINK_CTRL 0xbc /* PCI link control register */
+#define PCI_DEV_STAT_CTRL2 0xd4 /* PCI device status control 2 register */
+#define PCIE_LTR_MAX_SNOOP 0x1b4 /* PCIE LTRMaxSnoopLatency */
+#define PCI_L1SS_CTRL 0x248 /* The L1 PM Substates Control register */
+#define PCI_L1SS_CTRL2 0x24c /* The L1 PM Substates Control 2 register */
/* Private Registers */
#define PCI_STAT_CTRL 0xa80
@@ -560,5 +556,45 @@
#define PCI_STAT_TA 0x08000000 /* target abort status */
#endif /* LINUX_POSTMOGRIFY_REMOVAL */
+/* Header types */
+#define PCI_HEADER_MULTI 0x80
+#define PCI_HEADER_MASK 0x7f
+typedef enum {
+ PCI_HEADER_NORMAL,
+ PCI_HEADER_BRIDGE,
+ PCI_HEADER_CARDBUS
+} pci_header_types;
+
#define PCI_CONFIG_SPACE_SIZE 256
+
+#define DWORD_ALIGN(x) (x & ~(0x03))
+#define BYTE_POS(x) (x & 0x3)
+#define WORD_POS(x) (x & 0x1)
+
+#define BYTE_SHIFT(x) (8 * BYTE_POS(x))
+#define WORD_SHIFT(x) (16 * WORD_POS(x))
+
+#define BYTE_VAL(a, x) ((a >> BYTE_SHIFT(x)) & 0xFF)
+#define WORD_VAL(a, x) ((a >> WORD_SHIFT(x)) & 0xFFFF)
+
+#define read_pci_cfg_byte(a) \
+ (BYTE_VAL(OSL_PCI_READ_CONFIG(osh, DWORD_ALIGN(a), 4), a) & 0xff)
+
+#define read_pci_cfg_word(a) \
+ (WORD_VAL(OSL_PCI_READ_CONFIG(osh, DWORD_ALIGN(a), 4), a) & 0xffff)
+
+#define write_pci_cfg_byte(a, val) do { \
+ uint32 tmpval; \
+ tmpval = (OSL_PCI_READ_CONFIG(osh, DWORD_ALIGN(a), 4) & ~0xFF << BYTE_POS(a)) | \
+ val << BYTE_POS(a); \
+ OSL_PCI_WRITE_CONFIG(osh, DWORD_ALIGN(a), 4, tmpval); \
+ } while (0)
+
+#define write_pci_cfg_word(a, val) do { \
+ uint32 tmpval; \
+ tmpval = (OSL_PCI_READ_CONFIG(osh, DWORD_ALIGN(a), 4) & ~0xFFFF << WORD_POS(a)) | \
+ val << WORD_POS(a); \
+ OSL_PCI_WRITE_CONFIG(osh, DWORD_ALIGN(a), 4, tmpval); \
+ } while (0)
+
#endif /* _h_pcicfg_ */
diff -Nur a/drivers/net/wireless/bcmdhd/include/proto/802.11.h c/drivers/net/wireless/bcmdhd/include/proto/802.11.h
--- a/drivers/net/wireless/bcmdhd/include/proto/802.11.h 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/include/proto/802.11.h 2016-05-13 09:48:20.000000000 +0200
@@ -3,7 +3,7 @@
*
* Fundamental types and constants relating to 802.11
*
- * $Id: 802.11.h 469158 2014-04-09 21:31:31Z $
+ * $Id: 802.11.h 495738 2014-08-08 03:36:17Z $
*/
#ifndef _802_11_H_
@@ -2905,7 +2905,7 @@
BWL_PRE_PACKED_STRUCT struct brcm_prop_ie_s {
uint8 id; /* IE ID, 221, DOT11_MNG_PROPR_ID */
uint8 len; /* IE length */
- uint8 oui[3]; /* Proprietary OUI, BRCM_PROP_OUI */
+ uint8 oui[3];
uint8 type; /* type of this IE */
uint16 cap; /* DPT capabilities */
} BWL_POST_PACKED_STRUCT;
@@ -2949,10 +2949,6 @@
#define BRF_ABCOUNTER_MASK 0xf0 /* afterburner is obsolete, defined for backward compat */
#define BRF_PROP_11N_MCS 0x10 /* re-use afterburner bit */
-/**
- * Support for Broadcom proprietary HT MCS rates. Re-uses afterburner bits since afterburner is not
- * used anymore. Checks for BRF_ABCAP to stay compliant with 'old' images in the field.
- */
#define GET_BRF_PROP_11N_MCS(brcm_ie) \
(!((brcm_ie)->flags & BRF_ABCAP) && ((brcm_ie)->flags & BRF_PROP_11N_MCS))
@@ -3861,7 +3857,6 @@
/* QoS map */
#define QOS_MAP_FIXED_LENGTH (8 * 2) /* DSCP ranges fixed with 8 entries */
-/* BCM proprietary IE type for AIBSS */
#define BCM_AIBSS_IE_TYPE 56
/* This marks the end of a packed structure section. */
diff -Nur a/drivers/net/wireless/bcmdhd/include/proto/bcmdhcp.h c/drivers/net/wireless/bcmdhd/include/proto/bcmdhcp.h
--- a/drivers/net/wireless/bcmdhd/include/proto/bcmdhcp.h 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/include/proto/bcmdhcp.h 2016-05-13 09:48:20.000000000 +0200
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2014, Broadcom Corporation
* All Rights Reserved.
- *
+ *
* This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation;
* the contents of this file may not be disclosed to third parties, copied
* or duplicated in any form, in whole or in part, without the prior
diff -Nur a/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h c/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h
--- a/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h 2016-05-13 09:48:20.000000000 +0200
@@ -5,7 +5,7 @@
*
* Dependencies: proto/bcmeth.h
*
- * $Id: bcmevent.h 490387 2014-07-10 15:12:52Z $
+ * $Id: bcmevent.h 505096 2014-09-26 12:49:04Z $
*
*/
@@ -384,6 +384,21 @@
#define WLC_E_REASON_RMC_AR_LOST 1
#define WLC_E_REASON_RMC_AR_NO_ACK 2
+#ifdef WLTDLS
+/* TDLS Action Category code */
+#define TDLS_AF_CATEGORY 12
+/* Wi-Fi Display (WFD) Vendor Specific Category */
+/* used for WFD Tunneled Probe Request and Response */
+#define TDLS_VENDOR_SPECIFIC 127
+/* TDLS Action Field Values */
+#define TDLS_ACTION_SETUP_REQ 0
+#define TDLS_ACTION_SETUP_RESP 1
+#define TDLS_ACTION_SETUP_CONFIRM 2
+#define TDLS_ACTION_TEARDOWN 3
+#define WLAN_TDLS_SET_PROBE_WFD_IE 11
+#define WLAN_TDLS_SET_SETUP_WFD_IE 12
+#endif
+
/* GAS event data */
typedef BWL_PRE_PACKED_STRUCT struct wl_event_gas {
diff -Nur a/drivers/net/wireless/bcmdhd/include/proto/bcmudp.h c/drivers/net/wireless/bcmdhd/include/proto/bcmudp.h
--- a/drivers/net/wireless/bcmdhd/include/proto/bcmudp.h 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/include/proto/bcmudp.h 2016-05-13 09:48:20.000000000 +0200
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2014, Broadcom Corporation
* All Rights Reserved.
- *
+ *
* This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation;
* the contents of this file may not be disclosed to third parties, copied
* or duplicated in any form, in whole or in part, without the prior
diff -Nur a/drivers/net/wireless/bcmdhd/include/proto/wpa.h c/drivers/net/wireless/bcmdhd/include/proto/wpa.h
--- a/drivers/net/wireless/bcmdhd/include/proto/wpa.h 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/include/proto/wpa.h 2016-05-13 09:48:20.000000000 +0200
@@ -3,7 +3,7 @@
*
* $Copyright Open Broadcom Corporation$
*
- * $Id: wpa.h 450928 2014-01-23 14:13:38Z $
+ * $Id: wpa.h 492853 2014-07-23 17:20:34Z $
*/
#ifndef _proto_wpa_h_
@@ -177,6 +177,7 @@
#define WPA_CAP_WPA2_PREAUTH RSN_CAP_PREAUTH
#define WPA2_PMKID_COUNT_LEN 2
+#define RSN_GROUPMANAGE_CIPHER_LEN 4
#ifdef BCMWAPI_WAI
#define WAPI_CAP_PREAUTH RSN_CAP_PREAUTH
diff -Nur a/drivers/net/wireless/bcmdhd/include/sbchipc.h c/drivers/net/wireless/bcmdhd/include/sbchipc.h
--- a/drivers/net/wireless/bcmdhd/include/sbchipc.h 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/include/sbchipc.h 2016-05-13 09:48:20.000000000 +0200
@@ -2824,7 +2824,8 @@
#define CCTRL2_4335_PMUWAKE (1 << 31)
#define PATCHTBL_SIZE (0x800)
#define CR4_4335_RAM_BASE (0x180000)
-#define CR4_4345_RAM_BASE (0x1b0000)
+#define CR4_4345_LT_C0_RAM_BASE (0x1b0000)
+#define CR4_4345_GE_C0_RAM_BASE (0x198000)
#define CR4_4349_RAM_BASE (0x180000)
#define CR4_4350_RAM_BASE (0x180000)
#define CR4_4360_RAM_BASE (0x0)
diff -Nur a/drivers/net/wireless/bcmdhd/include/sdiovar.h c/drivers/net/wireless/bcmdhd/include/sdiovar.h
--- a/drivers/net/wireless/bcmdhd/include/sdiovar.h 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/include/sdiovar.h 2016-05-13 09:48:20.000000000 +0200
@@ -31,6 +31,7 @@
#define SDH_CTRL_VAL 0x0020 /* Control Regs */
#define SDH_LOG_VAL 0x0040 /* Enable bcmlog */
#define SDH_DMA_VAL 0x0080 /* DMA */
+#define SDH_COST_VAL 0x8000 /* Control Regs */
#define NUM_PREV_TRANSACTIONS 16
diff -Nur a/drivers/net/wireless/bcmdhd/include/siutils.h c/drivers/net/wireless/bcmdhd/include/siutils.h
--- a/drivers/net/wireless/bcmdhd/include/siutils.h 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/include/siutils.h 2016-05-13 09:48:20.000000000 +0200
@@ -363,7 +363,7 @@
#if defined(BCMDBG_PHYDUMP)
extern void si_dumpregs(si_t *sih, struct bcmstrbuf *b);
-#endif
+#endif
extern uint32 si_ccreg(si_t *sih, uint32 offset, uint32 mask, uint32 val);
extern uint32 si_pciereg(si_t *sih, uint32 offset, uint32 mask, uint32 val, uint type);
diff -Nur a/drivers/net/wireless/bcmdhd/include/typedefs.h c/drivers/net/wireless/bcmdhd/include/typedefs.h
--- a/drivers/net/wireless/bcmdhd/include/typedefs.h 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/include/typedefs.h 2016-05-13 09:48:20.000000000 +0200
@@ -94,7 +94,7 @@
#endif
#endif /* == 2.6.18 */
#endif /* __KERNEL__ */
-#endif /* !defined(LINUX_HYBRID) || defined(LINUX_PORT) */
+#endif /* !defined(LINUX_HYBRID) || defined(LINUX_PORT) */
/* Do not support the (u)int64 types with strict ansi for GNU C */
@@ -132,7 +132,7 @@
#endif /* linux && __KERNEL__ */
-#endif
+#endif
/* use the default typedefs in the next section of this file */
@@ -272,7 +272,7 @@
#define BWL_COMPILER_ARMCC
#else
#error "Unknown compiler!"
-#endif
+#endif
#ifndef INLINE
@@ -284,7 +284,7 @@
#define INLINE __inline
#else
#define INLINE
- #endif
+ #endif
#endif /* INLINE */
#undef TYPEDEF_BOOL
diff -Nur a/drivers/net/wireless/bcmdhd/include/wlfc_proto.h c/drivers/net/wireless/bcmdhd/include/wlfc_proto.h
--- a/drivers/net/wireless/bcmdhd/include/wlfc_proto.h 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/include/wlfc_proto.h 2016-05-13 09:48:20.000000000 +0200
@@ -1,6 +1,6 @@
/*
* $Copyright Open 2009 Broadcom Corporation$
-* $Id: wlfc_proto.h 455301 2014-02-13 12:42:13Z $
+* $Id: wlfc_proto.h 499510 2014-08-28 23:40:47Z $
*
*/
#ifndef __wlfc_proto_definitions_h__
@@ -107,8 +107,9 @@
#define WLFC_CTL_VALUE_LEN_REQUEST_PACKET 3 /* credit, MAC-handle, prec_bitmap */
-#define WLFC_PKTFLAG_PKTFROMHOST 0x01
-#define WLFC_PKTFLAG_PKT_REQUESTED 0x02
+#define WLFC_PKTFLAG_PKTFROMHOST 0x01 /* packet originated from hot side */
+#define WLFC_PKTFLAG_PKT_REQUESTED 0x02 /* packet requsted by firmware side */
+#define WLFC_PKTFLAG_PKT_FORCELOWRATE 0x04 /* force low rate for this packet */
#define WL_TXSTATUS_STATUS_MASK 0xff /* allow 8 bits */
#define WL_TXSTATUS_STATUS_SHIFT 24
@@ -199,13 +200,6 @@
/* b[7:5] -reuse guard, b[4:0] -value */
#define WLFC_MAC_DESC_GET_LOOKUP_INDEX(x) ((x) & 0x1f)
-#define WLFC_PKTFLAG_SET_PKTREQUESTED(x) (x) |= \
- (WLFC_PKTFLAG_PKT_REQUESTED << WL_TXSTATUS_FLAGS_SHIFT)
-
-#define WLFC_PKTFLAG_CLR_PKTREQUESTED(x) (x) &= \
- ~(WLFC_PKTFLAG_PKT_REQUESTED << WL_TXSTATUS_FLAGS_SHIFT)
-
-
#define WLFC_MAX_PENDING_DATALEN 120
/* host is free to discard the packet */
diff -Nur a/drivers/net/wireless/bcmdhd/include/wlioctl.h c/drivers/net/wireless/bcmdhd/include/wlioctl.h
--- a/drivers/net/wireless/bcmdhd/include/wlioctl.h 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/include/wlioctl.h 2016-05-13 09:48:20.000000000 +0200
@@ -6,7 +6,7 @@
*
* $Copyright Open Broadcom Corporation$
*
- * $Id: wlioctl.h 490639 2014-07-11 08:31:53Z $
+ * $Id: wlioctl.h 504503 2014-09-24 11:28:56Z $
*/
#ifndef _wlioctl_h_
@@ -24,9 +24,6 @@
#include <bcmwifi_rates.h>
#include <devctrl_if/wlioctl_defs.h>
-#if 0 && (NDISVER >= 0x0600)
-#include <proto/bcmipv6.h>
-#endif
#ifndef LINUX_POSTMOGRIFY_REMOVAL
#include <bcm_mpool_pub.h>
@@ -2264,6 +2261,25 @@
uint32 bphy_badplcp;
} wl_delta_stats_t;
+
+#if defined(CUSTOM_PLATFORM_NV_TEGRA)
+/* structure to store per-rate rx statistics */
+typedef struct wl_scb_rx_rate_stats {
+ uint32 rx1mbps[2]; /* packets rx at 1Mbps */
+ uint32 rx2mbps[2]; /* packets rx at 2Mbps */
+ uint32 rx5mbps5[2]; /* packets rx at 5.5Mbps */
+ uint32 rx6mbps[2]; /* packets rx at 6Mbps */
+ uint32 rx9mbps[2]; /* packets rx at 9Mbps */
+ uint32 rx11mbps[2]; /* packets rx at 11Mbps */
+ uint32 rx12mbps[2]; /* packets rx at 12Mbps */
+ uint32 rx18mbps[2]; /* packets rx at 18Mbps */
+ uint32 rx24mbps[2]; /* packets rx at 24Mbps */
+ uint32 rx36mbps[2]; /* packets rx at 36Mbps */
+ uint32 rx48mbps[2]; /* packets rx at 48Mbps */
+ uint32 rx54mbps[2]; /* packets rx at 54Mbps */
+} wl_scb_rx_rate_stats_t;
+#endif /* defined(CUSTOM_PLATFORM_NV_TEGRA) */
+
#endif /* LINUX_POSTMOGRIFY_REMOVAL */
typedef struct {
@@ -2917,6 +2933,20 @@
* Dongle pattern matching filter.
*/
+/* Packet filter operation mode */
+/* True: 1; False: 0 */
+#define PKT_FILTER_MODE_FORWARD_ON_MATCH 1
+/* Enable and disable pkt_filter as a whole */
+#define PKT_FILTER_MODE_DISABLE 2
+/* Cache first matched rx pkt(be queried by host later) */
+#define PKT_FILTER_MODE_PKT_CACHE_ON_MATCH 4
+/* If pkt_filter is enabled and no filter is set, don't forward anything */
+#define PKT_FILTER_MODE_PKT_FORWARD_OFF_DEFAULT 8
+#if defined(CUSTOM_PLATFORM_NV_TEGRA)
+/* Ports only filter mode */
+#define PKT_FILTER_MODE_PORTS_ONLY 16
+#endif /* defined(CUSTOM_PLATFORM_NV_TEGRA) */
+
#define MAX_WAKE_PACKET_CACHE_BYTES 128 /* Maximum cached wake packet */
#define MAX_WAKE_PACKET_BYTES (DOT11_A3_HDR_LEN + \
@@ -2959,12 +2989,13 @@
* that indicates which bits within the pattern should be matched.
*/
typedef struct wl_pkt_filter_pattern {
- union {
+// terence 20150525: fix pkt filter error -14 in 64bit OS
+// union {
uint32 offset; /* Offset within received packet to start pattern matching.
* Offset '0' is the first byte of the ethernet header.
*/
- wl_pkt_decrypter_t* decrypt_ctx; /* Decrypt context */
- };
+// wl_pkt_decrypter_t* decrypt_ctx; /* Decrypt context */
+// };
uint32 size_bytes; /* Size of the pattern. Bitmask must be the same size. */
uint8 mask_and_pattern[1]; /* Variable length mask and pattern data. mask starts
* at offset 0. Pattern immediately follows mask.
@@ -3458,6 +3489,13 @@
uint32 count;
} BWL_POST_PACKED_STRUCT pcie_bus_tput_stats_t;
+#define MAX_ROAMOFFL_BSSID_NUM 100
+
+typedef BWL_PRE_PACKED_STRUCT struct roamoffl_bssid_list {
+ int cnt;
+ struct ether_addr bssid[1];
+} BWL_POST_PACKED_STRUCT roamoffl_bssid_list_t;
+
/* no default structure packing */
#include <packed_section_end.h>
@@ -3663,22 +3701,6 @@
uint8 id;
} BWL_POST_PACKED_STRUCT;
-#if 0 && (NDISVER >= 0x0600)
-/* Return values */
-#define ND_REPLY_PEER 0x1 /* Reply was sent to service NS request from peer */
-#define ND_REQ_SINK 0x2 /* Input packet should be discarded */
-#define ND_FORCE_FORWARD 0X3 /* For the dongle to forward req to HOST */
-
-
-/* Neighbor Solicitation Response Offload IOVAR param */
-typedef BWL_PRE_PACKED_STRUCT struct nd_param {
- struct ipv6_addr host_ip[2];
- struct ipv6_addr solicit_ip;
- struct ipv6_addr remote_ip;
- uint8 host_mac[ETHER_ADDR_LEN];
- uint32 offload_id;
-} BWL_POST_PACKED_STRUCT nd_param_t;
-#endif
typedef BWL_PRE_PACKED_STRUCT struct wl_pfn_roam_thresh {
uint32 pfn_alert_thresh; /* time in ms */
@@ -5020,6 +5042,8 @@
typedef BWL_PRE_PACKED_STRUCT struct nan_scan_params {
uint16 scan_time;
uint16 home_time;
+ uint16 ms_intvl; /* interval between merge scan */
+ uint16 ms_dur; /* duration of merge scan */
uint16 chspec_num;
chanspec_t chspec_list[NAN_SCAN_MAX_CHCNT]; /* act. used 3, 5 rfu */
} BWL_POST_PACKED_STRUCT nan_scan_params_t;
@@ -5858,6 +5882,48 @@
wl_roam_prof_t roam_prof[WL_MAX_ROAM_PROF_BRACKETS];
} wl_roam_prof_band_t;
+/* Data structures for Interface Create/Remove */
+
+#define WL_INTERFACE_CREATE_VER (0)
+
+/*
+ * The flags filed of the wl_interface_create is designed to be
+ * a Bit Mask. As of now only Bit 0 and Bit 1 are used as mentioned below.
+ * The rest of the bits can be used, incase we have to provide
+ * more information to the dongle
+ */
+
+/*
+ * Bit 0 of flags field is used to inform whether the interface requested to
+ * be created is STA or AP.
+ * 0 - Create a STA interface
+ * 1 - Create an AP interface
+ */
+#define WL_INTERFACE_CREATE_STA (0 << 0)
+#define WL_INTERFACE_CREATE_AP (1 << 0)
+
+/*
+ * Bit 1 of flags field is used to inform whether MAC is present in the
+ * data structure or not.
+ * 0 - Ignore mac_addr field
+ * 1 - Use the mac_addr field
+ */
+#define WL_INTERFACE_MAC_DONT_USE (0 << 1)
+#define WL_INTERFACE_MAC_USE (1 << 1)
+
+typedef struct wl_interface_create {
+ uint16 ver; /* version of this struct */
+ uint32 flags; /* flags that defines the operation */
+ struct ether_addr mac_addr; /* Optional Mac address */
+} wl_interface_create_t;
+
+typedef struct wl_interface_info {
+ uint16 ver; /* version of this struct */
+ struct ether_addr mac_addr; /* MAC address of the interface */
+ char ifname[BCM_MSG_IFNAME_MAX]; /* name of interface */
+ uint8 bsscfgidx; /* source bsscfg index */
+} wl_interface_info_t;
+
/* no default structure packing */
#include <packed_section_end.h>
diff -Nur a/drivers/net/wireless/bcmdhd/Kconfig c/drivers/net/wireless/bcmdhd/Kconfig
--- a/drivers/net/wireless/bcmdhd/Kconfig 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/Kconfig 2016-05-13 09:48:20.000000000 +0200
@@ -18,13 +18,6 @@
---help---
Path to the calibration file.
-config BCMDHD_CONFIG_PATH
- depends on BCMDHD
- string "Config path"
- default "/system/etc/firmware/config.txt"
- ---help---
- Path to the driver configuration file.
-
config BCMDHD_WEXT
bool "Enable WEXT support"
depends on BCMDHD && CFG80211 = n
@@ -34,18 +27,31 @@
Enables WEXT support
choice
+ prompt "Enable Chip Interface"
depends on BCMDHD
+ ---help---
+ Enable Chip Interface.
+config BCMDHD_SDIO
+ bool "SDIO bus interface support"
+ depends on BCMDHD && MMC
+config BCMDHD_PCIE
+ bool "PCIe bus interface support"
+ depends on BCMDHD && PCI
+endchoice
+
+choice
+ depends on BCMDHD && BCMDHD_SDIO
prompt "Interrupt type"
---help---
- Interrupt type
+ Interrupt type
config BCMDHD_OOB
- depends on BCMDHD
+ depends on BCMDHD && BCMDHD_SDIO
bool "Out-of-Band Interrupt"
default y
---help---
- Interrupt from WL_HOST_WAKE.
+ Interrupt from WL_HOST_WAKE.
config BCMDHD_SDIO_IRQ
- depends on BCMDHD
+ depends on BCMDHD && BCMDHD_SDIO
bool "In-Band Interrupt"
---help---
Interrupt from SDIO DAT[1]
diff -Nur a/drivers/net/wireless/bcmdhd/linux_osl.c c/drivers/net/wireless/bcmdhd/linux_osl.c
--- a/drivers/net/wireless/bcmdhd/linux_osl.c 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/linux_osl.c 2016-05-13 09:48:20.000000000 +0200
@@ -3,7 +3,7 @@
*
* $Copyright Open Broadcom Corporation$
*
- * $Id: linux_osl.c 490846 2014-07-12 13:08:59Z $
+ * $Id: linux_osl.c 503131 2014-09-17 12:16:08Z $
*/
#define LINUX_PORT
@@ -23,9 +23,31 @@
#include <bcmutils.h>
#include <linux/delay.h>
#include <pcicfg.h>
+#include <asm-generic/pci-dma-compat.h>
+#ifdef BCM_SECURE_DMA
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/printk.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/moduleparam.h>
+#include <asm/io.h>
+#include <linux/skbuff.h>
+#include <linux/vmalloc.h>
+#include <linux/highmem.h>
+#include <linux/dma-mapping.h>
+#include <asm/memory.h>
+#if defined(__ARM_ARCH_7A__)
+#include <arch/arm/include/asm/tlbflush.h>
+#include <arch/arm/mm/mm.h>
+#endif
+#include <linux/brcmstb/cma_driver.h>
+#endif /* BCM_SECURE_DMA */
+
#include <linux/fs.h>
#ifdef BCM47XX_ACP_WAR
@@ -33,6 +55,12 @@
extern spinlock_t l2x0_reg_lock;
#endif
+#if defined(BCMPCIE)
+#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_FLOWRING)
+#include <bcmpcie.h>
+#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_FLOWRING */
+#endif /* BCMPCIE */
+
#define PCI_CFG_RETRY 10
#define OS_HANDLE_MAGIC 0x1234abcd /* Magic # to recognize osh */
@@ -78,6 +106,20 @@
static bcm_static_pkt_t *bcm_static_skb = 0;
+#if defined(BCMPCIE) && defined(DHD_USE_STATIC_FLOWRING)
+#define STATIC_BUF_FLOWRING_SIZE ((PAGE_SIZE)*(7))
+#define STATIC_BUF_FLOWRING_NUM 42
+#define RINGID_TO_FLOWID(idx) ((idx) + (BCMPCIE_H2D_COMMON_MSGRINGS) \
+ - (BCMPCIE_H2D_TXFLOWRINGID))
+typedef struct bcm_static_flowring_buf {
+ spinlock_t flowring_lock;
+ void *buf_ptr[STATIC_BUF_FLOWRING_NUM];
+ unsigned char buf_use[STATIC_BUF_FLOWRING_NUM];
+} bcm_static_flowring_buf_t;
+
+bcm_static_flowring_buf_t *bcm_static_flowring = 0;
+#endif /* BCMPCIE && DHD_USE_STATIC_FLOWRING */
+
void* wifi_platform_prealloc(void *adapter, int section, unsigned long size);
#endif /* CONFIG_DHD_USE_STATIC_BUF */
@@ -118,7 +160,50 @@
int ctrace_num;
#endif /* BCMDBG_CTRACE */
uint32 flags; /* If specific cases to be handled in the OSL */
+#ifdef BCM_SECURE_DMA
+ struct cma_dev *cma;
+ struct sec_mem_elem *sec_list_512;
+ struct sec_mem_elem *sec_list_base_512;
+ struct sec_mem_elem *sec_list_2048;
+ struct sec_mem_elem *sec_list_base_2048;
+ struct sec_mem_elem *sec_list_4096;
+ struct sec_mem_elem *sec_list_base_4096;
+ phys_addr_t contig_base;
+ void *contig_base_va;
+ phys_addr_t contig_base_alloc;
+ void *contig_base_alloc_va;
+ phys_addr_t contig_base_alloc_coherent;
+ void *contig_base_alloc_coherent_va;
+ phys_addr_t contig_delta_va_pa;
+ struct {
+ phys_addr_t pa;
+ void *va;
+ bool avail;
+ } sec_cma_coherent[SEC_CMA_COHERENT_MAX];
+
+#endif /* BCM_SECURE_DMA */
+
};
+#ifdef BCM_SECURE_DMA
+phys_addr_t g_contig_delta_va_pa;
+static void osl_sec_dma_setup_contig_mem(osl_t *osh, unsigned long memsize, int regn);
+static int osl_sec_dma_alloc_contig_mem(osl_t *osh, unsigned long memsize, int regn);
+static void osl_sec_dma_free_contig_mem(osl_t *osh, u32 memsize, int regn);
+static void * osl_sec_dma_ioremap(osl_t *osh, struct page *page, size_t size,
+ bool iscache, bool isdecr);
+static void osl_sec_dma_iounmap(osl_t *osh, void *contig_base_va, size_t size);
+static void osl_sec_dma_init_elem_mem_block(osl_t *osh, size_t mbsize, int max,
+ sec_mem_elem_t **list);
+static void osl_sec_dma_deinit_elem_mem_block(osl_t *osh, size_t mbsize, int max,
+ void *sec_list_base);
+static sec_mem_elem_t * osl_sec_dma_alloc_mem_elem(osl_t *osh, void *va, uint size,
+ int direction, struct sec_cma_info *ptr_cma_info, uint offset);
+static void osl_sec_dma_free_mem_elem(osl_t *osh, sec_mem_elem_t *sec_mem_elem);
+static void osl_sec_dma_init_consistent(osl_t *osh);
+static void *osl_sec_dma_alloc_consistent(osl_t *osh, uint size, uint16 align_bits,
+ ulong *pap);
+static void osl_sec_dma_free_consistent(osl_t *osh, void *va, uint size, dmaaddr_t pa);
+#endif /* BCM_SECURE_DMA */
#define OSL_PKTTAG_CLEAR(p) \
do { \
@@ -213,14 +298,15 @@
/* Array bounds covered by ASSERT in osl_attach */
return linuxbcmerrormap[-bcmerror];
}
-#ifdef SHARED_OSL_CMN
+
osl_t *
+#ifdef SHARED_OSL_CMN
osl_attach(void *pdev, uint bustype, bool pkttag, void **osl_cmn)
-{
#else
-osl_t *
osl_attach(void *pdev, uint bustype, bool pkttag)
+#endif /* SHARED_OSL_CMN */
{
+#ifndef SHARED_OSL_CMN
void **osl_cmn = NULL;
#endif /* SHARED_OSL_CMN */
osl_t *osh;
@@ -261,6 +347,39 @@
osh->pub.pkttag = pkttag;
osh->bustype = bustype;
osh->magic = OS_HANDLE_MAGIC;
+#ifdef BCM_SECURE_DMA
+
+ osl_sec_dma_setup_contig_mem(osh, CMA_MEMBLOCK, CONT_ARMREGION);
+
+#ifdef BCM47XX_CA9
+ osh->contig_base_alloc_coherent_va = osl_sec_dma_ioremap(osh,
+ phys_to_page((u32)osh->contig_base_alloc),
+ CMA_DMA_DESC_MEMBLOCK, TRUE, TRUE);
+#else
+ osh->contig_base_alloc_coherent_va = osl_sec_dma_ioremap(osh,
+ phys_to_page((u32)osh->contig_base_alloc),
+ CMA_DMA_DESC_MEMBLOCK, FALSE, TRUE);
+#endif /* BCM47XX_CA9 */
+
+ osh->contig_base_alloc_coherent = osh->contig_base_alloc;
+ osl_sec_dma_init_consistent(osh);
+
+ osh->contig_base_alloc += CMA_DMA_DESC_MEMBLOCK;
+
+ osh->contig_base_alloc_va = osl_sec_dma_ioremap(osh,
+ phys_to_page((u32)osh->contig_base_alloc), CMA_DMA_DATA_MEMBLOCK, TRUE, FALSE);
+ osh->contig_base_va = osh->contig_base_alloc_va;
+
+ /*
+ * osl_sec_dma_init_elem_mem_block(osh, CMA_BUFSIZE_512, CMA_BUFNUM, &osh->sec_list_512);
+ * osh->sec_list_base_512 = osh->sec_list_512;
+ * osl_sec_dma_init_elem_mem_block(osh, CMA_BUFSIZE_2K, CMA_BUFNUM, &osh->sec_list_2048);
+ * osh->sec_list_base_2048 = osh->sec_list_2048;
+ */
+ osl_sec_dma_init_elem_mem_block(osh, CMA_BUFSIZE_4K, CMA_BUFNUM, &osh->sec_list_4096);
+ osh->sec_list_base_4096 = osh->sec_list_4096;
+
+#endif /* BCM_SECURE_DMA */
switch (bustype) {
case PCI_BUS:
@@ -293,47 +412,70 @@
int osl_static_mem_init(osl_t *osh, void *adapter)
{
#ifdef CONFIG_DHD_USE_STATIC_BUF
- if (!bcm_static_buf && adapter) {
- if (!(bcm_static_buf = (bcm_static_buf_t *)wifi_platform_prealloc(adapter,
- 3, STATIC_BUF_SIZE + STATIC_BUF_TOTAL_LEN))) {
- printk("can not alloc static buf!\n");
- bcm_static_skb = NULL;
- ASSERT(osh->magic == OS_HANDLE_MAGIC);
- kfree(osh);
- return -ENOMEM;
- }
- else
- printk("alloc static buf at %x!\n", (unsigned int)bcm_static_buf);
+ if (!bcm_static_buf && adapter) {
+ if (!(bcm_static_buf = (bcm_static_buf_t *)wifi_platform_prealloc(adapter,
+ 3, STATIC_BUF_SIZE + STATIC_BUF_TOTAL_LEN))) {
+ printk("can not alloc static buf!\n");
+ bcm_static_skb = NULL;
+ ASSERT(osh->magic == OS_HANDLE_MAGIC);
+ return -ENOMEM;
+ }
+ else
+ printk("alloc static buf at %p!\n", bcm_static_buf);
- sema_init(&bcm_static_buf->static_sem, 1);
+ sema_init(&bcm_static_buf->static_sem, 1);
- bcm_static_buf->buf_ptr = (unsigned char *)bcm_static_buf + STATIC_BUF_SIZE;
- }
+ bcm_static_buf->buf_ptr = (unsigned char *)bcm_static_buf + STATIC_BUF_SIZE;
+ }
#ifdef BCMSDIO
- if (!bcm_static_skb && adapter) {
- int i;
- void *skb_buff_ptr = 0;
- bcm_static_skb = (bcm_static_pkt_t *)((char *)bcm_static_buf + 2048);
- skb_buff_ptr = wifi_platform_prealloc(adapter, 4, 0);
- if (!skb_buff_ptr) {
- printk("cannot alloc static buf!\n");
- bcm_static_buf = NULL;
- bcm_static_skb = NULL;
- ASSERT(osh->magic == OS_HANDLE_MAGIC);
- kfree(osh);
- return -ENOMEM;
- }
+ if (!bcm_static_skb && adapter) {
+ int i;
+ void *skb_buff_ptr = 0;
+ bcm_static_skb = (bcm_static_pkt_t *)((char *)bcm_static_buf + 2048);
+ skb_buff_ptr = wifi_platform_prealloc(adapter, 4, 0);
+ if (!skb_buff_ptr) {
+ printk("cannot alloc static buf!\n");
+ bcm_static_buf = NULL;
+ bcm_static_skb = NULL;
+ ASSERT(osh->magic == OS_HANDLE_MAGIC);
+ return -ENOMEM;
+ }
- bcopy(skb_buff_ptr, bcm_static_skb, sizeof(struct sk_buff *) *
- (STATIC_PKT_MAX_NUM * 2 + STATIC_PKT_4PAGE_NUM));
- for (i = 0; i < STATIC_PKT_MAX_NUM * 2 + STATIC_PKT_4PAGE_NUM; i++)
- bcm_static_skb->pkt_use[i] = 0;
+ bcopy(skb_buff_ptr, bcm_static_skb, sizeof(struct sk_buff *) *
+ (STATIC_PKT_MAX_NUM * 2 + STATIC_PKT_4PAGE_NUM));
+ for (i = 0; i < STATIC_PKT_MAX_NUM * 2 + STATIC_PKT_4PAGE_NUM; i++)
+ bcm_static_skb->pkt_use[i] = 0;
- sema_init(&bcm_static_skb->osl_pkt_sem, 1);
- }
+ sema_init(&bcm_static_skb->osl_pkt_sem, 1);
+ }
#endif /* BCMSDIO */
+#if defined(BCMPCIE) && defined(DHD_USE_STATIC_FLOWRING)
+ if (!bcm_static_flowring && adapter) {
+ int i;
+ void *flowring_ptr = 0;
+ bcm_static_flowring =
+ (bcm_static_flowring_buf_t *)((char *)bcm_static_buf + 4096);
+ flowring_ptr = wifi_platform_prealloc(adapter, 10, 0);
+ if (!flowring_ptr) {
+ printk("%s: flowring_ptr is NULL\n", __FUNCTION__);
+ bcm_static_buf = NULL;
+ bcm_static_skb = NULL;
+ bcm_static_flowring = NULL;
+ ASSERT(osh->magic == OS_HANDLE_MAGIC);
+ return -ENOMEM;
+ }
+
+ bcopy(flowring_ptr, bcm_static_flowring->buf_ptr,
+ sizeof(void *) * STATIC_BUF_FLOWRING_NUM);
+ for (i = 0; i < STATIC_BUF_FLOWRING_NUM; i++) {
+ bcm_static_flowring->buf_use[i] = 0;
+ }
+
+ spin_lock_init(&bcm_static_flowring->flowring_lock);
+ }
+#endif /* BCMPCIE && DHD_USE_STATIC_FLOWRING */
#endif /* CONFIG_DHD_USE_STATIC_BUF */
return 0;
@@ -354,6 +496,13 @@
{
if (osh == NULL)
return;
+#ifdef BCM_SECURE_DMA
+ osl_sec_dma_free_contig_mem(osh, CMA_MEMBLOCK, CONT_ARMREGION);
+ osl_sec_dma_deinit_elem_mem_block(osh, CMA_BUFSIZE_512, CMA_BUFNUM, osh->sec_list_base_512);
+ osl_sec_dma_deinit_elem_mem_block(osh, CMA_BUFSIZE_2K, CMA_BUFNUM, osh->sec_list_base_2048);
+ osl_sec_dma_deinit_elem_mem_block(osh, CMA_BUFSIZE_4K, CMA_BUFNUM, osh->sec_list_base_4096);
+ osl_sec_dma_iounmap(osh, osh->contig_base_va, CMA_MEMBLOCK);
+#endif /* BCM_SECURE_DMA */
ASSERT(osh->magic == OS_HANDLE_MAGIC);
atomic_sub(1, &osh->cmn->refcount);
@@ -374,6 +523,11 @@
bcm_static_skb = 0;
}
#endif /* BCMSDIO */
+#if defined(BCMPCIE) && defined(DHD_USE_STATIC_FLOWRING)
+ if (bcm_static_flowring) {
+ bcm_static_flowring = 0;
+ }
+#endif /* BCMPCIE && DHD_USE_STATIC_FLOWRING */
#endif /* CONFIG_DHD_USE_STATIC_BUF */
return 0;
}
@@ -543,6 +697,11 @@
bcm_static_skb = 0;
}
#endif /* BCMSDIO */
+#if defined(BCMPCIE) && defined(DHD_USE_STATIC_FLOWRING)
+ if (bcm_static_flowring) {
+ bcm_static_flowring = 0;
+ }
+#endif /* BCMPCIE && DHD_USE_STATIC_FLOWRING */
#endif /* CONFIG_DHD_USE_STATIC_BUF */
bb = b;
@@ -633,18 +792,17 @@
/* Account for a downstream forwarder delivered packet to a WL/DHD driver.
* Increment a GMAC forwarder interface's pktalloced count.
*/
-#ifdef BCMDBG_CTRACE
void BCMFASTPATH
+#ifdef BCMDBG_CTRACE
osl_pkt_frmfwder(osl_t *osh, void *skbs, int skb_cnt, int line, char *file)
#else
-void BCMFASTPATH
osl_pkt_frmfwder(osl_t *osh, void *skbs, int skb_cnt)
#endif /* BCMDBG_CTRACE */
{
#if defined(BCMDBG_CTRACE)
int i;
struct sk_buff *skb;
-#endif
+#endif
#if defined(BCMDBG_CTRACE)
if (skb_cnt > 1) {
@@ -663,7 +821,7 @@
ADD_CTRACE(osh, skb, file, line);
#endif /* BCMDBG_CTRACE */
}
-#endif
+#endif
atomic_add(skb_cnt, &osh->cmn->pktalloced);
}
@@ -709,11 +867,10 @@
* In the process, native packet is destroyed, there is no copying
* Also, a packettag is zeroed out
*/
-#ifdef BCMDBG_CTRACE
void * BCMFASTPATH
+#ifdef BCMDBG_CTRACE
osl_pkt_frmnative(osl_t *osh, void *pkt, int line, char *file)
#else
-void * BCMFASTPATH
osl_pkt_frmnative(osl_t *osh, void *pkt)
#endif /* BCMDBG_CTRACE */
{
@@ -745,11 +902,10 @@
}
/* Return a new packet. zero out pkttag */
-#ifdef BCMDBG_CTRACE
void * BCMFASTPATH
+#ifdef BCMDBG_CTRACE
osl_pktget(osl_t *osh, uint len, int line, char *file)
#else
-void * BCMFASTPATH
osl_pktget(osl_t *osh, uint len)
#endif /* BCMDBG_CTRACE */
{
@@ -758,10 +914,11 @@
#ifdef CTFPOOL
/* Allocate from local pool */
skb = osl_pktfastget(osh, len);
- if ((skb != NULL) || ((skb = osl_alloc_skb(osh, len)) != NULL)) {
+ if ((skb != NULL) || ((skb = osl_alloc_skb(osh, len)) != NULL))
#else /* CTFPOOL */
- if ((skb = osl_alloc_skb(osh, len))) {
+ if ((skb = osl_alloc_skb(osh, len)))
#endif /* CTFPOOL */
+ {
skb->tail += len;
skb->len += len;
skb->priority = 0;
@@ -872,6 +1029,9 @@
int i = 0;
struct sk_buff *skb;
+ if (!bcm_static_skb)
+ return osl_pktget(osh, len);
+
if (len > DHD_SKB_MAX_BUFSIZE) {
printk("%s: attempt to allocate huge packet (0x%x)\n", __FUNCTION__, len);
return osl_pktget(osh, len);
@@ -889,7 +1049,11 @@
bcm_static_skb->pkt_use[i] = 1;
skb = bcm_static_skb->skb_4k[i];
+#ifdef NET_SKBUFF_DATA_USES_OFFSET
+ skb_set_tail_pointer(skb, len);
+#else
skb->tail = skb->data + len;
+#endif /* NET_SKBUFF_DATA_USES_OFFSET */
skb->len = len;
up(&bcm_static_skb->osl_pkt_sem);
@@ -907,7 +1071,11 @@
if (i != STATIC_PKT_MAX_NUM) {
bcm_static_skb->pkt_use[i + STATIC_PKT_MAX_NUM] = 1;
skb = bcm_static_skb->skb_8k[i];
+#ifdef NET_SKBUFF_DATA_USES_OFFSET
+ skb_set_tail_pointer(skb, len);
+#else
skb->tail = skb->data + len;
+#endif /* NET_SKBUFF_DATA_USES_OFFSET */
skb->len = len;
up(&bcm_static_skb->osl_pkt_sem);
@@ -920,13 +1088,17 @@
bcm_static_skb->pkt_use[STATIC_PKT_MAX_NUM * 2] = 1;
skb = bcm_static_skb->skb_16k;
+#ifdef NET_SKBUFF_DATA_USES_OFFSET
+ skb_set_tail_pointer(skb, len);
+#else
skb->tail = skb->data + len;
+#endif /* NET_SKBUFF_DATA_USES_OFFSET */
skb->len = len;
up(&bcm_static_skb->osl_pkt_sem);
return skb;
}
-#endif
+#endif /* ENHANCED_STATIC_BUF */
up(&bcm_static_skb->osl_pkt_sem);
printk("%s: all static pkt in use!\n", __FUNCTION__);
@@ -968,6 +1140,92 @@
up(&bcm_static_skb->osl_pkt_sem);
osl_pktfree(osh, p, send);
}
+
+#if defined(BCMPCIE) && defined(DHD_USE_STATIC_FLOWRING)
+void*
+osl_dma_alloc_consistent_static(osl_t *osh, uint size, uint16 align_bits,
+ uint *alloced, dmaaddr_t *pap, uint16 idx)
+{
+ void *va = NULL;
+ uint16 align = (1 << align_bits);
+ uint16 flow_id = RINGID_TO_FLOWID(idx);
+ unsigned long flags;
+
+ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
+
+ if (!ISALIGNED(DMA_CONSISTENT_ALIGN, align))
+ size += align;
+
+ if ((flow_id < 0) || (flow_id >= STATIC_BUF_FLOWRING_NUM)) {
+ printk("%s: flow_id %d is wrong\n", __FUNCTION__, flow_id);
+ return osl_dma_alloc_consistent(osh, size, align_bits,
+ alloced, pap);
+ }
+
+ if (!bcm_static_flowring) {
+ printk("%s: bcm_static_flowring is not initialized\n",
+ __FUNCTION__);
+ return osl_dma_alloc_consistent(osh, size, align_bits,
+ alloced, pap);
+ }
+
+ if (size > STATIC_BUF_FLOWRING_SIZE) {
+ printk("%s: attempt to allocate huge packet, size=%d\n",
+ __FUNCTION__, size);
+ return osl_dma_alloc_consistent(osh, size, align_bits,
+ alloced, pap);
+ }
+
+ *alloced = size;
+
+ spin_lock_irqsave(&bcm_static_flowring->flowring_lock, flags);
+ if (bcm_static_flowring->buf_use[flow_id]) {
+ printk("%s: flowring %d is already alloced\n",
+ __FUNCTION__, flow_id);
+ spin_unlock_irqrestore(&bcm_static_flowring->flowring_lock, flags);
+ return NULL;
+ }
+
+ va = bcm_static_flowring->buf_ptr[flow_id];
+ if (va) {
+ *pap = (ulong)__virt_to_phys((ulong)va);
+ bcm_static_flowring->buf_use[flow_id] = 1;
+ }
+ spin_unlock_irqrestore(&bcm_static_flowring->flowring_lock, flags);
+
+ return va;
+}
+
+void
+osl_dma_free_consistent_static(osl_t *osh, void *va, uint size,
+ dmaaddr_t pa, uint16 idx)
+{
+ uint16 flow_id = RINGID_TO_FLOWID(idx);
+ unsigned long flags;
+
+ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
+
+ if ((flow_id < 0) || (flow_id >= STATIC_BUF_FLOWRING_NUM)) {
+ printk("%s: flow_id %d is wrong\n", __FUNCTION__, flow_id);
+ return osl_dma_free_consistent(osh, va, size, pa);
+ }
+
+ if (!bcm_static_flowring) {
+ printk("%s: bcm_static_flowring is not initialized\n",
+ __FUNCTION__);
+ return osl_dma_free_consistent(osh, va, size, pa);
+ }
+
+ spin_lock_irqsave(&bcm_static_flowring->flowring_lock, flags);
+ if (bcm_static_flowring->buf_use[flow_id]) {
+ bcm_static_flowring->buf_use[flow_id] = 0;
+ } else {
+ printk("%s: flowring %d is already freed\n",
+ __FUNCTION__, flow_id);
+ }
+ spin_unlock_irqrestore(&bcm_static_flowring->flowring_lock, flags);
+}
+#endif /* BCMPCIE && DHD_USE_STATIC_FLOWRING */
#endif /* CONFIG_DHD_USE_STATIC_BUF */
uint32
@@ -1094,7 +1352,7 @@
if (bcm_static_buf)
{
int i = 0;
- if ((size >= PAGE_SIZE)&&(size <= STATIC_BUF_SIZE))
+ if ((size >= PAGE_SIZE) && (size <= STATIC_BUF_SIZE))
{
down(&bcm_static_buf->static_sem);
@@ -1227,6 +1485,7 @@
size += align;
*alloced = size;
+#ifndef BCM_SECURE_DMA
#if defined(BCM47XX_CA9) && defined(__ARM_ARCH_7A__)
va = kmalloc(size, GFP_ATOMIC | __GFP_ZERO);
if (va)
@@ -1234,23 +1493,38 @@
#else
{
dma_addr_t pap_lin;
- va = pci_alloc_consistent(osh->pdev, size, &pap_lin);
+ struct pci_dev *hwdev = osh->pdev;
+#ifdef PCIE_TX_DEFERRAL
+ va = dma_alloc_coherent(&hwdev->dev, size, &pap_lin, GFP_KERNEL);
+#else
+ va = dma_alloc_coherent(&hwdev->dev, size, &pap_lin, GFP_ATOMIC);
+#endif
*pap = (dmaaddr_t)pap_lin;
}
#endif /* BCM47XX_CA9 && __ARM_ARCH_7A__ */
+#else
+ va = osl_sec_dma_alloc_consistent(osh, size, align_bits, pap);
+#endif /* BCM_SECURE_DMA */
return va;
}
void
osl_dma_free_consistent(osl_t *osh, void *va, uint size, dmaaddr_t pa)
{
+#ifndef BCM_SECURE_DMA
+#if !defined(BCM47XX_CA9) || !defined(__ARM_ARCH_7A__)
+ struct pci_dev *hwdev = osh->pdev;
+#endif
ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
#if defined(BCM47XX_CA9) && defined(__ARM_ARCH_7A__)
kfree(va);
#else
- pci_free_consistent(osh->pdev, size, va, (dma_addr_t)pa);
+ dma_free_coherent(&hwdev->dev, size, va, (dma_addr_t)pa);
#endif /* BCM47XX_CA9 && __ARM_ARCH_7A__ */
+#else
+ osl_sec_dma_free_consistent(osh, va, size, pa);
+#endif /* BCM_SECURE_DMA */
}
dmaaddr_t BCMFASTPATH
@@ -1338,22 +1612,33 @@
inline void BCMFASTPATH
osl_cache_flush(void *va, uint size)
{
+#ifndef BCM_SECURE_DMA
#ifdef BCM47XX_ACP_WAR
if (virt_to_phys(va) < ACP_WIN_LIMIT)
return;
#endif
if (size > 0)
dma_sync_single_for_device(OSH_NULL, virt_to_dma(OSH_NULL, va), size, DMA_TX);
+#else
+ phys_addr_t orig_pa = (phys_addr_t)(va - g_contig_delta_va_pa);
+ if (size > 0)
+ dma_sync_single_for_device(OSH_NULL, orig_pa, size, DMA_TX);
+#endif /* defined BCM_SECURE_DMA */
}
inline void BCMFASTPATH
osl_cache_inv(void *va, uint size)
{
+#ifndef BCM_SECURE_DMA
#ifdef BCM47XX_ACP_WAR
if (virt_to_phys(va) < ACP_WIN_LIMIT)
return;
#endif
dma_sync_single_for_cpu(OSH_NULL, virt_to_dma(OSH_NULL, va), size, DMA_RX);
+#else
+ phys_addr_t orig_pa = (phys_addr_t)(va - g_contig_delta_va_pa);
+ dma_sync_single_for_cpu(OSH_NULL, orig_pa, size, DMA_RX);
+#endif /* defined BCM_SECURE_DMA */
}
inline void osl_prefetch(const void *ptr)
@@ -1374,7 +1659,7 @@
return arch_is_coherent();
#endif
}
-#endif
+#endif
#if defined(BCMASSERT_LOG)
void
@@ -1399,7 +1684,7 @@
}
-#endif
+#endif
void
osl_delay(uint usec)
@@ -1429,11 +1714,10 @@
/* Clone a packet.
* The pkttag contents are NOT cloned.
*/
-#ifdef BCMDBG_CTRACE
void *
+#ifdef BCMDBG_CTRACE
osl_pktdup(osl_t *osh, void *skb, int line, char *file)
#else
-void *
osl_pktdup(osl_t *osh, void *skb)
#endif /* BCMDBG_CTRACE */
{
@@ -1678,3 +1962,528 @@
{
return (osh->flags & mask);
}
+#ifdef BCM_SECURE_DMA
+
+static void
+osl_sec_dma_setup_contig_mem(osl_t *osh, unsigned long memsize, int regn)
+{
+ int ret;
+
+#if defined(__ARM_ARCH_7A__)
+ if (regn == CONT_ARMREGION) {
+ ret = osl_sec_dma_alloc_contig_mem(osh, memsize, regn);
+ if (ret != BCME_OK)
+ printk("linux_osl.c: CMA memory access failed\n");
+ }
+#endif
+ /* implement the MIPS Here */
+}
+
+static int
+osl_sec_dma_alloc_contig_mem(osl_t *osh, unsigned long memsize, int regn)
+{
+ u64 addr;
+
+ printk("linux_osl.c: The value of cma mem block size = %ld\n", memsize);
+ osh->cma = cma_dev_get_cma_dev(regn);
+ printk("The value of cma = %p\n", osh->cma);
+ if (!osh->cma) {
+ printk("linux_osl.c:contig_region index is invalid\n");
+ return BCME_ERROR;
+ }
+ if (cma_dev_get_mem(osh->cma, &addr, (u32)memsize, SEC_DMA_ALIGN) < 0) {
+ printk("linux_osl.c: contiguous memory block allocation failure\n");
+ return BCME_ERROR;
+ }
+ osh->contig_base_alloc = (phys_addr_t)addr;
+ osh->contig_base = (phys_addr_t)osh->contig_base_alloc;
+ printk("contig base alloc=%lx \n", (ulong)osh->contig_base_alloc);
+
+ return BCME_OK;
+}
+
+static void
+osl_sec_dma_free_contig_mem(osl_t *osh, u32 memsize, int regn)
+{
+ int ret;
+
+ ret = cma_dev_put_mem(osh->cma, (u64)osh->contig_base, memsize);
+ if (ret)
+ printf("%s contig base free failed\n", __FUNCTION__);
+}
+
+static void *
+osl_sec_dma_ioremap(osl_t *osh, struct page *page, size_t size, bool iscache, bool isdecr)
+{
+
+ struct page **map;
+ int order, i;
+ void *addr = NULL;
+
+ size = PAGE_ALIGN(size);
+ order = get_order(size);
+
+ map = kmalloc(sizeof(struct page *) << order, GFP_ATOMIC);
+
+ if (map == NULL)
+ return NULL;
+
+ for (i = 0; i < (size >> PAGE_SHIFT); i++)
+ map[i] = page + i;
+
+ if (iscache) {
+ addr = vmap(map, size >> PAGE_SHIFT, VM_MAP, __pgprot(PAGE_KERNEL));
+ if (isdecr) {
+ osh->contig_delta_va_pa = (phys_addr_t)(addr - page_to_phys(page));
+ g_contig_delta_va_pa = osh->contig_delta_va_pa;
+ }
+ }
+ else {
+
+#if defined(__ARM_ARCH_7A__)
+ addr = vmap(map, size >> PAGE_SHIFT, VM_MAP,
+ pgprot_noncached(__pgprot(PAGE_KERNEL)));
+#endif
+ if (isdecr) {
+ osh->contig_delta_va_pa = (phys_addr_t)(addr - page_to_phys(page));
+ g_contig_delta_va_pa = osh->contig_delta_va_pa;
+ }
+ }
+
+ kfree(map);
+ return (void *)addr;
+}
+
+static void
+osl_sec_dma_iounmap(osl_t *osh, void *contig_base_va, size_t size)
+{
+ vunmap(contig_base_va);
+}
+
+static void
+osl_sec_dma_deinit_elem_mem_block(osl_t *osh, size_t mbsize, int max, void *sec_list_base)
+{
+ if (sec_list_base)
+ kfree(sec_list_base);
+}
+
+static void
+osl_sec_dma_init_elem_mem_block(osl_t *osh, size_t mbsize, int max, sec_mem_elem_t **list)
+{
+ int i;
+ sec_mem_elem_t *sec_mem_elem;
+
+ if ((sec_mem_elem = kmalloc(sizeof(sec_mem_elem_t)*(max), GFP_ATOMIC)) != NULL) {
+
+ *list = sec_mem_elem;
+ bzero(sec_mem_elem, sizeof(sec_mem_elem_t)*(max));
+ for (i = 0; i < max-1; i++) {
+ sec_mem_elem->next = (sec_mem_elem + 1);
+ sec_mem_elem->size = mbsize;
+ sec_mem_elem->pa_cma = (u32)osh->contig_base_alloc;
+ sec_mem_elem->vac = osh->contig_base_alloc_va;
+
+ osh->contig_base_alloc += mbsize;
+ osh->contig_base_alloc_va += mbsize;
+
+ sec_mem_elem = sec_mem_elem + 1;
+ }
+ sec_mem_elem->next = NULL;
+ sec_mem_elem->size = mbsize;
+ sec_mem_elem->pa_cma = (u32)osh->contig_base_alloc;
+ sec_mem_elem->vac = osh->contig_base_alloc_va;
+
+ osh->contig_base_alloc += mbsize;
+ osh->contig_base_alloc_va += mbsize;
+
+ }
+ else
+ printf("%s sec mem elem kmalloc failed\n", __FUNCTION__);
+}
+
+
+static sec_mem_elem_t * BCMFASTPATH
+osl_sec_dma_alloc_mem_elem(osl_t *osh, void *va, uint size, int direction,
+ struct sec_cma_info *ptr_cma_info, uint offset)
+{
+ sec_mem_elem_t *sec_mem_elem = NULL;
+
+ if (size <= 512 && osh->sec_list_512) {
+ sec_mem_elem = osh->sec_list_512;
+ osh->sec_list_512 = sec_mem_elem->next;
+ }
+ else if (size <= 2048 && osh->sec_list_2048) {
+ sec_mem_elem = osh->sec_list_2048;
+ osh->sec_list_2048 = sec_mem_elem->next;
+ }
+ else if (osh->sec_list_4096) {
+ sec_mem_elem = osh->sec_list_4096;
+ osh->sec_list_4096 = sec_mem_elem->next;
+ } else {
+ printf("%s No matching Pool available size=%d \n", __FUNCTION__, size);
+ return NULL;
+ }
+
+ if (sec_mem_elem != NULL) {
+ sec_mem_elem->next = NULL;
+
+ if (ptr_cma_info->sec_alloc_list_tail) {
+ ptr_cma_info->sec_alloc_list_tail->next = sec_mem_elem;
+ }
+
+ ptr_cma_info->sec_alloc_list_tail = sec_mem_elem;
+ if (ptr_cma_info->sec_alloc_list == NULL)
+ ptr_cma_info->sec_alloc_list = sec_mem_elem;
+ }
+ return sec_mem_elem;
+}
+
+static void BCMFASTPATH
+osl_sec_dma_free_mem_elem(osl_t *osh, sec_mem_elem_t *sec_mem_elem)
+{
+ sec_mem_elem->dma_handle = 0x0;
+ sec_mem_elem->va = NULL;
+
+ if (sec_mem_elem->size == 512) {
+ sec_mem_elem->next = osh->sec_list_512;
+ osh->sec_list_512 = sec_mem_elem;
+ }
+ else if (sec_mem_elem->size == 2048) {
+ sec_mem_elem->next = osh->sec_list_2048;
+ osh->sec_list_2048 = sec_mem_elem;
+ }
+ else if (sec_mem_elem->size == 4096) {
+ sec_mem_elem->next = osh->sec_list_4096;
+ osh->sec_list_4096 = sec_mem_elem;
+ }
+ else
+ printf("%s free failed size=%d \n", __FUNCTION__, sec_mem_elem->size);
+}
+
+
+static sec_mem_elem_t * BCMFASTPATH
+osl_sec_dma_find_rem_elem(osl_t *osh, struct sec_cma_info *ptr_cma_info, dma_addr_t dma_handle)
+{
+ sec_mem_elem_t *sec_mem_elem = ptr_cma_info->sec_alloc_list;
+ sec_mem_elem_t *sec_prv_elem = ptr_cma_info->sec_alloc_list;
+
+ if (sec_mem_elem->dma_handle == dma_handle) {
+
+ ptr_cma_info->sec_alloc_list = sec_mem_elem->next;
+
+ if (sec_mem_elem == ptr_cma_info->sec_alloc_list_tail) {
+ ptr_cma_info->sec_alloc_list_tail = NULL;
+ ASSERT(ptr_cma_info->sec_alloc_list == NULL);
+ }
+
+ return sec_mem_elem;
+ }
+
+ while (sec_mem_elem != NULL) {
+
+ if (sec_mem_elem->dma_handle == dma_handle) {
+
+ sec_prv_elem->next = sec_mem_elem->next;
+ if (sec_mem_elem == ptr_cma_info->sec_alloc_list_tail)
+ ptr_cma_info->sec_alloc_list_tail = sec_prv_elem;
+
+ return sec_mem_elem;
+ }
+ sec_prv_elem = sec_mem_elem;
+ sec_mem_elem = sec_mem_elem->next;
+ }
+ return NULL;
+}
+
+static sec_mem_elem_t *
+osl_sec_dma_rem_first_elem(osl_t *osh, struct sec_cma_info *ptr_cma_info)
+{
+ sec_mem_elem_t *sec_mem_elem = ptr_cma_info->sec_alloc_list;
+
+ if (sec_mem_elem) {
+
+ ptr_cma_info->sec_alloc_list = sec_mem_elem->next;
+
+ if (ptr_cma_info->sec_alloc_list == NULL)
+ ptr_cma_info->sec_alloc_list_tail = NULL;
+
+ return sec_mem_elem;
+
+ } else
+ return NULL;
+}
+
+static void * BCMFASTPATH
+osl_sec_dma_last_elem(osl_t *osh, struct sec_cma_info *ptr_cma_info)
+{
+ return ptr_cma_info->sec_alloc_list_tail;
+}
+
+dma_addr_t BCMFASTPATH
+osl_sec_dma_map_txmeta(osl_t *osh, void *va, uint size, int direction, void *p,
+ hnddma_seg_map_t *dmah, void *ptr_cma_info)
+{
+ sec_mem_elem_t *sec_mem_elem;
+ struct page *pa_cma_page;
+ uint loffset;
+ void *vaorig = va + size;
+ dma_addr_t dma_handle = 0x0;
+ /* packet will be the one added with osl_sec_dma_map() just before this call */
+
+ sec_mem_elem = osl_sec_dma_last_elem(osh, ptr_cma_info);
+
+ if (sec_mem_elem && sec_mem_elem->va == vaorig) {
+
+ pa_cma_page = phys_to_page(sec_mem_elem->pa_cma);
+ loffset = sec_mem_elem->pa_cma -(sec_mem_elem->pa_cma & ~(PAGE_SIZE-1));
+
+ dma_handle = dma_map_page(osh->cma->dev, pa_cma_page, loffset, size,
+ (direction == DMA_TX ? DMA_TO_DEVICE:DMA_FROM_DEVICE));
+
+ } else {
+ printf("%s: error orig va not found va = 0x%p \n",
+ __FUNCTION__, vaorig);
+ }
+ return dma_handle;
+}
+
+dma_addr_t BCMFASTPATH
+osl_sec_dma_map(osl_t *osh, void *va, uint size, int direction, void *p,
+ hnddma_seg_map_t *dmah, void *ptr_cma_info, uint offset)
+{
+
+ sec_mem_elem_t *sec_mem_elem;
+ struct page *pa_cma_page;
+ void *pa_cma_kmap_va = NULL;
+ int *fragva;
+ uint buflen = 0;
+ struct sk_buff *skb;
+ dma_addr_t dma_handle = 0x0;
+ uint loffset;
+ int i = 0;
+
+ sec_mem_elem = osl_sec_dma_alloc_mem_elem(osh, va, size, direction, ptr_cma_info, offset);
+
+ if (sec_mem_elem == NULL) {
+ printk("linux_osl.c: osl_sec_dma_map - cma allocation failed\n");
+ return 0;
+ }
+ sec_mem_elem->va = va;
+ sec_mem_elem->direction = direction;
+ pa_cma_page = phys_to_page(sec_mem_elem->pa_cma);
+
+ loffset = sec_mem_elem->pa_cma -(sec_mem_elem->pa_cma & ~(PAGE_SIZE-1));
+ /* pa_cma_kmap_va = kmap_atomic(pa_cma_page);
+ * pa_cma_kmap_va += loffset;
+ */
+
+ pa_cma_kmap_va = sec_mem_elem->vac;
+
+ if (direction == DMA_TX) {
+
+ if (p == NULL) {
+
+ memcpy(pa_cma_kmap_va+offset, va, size);
+ buflen = size;
+ }
+ else {
+ for (skb = (struct sk_buff *)p; skb != NULL; skb = PKTNEXT(osh, skb)) {
+ if (skb_is_nonlinear(skb)) {
+
+
+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+ skb_frag_t *f = &skb_shinfo(skb)->frags[i];
+ fragva = kmap_atomic(skb_frag_page(f));
+ memcpy((pa_cma_kmap_va+offset+buflen),
+ (fragva + f->page_offset), skb_frag_size(f));
+ kunmap_atomic(fragva);
+ buflen += skb_frag_size(f);
+ }
+ }
+ else {
+ memcpy((pa_cma_kmap_va+offset+buflen), skb->data, skb->len);
+ buflen += skb->len;
+ }
+ }
+
+ }
+ if (dmah) {
+ dmah->nsegs = 1;
+ dmah->origsize = buflen;
+ }
+ }
+
+ else if (direction == DMA_RX)
+ {
+ buflen = size;
+ if ((p != NULL) && (dmah != NULL)) {
+ dmah->nsegs = 1;
+ dmah->origsize = buflen;
+ }
+ }
+ if (direction == DMA_RX || direction == DMA_TX) {
+
+ dma_handle = dma_map_page(osh->cma->dev, pa_cma_page, loffset+offset, buflen,
+ (direction == DMA_TX ? DMA_TO_DEVICE:DMA_FROM_DEVICE));
+
+ }
+ if (dmah) {
+ dmah->segs[0].addr = dma_handle;
+ dmah->segs[0].length = buflen;
+ }
+ sec_mem_elem->dma_handle = dma_handle;
+ /* kunmap_atomic(pa_cma_kmap_va-loffset); */
+ return dma_handle;
+}
+
+dma_addr_t BCMFASTPATH
+osl_sec_dma_dd_map(osl_t *osh, void *va, uint size, int direction, void *p, hnddma_seg_map_t *map)
+{
+
+ struct page *pa_cma_page;
+ phys_addr_t pa_cma;
+ dma_addr_t dma_handle = 0x0;
+ uint loffset;
+
+ pa_cma = (phys_addr_t)(va - osh->contig_delta_va_pa);
+ pa_cma_page = phys_to_page(pa_cma);
+ loffset = pa_cma -(pa_cma & ~(PAGE_SIZE-1));
+
+ dma_handle = dma_map_page(osh->cma->dev, pa_cma_page, loffset, size,
+ (direction == DMA_TX ? DMA_TO_DEVICE:DMA_FROM_DEVICE));
+
+ return dma_handle;
+
+}
+
+void BCMFASTPATH
+osl_sec_dma_unmap(osl_t *osh, dma_addr_t dma_handle, uint size, int direction,
+void *p, hnddma_seg_map_t *map, void *ptr_cma_info, uint offset)
+{
+ sec_mem_elem_t *sec_mem_elem;
+ struct page *pa_cma_page;
+ void *pa_cma_kmap_va = NULL;
+ uint buflen = 0;
+ dma_addr_t pa_cma;
+ void *va;
+ uint loffset = 0;
+ int read_count = 0;
+ BCM_REFERENCE(buflen);
+ BCM_REFERENCE(read_count);
+
+ sec_mem_elem = osl_sec_dma_find_rem_elem(osh, ptr_cma_info, dma_handle);
+ if (sec_mem_elem == NULL) {
+ printf("%s sec_mem_elem is NULL and dma_handle =0x%lx and dir=%d\n",
+ __FUNCTION__, (ulong)dma_handle, direction);
+ return;
+ }
+
+ va = sec_mem_elem->va;
+ va -= offset;
+ pa_cma = sec_mem_elem->pa_cma;
+
+ pa_cma_page = phys_to_page(pa_cma);
+ loffset = sec_mem_elem->pa_cma -(sec_mem_elem->pa_cma & ~(PAGE_SIZE-1));
+
+ if (direction == DMA_RX) {
+
+ if (p == NULL) {
+
+ /* pa_cma_kmap_va = kmap_atomic(pa_cma_page);
+ * pa_cma_kmap_va += loffset;
+ */
+
+ pa_cma_kmap_va = sec_mem_elem->vac;
+
+ dma_unmap_page(osh->cma->dev, pa_cma, size, DMA_FROM_DEVICE);
+ memcpy(va, pa_cma_kmap_va, size);
+ /* kunmap_atomic(pa_cma_kmap_va); */
+ }
+ } else {
+ dma_unmap_page(osh->cma->dev, pa_cma, size+offset, DMA_TO_DEVICE);
+ }
+
+ osl_sec_dma_free_mem_elem(osh, sec_mem_elem);
+}
+
+void
+osl_sec_dma_unmap_all(osl_t *osh, void *ptr_cma_info)
+{
+
+ sec_mem_elem_t *sec_mem_elem;
+
+ sec_mem_elem = osl_sec_dma_rem_first_elem(osh, ptr_cma_info);
+
+ while (sec_mem_elem != NULL) {
+
+ dma_unmap_page(osh->cma->dev, sec_mem_elem->pa_cma, sec_mem_elem->size,
+ sec_mem_elem->direction == DMA_TX ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+ osl_sec_dma_free_mem_elem(osh, sec_mem_elem);
+
+ sec_mem_elem = osl_sec_dma_rem_first_elem(osh, ptr_cma_info);
+ }
+}
+
+static void
+osl_sec_dma_init_consistent(osl_t *osh)
+{
+ int i;
+ void *temp_va = osh->contig_base_alloc_coherent_va;
+ phys_addr_t temp_pa = osh->contig_base_alloc_coherent;
+
+ for (i = 0; i < SEC_CMA_COHERENT_MAX; i++) {
+ osh->sec_cma_coherent[i].avail = TRUE;
+ osh->sec_cma_coherent[i].va = temp_va;
+ osh->sec_cma_coherent[i].pa = temp_pa;
+ temp_va += SEC_CMA_COHERENT_BLK;
+ temp_pa += SEC_CMA_COHERENT_BLK;
+ }
+}
+
+static void *
+osl_sec_dma_alloc_consistent(osl_t *osh, uint size, uint16 align_bits, ulong *pap)
+{
+
+ void *temp_va = NULL;
+ ulong temp_pa = 0;
+ int i;
+
+ if (size > SEC_CMA_COHERENT_BLK) {
+ printf("%s unsupported size\n", __FUNCTION__);
+ return NULL;
+ }
+
+ for (i = 0; i < SEC_CMA_COHERENT_MAX; i++) {
+ if (osh->sec_cma_coherent[i].avail == TRUE) {
+ temp_va = osh->sec_cma_coherent[i].va;
+ temp_pa = osh->sec_cma_coherent[i].pa;
+ osh->sec_cma_coherent[i].avail = FALSE;
+ break;
+ }
+ }
+
+ if (i == SEC_CMA_COHERENT_MAX)
+ printf("%s:No coherent mem: va = 0x%p pa = 0x%lx size = %d\n", __FUNCTION__,
+ temp_va, (ulong)temp_pa, size);
+
+ *pap = (unsigned long)temp_pa;
+ return temp_va;
+}
+
+static void
+osl_sec_dma_free_consistent(osl_t *osh, void *va, uint size, dmaaddr_t pa)
+{
+ int i = 0;
+
+ for (i = 0; i < SEC_CMA_COHERENT_MAX; i++) {
+ if (osh->sec_cma_coherent[i].va == va) {
+ osh->sec_cma_coherent[i].avail = TRUE;
+ break;
+ }
+ }
+ if (i == SEC_CMA_COHERENT_MAX)
+ printf("%s:Error: va = 0x%p pa = 0x%lx size = %d\n", __FUNCTION__,
+ va, (ulong)pa, size);
+}
+
+#endif /* BCM_SECURE_DMA */
diff -Nur a/drivers/net/wireless/bcmdhd/Makefile c/drivers/net/wireless/bcmdhd/Makefile
--- a/drivers/net/wireless/bcmdhd/Makefile 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/Makefile 2016-09-30 02:00:11.748108740 +0200
@@ -1,24 +1,15 @@
# bcmdhd
# 1. WL_IFACE_COMB_NUM_CHANNELS must be added if Android version is 4.4 with Kernel version 3.0~3.4,
# otherwise please remove it.
-DHDCFLAGS = -Wall -Wstrict-prototypes -Dlinux -DBCMDRIVER \
+
+DHDCFLAGS = -Wall -Wstrict-prototypes -Dlinux -DBCMDRIVER -DSDTEST \
-DBCMDONGLEHOST -DUNRELEASEDCHIP -DBCMDMA32 -DBCMFILEIMAGE \
- -DDHDTHREAD -DDHD_DEBUG -DSHOW_EVENTS -DBCMDBG \
- -DWIFI_ACT_FRAME -DARP_OFFLOAD_SUPPORT \
- -DKEEP_ALIVE -DPKT_FILTER_SUPPORT \
- -DEMBEDDED_PLATFORM -DENABLE_INSMOD_NO_FW_LOAD -DPNO_SUPPORT \
- -DDHD_USE_IDLECOUNT -DSET_RANDOM_MAC_SOFTAP -DVSDB \
- -DWL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST \
- -DESCAN_RESULT_PATCH -DSUPPORT_PM2_ONLY -DWLTDLS \
+ -DDHDTHREAD -DDHD_DEBUG -DSHOW_EVENTS -DBCMDBG -DGET_OTP_MAC_ENABLE \
+ -DWIFI_ACT_FRAME -DARP_OFFLOAD_SUPPORT -DSUPPORT_PM2_ONLY \
+ -DKEEP_ALIVE -DPKT_FILTER_SUPPORT -DPNO_SUPPORT -DDHDTCPACK_SUPPRESS \
-DDHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT -DRXFRAME_THREAD \
- -DMIRACAST_AMPDU_SIZE=8 -DGET_CUSTOM_MAC_ENABLE \
- -DSDTEST -DBDC -DDHD_BCMEVENTS -DPROP_TXSTATUS -DPROP_TXSTATUS_VSDB \
- -DWL_SUPPORT_BACKPORTED_KPATCHES -DDHDTCPACK_SUPPRESS \
- -Idrivers/net/wireless/bcmdhd -Idrivers/net/wireless/bcmdhd/include
-
-DHDCFLAGS += \
- -DMMC_SDIO_ABORT -DBCMSDIO -DBCMLXSDMMC -DSDIO_CRC_ERROR_FIX \
- -DCUSTOM_SDIO_F2_BLKSIZE=128 -DUSE_SDIOFIFO_IOVAR
+ -DSWTXGLOM \
+ -I$(src) -I$(src)/include
DHDOFILES = aiutils.o siutils.o sbutils.o bcmutils.o bcmwifi_channels.o \
dhd_linux.o dhd_linux_platdev.o dhd_linux_sched.o dhd_pno.o \
@@ -26,23 +17,15 @@
bcmevent.o hndpmu.o linux_osl.o wldev_common.o wl_android.o \
hnd_pktq.o hnd_pktpool.o dhd_config.o
+ifneq ($(CONFIG_BCMDHD_SDIO),)
+DHDCFLAGS += \
+ -DBCMSDIO -DMMC_SDIO_ABORT -DBCMLXSDMMC -DUSE_SDIOFIFO_IOVAR \
+ -DBDC -DPROP_TXSTATUS -DDHD_USE_IDLECOUNT -DBCMSDIOH_TXGLOM \
+ -DCUSTOM_SDIO_F2_BLKSIZE=128
+
DHDOFILES += bcmsdh.o bcmsdh_linux.o bcmsdh_sdmmc.o bcmsdh_sdmmc_linux.o \
dhd_sdio.o dhd_cdc.o dhd_wlfc.o
-obj-$(CONFIG_BCMDHD) += bcmdhd.o
-bcmdhd-objs += $(DHDOFILES)
-
-#ifeq ($(CONFIG_MACH_ODROID_4210),y)
-DHDOFILES += dhd_gpio.o
-DHDCFLAGS += -DCUSTOMER_HW -DDHD_OF_SUPPORT
-#DHDCFLAGS += -DBCMWAPI_WPI -DBCMWAPI_WAI
-#endif
-ifeq ($(CONFIG_ARCH_SUNXI),y)
-DHDOFILES += dhd_gpio.o
-DHDCFLAGS += -Iarch/arm/mach-sunxi/include
-DHDCFLAGS += -DCUSTOMER_HW -DDHD_OF_SUPPORT
-endif
-
ifeq ($(CONFIG_BCMDHD_OOB),y)
DHDCFLAGS += -DOOB_INTR_ONLY -DHW_OOB -DCUSTOMER_OOB
ifeq ($(CONFIG_BCMDHD_DISABLE_WOWLAN),y)
@@ -51,33 +34,62 @@
else
DHDCFLAGS += -DSDIO_ISR_THREAD
endif
+endif
+
+ifneq ($(CONFIG_BCMDHD_PCIE),)
+DHDCFLAGS += \
+ -DPCIE_FULL_DONGLE -DBCMPCIE -DSHOW_LOGTRACE -DDPCIE_TX_DEFERRAL \
+ -DCUSTOM_DPC_PRIO_SETTING=-1
+
+DHDOFILES += dhd_pcie.o dhd_pcie_linux.o pcie_core.o dhd_flowring.o \
+ dhd_msgbuf.o
+endif
+
+obj-$(CONFIG_BCMDHD) += dhd.o
+dhd-objs += $(DHDOFILES)
+
+#ifeq ($(CONFIG_MACH_ODROID_4210),y)
+DHDOFILES += dhd_gpio.o
+DHDCFLAGS += -DCUSTOMER_HW -DDHD_OF_SUPPORT
+DHDCFLAGS += -Iarch/arm/mach-sunxi/include
+#DHDCFLAGS += -DBCMWAPI_WPI -DBCMWAPI_WAI
+#endif
ifeq ($(CONFIG_BCMDHD_AG),y)
DHDCFLAGS += -DBAND_AG
endif
ifeq ($(CONFIG_DHD_USE_STATIC_BUF),y)
-DHDCFLAGS += -DSTATIC_WL_PRIV_STRUCT
+# add dhd_static_buf to kernel image build
+#obj-y += dhd_static_buf.o
+DHDCFLAGS += -DCONFIG_DHD_USE_STATIC_BUF
+DHDCFLAGS += -DSTATIC_WL_PRIV_STRUCT -DENHANCED_STATIC_BUF
endif
ifneq ($(CONFIG_WIRELESS_EXT),)
-bcmdhd-objs += wl_iw.o
+DHDOFILES += wl_iw.o
DHDCFLAGS += -DSOFTAP -DWL_WIRELESS_EXT -DUSE_IW
endif
ifneq ($(CONFIG_CFG80211),)
-bcmdhd-objs += wl_cfg80211.o wl_cfgp2p.o wl_linux_mon.o dhd_cfg80211.o wl_cfg_btcoex.o
-DHDCFLAGS += -DWL_CFG80211 -DWLP2P -DWL_CFG80211_STA_EVENT -DWL_ENABLE_P2P_IF
+DHDOFILES += wl_cfg80211.o wl_cfgp2p.o wl_linux_mon.o wl_cfg_btcoex.o
+DHDOFILES += dhd_cfg80211.o dhd_cfg_vendor.o
+DHDCFLAGS += -DWL_CFG80211 -DWL_CFG80211_STA_EVENT
+#DHDCFLAGS += -DWLP2P -DWL_ENABLE_P2P_IF
DHDCFLAGS += -DWL_IFACE_COMB_NUM_CHANNELS
DHDCFLAGS += -DCUSTOM_ROAM_TRIGGER_SETTING=-65
DHDCFLAGS += -DCUSTOM_ROAM_DELTA_SETTING=15
DHDCFLAGS += -DCUSTOM_KEEP_ALIVE_SETTING=28000
DHDCFLAGS += -DCUSTOM_PNO_EVENT_LOCK_xTIME=7
DHDCFLAGS += -DWL_SUPPORT_AUTO_CHANNEL
-endif
-ifneq ($(CONFIG_DHD_USE_SCHED_SCAN),)
-DHDCFLAGS += -DWL_SCHED_SCAN
+DHDCFLAGS += -DWL_SUPPORT_BACKPORTED_KPATCHES
+DHDCFLAGS += -DESCAN_RESULT_PATCH
+DHDCFLAGS += -DVSDB -DWL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
+DHDCFLAGS += -DWLTDLS -DMIRACAST_AMPDU_SIZE=8 -DPROP_TXSTATUS_VSDB
endif
EXTRA_CFLAGS = $(DHDCFLAGS)
ifeq ($(CONFIG_BCMDHD),m)
-EXTRA_LDFLAGS += --strip-debug
+#DHDCFLAGS += -DMULTIPLE_SUPPLICANT
+#EXTRA_LDFLAGS += --strip-debug
+else
+DHDCFLAGS += -DBUILD_IN_KERNEL
endif
diff -Nur a/drivers/net/wireless/bcmdhd/sbutils.c c/drivers/net/wireless/bcmdhd/sbutils.c
--- a/drivers/net/wireless/bcmdhd/sbutils.c 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/sbutils.c 2016-05-13 09:48:20.000000000 +0200
@@ -1084,4 +1084,4 @@
sb_setcoreidx(sih, origidx);
INTR_RESTORE(sii, intr_val);
}
-#endif
+#endif
diff -Nur a/drivers/net/wireless/bcmdhd/siutils.c c/drivers/net/wireless/bcmdhd/siutils.c
--- a/drivers/net/wireless/bcmdhd/siutils.c 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/siutils.c 2016-05-13 09:48:20.000000000 +0200
@@ -4,7 +4,7 @@
*
* $Copyright Open Broadcom Corporation$
*
- * $Id: siutils.c 481602 2014-05-29 22:43:34Z $
+ * $Id: siutils.c 497460 2014-08-19 15:14:13Z $
*/
#include <bcm_cfg.h>
@@ -70,6 +70,7 @@
#endif /* BCMLTECOEX */
+
/* global variable to indicate reservation/release of gpio's */
static uint32 si_gpioreservation = 0;
@@ -291,7 +292,8 @@
/* for SDIO but downloaded on PCIE dev */
if (cid == PCIE2_CORE_ID) {
if ((CHIPID(sii->pub.chip) == BCM43602_CHIP_ID) ||
- ((CHIPID(sii->pub.chip) == BCM4345_CHIP_ID) &&
+ ((CHIPID(sii->pub.chip) == BCM4345_CHIP_ID ||
+ CHIPID(sii->pub.chip) == BCM43454_CHIP_ID) &&
CST4345_CHIPMODE_PCIE(sii->pub.chipst))) {
pcieidx = i;
pcierev = crev;
@@ -426,7 +428,7 @@
char *pvars = NULL;
uint origidx;
#if !defined(_CFEZ_) || defined(CFG_WL)
-#endif
+#endif
ASSERT(GOODREGS(regs));
@@ -486,6 +488,18 @@
SI_ERROR(("%s: chipcommon register space is null \n", __FUNCTION__));
return NULL;
}
+#ifdef COSTOMER_HW4
+#ifdef CONFIG_MACH_UNIVERSAL5433
+ /* old revision check */
+ if (!check_rev()) {
+ /* abnormal link status */
+ if (!check_pcie_link_status()) {
+ printk("%s : PCIE LINK is abnormal status\n", __FUNCTION__);
+ return NULL;
+ }
+ }
+#endif /* CONFIG_MACH_UNIVERSAL5433 */
+#endif
w = R_REG(osh, &cc->chipid);
if ((w & 0xfffff) == 148277) w -= 65532;
sih->socitype = (w & CID_TYPE_MASK) >> CID_TYPE_SHIFT;
@@ -494,7 +508,7 @@
sih->chiprev = (w & CID_REV_MASK) >> CID_REV_SHIFT;
sih->chippkg = (w & CID_PKG_MASK) >> CID_PKG_SHIFT;
-#if defined(HW_OOB)
+#if defined(HW_OOB) || defined(FORCE_WOWLAN)
dhd_conf_set_hw_oob_intr(sdh, sih->chip);
#endif
@@ -571,7 +585,7 @@
if (bustype == PCI_BUS) {
}
-#endif
+#endif
#ifdef BCM_SDRBL
/* 4360 rom bootloader in PCIE case, if the SDR is enabled, But preotection is
* not turned on, then we want to hold arm in reset.
@@ -1400,6 +1414,7 @@
break;
case BCM4345_CHIP_ID:
+ case BCM43454_CHIP_ID:
if (CST4345_CHIPMODE_USB20D(sih->chipst) || CST4345_CHIPMODE_HSIC(sih->chipst))
hosti = CHIP_HOSTIF_USBMODE;
else if (CST4345_CHIPMODE_SDIOD(sih->chipst))
@@ -1461,7 +1476,7 @@
si_core_disable(sih, 1);
si_setcore(sih, CC_CORE_ID, 0);
}
-#endif
+#endif
nb = (sih->ccrev < 26) ? 16 : ((sih->ccrev >= 37) ? 32 : 24);
/* The mips compiler uses the sllv instruction,
@@ -2643,7 +2658,7 @@
}
si_setcoreidx(sih, origidx);
}
-#endif
+#endif
uint
si_pll_reset(si_t *sih)
@@ -2804,6 +2819,7 @@
!(sih->chipst & CST4324_SFLASH_MASK));
case BCM4335_CHIP_ID:
case BCM4345_CHIP_ID:
+ case BCM43454_CHIP_ID:
return ((sih->chipst & CST4335_SPROM_MASK) &&
!(sih->chipst & CST4335_SFLASH_MASK));
case BCM4349_CHIP_GRPID:
diff -Nur a/drivers/net/wireless/bcmdhd/siutils_priv.h c/drivers/net/wireless/bcmdhd/siutils_priv.h
--- a/drivers/net/wireless/bcmdhd/siutils_priv.h 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/siutils_priv.h 2016-05-13 09:48:20.000000000 +0200
@@ -196,7 +196,7 @@
#if defined(BCMDBG_PHYDUMP)
extern void sb_dumpregs(si_t *sih, struct bcmstrbuf *b);
-#endif
+#endif
/* Wake-on-wireless-LAN (WOWL) */
extern bool sb_pci_pmecap(si_t *sih);
@@ -239,7 +239,7 @@
#if defined(BCMDBG_PHYDUMP)
extern void ai_dumpregs(si_t *sih, struct bcmstrbuf *b);
-#endif
+#endif
#define ub_scan(a, b, c) do {} while (0)
diff -Nur a/drivers/net/wireless/bcmdhd/wl_android.c c/drivers/net/wireless/bcmdhd/wl_android.c
--- a/drivers/net/wireless/bcmdhd/wl_android.c 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/wl_android.c 2016-05-13 09:48:20.000000000 +0200
@@ -3,7 +3,7 @@
*
* $Copyright Open Broadcom Corporation$
*
- * $Id: wl_android.c 490852 2014-07-12 15:20:53Z $
+ * $Id: wl_android.c 505064 2014-09-26 09:40:28Z $
*/
#include <linux/module.h>
@@ -85,10 +85,16 @@
#define CMD_SCAN_PASSIVE "SCAN-PASSIVE"
#define CMD_RSSI "RSSI"
#define CMD_LINKSPEED "LINKSPEED"
+#ifdef PKT_FILTER_SUPPORT
#define CMD_RXFILTER_START "RXFILTER-START"
#define CMD_RXFILTER_STOP "RXFILTER-STOP"
#define CMD_RXFILTER_ADD "RXFILTER-ADD"
#define CMD_RXFILTER_REMOVE "RXFILTER-REMOVE"
+#if defined(CUSTOM_PLATFORM_NV_TEGRA)
+#define CMD_PKT_FILTER_MODE "PKT_FILTER_MODE"
+#define CMD_PKT_FILTER_PORTS "PKT_FILTER_PORTS"
+#endif /* defined(CUSTOM_PLATFORM_NV_TEGRA) */
+#endif /* PKT_FILTER_SUPPORT */
#define CMD_BTCOEXSCAN_START "BTCOEXSCAN-START"
#define CMD_BTCOEXSCAN_STOP "BTCOEXSCAN-STOP"
#define CMD_BTCOEXMODE "BTCOEXMODE"
@@ -111,7 +117,7 @@
#define CMD_MIRACAST "MIRACAST"
#define CMD_NAN "NAN_"
#define CMD_GET_CHANNEL "GET_CHANNEL"
-#define CMD_SET_ROAM "SET_ROAM_TRIGGER"
+#define CMD_SET_ROAM "SET_ROAM_TRIGGER"
#define CMD_GET_ROAM "GET_ROAM_TRIGGER"
#define CMD_GET_KEEP_ALIVE "GET_KEEP_ALIVE"
#define CMD_GET_PM "GET_PM"
@@ -122,6 +128,12 @@
#define CMD_GET_BEST_CHANNELS "GET_BEST_CHANNELS"
#endif /* WL_SUPPORT_AUTO_CHANNEL */
+#if defined(CUSTOM_PLATFORM_NV_TEGRA)
+#define CMD_SETMIRACAST "SETMIRACAST"
+#define CMD_ASSOCRESPIE "ASSOCRESPIE"
+#define CMD_RXRATESTATS "RXRATESTATS"
+#endif /* defined(CUSTOM_PLATFORM_NV_TEGRA) */
+
#define CMD_KEEP_ALIVE "KEEPALIVE"
/* CCX Private Commands */
@@ -158,6 +170,19 @@
#endif /* WLAIBSS */
#define CMD_ROAM_OFFLOAD "SETROAMOFFLOAD"
+#define CMD_ROAM_OFFLOAD_APLIST "SETROAMOFFLAPLIST"
+#define CMD_GET_LINK_STATUS "GETLINKSTATUS"
+
+#ifdef P2PRESP_WFDIE_SRC
+#define CMD_P2P_SET_WFDIE_RESP "P2P_SET_WFDIE_RESP"
+#define CMD_P2P_GET_WFDIE_RESP "P2P_GET_WFDIE_RESP"
+#endif /* P2PRESP_WFDIE_SRC */
+
+/* related with CMD_GET_LINK_STATUS */
+#define WL_ANDROID_LINK_VHT 0x01
+#define WL_ANDROID_LINK_MIMO 0x02
+#define WL_ANDROID_LINK_AP_VHT_SUPPORT 0x04
+#define WL_ANDROID_LINK_AP_MIMO_SUPPORT 0x08
/* miracast related definition */
#define MIRACAST_MODE_OFF 0
@@ -176,6 +201,26 @@
#define MIRACAST_MCHAN_BW 25
#endif
+#ifdef CONNECTION_STATISTICS
+#define CMD_GET_CONNECTION_STATS "GET_CONNECTION_STATS"
+
+struct connection_stats {
+ u32 txframe;
+ u32 txbyte;
+ u32 txerror;
+ u32 rxframe;
+ u32 rxbyte;
+ u32 txfail;
+ u32 txretry;
+ u32 txretrie;
+ u32 txrts;
+ u32 txnocts;
+ u32 txexptime;
+ u32 txrate;
+ u8 chan_idle;
+};
+#endif /* CONNECTION_STATISTICS */
+
static LIST_HEAD(miracast_resume_list);
#ifdef WL_CFG80211
static u8 miracast_cur_mode;
@@ -862,16 +907,26 @@
int wl_android_wifi_on(struct net_device *dev)
{
int ret = 0;
+#ifdef CONFIG_MACH_UNIVERSAL5433
+ int retry;
+ /* Do not retry old revision Helsinki Prime */
+ if (!check_rev()) {
+ retry = 1;
+ } else {
+ retry = POWERUP_MAX_RETRY;
+ }
+#else
int retry = POWERUP_MAX_RETRY;
+#endif /* CONFIG_MACH_UNIVERSAL5433 */
if (!dev) {
ANDROID_ERROR(("%s: dev is null\n", __FUNCTION__));
return -EINVAL;
}
- printk("%s in 1\n", __FUNCTION__);
+ printf("%s in 1\n", __FUNCTION__);
dhd_net_if_lock(dev);
- printk("%s in 2: g_wifi_on=%d\n", __FUNCTION__, g_wifi_on);
+ printf("%s in 2: g_wifi_on=%d\n", __FUNCTION__, g_wifi_on);
if (!g_wifi_on) {
do {
dhd_net_wifi_platform_set_power(dev, TRUE, WIFI_TURNON_DELAY);
@@ -913,20 +968,19 @@
}
exit:
- printk("%s: Success\n", __FUNCTION__);
+ printf("%s: Success\n", __FUNCTION__);
dhd_net_if_unlock(dev);
return ret;
-err:
#ifdef BCMSDIO
+err:
dhd_net_bus_devreset(dev, TRUE);
dhd_net_bus_suspend(dev);
-#endif
dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY);
- printk("%s: Failed\n", __FUNCTION__);
+ printf("%s: Failed\n", __FUNCTION__);
dhd_net_if_unlock(dev);
-
return ret;
+#endif
}
int wl_android_wifi_off(struct net_device *dev)
@@ -938,9 +992,9 @@
return -EINVAL;
}
- printk("%s in 1\n", __FUNCTION__);
+ printf("%s in 1\n", __FUNCTION__);
dhd_net_if_lock(dev);
- printk("%s in 2: g_wifi_on=%d\n", __FUNCTION__, g_wifi_on);
+ printf("%s in 2: g_wifi_on=%d\n", __FUNCTION__, g_wifi_on);
if (g_wifi_on) {
#if defined(BCMSDIO) || defined(BCMPCIE)
ret = dhd_net_bus_devreset(dev, TRUE);
@@ -951,7 +1005,7 @@
dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY);
g_wifi_on = FALSE;
}
- printk("%s out\n", __FUNCTION__);
+ printf("%s out\n", __FUNCTION__);
dhd_net_if_unlock(dev);
return ret;
@@ -964,6 +1018,145 @@
return dhd_net_set_fw_path(net, command + strlen(CMD_SETFWPATH) + 1);
}
+#ifdef CONNECTION_STATISTICS
+static int
+wl_chanim_stats(struct net_device *dev, u8 *chan_idle)
+{
+ int err;
+ wl_chanim_stats_t *list;
+ /* Parameter _and_ returned buffer of chanim_stats. */
+ wl_chanim_stats_t param;
+ u8 result[WLC_IOCTL_SMLEN];
+ chanim_stats_t *stats;
+
+ memset(&param, 0, sizeof(param));
+ memset(result, 0, sizeof(result));
+
+ param.buflen = htod32(sizeof(wl_chanim_stats_t));
+ param.count = htod32(WL_CHANIM_COUNT_ONE);
+
+ if ((err = wldev_iovar_getbuf(dev, "chanim_stats", (char*)&param, sizeof(wl_chanim_stats_t),
+ (char*)result, sizeof(result), 0)) < 0) {
+ ANDROID_ERROR(("Failed to get chanim results %d \n", err));
+ return err;
+ }
+
+ list = (wl_chanim_stats_t*)result;
+
+ list->buflen = dtoh32(list->buflen);
+ list->version = dtoh32(list->version);
+ list->count = dtoh32(list->count);
+
+ if (list->buflen == 0) {
+ list->version = 0;
+ list->count = 0;
+ } else if (list->version != WL_CHANIM_STATS_VERSION) {
+ ANDROID_ERROR(("Sorry, firmware has wl_chanim_stats version %d "
+ "but driver supports only version %d.\n",
+ list->version, WL_CHANIM_STATS_VERSION));
+ list->buflen = 0;
+ list->count = 0;
+ }
+
+ stats = list->stats;
+ stats->glitchcnt = dtoh32(stats->glitchcnt);
+ stats->badplcp = dtoh32(stats->badplcp);
+ stats->chanspec = dtoh16(stats->chanspec);
+ stats->timestamp = dtoh32(stats->timestamp);
+ stats->chan_idle = dtoh32(stats->chan_idle);
+
+ ANDROID_INFO(("chanspec: 0x%4x glitch: %d badplcp: %d idle: %d timestamp: %d\n",
+ stats->chanspec, stats->glitchcnt, stats->badplcp, stats->chan_idle,
+ stats->timestamp));
+
+ *chan_idle = stats->chan_idle;
+
+ return (err);
+}
+
+static int
+wl_android_get_connection_stats(struct net_device *dev, char *command, int total_len)
+{
+ wl_cnt_t* cnt = NULL;
+ int link_speed = 0;
+ struct connection_stats *output;
+ unsigned int bufsize = 0;
+ int bytes_written = 0;
+ int ret = 0;
+
+ ANDROID_INFO(("%s: enter Get Connection Stats\n", __FUNCTION__));
+
+ if (total_len <= 0) {
+ ANDROID_ERROR(("%s: invalid buffer size %d\n", __FUNCTION__, total_len));
+ goto error;
+ }
+
+ bufsize = total_len;
+ if (bufsize < sizeof(struct connection_stats)) {
+ ANDROID_ERROR(("%s: not enough buffer size, provided=%u, requires=%u\n",
+ __FUNCTION__, bufsize,
+ sizeof(struct connection_stats)));
+ goto error;
+ }
+
+ if ((cnt = kmalloc(sizeof(*cnt), GFP_KERNEL)) == NULL) {
+ ANDROID_ERROR(("kmalloc failed\n"));
+ return -1;
+ }
+ memset(cnt, 0, sizeof(*cnt));
+
+ ret = wldev_iovar_getbuf(dev, "counters", NULL, 0, (char *)cnt, sizeof(wl_cnt_t), NULL);
+ if (ret) {
+ ANDROID_ERROR(("%s: wldev_iovar_getbuf() failed, ret=%d\n",
+ __FUNCTION__, ret));
+ goto error;
+ }
+
+ if (dtoh16(cnt->version) > WL_CNT_T_VERSION) {
+ ANDROID_ERROR(("%s: incorrect version of wl_cnt_t, expected=%u got=%u\n",
+ __FUNCTION__, WL_CNT_T_VERSION, cnt->version));
+ goto error;
+ }
+
+ /* link_speed is in kbps */
+ ret = wldev_get_link_speed(dev, &link_speed);
+ if (ret || link_speed < 0) {
+ ANDROID_ERROR(("%s: wldev_get_link_speed() failed, ret=%d, speed=%d\n",
+ __FUNCTION__, ret, link_speed));
+ goto error;
+ }
+
+ output = (struct connection_stats *)command;
+ output->txframe = dtoh32(cnt->txframe);
+ output->txbyte = dtoh32(cnt->txbyte);
+ output->txerror = dtoh32(cnt->txerror);
+ output->rxframe = dtoh32(cnt->rxframe);
+ output->rxbyte = dtoh32(cnt->rxbyte);
+ output->txfail = dtoh32(cnt->txfail);
+ output->txretry = dtoh32(cnt->txretry);
+ output->txretrie = dtoh32(cnt->txretrie);
+ output->txrts = dtoh32(cnt->txrts);
+ output->txnocts = dtoh32(cnt->txnocts);
+ output->txexptime = dtoh32(cnt->txexptime);
+ output->txrate = link_speed;
+
+ /* Channel idle ratio. */
+ if (wl_chanim_stats(dev, &(output->chan_idle)) < 0) {
+ output->chan_idle = 0;
+ };
+
+ kfree(cnt);
+
+ bytes_written = sizeof(struct connection_stats);
+ return bytes_written;
+
+error:
+ if (cnt) {
+ kfree(cnt);
+ }
+ return -1;
+}
+#endif /* CONNECTION_STATISTICS */
static int
wl_android_set_pmk(struct net_device *dev, char *command, int total_len)
@@ -1869,6 +2062,228 @@
return res;
}
+
+static const char *
+get_string_by_separator(char *result, int result_len, const char *src, char separator)
+{
+ char *end = result + result_len - 1;
+ while ((result != end) && (*src != separator) && (*src)) {
+ *result++ = *src++;
+ }
+ *result = 0;
+ if (*src == separator)
+ ++src;
+ return src;
+}
+
+int
+wl_android_set_roam_offload_bssid_list(struct net_device *dev, const char *cmd)
+{
+ char sbuf[32];
+ int i, cnt, size, err, ioctl_buf_len;
+ roamoffl_bssid_list_t *bssid_list;
+ const char *str = cmd;
+ char *ioctl_buf;
+
+ str = get_string_by_separator(sbuf, 32, str, ',');
+ cnt = bcm_atoi(sbuf);
+ cnt = MIN(cnt, MAX_ROAMOFFL_BSSID_NUM);
+ size = sizeof(int) + sizeof(struct ether_addr) * cnt;
+ ANDROID_ERROR(("ROAM OFFLOAD BSSID LIST %d BSSIDs, size %d\n", cnt, size));
+ bssid_list = kmalloc(size, GFP_KERNEL);
+ if (bssid_list == NULL) {
+ ANDROID_ERROR(("%s: memory alloc for bssid list(%d) failed\n",
+ __FUNCTION__, size));
+ return -ENOMEM;
+ }
+ ioctl_buf_len = size + 64;
+ ioctl_buf = kmalloc(ioctl_buf_len, GFP_KERNEL);
+ if (ioctl_buf == NULL) {
+ ANDROID_ERROR(("%s: memory alloc for ioctl_buf(%d) failed\n",
+ __FUNCTION__, ioctl_buf_len));
+ kfree(bssid_list);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < cnt; i++) {
+ str = get_string_by_separator(sbuf, 32, str, ',');
+ if (bcm_ether_atoe(sbuf, &bssid_list->bssid[i]) == 0) {
+ ANDROID_ERROR(("%s: Invalid station MAC Address!!!\n", __FUNCTION__));
+ kfree(bssid_list);
+ kfree(ioctl_buf);
+ return -1;
+ }
+ }
+
+ bssid_list->cnt = cnt;
+ err = wldev_iovar_setbuf(dev, "roamoffl_bssid_list",
+ bssid_list, size, ioctl_buf, ioctl_buf_len, NULL);
+ kfree(bssid_list);
+ kfree(ioctl_buf);
+
+ return err;
+}
+
+#ifdef P2PRESP_WFDIE_SRC
+static int wl_android_get_wfdie_resp(struct net_device *dev, char *command, int total_len)
+{
+ int error = 0;
+ int bytes_written = 0;
+ int only_resp_wfdsrc = 0;
+
+ error = wldev_iovar_getint(dev, "p2p_only_resp_wfdsrc", &only_resp_wfdsrc);
+ if (error) {
+ ANDROID_ERROR(("%s: Failed to get the mode for only_resp_wfdsrc, error = %d\n",
+ __FUNCTION__, error));
+ return -1;
+ }
+
+ bytes_written = snprintf(command, total_len, "%s %d",
+ CMD_P2P_GET_WFDIE_RESP, only_resp_wfdsrc);
+
+ return bytes_written;
+}
+
+static int wl_android_set_wfdie_resp(struct net_device *dev, int only_resp_wfdsrc)
+{
+ int error = 0;
+
+ error = wldev_iovar_setint(dev, "p2p_only_resp_wfdsrc", only_resp_wfdsrc);
+ if (error) {
+ ANDROID_ERROR(("%s: Failed to set only_resp_wfdsrc %d, error = %d\n",
+ __FUNCTION__, only_resp_wfdsrc, error));
+ return -1;
+ }
+
+ return 0;
+}
+#endif /* P2PRESP_WFDIE_SRC */
+
+static int wl_android_get_link_status(struct net_device *dev, char *command,
+ int total_len)
+{
+ int bytes_written, error, result = 0, single_stream, stf = -1, i, nss = 0, mcs_map;
+ uint32 rspec;
+ uint encode, rate, txexp;
+ struct wl_bss_info *bi;
+ int datalen = sizeof(uint32) + sizeof(wl_bss_info_t);
+ char buf[datalen];
+
+ /* get BSS information */
+ *(u32 *) buf = htod32(datalen);
+ error = wldev_ioctl(dev, WLC_GET_BSS_INFO, (void *)buf, datalen, false);
+ if (unlikely(error)) {
+ ANDROID_ERROR(("Could not get bss info %d\n", error));
+ return -1;
+ }
+
+ bi = (struct wl_bss_info *) (buf + sizeof(uint32));
+
+ for (i = 0; i < ETHER_ADDR_LEN; i++) {
+ if (bi->BSSID.octet[i] > 0) {
+ break;
+ }
+ }
+
+ if (i == ETHER_ADDR_LEN) {
+ ANDROID_TRACE(("No BSSID\n"));
+ return -1;
+ }
+
+ /* check VHT capability at beacon */
+ if (bi->vht_cap) {
+ if (CHSPEC_IS5G(bi->chanspec)) {
+ result |= WL_ANDROID_LINK_AP_VHT_SUPPORT;
+ }
+ }
+
+ /* get a rspec (radio spectrum) rate */
+ error = wldev_iovar_getint(dev, "nrate", &rspec);
+ if (unlikely(error) || rspec == 0) {
+ ANDROID_ERROR(("get link status error (%d)\n", error));
+ return -1;
+ }
+
+ encode = (rspec & WL_RSPEC_ENCODING_MASK);
+ rate = (rspec & WL_RSPEC_RATE_MASK);
+ txexp = (rspec & WL_RSPEC_TXEXP_MASK) >> WL_RSPEC_TXEXP_SHIFT;
+
+ switch (encode) {
+ case WL_RSPEC_ENCODE_HT:
+ /* check Rx MCS Map for HT */
+ for (i = 0; i < MAX_STREAMS_SUPPORTED; i++) {
+ int8 bitmap = 0xFF;
+ if (i == MAX_STREAMS_SUPPORTED-1) {
+ bitmap = 0x7F;
+ }
+ if (bi->basic_mcs[i] & bitmap) {
+ nss++;
+ }
+ }
+ break;
+ case WL_RSPEC_ENCODE_VHT:
+ /* check Rx MCS Map for VHT */
+ for (i = 1; i <= VHT_CAP_MCS_MAP_NSS_MAX; i++) {
+ mcs_map = VHT_MCS_MAP_GET_MCS_PER_SS(i, dtoh16(bi->vht_rxmcsmap));
+ if (mcs_map != VHT_CAP_MCS_MAP_NONE) {
+ nss++;
+ }
+ }
+ break;
+ }
+
+ /* check MIMO capability with nss in beacon */
+ if (nss > 1) {
+ result |= WL_ANDROID_LINK_AP_MIMO_SUPPORT;
+ }
+
+ single_stream = (encode == WL_RSPEC_ENCODE_RATE) ||
+ ((encode == WL_RSPEC_ENCODE_HT) && rate < 8) ||
+ ((encode == WL_RSPEC_ENCODE_VHT) &&
+ ((rspec & WL_RSPEC_VHT_NSS_MASK) >> WL_RSPEC_VHT_NSS_SHIFT) == 1);
+
+ if (txexp == 0) {
+ if ((rspec & WL_RSPEC_STBC) && single_stream) {
+ stf = OLD_NRATE_STF_STBC;
+ } else {
+ stf = (single_stream) ? OLD_NRATE_STF_SISO : OLD_NRATE_STF_SDM;
+ }
+ } else if (txexp == 1 && single_stream) {
+ stf = OLD_NRATE_STF_CDD;
+ }
+
+ /* check 11ac (VHT) */
+ if (encode == WL_RSPEC_ENCODE_VHT) {
+ if (CHSPEC_IS5G(bi->chanspec)) {
+ result |= WL_ANDROID_LINK_VHT;
+ }
+ }
+
+ /* check MIMO */
+ if (result & WL_ANDROID_LINK_AP_MIMO_SUPPORT) {
+ switch (stf) {
+ case OLD_NRATE_STF_SISO:
+ break;
+ case OLD_NRATE_STF_CDD:
+ case OLD_NRATE_STF_STBC:
+ result |= WL_ANDROID_LINK_MIMO;
+ break;
+ case OLD_NRATE_STF_SDM:
+ if (!single_stream) {
+ result |= WL_ANDROID_LINK_MIMO;
+ }
+ break;
+ }
+ }
+
+ ANDROID_TRACE(("%s:result=%d, stf=%d, single_stream=%d, mcs map=%d\n",
+ __FUNCTION__, result, stf, single_stream, nss));
+
+ bytes_written = sprintf(command, "%s %d", CMD_GET_LINK_STATUS, result);
+
+ return bytes_written;
+}
+
int
wl_android_get_channel(
struct net_device *dev, char* command, int total_len)
@@ -1897,7 +2312,7 @@
sscanf(command, "%*s %10d", &roam_trigger[0]);
roam_trigger[1] = WLC_BAND_ALL;
-
+
ret = wldev_ioctl(dev, WLC_SET_ROAM_TRIGGER, roam_trigger, sizeof(roam_trigger), 1);
if (ret)
ANDROID_ERROR(("WLC_SET_ROAM_TRIGGER ERROR %d ret=%d\n", roam_trigger[0], ret));
@@ -1913,21 +2328,21 @@
int bytes_written;
int roam_trigger[2] = {0, 0};
int trigger[2]= {0, 0};
-
+
roam_trigger[1] = WLC_BAND_2G;
ret = wldev_ioctl(dev, WLC_GET_ROAM_TRIGGER, roam_trigger, sizeof(roam_trigger), 0);
if (!ret)
trigger[0] = roam_trigger[0];
- else
+ else
ANDROID_ERROR(("2G WLC_GET_ROAM_TRIGGER ERROR %d ret=%d\n", roam_trigger[0], ret));
roam_trigger[1] = WLC_BAND_5G;
ret = wldev_ioctl(dev, WLC_GET_ROAM_TRIGGER, roam_trigger, sizeof(roam_trigger), 0);
if (!ret)
trigger[1] = roam_trigger[0];
- else
+ else
ANDROID_ERROR(("5G WLC_GET_ROAM_TRIGGER ERROR %d ret=%d\n", roam_trigger[0], ret));
-
+
ANDROID_TRACE(("roam_trigger %d %d\n", trigger[0], trigger[1]));
bytes_written = snprintf(command, total_len, "%d %d", trigger[0], trigger[1]);
@@ -2135,6 +2550,15 @@
int filter_num = *(command + strlen(CMD_RXFILTER_REMOVE) + 1) - '0';
bytes_written = net_os_rxfilter_add_remove(net, FALSE, filter_num);
}
+#if defined(CUSTOM_PLATFORM_NV_TEGRA)
+ else if (strnicmp(command, CMD_PKT_FILTER_MODE, strlen(CMD_PKT_FILTER_MODE)) == 0) {
+ dhd_set_packet_filter_mode(net, &command[strlen(CMD_PKT_FILTER_MODE) + 1]);
+ } else if (strnicmp(command, CMD_PKT_FILTER_PORTS, strlen(CMD_PKT_FILTER_PORTS)) == 0) {
+ bytes_written = dhd_set_packet_filter_ports(net,
+ &command[strlen(CMD_PKT_FILTER_PORTS) + 1]);
+ ret = bytes_written;
+ }
+#endif /* defined(CUSTOM_PLATFORM_NV_TEGRA) */
#endif /* PKT_FILTER_SUPPORT */
else if (strnicmp(command, CMD_BTCOEXSCAN_START, strlen(CMD_BTCOEXSCAN_START)) == 0) {
/* TBD: BTCOEXSCAN-START */
@@ -2165,6 +2589,12 @@
}
else if (strnicmp(command, CMD_SETBAND, strlen(CMD_SETBAND)) == 0) {
uint band = *(command + strlen(CMD_SETBAND) + 1) - '0';
+
+ if (dhd_conf_get_band(dhd_get_pub(net)) != WLC_BAND_AUTO) {
+ printf("%s: Band is fixed in config.txt\n", __FUNCTION__);
+ goto exit;
+ }
+
#ifdef WL_HOST_BAND_MGMT
s32 ret = 0;
if ((ret = wl_cfg80211_set_band(net, band)) < 0) {
@@ -2190,7 +2620,12 @@
/* CUSTOMER_SET_COUNTRY feature is define for only GGSM model */
else if (strnicmp(command, CMD_COUNTRY, strlen(CMD_COUNTRY)) == 0) {
char *country_code = command + strlen(CMD_COUNTRY) + 1;
+#ifdef CUSTOMER_HW5
+ /* Customer_hw5 want to keep connections */
+ bytes_written = wldev_set_country(net, country_code, true, false);
+#else
bytes_written = wldev_set_country(net, country_code, true, true);
+#endif
}
#endif /* WL_CFG80211 */
@@ -2302,6 +2737,14 @@
#ifdef WL_CFG80211
else if (strnicmp(command, CMD_MIRACAST, strlen(CMD_MIRACAST)) == 0)
bytes_written = wl_android_set_miracast(net, command, priv_cmd.total_len);
+#if defined(CUSTOM_PLATFORM_NV_TEGRA)
+ else if (strnicmp(command, CMD_SETMIRACAST, strlen(CMD_SETMIRACAST)) == 0)
+ bytes_written = wldev_miracast_tuning(net, command, priv_cmd.total_len);
+ else if (strnicmp(command, CMD_ASSOCRESPIE, strlen(CMD_ASSOCRESPIE)) == 0)
+ bytes_written = wldev_get_assoc_resp_ie(net, command, priv_cmd.total_len);
+ else if (strnicmp(command, CMD_RXRATESTATS, strlen(CMD_RXRATESTATS)) == 0)
+ bytes_written = wldev_get_rx_rate_stats(net, command, priv_cmd.total_len);
+#endif /* defined(CUSTOM_PLATFORM_NV_TEGRA) */
else if (strnicmp(command, CMD_SETIBSSBEACONOUIDATA, strlen(CMD_SETIBSSBEACONOUIDATA)) == 0)
bytes_written = wl_android_set_ibss_beacon_ouidata(net,
command, priv_cmd.total_len);
@@ -2336,6 +2779,30 @@
int enable = *(command + strlen(CMD_ROAM_OFFLOAD) + 1) - '0';
bytes_written = wl_cfg80211_enable_roam_offload(net, enable);
}
+ else if (strnicmp(command, CMD_ROAM_OFFLOAD_APLIST, strlen(CMD_ROAM_OFFLOAD_APLIST)) == 0) {
+ bytes_written = wl_android_set_roam_offload_bssid_list(net,
+ command + strlen(CMD_ROAM_OFFLOAD_APLIST) + 1);
+ }
+#endif
+#ifdef P2PRESP_WFDIE_SRC
+ else if (strnicmp(command, CMD_P2P_SET_WFDIE_RESP,
+ strlen(CMD_P2P_SET_WFDIE_RESP)) == 0) {
+ int mode = *(command + strlen(CMD_P2P_SET_WFDIE_RESP) + 1) - '0';
+ bytes_written = wl_android_set_wfdie_resp(net, mode);
+ } else if (strnicmp(command, CMD_P2P_GET_WFDIE_RESP,
+ strlen(CMD_P2P_GET_WFDIE_RESP)) == 0) {
+ bytes_written = wl_android_get_wfdie_resp(net, command, priv_cmd.total_len);
+ }
+#endif /* P2PRESP_WFDIE_SRC */
+ else if (strnicmp(command, CMD_GET_LINK_STATUS, strlen(CMD_GET_LINK_STATUS)) == 0) {
+ bytes_written = wl_android_get_link_status(net, command, priv_cmd.total_len);
+ }
+#ifdef CONNECTION_STATISTICS
+ else if (strnicmp(command, CMD_GET_CONNECTION_STATS,
+ strlen(CMD_GET_CONNECTION_STATS)) == 0) {
+ bytes_written = wl_android_get_connection_stats(net, command,
+ priv_cmd.total_len);
+ }
#endif
else if(strnicmp(command, CMD_GET_CHANNEL, strlen(CMD_GET_CHANNEL)) == 0) {
bytes_written = wl_android_get_channel(net, command, priv_cmd.total_len);
@@ -2848,7 +3315,7 @@
if (!memcmp(&node->BSSID, &bssid, ETHER_ADDR_LEN)) {
ANDROID_INFO(("%s: Update %d with BSSID %pM, RSSI=%d\n",
__FUNCTION__, k, &bssid, rssi));
- for(j=0; j<RSSIAVG_LEN-1; j++)
+ for (j = 0; j < RSSIAVG_LEN-1; j++)
node->RSSI[j] = node->RSSI[j+1];
node->RSSI[j] = rssi;
node->dirty = 0;
@@ -2863,10 +3330,10 @@
leaf = kmalloc(sizeof(wl_rssi_cache_t), GFP_KERNEL);
if (!leaf) {
ANDROID_ERROR(("%s: Memory alloc failure %d\n",
- __FUNCTION__, sizeof(wl_rssi_cache_t)));
+ __FUNCTION__, (int)sizeof(wl_rssi_cache_t)));
return 0;
}
- ANDROID_INFO(("%s: Add %d with cached BSSID %pM, RSSI=%d in the leaf\n",
+ ANDROID_INFO(("%s: Add %d with cached BSSID %pM, RSSI=%3d in the leaf\n",
__FUNCTION__, k, &bssid, rssi));
leaf->next = NULL;
@@ -2919,9 +3386,9 @@
bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : ss_list->bss_info;
for (;node;) {
if (!memcmp(&node->BSSID, &bi->BSSID, ETHER_ADDR_LEN)) {
- ANDROID_INFO(("%s: Update %d with BSSID %pM, RSSI=%d, SSID \"%s\"\n",
+ ANDROID_INFO(("%s: Update %d with BSSID %pM, RSSI=%3d, SSID \"%s\"\n",
__FUNCTION__, k, &bi->BSSID, dtoh16(bi->RSSI), bi->SSID));
- for(j=0; j<RSSIAVG_LEN-1; j++)
+ for (j = 0; j < RSSIAVG_LEN-1; j++)
node->RSSI[j] = node->RSSI[j+1];
node->RSSI[j] = dtoh16(bi->RSSI);
node->dirty = 0;
@@ -2939,10 +3406,10 @@
leaf = kmalloc(sizeof(wl_rssi_cache_t), GFP_KERNEL);
if (!leaf) {
ANDROID_ERROR(("%s: Memory alloc failure %d\n",
- __FUNCTION__, sizeof(wl_rssi_cache_t)));
+ __FUNCTION__, (int)sizeof(wl_rssi_cache_t)));
return;
}
- ANDROID_INFO(("%s: Add %d with cached BSSID %pM, RSSI=%d, SSID \"%s\" in the leaf\n",
+ ANDROID_INFO(("%s: Add %d with cached BSSID %pM, RSSI=%3d, SSID \"%s\" in the leaf\n",
__FUNCTION__, k, &bi->BSSID, dtoh16(bi->RSSI), bi->SSID));
leaf->next = NULL;
@@ -2992,32 +3459,27 @@
int
wl_update_rssi_offset(struct net_device *net, int rssi)
{
- uint chip, chiprev;
+#if defined(RSSIOFFSET_NEW)
+ int j;
+#endif
if (!g_wifi_on)
return rssi;
- chip = dhd_conf_get_chip(dhd_get_pub(net));
- chiprev = dhd_conf_get_chiprev(dhd_get_pub(net));
- if (chip == BCM4330_CHIP_ID && chiprev == BCM4330B2_CHIP_REV) {
#if defined(RSSIOFFSET_NEW)
- int j;
- for (j=0; j<RSSI_OFFSET; j++) {
- if (rssi - (RSSI_OFFSET_MINVAL+RSSI_OFFSET_INTVAL*(j+1)) < 0)
- break;
- }
- rssi += j;
+ for (j=0; j<RSSI_OFFSET; j++) {
+ if (rssi - (RSSI_OFFSET_MINVAL+RSSI_OFFSET_INTVAL*(j+1)) < 0)
+ break;
+ }
+ rssi += j;
#else
- rssi += RSSI_OFFSET;
+ rssi += RSSI_OFFSET;
#endif
- }
return MIN(rssi, RSSI_MAXVAL);
}
#endif
#if defined(BSSCACHE)
-#define WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN 32
-
void
wl_free_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl)
{
@@ -3062,7 +3524,7 @@
tmp = 0;
prev->next = node->next;
}
- ANDROID_TRACE(("%s: Del %d with BSSID %pM, RSSI=%d, SSID \"%s\"\n",
+ ANDROID_TRACE(("%s: Del %d with BSSID %pM, RSSI=%3d, SSID \"%s\"\n",
__FUNCTION__, i, &node->results.bss_info->BSSID,
dtoh16(node->results.bss_info->RSSI), node->results.bss_info->SSID));
kfree(node);
@@ -3098,7 +3560,7 @@
tmp = 0;
prev->next = node->next;
}
- ANDROID_TRACE(("%s: Del %d with BSSID %pM, RSSI=%d, SSID \"%s\"\n",
+ ANDROID_TRACE(("%s: Del %d with BSSID %pM, RSSI=%3d, SSID \"%s\"\n",
__FUNCTION__, i, &node->results.bss_info->BSSID,
dtoh16(node->results.bss_info->RSSI), node->results.bss_info->SSID));
kfree(node);
@@ -3130,12 +3592,41 @@
}
}
+void dump_bss_cache(
+#if defined(RSSIAVG)
+ wl_rssi_cache_ctrl_t *rssi_cache_ctrl,
+#endif
+ wl_bss_cache_t *node)
+{
+ int k = 0;
+ int16 rssi;
+
+ for (;node;) {
+#if defined(RSSIAVG)
+ rssi = wl_get_avg_rssi(rssi_cache_ctrl, &node->results.bss_info->BSSID);
+#else
+ rssi = dtoh16(node->results.bss_info->RSSI);
+#endif
+ ANDROID_TRACE(("%s: dump %d with cached BSSID %pM, RSSI=%3d, SSID \"%s\"\n",
+ __FUNCTION__, k, &node->results.bss_info->BSSID, rssi, node->results.bss_info->SSID));
+ k++;
+ node = node->next;
+ }
+}
+
void
-wl_update_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl, wl_scan_results_t *ss_list)
+wl_update_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl,
+#if defined(RSSIAVG)
+ wl_rssi_cache_ctrl_t *rssi_cache_ctrl,
+#endif
+ wl_scan_results_t *ss_list)
{
- wl_bss_cache_t *node, *prev, *leaf, *tmp, **bss_head;
+ wl_bss_cache_t *node, *prev, *leaf, **bss_head;
wl_bss_info_t *bi = NULL;
int i, k=0;
+#if defined(SORT_BSS_BY_RSSI)
+ int16 rssi, rssi_node;
+#endif
struct timeval now, timeout;
if (!ss_list->count)
@@ -3158,50 +3649,33 @@
node = *bss_head;
prev = NULL;
bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : ss_list->bss_info;
-
+
for (;node;) {
if (!memcmp(&node->results.bss_info->BSSID, &bi->BSSID, ETHER_ADDR_LEN)) {
- tmp = node;
- leaf = kmalloc(dtoh32(bi->length) + WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN, GFP_KERNEL);
- if (!leaf) {
- ANDROID_ERROR(("%s: Memory alloc failure %d and keep old BSS info\n",
- __FUNCTION__, dtoh32(bi->length) + WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN));
- break;
+ if (node == *bss_head)
+ *bss_head = node->next;
+ else {
+ prev->next = node->next;
}
-
- memcpy(leaf->results.bss_info, bi, dtoh32(bi->length));
- leaf->next = node->next;
- leaf->dirty = 0;
- leaf->tv = timeout;
- leaf->results.count = 1;
- leaf->results.version = ss_list->version;
- ANDROID_TRACE(("%s: Update %d with BSSID %pM, RSSI=%d, SSID \"%s\", length=%d\n",
- __FUNCTION__, k, &bi->BSSID, dtoh16(bi->RSSI), bi->SSID, dtoh32(bi->length)));
- if (!prev)
- *bss_head = leaf;
- else
- prev->next = leaf;
- node = leaf;
- prev = node;
-
- kfree(tmp);
- k++;
break;
}
prev = node;
node = node->next;
}
- if (node)
- continue;
-
- leaf = kmalloc(dtoh32(bi->length) + WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN, GFP_KERNEL);
+ leaf = kmalloc(dtoh32(bi->length) + sizeof(wl_bss_cache_t), GFP_KERNEL);
if (!leaf) {
ANDROID_ERROR(("%s: Memory alloc failure %d\n", __FUNCTION__,
- dtoh32(bi->length) + WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN));
+ dtoh32(bi->length) + (int)sizeof(wl_bss_cache_t)));
return;
}
- ANDROID_TRACE(("%s: Add %d with cached BSSID %pM, RSSI=%d, SSID \"%s\" in the leaf\n",
+ if (node) {
+ kfree(node);
+ node = NULL;
+ ANDROID_TRACE(("%s: Update %d with cached BSSID %pM, RSSI=%3d, SSID \"%s\"\n",
+ __FUNCTION__, k, &bi->BSSID, dtoh16(bi->RSSI), bi->SSID));
+ } else
+ ANDROID_TRACE(("%s: Add %d with cached BSSID %pM, RSSI=%3d, SSID \"%s\"\n",
__FUNCTION__, k, &bi->BSSID, dtoh16(bi->RSSI), bi->SSID));
memcpy(leaf->results.bss_info, bi, dtoh32(bi->length));
@@ -3212,11 +3686,46 @@
leaf->results.version = ss_list->version;
k++;
- if (!prev)
+ if (*bss_head == NULL)
*bss_head = leaf;
- else
- prev->next = leaf;
+ else {
+#if defined(SORT_BSS_BY_RSSI)
+ node = *bss_head;
+#if defined(RSSIAVG)
+ rssi = wl_get_avg_rssi(rssi_cache_ctrl, &leaf->results.bss_info->BSSID);
+#else
+ rssi = dtoh16(leaf->results.bss_info->RSSI);
+#endif
+ for (;node;) {
+#if defined(RSSIAVG)
+ rssi_node = wl_get_avg_rssi(rssi_cache_ctrl, &node->results.bss_info->BSSID);
+#else
+ rssi_node = dtoh16(node->results.bss_info->RSSI);
+#endif
+ if (rssi > rssi_node) {
+ leaf->next = node;
+ if (node == *bss_head)
+ *bss_head = leaf;
+ else
+ prev->next = leaf;
+ break;
+ }
+ prev = node;
+ node = node->next;
+ }
+ if (node == NULL)
+ prev->next = leaf;
+#else
+ leaf->next = *bss_head;
+ *bss_head = leaf;
+#endif
+ }
}
+ dump_bss_cache(
+#if defined(RSSIAVG)
+ rssi_cache_ctrl,
+#endif
+ *bss_head);
}
void
diff -Nur a/drivers/net/wireless/bcmdhd/wl_android.h c/drivers/net/wireless/bcmdhd/wl_android.h
--- a/drivers/net/wireless/bcmdhd/wl_android.h 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/wl_android.h 2016-05-13 09:48:20.000000000 +0200
@@ -104,11 +104,13 @@
* BSSCACHE: Cache bss list
* RSSAVG: Average RSSI of BSS list
* RSSIOFFSET: RSSI offset
+ * SORT_BSS_BY_RSSI: Sort BSS by RSSI
*/
-#define BSSCACHE
-#define RSSIAVG
-#define RSSIOFFSET
+//#define BSSCACHE
+//#define RSSIAVG
+//#define RSSIOFFSET
//#define RSSIOFFSET_NEW
+//#define SORT_BSS_BY_RSSI
#define RSSI_MAXVAL -2
#define RSSI_MINVAL -200
@@ -174,7 +176,11 @@
void wl_delete_dirty_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl);
void wl_delete_disconnected_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl, u8 *bssid);
void wl_reset_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl);
-void wl_update_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl, wl_scan_results_t *ss_list);
+void wl_update_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl,
+#if defined(RSSIAVG)
+ wl_rssi_cache_ctrl_t *rssi_cache_ctrl,
+#endif
+ wl_scan_results_t *ss_list);
void wl_release_bss_cache_ctrl(wl_bss_cache_ctrl_t *bss_cache_ctrl);
#endif
#endif /* _wl_android_ */
diff -Nur a/drivers/net/wireless/bcmdhd/wl_cfg80211.c c/drivers/net/wireless/bcmdhd/wl_cfg80211.c
--- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/wl_cfg80211.c 2016-05-13 09:48:20.000000000 +0200
@@ -3,7 +3,7 @@
*
* $Copyright Open Broadcom Corporation$
*
- * $Id: wl_cfg80211.c 491569 2014-07-16 21:28:40Z $
+ * $Id: wl_cfg80211.c 506036 2014-10-02 11:33:14Z $
*/
/* */
#include <typedefs.h>
@@ -101,7 +101,6 @@
static struct bcm_cfg80211 *g_bcm_cfg = NULL;
u32 wl_dbg_level = WL_DBG_ERR;
-#define MAX_WAIT_TIME 1500
#ifdef WLAIBSS_MCHAN
#define IBSS_IF_NAME "ibss%d"
#endif /* WLAIBSS_MCHAN */
@@ -135,7 +134,6 @@
#define WL_IS_P2P_DEV_EVENT(e) ((e->emsg.ifidx == 0) && \
(e->emsg.bsscfgidx == P2PAPI_BSSCFG_DEVICE))
-#define DNGL_FUNC(func, parameters) func parameters
#define COEX_DHCP
#define WLAN_EID_SSID 0
@@ -271,9 +269,6 @@
#define WPS_CONFIG_VIRT_DISPLAY 0x2008
#define WPS_CONFIG_PHY_DISPLAY 0x4008
-#define PM_BLOCK 1
-#define PM_ENABLE 0
-
#ifdef BCMCCX
#ifndef WLAN_AKM_SUITE_CCKM
#define WLAN_AKM_SUITE_CCKM 0x00409600
@@ -284,6 +279,8 @@
#ifdef MFP
#define WL_AKM_SUITE_MFP_1X 0x000FAC05
#define WL_AKM_SUITE_MFP_PSK 0x000FAC06
+#define WL_MFP_CAPABLE 0x1
+#define WL_MFP_REQUIRED 0x2
#endif /* MFP */
#ifndef IBSS_COALESCE_ALLOWED
@@ -381,10 +378,23 @@
struct cfg80211_pmksa *pmksa);
static s32 wl_cfg80211_flush_pmksa(struct wiphy *wiphy,
struct net_device *dev);
-static void wl_cfg80211_scan_abort(struct bcm_cfg80211 *cfg);
+#ifdef P2PONEINT
+void wl_cfg80211_scan_abort(struct bcm_cfg80211 *cfg);
+#else
+void wl_cfg80211_scan_abort(struct bcm_cfg80211 *cfg);
+#endif
static s32 wl_notify_escan_complete(struct bcm_cfg80211 *cfg,
struct net_device *ndev, bool aborted, bool fw_abort);
#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)
+#if defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2)
+static s32 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
+ u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
+ u32 peer_capability, const u8 *data, size_t len);
+#else
+static s32 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
+ u8 *peer, u8 action_code, u8 dialog_token, u16 status_code, const u8 *data,
+ size_t len);
+#endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
static s32 wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
u8 *peer, enum nl80211_tdls_operation oper);
#endif /* LINUX_VERSION > KERNEL_VERSION(3,2,0) || WL_COMPAT_WIRELESS */
@@ -522,7 +532,7 @@
uint8 ie_id, uint8 *data, uint8 data_len);
#endif /* WL11U */
-static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *dev, void *data);
+static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *dev, dhd_pub_t *data);
static void wl_free_wdev(struct bcm_cfg80211 *cfg);
#ifdef CONFIG_CFG80211_INTERNAL_REGDB
static int
@@ -532,7 +542,11 @@
static s32 wl_inform_bss(struct bcm_cfg80211 *cfg);
static s32 wl_inform_single_bss(struct bcm_cfg80211 *cfg, struct wl_bss_info *bi, bool roam);
static s32 wl_update_bss_info(struct bcm_cfg80211 *cfg, struct net_device *ndev, bool roam);
-static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy);
+#ifdef P2PONEINT
+chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy);
+#else
+chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy);
+#endif
s32 wl_cfg80211_channel_to_freq(u32 channel);
#if defined(DHCP_SCAN_SUPPRESS)
@@ -654,6 +668,8 @@
extern int disable_proptx;
#endif /* PROP_TXSTATUS_VSDB */
+extern int passive_channel_skip;
+
#if (WL_DBG_LEVEL > 0)
#define WL_DBG_ESTR_MAX 50
static s8 wl_dbg_estr[][WL_DBG_ESTR_MAX] = {
@@ -1287,7 +1303,12 @@
return err;
}
-static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy)
+chanspec_t
+#ifdef P2PONEINT
+wl_cfg80211_get_shared_freq(struct wiphy *wiphy)
+#else
+wl_cfg80211_get_shared_freq(struct wiphy *wiphy)
+#endif
{
chanspec_t chspec;
int err = 0;
@@ -1362,8 +1383,11 @@
s32 up = 1;
dhd_pub_t *dhd;
bool enabled;
-#endif
+#endif
#endif /* PROP_TXSTATUS_VSDB */
+#if defined(SUPPORT_AP_POWERSAVE)
+ dhd_pub_t *dhd;
+#endif
if (!cfg)
return ERR_PTR(-EINVAL);
@@ -1371,9 +1395,11 @@
#ifdef PROP_TXSTATUS_VSDB
#if defined(BCMSDIO)
dhd = (dhd_pub_t *)(cfg->pub);
-#endif
+#endif
#endif /* PROP_TXSTATUS_VSDB */
-
+#if defined(SUPPORT_AP_POWERSAVE)
+ dhd = (dhd_pub_t *)(cfg->pub);
+#endif
/* Use primary I/F for sending cmds down to firmware */
primary_ndev = bcmcfg_to_prmry_ndev(cfg);
@@ -1443,7 +1469,7 @@
#if defined(BCMSDIO)
if (!dhd)
return ERR_PTR(-ENODEV);
-#endif
+#endif
#endif /* PROP_TXSTATUS_VSDB */
if (!cfg->p2p)
return ERR_PTR(-ENODEV);
@@ -1474,7 +1500,7 @@
}
cfg->wlfc_on = true;
}
-#endif
+#endif
#endif /* PROP_TXSTATUS_VSDB */
/* In concurrency case, STA may be already associated in a particular channel.
@@ -1549,6 +1575,11 @@
"created net attach done\n", cfg->p2p->vir_ifname));
if (mode == WL_MODE_AP)
wl_set_drv_status(cfg, CONNECTED, new_ndev);
+#ifdef SUPPORT_AP_POWERSAVE
+ if (mode == WL_MODE_AP) {
+ dhd_set_ap_powersave(dhd, 0, TRUE);
+ }
+#endif
if (type == NL80211_IFTYPE_P2P_CLIENT)
dhd_mode = DHD_FLAG_P2P_GC_MODE;
else if (type == NL80211_IFTYPE_P2P_GO)
@@ -1564,6 +1595,35 @@
} else {
wl_clr_p2p_status(cfg, IF_ADDING);
WL_ERR((" virtual interface(%s) is not created \n", cfg->p2p->vir_ifname));
+
+ WL_ERR(("left timeout : %d\n", timeout));
+ WL_ERR(("IF_ADDING status : %d\n", wl_get_p2p_status(cfg, IF_ADDING)));
+ WL_ERR(("event valid : %d\n", cfg->if_event_info.valid));
+
+ wl_clr_p2p_status(cfg, GO_NEG_PHASE);
+ wl_set_p2p_status(cfg, IF_DELETING);
+
+ err = wl_cfgp2p_ifdel(cfg, &cfg->p2p->int_addr);
+ if (err == BCME_OK) {
+ timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
+ (wl_get_p2p_status(cfg, IF_DELETING) == false),
+ msecs_to_jiffies(MAX_WAIT_TIME));
+ if (timeout > 0 && !wl_get_p2p_status(cfg, IF_DELETING) &&
+ cfg->if_event_info.valid) {
+ WL_ERR(("IFDEL operation done\n"));
+ } else {
+ WL_ERR(("IFDEL didn't complete properly\n"));
+ err = BCME_ERROR;
+ }
+ }
+ if (err != BCME_OK) {
+ struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
+
+ WL_ERR(("p2p_ifdel failed, error %d, sent HANG event to %s\n",
+ err, ndev->name));
+ net_os_send_hang_message(ndev);
+ }
+
memset(cfg->p2p->vir_ifname, '\0', IFNAMSIZ);
cfg->p2p->vif_created = false;
#ifdef PROP_TXSTATUS_VSDB
@@ -1574,7 +1634,7 @@
dhd_wlfc_deinit(dhd);
cfg->wlfc_on = false;
}
-#endif
+#endif
#endif /* PROP_TXSTATUS_VSDB */
}
}
@@ -1683,7 +1743,7 @@
ret, ndev->name));
#if defined(BCMDONGLEHOST) && defined(OEM_ANDROID)
net_os_send_hang_message(ndev);
- #endif
+ #endif
} else {
/* Wait for IF_DEL operation to be finished */
timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
@@ -1767,7 +1827,7 @@
chspec = wl_cfg80211_get_shared_freq(wiphy);
wlif_type = WL_P2P_IF_GO;
- printk("%s : ap (%d), infra (%d), iftype: (%d)\n",
+ printf("%s : ap (%d), infra (%d), iftype: (%d)\n",
ndev->name, ap, infra, type);
wl_set_p2p_status(cfg, IF_CHANGING);
wl_clr_p2p_status(cfg, IF_CHANGED);
@@ -1782,6 +1842,9 @@
wl_clr_p2p_status(cfg, IF_CHANGED);
if (mode == WL_MODE_AP)
wl_set_drv_status(cfg, CONNECTED, ndev);
+#ifdef SUPPORT_AP_POWERSAVE
+ dhd_set_ap_powersave(dhd, 0, TRUE);
+#endif
} else if (ndev == bcmcfg_to_prmry_ndev(cfg) &&
!wl_get_drv_status(cfg, AP_CREATED, ndev)) {
wl_set_drv_status(cfg, AP_CREATING, ndev);
@@ -1796,6 +1859,52 @@
}
} else {
WL_DBG(("Change_virtual_iface for transition from GO/AP to client/STA"));
+#ifdef SUPPORT_AP_POWERSAVE
+ dhd_set_ap_powersave(dhd, 0, FALSE);
+#endif
+#ifdef P2PONEINT
+ wl_set_mode_by_netdev(cfg, ndev, mode);
+ if (cfg->p2p_supported && cfg->p2p->vif_created) {
+ WL_DBG(("p2p_vif_created (%d) p2p_on (%d)\n", cfg->p2p->vif_created,
+ p2p_on(cfg)));
+ wldev_iovar_setint(ndev, "mpc", 0);
+ wl_notify_escan_complete(cfg, ndev, true, true);
+
+ /* In concurrency case, STA may be already associated in a particular
+ * channel. so retrieve the current channel of primary interface and
+ * then start the virtual interface on that.
+ */
+ chspec = wl_cfg80211_get_shared_freq(wiphy);
+
+ wlif_type = WL_P2P_IF_CLIENT;
+ WL_ERR(("%s : ap (%d), infra (%d), iftype: (%d) chspec 0x%x \n",
+ ndev->name, ap, infra, type, chspec));
+ wl_set_p2p_status(cfg, IF_CHANGING);
+ wl_clr_p2p_status(cfg, IF_CHANGED);
+ wl_cfgp2p_ifchange(cfg, &cfg->p2p->int_addr, htod32(wlif_type), chspec);
+ wait_event_interruptible_timeout(cfg->netif_change_event,
+ (wl_get_p2p_status(cfg, IF_CHANGED) == true),
+ msecs_to_jiffies(MAX_WAIT_TIME));
+ wl_set_mode_by_netdev(cfg, ndev, mode);
+ dhd->op_mode |= DHD_FLAG_P2P_GC_MODE;
+ dhd->op_mode &= ~DHD_FLAG_P2P_GO_MODE;
+ wl_clr_p2p_status(cfg, IF_CHANGING);
+ wl_clr_p2p_status(cfg, IF_CHANGED);
+
+#define INIT_IE(IE_TYPE, BSS_TYPE) \
+ do { \
+ memset(wl_to_p2p_bss_saved_ie(cfg, BSS_TYPE).p2p_ ## IE_TYPE ## _ie, 0, \
+ sizeof(wl_to_p2p_bss_saved_ie(cfg, BSS_TYPE).p2p_ ## IE_TYPE ## _ie)); \
+ wl_to_p2p_bss_saved_ie(cfg, BSS_TYPE).p2p_ ## IE_TYPE ## _ie_len = 0; \
+ } while (0);
+
+ INIT_IE(probe_req, P2PAPI_BSSCFG_CONNECTION);
+ INIT_IE(probe_res, P2PAPI_BSSCFG_CONNECTION);
+ INIT_IE(assoc_req, P2PAPI_BSSCFG_CONNECTION);
+ INIT_IE(assoc_res, P2PAPI_BSSCFG_CONNECTION);
+ INIT_IE(beacon, P2PAPI_BSSCFG_CONNECTION);
+ }
+#endif /* P2PONEINT */
}
if (ibss) {
@@ -1899,7 +2008,7 @@
#if defined(BCMSDIO)
dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
bool enabled;
-#endif
+#endif
#endif /* PROP_TXSTATUS_VSDB */
bssidx = if_event_info->bssidx;
@@ -1935,7 +2044,7 @@
dhd_wlfc_deinit(dhd);
cfg->wlfc_on = false;
}
-#endif
+#endif
#endif /* PROP_TXSTATUS_VSDB */
}
@@ -2054,6 +2163,8 @@
(IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IR)))
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0) */
continue;
+ if (!dhd_conf_match_channel(cfg->pub, channel))
+ continue;
if (request->channels[i]->band == IEEE80211_BAND_2GHZ) {
#ifdef WL_HOST_BAND_MGMT
@@ -2142,7 +2253,7 @@
#if defined(USE_INITIAL_SHORT_DWELL_TIME)
#define FIRST_SCAN_ACTIVE_DWELL_TIME_MS 40
bool g_first_broadcast_scan = TRUE;
-#endif
+#endif
static s32
wl_run_escan(struct bcm_cfg80211 *cfg, struct net_device *ndev,
@@ -2189,7 +2300,7 @@
is_first_init_2g_scan = true;
g_first_broadcast_scan = false;
}
-#endif
+#endif
/* if scan request is not empty parse scan request paramters */
if (request != NULL) {
@@ -2215,7 +2326,7 @@
/* Override active_time to reduce scan time if it's first bradcast scan. */
if (is_first_init_2g_scan)
params->params.active_time = FIRST_SCAN_ACTIVE_DWELL_TIME_MS;
-#endif
+#endif
params->version = htod32(ESCAN_REQ_VERSION);
params->action = htod16(action);
@@ -2365,6 +2476,8 @@
{
s32 err = BCME_OK;
s32 passive_scan;
+ s32 passive_scan_time;
+ s32 passive_scan_time_org;
wl_scan_results_t *results;
WL_SCAN(("Enter \n"));
mutex_lock(&cfg->usr_sync);
@@ -2385,7 +2498,43 @@
goto exit;
}
+ if (passive_channel_skip) {
+
+ err = wldev_ioctl(ndev, WLC_GET_SCAN_PASSIVE_TIME,
+ &passive_scan_time_org, sizeof(passive_scan_time_org), false);
+ if (unlikely(err)) {
+ WL_ERR(("== error (%d)\n", err));
+ goto exit;
+ }
+
+ WL_SCAN(("PASSIVE SCAN time : %d \n", passive_scan_time_org));
+
+ passive_scan_time = 0;
+ err = wldev_ioctl(ndev, WLC_SET_SCAN_PASSIVE_TIME,
+ &passive_scan_time, sizeof(passive_scan_time), true);
+ if (unlikely(err)) {
+ WL_ERR(("== error (%d)\n", err));
+ goto exit;
+ }
+
+ WL_SCAN(("PASSIVE SCAN SKIPED!! (passive_channel_skip:%d) \n",
+ passive_channel_skip));
+ }
+
err = wl_run_escan(cfg, ndev, request, WL_SCAN_ACTION_START);
+
+ if (passive_channel_skip) {
+ err = wldev_ioctl(ndev, WLC_SET_SCAN_PASSIVE_TIME,
+ &passive_scan_time_org, sizeof(passive_scan_time_org), true);
+ if (unlikely(err)) {
+ WL_ERR(("== error (%d)\n", err));
+ goto exit;
+ }
+
+ WL_SCAN(("PASSIVE SCAN RECOVERED!! (passive_scan_time_org:%d) \n",
+ passive_scan_time_org));
+ }
+
exit:
mutex_unlock(&cfg->usr_sync);
return err;
@@ -2562,6 +2711,10 @@
ssids = this_ssid;
}
+ if (request && cfg->p2p && !p2p_scan(cfg)) {
+ WL_TRACE_HW4(("START SCAN\n"));
+ }
+
cfg->scan_request = request;
wl_set_drv_status(cfg, SCANNING, ndev);
@@ -2672,6 +2825,11 @@
WL_DBG(("Enter \n"));
RETURN_EIO_IF_NOT_UP(cfg);
+#ifdef P2PONEINT
+ ndev = bcmcfg_to_prmry_ndev(cfg);
+ WL_DBG(("scan use [dev name %s ] \n", ndev->name));
+#endif
+
err = __wl_cfg80211_scan(wiphy, ndev, request, NULL);
if (unlikely(err)) {
if ((err == BCME_EPERM) && cfg->scan_suppressed)
@@ -3005,6 +3163,51 @@
}
#endif /* WLAIBSS_MCHAN */
+s32
+wl_cfg80211_interface_ops(struct bcm_cfg80211 *cfg,
+ struct net_device *ndev, s32 bsscfg_idx,
+ enum nl80211_iftype iface_type, s32 del, u8 *addr)
+{
+ wl_interface_create_t iface;
+ s32 ret;
+ wl_interface_info_t *info;
+
+ bzero(&iface, sizeof(wl_interface_create_t));
+
+ iface.ver = WL_INTERFACE_CREATE_VER;
+
+ if (iface_type == NL80211_IFTYPE_AP)
+ iface.flags = WL_INTERFACE_CREATE_AP;
+ else
+ iface.flags = WL_INTERFACE_CREATE_STA;
+
+ if (del) {
+ ret = wldev_iovar_setbuf(ndev, "interface_remove",
+ NULL, 0, cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
+ } else {
+ if (addr) {
+ memcpy(&iface.mac_addr.octet, addr, ETH_ALEN);
+ iface.flags |= WL_INTERFACE_MAC_USE;
+ }
+ ret = wldev_iovar_getbuf(ndev, "interface_create",
+ &iface, sizeof(wl_interface_create_t),
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
+ if (ret == 0) {
+ /* success */
+ info = (wl_interface_info_t *)cfg->ioctl_buf;
+ WL_DBG(("wl interface create success!! bssidx:%d \n",
+ info->bsscfgidx));
+ ret = info->bsscfgidx;
+ }
+ }
+
+ if (ret < 0)
+ WL_ERR(("Interface %s failed!! ret %d\n",
+ del ? "remove" : "create", ret));
+
+ return ret;
+}
+
#if defined(DUAL_STA) || defined(DUAL_STA_STATIC_IF)
s32
wl_cfg80211_add_del_bss(struct bcm_cfg80211 *cfg,
@@ -3119,9 +3322,20 @@
/*
* Intialize the firmware I/F.
*/
- if ((ret = wl_cfg80211_add_del_bss(cfg, primary_ndev,
- bsscfg_idx, iface_type, 0, addr)) < 0) {
- return NULL;
+ ret = wl_cfg80211_interface_ops(cfg, primary_ndev, bsscfg_idx,
+ NL80211_IFTYPE_STATION, 0, addr);
+ if (ret == BCME_UNSUPPORTED) {
+ /* Use bssidx 1 by default */
+ if ((ret = wl_cfg80211_add_del_bss(cfg, primary_ndev,
+ bsscfg_idx, iface_type, 0, addr)) < 0) {
+ return NULL;
+ }
+ } else if (ret < 0) {
+ WL_ERR(("Interface create failed!! ret:%d \n", ret));
+ goto fail;
+ } else {
+ /* Success */
+ bsscfg_idx = ret;
}
/*
@@ -3210,6 +3424,7 @@
s32 ret = BCME_OK;
s32 bsscfg_idx = 1;
u32 timeout;
+ u32 ifidx;
enum nl80211_iftype iface_type = NL80211_IFTYPE_STATION;
WL_DBG(("Enter\n"));
@@ -3230,10 +3445,17 @@
memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info));
/* Delete the firmware interface */
- if ((ret = wl_cfg80211_add_del_bss(cfg, ndev,
- bsscfg_idx, iface_type, true, NULL)) < 0) {
- WL_ERR(("DEL bss failed ret:%d \n", ret));
- return ret;
+ ret = wl_cfg80211_interface_ops(cfg, ndev, cfg->cfgdev_bssidx,
+ NL80211_IFTYPE_STATION, 1, NULL);
+ if (ret == BCME_UNSUPPORTED) {
+ if ((ret = wl_cfg80211_add_del_bss(cfg, ndev,
+ bsscfg_idx, iface_type, true, NULL)) < 0) {
+ WL_ERR(("DEL bss failed ret:%d \n", ret));
+ return ret;
+ }
+ } else if (ret < 0) {
+ WL_ERR(("Interface DEL failed ret:%d \n", ret));
+ return ret;
}
timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
@@ -3241,8 +3463,8 @@
if (timeout <= 0 || cfg->bss_pending_op) {
WL_ERR(("timeout in waiting IF_DEL event\n"));
}
-
- wl_cfg80211_remove_if(cfg, cfg->if_event_info.ifidx, ndev);
+ ifidx = dhd_net2idx(((struct dhd_pub *)(cfg->pub))->info, ndev);
+ wl_cfg80211_remove_if(cfg, ifidx, ndev);
cfg->bss_cfgdev = NULL;
cfg->cfgdev_bssidx = -1;
cfg->bss_pending_op = FALSE;
@@ -3771,6 +3993,13 @@
wsec_val |= MFP_CAPABLE;
if (rsn_cap[0] & RSN_CAP_MFPR)
wsec_val |= MFP_REQUIRED;
+
+ if (rsn_cap[0] & RSN_CAP_MFPR)
+ mfp = WL_MFP_REQUIRED;
+ else
+ mfp = WL_MFP_CAPABLE;
+ err = wldev_iovar_setint_bsscfg(dev, "mfp",
+ mfp, bssidx);
}
}
}
@@ -4137,11 +4366,19 @@
wpaie = (wpa_ie != NULL) ? (u8 *)wpa_ie : (u8 *)wpa2_ie;
wpaie_len = (wpa_ie != NULL) ? wpa_ie->length : wpa2_ie->len;
wpaie_len += WPA_RSN_IE_TAG_FIXED_LEN;
- wldev_iovar_setbuf(dev, "wpaie", wpaie, wpaie_len,
+ err = wldev_iovar_setbuf(dev, "wpaie", wpaie, wpaie_len,
cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
+ if (unlikely(err)) {
+ WL_ERR(("wpaie set error (%d)\n", err));
+ return err;
+ }
} else {
- wldev_iovar_setbuf(dev, "wpaie", NULL, 0,
+ err = wldev_iovar_setbuf(dev, "wpaie", NULL, 0,
cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
+ if (unlikely(err)) {
+ WL_ERR(("wpaie set error (%d)\n", err));
+ return err;
+ }
}
if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) {
@@ -4272,7 +4509,7 @@
err = wldev_iovar_setbuf_bsscfg(dev, "join", ext_join_params, join_params_size,
cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
- printk("Connectting with " MACDBG " channel (%d) ssid \"%s\", len (%d)\n\n",
+ printf("Connectting with " MACDBG " channel (%d) ssid \"%s\", len (%d)\n\n",
MAC2STRDBG((u8*)(&ext_join_params->assoc.bssid)), cfg->channel,
ext_join_params->ssid.SSID, ext_join_params->ssid.SSID_len);
@@ -4335,6 +4572,14 @@
RETURN_EIO_IF_NOT_UP(cfg);
act = *(bool *) wl_read_prof(cfg, dev, WL_PROF_ACT);
curbssid = wl_read_prof(cfg, dev, WL_PROF_BSSID);
+#ifdef ESCAN_RESULT_PATCH
+ if (wl_get_drv_status(cfg, CONNECTING, dev) && curbssid &&
+ (memcmp(curbssid, connect_req_bssid, ETHER_ADDR_LEN) == 0)) {
+ WL_ERR(("Disconnecting from connecting device: " MACDBG "\n",
+ MAC2STRDBG(curbssid)));
+ act = true;
+ }
+#endif /* ESCAN_RESULT_PATCH */
if (act) {
/*
* Cancel ongoing scan to sync up with sme state machine of cfg80211.
@@ -4574,7 +4819,7 @@
}
int
-wl_cfg80211_enable_roam_offload(struct net_device *dev, bool enable)
+wl_cfg80211_enable_roam_offload(struct net_device *dev, int enable)
{
int err;
wl_eventmsg_buf_t ev_buf;
@@ -4583,7 +4828,7 @@
/* roam offload is only for the primary device */
return -1;
}
- err = wldev_iovar_setint(dev, "roam_offload", (int)enable);
+ err = wldev_iovar_setint(dev, "roam_offload", enable);
if (err)
return err;
@@ -4863,13 +5108,9 @@
return err;
}
-// terence 20130703: Fix for wrong group_capab (timing issue)
-int p2p_disconnected = 0;
-struct ether_addr p2p_disconnected_bssid;
-
#if defined(RSSIAVG)
static wl_rssi_cache_ctrl_t g_rssi_cache_ctrl;
-static wl_rssi_cache_ctrl_t g_rssi2_cache_ctrl;
+static wl_rssi_cache_ctrl_t g_connected_rssi_cache_ctrl;
#endif
#if defined(BSSCACHE)
static wl_bss_cache_ctrl_t g_bss_cache_ctrl;
@@ -4879,8 +5120,12 @@
wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
struct net_device *dev, u8 key_idx)
{
+#ifdef MFP
+ return 0;
+#else
WL_INFORM(("Not supported\n"));
return -EOPNOTSUPP;
+#endif /* MFP */
}
static s32
@@ -4997,17 +5242,21 @@
}
rssi = dtoh32(scb_val.val);
#if defined(RSSIAVG)
- err = wl_update_connected_rssi_cache(dev, &g_rssi2_cache_ctrl, &rssi);
+ err = wl_update_connected_rssi_cache(dev, &g_connected_rssi_cache_ctrl, &rssi);
if (err) {
WL_ERR(("Could not get rssi (%d)\n", err));
goto get_station_err;
}
- wl_delete_dirty_rssi_cache(&g_rssi2_cache_ctrl);
- wl_reset_rssi_cache(&g_rssi2_cache_ctrl);
+ wl_delete_dirty_rssi_cache(&g_connected_rssi_cache_ctrl);
+ wl_reset_rssi_cache(&g_connected_rssi_cache_ctrl);
#endif
#if defined(RSSIOFFSET)
rssi = wl_update_rssi_offset(dev, rssi);
#endif
+#if !defined(RSSIAVG) && !defined(RSSIOFFSET)
+ // terence 20150419: limit the max. rssi to -2 or the bss will be filtered out in android OS
+ rssi = MIN(rssi, RSSI_MAXVAL);
+#endif
sinfo->filled |= STATION_INFO_SIGNAL;
sinfo->signal = rssi;
WL_DBG(("RSSI %d dBm\n", rssi));
@@ -5051,6 +5300,7 @@
s32 err = 0;
struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
struct net_info *_net_info = wl_get_netinfo_by_netdev(cfg, dev);
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
RETURN_EIO_IF_NOT_UP(cfg);
WL_DBG(("Enter\n"));
@@ -5068,6 +5318,8 @@
dev->name, _net_info->pm_block));
pm = PM_OFF;
}
+ if (enabled && dhd_conf_get_pm(dhd) >= 0)
+ pm = dhd_conf_get_pm(dhd);
pm = htod32(pm);
WL_DBG(("%s:power save %s\n", dev->name, (pm ? "enabled" : "disabled")));
err = wldev_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm), true);
@@ -5483,6 +5735,11 @@
{
s32 err = 0;
+#ifdef P2PLISTEN_AP_SAMECHN
+ struct bcm_cfg80211 *cfg = g_bcm_cfg;
+ struct net_device *dev;
+#endif /* P2PLISTEN_AP_SAMECHN */
+
#if defined(WL_CFG80211_P2P_DEV_IF)
if (cfgdev->iftype == NL80211_IFTYPE_P2P_DEVICE) {
WL_DBG((" enter ) on P2P dedicated discover interface\n"));
@@ -5490,6 +5747,15 @@
#else
WL_DBG((" enter ) netdev_ifidx: %d \n", cfgdev->ifindex));
#endif /* WL_CFG80211_P2P_DEV_IF */
+
+#ifdef P2PLISTEN_AP_SAMECHN
+ if (cfg && cfg->p2p_resp_apchn_status) {
+ dev = bcmcfg_to_prmry_ndev(cfg);
+ wl_cfg80211_set_p2p_resp_ap_chn(dev, 0);
+ cfg->p2p_resp_apchn_status = false;
+ WL_DBG(("p2p_resp_apchn_status Turn OFF \n"));
+ }
+#endif /* P2PLISTEN_AP_SAMECHN */
return err;
}
@@ -6035,8 +6301,17 @@
dev = cfgdev_to_wlc_ndev(cfgdev, cfg);
+ if (!dev) {
+ WL_ERR(("dev is NULL\n"));
+ return -EINVAL;
+ }
+
/* set bsscfg idx for iovar (wlan0: P2PAPI_BSSCFG_PRIMARY, p2p: P2PAPI_BSSCFG_DEVICE) */
if (discover_cfgdev(cfgdev, cfg)) {
+ if (!cfg->p2p_supported || !cfg->p2p) {
+ WL_ERR(("P2P doesn't setup completed yet\n"));
+ return -EINVAL;
+ }
bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
}
else {
@@ -6067,6 +6342,10 @@
if (ieee80211_is_probe_resp(mgmt->frame_control)) {
s32 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
s32 ie_len = len - ie_offset;
+#ifdef P2PONEINT
+ if (dev == wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION))
+ dev = bcmcfg_to_prmry_ndev(cfg);
+#endif
if ((dev == bcmcfg_to_prmry_ndev(cfg)) && cfg->p2p)
bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
wl_cfgp2p_set_management_ie(cfg, dev, bssidx,
@@ -6300,9 +6579,15 @@
}
static s32
+#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) && !defined(WL_COMPAT_WIRELESS))
+wl_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev,
+ struct ieee80211_channel *chan,
+ struct cfg80211_chan_def chandef)
+#else
wl_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type)
+#endif /* ((LINUX_VERSION >= VERSION(3, 6, 0) && !WL_COMPAT_WIRELESS) */
{
s32 _chan;
chanspec_t chspec = 0;
@@ -6320,11 +6605,40 @@
dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
#endif /* CUSTOM_SET_CPUCORE */
+#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) && !defined(WL_COMPAT_WIRELESS))
+ enum nl80211_channel_type channel_type = NL80211_CHAN_HT20;
+#endif /* ((LINUX_VERSION >= VERSION(3, 6, 0) && !WL_COMPAT_WIRELESS) */
+
+#ifndef P2PONEINT
dev = ndev_to_wlc_ndev(dev, cfg);
+#endif
_chan = ieee80211_frequency_to_channel(chan->center_freq);
- printk("netdev_ifidx(%d), chan_type(%d) target channel(%d) \n",
+ printf("netdev_ifidx(%d), chan_type(%d) target channel(%d) \n",
dev->ifindex, channel_type, _chan);
+#ifdef CUSTOM_PLATFORM_NV_TEGRA
+#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) && !defined(WL_COMPAT_WIRELESS))
+ WL_ERR(("chan_width = %d\n", chandef.width));
+ switch (chandef.width) {
+ case NL80211_CHAN_WIDTH_40:
+ bw = WL_CHANSPEC_BW_40;
+ break;
+ case NL80211_CHAN_WIDTH_80:
+ bw = WL_CHANSPEC_BW_80;
+ break;
+ case NL80211_CHAN_WIDTH_80P80:
+ bw = WL_CHANSPEC_BW_8080;
+ break;
+ case NL80211_CHAN_WIDTH_160:
+ bw = WL_CHANSPEC_BW_160;
+ break;
+ default:
+ bw = WL_CHANSPEC_BW_20;
+ break;
+ }
+ goto set_channel;
+#endif /* ((LINUX_VERSION >= VERSION(3, 8, 0) && !WL_COMPAT_WIRELESS) */
+#endif /* CUSTOM_PLATFORM_NV_TEGRA */
if (chan->band == IEEE80211_BAND_5GHZ) {
param.band = WLC_BAND_5G;
@@ -6459,6 +6773,12 @@
wpa_suite_mcast_t *mcast;
wpa_suite_ucast_t *ucast;
wpa_suite_auth_key_mgmt_t *mgmt;
+ wpa_pmkid_list_t *pmkid;
+ int cnt = 0;
+#ifdef MFP
+ int mfp = 0;
+ struct bcm_cfg80211 *cfg = g_bcm_cfg;
+#endif /* MFP */
u16 suite_count;
u8 rsn_cap[2];
@@ -6468,7 +6788,7 @@
goto exit;
WL_DBG(("Enter \n"));
- len = wpa2ie->len;
+ len = wpa2ie->len - WPA2_VERSION_LEN;
/* check the mcast cipher */
mcast = (wpa_suite_mcast_t *)&wpa2ie->data[WPA2_VERSION_LEN];
switch (mcast->type) {
@@ -6529,19 +6849,31 @@
wsec = (pval | gval | SES_OW_ENABLED);
/* check the AKM */
mgmt = (wpa_suite_auth_key_mgmt_t *)&ucast->list[suite_count];
- suite_count = ltoh16_ua(&mgmt->count);
- switch (mgmt->list[0].type) {
- case RSN_AKM_NONE:
- wpa_auth = WPA_AUTH_NONE;
- break;
- case RSN_AKM_UNSPECIFIED:
- wpa_auth = WPA2_AUTH_UNSPECIFIED;
- break;
- case RSN_AKM_PSK:
- wpa_auth = WPA2_AUTH_PSK;
- break;
- default:
- WL_ERR(("No Key Mgmt Info\n"));
+ suite_count = cnt = ltoh16_ua(&mgmt->count);
+ while (cnt--) {
+ switch (mgmt->list[cnt].type) {
+ case RSN_AKM_NONE:
+ wpa_auth = WPA_AUTH_NONE;
+ break;
+ case RSN_AKM_UNSPECIFIED:
+ wpa_auth = WPA2_AUTH_UNSPECIFIED;
+ break;
+ case RSN_AKM_PSK:
+ wpa_auth = WPA2_AUTH_PSK;
+ break;
+#ifdef MFP
+ case RSN_AKM_MFP_PSK:
+ wpa_auth |= WPA2_AUTH_PSK;
+ wsec |= MFP_SHA256;
+ break;
+ case RSN_AKM_MFP_1X:
+ wpa_auth |= WPA2_AUTH_UNSPECIFIED;
+ wsec |= MFP_SHA256;
+ break;
+#endif /* MFP */
+ default:
+ WL_ERR(("No Key Mgmt Info\n"));
+ }
}
if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) >= RSN_CAP_LEN) {
@@ -6554,6 +6886,16 @@
wme_bss_disable = 1;
}
+#ifdef MFP
+ if (rsn_cap[0] & RSN_CAP_MFPR) {
+ WL_DBG(("MFP Required \n"));
+ mfp = WL_MFP_REQUIRED;
+ } else if (rsn_cap[0] & RSN_CAP_MFPC) {
+ WL_DBG(("MFP Capable \n"));
+ mfp = WL_MFP_CAPABLE;
+ }
+#endif /* MFP */
+
/* set wme_bss_disable to sync RSN Capabilities */
err = wldev_iovar_setint_bsscfg(dev, "wme_bss_disable", wme_bss_disable, bssidx);
if (err < 0) {
@@ -6564,6 +6906,30 @@
WL_DBG(("There is no RSN Capabilities. remained len %d\n", len));
}
+ if ((len -= RSN_CAP_LEN) >= WPA2_PMKID_COUNT_LEN) {
+ pmkid = (wpa_pmkid_list_t *)((u8 *)&mgmt->list[suite_count] + RSN_CAP_LEN);
+ cnt = ltoh16_ua(&pmkid->count);
+ if (cnt != 0) {
+ WL_ERR(("AP has non-zero PMKID count. Wrong!\n"));
+ return BCME_ERROR;
+ }
+ /* since PMKID cnt is known to be 0 for AP, */
+ /* so don't bother to send down this info to firmware */
+ }
+
+#ifdef MFP
+ if ((len -= WPA2_PMKID_COUNT_LEN) >= RSN_GROUPMANAGE_CIPHER_LEN) {
+ err = wldev_iovar_setbuf_bsscfg(dev, "bip",
+ (void *)((u8 *)&mgmt->list[suite_count] + RSN_CAP_LEN + WPA2_PMKID_COUNT_LEN),
+ RSN_GROUPMANAGE_CIPHER_LEN,
+ cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync);
+ if (err < 0) {
+ WL_ERR(("bip set error %d\n", err));
+ return BCME_ERROR;
+ }
+ }
+#endif
+
/* set auth */
err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx);
if (err < 0) {
@@ -6576,6 +6942,19 @@
WL_ERR(("wsec error %d\n", err));
return BCME_ERROR;
}
+
+#ifdef MFP
+ if (mfp) {
+ /* This needs to go after wsec otherwise the wsec command will
+ * overwrite the values set by MFP
+ */
+ if ((err = wldev_iovar_setint_bsscfg(dev, "mfp", mfp, bssidx)) < 0) {
+ WL_ERR(("MFP Setting failed. ret = %d \n", err));
+ return err;
+ }
+ }
+#endif /* MFP */
+
/* set upper-layer auth */
err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_auth, bssidx);
if (err < 0) {
@@ -7506,7 +7885,7 @@
sizeof(scb_val_t), true);
if (err < 0)
WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON err %d\n", err));
- printk("Disconnect STA : %s scb_val.val %d\n",
+ printf("Disconnect STA : %s scb_val.val %d\n",
bcm_ether_ntoa((const struct ether_addr *)mac_addr, eabuf),
scb_val.val);
@@ -7567,7 +7946,9 @@
else if (dev == cfg->p2p_net) {
/* Group Add request on p2p0 */
WL_DBG(("Start AP req on P2P iface: GO\n"));
+#ifndef P2PONEINT
dev = bcmcfg_to_prmry_ndev(cfg);
+#endif
dev_role = NL80211_IFTYPE_P2P_GO;
}
#endif /* WL_ENABLE_P2P_IF */
@@ -7588,7 +7969,7 @@
#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) && !defined(WL_COMPAT_WIRELESS))
if ((err = wl_cfg80211_set_channel(wiphy, dev,
dev->ieee80211_ptr->preset_chandef.chan,
- NL80211_CHAN_HT20) < 0)) {
+ dev->ieee80211_ptr->preset_chandef) < 0)) {
WL_ERR(("Set channel failed \n"));
goto fail;
}
@@ -7670,7 +8051,9 @@
#if defined(WL_ENABLE_P2P_IF)
else if (dev == cfg->p2p_net) {
/* Group Add request on p2p0 */
+#ifndef P2PONEINT
dev = bcmcfg_to_prmry_ndev(cfg);
+#endif
dev_role = NL80211_IFTYPE_P2P_GO;
}
#endif /* WL_ENABLE_P2P_IF */
@@ -7752,7 +8135,9 @@
#if defined(WL_ENABLE_P2P_IF)
else if (dev == cfg->p2p_net) {
/* Group Add request on p2p0 */
+#ifndef P2PONEINT
dev = bcmcfg_to_prmry_ndev(cfg);
+#endif
dev_role = NL80211_IFTYPE_P2P_GO;
}
#endif /* WL_ENABLE_P2P_IF */
@@ -7829,7 +8214,9 @@
#if defined(WL_ENABLE_P2P_IF)
else if (dev == cfg->p2p_net) {
/* Group Add request on p2p0 */
+#ifndef P2PONEINT
dev = bcmcfg_to_prmry_ndev(cfg);
+#endif
dev_role = NL80211_IFTYPE_P2P_GO;
}
#endif /* WL_ENABLE_P2P_IF */
@@ -8312,6 +8699,7 @@
.mgmt_tx_cancel_wait = wl_cfg80211_mgmt_tx_cancel_wait,
#endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VERSION >= (3,2,0) */
#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)
+ .tdls_mgmt = wl_cfg80211_tdls_mgmt,
.tdls_oper = wl_cfg80211_tdls_oper,
#endif /* LINUX_VERSION > VERSION(3, 2, 0) || WL_COMPAT_WIRELESS */
#ifdef WL_SUPPORT_ACS
@@ -8388,7 +8776,7 @@
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
#endif /* CONFIG_PM */
-static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev, void *context)
+static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev, dhd_pub_t *context)
{
s32 err = 0;
#if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) || defined(WL_COMPAT_WIRELESS))
@@ -8400,7 +8788,7 @@
err = -ENODEV;
return err;
}
-#endif
+#endif
wdev->wiphy =
wiphy_new(&wl_cfg80211_ops, sizeof(struct bcm_cfg80211));
@@ -8501,7 +8889,7 @@
wdev->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
wdev->wiphy->probe_resp_offload = 0;
}
-#endif
+#endif
#endif /* WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) */
#ifdef CONFIG_CFG80211_INTERNAL_REGDB
@@ -8593,69 +8981,82 @@
bss_list = cfg->bss_list;
-#if defined(BSSCACHE)
+ /* Free cache in p2p scanning*/
if (p2p_is_on(cfg) && p2p_scan(cfg)) {
#if defined(RSSIAVG)
wl_free_rssi_cache(&g_rssi_cache_ctrl);
#endif
+#if defined(BSSCACHE)
wl_free_bss_cache(&g_bss_cache_ctrl);
+#endif
}
- wl_update_bss_cache(&g_bss_cache_ctrl, bss_list);
- wl_delete_dirty_bss_cache(&g_bss_cache_ctrl);
- wl_reset_bss_cache(&g_bss_cache_ctrl);
+
+ /* Delete disconnected cache */
+#if defined(BSSCACHE)
+ wl_delete_disconnected_bss_cache(&g_bss_cache_ctrl, (u8*)&cfg->disconnected_bssid);
+#if defined(RSSIAVG)
+ wl_delete_disconnected_rssi_cache(&g_rssi_cache_ctrl, (u8*)&cfg->disconnected_bssid);
+#endif
+ if (cfg->p2p_disconnected == 0)
+ memset(&cfg->disconnected_bssid, 0, ETHER_ADDR_LEN);
#endif
+ /* Update cache */
#if defined(RSSIAVG)
-#if defined(BSSCACHE)
- node = g_bss_cache_ctrl.m_cache_head;
- for (;node;) {
- wl_update_rssi_cache(&g_rssi_cache_ctrl, &node->results);
- node = node->next;
- }
-#else
wl_update_rssi_cache(&g_rssi_cache_ctrl, bss_list);
-#endif
if (!in_atomic())
wl_update_connected_rssi_cache(ndev, &g_rssi_cache_ctrl, &rssi);
+#endif
+#if defined(BSSCACHE)
+ wl_update_bss_cache(&g_bss_cache_ctrl,
+#if defined(RSSIAVG)
+ &g_rssi_cache_ctrl,
+#endif
+ bss_list);
+#endif
+
+ /* delete dirty cache */
+#if defined(RSSIAVG)
wl_delete_dirty_rssi_cache(&g_rssi_cache_ctrl);
wl_reset_rssi_cache(&g_rssi_cache_ctrl);
#endif
+#if defined(BSSCACHE)
+ wl_delete_dirty_bss_cache(&g_bss_cache_ctrl);
+ wl_reset_bss_cache(&g_bss_cache_ctrl);
+#endif
#if defined(BSSCACHE)
- if (p2p_disconnected > 0) {
+ if (cfg->p2p_disconnected > 0) {
// terence 20130703: Fix for wrong group_capab (timing issue)
- wl_delete_disconnected_bss_cache(&g_bss_cache_ctrl, (u8*)&p2p_disconnected_bssid);
+ wl_delete_disconnected_bss_cache(&g_bss_cache_ctrl, (u8*)&cfg->disconnected_bssid);
#if defined(RSSIAVG)
- wl_delete_disconnected_rssi_cache(&g_rssi_cache_ctrl, (u8*)&p2p_disconnected_bssid);
+ wl_delete_disconnected_rssi_cache(&g_rssi_cache_ctrl, (u8*)&cfg->disconnected_bssid);
#endif
}
- WL_SCAN(("Inform cached AP list\n"));
+ WL_SCAN(("scanned AP count (%d)\n", bss_list->count));
node = g_bss_cache_ctrl.m_cache_head;
for (i=0; node && i<WL_AP_MAX; i++) {
- if (node->dirty > 1) {
- // just inform dirty bss
- bi = node->results.bss_info;
- err = wl_inform_single_bss(cfg, bi, false);
- }
+ bi = node->results.bss_info;
+ err = wl_inform_single_bss(cfg, bi, false);
node = node->next;
}
- bi = NULL;
-#endif
-
+#else
WL_SCAN(("scanned AP count (%d)\n", bss_list->count));
-
bi = next_bss(bss_list, bi);
for_each_bss(bss_list, bi, i) {
- if (p2p_disconnected > 0 && !memcmp(&bi->BSSID, &p2p_disconnected_bssid, ETHER_ADDR_LEN))
+ if (cfg->p2p_disconnected > 0 && !memcmp(&bi->BSSID, &cfg->disconnected_bssid, ETHER_ADDR_LEN))
continue;
err = wl_inform_single_bss(cfg, bi, false);
}
+#endif
- if (p2p_disconnected > 0) {
+ if (cfg->p2p_disconnected > 0) {
// terence 20130703: Fix for wrong group_capab (timing issue)
- p2p_disconnected++;
- if (p2p_disconnected >= REPEATED_SCAN_RESULT_CNT+1)
- p2p_disconnected = 0;
+ cfg->p2p_disconnected++;
+ if (cfg->p2p_disconnected >= REPEATED_SCAN_RESULT_CNT+1) {
+ cfg->p2p_disconnected = 0;
+ memset(&cfg->disconnected_bssid, 0, ETHER_ADDR_LEN);
+ }
}
return err;
@@ -8710,6 +9111,10 @@
#if defined(RSSIOFFSET)
notif_bss_info->rssi = wl_update_rssi_offset(bcmcfg_to_prmry_ndev(cfg), notif_bss_info->rssi);
#endif
+#if !defined(RSSIAVG) && !defined(RSSIOFFSET)
+ // terence 20150419: limit the max. rssi to -2 or the bss will be filtered out in android OS
+ notif_bss_info->rssi = MIN(notif_bss_info->rssi, RSSI_MAXVAL);
+#endif
memcpy(mgmt->bssid, &bi->BSSID, ETHER_ADDR_LEN);
mgmt_type = cfg->active_scan ?
IEEE80211_STYPE_PROBE_RESP : IEEE80211_STYPE_BEACON;
@@ -8741,16 +9146,16 @@
return -EINVAL;
}
channel = ieee80211_get_channel(wiphy, freq);
+ WL_SCAN(("BSSID %pM, channel %2d, rssi %3d, capa 0x04%x, mgmt_type %d, "
+ "frame_len %d, SSID \"%s\"\n", &bi->BSSID, notif_bss_info->channel,
+ notif_bss_info->rssi, mgmt->u.beacon.capab_info, mgmt_type,
+ notif_bss_info->frame_len, bi->SSID));
if (unlikely(!channel)) {
WL_ERR(("ieee80211_get_channel error, freq=%d, channel=%d\n",
freq, notif_bss_info->channel));
kfree(notif_bss_info);
return -EINVAL;
}
- WL_SCAN(("BSSID %pM, channel %d, rssi %d, capa 0x04%x, mgmt_type %d, "
- "frame_len %d, SSID \"%s\"\n", &bi->BSSID, notif_bss_info->channel,
- notif_bss_info->rssi, mgmt->u.beacon.capab_info, mgmt_type,
- notif_bss_info->frame_len, bi->SSID));
signal = notif_bss_info->rssi * 100;
if (!mgmt->u.probe_resp.timestamp) {
@@ -8970,25 +9375,34 @@
isfree = true;
if (event == WLC_E_ASSOC_IND && reason == DOT11_SC_SUCCESS) {
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
+ cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, 0);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, 0, GFP_ATOMIC);
-#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS)
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
+ defined(WL_COMPAT_WIRELESS)
cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC);
#else
cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
#endif /* LINUX_VERSION >= VERSION(3, 12, 0) */
} else if (event == WLC_E_DISASSOC_IND) {
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
+ cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, 0);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, 0, GFP_ATOMIC);
-#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS)
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
+ defined(WL_COMPAT_WIRELESS)
cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC);
#else
cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
#endif /* LINUX_VERSION >= VERSION(3, 12, 0) */
} else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) {
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
+ cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, 0);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, 0, GFP_ATOMIC);
-#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS)
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
+ defined(WL_COMPAT_WIRELESS)
cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC);
#else
cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
@@ -9011,13 +9425,13 @@
}
sinfo.assoc_req_ies = data;
sinfo.assoc_req_ies_len = len;
- printk("%s: connected device "MACDBG"\n", __FUNCTION__, MAC2STRDBG(e->addr.octet));
+ printf("%s: connected device "MACDBG"\n", __FUNCTION__, MAC2STRDBG(e->addr.octet));
cfg80211_new_sta(ndev, e->addr.octet, &sinfo, GFP_ATOMIC);
} else if (event == WLC_E_DISASSOC_IND) {
- printk("%s: disassociated device "MACDBG"\n", __FUNCTION__, MAC2STRDBG(e->addr.octet));
+ printf("%s: disassociated device "MACDBG"\n", __FUNCTION__, MAC2STRDBG(e->addr.octet));
cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC);
} else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) {
- printk("%s: deauthenticated device "MACDBG"\n", __FUNCTION__, MAC2STRDBG(e->addr.octet));
+ printf("%s: deauthenticated device "MACDBG"\n", __FUNCTION__, MAC2STRDBG(e->addr.octet));
cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC);
}
#endif /* LINUX_VERSION < VERSION(3,2,0) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */
@@ -9054,6 +9468,12 @@
u16 flags = ntoh16(e->flags);
u32 status = ntoh32(e->status);
bool active;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
+ struct ieee80211_channel *channel = NULL;
+ struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
+ u32 chanspec, chan;
+ u32 freq, band;
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
if (event == WLC_E_JOIN) {
WL_DBG(("joined in IBSS network\n"));
@@ -9063,6 +9483,17 @@
}
if (event == WLC_E_JOIN || event == WLC_E_START ||
(event == WLC_E_LINK && (flags == WLC_EVENT_MSG_LINK))) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
+ err = wldev_iovar_getint(ndev, "chanspec", (s32 *)&chanspec);
+ if (unlikely(err)) {
+ WL_ERR(("Could not get chanspec %d\n", err));
+ return err;
+ }
+ chan = wf_chspec_ctlchan(wl_chspec_driver_to_host(chanspec));
+ band = (chan <= CH_MAX_2G_CHANNEL) ? IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
+ freq = ieee80211_channel_to_frequency(chan, band);
+ channel = ieee80211_get_channel(wiphy, freq);
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
/* ROAM or Redundant */
u8 *cur_bssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
@@ -9076,7 +9507,11 @@
wl_get_assoc_ies(cfg, ndev);
wl_update_prof(cfg, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID);
wl_update_bss_info(cfg, ndev, false);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
+ cfg80211_ibss_joined(ndev, (s8 *)&e->addr, channel, GFP_KERNEL);
+#else
cfg80211_ibss_joined(ndev, (s8 *)&e->addr, GFP_KERNEL);
+#endif
}
else {
/* New connection */
@@ -9085,7 +9520,11 @@
wl_get_assoc_ies(cfg, ndev);
wl_update_prof(cfg, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID);
wl_update_bss_info(cfg, ndev, false);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
+ cfg80211_ibss_joined(ndev, (s8 *)&e->addr, channel, GFP_KERNEL);
+#else
cfg80211_ibss_joined(ndev, (s8 *)&e->addr, GFP_KERNEL);
+#endif
wl_set_drv_status(cfg, CONNECTED, ndev);
active = true;
wl_update_prof(cfg, ndev, NULL, (void *)&active, WL_PROF_ACT);
@@ -9131,19 +9570,27 @@
wl_link_up(cfg);
act = true;
if (!wl_get_drv_status(cfg, DISCONNECTING, ndev)) {
- printk("wl_bss_connect_done succeeded with " MACDBG "\n",
+ printf("wl_bss_connect_done succeeded with " MACDBG "\n",
MAC2STRDBG((u8*)(&e->addr)));
wl_bss_connect_done(cfg, ndev, e, data, true);
- dhd_conf_set_phyoclscdenable((dhd_pub_t *)cfg->pub);
+ dhd_conf_set_fw_string_cmd(cfg->pub, "phy_oclscdenable", cfg->pub->conf->phy_oclscdenable, 0, FALSE);
WL_DBG(("joined in BSS network \"%s\"\n",
((struct wlc_ssid *)
wl_read_prof(cfg, ndev, WL_PROF_SSID))->SSID));
}
wl_update_prof(cfg, ndev, e, &act, WL_PROF_ACT);
wl_update_prof(cfg, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID);
- dhd_conf_set_wme((dhd_pub_t *)cfg->pub);
+ dhd_conf_set_wme(cfg->pub);
} else if (wl_is_linkdown(cfg, e)) {
+#ifdef P2PLISTEN_AP_SAMECHN
+ if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
+ wl_cfg80211_set_p2p_resp_ap_chn(ndev, 0);
+ cfg->p2p_resp_apchn_status = false;
+ WL_DBG(("p2p_resp_apchn_status Turn OFF \n"));
+ }
+#endif /* P2PLISTEN_AP_SAMECHN */
+
if (cfg->scan_request)
wl_notify_escan_complete(cfg, ndev, true, true);
if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
@@ -9155,7 +9602,7 @@
/* WLAN_REASON_UNSPECIFIED is used for hang up event in Android */
reason = (reason == WLAN_REASON_UNSPECIFIED)? 0 : reason;
- printk("link down if %s may call cfg80211_disconnected. "
+ printf("link down if %s may call cfg80211_disconnected. "
"event : %d, reason=%d from " MACDBG "\n",
ndev->name, event, ntoh32(e->reason),
MAC2STRDBG((u8*)(&e->addr)));
@@ -9168,9 +9615,9 @@
}
if (!memcmp(ndev->name, WL_P2P_INTERFACE_PREFIX, strlen(WL_P2P_INTERFACE_PREFIX))) {
// terence 20130703: Fix for wrong group_capab (timing issue)
- p2p_disconnected = 1;
- memcpy(&p2p_disconnected_bssid, curbssid, ETHER_ADDR_LEN);
+ cfg->p2p_disconnected = 1;
}
+ memcpy(&cfg->disconnected_bssid, curbssid, ETHER_ADDR_LEN);
wl_clr_drv_status(cfg, CONNECTED, ndev);
if (! wl_get_drv_status(cfg, DISCONNECTING, ndev)) {
/* To make sure disconnect, explictly send dissassoc
@@ -9192,7 +9639,7 @@
}
}
else if (wl_get_drv_status(cfg, CONNECTING, ndev)) {
- printk("link down, during connecting\n");
+ printf("link down, during connecting\n");
#ifdef ESCAN_RESULT_PATCH
if ((memcmp(connect_req_bssid, broad_bssid, ETHER_ADDR_LEN) == 0) ||
(memcmp(&e->addr, broad_bssid, ETHER_ADDR_LEN) == 0) ||
@@ -9208,7 +9655,7 @@
complete(&cfg->iface_disable);
} else if (wl_is_nonetwork(cfg, e)) {
- printk("connect failed event=%d e->status %d e->reason %d \n",
+ printf("connect failed event=%d e->status %d e->reason %d \n",
event, (int)ntoh32(e->status), (int)ntoh32(e->reason));
/* Clean up any pending scan request */
if (cfg->scan_request)
@@ -9313,7 +9760,7 @@
act = true;
wl_update_prof(cfg, ndev, e, &act, WL_PROF_ACT);
wl_update_prof(cfg, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID);
- dhd_conf_set_wme((dhd_pub_t *)cfg->pub);
+ dhd_conf_set_wme(cfg->pub);
}
return err;
}
@@ -9434,14 +9881,13 @@
s32 err = 0;
struct wiphy *wiphy;
u32 channel;
+ struct ieee80211_channel *cur_channel;
+ u32 freq, band;
wiphy = bcmcfg_to_wiphy(cfg);
ssid = (struct wlc_ssid *)wl_read_prof(cfg, ndev, WL_PROF_SSID);
curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
- bss = cfg80211_get_bss(wiphy, NULL, curbssid,
- ssid->SSID, ssid->SSID_len, WLAN_CAPABILITY_ESS,
- WLAN_CAPABILITY_ESS);
mutex_lock(&cfg->usr_sync);
@@ -9455,6 +9901,17 @@
bi = (struct wl_bss_info *)(cfg->extra_buf + 4);
channel = wf_chspec_ctlchan(wl_chspec_driver_to_host(bi->chanspec));
wl_update_prof(cfg, ndev, NULL, &channel, WL_PROF_CHAN);
+#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS)
+ freq = ieee80211_channel_to_frequency(channel);
+#else
+ band = (channel <= CH_MAX_2G_CHANNEL) ? IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
+ freq = ieee80211_channel_to_frequency(channel, band);
+#endif
+ cur_channel = ieee80211_get_channel(wiphy, freq);
+
+ bss = cfg80211_get_bss(wiphy, cur_channel, curbssid,
+ ssid->SSID, ssid->SSID_len, WLAN_CAPABILITY_ESS,
+ WLAN_CAPABILITY_ESS);
if (!bss) {
WL_DBG(("Could not find the AP\n"));
@@ -9561,9 +10018,9 @@
memcpy(cfg->fbt_key, data, FBT_KEYLEN);
}
#endif /* WLFBT */
- printk("wl_bss_roaming_done succeeded to " MACDBG "\n",
+ printf("wl_bss_roaming_done succeeded to " MACDBG "\n",
MAC2STRDBG((u8*)(&e->addr)));
- dhd_conf_set_wme((dhd_pub_t *)cfg->pub);
+ dhd_conf_set_wme(cfg->pub);
cfg80211_roamed(ndev,
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS)
@@ -9587,7 +10044,7 @@
struct wl_security *sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
#if defined(CUSTOM_SET_CPUCORE)
dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
-#endif
+#endif
s32 err = 0;
u8 *curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
if (!sec) {
@@ -9656,7 +10113,7 @@
GFP_KERNEL);
if (completed) {
WL_INFORM(("Report connect result - connection succeeded\n"));
- dhd_conf_set_wme((dhd_pub_t *)cfg->pub);
+ dhd_conf_set_wme(cfg->pub);
} else
WL_ERR(("Report connect result - connection failed\n"));
}
@@ -9912,6 +10369,9 @@
memset(&bssid, 0, ETHER_ADDR_LEN);
ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
+#ifdef P2PONEINT
+ WL_DBG((" device name is ndev %s \n", ndev->name));
+#endif
if (channel <= CH_MAX_2G_CHANNEL)
band = wiphy->bands[IEEE80211_BAND_2GHZ];
@@ -9976,6 +10436,21 @@
}
}
(void) sd_act_frm;
+#ifdef WLTDLS
+ } else if (mgmt_frame[DOT11_MGMT_HDR_LEN] == TDLS_AF_CATEGORY) {
+ WL_DBG((" TDLS Action Frame Received type = %d \n",
+ mgmt_frame[DOT11_MGMT_HDR_LEN + 1]));
+
+ if (mgmt_frame[DOT11_MGMT_HDR_LEN + 1] == TDLS_ACTION_SETUP_RESP) {
+ cfg->tdls_mgmt_frame = mgmt_frame;
+ cfg->tdls_mgmt_frame_len = mgmt_frame_len;
+ cfg->tdls_mgmt_freq = freq;
+ return 0;
+ }
+
+ } else if (mgmt_frame[DOT11_MGMT_HDR_LEN] == TDLS_VENDOR_SPECIFIC) {
+ WL_DBG((" TDLS Vendor Specific Received type \n"));
+#endif
} else {
if (cfg->next_af_subtype != P2P_PAF_SUBTYPE_INVALID) {
@@ -10079,7 +10554,17 @@
}
}
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
+#ifdef P2PONEINT
+ if (ndev == cfg->p2p_net && ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
+ ndev = bcmcfg_to_prmry_ndev(cfg);
+ cfgdev = ndev_to_cfgdev(ndev);
+ }
+ WL_DBG((" device name is ndev %s \n", ndev->name));
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
+ retval = cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, mgmt_frame_len, 0);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
retval = cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, mgmt_frame_len, 0, GFP_ATOMIC);
#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
defined(WL_COMPAT_WIRELESS)
@@ -10422,6 +10907,12 @@
kfree(cfg->ap_info);
cfg->ap_info = NULL;
}
+#ifdef WLTDLS
+ if (cfg->tdls_mgmt_frame) {
+ kfree(cfg->tdls_mgmt_frame);
+ cfg->tdls_mgmt_frame = NULL;
+ }
+#endif /* WLTDLS */
}
static s32 wl_create_event_handler(struct bcm_cfg80211 *cfg)
@@ -10471,9 +10962,14 @@
static s32
wl_cfg80211_netdev_notifier_call(struct notifier_block * nb,
unsigned long state,
- void *ndev)
+ void *ptr)
{
- struct net_device *dev = ndev;
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0))
+ struct net_device *dev = ptr;
+#else
+ // terence 20150701: fix for p2p connection issue
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+#endif
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct bcm_cfg80211 *cfg = g_bcm_cfg;
@@ -10521,7 +11017,7 @@
case NETDEV_UNREGISTER:
/* after calling list_del_rcu(&wdev->list) */
- wl_dealloc_netinfo(cfg, ndev);
+ wl_dealloc_netinfo(cfg, dev);
break;
case NETDEV_GOING_DOWN:
/* At NETDEV_DOWN state, wdev_cleanup_work work will be called.
@@ -10544,7 +11040,12 @@
*/
static bool wl_cfg80211_netdev_notifier_registered = FALSE;
-static void wl_cfg80211_scan_abort(struct bcm_cfg80211 *cfg)
+void
+#ifdef P2PONEINT
+wl_cfg80211_scan_abort(struct bcm_cfg80211 *cfg)
+#else
+wl_cfg80211_scan_abort(struct bcm_cfg80211 *cfg)
+#endif
{
wl_scan_params_t *params = NULL;
s32 params_size = 0;
@@ -10638,6 +11139,64 @@
return err;
}
+#ifdef ESCAN_BUF_OVERFLOW_MGMT
+static void
+wl_cfg80211_find_removal_candidate(wl_bss_info_t *bss, removal_element_t *candidate)
+{
+ int idx;
+ for (idx = 0; idx < BUF_OVERFLOW_MGMT_COUNT; idx++) {
+ int len = BUF_OVERFLOW_MGMT_COUNT - idx - 1;
+ if (bss->RSSI < candidate[idx].RSSI) {
+ if (len)
+ memcpy(&candidate[idx + 1], &candidate[idx],
+ sizeof(removal_element_t) * len);
+ candidate[idx].RSSI = bss->RSSI;
+ candidate[idx].length = bss->length;
+ memcpy(&candidate[idx].BSSID, &bss->BSSID, ETHER_ADDR_LEN);
+ return;
+ }
+ }
+}
+
+static void
+wl_cfg80211_remove_lowRSSI_info(wl_scan_results_t *list, removal_element_t *candidate,
+ wl_bss_info_t *bi)
+{
+ int idx1, idx2;
+ int total_delete_len = 0;
+ for (idx1 = 0; idx1 < BUF_OVERFLOW_MGMT_COUNT; idx1++) {
+ int cur_len = WL_SCAN_RESULTS_FIXED_SIZE;
+ wl_bss_info_t *bss = NULL;
+ if (candidate[idx1].RSSI >= bi->RSSI)
+ continue;
+ for (idx2 = 0; idx2 < list->count; idx2++) {
+ bss = bss ? (wl_bss_info_t *)((uintptr)bss + dtoh32(bss->length)) :
+ list->bss_info;
+ if (!bcmp(&candidate[idx1].BSSID, &bss->BSSID, ETHER_ADDR_LEN) &&
+ candidate[idx1].RSSI == bss->RSSI &&
+ candidate[idx1].length == dtoh32(bss->length)) {
+ u32 delete_len = dtoh32(bss->length);
+ WL_DBG(("delete scan info of " MACDBG " to add new AP\n",
+ MAC2STRDBG(bss->BSSID.octet)));
+ if (idx2 < list->count -1) {
+ memmove((u8 *)bss, (u8 *)bss + delete_len,
+ list->buflen - cur_len - delete_len);
+ }
+ list->buflen -= delete_len;
+ list->count--;
+ total_delete_len += delete_len;
+ /* if delete_len is greater than or equal to result length */
+ if (total_delete_len >= bi->length) {
+ return;
+ }
+ break;
+ }
+ cur_len += dtoh32(bss->length);
+ }
+ }
+}
+#endif /* ESCAN_BUF_OVERFLOW_MGMT */
+
static s32 wl_escan_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
const wl_event_msg_t *e, void *data)
{
@@ -10709,7 +11268,7 @@
WL_ERR(("No valid band\n"));
goto exit;
}
- if (!dhd_conf_match_channel((dhd_pub_t *)cfg->pub, channel))
+ if (!dhd_conf_match_channel(cfg->pub, channel))
goto exit;
/* ----- terence 20130524: skip invalid bss */
@@ -10747,6 +11306,13 @@
} else {
int cur_len = WL_SCAN_RESULTS_FIXED_SIZE;
+#ifdef ESCAN_BUF_OVERFLOW_MGMT
+ removal_element_t candidate[BUF_OVERFLOW_MGMT_COUNT];
+ int remove_lower_rssi = FALSE;
+
+ bzero(candidate, sizeof(removal_element_t)*BUF_OVERFLOW_MGMT_COUNT);
+#endif /* ESCAN_BUF_OVERFLOW_MGMT */
+
list = wl_escan_get_buf(cfg, FALSE);
if (scan_req_match(cfg)) {
#ifdef WL_HOST_BAND_MGMT
@@ -10778,11 +11344,24 @@
}
#endif /* WL_HOST_BAND_MGMT */
}
+#ifdef ESCAN_BUF_OVERFLOW_MGMT
+ if (bi_length > ESCAN_BUF_SIZE - list->buflen)
+ remove_lower_rssi = TRUE;
+#endif /* ESCAN_BUF_OVERFLOW_MGMT */
+
WL_SCAN(("%s("MACDBG") RSSI %d flags 0x%x length %d\n", bi->SSID,
MAC2STRDBG(bi->BSSID.octet), bi->RSSI, bi->flags, bi->length));
for (i = 0; i < list->count; i++) {
bss = bss ? (wl_bss_info_t *)((uintptr)bss + dtoh32(bss->length))
: list->bss_info;
+#ifdef ESCAN_BUF_OVERFLOW_MGMT
+ WL_TRACE(("%s("MACDBG"), i=%d bss: RSSI %d list->count %d\n",
+ bss->SSID, MAC2STRDBG(bss->BSSID.octet),
+ i, bss->RSSI, list->count));
+
+ if (remove_lower_rssi)
+ wl_cfg80211_find_removal_candidate(bss, candidate);
+#endif /* ESCAN_BUF_OVERFLOW_MGMT */
if (!bcmp(&bi->BSSID, &bss->BSSID, ETHER_ADDR_LEN) &&
(CHSPEC_BAND(wl_chspec_driver_to_host(bi->chanspec))
@@ -10861,8 +11440,17 @@
cur_len += dtoh32(bss->length);
}
if (bi_length > ESCAN_BUF_SIZE - list->buflen) {
+#ifdef ESCAN_BUF_OVERFLOW_MGMT
+ wl_cfg80211_remove_lowRSSI_info(list, candidate, bi);
+ if (bi_length > ESCAN_BUF_SIZE - list->buflen) {
+ WL_DBG(("RSSI(" MACDBG ") is too low(%d) to add Buffer\n",
+ MAC2STRDBG(bi->BSSID.octet), bi->RSSI));
+ goto exit;
+ }
+#else
WL_ERR(("Buffer is too small: ignoring\n"));
goto exit;
+#endif /* ESCAN_BUF_OVERFLOW_MGMT */
}
if (strlen(bi->SSID) == 0) { // terence: fix for hidden SSID
WL_SCAN(("Skip hidden SSID %pM\n", &bi->BSSID));
@@ -10878,6 +11466,17 @@
}
else if (status == WLC_E_STATUS_SUCCESS) {
+#if defined(CUSTOM_PLATFORM_NV_TEGRA)
+#if defined(P2P_DISCOVERY_WAR)
+ if (cfg->p2p_net && cfg->scan_request &&
+ cfg->scan_request->dev == cfg->p2p_net &&
+ !cfg->p2p->vif_created) {
+ if (wldev_iovar_setint(wl_to_prmry_ndev(cfg), "mpc", 1) < 0) {
+ WL_ERR(("mpc enabling back failed\n"));
+ }
+ }
+#endif /* defined(P2P_DISCOVERY_WAR) */
+#endif /* defined(CUSTOM_PLATFORM_NV_TEGRA) */
cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
wl_escan_print_sync_id(status, cfg->escan_info.cur_sync_id,
escan_result->sync_id);
@@ -10901,6 +11500,17 @@
wl_escan_increment_sync_id(cfg, SCAN_BUF_NEXT);
}
else if (status == WLC_E_STATUS_ABORT) {
+#if defined(CUSTOM_PLATFORM_NV_TEGRA)
+#if defined(P2P_DISCOVERY_WAR)
+ if (cfg->p2p_net && cfg->scan_request &&
+ cfg->scan_request->dev == cfg->p2p_net &&
+ !cfg->p2p->vif_created) {
+ if (wldev_iovar_setint(wl_to_prmry_ndev(cfg), "mpc", 1) < 0) {
+ WL_ERR(("mpc enabling back failed\n"));
+ }
+ }
+#endif /* defined(P2P_DISCOVERY_WAR) */
+#endif /* defined(CUSTOM_PLATFORM_NV_TEGRA) */
cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
wl_escan_print_sync_id(status, escan_result->sync_id,
cfg->escan_info.cur_sync_id);
@@ -11030,7 +11640,7 @@
}
}
}
- printk("%s concurrency is enabled\n", cfg->vsdb_mode ? "Multi Channel" : "Same Channel");
+ printf("%s concurrency is enabled\n", cfg->vsdb_mode ? "Multi Channel" : "Same Channel");
return;
}
@@ -11043,6 +11653,7 @@
u32 chan = 0;
struct net_info *iter, *next;
struct net_device *primary_dev = bcmcfg_to_prmry_ndev(cfg);
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
WL_DBG(("Enter state %d set %d _net_info->pm_restore %d iface %s\n",
state, set, _net_info->pm_restore, _net_info->ndev->name));
@@ -11066,6 +11677,8 @@
*/
if (!_net_info->pm_block && (mode == WL_MODE_BSS)) {
_net_info->pm = PM_FAST;
+ if (dhd_conf_get_pm(dhd) >= 0)
+ _net_info->pm = dhd_conf_get_pm(dhd);
_net_info->pm_restore = true;
}
pm = PM_OFF;
@@ -11085,6 +11698,8 @@
for_each_ndev(cfg, iter, next) {
if (!wl_get_drv_status(cfg, CONNECTED, iter->ndev))
continue;
+ if (pm != PM_OFF && dhd_conf_get_pm(dhd) >= 0)
+ pm = dhd_conf_get_pm(dhd);
if ((err = wldev_ioctl(iter->ndev, WLC_SET_PM, &pm,
sizeof(pm), true)) != 0) {
if (err == -ENODEV)
@@ -11122,6 +11737,8 @@
for_each_ndev(cfg, iter, next) {
if (!wl_get_drv_status(cfg, CONNECTED, iter->ndev))
continue;
+ if (pm != PM_OFF && dhd_conf_get_pm(dhd) >= 0)
+ pm = dhd_conf_get_pm(dhd);
if ((err = wldev_ioctl(iter->ndev, WLC_SET_PM, &pm,
sizeof(pm), true)) != 0) {
if (err == -ENODEV)
@@ -11159,6 +11776,8 @@
if (iter->pm_restore && iter->pm) {
WL_DBG(("%s:restoring power save %s\n",
iter->ndev->name, (iter->pm ? "enabled" : "disabled")));
+ if (iter->pm != PM_OFF && dhd_conf_get_pm(dhd) >= 0)
+ iter->pm = dhd_conf_get_pm(dhd);
err = wldev_ioctl(iter->ndev,
WLC_SET_PM, &iter->pm, sizeof(iter->pm), true);
if (unlikely(err)) {
@@ -11211,7 +11830,7 @@
cfg->vsdb_mode = false;
#if defined(BCMSDIO)
cfg->wlfc_on = false;
-#endif
+#endif
cfg->roamoff_on_concurrent = true;
cfg->disable_roam_event = false;
/* register interested state */
@@ -11255,7 +11874,12 @@
}
}
-#if defined(WL_ENABLE_P2P_IF) || defined(WL_NEWCFG_PRIVCMD_SUPPORT)
+#if defined(CUSTOMER_HW20) && defined(WLANAUDIO)
+struct net_device *wl0dot1_dev;
+#endif /* CUSTOMER_HW20 && WLANAUDIO */
+
+#if defined(WL_ENABLE_P2P_IF) || defined(WL_NEWCFG_PRIVCMD_SUPPORT) || \
+ defined(P2PONEINT)
static s32 wl_cfg80211_attach_p2p(void)
{
struct bcm_cfg80211 *cfg = g_bcm_cfg;
@@ -11267,9 +11891,15 @@
return -ENODEV;
}
+#if defined(CUSTOMER_HW20) && defined(WLANAUDIO)
+ wl0dot1_dev = cfg->p2p_net;
+#endif /* CUSTOMER_HW20 && WLANAUDIO */
+
return 0;
}
+#endif /* WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT || P2PONEINT */
+#if defined(WL_ENABLE_P2P_IF) || defined(WL_NEWCFG_PRIVCMD_SUPPORT)
static s32 wl_cfg80211_detach_p2p(void)
{
struct bcm_cfg80211 *cfg = g_bcm_cfg;
@@ -11329,12 +11959,23 @@
if ((err = wl_cfgp2p_init_priv(cfg)) != 0)
goto fail;
-#if defined(WL_ENABLE_P2P_IF)
+#ifdef P2PONEINT
+ if (!cfg->p2p_net) {
+ cfg->p2p_supported = true;
+
+ err = wl_cfg80211_attach_p2p();
+ if (err)
+ goto fail;
+
+ cfg->p2p_supported = true;
+ }
+#endif
+#if defined(WL_ENABLE_P2P_IF) || defined(P2PONEINT)
if (cfg->p2p_net) {
/* Update MAC addr for p2p0 interface here. */
memcpy(cfg->p2p_net->dev_addr, ndev->dev_addr, ETH_ALEN);
cfg->p2p_net->dev_addr[0] |= 0x02;
- printk("%s: p2p_dev_addr="MACDBG "\n",
+ printf("%s: p2p_dev_addr="MACDBG "\n",
cfg->p2p_net->name,
MAC2STRDBG(cfg->p2p_net->dev_addr));
} else {
@@ -11343,7 +11984,9 @@
return -ENODEV;
}
#endif /* WL_ENABLE_P2P_IF */
+#ifndef P2PONEINT
cfg->p2p_supported = true;
+#endif
} else if (ret == 0) {
if ((err = wl_cfgp2p_init_priv(cfg)) != 0)
goto fail;
@@ -11359,7 +12002,7 @@
return err;
}
-s32 wl_cfg80211_attach(struct net_device *ndev, void *context)
+s32 wl_cfg80211_attach(struct net_device *ndev, dhd_pub_t *context)
{
struct wireless_dev *wdev;
struct bcm_cfg80211 *cfg;
@@ -11434,9 +12077,11 @@
g_bcm_cfg = cfg;
#if defined(WL_ENABLE_P2P_IF) || defined(WL_NEWCFG_PRIVCMD_SUPPORT)
+#ifndef P2PONEINT
err = wl_cfg80211_attach_p2p();
if (err)
goto cfg80211_attach_out;
+#endif
#endif /* WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT */
return err;
@@ -11461,7 +12106,7 @@
#if defined(COEX_DHCP)
wl_cfg80211_btcoex_deinit();
cfg->btcoex_info = NULL;
-#endif
+#endif
wl_setup_rfkill(cfg, FALSE);
#ifdef DEBUGFS_CFG80211
@@ -11490,7 +12135,7 @@
wl_free_wdev(cfg);
#if defined(RSSIAVG)
wl_free_rssi_cache(&g_rssi_cache_ctrl);
- wl_free_rssi_cache(&g_rssi2_cache_ctrl);
+ wl_free_rssi_cache(&g_connected_rssi_cache_ctrl);
#endif
#if defined(BSSCACHE)
wl_release_bss_cache_ctrl(&g_bss_cache_ctrl);
@@ -11509,43 +12154,54 @@
}
}
-#if defined(WL_ENABLE_P2P_IF)
+#if defined(P2PONEINT) || defined(WL_ENABLE_P2P_IF)
static int wl_is_p2p_event(struct wl_event_q *e)
{
- switch (e->etype) {
- /* We have to seperate out the P2P events received
- * on primary interface so that it can be send up
- * via p2p0 interface.
- */
- case WLC_E_P2P_PROBREQ_MSG:
- case WLC_E_P2P_DISC_LISTEN_COMPLETE:
- case WLC_E_ACTION_FRAME_RX:
- case WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE:
- case WLC_E_ACTION_FRAME_COMPLETE:
+ struct bcm_cfg80211 *cfg = g_bcm_cfg;
- if (e->emsg.ifidx != 0) {
- WL_TRACE(("P2P event(%d) on virtual interface(ifidx:%d)\n",
- e->etype, e->emsg.ifidx));
- /* We are only bothered about the P2P events received
- * on primary interface. For rest of them return false
- * so that it is sent over the interface corresponding
- * to the ifidx.
- */
- return FALSE;
- } else {
+ switch (e->etype) {
+ case WLC_E_IF:
WL_TRACE(("P2P event(%d) on interface(ifidx:%d)\n",
e->etype, e->emsg.ifidx));
- return TRUE;
- }
- break;
- default:
- WL_TRACE(("NON-P2P event(%d) on interface(ifidx:%d)\n",
- e->etype, e->emsg.ifidx));
- return FALSE;
+ (void)schedule_timeout(20);
+
+ if (wl_get_p2p_status(cfg, IF_ADDING) ||
+ wl_get_p2p_status(cfg, IF_DELETING) ||
+ wl_get_p2p_status(cfg, IF_CHANGING) ||
+ wl_get_p2p_status(cfg, IF_CHANGED)) {
+ WL_TRACE(("P2P Event on Primary I/F (ifidx:%d)."
+ " Sent it to p2p0 \n", e->emsg.ifidx));
+ return TRUE;
+ } else {
+ WL_TRACE(("Event is Not p2p event return False \n"));
+ return FALSE;
+ }
+
+ case WLC_E_P2P_PROBREQ_MSG:
+ case WLC_E_P2P_DISC_LISTEN_COMPLETE:
+ case WLC_E_ACTION_FRAME_RX:
+ case WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE:
+ case WLC_E_ACTION_FRAME_COMPLETE:
+
+ if (e->emsg.ifidx != 0) {
+ WL_TRACE(("P2P event(%d) on virtual interface(ifidx:%d)\n",
+ e->etype, e->emsg.ifidx));
+ return FALSE;
+ } else {
+ WL_TRACE(("P2P event(%d) on interface(ifidx:%d)\n",
+ e->etype, e->emsg.ifidx));
+ return TRUE;
+ }
+ break;
+
+ default:
+ WL_TRACE(("NON-P2P event(%d) on interface(ifidx:%d)\n",
+ e->etype, e->emsg.ifidx));
+ return FALSE;
}
}
-#endif /* BCMDONGLEHOST && (WL_CFG80211_P2P_DEV_IF || WL_ENABLE_P2P_IF) */
+#endif
static s32 wl_event_handler(void *data)
{
@@ -11556,7 +12212,7 @@
cfg = (struct bcm_cfg80211 *)tsk->parent;
- printk("tsk Enter, tsk = 0x%p\n", tsk);
+ printf("tsk Enter, tsk = 0x%p\n", tsk);
while (down_interruptible (&tsk->sema) == 0) {
SMP_RD_BARRIER_DEPENDS();
@@ -11569,7 +12225,12 @@
* interface.
*/
#if defined(WL_CFG80211_P2P_DEV_IF)
- if (WL_IS_P2P_DEV_EVENT(e) && (cfg->p2p_wdev)) {
+#ifdef P2PONEINT
+ if ((wl_is_p2p_event(e) == TRUE) && (cfg->p2p_wdev))
+#else
+ if (WL_IS_P2P_DEV_EVENT(e) && (cfg->p2p_wdev))
+#endif
+ {
cfgdev = bcmcfg_to_p2p_wdev(cfg);
} else {
struct net_device *ndev = NULL;
@@ -11577,6 +12238,22 @@
ndev = dhd_idx2net((struct dhd_pub *)(cfg->pub), e->emsg.ifidx);
if (ndev)
cfgdev = ndev_to_wdev(ndev);
+#ifdef P2PONEINT
+ else if (e->etype == WLC_E_IF) {
+ wl_put_event(e);
+ DHD_OS_WAKE_UNLOCK(cfg->pub);
+ continue;
+ }
+
+ if (cfgdev == NULL) {
+ if (e->etype == WLC_E_IF)
+ cfgdev = bcmcfg_to_prmry_wdev(cfg);
+ else {
+ cfgdev = ndev_to_wdev(wl_to_p2p_bss_ndev(cfg,
+ P2PAPI_BSSCFG_CONNECTION));
+ }
+ }
+#endif
}
#elif defined(WL_ENABLE_P2P_IF)
// terence 20150116: fix for p2p connection in kernel 3.4
@@ -11592,7 +12269,7 @@
if (!cfgdev) {
#if defined(WL_CFG80211_P2P_DEV_IF)
cfgdev = bcmcfg_to_prmry_wdev(cfg);
-#elif defined(WL_ENABLE_P2P_IF)
+#else
cfgdev = bcmcfg_to_prmry_ndev(cfg);
#endif /* WL_CFG80211_P2P_DEV_IF */
}
@@ -11605,7 +12282,7 @@
}
DHD_OS_WAKE_UNLOCK(cfg->pub);
}
- printk("%s: was terminated\n", __FUNCTION__);
+ printf("%s: was terminated\n", __FUNCTION__);
complete_and_exit(&tsk->completed, 0);
return 0;
}
@@ -11955,6 +12632,8 @@
index = j;
else
index = *n_cnt;
+ if (!dhd_conf_match_channel(cfg->pub, channel))
+ continue;
if (index < array_size) {
#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS)
band_chan_arr[index].center_freq =
@@ -11964,6 +12643,7 @@
ieee80211_channel_to_frequency(channel, band);
#endif
band_chan_arr[index].hw_value = channel;
+ WL_DBG(("channel = %d\n", channel));
if (CHSPEC_IS40(c) && ht40_allowed) {
/* assuming the order is HT20, HT40 Upper,
@@ -12211,7 +12891,7 @@
#ifdef PROP_TXSTATUS_VSDB
#if defined(BCMSDIO)
dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
-#endif
+#endif
#endif /* PROP_TXSTATUS_VSDB */
WL_DBG(("In\n"));
/* Delete pm_enable_work */
@@ -12234,7 +12914,7 @@
cfg->wlfc_on = false;
}
}
-#endif
+#endif
#endif /* PROP_TXSTATUS_VSDB */
}
@@ -12690,6 +13370,21 @@
return wl_cfgp2p_set_p2p_ps(cfg, net, buf, len);
}
+#ifdef P2PLISTEN_AP_SAMECHN
+s32 wl_cfg80211_set_p2p_resp_ap_chn(struct net_device *net, s32 enable)
+{
+ s32 ret = wldev_iovar_setint(net, "p2p_resp_ap_chn", enable);
+
+ if ((ret == 0) && enable) {
+ /* disable PM for p2p responding on infra AP channel */
+ s32 pm = PM_OFF;
+
+ ret = wldev_ioctl(net, WLC_SET_PM, &pm, sizeof(pm), true);
+ }
+
+ return ret;
+}
+#endif /* P2PLISTEN_AP_SAMECHN */
s32 wl_cfg80211_channel_to_freq(u32 channel)
{
@@ -12774,6 +13469,10 @@
#if defined(RSSIOFFSET)
info.rssi = wl_update_rssi_offset(ndev, info.rssi);
#endif
+#if !defined(RSSIAVG) && !defined(RSSIOFFSET)
+ // terence 20150419: limit the max. rssi to -2 or the bss will be filtered out in android OS
+ info.rssi = MIN(info.rssi, RSSI_MAXVAL);
+#endif
memcpy(info.bssid, &bi->BSSID, ETH_ALEN);
info.ie_len = buflen;
@@ -13578,12 +14277,36 @@
#ifdef PCIE_FULL_DONGLE
dhd_tdls_update_peer_info(ndev, TRUE, (uint8 *)&e->addr.octet[0]);
#endif /* PCIE_FULL_DONGLE */
+ if (cfg->tdls_mgmt_frame) {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
+ cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq, 0,
+ cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len, 0);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
+ cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq, 0,
+ cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len,
+ 0, GFP_ATOMIC);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
+ defined(WL_COMPAT_WIRELESS)
+ cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq, 0,
+ cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len,
+ GFP_ATOMIC);
+#else
+ cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq,
+ cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len,
+ GFP_ATOMIC);
+#endif /* LINUX_VERSION >= VERSION(3, 12, 0) */
+ }
msg = " TDLS PEER CONNECTED ";
break;
case WLC_E_TDLS_PEER_DISCONNECTED :
#ifdef PCIE_FULL_DONGLE
dhd_tdls_update_peer_info(ndev, FALSE, (uint8 *)&e->addr.octet[0]);
#endif /* PCIE_FULL_DONGLE */
+ if (cfg->tdls_mgmt_frame) {
+ kfree(cfg->tdls_mgmt_frame);
+ cfg->tdls_mgmt_frame = NULL;
+ cfg->tdls_mgmt_freq = 0;
+ }
msg = "TDLS PEER DISCONNECTED ";
break;
}
@@ -13594,10 +14317,65 @@
return 0;
}
-#endif /* WLTDLS */
+#endif /* WLTDLS */
#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)
static s32
+#if defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2)
+wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
+ u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
+ u32 peer_capability, const u8 *data, size_t len)
+#else
+wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
+ u8 *peer, u8 action_code, u8 dialog_token, u16 status_code, const u8 *data,
+ size_t len)
+#endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
+{
+ s32 ret = 0;
+#ifdef WLTDLS
+ struct bcm_cfg80211 *cfg;
+ tdls_wfd_ie_iovar_t info;
+ memset(&info, 0, sizeof(tdls_wfd_ie_iovar_t));
+ cfg = g_bcm_cfg;
+
+#if defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2)
+ /* Some customer platform back ported this feature from kernel 3.15 to kernel 3.10
+ * and that cuases build error
+ */
+ BCM_REFERENCE(peer_capability);
+#endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
+
+ switch (action_code) {
+ /* We need to set TDLS Wifi Display IE to firmware
+ * using tdls_wfd_ie iovar
+ */
+ case WLAN_TDLS_SET_PROBE_WFD_IE:
+ info.mode = TDLS_WFD_PROBE_IE_TX;
+ memcpy(&info.data, data, len);
+ info.length = len;
+ break;
+ case WLAN_TDLS_SET_SETUP_WFD_IE:
+ info.mode = TDLS_WFD_IE_TX;
+ memcpy(&info.data, data, len);
+ info.length = len;
+ break;
+ default:
+ WL_ERR(("Unsupported action code : %d\n", action_code));
+ goto out;
+ }
+
+ ret = wldev_iovar_setbuf(dev, "tdls_wfd_ie", &info, sizeof(info),
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
+
+ if (ret) {
+ WL_ERR(("tdls_wfd_ie error %d\n", ret));
+ }
+out:
+#endif /* WLTDLS */
+ return ret;
+}
+
+static s32
wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
u8 *peer, enum nl80211_tdls_operation oper)
{
@@ -13615,7 +14393,15 @@
ret = dhd_tdls_enable(dev, true, false, NULL);
if (ret < 0)
return ret;
- info.mode = TDLS_MANUAL_EP_DISCOVERY;
+ /* If the discovery request is broadcast then we need to set
+ * info.mode to Tunneled Probe Request
+ */
+ if (memcmp(peer, (const uint8 *)BSSID_BROADCAST, ETHER_ADDR_LEN) == 0) {
+ info.mode = TDLS_MANUAL_EP_WFD_TPQ;
+ }
+ else {
+ info.mode = TDLS_MANUAL_EP_DISCOVERY;
+ }
break;
case NL80211_TDLS_SETUP:
/* auto mode on */
@@ -14131,7 +14917,7 @@
uint i, tokens, log_on = 0;
memset(tbuf, 0, sizeof(tbuf));
memset(sublog, 0, sizeof(sublog));
- if (copy_from_user(&tbuf, userbuf, min_t(size_t, sizeof(tbuf), count)))
+ if (copy_from_user(&tbuf, userbuf, min_t(size_t, (sizeof(tbuf) - 1), count)))
return -EFAULT;
params = &tbuf[0];
@@ -14278,8 +15064,10 @@
if (!cfg || !cfg->wdev)
return -EINVAL;
+#if !defined(P2PONEINT)
if (dhd_do_driver_init(cfg->wdev->netdev) < 0)
return -1;
+#endif /* BCMDONGLEHOST */
return 0;
}
@@ -14287,7 +15075,7 @@
void wl_cfg80211_enable_trace(u32 level)
{
wl_dbg_level = level;
- printk("%s: wl_dbg_level = 0x%x\n", __FUNCTION__, wl_dbg_level);
+ printf("%s: wl_dbg_level = 0x%x\n", __FUNCTION__, wl_dbg_level);
}
#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \
@@ -14558,6 +15346,7 @@
struct net_info *iter, *next;
s32 err = BCME_OK;
s32 pm = PM_FAST;
+ dhd_pub_t *dhd;
cfg = container_of(work, struct bcm_cfg80211, pm_enable_work.work);
WL_DBG(("Enter \n"));
@@ -14568,6 +15357,9 @@
(wl_get_mode_by_netdev(cfg, iter->ndev) != WL_MODE_BSS))
continue;
if (iter->ndev) {
+ dhd = (dhd_pub_t *)(cfg->pub);
+ if (pm != PM_OFF && dhd_conf_get_pm(dhd) >= 0)
+ pm = dhd_conf_get_pm(dhd);
if ((err = wldev_ioctl(iter->ndev, WLC_SET_PM,
&pm, sizeof(pm), true)) != 0) {
if (err == -ENODEV)
@@ -14633,7 +15425,7 @@
wl_event_msg_t e;
bzero(&e, sizeof(e));
- e.event_type = cpu_to_be32(WLC_E_ROAM);
+ e.event_type = cpu_to_be32(WLC_E_BSSID);
memcpy(&e.addr, bssid, ETHER_ADDR_LEN);
/* trigger the roam event handler */
err = wl_notify_roaming_status(cfg, ndev_to_cfgdev(ndev), &e, NULL);
diff -Nur a/drivers/net/wireless/bcmdhd/wl_cfg80211.h c/drivers/net/wireless/bcmdhd/wl_cfg80211.h
--- a/drivers/net/wireless/bcmdhd/wl_cfg80211.h 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/wl_cfg80211.h 2016-05-13 09:48:20.000000000 +0200
@@ -3,7 +3,7 @@
*
* $Copyright Open Broadcom Corporation$
*
- * $Id: wl_cfg80211.h 491407 2014-07-16 09:23:04Z $
+ * $Id: wl_cfg80211.h 505096 2014-09-26 12:49:04Z $
*/
/**
@@ -21,6 +21,8 @@
#include <net/cfg80211.h>
#include <linux/rfkill.h>
+#include <dngl_stats.h>
+#include <dhd.h>
#include <wl_cfgp2p.h>
struct wl_conf;
@@ -50,6 +52,12 @@
#define CFG80211_ERROR_TEXT "CFG80211-ERROR) "
+#define MAX_WAIT_TIME 1500
+#define DNGL_FUNC(func, parameters) func parameters;
+
+#define PM_BLOCK 1
+#define PM_ENABLE 0
+
#if defined(DHD_DEBUG)
#define WL_ERR(args) \
do { \
@@ -394,6 +402,15 @@
struct net_device *ndev;
};
+#ifdef ESCAN_BUF_OVERFLOW_MGMT
+#define BUF_OVERFLOW_MGMT_COUNT 3
+typedef struct {
+ int RSSI;
+ int length;
+ struct ether_addr BSSID;
+} removal_element_t;
+#endif /* ESCAN_BUF_OVERFLOW_MGMT */
+
struct ap_info {
/* Structure to hold WPS, WPA IEs for a AP */
u8 probe_res_ie[VNDR_IES_MAX_BUF_LEN];
@@ -550,7 +567,7 @@
#endif /* DEBUGFS_CFG80211 */
struct wl_pmk_list *pmk_list; /* wpa2 pmk list */
tsk_ctl_t event_tsk; /* task of main event handler thread */
- void *pub;
+ dhd_pub_t *pub;
u32 iface_cnt;
u32 channel; /* current channel */
u32 af_sent_channel; /* channel action frame is sent */
@@ -570,7 +587,7 @@
bool scan_tried; /* indicates if first scan attempted */
#if defined(BCMSDIO) || defined(BCMPCIE)
bool wlfc_on;
-#endif
+#endif
bool vsdb_mode;
bool roamoff_on_concurrent;
u8 *ioctl_buf; /* ioctl buffer */
@@ -638,8 +655,18 @@
#ifdef WLFBT
uint8 fbt_key[FBT_KEYLEN];
#endif
- bool roam_offload;
+ int roam_offload;
bool nan_running;
+#ifdef P2PLISTEN_AP_SAMECHN
+ bool p2p_resp_apchn_status;
+#endif /* P2PLISTEN_AP_SAMECHN */
+#ifdef WLTDLS
+ u8 *tdls_mgmt_frame;
+ u32 tdls_mgmt_frame_len;
+ s32 tdls_mgmt_freq;
+#endif /* WLTDLS */
+ int p2p_disconnected; // terence 20130703: Fix for wrong group_capab (timing issue)
+ struct ether_addr disconnected_bssid;
};
@@ -910,7 +937,7 @@
((wl_cfgp2p_find_wpsie((u8 *)_sme->ie, _sme->ie_len) != NULL) && \
(!_sme->crypto.n_ciphers_pairwise) && \
(!_sme->crypto.cipher_group))
-extern s32 wl_cfg80211_attach(struct net_device *ndev, void *context);
+extern s32 wl_cfg80211_attach(struct net_device *ndev, dhd_pub_t *context);
extern s32 wl_cfg80211_attach_post(struct net_device *ndev);
extern void wl_cfg80211_detach(void *para);
@@ -939,6 +966,9 @@
extern s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf, int len,
enum wl_management_type type);
extern s32 wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len);
+#ifdef P2PLISTEN_AP_SAMECHN
+extern s32 wl_cfg80211_set_p2p_resp_ap_chn(struct net_device *net, s32 enable);
+#endif /* P2PLISTEN_AP_SAMECHN */
/* btcoex functions */
void* wl_cfg80211_btcoex_init(struct net_device *ndev);
@@ -1036,11 +1066,15 @@
#endif /* WL_SUPPORT_ACS */
extern int wl_cfg80211_get_ioctl_version(void);
-extern int wl_cfg80211_enable_roam_offload(struct net_device *dev, bool enable);
+extern int wl_cfg80211_enable_roam_offload(struct net_device *dev, int enable);
#ifdef WL_NAN
extern int wl_cfg80211_nan_cmd_handler(struct net_device *ndev, char *cmd,
int cmd_len);
#endif /* WL_NAN */
-#endif /* _wl_cfg80211_h_ */
+#ifdef WL_CFG80211_P2P_DEV_IF
+extern void wl_cfg80211_del_p2p_wdev(void);
+#endif /* WL_CFG80211_P2P_DEV_IF */
+
+#endif /* _wl_cfg80211_h_ */
diff -Nur a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c c/drivers/net/wireless/bcmdhd/wl_cfgp2p.c
--- a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/wl_cfgp2p.c 2016-05-13 09:48:20.000000000 +0200
@@ -3,7 +3,7 @@
*
* $Copyright Open Broadcom Corporation$
*
- * $Id: wl_cfgp2p.c 490694 2014-07-11 14:37:00Z $
+ * $Id: wl_cfgp2p.c 504573 2014-09-24 15:21:25Z $
*
*/
#include <typedefs.h>
@@ -30,6 +30,11 @@
#include <wldev_common.h>
#include <wl_android.h>
+#if defined(P2PONEINT)
+#include <dngl_stats.h>
+#include <dhd.h>
+#endif
+
static s8 scanparambuf[WLC_IOCTL_SMLEN];
static s8 g_mgmt_ie_buf[2048];
static bool
@@ -41,17 +46,27 @@
static s32 wl_cfgp2p_cancel_listen(struct bcm_cfg80211 *cfg, struct net_device *ndev,
struct wireless_dev *wdev, bool notify);
+#ifdef P2PONEINT
+void wl_cfg80211_scan_abort(struct bcm_cfg80211 *cfg);
+chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy);
+s32 dhd_cfg80211_set_p2p_info(struct bcm_cfg80211 *cfg, int val);
+int wl_cfgp2p_if_open(struct net_device *net);
+int wl_cfgp2p_if_stop(struct net_device *net);
+#endif
+
#if defined(WL_ENABLE_P2P_IF)
static int wl_cfgp2p_start_xmit(struct sk_buff *skb, struct net_device *ndev);
static int wl_cfgp2p_do_ioctl(struct net_device *net, struct ifreq *ifr, int cmd);
-static int wl_cfgp2p_if_open(struct net_device *net);
-static int wl_cfgp2p_if_stop(struct net_device *net);
+int wl_cfgp2p_if_open(struct net_device *net);
+int wl_cfgp2p_if_stop(struct net_device *net);
static const struct net_device_ops wl_cfgp2p_if_ops = {
.ndo_open = wl_cfgp2p_if_open,
.ndo_stop = wl_cfgp2p_if_stop,
.ndo_do_ioctl = wl_cfgp2p_do_ioctl,
+#ifndef P2PONEINT
.ndo_start_xmit = wl_cfgp2p_start_xmit,
+#endif
};
#endif /* WL_ENABLE_P2P_IF */
@@ -559,6 +574,38 @@
return BCME_NOTFOUND;
}
+#ifdef P2PLISTEN_AP_SAMECHN
+ CFGP2P_DBG(("p2p0 listen channel %d AP connection chan %d \n",
+ channel, cfg->channel));
+ if ((mode == WL_P2P_DISC_ST_LISTEN) && (cfg->channel == channel)) {
+ struct net_device *primary_ndev = bcmcfg_to_prmry_ndev(cfg);
+
+ if (cfg->p2p_resp_apchn_status) {
+ CFGP2P_DBG(("p2p_resp_apchn_status already ON \n"));
+ return BCME_OK;
+ }
+
+ if (wl_get_drv_status(cfg, CONNECTED, primary_ndev)) {
+ ret = wl_cfg80211_set_p2p_resp_ap_chn(primary_ndev, 1);
+ cfg->p2p_resp_apchn_status = true;
+ CFGP2P_DBG(("p2p_resp_apchn_status ON \n"));
+ return ret;
+ }
+ }
+#endif /* P2PLISTEN_AP_SAMECHN */
+
+#if defined(CUSTOM_PLATFORM_NV_TEGRA)
+#if defined(P2P_DISCOVERY_WAR)
+ if (mode == WL_P2P_DISC_ST_LISTEN || mode == WL_P2P_DISC_ST_SEARCH) {
+ if (!cfg->p2p->vif_created) {
+ if (wldev_iovar_setint(wl_to_prmry_ndev(cfg), "mpc", 0) < 0) {
+ WL_ERR(("mpc disabling failed\n"));
+ }
+ }
+ }
+#endif /* defined(P2P_DISCOVERY_WAR) */
+#endif /* defined(CUSTOM_PLATFORM_NV_TEGRA) */
+
/* Put the WL driver into P2P Listen Mode to respond to P2P probe reqs */
discovery_mode.state = mode;
discovery_mode.chspec = wl_ch_host_to_driver(channel);
@@ -641,7 +688,7 @@
s32 ret = BCME_OK;
CFGP2P_DBG(("enter\n"));
- if (wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) == 0) {
+ if (wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) <= 0) {
CFGP2P_ERR(("do nothing, not initialized\n"));
return -1;
}
@@ -736,7 +783,7 @@
CFGP2P_DBG((" enter\n"));
wl_clr_p2p_status(cfg, DISCOVERY_ON);
- if(!cfg->p2p) { // terence 20130113: Fix for p2p NULL pointer
+ if (!cfg->p2p) { // terence 20130113: Fix for p2p NULL pointer
ret = BCME_ERROR;
CFGP2P_ERR(("wl->p2p is NULL\n"));
goto exit;
@@ -1066,7 +1113,7 @@
CFGP2P_DBG((" bssidx %d, pktflag : 0x%02X\n", bssidx, pktflag));
#ifdef DUAL_STA
- if ((cfg->p2p != NULL) && (bssidx != cfg->cfgdev_bssidx))
+ if ((cfg->p2p != NULL) && ((bssidx == 0) || (bssidx != cfg->cfgdev_bssidx)))
#else
if (cfg->p2p != NULL)
#endif
@@ -1109,6 +1156,11 @@
return BCME_ERROR;
}
} else if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP) {
+ if (cfg->ap_info == NULL) {
+ CFGP2P_ERR(("hostapd ap_info null ptr refrence while setting IE\n"));
+ return BCME_ERROR;
+
+ }
switch (pktflag) {
case VNDR_IE_PRBRSP_FLAG :
mgmt_ie_buf = cfg->ap_info->probe_res_ie;
@@ -1560,6 +1612,16 @@
ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
+#if defined(CUSTOM_PLATFORM_NV_TEGRA)
+#if defined(P2P_DISCOVERY_WAR)
+ if (!cfg->p2p->vif_created) {
+ if (wldev_iovar_setint(ndev, "mpc", 1) < 0) {
+ WL_ERR(("mpc enabling back failed\n"));
+ }
+ }
+#endif /* defined(P2P_DISCOVERY_WAR) */
+#endif /* defined(CUSTOM_PLATFORM_NV_TEGRA) */
+
if (wl_get_p2p_status(cfg, LISTEN_EXPIRED) == 0) {
wl_set_p2p_status(cfg, LISTEN_EXPIRED);
if (timer_pending(&cfg->p2p->listen_timer)) {
@@ -1591,17 +1653,24 @@
wl_get_drv_status_all(cfg, FAKE_REMAINING_ON_CHANNEL))
#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
{
- WL_DBG(("Listen DONE for ramain on channel expired\n"));
+ WL_DBG(("Listen DONE for remain on channel expired\n"));
wl_clr_drv_status(cfg, REMAINING_ON_CHANNEL, ndev);
#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
wl_clr_drv_status(cfg, FAKE_REMAINING_ON_CHANNEL, ndev);
#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
if (ndev && (ndev->ieee80211_ptr != NULL)) {
#if defined(WL_CFG80211_P2P_DEV_IF)
- // terence 20141221: Fix p2p connection issue in both p2p device in Android 5.0
- // error log: CFG80211-ERROR) wl_cfg80211_send_action_frame : couldn't find peer's channel.
- cfg80211_remain_on_channel_expired(bcmcfg_to_p2p_wdev(cfg),
- cfg->last_roc_id, &cfg->remain_on_chan, GFP_KERNEL);
+ if (cfgdev && ((struct wireless_dev *)cfgdev)->wiphy) {
+ /*
+ * To prevent kernel panic,
+ * if cfgdev->wiphy may be invalid, adding explicit check
+ */
+ cfg80211_remain_on_channel_expired(cfgdev, cfg->last_roc_id,
+ &cfg->remain_on_chan, GFP_KERNEL);
+ } else {
+ CFGP2P_ERR(("Invalid cfgdev. Dropping the"
+ "remain_on_channel_expired event.\n"));
+ }
#else
cfg80211_remain_on_channel_expired(cfgdev, cfg->last_roc_id,
&cfg->remain_on_chan, cfg->remain_on_chan_type, GFP_KERNEL);
@@ -1655,9 +1724,11 @@
del_timer_sync(&cfg->p2p->listen_timer);
if (notify) {
#if defined(WL_CFG80211_P2P_DEV_IF)
+#ifdef P2PONEINT
+ if (wdev == NULL)
+ wdev = bcmcfg_to_p2p_wdev(cfg);
+#endif
if (wdev)
- // terence 20141221: Fix p2p connection issue in both p2p device in Android 5.0
- // error log: CFG80211-ERROR) wl_cfg80211_send_action_frame : couldn't find peer's channel.
cfg80211_remain_on_channel_expired(bcmcfg_to_p2p_wdev(cfg),
cfg->last_roc_id, &cfg->remain_on_chan, GFP_KERNEL);
#else
@@ -1898,7 +1969,9 @@
* different from the P2P Device Address.
*/
memcpy(out_int_addr, out_dev_addr, sizeof(*out_int_addr));
+#ifndef P2PONEINT
out_int_addr->octet[4] ^= 0x80;
+#endif
}
@@ -2043,8 +2116,12 @@
s32 i = 0, index = -1;
#if defined(WL_CFG80211_P2P_DEV_IF)
- ndev = bcmcfg_to_prmry_ndev(cfg);
wdev = bcmcfg_to_p2p_wdev(cfg);
+#ifdef P2PONEINT
+ ndev = wdev_to_ndev(wdev);
+#else
+ ndev = bcmcfg_to_prmry_ndev(cfg);
+#endif
#elif defined(WL_ENABLE_P2P_IF)
ndev = cfg->p2p_net ? cfg->p2p_net : bcmcfg_to_prmry_ndev(cfg);
wdev = ndev_to_wdev(ndev);
@@ -2357,7 +2434,153 @@
};
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */
-#if defined(WL_ENABLE_P2P_IF) || defined(WL_NEWCFG_PRIVCMD_SUPPORT)
+#if defined(WL_ENABLE_P2P_IF) || defined(WL_NEWCFG_PRIVCMD_SUPPORT) || \
+ defined(P2PONEINT)
+#ifdef P2PONEINT
+s32
+wl_cfgp2p_register_ndev(struct bcm_cfg80211 *cfg)
+{
+
+ struct net_device *_ndev;
+ struct ether_addr primary_mac;
+ struct net_device *new_ndev;
+ chanspec_t chspec;
+ uint8 name[IFNAMSIZ];
+ s32 mode = 0;
+ s32 val = 0;
+
+
+ s32 wlif_type = -1;
+ s32 err, timeout = -1;
+
+ memset(name, 0, IFNAMSIZ);
+ strncpy(name, "p2p0", 4);
+ name[IFNAMSIZ - 1] = '\0';
+
+ if (cfg->p2p_net) {
+ CFGP2P_ERR(("p2p_net defined already.\n"));
+ return -EINVAL;
+ }
+
+ if (!cfg->p2p)
+ return -EINVAL;
+
+ if (cfg->p2p && !cfg->p2p->on && strstr(name, WL_P2P_INTERFACE_PREFIX)) {
+ p2p_on(cfg) = true;
+ wl_cfgp2p_set_firm_p2p(cfg);
+ wl_cfgp2p_init_discovery(cfg);
+ get_primary_mac(cfg, &primary_mac);
+ wl_cfgp2p_generate_bss_mac(&primary_mac,
+ &cfg->p2p->dev_addr, &cfg->p2p->int_addr);
+ }
+
+ _ndev = bcmcfg_to_prmry_ndev(cfg);
+ memset(cfg->p2p->vir_ifname, 0, IFNAMSIZ);
+ strncpy(cfg->p2p->vir_ifname, name, IFNAMSIZ - 1);
+
+ wl_cfg80211_scan_abort(cfg);
+
+
+ /* In concurrency case, STA may be already associated in a particular channel.
+ * so retrieve the current channel of primary interface and then start the virtual
+ * interface on that.
+ */
+ chspec = wl_cfg80211_get_shared_freq(cfg->wdev->wiphy);
+
+ /* For P2P mode, use P2P-specific driver features to create the
+ * bss: "cfg p2p_ifadd"
+ */
+ wl_set_p2p_status(cfg, IF_ADDING);
+ memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info));
+ wlif_type = WL_P2P_IF_CLIENT;
+
+
+ err = wl_cfgp2p_ifadd(cfg, &cfg->p2p->int_addr, htod32(wlif_type), chspec);
+ if (unlikely(err)) {
+ wl_clr_p2p_status(cfg, IF_ADDING);
+ WL_ERR((" virtual iface add failed (%d) \n", err));
+ return -ENOMEM;
+ }
+
+ timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
+ (wl_get_p2p_status(cfg, IF_ADDING) == false),
+ msecs_to_jiffies(MAX_WAIT_TIME));
+
+
+ if (timeout > 0 && !wl_get_p2p_status(cfg, IF_ADDING) && cfg->if_event_info.valid) {
+ struct wireless_dev *vwdev;
+ int pm_mode = PM_ENABLE;
+ wl_if_event_info *event = &cfg->if_event_info;
+
+ /* IF_ADD event has come back, we can proceed to to register
+ * the new interface now, use the interface name provided by caller (thus
+ * ignore the one from wlc)
+ */
+ strncpy(cfg->if_event_info.name, name, IFNAMSIZ - 1);
+ new_ndev = wl_cfg80211_allocate_if(cfg, event->ifidx, cfg->p2p->vir_ifname,
+ event->mac, event->bssidx);
+ if (new_ndev == NULL)
+ goto fail;
+
+ wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION) = new_ndev;
+ wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_CONNECTION) = event->bssidx;
+
+ vwdev = kzalloc(sizeof(*vwdev), GFP_KERNEL);
+ if (unlikely(!vwdev)) {
+ WL_ERR(("Could not allocate wireless device\n"));
+ goto fail;
+ }
+ vwdev->wiphy = cfg->wdev->wiphy;
+ WL_TRACE(("virtual interface(%s) is created\n", cfg->p2p->vir_ifname));
+ vwdev->iftype = NL80211_IFTYPE_P2P_DEVICE;
+ vwdev->netdev = new_ndev;
+ new_ndev->ieee80211_ptr = vwdev;
+ SET_NETDEV_DEV(new_ndev, wiphy_dev(vwdev->wiphy));
+ wl_set_drv_status(cfg, READY, new_ndev);
+ cfg->p2p->vif_created = true;
+ wl_set_mode_by_netdev(cfg, new_ndev, mode);
+
+ if (wl_cfg80211_register_if(cfg, event->ifidx, new_ndev) != BCME_OK) {
+ wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev);
+ goto fail;
+ }
+
+ wl_alloc_netinfo(cfg, new_ndev, vwdev, mode, pm_mode);
+ val = 1;
+ /* Disable firmware roaming for P2P interface */
+ wldev_iovar_setint(new_ndev, "roam_off", val);
+
+ if (mode != WL_MODE_AP)
+ wldev_iovar_setint(new_ndev, "buf_key_b4_m4", 1);
+
+ WL_ERR((" virtual interface(%s) is "
+ "created net attach done\n", cfg->p2p->vir_ifname));
+
+ /* reinitialize completion to clear previous count */
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
+ INIT_COMPLETION(cfg->iface_disable);
+#else
+ init_completion(&cfg->iface_disable);
+#endif
+ cfg->p2p_net = new_ndev;
+ cfg->p2p_wdev = vwdev;
+
+ return 0;
+ } else {
+ wl_clr_p2p_status(cfg, IF_ADDING);
+ WL_ERR((" virtual interface(%s) is not created \n", cfg->p2p->vir_ifname));
+ memset(cfg->p2p->vir_ifname, '\0', IFNAMSIZ);
+ cfg->p2p->vif_created = false;
+ }
+
+
+fail:
+ if (wlif_type == WL_P2P_IF_GO)
+ wldev_iovar_setint(_ndev, "mpc", 1);
+ return -ENODEV;
+
+}
+#else
s32
wl_cfgp2p_register_ndev(struct bcm_cfg80211 *cfg)
{
@@ -2445,10 +2668,11 @@
#endif /* WL_NEWCFG_PRIVCMD_SUPPORT */
cfg->p2p_net = net;
- printk("%s: P2P Interface Registered\n", net->name);
+ printf("%s: P2P Interface Registered\n", net->name);
return ret;
}
+#endif /* P2PONEINT */
s32
wl_cfgp2p_unregister_ndev(struct bcm_cfg80211 *cfg)
@@ -2465,6 +2689,7 @@
return 0;
}
+#ifndef P2PONEINT
static int wl_cfgp2p_start_xmit(struct sk_buff *skb, struct net_device *ndev)
{
@@ -2499,10 +2724,16 @@
return ret;
}
-#endif /* WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT */
+#endif /* P2PONEINT */
+#endif /* WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT || defined(P2PONEINT) */
-#if defined(WL_ENABLE_P2P_IF)
-static int wl_cfgp2p_if_open(struct net_device *net)
+#if defined(WL_ENABLE_P2P_IF) || defined(P2PONEINT)
+int
+#ifdef P2PONEINT
+wl_cfgp2p_if_open(struct net_device *net)
+#else
+wl_cfgp2p_if_open(struct net_device *net)
+#endif
{
struct wireless_dev *wdev = net->ieee80211_ptr;
@@ -2524,14 +2755,26 @@
return 0;
}
-static int wl_cfgp2p_if_stop(struct net_device *net)
+int
+#ifdef P2PONEINT
+wl_cfgp2p_if_stop(struct net_device *net)
+#else
+wl_cfgp2p_if_stop(struct net_device *net)
+#endif
{
struct wireless_dev *wdev = net->ieee80211_ptr;
-
+#ifdef P2PONEINT
+ bcm_struct_cfgdev *cfgdev;
+#endif
if (!wdev)
return -EINVAL;
+#ifdef P2PONEINT
+ cfgdev = ndev_to_cfgdev(net);
+ wl_cfg80211_scan_stop(cfgdev);
+#else
wl_cfg80211_scan_stop(net);
+#endif
#if !defined(WL_IFACE_COMB_NUM_CHANNELS)
wdev->wiphy->interface_modes = (wdev->wiphy->interface_modes)
@@ -2540,7 +2783,9 @@
#endif /* !WL_IFACE_COMB_NUM_CHANNELS */
return 0;
}
+#endif /* defined(WL_ENABLE_P2P_IF) || defined(P2PONEINT) */
+#if defined(WL_ENABLE_P2P_IF)
bool wl_cfgp2p_is_ifops(const struct net_device_ops *if_ops)
{
return (if_ops == &wl_cfgp2p_if_ops);
@@ -2554,7 +2799,7 @@
struct wireless_dev *wdev = NULL;
struct ether_addr primary_mac;
- if (!cfg)
+ if (!cfg || !cfg->p2p_supported)
return ERR_PTR(-EINVAL);
WL_TRACE(("Enter\n"));
@@ -2566,7 +2811,7 @@
CFGP2P_ERR(("p2p_wdev deleted.\n"));
#else
return ERR_PTR(-ENFILE);
-#endif
+#endif
}
wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
@@ -2592,7 +2837,7 @@
/* store p2p wdev ptr for further reference. */
cfg->p2p_wdev = wdev;
- WL_TRACE(("P2P interface registered\n"));
+ printf("P2P interface registered\n");
return wdev;
}
@@ -2622,7 +2867,7 @@
p2p_on(cfg) = true;
- CFGP2P_DBG(("P2P interface started\n"));
+ printf("P2P interface started\n");
exit:
return ret;
@@ -2654,7 +2899,7 @@
p2p_on(cfg) = false;
- CFGP2P_DBG(("P2P interface stopped\n"));
+ printf("P2P interface stopped\n");
return;
}
@@ -2667,6 +2912,10 @@
if (!wdev)
return -EINVAL;
+#ifdef P2PONEINT
+ return -EINVAL;
+#endif
+
WL_TRACE(("Enter\n"));
if (!rtnl_is_locked()) {
@@ -2684,7 +2933,7 @@
if (cfg)
cfg->p2p_wdev = NULL;
- CFGP2P_ERR(("P2P interface unregistered\n"));
+ printf("P2P interface unregistered\n");
return 0;
}
diff -Nur a/drivers/net/wireless/bcmdhd/wl_cfgp2p.h c/drivers/net/wireless/bcmdhd/wl_cfgp2p.h
--- a/drivers/net/wireless/bcmdhd/wl_cfgp2p.h 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/wl_cfgp2p.h 2016-05-13 09:48:20.000000000 +0200
@@ -3,7 +3,7 @@
*
* $Copyright Open Broadcom Corporation$
*
- * $Id: wl_cfgp2p.h 472818 2014-04-25 08:07:56Z $
+ * $Id: wl_cfgp2p.h 497431 2014-08-19 11:03:27Z $
*/
#ifndef _wl_cfgp2p_h_
#define _wl_cfgp2p_h_
@@ -56,7 +56,7 @@
};
struct p2p_bss {
- u32 bssidx;
+ s32 bssidx;
struct net_device *dev;
struct p2p_saved_ie saved_ie;
void *private_data;
diff -Nur a/drivers/net/wireless/bcmdhd/wl_cfgvendor.h c/drivers/net/wireless/bcmdhd/wl_cfgvendor.h
--- a/drivers/net/wireless/bcmdhd/wl_cfgvendor.h 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/wl_cfgvendor.h 2016-05-13 09:48:20.000000000 +0200
@@ -6,10 +6,6 @@
* $Id: wl_cfgvendor.h 455257 2014-02-20 08:10:24Z $
*/
-/*
- * New vendor interface additon to nl80211/cfg80211 to allow vendors
- * to implement proprietary features over the cfg80211 stack.
- */
#ifndef _wl_cfgvendor_h_
#define _wl_cfgvendor_h_
diff -Nur a/drivers/net/wireless/bcmdhd/wl_dbg.h c/drivers/net/wireless/bcmdhd/wl_dbg.h
--- a/drivers/net/wireless/bcmdhd/wl_dbg.h 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/wl_dbg.h 2016-05-13 09:48:20.000000000 +0200
@@ -385,7 +385,7 @@
#endif
#define WL_PCIE(args) do {if (wl_msg_level2 & WL_PCIE_VAL) WL_PRINT(args);} while (0)
#define WL_PCIE_ON() (wl_msg_level2 & WL_PCIE_VAL)
-#endif
+#endif
extern uint32 wl_msg_level;
extern uint32 wl_msg_level2;
diff -Nur a/drivers/net/wireless/bcmdhd/wldev_common.c c/drivers/net/wireless/bcmdhd/wldev_common.c
--- a/drivers/net/wireless/bcmdhd/wldev_common.c 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/wldev_common.c 2016-05-13 09:48:20.000000000 +0200
@@ -3,7 +3,7 @@
*
* $Copyright Open Broadcom Corporation$
*
- * $Id: wldev_common.c 467328 2014-04-03 01:23:40Z $
+ * $Id: wldev_common.c 504503 2014-09-24 11:28:56Z $
*/
#include <osl.h>
@@ -352,7 +352,9 @@
cspec.rev = -1;
memcpy(cspec.country_abbrev, country_code, WLC_CNTRY_BUF_SZ);
memcpy(cspec.ccode, country_code, WLC_CNTRY_BUF_SZ);
- dhd_get_customized_country_code(dev, (char *)&cspec.country_abbrev, &cspec);
+ error = dhd_conf_get_country_from_config(dhd_get_pub(dev), &cspec);
+ if (error)
+ dhd_get_customized_country_code(dev, (char *)&cspec.country_abbrev, &cspec);
error = wldev_iovar_setbuf(dev, "country", &cspec, sizeof(cspec),
smbuf, sizeof(smbuf), NULL);
if (error < 0) {
@@ -363,8 +365,8 @@
dhd_conf_fix_country(dhd_get_pub(dev));
dhd_conf_get_country(dhd_get_pub(dev), &cspec);
dhd_bus_country_set(dev, &cspec, notify);
- WLDEV_ERROR(("%s: set country for %s as %s rev %d\n",
- __FUNCTION__, country_code, cspec.ccode, cspec.rev));
+ printf("%s: set country for %s as %s rev %d\n",
+ __FUNCTION__, country_code, cspec.ccode, cspec.rev);
}
return 0;
}
diff -Nur a/drivers/net/wireless/bcmdhd/wldev_common.h c/drivers/net/wireless/bcmdhd/wldev_common.h
--- a/drivers/net/wireless/bcmdhd/wldev_common.h 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/wldev_common.h 2016-05-13 09:48:20.000000000 +0200
@@ -3,7 +3,7 @@
*
* $Copyright Open Broadcom Corporation$
*
- * $Id: wldev_common.h 467328 2014-04-03 01:23:40Z $
+ * $Id: wldev_common.h 504503 2014-09-24 11:28:56Z $
*/
#ifndef __WLDEV_COMMON_H__
#define __WLDEV_COMMON_H__
@@ -97,4 +97,10 @@
int wldev_set_band(struct net_device *dev, uint band);
+#if defined(CUSTOM_PLATFORM_NV_TEGRA)
+int wldev_miracast_tuning(struct net_device *dev, char *command, int total_len);
+int wldev_get_assoc_resp_ie(struct net_device *dev, char *command, int total_len);
+int wldev_get_rx_rate_stats(struct net_device *dev, char *command, int total_len);
+#endif /* defined(CUSTOM_PLATFORM_NV_TEGRA) */
+
#endif /* __WLDEV_COMMON_H__ */
diff -Nur a/drivers/net/wireless/bcmdhd/wl_iw.c c/drivers/net/wireless/bcmdhd/wl_iw.c
--- a/drivers/net/wireless/bcmdhd/wl_iw.c 2016-06-09 19:33:24.000000000 +0200
+++ c/drivers/net/wireless/bcmdhd/wl_iw.c 2016-05-13 09:48:20.000000000 +0200
@@ -22,6 +22,7 @@
typedef const struct si_pub si_t;
#include <wlioctl.h>
+#include <wl_android.h>
/* message levels */
@@ -458,9 +459,6 @@
error = dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm));
return error;
}
-
-#if WIRELESS_EXT > 17
-#endif /* WIRELESS_EXT > 17 */
#endif /* WIRELESS_EXT > 12 */
int
@@ -599,9 +597,12 @@
chan = wf_mhz2channel(fwrq->m, sf);
}
+ WL_ERROR(("%s: chan=%d\n", __FUNCTION__, chan));
chan = htod32(chan);
- if ((error = dev_wlc_ioctl(dev, WLC_SET_CHANNEL, &chan, sizeof(chan))))
+ if ((error = dev_wlc_ioctl(dev, WLC_SET_CHANNEL, &chan, sizeof(chan)))) {
+ WL_ERROR(("%s: WLC_DISASSOC failed (%d).\n", __FUNCTION__, error));
return error;
+ }
/* -EINPROGRESS: Call commit handler */
return -EINPROGRESS;
@@ -993,6 +994,7 @@
if (ETHER_ISBCAST(awrq->sa_data) || ETHER_ISNULLADDR(awrq->sa_data)) {
scb_val_t scbval;
bzero(&scbval, sizeof(scb_val_t));
+ WL_ERROR(("%s: WLC_DISASSOC\n", __FUNCTION__));
if ((error = dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t)))) {
WL_ERROR(("%s: WLC_DISASSOC failed (%d).\n", __FUNCTION__, error));
}
@@ -1006,6 +1008,7 @@
WL_ERROR(("%s: WLC_REASSOC failed (%d).\n", __FUNCTION__, error));
return error;
}
+ WL_ERROR(("%s: join BSSID="MACSTR"\n", __FUNCTION__, MAC2STR((u8 *)awrq->sa_data)));
return 0;
}
@@ -1085,6 +1088,7 @@
wl_bss_info_t *bi = NULL;
int error, i;
uint buflen = dwrq->length;
+ int16 rssi;
WL_TRACE(("%s: SIOCGIWAPLIST\n", dev->name));
@@ -1119,8 +1123,10 @@
/* BSSID */
memcpy(addr[dwrq->length].sa_data, &bi->BSSID, ETHER_ADDR_LEN);
addr[dwrq->length].sa_family = ARPHRD_ETHER;
- qual[dwrq->length].qual = rssi_to_qual(dtoh16(bi->RSSI));
- qual[dwrq->length].level = 0x100 + dtoh16(bi->RSSI);
+ // terence 20150419: limit the max. rssi to -2 or the bss will be filtered out in android OS
+ rssi = MIN(dtoh16(bi->RSSI), RSSI_MAXVAL);
+ qual[dwrq->length].qual = rssi_to_qual(rssi);
+ qual[dwrq->length].level = 0x100 + rssi;
qual[dwrq->length].noise = 0x100 + bi->phy_noise;
/* Updated qual, level, and noise */
@@ -1160,6 +1166,7 @@
struct iw_quality qual[IW_MAX_AP];
wl_bss_info_t *bi = NULL;
int i;
+ int16 rssi;
WL_TRACE(("%s: SIOCGIWAPLIST\n", dev->name));
@@ -1189,8 +1196,10 @@
/* BSSID */
memcpy(addr[dwrq->length].sa_data, &bi->BSSID, ETHER_ADDR_LEN);
addr[dwrq->length].sa_family = ARPHRD_ETHER;
- qual[dwrq->length].qual = rssi_to_qual(dtoh16(bi->RSSI));
- qual[dwrq->length].level = 0x100 + dtoh16(bi->RSSI);
+ // terence 20150419: limit the max. rssi to -2 or the bss will be filtered out in android OS
+ rssi = MIN(dtoh16(bi->RSSI), RSSI_MAXVAL);
+ qual[dwrq->length].qual = rssi_to_qual(rssi);
+ qual[dwrq->length].level = 0x100 + rssi;
qual[dwrq->length].noise = 0x100 + bi->phy_noise;
/* Updated qual, level, and noise */
@@ -1476,12 +1485,13 @@
break;
}
#endif /* BCMWAPI_WPI */
- *event_p = event;
+ *event_p = event;
}
#endif /* WIRELESS_EXT > 17 */
return 0;
}
+
static int
wl_iw_get_scan(
struct net_device *dev,
@@ -1497,6 +1507,8 @@
int error, i, j;
char *event = extra, *end = extra + dwrq->length, *value;
uint buflen = dwrq->length;
+ int16 rssi;
+ int channel;
WL_TRACE(("%s: %s SIOCGIWSCAN\n", __FUNCTION__, dev->name));
@@ -1531,6 +1543,12 @@
ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list +
buflen));
+ // terence 20150419: limit the max. rssi to -2 or the bss will be filtered out in android OS
+ rssi = MIN(dtoh16(bi->RSSI), RSSI_MAXVAL);
+ channel = (bi->ctl_ch == 0) ? CHSPEC_CHANNEL(bi->chanspec) : bi->ctl_ch;
+ WL_SCAN(("%s: BSSID="MACSTR", channel=%d, RSSI=%d, merge broadcast SSID=\"%s\"\n",
+ __FUNCTION__, MAC2STR(bi->BSSID.octet), channel, rssi, bi->SSID));
+
/* First entry must be the BSSID */
iwe.cmd = SIOCGIWAP;
iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
@@ -1555,8 +1573,7 @@
/* Channel */
iwe.cmd = SIOCGIWFREQ;
-
- iwe.u.freq.m = wf_channel2mhz(CHSPEC_CHANNEL(bi->chanspec),
+ iwe.u.freq.m = wf_channel2mhz(channel,
(CHSPEC_IS2G(bi->chanspec)) ?
WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G);
iwe.u.freq.e = 6;
@@ -1564,8 +1581,8 @@
/* Channel quality */
iwe.cmd = IWEVQUAL;
- iwe.u.qual.qual = rssi_to_qual(dtoh16(bi->RSSI));
- iwe.u.qual.level = 0x100 + dtoh16(bi->RSSI);
+ iwe.u.qual.qual = rssi_to_qual(rssi);
+ iwe.u.qual.level = 0x100 + rssi;
iwe.u.qual.noise = 0x100 + bi->phy_noise;
event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_QUAL_LEN);
@@ -1620,6 +1637,8 @@
char *event = extra, *end = extra + dwrq->length, *value;
iscan_info_t *iscan = g_iscan;
iscan_buf_t * p_buf;
+ int16 rssi;
+ int channel;
WL_TRACE(("%s: %s SIOCGIWSCAN\n", __FUNCTION__, dev->name));
@@ -1632,97 +1651,105 @@
}
/* Check for scan in progress */
- if (iscan->iscan_state == ISCAN_STATE_SCANING)
+ if (iscan->iscan_state == ISCAN_STATE_SCANING) {
+ WL_TRACE(("%s: SIOCGIWSCAN GET still scanning\n", dev->name));
return -EAGAIN;
+ }
apcnt = 0;
p_buf = iscan->list_hdr;
/* Get scan results */
while (p_buf != iscan->list_cur) {
- list = &((wl_iscan_results_t*)p_buf->iscan_buf)->results;
-
- if (list->version != WL_BSS_INFO_VERSION) {
- WL_ERROR(("list->version %d != WL_BSS_INFO_VERSION\n", list->version));
- }
+ list = &((wl_iscan_results_t*)p_buf->iscan_buf)->results;
- bi = NULL;
- for (ii = 0; ii < list->count && apcnt < IW_MAX_AP; apcnt++, ii++) {
- bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info;
- ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list +
- WLC_IW_ISCAN_MAXLEN));
-
- /* overflow check cover fields before wpa IEs */
- if (event + ETHER_ADDR_LEN + bi->SSID_len + IW_EV_UINT_LEN + IW_EV_FREQ_LEN +
- IW_EV_QUAL_LEN >= end)
- return -E2BIG;
- /* First entry must be the BSSID */
- iwe.cmd = SIOCGIWAP;
- iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
- memcpy(iwe.u.ap_addr.sa_data, &bi->BSSID, ETHER_ADDR_LEN);
- event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_ADDR_LEN);
-
- /* SSID */
- iwe.u.data.length = dtoh32(bi->SSID_len);
- iwe.cmd = SIOCGIWESSID;
- iwe.u.data.flags = 1;
- event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, bi->SSID);
-
- /* Mode */
- if (dtoh16(bi->capability) & (DOT11_CAP_ESS | DOT11_CAP_IBSS)) {
- iwe.cmd = SIOCGIWMODE;
- if (dtoh16(bi->capability) & DOT11_CAP_ESS)
- iwe.u.mode = IW_MODE_INFRA;
- else
- iwe.u.mode = IW_MODE_ADHOC;
- event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_UINT_LEN);
+ if (list->version != WL_BSS_INFO_VERSION) {
+ WL_ERROR(("list->version %d != WL_BSS_INFO_VERSION\n", list->version));
}
- /* Channel */
- iwe.cmd = SIOCGIWFREQ;
-
- iwe.u.freq.m = wf_channel2mhz(CHSPEC_CHANNEL(bi->chanspec),
- (CHSPEC_IS2G(bi->chanspec)) ?
- WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G);
- iwe.u.freq.e = 6;
- event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_FREQ_LEN);
-
- /* Channel quality */
- iwe.cmd = IWEVQUAL;
- iwe.u.qual.qual = rssi_to_qual(dtoh16(bi->RSSI));
- iwe.u.qual.level = 0x100 + dtoh16(bi->RSSI);
- iwe.u.qual.noise = 0x100 + bi->phy_noise;
- event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_QUAL_LEN);
+ bi = NULL;
+ for (ii = 0; ii < list->count && apcnt < IW_MAX_AP; apcnt++, ii++) {
+ bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info;
+ ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list +
+ WLC_IW_ISCAN_MAXLEN));
- /* WPA, WPA2, WPS, WAPI IEs */
- wl_iw_handle_scanresults_ies(&event, end, info, bi);
-
- /* Encryption */
- iwe.cmd = SIOCGIWENCODE;
- if (dtoh16(bi->capability) & DOT11_CAP_PRIVACY)
- iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
- else
- iwe.u.data.flags = IW_ENCODE_DISABLED;
- iwe.u.data.length = 0;
- event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)event);
-
- /* Rates */
- if (bi->rateset.count <= sizeof(bi->rateset.rates)) {
- if (event + IW_MAX_BITRATES*IW_EV_PARAM_LEN >= end)
+ /* overflow check cover fields before wpa IEs */
+ if (event + ETHER_ADDR_LEN + bi->SSID_len + IW_EV_UINT_LEN + IW_EV_FREQ_LEN +
+ IW_EV_QUAL_LEN >= end)
return -E2BIG;
- value = event + IW_EV_LCP_LEN;
- iwe.cmd = SIOCGIWRATE;
- /* Those two flags are ignored... */
- iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
- for (j = 0; j < bi->rateset.count && j < IW_MAX_BITRATES; j++) {
- iwe.u.bitrate.value = (bi->rateset.rates[j] & 0x7f) * 500000;
- value = IWE_STREAM_ADD_VALUE(info, event, value, end, &iwe,
- IW_EV_PARAM_LEN);
+ // terence 20150419: limit the max. rssi to -2 or the bss will be filtered out in android OS
+ rssi = MIN(dtoh16(bi->RSSI), RSSI_MAXVAL);
+ channel = (bi->ctl_ch == 0) ? CHSPEC_CHANNEL(bi->chanspec) : bi->ctl_ch;
+ WL_SCAN(("%s: BSSID="MACSTR", channel=%d, RSSI=%d, merge broadcast SSID=\"%s\"\n",
+ __FUNCTION__, MAC2STR(bi->BSSID.octet), channel, rssi, bi->SSID));
+
+ /* First entry must be the BSSID */
+ iwe.cmd = SIOCGIWAP;
+ iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+ memcpy(iwe.u.ap_addr.sa_data, &bi->BSSID, ETHER_ADDR_LEN);
+ event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_ADDR_LEN);
+
+ /* SSID */
+ iwe.u.data.length = dtoh32(bi->SSID_len);
+ iwe.cmd = SIOCGIWESSID;
+ iwe.u.data.flags = 1;
+ event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, bi->SSID);
+
+ /* Mode */
+ if (dtoh16(bi->capability) & (DOT11_CAP_ESS | DOT11_CAP_IBSS)) {
+ iwe.cmd = SIOCGIWMODE;
+ if (dtoh16(bi->capability) & DOT11_CAP_ESS)
+ iwe.u.mode = IW_MODE_INFRA;
+ else
+ iwe.u.mode = IW_MODE_ADHOC;
+ event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_UINT_LEN);
+ }
+
+ /* Channel */
+ iwe.cmd = SIOCGIWFREQ;
+ iwe.u.freq.m = wf_channel2mhz(channel,
+ (CHSPEC_IS2G(bi->chanspec)) ?
+ WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G);
+ iwe.u.freq.e = 6;
+ event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_FREQ_LEN);
+
+ /* Channel quality */
+ iwe.cmd = IWEVQUAL;
+ iwe.u.qual.qual = rssi_to_qual(rssi);
+ iwe.u.qual.level = 0x100 + rssi;
+ iwe.u.qual.noise = 0x100 + bi->phy_noise;
+ event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_QUAL_LEN);
+
+ /* WPA, WPA2, WPS, WAPI IEs */
+ wl_iw_handle_scanresults_ies(&event, end, info, bi);
+
+ /* Encryption */
+ iwe.cmd = SIOCGIWENCODE;
+ if (dtoh16(bi->capability) & DOT11_CAP_PRIVACY)
+ iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+ else
+ iwe.u.data.flags = IW_ENCODE_DISABLED;
+ iwe.u.data.length = 0;
+ event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)event);
+
+ /* Rates */
+ if (bi->rateset.count <= sizeof(bi->rateset.rates)) {
+ if (event + IW_MAX_BITRATES*IW_EV_PARAM_LEN >= end)
+ return -E2BIG;
+
+ value = event + IW_EV_LCP_LEN;
+ iwe.cmd = SIOCGIWRATE;
+ /* Those two flags are ignored... */
+ iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
+ for (j = 0; j < bi->rateset.count && j < IW_MAX_BITRATES; j++) {
+ iwe.u.bitrate.value = (bi->rateset.rates[j] & 0x7f) * 500000;
+ value = IWE_STREAM_ADD_VALUE(info, event, value, end, &iwe,
+ IW_EV_PARAM_LEN);
+ }
+ event = value;
}
- event = value;
}
- }
- p_buf = p_buf->next;
+ p_buf = p_buf->next;
} /* while (p_buf) */
dwrq->length = event - extra;
@@ -1758,15 +1785,21 @@
memcpy(ssid.SSID, extra, ssid.SSID_len);
ssid.SSID_len = htod32(ssid.SSID_len);
- if ((error = dev_wlc_ioctl(dev, WLC_SET_SSID, &ssid, sizeof(ssid))))
+ if ((error = dev_wlc_ioctl(dev, WLC_SET_SSID, &ssid, sizeof(ssid)))) {
+ WL_ERROR(("%s: WLC_SET_SSID failed (%d).\n", __FUNCTION__, error));
return error;
+ }
+ WL_ERROR(("%s: join SSID=%s\n", __FUNCTION__, ssid.SSID));
}
/* If essid null then it is "iwconfig <interface> essid off" command */
else {
scb_val_t scbval;
bzero(&scbval, sizeof(scb_val_t));
- if ((error = dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t))))
+ WL_ERROR(("%s: WLC_DISASSOC\n", __FUNCTION__));
+ if ((error = dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t)))) {
+ WL_ERROR(("%s: WLC_DISASSOC failed (%d).\n", __FUNCTION__, error));
return error;
+ }
}
return 0;
}
@@ -2495,9 +2528,12 @@
bcopy(keystring, pmk.key, len);
pmk.flags = htod16(WSEC_PASSPHRASE);
+ WL_WSEC(("%s: set key %s\n", __FUNCTION__, keystring));
error = dev_wlc_ioctl(dev, WLC_SET_WSEC_PMK, &pmk, sizeof(pmk));
- if (error)
+ if (error) {
+ WL_ERROR(("%s: WLC_SET_WSEC_PMK error %d\n", __FUNCTION__, error));
return error;
+ }
}
else {
@@ -2568,7 +2604,6 @@
}
-#if WIRELESS_EXT > 17
struct {
pmkid_list_t pmkids;
pmkid_t foo[MAXPMKID-1];
@@ -2655,7 +2690,6 @@
dev_wlc_bufvar_set(dev, "pmkid_info", (char *)&pmkid_list, sizeof(pmkid_list));
return 0;
}
-#endif /* WIRELESS_EXT > 17 */
static int
wl_iw_get_encodeext(
@@ -2722,8 +2756,11 @@
iw->gwsec = paramval;
}
- if ((error = dev_wlc_intvar_get(dev, "wsec", &val)))
+ if ((error = dev_wlc_intvar_get(dev, "wsec", &val))) {
+ WL_ERROR(("%s: wsec error %d\n", __FUNCTION__, error));
return error;
+ }
+ WL_WSEC(("%s: get wsec=0x%x\n", __FUNCTION__, val));
cipher_combined = iw->gwsec | iw->pwsec;
val &= ~(WEP_ENABLED | TKIP_ENABLED | AES_ENABLED);
@@ -2753,21 +2790,29 @@
}
}
- if ((error = dev_wlc_intvar_set(dev, "wsec", val)))
+ WL_WSEC(("%s: set wsec=0x%x\n", __FUNCTION__, val));
+ if ((error = dev_wlc_intvar_set(dev, "wsec", val))) {
+ WL_ERROR(("%s: wsec error %d\n", __FUNCTION__, error));
return error;
+ }
/* Ensure in-dongle supplicant is turned on when FBT wants to do the 4-way
* handshake.
*/
if (dev_wlc_intvar_get(dev, "fbt_cap", &fbt_cap) == 0) {
+ WL_WSEC(("%s: get fbt_cap=0x%x\n", __FUNCTION__, fbt_cap));
if (fbt_cap == WLC_FBT_CAP_DRV_4WAY_AND_REASSOC) {
if ((paramid == IW_AUTH_CIPHER_PAIRWISE) && (val & AES_ENABLED)) {
- if ((error = dev_wlc_intvar_set(dev, "sup_wpa", 1)))
+ if ((error = dev_wlc_intvar_set(dev, "sup_wpa", 1))) {
+ WL_ERROR(("%s: sup_wpa 1 error %d\n", __FUNCTION__, error));
return error;
+ }
}
else if (val == 0) {
- if ((error = dev_wlc_intvar_set(dev, "sup_wpa", 0)))
+ if ((error = dev_wlc_intvar_set(dev, "sup_wpa", 0))) {
+ WL_ERROR(("%s: sup_wpa 0 error %d\n", __FUNCTION__, error));
return error;
+ }
}
}
}
@@ -2775,8 +2820,11 @@
}
case IW_AUTH_KEY_MGMT:
- if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val)))
+ if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val))) {
+ WL_ERROR(("%s: wpa_auth error %d\n", __FUNCTION__, error));
return error;
+ }
+ WL_WSEC(("%s: get wpa_auth to %d\n", __FUNCTION__, val));
if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
if (paramval & (IW_AUTH_KEY_MGMT_FT_PSK | IW_AUTH_KEY_MGMT_PSK))
@@ -3085,8 +3133,6 @@
WL_IW_SET_LEDDC = SIOCIWFIRSTPRIV,
WL_IW_SET_VLANMODE,
WL_IW_SET_PM,
-#if WIRELESS_EXT > 17
-#endif /* WIRELESS_EXT > 17 */
WL_IW_SET_LAST
};
@@ -3094,8 +3140,6 @@
wl_iw_set_leddc,
wl_iw_set_vlanmode,
wl_iw_set_pm,
-#if WIRELESS_EXT > 17
-#endif /* WIRELESS_EXT > 17 */
NULL
};
@@ -3118,8 +3162,6 @@
0,
"set_pm"
},
-#if WIRELESS_EXT > 17
-#endif /* WIRELESS_EXT > 17 */
{ 0, 0, 0, { 0 } }
};
@@ -3383,8 +3425,13 @@
cmd = SIOCGIWAP;
wrqu.data.length = strlen(extra);
if (!(flags & WLC_EVENT_MSG_LINK)) {
+ printf("%s: Link Down with BSSID="MACSTR"\n", __FUNCTION__,
+ MAC2STR((u8 *)wrqu.addr.sa_data));
bzero(wrqu.addr.sa_data, ETHER_ADDR_LEN);
bzero(&extra, ETHER_ADDR_LEN);
+ } else {
+ printf("%s: Link UP with BSSID="MACSTR"\n", __FUNCTION__,
+ MAC2STR((u8 *)wrqu.addr.sa_data));
}
break;
case WLC_E_ACTION_FRAME:
@@ -3482,9 +3529,11 @@
}
if (cmd) {
- if (cmd == SIOCGIWSCAN)
- wireless_send_event(dev, cmd, &wrqu, NULL);
- else
+ if (cmd == SIOCGIWSCAN) {
+ if ((!g_iscan) || (g_iscan->sysioc_pid < 0)) {
+ wireless_send_event(dev, cmd, &wrqu, NULL);
+ };
+ } else
wireless_send_event(dev, cmd, &wrqu, extra);
}
@@ -3741,6 +3790,7 @@
uint32 status;
iscan_info_t *iscan = (iscan_info_t *)data;
+ printf("%s: thread Enter\n", __FUNCTION__);
DAEMONIZE("iscan_sysioc");
status = WL_SCAN_RESULTS_PARTIAL;
@@ -3796,6 +3846,7 @@
break;
}
}
+ printf("%s: was terminated\n", __FUNCTION__);
complete_and_exit(&iscan->sysioc_exited, 0);
}
@@ -3804,7 +3855,7 @@
{
iscan_info_t *iscan = NULL;
- WL_TRACE(("%s: iscan=%p\n", __FUNCTION__, iscan));
+ printf("%s: Enter\n", __FUNCTION__);
if (!dev)
return 0;