From 1282ad1837801103f42b4a7b8de4f231907bd4ef Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Mon, 27 Feb 2012 12:35:15 -0800 Subject: [PATCH] net: wireless: bcmdhd: Update to Version 5.90.195.28 - Improve scan for p2p - Use use_rxchain support - Use WL_WIRELESS_EXT instead of CONFIG_WIRELESS_EXT - Initial sched_scan support Signed-off-by: Dmitry Shmidt --- drivers/net/wireless/bcmdhd/Makefile | 2 +- drivers/net/wireless/bcmdhd/aiutils.c | 2 +- drivers/net/wireless/bcmdhd/bcmsdh.c | 2 +- drivers/net/wireless/bcmdhd/bcmsdh_linux.c | 18 +- drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c | 204 ++++-- .../net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c | 6 +- drivers/net/wireless/bcmdhd/dhd_cfg80211.c | 2 +- drivers/net/wireless/bcmdhd/dhd_linux.c | 76 +-- drivers/net/wireless/bcmdhd/dhd_sdio.c | 2 +- .../wireless/bcmdhd/include/bcmsdh_sdmmc.h | 9 +- drivers/net/wireless/bcmdhd/include/epivers.h | 8 +- .../net/wireless/bcmdhd/include/linuxver.h | 7 +- drivers/net/wireless/bcmdhd/include/sbchipc.h | 5 +- drivers/net/wireless/bcmdhd/include/wlioctl.h | 4 +- drivers/net/wireless/bcmdhd/wl_android.c | 6 +- drivers/net/wireless/bcmdhd/wl_cfg80211.c | 599 ++++++++++++++---- drivers/net/wireless/bcmdhd/wl_cfg80211.h | 4 + drivers/net/wireless/bcmdhd/wl_iw.c | 3 - 18 files changed, 695 insertions(+), 264 deletions(-) diff --git a/drivers/net/wireless/bcmdhd/Makefile b/drivers/net/wireless/bcmdhd/Makefile index 17f07ca3a307..9828de6fad9d 100644 --- a/drivers/net/wireless/bcmdhd/Makefile +++ b/drivers/net/wireless/bcmdhd/Makefile @@ -19,7 +19,7 @@ obj-$(CONFIG_BCMDHD) += bcmdhd.o bcmdhd-objs += $(DHDOFILES) ifneq ($(CONFIG_WIRELESS_EXT),) bcmdhd-objs += wl_iw.o -DHDCFLAGS += -DSOFTAP +DHDCFLAGS += -DSOFTAP -DWL_WIRELESS_EXT endif ifneq ($(CONFIG_CFG80211),) bcmdhd-objs += wl_cfg80211.o wl_cfgp2p.o wl_linux_mon.o diff --git a/drivers/net/wireless/bcmdhd/aiutils.c b/drivers/net/wireless/bcmdhd/aiutils.c index 059df8907928..5ca0993c9333 100644 --- a/drivers/net/wireless/bcmdhd/aiutils.c +++ b/drivers/net/wireless/bcmdhd/aiutils.c @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: aiutils.c,v 1.26.2.1 2010-03-09 18:41:21 Exp $ + * $Id: aiutils.c,v 1.26.2.1 2010-03-09 18:41:21 $ */ diff --git a/drivers/net/wireless/bcmdhd/bcmsdh.c b/drivers/net/wireless/bcmdhd/bcmsdh.c index 918c8e648f13..f67b13a03a1c 100644 --- a/drivers/net/wireless/bcmdhd/bcmsdh.c +++ b/drivers/net/wireless/bcmdhd/bcmsdh.c @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: bcmsdh.c 275784 2011-08-04 22:41:49Z $ + * $Id: bcmsdh.c 300445 2011-12-03 05:37:20Z $ */ /** diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_linux.c b/drivers/net/wireless/bcmdhd/bcmsdh_linux.c index e01b6f8a2d4f..d257ddab84a3 100644 --- a/drivers/net/wireless/bcmdhd/bcmsdh_linux.c +++ b/drivers/net/wireless/bcmdhd/bcmsdh_linux.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: bcmsdh_linux.c 308641 2012-01-17 02:18:02Z $ + * $Id: bcmsdh_linux.c 312788 2012-02-03 23:06:32Z $ */ /** @@ -620,13 +620,6 @@ int bcmsdh_register_oob_intr(void * dhdp) return 0; } -void *bcmsdh_get_drvdata(void) -{ - if (!sdhcinfo) - return NULL; - return dev_get_drvdata(sdhcinfo->dev); -} - void bcmsdh_set_irq(int flag) { if (sdhcinfo->oob_irq_registered && sdhcinfo->oob_irq_enable_flag != flag) { @@ -654,6 +647,15 @@ void bcmsdh_unregister_oob_intr(void) } #endif /* defined(OOB_INTR_ONLY) */ +#if defined(BCMLXSDMMC) +void *bcmsdh_get_drvdata(void) +{ + if (!sdhcinfo) + return NULL; + return dev_get_drvdata(sdhcinfo->dev); +} +#endif + /* Module parameters specific to each host-controller driver */ extern uint sd_msglevel; /* Debug message level */ diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c index 6a8ff9431e92..b88e57a5203b 100644 --- a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c +++ b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: bcmsdh_sdmmc.c 301794 2011-12-08 20:41:35Z $ + * $Id: bcmsdh_sdmmc.c 314904 2012-02-14 21:36:04Z $ */ #include @@ -35,6 +35,7 @@ #include /* ioctl/iovars */ #include +#include #include #include @@ -148,6 +149,7 @@ sdioh_attach(osl_t *osh, void *bar0, uint irq) sd->sd_blockmode = TRUE; sd->use_client_ints = TRUE; sd->client_block_size[0] = 64; + sd->use_rxchain = FALSE; gInstance->sd = sd; @@ -512,7 +514,7 @@ sdioh_iovar_op(sdioh_info_t *si, const char *name, } case IOV_GVAL(IOV_RXCHAIN): - int_val = FALSE; + int_val = (int32)si->use_rxchain; bcopy(&int_val, arg, val_size); break; @@ -902,8 +904,12 @@ sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func, bool fifo = (fix_inc == SDIOH_DATA_FIX); uint32 SGCount = 0; int err_ret = 0; - - void *pnext; + void *pnext, *pprev; + uint ttl_len, dma_len, lft_len, xfred_len, pkt_len; + uint blk_num; + struct mmc_request mmc_req; + struct mmc_command mmc_cmd; + struct mmc_data mmc_dat; sd_trace(("%s: Enter\n", __FUNCTION__)); @@ -911,66 +917,148 @@ sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func, DHD_PM_RESUME_WAIT(sdioh_request_packet_wait); DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL); - /* Claim host controller */ - sdio_claim_host(gInstance->func[func]); - for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext)) { - uint pkt_len = PKTLEN(sd->osh, pnext); - pkt_len += 3; - pkt_len &= 0xFFFFFFFC; + ttl_len = xfred_len = 0; + /* 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); -#ifdef CONFIG_MMC_MSM7X00A - if ((pkt_len % 64) == 32) { - sd_trace(("%s: Rounding up TX packet +=32\n", __FUNCTION__)); - pkt_len += 32; - } -#endif /* CONFIG_MMC_MSM7X00A */ - /* Make sure the packet is aligned properly. If it isn't, then this - * is the fault of sdioh_request_buffer() which is supposed to give - * us something we can work with. - */ - ASSERT(((uint32)(PKTDATA(sd->osh, pkt)) & DMA_ALIGN_MASK) == 0); - - if ((write) && (!fifo)) { - err_ret = sdio_memcpy_toio(gInstance->func[func], addr, - ((uint8*)PKTDATA(sd->osh, pnext)), - pkt_len); - } else if (write) { - err_ret = sdio_memcpy_toio(gInstance->func[func], addr, - ((uint8*)PKTDATA(sd->osh, pnext)), - pkt_len); - } else if (fifo) { - err_ret = sdio_readsb(gInstance->func[func], - ((uint8*)PKTDATA(sd->osh, pnext)), - addr, - pkt_len); - } else { - err_ret = sdio_memcpy_fromio(gInstance->func[func], - ((uint8*)PKTDATA(sd->osh, pnext)), - addr, + if (!sd->use_rxchain || ttl_len <= sd->client_block_size[func]) { + blk_num = 0; + dma_len = 0; + } else { + blk_num = ttl_len / sd->client_block_size[func]; + dma_len = blk_num * sd->client_block_size[func]; + } + 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 */ + pprev = pkt; + 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 (err_ret) { - sd_err(("%s: %s FAILED %p[%d], addr=0x%05x, pkt_len=%d, ERR=0x%08x\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 (SGCount >= SDIOH_SDMMC_MAX_SG_ENTRIES) { + sd_err(("%s: sg list entries exceed limit\n", + __FUNCTION__)); + return (SDIOH_API_RC_FAIL); + } } - if (!fifo) { - addr += pkt_len; - } - SGCount ++; + mmc_dat.sg = sd->sg_list; + mmc_dat.sg_len = SGCount; + mmc_dat.blksz = sd->client_block_size[func]; + 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(gInstance->func[func]); + mmc_set_data_timeout(&mmc_dat, gInstance->func[func]->card); + mmc_wait_for_req(gInstance->func[func]->card->host, &mmc_req); + sdio_release_host(gInstance->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)); + sd_err(("%s:Disabling rxchain and fire it with PIO\n", + __FUNCTION__)); + sd->use_rxchain = FALSE; + pkt = pprev; + lft_len = ttl_len; + } else if (!fifo) { + addr = addr + ttl_len - lft_len - dma_len; + } } - /* Release host controller */ - sdio_release_host(gInstance->func[func]); + /* PIO mode */ + if (0 != lft_len) { + /* Claim host controller */ + sdio_claim_host(gInstance->func[func]); + for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext)) { + uint8 *buf = (uint8*)PKTDATA(sd->osh, pnext) + + xfred_len; + pkt_len = PKTLEN(sd->osh, pnext); + if (0 != xfred_len) { + pkt_len -= xfred_len; + xfred_len = 0; + } + pkt_len = (pkt_len + 3) & 0xFFFFFFFC; +#ifdef CONFIG_MMC_MSM7X00A + if ((pkt_len % 64) == 32) { + sd_trace(("%s: Rounding up TX packet +=32\n", __FUNCTION__)); + pkt_len += 32; + } +#endif /* CONFIG_MMC_MSM7X00A */ + + if ((write) && (!fifo)) + err_ret = sdio_memcpy_toio( + gInstance->func[func], + addr, buf, pkt_len); + else if (write) + err_ret = sdio_memcpy_toio( + gInstance->func[func], + addr, buf, pkt_len); + else if (fifo) + err_ret = sdio_readsb( + gInstance->func[func], + buf, addr, pkt_len); + else + err_ret = sdio_memcpy_fromio( + gInstance->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(gInstance->func[func]); + } sd_trace(("%s: Exit\n", __FUNCTION__)); return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL); @@ -1232,8 +1320,10 @@ sdioh_start(sdioh_info_t *si, int stage) 2.6.27. The implementation prior to that is buggy, and needs broadcom's patch for it */ - if ((ret = sdio_reset_comm(gInstance->func[0]->card))) + if ((ret = sdio_reset_comm(gInstance->func[0]->card))) { sd_err(("%s Failed, error = %d\n", __FUNCTION__, ret)); + return ret; + } else { sd->num_funcs = 2; sd->sd_blockmode = TRUE; diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c index 83f4d3df671f..f296dd382b5c 100644 --- a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c +++ b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: bcmsdh_sdmmc_linux.c 308645 2012-01-17 02:33:26Z $ + * $Id: bcmsdh_sdmmc_linux.c 312783 2012-02-03 22:53:56Z $ */ #include @@ -98,7 +98,6 @@ PBCMSDH_SDMMC_INSTANCE gInstance; extern int bcmsdh_probe(struct device *dev); extern int bcmsdh_remove(struct device *dev); - extern volatile bool dhd_mmc_suspend; static int bcmsdh_sdmmc_probe(struct sdio_func *func, @@ -194,8 +193,9 @@ static int bcmsdh_sdmmc_suspend(struct device *pdev) static int bcmsdh_sdmmc_resume(struct device *pdev) { +#if defined(OOB_INTR_ONLY) struct sdio_func *func = dev_to_sdio_func(pdev); - +#endif sd_trace(("%s Enter\n", __FUNCTION__)); dhd_mmc_suspend = FALSE; #if defined(OOB_INTR_ONLY) diff --git a/drivers/net/wireless/bcmdhd/dhd_cfg80211.c b/drivers/net/wireless/bcmdhd/dhd_cfg80211.c index 800590cca653..917b09b35a35 100644 --- a/drivers/net/wireless/bcmdhd/dhd_cfg80211.c +++ b/drivers/net/wireless/bcmdhd/dhd_cfg80211.c @@ -467,7 +467,6 @@ void wl_cfg80211_btcoex_deinit(struct wl_priv *wl) kfree(wl->btcoex_info); wl->btcoex_info = NULL; } -#endif int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, char *command) { @@ -591,3 +590,4 @@ int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, char *command) return (strlen("OK")); } +#endif diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c index 0c34e79bf2ca..597d12560c19 100644 --- a/drivers/net/wireless/bcmdhd/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd/dhd_linux.c @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_linux.c 308879 2012-01-17 22:03:47Z $ + * $Id: dhd_linux.c 314746 2012-02-14 03:45:02Z $ */ #include @@ -149,10 +149,10 @@ print_tainted() #endif /* LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15) */ /* Linux wireless extension support */ -#if defined(CONFIG_WIRELESS_EXT) +#if defined(WL_WIRELESS_EXT) #include extern wl_iw_extra_params_t g_wl_iw_params; -#endif /* defined(CONFIG_WIRELESS_EXT) */ +#endif /* defined(WL_WIRELESS_EXT) */ #if defined(CONFIG_HAS_EARLYSUSPEND) #include @@ -212,9 +212,9 @@ static uint32 maxdelay = 0, tspktcnt = 0, maxdelaypktno = 0; /* Local private structure (extension of pub) */ typedef struct dhd_info { -#if defined(CONFIG_WIRELESS_EXT) +#if defined(WL_WIRELESS_EXT) wl_iw_t iw; /* wireless extensions state (must be first) */ -#endif /* defined(CONFIG_WIRELESS_EXT) */ +#endif /* defined(WL_WIRELESS_EXT) */ dhd_pub_t pub; @@ -359,12 +359,6 @@ uint dhd_radio_up = 1; char iface_name[IFNAMSIZ] = {'\0'}; module_param_string(iface_name, iface_name, IFNAMSIZ, 0); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) -#define BLOCKABLE() (!in_atomic()) -#else -#define BLOCKABLE() (!in_interrupt()) -#endif - /* The following are specific to the SDIO dongle */ /* IOCTL response timeout */ @@ -451,9 +445,9 @@ int dhd_monitor_init(void *dhd_pub); int dhd_monitor_uninit(void); -#if defined(CONFIG_WIRELESS_EXT) +#if defined(WL_WIRELESS_EXT) struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev); -#endif /* defined(CONFIG_WIRELESS_EXT) */ +#endif /* defined(WL_WIRELESS_EXT) */ static void dhd_dpc(ulong data); /* forward decl */ @@ -2053,7 +2047,7 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) return -1; } -#if defined(CONFIG_WIRELESS_EXT) +#if defined(WL_WIRELESS_EXT) /* linux wireless extensions */ if ((cmd >= SIOCIWFIRST) && (cmd <= SIOCIWLAST)) { /* may recurse, do NOT lock */ @@ -2061,7 +2055,7 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) DHD_OS_WAKE_UNLOCK(&dhd->pub); return ret; } -#endif /* defined(CONFIG_WIRELESS_EXT) */ +#endif /* defined(WL_WIRELESS_EXT) */ #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) if (cmd == SIOCETHTOOL) { @@ -2338,7 +2332,6 @@ dhd_open(struct net_device *net) } dhd->pub.hang_was_sent = 0; - #if !defined(WL_CFG80211) /* * Force start if ifconfig_up gets called before START command @@ -2672,7 +2665,7 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) dhd_monitor_init(&dhd->pub); dhd_state |= DHD_ATTACH_STATE_CFG80211; #endif -#if defined(CONFIG_WIRELESS_EXT) +#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) { @@ -2681,7 +2674,7 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) } dhd_state |= DHD_ATTACH_STATE_WL_ATTACH; } -#endif /* defined(CONFIG_WIRELESS_EXT) */ +#endif /* defined(WL_WIRELESS_EXT) */ /* Set up the watchdog timer */ @@ -2934,6 +2927,9 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #if defined(ARP_OFFLOAD_SUPPORT) int arpoe = 1; #endif +#if defined(KEEP_ALIVE) + int res; +#endif /* defined(KEEP_ALIVE) */ int scan_assoc_time = DHD_SCAN_ACTIVE_TIME; int scan_unassoc_time = 40; int scan_passive_time = DHD_SCAN_PASSIVE_TIME; @@ -2946,14 +2942,12 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #if (defined(AP) && !defined(WLP2P)) || (!defined(AP) && defined(WL_CFG80211)) uint32 mpc = 0; /* Turn MPC off for AP/APSTA mode */ #endif - #if defined(AP) || defined(WLP2P) uint32 apsta = 1; /* Enable APSTA mode */ #endif /* defined(AP) || defined(WLP2P) */ #ifdef GET_CUSTOM_MAC_ENABLE struct ether_addr ea_addr; #endif /* GET_CUSTOM_MAC_ENABLE */ - DHD_TRACE(("Enter %s\n", __FUNCTION__)); dhd->op_mode = 0; #ifdef GET_CUSTOM_MAC_ENABLE @@ -3083,6 +3077,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) /* 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)); @@ -3098,17 +3093,13 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #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 ((res = dhd_keep_alive_onoff(dhd)) < 0) DHD_ERROR(("%s set keeplive failed %d\n", __FUNCTION__, res)); - } #endif /* defined(KEEP_ALIVE) */ /* Read event_msgs mask */ @@ -3471,14 +3462,14 @@ dhd_net_attach(dhd_pub_t *dhdp, int ifidx) net->ethtool_ops = &dhd_ethtool_ops; #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */ -#if defined(CONFIG_WIRELESS_EXT) +#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(CONFIG_WIRELESS_EXT) */ +#endif /* defined(WL_WIRELESS_EXT) */ dhd->pub.rxsz = DBUS_RX_BUFFER_SIZE_DHD(net); @@ -3494,7 +3485,7 @@ dhd_net_attach(dhd_pub_t *dhdp, int ifidx) net->dev_addr[0], net->dev_addr[1], net->dev_addr[2], net->dev_addr[3], net->dev_addr[4], net->dev_addr[5]); -#if defined(SOFTAP) && defined(CONFIG_WIRELESS_EXT) && !defined(WL_CFG80211) +#if defined(SOFTAP) && defined(WL_WIRELESS_EXT) && !defined(WL_CFG80211) wl_iw_iscan_set_scan_broadcast_prep(net, 1); #endif @@ -3579,12 +3570,12 @@ void dhd_detach(dhd_pub_t *dhdp) } #endif /* defined(CONFIG_HAS_EARLYSUSPEND) */ -#if defined(CONFIG_WIRELESS_EXT) +#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(CONFIG_WIRELESS_EXT) */ +#endif /* defined(WL_WIRELESS_EXT) */ if (dhd->thr_sysioc_ctl.thr_pid >= 0) { PROC_STOP(&dhd->thr_sysioc_ctl); @@ -3748,20 +3739,20 @@ dhd_module_init(void) } #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) - /* - * Wait till MMC sdio_register_driver callback called and made driver attach. - * It's needed to make sync up exit from dhd insmod and - * Kernel MMC sdio device callback registration - */ + /* + * Wait till MMC sdio_register_driver callback called and made driver attach. + * It's needed to make sync up exit from dhd insmod and + * Kernel MMC sdio device callback registration + */ if (down_timeout(&dhd_registration_sem, msecs_to_jiffies(DHD_REGISTRATION_TIMEOUT)) != 0) { - error = -EINVAL; + error = -ENODEV; DHD_ERROR(("%s: sdio_register_driver timeout\n", __FUNCTION__)); goto fail_2; } #endif #if defined(WL_CFG80211) wl_android_post_init(); -#endif +#endif /* defined(WL_CFG80211) */ return error; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && 1 @@ -4037,7 +4028,7 @@ void dhd_os_prefree(void *osh, void *addr, uint size) } #endif /* defined(CONFIG_DHD_USE_STATIC_BUF) */ -#if defined(CONFIG_WIRELESS_EXT) +#if defined(WL_WIRELESS_EXT) struct iw_statistics * dhd_get_wireless_stats(struct net_device *dev) { @@ -4055,7 +4046,7 @@ dhd_get_wireless_stats(struct net_device *dev) else return NULL; } -#endif /* defined(CONFIG_WIRELESS_EXT) */ +#endif /* defined(WL_WIRELESS_EXT) */ static int dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata, @@ -4068,7 +4059,7 @@ dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata, if (bcmerror != BCME_OK) return (bcmerror); -#if defined(CONFIG_WIRELESS_EXT) +#if defined(WL_WIRELESS_EXT) if (event->bsscfgidx == 0) { /* * Wireless ext is on primary interface only @@ -4081,7 +4072,7 @@ dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata, wl_iw_event(dhd->iflist[*ifidx]->net, event, *data); } } -#endif /* defined(CONFIG_WIRELESS_EXT) */ +#endif /* defined(WL_WIRELESS_EXT) */ #ifdef WL_CFG80211 if ((ntoh32(event->event_type) == WLC_E_IF) && @@ -4386,6 +4377,8 @@ dhd_dev_get_pno_status(struct net_device *dev) #endif /* PNO_SUPPORT */ +struct work_struct work; + int net_os_send_hang_message(struct net_device *dev) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); @@ -4402,7 +4395,7 @@ int net_os_send_hang_message(struct net_device *dev) dev_close(dev); if (need_unlock) rtnl_unlock(); -#if defined(CONFIG_WIRELESS_EXT) +#if defined(WL_WIRELESS_EXT) ret = wl_iw_send_priv_event(dev, "HANG"); #endif #if defined(WL_CFG80211) @@ -4421,7 +4414,6 @@ void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec) memcpy(&dhd->pub.dhd_cspec, cspec, sizeof(wl_country_t)); } - void dhd_net_if_lock(struct net_device *dev) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); diff --git a/drivers/net/wireless/bcmdhd/dhd_sdio.c b/drivers/net/wireless/bcmdhd/dhd_sdio.c index 53eff583c381..282a7179540b 100644 --- a/drivers/net/wireless/bcmdhd/dhd_sdio.c +++ b/drivers/net/wireless/bcmdhd/dhd_sdio.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_sdio.c 309234 2012-01-19 01:44:16Z $ + * $Id: dhd_sdio.c 314732 2012-02-14 03:22:42Z $ */ #include diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h b/drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h index bea97b610a8e..db8ea596304c 100644 --- a/drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h +++ b/drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: bcmsdh_sdmmc.h 277737 2011-08-16 17:54:59Z $ + * $Id: bcmsdh_sdmmc.h 314048 2012-02-09 20:31:56Z $ */ #ifndef __BCMSDH_SDMMC_H__ @@ -82,9 +82,10 @@ struct sdioh_info { uint8 num_funcs; /* Supported funcs on client */ uint32 com_cis_ptr; uint32 func_cis_ptr[SDIOD_MAX_IOFUNCS]; - uint max_dma_len; - uint max_dma_descriptors; /* DMA Descriptors supported by this controller. */ -// SDDMA_DESCRIPTOR SGList[32]; /* Scatter/Gather DMA List */ + +#define SDIOH_SDMMC_MAX_SG_ENTRIES 32 + struct scatterlist sg_list[SDIOH_SDMMC_MAX_SG_ENTRIES]; + bool use_rxchain; }; /************************************************************ diff --git a/drivers/net/wireless/bcmdhd/include/epivers.h b/drivers/net/wireless/bcmdhd/include/epivers.h index 53dd2f736734..0e720456f582 100644 --- a/drivers/net/wireless/bcmdhd/include/epivers.h +++ b/drivers/net/wireless/bcmdhd/include/epivers.h @@ -33,17 +33,17 @@ #define EPI_RC_NUMBER 195 -#define EPI_INCREMENTAL_NUMBER 23 +#define EPI_INCREMENTAL_NUMBER 28 #define EPI_BUILD_NUMBER 0 -#define EPI_VERSION 5, 90, 195, 23 +#define EPI_VERSION 5, 90, 195, 28 -#define EPI_VERSION_NUM 0x055ac317 +#define EPI_VERSION_NUM 0x055ac31c #define EPI_VERSION_DEV 5.90.195 -#define EPI_VERSION_STR "5.90.195.23" +#define EPI_VERSION_STR "5.90.195.28" #endif diff --git a/drivers/net/wireless/bcmdhd/include/linuxver.h b/drivers/net/wireless/bcmdhd/include/linuxver.h index d269e66f7fb8..54d88ee923b2 100644 --- a/drivers/net/wireless/bcmdhd/include/linuxver.h +++ b/drivers/net/wireless/bcmdhd/include/linuxver.h @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: linuxver.h 280266 2011-08-28 04:18:20Z $ + * $Id: linuxver.h 312264 2012-02-02 00:49:43Z $ */ @@ -524,6 +524,11 @@ typedef struct { } while (0); #endif /* LINUX_VERSION_CODE */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) +#define BLOCKABLE() (!in_atomic()) +#else +#define BLOCKABLE() (!in_interrupt()) +#endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) #define KILL_PROC(nr, sig) \ diff --git a/drivers/net/wireless/bcmdhd/include/sbchipc.h b/drivers/net/wireless/bcmdhd/include/sbchipc.h index 3fe2a5a49d30..8f757509b95d 100644 --- a/drivers/net/wireless/bcmdhd/include/sbchipc.h +++ b/drivers/net/wireless/bcmdhd/include/sbchipc.h @@ -5,7 +5,7 @@ * JTAG, 0/1/2 UARTs, clock frequency control, a watchdog interrupt timer, * GPIO interface, extbus, and support for serial and parallel flashes. * - * $Id: sbchipc.h 277737 2011-08-16 17:54:59Z $ + * $Id: sbchipc.h 311371 2012-01-28 05:47:25Z $ * * Copyright (C) 1999-2011, Broadcom Corporation * @@ -1659,6 +1659,9 @@ typedef volatile struct { #define CCTRL_4330_JTAG_DISABLE 0x00000008 +#define CCTRL_43239_GPIO_SEL 0x00000002 +#define CCTRL_43239_SDIO_HOST_WAKE 0x00000004 + #define RES4313_BB_PU_RSRC 0 #define RES4313_ILP_REQ_RSRC 1 #define RES4313_XTAL_PU_RSRC 2 diff --git a/drivers/net/wireless/bcmdhd/include/wlioctl.h b/drivers/net/wireless/bcmdhd/include/wlioctl.h index e31bfa94c006..91274a0c680b 100644 --- a/drivers/net/wireless/bcmdhd/include/wlioctl.h +++ b/drivers/net/wireless/bcmdhd/include/wlioctl.h @@ -24,7 +24,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wlioctl.h 307468 2012-01-11 18:29:27Z $ + * $Id: wlioctl.h 312596 2012-02-03 02:53:30Z $ */ @@ -1213,7 +1213,7 @@ typedef struct { #define WL_AUTH_OPEN_SYSTEM 0 #define WL_AUTH_SHARED_KEY 1 -#define WL_AUTH_OPEN_SHARED 3 +#define WL_AUTH_OPEN_SHARED 2 #define WL_RADIO_SW_DISABLE (1<<0) diff --git a/drivers/net/wireless/bcmdhd/wl_android.c b/drivers/net/wireless/bcmdhd/wl_android.c index 2cbe333b0dd6..8f6b1988180e 100644 --- a/drivers/net/wireless/bcmdhd/wl_android.c +++ b/drivers/net/wireless/bcmdhd/wl_android.c @@ -223,7 +223,7 @@ static int wl_android_get_band(struct net_device *dev, char *command, int total_ return bytes_written; } -#ifdef PNO_SUPPORT +#if defined(PNO_SUPPORT) && !defined(WL_SCHED_SCAN) static int wl_android_set_pno_setup(struct net_device *dev, char *command, int total_len) { wlc_ssid_t ssids_local[MAX_PFN_LIST_COUNT]; @@ -329,7 +329,7 @@ static int wl_android_set_pno_setup(struct net_device *dev, char *command, int t exit_proc: return res; } -#endif /* PNO_SUPPORT */ +#endif /* PNO_SUPPORT && !WL_SCHED_SCAN */ static int wl_android_get_p2p_dev_addr(struct net_device *ndev, char *command, int total_len) { @@ -516,7 +516,7 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) char *country_code = command + strlen(CMD_COUNTRY) + 1; bytes_written = wldev_set_country(net, country_code); } -#ifdef PNO_SUPPORT +#if defined(PNO_SUPPORT) && !defined(WL_SCHED_SCAN) else if (strnicmp(command, CMD_PNOSSIDCLR_SET, strlen(CMD_PNOSSIDCLR_SET)) == 0) { bytes_written = dhd_dev_pno_reset(net); } diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c index 125888d028fa..c910fc59407b 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c @@ -202,7 +202,8 @@ static s32 wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_pmksa *pmksa); static s32 wl_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *dev); -static void wl_notify_escan_complete(struct wl_priv *wl, struct net_device *ndev, bool aborted); +static s32 wl_notify_escan_complete(struct wl_priv *wl, + struct net_device *ndev, bool aborted, bool fw_abort); /* * event & event Q handlers for cfg80211 interfaces */ @@ -236,8 +237,15 @@ static s32 wl_bss_roaming_done(struct wl_priv *wl, struct net_device *ndev, const wl_event_msg_t *e, void *data); static s32 wl_notify_mic_status(struct wl_priv *wl, struct net_device *ndev, const wl_event_msg_t *e, void *data); +#ifdef WL_SCHED_SCAN +static s32 +wl_notify_sched_scan_results(struct wl_priv *wl, struct net_device *ndev, + const wl_event_msg_t *e, void *data); +#endif /* WL_SCHED_SCAN */ +#ifdef PNO_SUPPORT static s32 wl_notify_pfn_status(struct wl_priv *wl, struct net_device *ndev, const wl_event_msg_t *e, void *data); +#endif /* PNO_SUPPORT */ /* * register/deregister parent device */ @@ -516,11 +524,11 @@ static struct ieee80211_supported_band __wl_band_2ghz = { * doesn't match with the IE present in the 3/4 EAPOL msg. */ .ht_cap = { - IEEE80211_HT_CAP_SGI_20 | - IEEE80211_HT_CAP_DSSSCCK40 | IEEE80211_HT_CAP_MAX_AMSDU, - .ht_supported = TRUE, - .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K, - .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16 + IEEE80211_HT_CAP_SGI_20 | + IEEE80211_HT_CAP_DSSSCCK40 | IEEE80211_HT_CAP_MAX_AMSDU, + .ht_supported = TRUE, + .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K, + .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16 } #endif }; @@ -530,7 +538,22 @@ static struct ieee80211_supported_band __wl_band_5ghz_a = { .channels = __wl_5ghz_a_channels, .n_channels = ARRAY_SIZE(__wl_5ghz_a_channels), .bitrates = wl_a_rates, - .n_bitrates = wl_a_rates_size + .n_bitrates = wl_a_rates_size, +#if ENABLE_P2P_INTERFACE + /* wpa_supplicant sets wmm_enabled based on whether ht_cap + * is present or not. The wmm_enabled is inturn used to + * set the replay counters in the RSN IE. Without this + * the 4way handshake will fail complaining that IE in beacon + * doesn't match with the IE present in the 3/4 EAPOL msg. + */ + .ht_cap = { + IEEE80211_HT_CAP_SGI_20 | + IEEE80211_HT_CAP_DSSSCCK40 | IEEE80211_HT_CAP_MAX_AMSDU, + .ht_supported = TRUE, + .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K, + .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16 + } +#endif }; static const u32 __wl_cipher_suites[] = { @@ -918,8 +941,8 @@ wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev) if (wl->p2p_supported) { memcpy(p2p_mac.octet, wl->p2p->int_addr.octet, ETHER_ADDR_LEN); if (wl->p2p->vif_created) { - if (wl_get_drv_status(wl, SCANNING, dev)) { - wl_cfg80211_scan_abort(wl, dev); + if (wl->scan_request) { + wl_notify_escan_complete(wl, dev, true, true); } wldev_iovar_setint(dev, "mpc", 1); wl_set_p2p_status(wl, IF_DELETING); @@ -1088,7 +1111,7 @@ wl_cfg80211_notify_ifdel(struct net_device *ndev) rollback_lock = true; } WL_DBG(("ESCAN COMPLETED\n")); - wl_notify_escan_complete(wl, ndev, true); + wl_notify_escan_complete(wl, ndev, true, false); if (rollback_lock) rtnl_unlock(); } @@ -1508,7 +1531,7 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, wpa_ie_fixed_t *wps_ie; s32 passive_scan; bool iscan_req; - bool escan_req; + bool escan_req = false; bool p2p_ssid; s32 err = 0; s32 i; @@ -1907,21 +1930,21 @@ wl_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme) s32 bssidx = wl_cfgp2p_find_idx(wl, dev); switch (sme->auth_type) { case NL80211_AUTHTYPE_OPEN_SYSTEM: - val = 0; + val = WL_AUTH_OPEN_SYSTEM; WL_DBG(("open system\n")); break; case NL80211_AUTHTYPE_SHARED_KEY: - val = 1; + val = WL_AUTH_SHARED_KEY; WL_DBG(("shared key\n")); break; case NL80211_AUTHTYPE_AUTOMATIC: - val = 2; + val = WL_AUTH_OPEN_SHARED; WL_DBG(("automatic\n")); break; case NL80211_AUTHTYPE_NETWORK_EAP: WL_DBG(("network eap\n")); default: - val = 2; + val = WL_AUTH_OPEN_SHARED; WL_ERR(("invalid auth type (%d)\n", sme->auth_type)); break; } @@ -2119,9 +2142,9 @@ wl_set_set_sharedkey(struct net_device *dev, WL_ERR(("WLC_SET_KEY error (%d)\n", err)); return err; } - if (sec->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) { + if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) { WL_DBG(("set auth_type to shared key\n")); - val = 1; /* shared key */ + val = WL_AUTH_SHARED_KEY; /* shared key */ err = wldev_iovar_setint_bsscfg(dev, "auth", val, bssidx); if (unlikely(err)) { WL_ERR(("set auth failed (%d)\n", err)); @@ -2160,7 +2183,7 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, * Cancel ongoing scan to sync up with sme state machine of cfg80211. */ if (wl->scan_request) { - wl_cfg80211_scan_abort(wl, dev); + wl_notify_escan_complete(wl, dev, true, true); } /* Clean BSSID */ bzero(&bssid, sizeof(bssid)); @@ -2382,7 +2405,7 @@ wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, * Cancel ongoing scan to sync up with sme state machine of cfg80211. */ if (wl->scan_request) { - wl_cfg80211_scan_abort(wl, dev); + wl_notify_escan_complete(wl, dev, true, true); } wl_set_drv_status(wl, DISCONNECTING, dev); scbval.val = reason_code; @@ -2581,9 +2604,6 @@ wl_add_keyext(struct wiphy *wiphy, struct net_device *dev, return -EINVAL; } swap_key_from_BE(&key); -#if defined(CONFIG_WIRELESS_EXT) - dhd_wait_pend8021x(dev); -#endif wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); if (unlikely(err)) { @@ -2831,42 +2851,42 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, sta->idle * 1000)); #endif } else if (wl_get_mode_by_netdev(wl, dev) == WL_MODE_BSS) { - u8 *curmacp = wl_read_prof(wl, dev, WL_PROF_BSSID); - if (!wl_get_drv_status(wl, CONNECTED, dev) || - (dhd_is_associated(dhd, NULL) == FALSE)) { - WL_ERR(("NOT assoc\n")); - err = -ENODEV; - goto get_station_err; - } - if (memcmp(mac, curmacp, ETHER_ADDR_LEN)) { - WL_ERR(("Wrong Mac address: "MACSTR" != "MACSTR"\n", - MAC2STR(mac), MAC2STR(curmacp))); - } + u8 *curmacp = wl_read_prof(wl, dev, WL_PROF_BSSID); + if (!wl_get_drv_status(wl, CONNECTED, dev) || + (dhd_is_associated(dhd, NULL) == FALSE)) { - /* Report the current tx rate */ - err = wldev_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate), false); - if (err) { - WL_ERR(("Could not get rate (%d)\n", err)); - } else { - rate = dtoh32(rate); - sinfo->filled |= STATION_INFO_TX_BITRATE; - sinfo->txrate.legacy = rate * 5; - WL_DBG(("Rate %d Mbps\n", (rate / 2))); - } + WL_ERR(("NOT assoc\n")); + err = -ENODEV; + goto get_station_err; + } + if (memcmp(mac, curmacp, ETHER_ADDR_LEN)) { + WL_ERR(("Wrong Mac address: "MACSTR" != "MACSTR"\n", + MAC2STR(mac), MAC2STR(curmacp))); + } - memset(&scb_val, 0, sizeof(scb_val)); - scb_val.val = 0; - err = wldev_ioctl(dev, WLC_GET_RSSI, &scb_val, - sizeof(scb_val_t), false); - if (err) { - WL_ERR(("Could not get rssi (%d)\n", err)); - goto get_station_err; - } + /* Report the current tx rate */ + err = wldev_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate), false); + if (err) { + WL_ERR(("Could not get rate (%d)\n", err)); + } else { + rate = dtoh32(rate); + sinfo->filled |= STATION_INFO_TX_BITRATE; + sinfo->txrate.legacy = rate * 5; + WL_DBG(("Rate %d Mbps\n", (rate / 2))); + } - rssi = dtoh32(scb_val.val); - sinfo->filled |= STATION_INFO_SIGNAL; - sinfo->signal = rssi; - WL_DBG(("RSSI %d dBm\n", rssi)); + memset(&scb_val, 0, sizeof(scb_val)); + scb_val.val = 0; + err = wldev_ioctl(dev, WLC_GET_RSSI, &scb_val, + sizeof(scb_val_t), false); + if (err) { + WL_ERR(("Could not get rssi (%d)\n", err)); + goto get_station_err; + } + rssi = dtoh32(scb_val.val); + sinfo->filled |= STATION_INFO_SIGNAL; + sinfo->signal = rssi; + WL_DBG(("RSSI %d dBm\n", rssi)); get_station_err: if (err) { @@ -3009,8 +3029,8 @@ wl_update_pmklist(struct net_device *dev, struct wl_pmk_list *pmk_list, return -EINVAL; } /* pmk list is supported only for STA interface i.e. primary interface - * Refer code wlc_bsscfg.c->wlc_bsscfg_sta_init - */ + * Refer code wlc_bsscfg.c->wlc_bsscfg_sta_init + */ if (primary_dev != dev) { WL_INFO(("Not supporting Flushing pmklist on virtual" " interfaces than primary interface\n")); @@ -3173,8 +3193,21 @@ wl_cfg80211_scan_abort(struct wl_priv *wl, struct net_device *ndev) s32 params_size = 0; s32 err = BCME_OK; unsigned long flags; + struct net_device *dev; WL_DBG(("Enter\n")); + if (wl->scan_request) { + if (wl->scan_request->dev == wl->p2p_net) + dev = wl_to_prmry_ndev(wl); + else + dev = wl->scan_request->dev; + } + else { + WL_ERR(("wl->scan_request is NULL did we already do scan_abort?" + "Now scan_abort for ndev %p primary %p p2p_net %p", + ndev, wl_to_prmry_ndev(wl), wl->p2p_net)); + dev = ndev; + } /* Our scan params only need space for 1 channel and 0 ssids */ params = wl_cfg80211_scan_alloc_params(-1, 0, ¶ms_size); @@ -3183,18 +3216,26 @@ wl_cfg80211_scan_abort(struct wl_priv *wl, struct net_device *ndev) err = -ENOMEM; } else { /* Do a scan abort to stop the driver's scan engine */ - err = wldev_ioctl(ndev, WLC_SCAN, params, params_size, true); + err = wldev_ioctl(dev, WLC_SCAN, params, params_size, true); if (err < 0) { WL_ERR(("scan abort failed \n")); } } del_timer_sync(&wl->scan_timeout); spin_lock_irqsave(&wl->cfgdrv_lock, flags); + +#ifdef WL_SCHED_SCAN + if (wl->sched_scan_req && !wl->scan_request) { + cfg80211_sched_scan_stopped(wl_to_wiphy(wl)); + wl->sched_scan_req = NULL; + } +#endif /* WL_SCHED_SCAN */ + if (wl->scan_request) { cfg80211_scan_done(wl->scan_request, true); wl->scan_request = NULL; } - wl_clr_drv_status(wl, SCANNING, ndev); + wl_clr_drv_status(wl, SCANNING, dev); spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); if (params) kfree(params); @@ -3222,10 +3263,9 @@ wl_cfg80211_remain_on_channel(struct wiphy *wiphy, struct net_device *dev, ndev = dev; } - if (wl_get_drv_status(wl, SCANNING, ndev)) { - wl_cfg80211_scan_abort(wl, ndev); + if (wl->scan_request) { + wl_notify_escan_complete(wl, ndev, true, true); } - target_channel = ieee80211_frequency_to_channel(channel->center_freq); memcpy(&wl->remain_on_chan, channel, sizeof(struct ieee80211_channel)); wl->remain_on_chan_type = channel_type; @@ -3288,7 +3328,7 @@ wl_cfg80211_send_pending_tx_act_frm(struct wl_priv *wl) */ wl_clr_drv_status(wl, SENDING_ACT_FRM, wl->afx_hdl->dev); wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev); - wl_cfg80211_scan_abort(wl, dev); + wl_notify_escan_complete(wl, dev, true, true); wl_cfgp2p_discover_enable_search(wl, false); tx_act_frm->channel = wl->afx_hdl->peer_chan; wl->afx_hdl->ack_recv = (wl_cfgp2p_tx_action_frame(wl, dev, @@ -3442,8 +3482,8 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, scb_val.val = mgmt->u.disassoc.reason_code; wldev_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val, sizeof(scb_val_t), true); - WL_DBG(("Disconnect STA : %s\n", - bcm_ether_ntoa((const struct ether_addr *)mgmt->da, eabuf))); + WL_DBG(("Disconnect STA : %s scb_val.val %d\n", + bcm_ether_ntoa((const struct ether_addr *)mgmt->da, eabuf), scb_val.val)); cfg80211_mgmt_tx_status(ndev, *cookie, buf, len, true, GFP_KERNEL); goto exit; @@ -3455,7 +3495,7 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, * tx is still in progress (including the dwell time), * then this new action frame will not be sent out. */ - wl_cfg80211_scan_abort(wl, dev); + wl_notify_escan_complete(wl, dev, true, true); } @@ -3490,6 +3530,7 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, ieee80211_frequency_to_channel(channel->center_freq); if (channel->band == IEEE80211_BAND_5GHZ) { + WL_DBG(("5GHz channel %d", af_params->channel)); err = wldev_ioctl(dev, WLC_SET_CHANNEL, &af_params->channel, sizeof(af_params->channel), true); if (err < 0) { @@ -3653,7 +3694,7 @@ wl_validate_wpa2ie(struct net_device *dev, bcm_tlv_t *wpa2ie, s32 bssidx) { s32 len = 0; s32 err = BCME_OK; - u16 auth = 0; /* d11 open authentication */ + u16 auth = WL_AUTH_OPEN_SYSTEM; /* d11 open authentication */ u32 wsec; u32 pval = 0; u32 gval = 0; @@ -3757,7 +3798,7 @@ wl_validate_wpaie(struct net_device *dev, wpa_ie_fixed_t *wpaie, s32 bssidx) wpa_suite_mcast_t *mcast; wpa_suite_ucast_t *ucast; wpa_suite_auth_key_mgmt_t *mgmt; - u16 auth = 0; /* d11 open authentication */ + u16 auth = WL_AUTH_OPEN_SYSTEM; /* d11 open authentication */ u16 count; s32 err = BCME_OK; s32 len = 0; @@ -4080,7 +4121,7 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev, memcpy(beacon_ie, wps_ie, wpsie_len); wl_cfgp2p_set_management_ie(wl, dev, bssidx, VNDR_IE_BEACON_FLAG, beacon_ie, wpsie_len); - wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL); + wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL); /* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */ wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc); } else { @@ -4133,12 +4174,12 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev, memcmp(wl->ap_info->wps_ie, wps_ie, wpsie_len)) { WL_DBG((" WPS IE is changed\n")); kfree(wl->ap_info->wps_ie); - wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL); + wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL); /* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */ wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc); } else if (wl->ap_info->wps_ie == NULL) { WL_DBG((" WPS IE is added\n")); - wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL); + wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL); /* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */ wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc); } @@ -4224,6 +4265,105 @@ exit: return err; } +#ifdef WL_SCHED_SCAN +#define PNO_TIME 30 +#define PNO_REPEAT 4 +#define PNO_FREQ_EXPO_MAX 3 +int wl_cfg80211_sched_scan_start(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_sched_scan_request *request) +{ + ushort pno_time = PNO_TIME; + int pno_repeat = PNO_REPEAT; + int pno_freq_expo_max = PNO_FREQ_EXPO_MAX; + wlc_ssid_t ssids_local[MAX_PFN_LIST_COUNT]; + struct wl_priv *wl = wiphy_priv(wiphy); + struct cfg80211_ssid *ssid = NULL; + int ssid_count = 0; + int i; + int ret = 0; + + WL_DBG(("Enter n_match_sets:%d n_ssids:%d \n", + request->n_match_sets, request->n_ssids)); + WL_DBG(("ssids:%d pno_time:%d pno_repeat:%d pno_freq:%d \n", + request->n_ssids, pno_time, pno_repeat, pno_freq_expo_max)); + + if (wl_get_drv_status_all(wl, SCANNING)) { + WL_ERR(("Scanning already\n")); + return -EAGAIN; + } + + if (!request || !request->n_ssids || !request->n_match_sets) { + WL_ERR(("Invalid sched scan req!! n_ssids:%d \n", request->n_ssids)); + return -EINVAL; + } + + memset(&ssids_local, 0, sizeof(ssids_local)); + + if (request->n_match_sets > 0) { + for (i = 0; i < request->n_match_sets; i++) { + ssid = &request->match_sets[i].ssid; + memcpy(ssids_local[i].SSID, ssid->ssid, ssid->ssid_len); + ssids_local[i].SSID_len = ssid->ssid_len; + WL_DBG((">>> PNO filter set for ssid (%s) \n", ssid->ssid)); + ssid_count++; + } + } + + if (request->n_ssids > 0) { + for (i = 0; i < request->n_ssids; i++) { + /* Active scan req for ssids */ + WL_DBG((">>> Active scan req for ssid (%s) \n", request->ssids[i].ssid)); + + /* match_set ssids is a supert set of n_ssid list, so we need + * not add these set seperately + */ + } + } + + if (ssid_count) { + if ((ret = dhd_dev_pno_set(dev, ssids_local, request->n_match_sets, + pno_time, pno_repeat, pno_freq_expo_max)) < 0) { + WL_ERR(("PNO setup failed!! ret=%d \n", ret)); + return -EINVAL; + } + + /* Enable the PNO */ + if (dhd_dev_pno_enable(dev, 1) < 0) { + WL_ERR(("PNO enable failed!! ret=%d \n", ret)); + return -EINVAL; + } + wl->sched_scan_req = request; + } else { + return -EINVAL; + } + + return 0; +} + +int wl_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev) +{ + struct wl_priv *wl = wiphy_priv(wiphy); + + WL_DBG(("Enter \n")); + + if (dhd_dev_pno_enable(dev, 0) < 0) + WL_ERR(("PNO disable failed")); + + if (dhd_dev_pno_reset(dev) < 0) + WL_ERR(("PNO reset failed")); + + if (wl->scan_request && wl->sched_scan_running) { + wl_cfg80211_scan_abort(wl, dev); + } + + wl->sched_scan_req = NULL; + wl->sched_scan_running = FALSE; + + return 0; +} +#endif /* WL_SCHED_SCAN */ + static struct cfg80211_ops wl_cfg80211_ops = { .add_virtual_intf = wl_cfg80211_add_virtual_iface, .del_virtual_intf = wl_cfg80211_del_virtual_iface, @@ -4256,6 +4396,10 @@ static struct cfg80211_ops wl_cfg80211_ops = { .set_channel = wl_cfg80211_set_channel, .set_beacon = wl_cfg80211_add_set_beacon, .add_beacon = wl_cfg80211_add_set_beacon, +#ifdef WL_SCHED_SCAN + .sched_scan_start = wl_cfg80211_sched_scan_start, + .sched_scan_stop = wl_cfg80211_sched_scan_stop, +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) */ }; s32 wl_mode_to_nl80211_iftype(s32 mode) @@ -4291,12 +4435,18 @@ static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev /* Report how many SSIDs Driver can support per Scan request */ wdev->wiphy->max_scan_ssids = WL_SCAN_PARAMS_SSID_MAX; wdev->wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX; +#ifdef WL_SCHED_SCAN + wdev->wiphy->max_sched_scan_ssids = MAX_PFN_LIST_COUNT; + wdev->wiphy->max_match_sets = MAX_PFN_LIST_COUNT; + wdev->wiphy->max_sched_scan_ie_len = WL_SCAN_IE_LEN_MAX; + wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; +#endif /* WL_SCHED_SCAN */ wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_MONITOR); wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; - wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; + /* wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; - set in runtime */ wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; wdev->wiphy->cipher_suites = __wl_cipher_suites; wdev->wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites); @@ -4314,7 +4464,7 @@ static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev #endif WIPHY_FLAG_4ADDR_STATION; #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) - wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM; + wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM; #endif WL_DBG(("Registering custom regulatory)\n")); wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; @@ -4469,7 +4619,7 @@ static bool wl_is_linkup(struct wl_priv *wl, const wl_event_msg_t *e, struct net u32 status = ntoh32(e->status); u16 flags = ntoh16(e->flags); - WL_DBG(("event %d, status %d\n", event, status)); + WL_DBG(("event %d, status %d flags %x\n", event, status, flags)); if (event == WLC_E_SET_SSID) { if (status == WLC_E_STATUS_SUCCESS) { if (!wl_is_ibssmode(wl, ndev)) @@ -4552,7 +4702,7 @@ wl_notify_connect_status_ap(struct wl_priv *wl, struct net_device *ndev, #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !CFG80211_STA_EVENT_AVAILABLE memset(body, 0, sizeof(body)); memset(&bssid, 0, ETHER_ADDR_LEN); - WL_DBG(("Enter \n")); + WL_DBG(("Enter event %d ndev %p\n", event, ndev)); if (wl_get_mode_by_netdev(wl, ndev) == WL_INVALID) return WL_INVALID; @@ -4646,8 +4796,8 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, if (wl_get_mode_by_netdev(wl, ndev) == WL_MODE_AP) { wl_notify_connect_status_ap(wl, ndev, e, data); } else { - WL_DBG(("wl_notify_connect_status : event %d status : %d \n", - ntoh32(e->event_type), ntoh32(e->status))); + WL_DBG(("wl_notify_connect_status : event %d status : %d ndev %p\n", + ntoh32(e->event_type), ntoh32(e->status), ndev)); if (wl_is_linkup(wl, e, ndev)) { wl_link_up(wl); act = true; @@ -4670,30 +4820,34 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, } else if (wl_is_linkdown(wl, e)) { if (wl->scan_request) { - del_timer_sync(&wl->scan_timeout); if (wl->escan_on) { - wl_notify_escan_complete(wl, ndev, true); - } else + wl_notify_escan_complete(wl, ndev, true, true); + } else { + del_timer_sync(&wl->scan_timeout); wl_iscan_aborted(wl); + } } if (wl_get_drv_status(wl, CONNECTED, ndev)) { scb_val_t scbval; u8 *curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID); printk("link down, call cfg80211_disconnected\n"); wl_clr_drv_status(wl, CONNECTED, ndev); - /* To make sure disconnect, explictly send dissassoc - * for BSSID 00:00:00:00:00:00 issue - */ - scbval.val = WLAN_REASON_DEAUTH_LEAVING; - - memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN); - scbval.val = htod32(scbval.val); - wldev_ioctl(ndev, WLC_DISASSOC, &scbval, - sizeof(scb_val_t), true); - cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL); - wl_link_down(wl); - wl_init_prof(wl, ndev); - } else if (wl_get_drv_status(wl, CONNECTING, ndev)) { + if (! wl_get_drv_status(wl, DISCONNECTING, ndev)) { + /* To make sure disconnect, explictly send dissassoc + * for BSSID 00:00:00:00:00:00 issue + */ + scbval.val = WLAN_REASON_DEAUTH_LEAVING; + + memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN); + scbval.val = htod32(scbval.val); + wldev_ioctl(ndev, WLC_DISASSOC, &scbval, + sizeof(scb_val_t), true); + cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL); + wl_link_down(wl); + wl_init_prof(wl, ndev); + } + } + else if (wl_get_drv_status(wl, CONNECTING, ndev)) { printk("link down, during connecting\n"); wl_bss_connect_done(wl, ndev, e, data, false); } @@ -4704,11 +4858,12 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, event, (int)ntoh32(e->status)); /* Clean up any pending scan request */ if (wl->scan_request) { - del_timer_sync(&wl->scan_timeout); if (wl->escan_on) { - wl_notify_escan_complete(wl, ndev, true); - } else + wl_notify_escan_complete(wl, ndev, true, true); + } else { + del_timer_sync(&wl->scan_timeout); wl_iscan_aborted(wl); + } } if (wl_get_drv_status(wl, CONNECTING, ndev)) wl_bss_connect_done(wl, ndev, e, data, false); @@ -4857,6 +5012,7 @@ static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev) u8 *curbssid; s32 err = 0; struct wiphy *wiphy; + wiphy = wl_to_wiphy(wl); if (wl_is_ibssmode(wl, ndev)) @@ -4960,7 +5116,7 @@ wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev, WL_DBG((" enter\n")); if (wl->scan_request) { - wl_cfg80211_scan_abort(wl, ndev); + wl_notify_escan_complete(wl, ndev, true, true); } if (wl_get_drv_status(wl, CONNECTING, ndev)) { wl_clr_drv_status(wl, CONNECTING, ndev); @@ -5008,6 +5164,7 @@ wl_notify_mic_status(struct wl_priv *wl, struct net_device *ndev, return 0; } +#ifdef PNO_SUPPORT static s32 wl_notify_pfn_status(struct wl_priv *wl, struct net_device *ndev, const wl_event_msg_t *e, void *data) @@ -5015,11 +5172,19 @@ wl_notify_pfn_status(struct wl_priv *wl, struct net_device *ndev, WL_ERR((" PNO Event\n")); mutex_lock(&wl->usr_sync); +#ifndef WL_SCHED_SCAN /* TODO: Use cfg80211_sched_scan_results(wiphy); */ cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL); +#else + /* If cfg80211 scheduled scan is supported, report the pno results via sched + * scan results + */ + wl_notify_sched_scan_results(wl, ndev, e, data); +#endif /* WL_SCHED_SCAN */ mutex_unlock(&wl->usr_sync); return 0; } +#endif /* PNO_SUPPORT */ static s32 wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev, @@ -5199,7 +5364,7 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev, * After complete GO Negotiation, roll back to mpc mode */ if (act_frm && ((act_frm->subtype == P2P_PAF_GON_CONF) || - (act_frm->subtype == P2P_PAF_PROVDIS_RSP))) { + (act_frm->subtype == P2P_PAF_PROVDIS_RSP))) { wldev_iovar_setint(dev, "mpc", 1); } } else { @@ -5217,6 +5382,127 @@ exit: return 0; } +#ifdef WL_SCHED_SCAN +/* If target scan is not reliable, set the below define to "0" to do a + * full escan + */ +#define FULL_ESCAN_ON_PFN_NET_FOUND 1 +static s32 +wl_notify_sched_scan_results(struct wl_priv *wl, struct net_device *ndev, + const wl_event_msg_t *e, void *data) +{ + wl_pfn_net_info_t *netinfo, *pnetinfo; + struct cfg80211_scan_request request; + struct wiphy *wiphy = wl_to_wiphy(wl); + int err = 0; + struct cfg80211_ssid ssid[MAX_PFN_LIST_COUNT]; + struct ieee80211_channel *channel = NULL; + int channel_req = 0; + int band = 0; + struct wl_pfn_scanresults *pfn_result = (struct wl_pfn_scanresults *)data; + + WL_DBG(("Enter\n")); + + if (e->event_type == WLC_E_PFN_NET_LOST) { + WL_DBG(("PFN NET LOST event. Do Nothing \n")); + return 0; + } else { + WL_DBG(("PFN NET FOUND event. count:%d \n", pfn_result->count)); + + + if (pfn_result->count > 0) { + int i; + + memset(&request, 0x00, sizeof(struct cfg80211_scan_request)); + memset(&ssid, 0x00, sizeof(ssid)); + request.wiphy = wiphy; + + pnetinfo = (wl_pfn_net_info_t *)(data + sizeof(wl_pfn_scanresults_t) + - sizeof(wl_pfn_net_info_t)); + + channel = (struct ieee80211_channel *)kzalloc( + (sizeof(struct ieee80211_channel) * MAX_PFN_LIST_COUNT), + GFP_KERNEL); + if (!channel) { + WL_ERR(("No memory")); + err = -ENOMEM; + goto out_err; + } + + for (i = 0; i < pfn_result->count; i++) { + netinfo = &pnetinfo[i]; + if (!netinfo) { + WL_ERR(("Invalid netinfo ptr. index:%d", i)); + err = -EINVAL; + goto out_err; + } + + WL_DBG(("SSID:%s Channel:%d \n", + netinfo->pfnsubnet.SSID, netinfo->pfnsubnet.channel)); + /* PFN result doesn't have all the info which are required by the supplicant + * (For e.g IEs) Do a target Escan so that sched scan results are reported + * via wl_inform_single_bss in the required format. Escan does require the + * scan request in the form of cfg80211_scan_request. For timebeing, create + * cfg80211_scan_request one out of the received PNO event. + */ + memcpy(ssid[i].ssid, netinfo->pfnsubnet.SSID, + netinfo->pfnsubnet.SSID_len); + ssid[i].ssid_len = netinfo->pfnsubnet.SSID_len; + request.n_ssids++; + + channel_req = netinfo->pfnsubnet.channel; + band = (channel_req <= CH_MAX_2G_CHANNEL) ? NL80211_BAND_2GHZ + : NL80211_BAND_2GHZ; + channel[i].center_freq = ieee80211_channel_to_frequency(channel_req, band); + channel[i].band = band; + channel[i].flags |= IEEE80211_CHAN_NO_HT40; + request.channels[i] = &channel[i]; + request.n_channels++; + } + + /* assign parsed ssid array */ + if (request.n_ssids) + request.ssids = &ssid[0]; + + if (wl_get_drv_status_all(wl, SCANNING)) { + /* Abort any on-going scan */ + wl_cfg80211_scan_abort(wl, ndev); + } + + if (wl_get_p2p_status(wl, DISCOVERY_ON)) { + err = wl_cfgp2p_discover_enable_search(wl, false); + if (unlikely(err)) { + wl_clr_drv_status(wl, SCANNING, ndev); + goto out_err; + } + } + + wl_set_drv_status(wl, SCANNING, ndev); +#if FULL_ESCAN_ON_PFN_NET_FOUND + err = wl_do_escan(wl, wiphy, ndev, &request); +#else + err = wl_do_escan(wl, wiphy, ndev, NULL); +#endif + if (err) { + wl_clr_drv_status(wl, SCANNING, ndev); + goto out_err; + } + } else { + WL_ERR(("FALSE PNO Event. (pfn_count == 0) \n")); + } + wl->sched_scan_running = TRUE; + } + + kfree(channel); + return 0; + +out_err: + if (channel) + kfree(channel); + return err; +} +#endif /* WL_SCHED_SCAN */ + static void wl_init_conf(struct wl_conf *conf) { WL_DBG(("Enter \n")); @@ -5257,7 +5543,9 @@ static void wl_init_event_handler(struct wl_priv *wl) wl->evt_handler[WLC_E_P2P_DISC_LISTEN_COMPLETE] = wl_cfgp2p_listen_complete; wl->evt_handler[WLC_E_ACTION_FRAME_COMPLETE] = wl_cfgp2p_action_tx_complete; wl->evt_handler[WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE] = wl_cfgp2p_action_tx_complete; +#ifdef PNO_SUPPORT wl->evt_handler[WLC_E_PFN_NET_FOUND] = wl_notify_pfn_status; +#endif /* PNO_SUPPORT */ } static s32 wl_init_priv_mem(struct wl_priv *wl) @@ -5559,7 +5847,7 @@ static void wl_scan_timeout(unsigned long data) if (wl->scan_request) { WL_ERR(("timer expired\n")); if (wl->escan_on) - wl_notify_escan_complete(wl, wl->escan_info.ndev, true); + wl_notify_escan_complete(wl, wl->escan_info.ndev, true, true); else wl_notify_iscan_complete(wl_to_iscan(wl), true); } @@ -5629,23 +5917,70 @@ static struct notifier_block wl_cfg80211_netdev_notifier = { .notifier_call = wl_cfg80211_netdev_notifier_call, }; -static void wl_notify_escan_complete(struct wl_priv *wl, +static s32 wl_notify_escan_complete(struct wl_priv *wl, struct net_device *ndev, - bool aborted) + bool aborted, bool fw_abort) { + wl_scan_params_t *params = NULL; + s32 params_size = 0; + s32 err = BCME_OK; unsigned long flags; + struct net_device *dev; WL_DBG(("Enter \n")); - wl_clr_drv_status(wl, SCANNING, ndev); - if (p2p_is_on(wl)) - wl_clr_p2p_status(wl, SCANNING); + + if (wl->scan_request) { + if (wl->scan_request->dev == wl->p2p_net) + dev = wl_to_prmry_ndev(wl); + else + dev = wl->scan_request->dev; + } + else { + WL_ERR(("wl->scan_request is NULL may be internal scan." + "doing scan_abort for ndev %p primary %p p2p_net %p", + ndev, wl_to_prmry_ndev(wl), wl->p2p_net)); + dev = ndev; + } + if (fw_abort) { + /* Our scan params only need space for 1 channel and 0 ssids */ + params = wl_cfg80211_scan_alloc_params(-1, 0, ¶ms_size); + if (params == NULL) { + WL_ERR(("scan params allocation failed \n")); + err = -ENOMEM; + } else { + /* Do a scan abort to stop the driver's scan engine */ + err = wldev_ioctl(dev, WLC_SCAN, params, params_size, true); + if (err < 0) { + WL_ERR(("scan abort failed \n")); + } + } + } + del_timer_sync(&wl->scan_timeout); spin_lock_irqsave(&wl->cfgdrv_lock, flags); + +#ifdef WL_SCHED_SCAN + if (wl->sched_scan_req && wl->sched_scan_running && !wl->scan_request) { + WL_DBG((" REPORTING SCHED SCAN RESULTS \n")); + cfg80211_sched_scan_results(wl->sched_scan_req->wiphy); + wl->sched_scan_running = FALSE; + wl->sched_scan_req = NULL; + wl->scan_request = NULL; + } +#endif /* WL_SCHED_SCAN */ + if (likely(wl->scan_request)) { cfg80211_scan_done(wl->scan_request, aborted); wl->scan_request = NULL; } + if (p2p_is_on(wl)) + wl_clr_p2p_status(wl, SCANNING); + wl_clr_drv_status(wl, SCANNING, dev); spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); + if (params) + kfree(params); + + return err; } static s32 wl_escan_handler(struct wl_priv *wl, @@ -5769,13 +6104,12 @@ static s32 wl_escan_handler(struct wl_priv *wl, wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev); if (wl->afx_hdl->peer_chan == WL_INVALID) complete(&wl->act_frm_scan); - } else if (likely(wl->scan_request)) { + } else if ((likely(wl->scan_request)) || (wl->sched_scan_running)) { mutex_lock(&wl->usr_sync); - del_timer_sync(&wl->scan_timeout); WL_INFO(("ESCAN COMPLETED\n")); wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf; wl_inform_bss(wl); - wl_notify_escan_complete(wl, ndev, false); + wl_notify_escan_complete(wl, ndev, false, false); mutex_unlock(&wl->usr_sync); } } @@ -5787,13 +6121,12 @@ static s32 wl_escan_handler(struct wl_priv *wl, wl_clr_p2p_status(wl, SCANNING); if (wl->afx_hdl->peer_chan == WL_INVALID) complete(&wl->act_frm_scan); - } else if (likely(wl->scan_request)) { + } else if ((likely(wl->scan_request)) || (wl->sched_scan_running)) { mutex_lock(&wl->usr_sync); - del_timer_sync(&wl->scan_timeout); WL_INFO(("ESCAN ABORTED\n")); wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf; wl_inform_bss(wl); - wl_notify_escan_complete(wl, ndev, true); + wl_notify_escan_complete(wl, ndev, true, false); mutex_unlock(&wl->usr_sync); } } @@ -5806,12 +6139,11 @@ static s32 wl_escan_handler(struct wl_priv *wl, wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev); if (wl->afx_hdl->peer_chan == WL_INVALID) complete(&wl->act_frm_scan); - } else if (likely(wl->scan_request)) { + } else if ((likely(wl->scan_request)) || (wl->sched_scan_running)) { mutex_lock(&wl->usr_sync); - del_timer_sync(&wl->scan_timeout); wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf; wl_inform_bss(wl); - wl_notify_escan_complete(wl, ndev, true); + wl_notify_escan_complete(wl, ndev, true, false); mutex_unlock(&wl->usr_sync); } } @@ -6135,9 +6467,7 @@ static s32 wl_event_handler(void *data) tsk_ctl_t *tsk = (tsk_ctl_t *)data; wl = (struct wl_priv *)tsk->parent; - - DAEMONIZE("wl_event_handler"); - + DAEMONIZE("dhd_cfg80211_event"); complete(&tsk->completed); while (down_interruptible (&tsk->sema) == 0) { @@ -6166,7 +6496,7 @@ static s32 wl_event_handler(void *data) } DHD_OS_WAKE_UNLOCK(wl->pub); } - WL_DBG(("%s was terminated\n", __func__)); + WL_ERR(("%s was terminated\n", __func__)); complete_and_exit(&tsk->completed, 0); return 0; } @@ -6346,24 +6676,31 @@ eventmsg_out: s32 wl_update_wiphybands(struct wl_priv *wl) { struct wiphy *wiphy; - s8 phylist_buf[128]; - s8 *phy; + u32 bandlist[3]; + u32 nband = 0; + u32 i = 0; s32 err = 0; - - err = wldev_ioctl(wl_to_prmry_ndev(wl), WLC_GET_PHYLIST, phylist_buf, - sizeof(phylist_buf), false); + WL_DBG(("Entry")); + memset(bandlist, 0, sizeof(bandlist)); + err = wldev_ioctl(wl_to_prmry_ndev(wl), WLC_GET_BANDLIST, bandlist, + sizeof(bandlist), false); if (unlikely(err)) { WL_ERR(("error (%d)\n", err)); return err; } - phy = phylist_buf; - for (; *phy; phy++) { - if (*phy == 'a' || *phy == 'n') { - wiphy = wl_to_wiphy(wl); + wiphy = wl_to_wiphy(wl); + nband = bandlist[0]; + wiphy->bands[IEEE80211_BAND_5GHZ] = NULL; + wiphy->bands[IEEE80211_BAND_2GHZ] = NULL; + for (i = 1; i <= nband && i < sizeof(bandlist); i++) { + if (bandlist[i] == WLC_BAND_5G) wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; - } + else if (bandlist[i] == WLC_BAND_2G) + wiphy->bands[IEEE80211_BAND_2GHZ] = + &__wl_band_2ghz; } + wiphy_apply_custom_regulatory(wiphy, &brcm_regdom); return err; } @@ -6373,7 +6710,7 @@ static s32 __wl_cfg80211_up(struct wl_priv *wl) struct net_device *ndev = wl_to_prmry_ndev(wl); struct wireless_dev *wdev = ndev->ieee80211_ptr; - WL_TRACE(("In\n")); + WL_DBG(("In\n")); err = dhd_config_dongle(wl, false); if (unlikely(err)) @@ -6401,7 +6738,7 @@ static s32 __wl_cfg80211_down(struct wl_priv *wl) struct net_info *iter, *next; struct net_device *ndev = wl_to_prmry_ndev(wl); - WL_TRACE(("In\n")); + WL_DBG(("In\n")); /* Check if cfg80211 interface is already down */ if (!wl_get_drv_status(wl, READY, ndev)) return err; /* it is even not ready */ @@ -6443,7 +6780,7 @@ s32 wl_cfg80211_up(void *para) struct wl_priv *wl; s32 err = 0; - WL_TRACE(("In\n")); + WL_DBG(("In\n")); wl = wlcfg_drv_priv; mutex_lock(&wl->usr_sync); wl_cfg80211_attach_post(wl_to_prmry_ndev(wl)); @@ -6473,7 +6810,7 @@ s32 wl_cfg80211_down(void *para) struct wl_priv *wl; s32 err = 0; - WL_TRACE(("In\n")); + WL_DBG(("In\n")); wl = wlcfg_drv_priv; mutex_lock(&wl->usr_sync); err = __wl_cfg80211_down(wl); diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.h b/drivers/net/wireless/bcmdhd/wl_cfg80211.h index 2b8e66413f23..435d61833f1a 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.h +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.h @@ -442,6 +442,10 @@ struct wl_priv { bool p2p_supported; struct btcoex_info *btcoex_info; struct timer_list scan_timeout; /* Timer for catch scan event timeout */ +#ifdef WL_SCHED_SCAN + struct cfg80211_sched_scan_request *sched_scan_req; /* scheduled scan req */ +#endif /* WL_SCHED_SCAN */ + bool sched_scan_running; /* scheduled scan req status */ }; static inline struct wl_bss_info *next_bss(struct wl_scan_results *list, struct wl_bss_info *bss) diff --git a/drivers/net/wireless/bcmdhd/wl_iw.c b/drivers/net/wireless/bcmdhd/wl_iw.c index d09448a7932f..e724aa3ec725 100644 --- a/drivers/net/wireless/bcmdhd/wl_iw.c +++ b/drivers/net/wireless/bcmdhd/wl_iw.c @@ -162,11 +162,8 @@ uint wl_msg_level = WL_ERROR_VAL; #define htodchanspec(i) i #define dtohchanspec(i) i -#ifdef CONFIG_WIRELESS_EXT - extern struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev); extern int dhd_wait_pend8021x(struct net_device *dev); -#endif #if WIRELESS_EXT < 19 #define IW_IOCTL_IDX(cmd) ((cmd) - SIOCIWFIRST) -- 2.34.1