mirror of
https://github.com/Fishwaldo/build.git
synced 2025-03-26 16:51:48 +00:00
40326 lines
1.1 MiB
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 *)&du_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, ¶m);
|
|
- }
|
|
-
|
|
- 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, ¶m);
|
|
- } else {
|
|
- if (get_scheduler_policy(current) != SCHED_FIFO) {
|
|
- param.sched_priority = (prio < MAX_RT_PRIO)? prio : (MAX_RT_PRIO-1);
|
|
- setScheduler(current, SCHED_FIFO, ¶m);
|
|
- }
|
|
- }
|
|
-}
|
|
-#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, ¶m);
|
|
- }
|
|
-
|
|
-#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, ¶m);
|
|
- }
|
|
-
|
|
- 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 *)&du_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 *)&du_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 *)&du_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, ð.ether_dhost, ETHER_ADDR_LEN);
|
|
- bcopy(&dhdp->mac, ð.ether_shost, ETHER_ADDR_LEN);
|
|
- ETHER_TOGGLE_LOCALADDR(ð.ether_shost);
|
|
- eth.ether_type = hton16(ETHER_TYPE_BRCM);
|
|
-
|
|
- bcopy((void *)ð, 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, ðertype, &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, ¶m);
|
|
+ }
|
|
+
|
|
+ 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, ¶m);
|
|
+ } else {
|
|
+ if (get_scheduler_policy(current) != SCHED_FIFO) {
|
|
+ param.sched_priority = (prio < MAX_RT_PRIO)? prio : (MAX_RT_PRIO-1);
|
|
+ setScheduler(current, SCHED_FIFO, ¶m);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+#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, ¶m);
|
|
+ }
|
|
+
|
|
+#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, ¶m);
|
|
+ }
|
|
+
|
|
+ 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 *)&du_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 *)&du_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 *)&du_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, ð.ether_dhost, ETHER_ADDR_LEN);
|
|
+ bcopy(&dhdp->mac, ð.ether_shost, ETHER_ADDR_LEN);
|
|
+ ETHER_TOGGLE_LOCALADDR(ð.ether_shost);
|
|
+ eth.ether_type = hton16(ETHER_TYPE_BRCM);
|
|
+
|
|
+ bcopy((void *)ð, 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, ðertype, &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, ®s->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(¶m, 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*)¶m, 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;
|