From c421809918b7106b40a81134f9fb5103146fc715 Mon Sep 17 00:00:00 2001 From: sbrissen Date: Wed, 24 Apr 2013 13:09:33 -0400 Subject: update bcmdhd driver from GT-9505 Source drivers pulled from http://review.cyanogenmod.org/#/c/36122/ Change-Id: Ide4aef99ee1d594f4222ae69aca0bdb7d563e80a --- drivers/net/wireless/bcmdhd/dhd_linux.c | 1854 ++++++++++++++++++++----------- 1 file changed, 1214 insertions(+), 640 deletions(-) (limited to 'drivers/net/wireless/bcmdhd/dhd_linux.c') diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c index 8702a44..ff8e634 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 358016 2012-09-20 22:36:51Z $ + * $Id: dhd_linux.c 394719 2013-04-03 13:22:12Z $ */ #include @@ -78,6 +78,7 @@ #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; @@ -95,20 +96,14 @@ typedef struct histo_ { static histo_t vi_d1, vi_d2, vi_d3, vi_d4; #endif /* WLMEDIA_HTSF */ -#ifndef DTIM_COUNT -#define DTIM_COUNT 3 -#endif - -#if defined(PKT_FILTER_SUPPORT) -#if defined(BLOCK_IPV6_PACKET) +#if defined(BLOCK_IPV6_PACKET) && defined(CUSTOMER_HW4) #define HEX_PREF_STR "0x" #define UNI_FILTER_STR "010000000000" #define ZERO_ADDR_STR "000000000000" #define ETHER_TYPE_STR "0000" #define IPV6_FILTER_STR "20" #define ZERO_TYPE_STR "00" -#endif /* BLOCK_IPV6_PACKET */ -#endif /* PKT_FILTER_SUPPORT */ +#endif /* BLOCK_IPV6_PACKET && CUSTOMER_HW4 */ #if defined(SOFTAP) extern bool ap_cfg_running; @@ -130,7 +125,7 @@ extern bool ap_fw_loaded; #include #ifdef ARP_OFFLOAD_SUPPORT -void aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add); +void aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add, int idx); static int dhd_device_event(struct notifier_block *this, unsigned long event, void *ptr); @@ -196,13 +191,14 @@ extern wl_iw_extra_params_t g_wl_iw_params; #endif /* defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) */ #endif /* CUSTOMER_HW4 && CONFIG_PARTIALSUSPEND_SLP */ -extern int dhd_get_dtim_skip(dhd_pub_t *dhd); +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); #endif +#ifdef CUSTOMER_HW4 #ifdef READ_MACADDR extern int dhd_read_macaddr(struct dhd_info *dhd, struct ether_addr *mac); #endif @@ -222,11 +218,20 @@ extern int dhd_check_module_mac(dhd_pub_t *dhd, struct ether_addr *mac); #ifdef MIMO_ANT_SETTING extern int dhd_sel_ant_from_file(dhd_pub_t *dhd); #endif - #ifdef GLOBALCONFIG_WLAN_COUNTRY_CODE int dhd_customer_set_country(dhd_pub_t *dhd); #endif +#else + +#ifdef READ_MACADDR +extern int dhd_read_macaddr(struct dhd_info *dhd); +#endif +#ifdef WRITE_MACADDR +extern int dhd_write_macaddr(struct ether_addr *mac); +#endif +#endif /* CUSTOMER_HW4 */ + /* Interface control information */ typedef struct dhd_if { struct dhd_info *info; /* back pointer to dhd_info */ @@ -273,11 +278,6 @@ static uint32 maxdelay = 0, tspktcnt = 0, maxdelaypktno = 0; #endif /* WLMEDIA_HTSF */ -#if defined(CUSTOMER_HW4) && defined(CONFIG_PM_SLEEP) && defined(PLATFORM_SLP) -/* SLP_wakelock_alternative_code */ -extern struct device *pm_dev; -#endif /* CUSTOMER_HW4 && CONFIG_PM_SLEEP && PLATFORM_SLP */ - /* Local private structure (extension of pub) */ typedef struct dhd_info { #if defined(CONFIG_WIRELESS_EXT) @@ -310,6 +310,10 @@ typedef struct dhd_info { tsk_ctl_t thr_dpc_ctl; tsk_ctl_t thr_wdt_ctl; +#ifdef RXFRAME_THREAD + tsk_ctl_t thr_rxf_ctl; + spinlock_t rxf_lock; +#endif /* RXFRAME_THREAD */ #endif /* DHDTHREAD */ bool dhd_tasklet_create; tsk_ctl_t thr_sysioc_ctl; @@ -319,9 +323,10 @@ typedef struct dhd_info { /* 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_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 @@ -333,6 +338,7 @@ typedef struct dhd_info { #endif spinlock_t wakelock_spinlock; int wakelock_counter; + int wakelock_wd_counter; int wakelock_rx_timeout_enable; int wakelock_ctrl_timeout_enable; @@ -345,7 +351,7 @@ typedef struct dhd_info { #if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) struct early_suspend early_suspend; -#endif /* CONFIG_HAS_EARLYSUSPEND && defined(DHD_USE_EARLYSUSPEND) */ +#endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */ #ifdef ARP_OFFLOAD_SUPPORT u32 pend_ipaddr; @@ -357,6 +363,9 @@ typedef struct dhd_info { bool rpcth_timer_active; bool fdaggr; #endif +#ifdef DHDTCPACK_SUPPRESS + spinlock_t tcpack_lock; +#endif /* DHDTCPACK_SUPPRESS */ } dhd_info_t; /* Flag to indicate if we should download firmware on driver load */ @@ -368,10 +377,6 @@ uint dhd_download_fw_on_driverload = TRUE; char firmware_path[MOD_PARAM_PATHLEN]; char nvram_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); @@ -391,11 +396,22 @@ module_param(dhd_sysioc, uint, 0); /* Error bits */ module_param(dhd_msg_level, int, 0); +#ifdef ARP_OFFLOAD_SUPPORT +/* ARP offload enable */ +uint dhd_arp_enable = TRUE; +module_param(dhd_arp_enable, 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); +#ifdef CUSTOMER_HW4 module_param_string(nvram_path, nvram_path, MOD_PARAM_PATHLEN, 0660); +#else +module_param_string(nvram_path, nvram_path, MOD_PARAM_PATHLEN, 0); +#endif /* CUSTOMER_HW4 */ /* Watchdog interval */ uint dhd_watchdog_ms = 10; @@ -407,16 +423,25 @@ uint dhd_console_ms = 0; module_param(dhd_console_ms, uint, 0644); #endif /* defined(DHD_DEBUG) */ +#ifdef REPEAT_READFRAME +uint dhd_doflow = 1; +module_param(dhd_doflow, uint, 0644); + +uint dhd_dpcpoll = 1; +module_param(dhd_dpcpoll, uint, 0644); +#endif /* REPEAT_READFRAME */ + uint dhd_slpauto = TRUE; module_param(dhd_slpauto, uint, 0); /* ARP offload agent mode : Enable ARP Host Auto-Reply and ARP Peer Auto-Reply */ +#if defined(CUSTOMER_HW4) uint dhd_arp_mode = ARP_OL_AGENT | ARP_OL_PEER_AUTO_REPLY | ARP_OL_SNOOP; -module_param(dhd_arp_mode, uint, 0); +#else +uint dhd_arp_mode = ARP_OL_AGENT | ARP_OL_PEER_AUTO_REPLY; +#endif -/* ARP offload enable */ -uint dhd_arp_enable = TRUE; -module_param(dhd_arp_enable, uint, 0); +module_param(dhd_arp_mode, uint, 0); #ifdef PKT_FILTER_SUPPORT /* Global Pkt filter enable control */ @@ -444,6 +469,12 @@ module_param(dhd_watchdog_prio, int, 0); int dhd_dpc_prio = CUSTOM_DPC_PRIO_SETTING; module_param(dhd_dpc_prio, int, 0); +#ifdef RXFRAME_THREAD +/* RX frame thread priority */ +int dhd_rxf_prio = CUSTOM_RXF_PRIO_SETTING; +module_param(dhd_rxf_prio, int, 0); +#endif /* RXFRAME_THREAD */ + /* DPC thread priority, -1 to use tasklet */ extern int dhd_dongle_memsize; module_param(dhd_dongle_memsize, int, 0); @@ -546,10 +577,14 @@ static void dhd_dump_htsfhisto(histo_t *his, char *s); int dhd_monitor_init(void *dhd_pub); int dhd_monitor_uninit(void); -#ifdef CONFIG_CONTROL_PM +#if defined(CUSTOMER_HW4) && defined(CONFIG_CONTROL_PM) bool g_pm_control; void sec_control_pm(dhd_pub_t *dhd, uint *); -#endif +#endif /* CUSTOMER_HW4 & CONFIG_CONTROL_PM */ + +#if defined(CUSTOMER_HW4) && defined(USE_WL_FRAMEBURST) +uint32 sec_control_frameburst(void); +#endif /* CUSTOMER_HW4 & CONFIG_CONTROL_PM */ #if defined(CONFIG_WIRELESS_EXT) @@ -602,9 +637,77 @@ extern int register_pm_notifier(struct notifier_block *nb); extern int unregister_pm_notifier(struct notifier_block *nb); #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ +#if defined(DHDTHREAD) && defined(RXFRAME_THREAD) +/* 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); + +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 */ + /* Do I need to make this context sleep here? Definitely in Single processor case */ + dhd_os_rxfunlock(dhdp); + DHD_ERROR(("dhd_rxf_enqueue: pktbuf not consumed %p, store idx %d sent idx %d\n", + skb, store_idx, sent_idx)); + msleep(1); + return BCME_ERROR; + } + 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; +} +#endif /* defined(DHDTHREAD) && defined(RXFRAME_THREAD) */ + void dhd_set_packet_filter(dhd_pub_t *dhd) -#ifdef PKT_FILTER_SUPPORT { +#ifdef PKT_FILTER_SUPPORT int i; DHD_TRACE(("%s: enter\n", __FUNCTION__)); @@ -613,7 +716,7 @@ void dhd_set_packet_filter(dhd_pub_t *dhd) dhd_pktfilter_offload_set(dhd, dhd->pktfilter[i]); } } -#endif +#endif /* PKT_FILTER_SUPPORT */ } void dhd_enable_packet_filter(int value, dhd_pub_t *dhd) @@ -625,7 +728,8 @@ void dhd_enable_packet_filter(int value, dhd_pub_t *dhd) /* 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))) { + (dhd_support_sta_mode(dhd) && !dhd->dhcp_in_progress))) + { for (i = 0; i < dhd->pktfilter_count; i++) { #ifdef PASS_ARP_PACKET if (value && (i == dhd->pktfilter_count -1) && @@ -647,120 +751,127 @@ static int dhd_set_suspend(int value, dhd_pub_t *dhd) { #ifndef SUPPORT_PM2_ONLY int power_mode = PM_MAX; -#endif +#endif /* SUPPORT_PM2_ONLY */ /* wl_pkt_filter_enable_t enable_parm; */ char iovbuf[32]; -#if !defined(CUSTOMER_HW4) - int bcn_li_dtim = DTIM_COUNT; -#endif -#ifndef DISABLE_FW_ROAM_SUSPEND + int bcn_li_dtim = 0; /* Default bcn_li_dtim in resume mode is 0 */ +#ifndef ENABLE_FW_ROAM_SUSPEND uint roamvar = 1; -#endif -#ifdef ENABLE_BCN_LI_BCN_WAKEUP +#endif /* ENABLE_FW_ROAM_SUSPEND */ +#if defined(CUSTOMER_HW4) && defined(ENABLE_BCN_LI_BCN_WAKEUP) int bcn_li_bcn; -#endif /* ENABLE_BCN_LI_BCN_WAKEUP */ -#ifdef PASS_ALL_MCAST_PKTS +#endif /* CUSTOMER_HW4 && ENABLE_BCN_LI_BCN_WAKEUP */ +#if defined(PASS_ALL_MCAST_PKTS) && defined(CUSTOMER_HW4) + struct dhd_info *dhdinfo = dhd->info; uint32 allmulti; -#endif /* PASS_ALL_MCAST_PKTS */ + uint i; +#endif /* PASS_ALL_MCAST_PKTS && CUSTOMER_HW4 */ + + if (!dhd) + return -ENODEV; DHD_TRACE(("%s: enter, value = %d in_suspend=%d\n", __FUNCTION__, value, dhd->in_suspend)); dhd_suspend_lock(dhd); - if (dhd && dhd->up) { + 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__)); + 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 -#ifdef PKT_FILTER_SUPPORT +#endif /* SUPPORT_PM2_ONLY */ + /* Enable packet filter, only allow unicast packet to send up */ - if (!dhd->dhcp_in_progress) - dhd_enable_packet_filter(1, dhd); -#endif /* PKT_FILTER_SUPPORT */ -#ifdef PASS_ALL_MCAST_PKTS + dhd_enable_packet_filter(1, dhd); + +#if defined(PASS_ALL_MCAST_PKTS) && defined(CUSTOMER_HW4) allmulti = 0; - bcm_mkiovar("allmulti", (char *)&allmulti, - 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -#endif /* PASS_ALL_MCAST_PKTS */ + bcm_mkiovar("allmulti", (char *)&allmulti, 4, + iovbuf, sizeof(iovbuf)); + for (i = 0; i < DHD_MAX_IFS; i++) { + if (dhdinfo->iflist[i] && dhdinfo->iflist[i]->net) + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, + sizeof(iovbuf), TRUE, i); + } +#endif /* PASS_ALL_MCAST_PKTS && CUSTOMER_HW4 */ -#if !defined(CUSTOMER_HW4) /* 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_dtim_skip(dhd); + bcn_li_dtim = dhd_get_suspend_bcn_li_dtim(dhd); 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); -#endif /* !defined(CUSTOMER_HW4) */ -#ifndef DISABLE_FW_ROAM_SUSPEND + if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), + TRUE, 0) < 0) + DHD_ERROR(("%s: set dtim failed\n", __FUNCTION__)); + +#ifndef ENABLE_FW_ROAM_SUSPEND /* 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); -#endif -#ifdef ENABLE_BCN_LI_BCN_WAKEUP +#endif /* ENABLE_FW_ROAM_SUSPEND */ +#if defined(CUSTOMER_HW4) && defined(ENABLE_BCN_LI_BCN_WAKEUP) bcn_li_bcn = 0; bcm_mkiovar("bcn_li_bcn", (char *)&bcn_li_bcn, 4, iovbuf, sizeof(iovbuf)); dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -#endif /* ENABLE_BCN_LI_BCN_WAKEUP */ - +#endif /* CUSTOMER_HW4 && ENABLE_BCN_LI_BCN_WAKEUP */ } else { #ifdef PKT_FILTER_SUPPORT dhd->early_suspended = 0; #endif /* Kernel resumed */ - DHD_ERROR(("%s: Remove extra suspend setting\n", __FUNCTION__)); + 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 +#endif /* SUPPORT_PM2_ONLY */ #ifdef PKT_FILTER_SUPPORT /* disable pkt filter */ dhd_enable_packet_filter(0, dhd); #endif /* PKT_FILTER_SUPPORT */ -#ifdef PASS_ALL_MCAST_PKTS +#if defined(PASS_ALL_MCAST_PKTS) && defined(CUSTOMER_HW4) allmulti = 1; - bcm_mkiovar("allmulti", (char *)&allmulti, - 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -#endif /* PASS_ALL_MCAST_PKTS */ + bcm_mkiovar("allmulti", (char *)&allmulti, 4, + iovbuf, sizeof(iovbuf)); + for (i = 0; i < DHD_MAX_IFS; i++) { + if (dhdinfo->iflist[i] && dhdinfo->iflist[i]->net) + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, + sizeof(iovbuf), TRUE, i); + } +#endif /* PASS_ALL_MCAST_PKTS && CUSTOMER_HW4 */ -#if !defined(CUSTOMER_HW4) /* restore pre-suspend setting for dtim_skip */ - bcm_mkiovar("bcn_li_dtim", (char *)&dhd->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); -#endif -#ifndef DISABLE_FW_ROAM_SUSPEND +#ifndef ENABLE_FW_ROAM_SUSPEND 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); -#endif -#ifdef ENABLE_BCN_LI_BCN_WAKEUP +#endif /* ENABLE_FW_ROAM_SUSPEND */ +#if defined(CUSTOMER_HW4) && defined(ENABLE_BCN_LI_BCN_WAKEUP) bcn_li_bcn = 1; bcm_mkiovar("bcn_li_bcn", (char *)&bcn_li_bcn, 4, iovbuf, sizeof(iovbuf)); dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -#endif /* ENABLE_BCN_LI_BCN_WAKEUP */ - +#endif /* CUSTOMER_HW4 && ENABLE_BCN_LI_BCN_WAKEUP */ } } - dhd_suspend_unlock(dhd); + return 0; } @@ -800,7 +911,7 @@ static void dhd_late_resume(struct early_suspend *h) if (dhd) dhd_suspend_resume_helper(dhd, 0, 0); } -#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */ +#endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */ /* * Generalized timeout mechanism. Uses spin sleep with exponential back-off until @@ -967,33 +1078,37 @@ _dhd_set_multicast_list(dhd_info_t *dhd, int ifidx) for (i = 0; i < DHD_MAX_IFS; i++) { if (dhd->iflist[i]) { dev = dhd->iflist[i]->net; + if (!dev) + continue; #else - ASSERT(dhd && dhd->iflist[ifidx]); - dev = dhd->iflist[ifidx]->net; + ASSERT(dhd && dhd->iflist[ifidx]); + dev = dhd->iflist[ifidx]->net; + if (!dev) + return; #endif /* MCAST_LIST_ACCUMULATION */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) - netif_addr_lock_bh(dev); + netif_addr_lock_bh(dev); #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) #ifdef MCAST_LIST_ACCUMULATION cnt_iface[i] = netdev_mc_count(dev); cnt += cnt_iface[i]; #else - cnt = netdev_mc_count(dev); + cnt = netdev_mc_count(dev); #endif /* MCAST_LIST_ACCUMULATION */ #else #ifdef MCAST_LIST_ACCUMULATION cnt += dev->mc_count; #else - cnt = dev->mc_count; + cnt = dev->mc_count; #endif /* MCAST_LIST_ACCUMULATION */ #endif /* LINUX_VERSION_CODE */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) - netif_addr_unlock_bh(dev); + netif_addr_unlock_bh(dev); #endif - /* Determine initial value of allmulti flag */ + /* Determine initial value of allmulti flag */ #ifdef MCAST_LIST_ACCUMULATION allmulti |= (dev->flags & IFF_ALLMULTI) ? TRUE : FALSE; } @@ -1001,13 +1116,12 @@ _dhd_set_multicast_list(dhd_info_t *dhd, int ifidx) #else allmulti = (dev->flags & IFF_ALLMULTI) ? TRUE : FALSE; #endif /* MCAST_LIST_ACCUMULATION */ - -#ifdef PASS_ALL_MCAST_PKTS +#if defined(PASS_ALL_MCAST_PKTS) && defined(CUSTOMER_HW4) #ifdef PKT_FILTER_SUPPORT if (!dhd->pub.early_suspended) #endif /* PKT_FILTER_SUPPORT */ allmulti = TRUE; -#endif /* PASS_ALL_MCAST_PKTS */ +#endif /* PASS_ALL_MCAST_PKTS && CUSTOMER_HW4 */ /* Send down the multicast list first. */ @@ -1035,25 +1149,25 @@ _dhd_set_multicast_list(dhd_info_t *dhd, int ifidx) #endif /* MCAST_LIST_ACCUMULATION */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) - netif_addr_lock_bh(dev); + netif_addr_lock_bh(dev); #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) - netdev_for_each_mc_addr(ha, dev) { + netdev_for_each_mc_addr(ha, dev) { #ifdef MCAST_LIST_ACCUMULATION if (!cnt_iface[i]) #else - if (!cnt) + if (!cnt) #endif /* MCAST_LIST_ACCUMULATION */ - break; - memcpy(bufp, ha->addr, ETHER_ADDR_LEN); - bufp += ETHER_ADDR_LEN; + break; + memcpy(bufp, ha->addr, ETHER_ADDR_LEN); + bufp += ETHER_ADDR_LEN; #ifdef MCAST_LIST_ACCUMULATION DHD_TRACE(("_dhd_set_multicast_list: cnt " "%d " MACDBG "\n", cnt_iface[i], MAC2STRDBG(ha->addr))); cnt_iface[i]--; #else - cnt--; + cnt--; #endif /* MCAST_LIST_ACCUMULATION */ } #else @@ -1064,13 +1178,13 @@ _dhd_set_multicast_list(dhd_info_t *dhd, int ifidx) for (mclist = dev->mc_list; (mclist && (cnt > 0)); cnt--, mclist = mclist->next) { #endif /* MCAST_LIST_ACCUMULATION */ - memcpy(bufp, (void *)mclist->dmi_addr, ETHER_ADDR_LEN); - bufp += ETHER_ADDR_LEN; - } + 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); + netif_addr_unlock_bh(dev); #endif #ifdef MCAST_LIST_ACCUMULATION } @@ -1224,7 +1338,7 @@ dhd_op_if(dhd_if_t *ifp) } /* Allocate etherdev, including space for private structure */ if (!(ifp->net = alloc_etherdev(sizeof(dhd)))) { - DHD_ERROR(("%s: OOM - alloc_etherdev\n", __FUNCTION__)); + DHD_ERROR(("%s: OOM - alloc_etherdev(%d)\n", __FUNCTION__, sizeof(dhd))); ret = -ENOMEM; } if (ret == 0) { @@ -1309,6 +1423,13 @@ dhd_op_if(dhd_if_t *ifp) } } + +#ifdef DHDTCPACK_SUPPRESS +uint dhd_use_tcpack_suppress = TRUE; +module_param(dhd_use_tcpack_suppress, uint, FALSE); +extern bool dhd_tcpack_suppress(dhd_pub_t *dhdp, void *pkt); +#endif /* DHDTCPACK_SUPPRESS */ + static int _dhd_sysioc_thread(void *data) { @@ -1321,6 +1442,7 @@ _dhd_sysioc_thread(void *data) bool in_ap = FALSE; unsigned long flags; #endif + #ifndef USE_KTHREAD_API DAEMONIZE("dhd_sysioc"); @@ -1386,10 +1508,12 @@ _dhd_sysioc_thread(void *data) dhd->set_macaddress = 0; if (_dhd_set_mac_address(dhd, i, &dhd->macvalue) == 0) { DHD_INFO(( - "dhd_sysioc_thread: MACID is overwritten\n")); + "%s: MACID is overwritten\n", + __FUNCTION__)); } else { DHD_ERROR(( - "dhd_sysioc_thread: _dhd_set_mac_address() failed\n")); + "%s: _dhd_set_mac_address() failed\n", + __FUNCTION__)); } } } @@ -1470,7 +1594,7 @@ uint8 prio2fifo[8] = { 1, 0, 0, 1, 2, 2, 3, 3 }; int dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf) { - int ret; + int ret = BCME_OK; dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); struct ether_header *eh = NULL; @@ -1496,7 +1620,9 @@ dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf) } /* Look into the packet and update the packet priority */ +#ifndef PKTPRIO_OVERRIDE if (PKTPRIO(pktbuf) == 0) +#endif /* !CUSTOMER_HW4 */ pktsetprio(pktbuf, FALSE); #ifdef PROP_TXSTATUS @@ -1522,22 +1648,30 @@ dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf) #ifdef WLMEDIA_HTSF dhd_htsf_addtxts(dhdp, pktbuf); #endif +#ifdef DHDTCPACK_SUPPRESS + if (dhd_use_tcpack_suppress && dhd_tcpack_suppress(dhdp, pktbuf)) + ret = BCME_OK; + else +#endif /* DHDTCPACK_SUPPRESS */ #ifdef PROP_TXSTATUS - if (dhdp->wlfc_state && ((athost_wl_status_info_t*)dhdp->wlfc_state)->proptxstatus_mode - != WLFC_FCMODE_NONE) { + { dhd_os_wlfc_block(dhdp); - ret = dhd_wlfc_enque_sendq(dhdp->wlfc_state, DHD_PKTTAG_FIFO(PKTTAG(pktbuf)), - pktbuf); - dhd_wlfc_commit_packets(dhdp->wlfc_state, (f_commitpkt_t)dhd_bus_txdata, - dhdp->bus); - if (((athost_wl_status_info_t*)dhdp->wlfc_state)->toggle_host_if) { - ((athost_wl_status_info_t*)dhdp->wlfc_state)->toggle_host_if = 0; + if (dhdp->wlfc_state && + ((athost_wl_status_info_t*)dhdp->wlfc_state)->proptxstatus_mode + != WLFC_FCMODE_NONE) { + dhd_wlfc_commit_packets(dhdp->wlfc_state, (f_commitpkt_t)dhd_bus_txdata, + dhdp->bus, pktbuf); + if (((athost_wl_status_info_t*)dhdp->wlfc_state)->toggle_host_if) { + ((athost_wl_status_info_t*)dhdp->wlfc_state)->toggle_host_if = 0; + } + dhd_os_wlfc_unblock(dhdp); + } + else { + dhd_os_wlfc_unblock(dhdp); + /* non-proptxstatus way */ + ret = dhd_bus_txdata(dhdp->bus, pktbuf); } - dhd_os_wlfc_unblock(dhdp); } - else - /* non-proptxstatus way */ - ret = dhd_bus_txdata(dhdp->bus, pktbuf); #else ret = dhd_bus_txdata(dhdp->bus, pktbuf); #endif /* PROP_TXSTATUS */ @@ -1716,11 +1850,6 @@ static const char *_get_packet_type_str(uint16 type) } #endif /* DHD_RX_DUMP */ -#ifdef CUSTOMER_HW4 -extern int pkt_free; -extern int caller; -extern void *free_ptr; -#endif void dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) { @@ -1734,7 +1863,10 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) wl_event_msg_t event; int tout_rx = 0; int tout_ctrl = 0; - +#if defined(DHDTHREAD) && defined(RXFRAME_THREAD) + void *skbhead = NULL; + void *skbprev = NULL; +#endif /* defined(DHDTHREAD) && defined(RXFRAME_THREAD) */ #ifdef DHD_RX_DUMP #ifdef DHD_RX_FULL_DUMP int k; @@ -1751,6 +1883,9 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) struct dot11_llc_snap_header *lsh; #endif + pnext = PKTNEXT(dhdp->osh, pktbuf); + PKTSETNEXT(wl->sh.osh, pktbuf, NULL); + ifp = dhd->iflist[ifidx]; if (ifp == NULL) { DHD_ERROR(("%s: ifp is NULL. drop packet\n", @@ -1772,9 +1907,6 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) } #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */ - pnext = PKTNEXT(dhdp->osh, pktbuf); - PKTSETNEXT(wl->sh.osh, pktbuf, NULL); - #ifdef WLBTAMP eh = (struct ether_header *)PKTDATA(wl->sh.osh, pktbuf); lsh = (struct dot11_llc_snap_header *)&eh[1]; @@ -1796,16 +1928,10 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) piggy-back on */ ((athost_wl_status_info_t*)dhdp->wlfc_state)->stats.wlfc_header_only_pkt++; -#ifdef CUSTOMER_HW4 - /*if (numpkt == 1 && pkt_free && (free_ptr == pktbuf)) { - DHD_ERROR(("DHD TRACE2(FREE):%d %d %p\n", - pkt_free, caller, free_ptr)); - }*/ -#endif PKTFREE(dhdp->osh, pktbuf, TRUE); continue; } -#endif /* PROP_TXSTATUS */ +#endif skb = PKTTONATIVE(dhdp->osh, pktbuf); @@ -1886,29 +2012,33 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) 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_mac_header(skb), #else skb->mac.raw, #endif &event, &data); +#if defined(WLBTAMP) || defined(PNO_SUPPORT) 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) +#ifdef PNO_SUPPORT if (event.event_type == WLC_E_PFN_NET_FOUND) { +#ifdef CUSTOMER_HW4 + tout_ctrl = DHD_PNO_TIMEOUT_MS; +#else tout_ctrl *= 2; +#endif } #endif /* PNO_SUPPORT */ +#endif /* defined(WLBTAMP) || defined(PNO_SUPPORT) */ } else { tout_rx = DHD_PACKET_TIMEOUT_MS; } @@ -1923,6 +2053,7 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) dhdp->dstats.rx_bytes += skb->len; dhdp->rx_packets++; /* Local count */ + if (in_interrupt()) { netif_rx(skb); } else { @@ -1932,6 +2063,13 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) * by netif_rx_ni(), but in earlier kernels, we need * to do it manually. */ +#if defined(DHDTHREAD) && defined(RXFRAME_THREAD) + if (!skbhead) + skbhead = skb; + else + PKTSETNEXT(wl->sh.osh, skbprev, skb); + skbprev = skb; +#else #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) netif_rx_ni(skb); #else @@ -1941,9 +2079,13 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) RAISE_RX_SOFTIRQ(); local_irq_restore(flags); #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */ +#endif /* defined(DHDTHREAD) && defined(RXFRAME_THREAD) */ } } - +#if defined(DHDTHREAD) && defined(RXFRAME_THREAD) + if (skbhead) + dhd_sched_rxf(dhdp, skbhead); +#endif DHD_OS_WAKE_LOCK_RX_TIMEOUT_ENABLE(dhdp, tout_rx); DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(dhdp, tout_ctrl); } @@ -1958,7 +2100,6 @@ dhd_event(struct dhd_info *dhd, char *evpkt, int evlen, int ifidx) void dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success) { - uint ifidx; dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); struct ether_header *eh; uint16 type; @@ -1966,7 +2107,7 @@ dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success) uint len; #endif - dhd_prot_hdrpull(dhdp, &ifidx, txp, NULL, NULL); + dhd_prot_hdrpull(dhdp, NULL, txp, NULL, NULL); eh = (struct ether_header *)PKTDATA(dhdp->osh, txp); type = ntoh16(eh->ether_type); @@ -2055,6 +2196,8 @@ dhd_watchdog_thread(void *data) 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) { @@ -2065,20 +2208,24 @@ dhd_watchdog_thread(void *data) if (dhd->pub.dongle_reset == FALSE) { DHD_TIMER(("%s:\n", __FUNCTION__)); + /* Call the bus module watchdog */ dhd_bus_watchdog(&dhd->pub); flags = dhd_os_spin_lock(&dhd->pub); /* 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)); + jiffies + + msecs_to_jiffies(dhd_watchdog_ms) - + min(msecs_to_jiffies(dhd_watchdog_ms), time_lapse)); dhd_os_spin_unlock(&dhd->pub, flags); } dhd_os_sdunlock(&dhd->pub); - DHD_OS_WAKE_UNLOCK(&dhd->pub); } else { break; } @@ -2092,9 +2239,7 @@ static void dhd_watchdog(ulong data) dhd_info_t *dhd = (dhd_info_t *)data; unsigned long flags; - DHD_OS_WAKE_LOCK(&dhd->pub); if (dhd->pub.dongle_reset) { - DHD_OS_WAKE_UNLOCK(&dhd->pub); return; } @@ -2118,7 +2263,6 @@ static void dhd_watchdog(ulong data) mod_timer(&dhd->timer, jiffies + msecs_to_jiffies(dhd_watchdog_ms)); dhd_os_spin_unlock(&dhd->pub, flags); dhd_os_sdunlock(&dhd->pub); - DHD_OS_WAKE_UNLOCK(&dhd->pub); } #ifdef DHDTHREAD @@ -2145,10 +2289,13 @@ dhd_dpc_thread(void *data) complete(&tsk->completed); #endif +#ifdef CUSTOM_DPC_CPUCORE + set_cpus_allowed_ptr(current, cpumask_of(CUSTOM_DPC_CPUCORE)); +#endif + /* Run until signal received */ while (1) { if (down_interruptible(&tsk->sema) == 0) { - SMP_RD_BARRIER_DEPENDS(); if (tsk->terminated) { break; @@ -2174,6 +2321,75 @@ dhd_dpc_thread(void *data) complete_and_exit(&tsk->completed, 0); } + +#ifdef RXFRAME_THREAD +static int +dhd_rxf_thread(void *data) +{ + tsk_ctl_t *tsk = (tsk_ctl_t *)data; + dhd_info_t *dhd = (dhd_info_t *)tsk->parent; + 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); + + /* 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 + + 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; + } + + DHD_OS_WAKE_UNLOCK(pub); + } + else + break; + } + + complete_and_exit(&tsk->completed, 0); +} +#endif /* RXFRAME_THREAD */ #endif /* DHDTHREAD */ static void @@ -2216,6 +2432,27 @@ dhd_sched_dpc(dhd_pub_t *dhdp) tasklet_schedule(&dhd->tasklet); } +#if defined(DHDTHREAD) && defined(RXFRAME_THREAD) +static void +dhd_sched_rxf(dhd_pub_t *dhdp, void *skb) +{ + dhd_info_t *dhd = (dhd_info_t *)dhdp->info; + + DHD_OS_WAKE_LOCK(dhdp); + + DHD_TRACE(("dhd_sched_rxf: Enter\n")); + + 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 /* defined(DHDTHREAD) && defined(RXFRAME_THREAD) */ + #ifdef TOE /* Retrieve current toe component enables, which are kept as a bitmap in toe_ol iovar */ static int @@ -2423,7 +2660,7 @@ dhd_ethtool(dhd_info_t *dhd, void *uaddr) static bool dhd_check_hang(struct net_device *net, dhd_pub_t *dhdp, int error) { - dhd_info_t * dhd; + dhd_info_t *dhd; if (!dhdp) return FALSE; @@ -2444,128 +2681,60 @@ static bool dhd_check_hang(struct net_device *net, dhd_pub_t *dhdp, int error) return FALSE; } -static int -dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) +int dhd_ioctl_process(dhd_pub_t *pub, int ifidx, dhd_ioctl_t *ioc) { - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); - dhd_ioctl_t ioc; - int bcmerror = 0; + int bcmerror = BCME_OK; int buflen = 0; void *buf = NULL; - uint driver = 0; - int ifidx; - int ret; - - DHD_OS_WAKE_LOCK(&dhd->pub); + struct net_device *net; - /* 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); + net = dhd_idx2net(pub, ifidx); + if (!net) { + bcmerror = BCME_BADARG; + goto done; } - ifidx = dhd_net2idx(dhd, net); - DHD_TRACE(("%s: ifidx %d, cmd 0x%04x\n", __FUNCTION__, ifidx, cmd)); + /* Copy out any buffer passed */ + if (ioc->buf) { + if (ioc->len == 0) { + DHD_TRACE(("%s: ioc->len=0, returns BCME_BADARG \n", __FUNCTION__)); + bcmerror = BCME_BADARG; + goto done; + } + buflen = MIN(ioc->len, DHD_IOCTL_MAXLEN); + /* optimization for direct ioctl calls from kernel */ + /* + if (segment_eq(get_fs(), KERNEL_DS)) { + buf = ioc->buf; + } else { + */ + { + if (!(buf = (char*)MALLOC(pub->osh, buflen))) { + bcmerror = BCME_NOMEM; + goto done; + } + if (copy_from_user(buf, ioc->buf, buflen)) { + bcmerror = BCME_BADADDR; + goto done; + } + } + } - if (ifidx == DHD_BAD_IF) { - DHD_ERROR(("%s: BAD IF\n", __FUNCTION__)); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - return -1; - } - -#if defined(CONFIG_WIRELESS_EXT) - /* linux wireless extensions */ - if ((cmd >= SIOCIWFIRST) && (cmd <= SIOCIWLAST)) { - /* may recurse, do NOT lock */ - ret = wl_iw_ioctl(net, ifr, cmd); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - return ret; - } -#endif /* defined(CONFIG_WIRELESS_EXT) */ - -#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) - if (cmd == SIOCETHTOOL) { - ret = dhd_ethtool(dhd, (void*)ifr->ifr_data); - 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_OS_WAKE_UNLOCK(&dhd->pub); - return -EOPNOTSUPP; - } - - memset(&ioc, 0, sizeof(ioc)); - - /* 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; - } - - /* Copy out any buffer passed */ - if (ioc.buf) { - if (ioc.len == 0) { - DHD_TRACE(("%s: ioc.len=0, returns BCME_BADARG \n", __FUNCTION__)); - bcmerror = BCME_BADARG; - goto done; - } - buflen = MIN(ioc.len, DHD_IOCTL_MAXLEN); - /* optimization for direct ioctl calls from kernel */ - /* - if (segment_eq(get_fs(), KERNEL_DS)) { - buf = ioc.buf; - } else { - */ - { - if (!(buf = (char*)MALLOC(dhd->pub.osh, buflen))) { - bcmerror = BCME_NOMEM; - goto done; - } - if (copy_from_user(buf, ioc.buf, buflen)) { - bcmerror = BCME_BADADDR; - goto done; - } - } - } - - /* To differentiate between wl and dhd read 4 more byes */ - if ((copy_from_user(&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; - } - - /* check for local dhd ioctl and handle it */ - if (driver == DHD_IOCTL_MAGIC) { - bcmerror = dhd_ioctl((void *)&dhd->pub, &ioc, buf, buflen); - if (bcmerror) - dhd->pub.bcmerror = bcmerror; - goto done; + /* check for local dhd ioctl and handle it */ + if (ioc->driver == DHD_IOCTL_MAGIC) { + bcmerror = dhd_ioctl((void *)pub, ioc, buf, buflen); + if (bcmerror) + pub->bcmerror = bcmerror; + goto done; } /* send to dongle (must be up, and wl). */ - if (dhd->pub.busstate != DHD_BUS_DATA) { + if (pub->busstate != DHD_BUS_DATA) { bcmerror = BCME_DONGLE_DOWN; goto done; } - if (!dhd->pub.iswl) { + if (!pub->iswl) { bcmerror = BCME_DONGLE_DOWN; goto done; } @@ -2577,24 +2746,24 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) * 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 && ioc.buf != NULL && - strncmp("wsec_key", ioc.buf, 9) == 0) || - (ioc.cmd == WLC_SET_VAR && ioc.buf != NULL && - strncmp("bsscfg:wsec_key", ioc.buf, 15) == 0) || - ioc.cmd == WLC_DISASSOC) + if (ioc->cmd == WLC_SET_KEY || + (ioc->cmd == WLC_SET_VAR && ioc->buf != NULL && + strncmp("wsec_key", ioc->buf, 9) == 0) || + (ioc->cmd == WLC_SET_VAR && ioc->buf != NULL && + strncmp("bsscfg:wsec_key", ioc->buf, 15) == 0) || + ioc->cmd == WLC_DISASSOC) dhd_wait_pend8021x(net); #ifdef WLMEDIA_HTSF - if (ioc.buf) { + if (ioc->buf) { /* short cut wl ioctl calls here */ - if (strcmp("htsf", ioc.buf) == 0) { + if (strcmp("htsf", ioc->buf) == 0) { dhd_ioctl_htsf_get(dhd, 0); return BCME_OK; } - if (strcmp("htsflate", ioc.buf) == 0) { - if (ioc.set) { + if (strcmp("htsflate", ioc->buf) == 0) { + if (ioc->set) { memset(ts, 0, sizeof(tstamp_t)*TSMAX); memset(&maxdelayts, 0, sizeof(tstamp_t)); maxdelay = 0; @@ -2609,7 +2778,7 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) } return BCME_OK; } - if (strcmp("htsfclear", ioc.buf) == 0) { + if (strcmp("htsfclear", ioc->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); @@ -2617,16 +2786,16 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) htsf_seqnum = 0; return BCME_OK; } - if (strcmp("htsfhis", ioc.buf) == 0) { + if (strcmp("htsfhis", ioc->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", ioc.buf) == 0) { - if (ioc.set) { - memcpy(&tsport, ioc.buf + 7, 4); + if (strcmp("tsport", ioc->buf) == 0) { + if (ioc->set) { + memcpy(&tsport, ioc->buf + 7, 4); } else { DHD_ERROR(("current timestamp port: %d \n", tsport)); } @@ -2635,52 +2804,182 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) } #endif /* WLMEDIA_HTSF */ - if ((ioc.cmd == WLC_SET_VAR || ioc.cmd == WLC_GET_VAR) && - ioc.buf != NULL && strncmp("rpc_", ioc.buf, 4) == 0) { + if ((ioc->cmd == WLC_SET_VAR || ioc->cmd == WLC_GET_VAR) && + ioc->buf != NULL && strncmp("rpc_", ioc->buf, 4) == 0) { #ifdef BCM_FD_AGGR - bcmerror = dhd_fdaggr_ioctl(&dhd->pub, ifidx, (wl_ioctl_t *)&ioc, buf, buflen); + bcmerror = dhd_fdaggr_ioctl(pub, ifidx, (wl_ioctl_t *)ioc, buf, buflen); #else bcmerror = BCME_UNSUPPORTED; #endif goto done; } - bcmerror = dhd_wl_ioctl(&dhd->pub, ifidx, (wl_ioctl_t *)&ioc, buf, buflen); + bcmerror = dhd_wl_ioctl(pub, ifidx, (wl_ioctl_t *)ioc, buf, buflen); done: - dhd_check_hang(net, &dhd->pub, bcmerror); + dhd_check_hang(net, pub, bcmerror); - if (!bcmerror && buf && ioc.buf) { - if (copy_to_user(ioc.buf, buf, buflen)) + if (!bcmerror && buf && ioc->buf) { + if (copy_to_user(ioc->buf, buf, buflen)) bcmerror = -EFAULT; } if (buf) - MFREE(dhd->pub.osh, buf, buflen); + MFREE(pub->osh, buf, buflen); + return bcmerror; +} + +static int +dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); + dhd_ioctl_t ioc; + int bcmerror = 0; + int ifidx; + int ret; + + DHD_OS_WAKE_LOCK(&dhd->pub); + + /* 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_OS_WAKE_UNLOCK(&dhd->pub); + return -1; + } + +#if defined(CONFIG_WIRELESS_EXT) + /* linux wireless extensions */ + if ((cmd >= SIOCIWFIRST) && (cmd <= SIOCIWLAST)) { + /* may recurse, do NOT lock */ + ret = wl_iw_ioctl(net, ifr, cmd); + DHD_OS_WAKE_UNLOCK(&dhd->pub); + return ret; + } +#endif /* defined(CONFIG_WIRELESS_EXT) */ + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) + if (cmd == SIOCETHTOOL) { + ret = dhd_ethtool(dhd, (void*)ifr->ifr_data); + 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_OS_WAKE_UNLOCK(&dhd->pub); + return -EOPNOTSUPP; + } + + memset(&ioc, 0, sizeof(ioc)); + + /* 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; + } + + bcmerror = dhd_ioctl_process(&dhd->pub, ifidx, &ioc); + +done: DHD_OS_WAKE_UNLOCK(&dhd->pub); return OSL_ERROR(bcmerror); } #ifdef WL_CFG80211 +static void +dhd_delete_virt_iface(dhd_if_t *ifp) +{ + dhd_info_t *dhd; +#ifdef SOFTAP + unsigned long flags; +#endif + + if (!ifp || !ifp->info || !ifp->idx) + return; + ASSERT(ifp && ifp->info && ifp->idx); /* Virtual interfaces only */ + dhd = ifp->info; + + DHD_TRACE(("%s: idx %d, state %d\n", __FUNCTION__, ifp->idx, ifp->state)); + + if (wl_cfg80211_is_progress_ifchange()) + return; + + /* Make sure that we don't enter again here if .. */ + /* dhd_op_if is called again from some other context */ + ifp->state = DHD_IF_DELETING; + if (ifp->net != NULL) { + DHD_ERROR(("\n%s: got 'DHD_IF_DEL' state\n", __FUNCTION__)); + + ASSERT_RTNL(); + + netif_stop_queue(ifp->net); + if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) { + wl_cfg80211_ifdel_ops(ifp->net); + } + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)) + if (rtnl_is_locked()) + unregister_netdevice_queue(ifp->net, NULL); + else +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33) */ + unregister_netdev(ifp->net); + + if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) { + wl_cfg80211_notify_ifdel(); + } + + free_netdev(ifp->net); + ifp->net = NULL; + } + + ifp->set_multicast = FALSE; + dhd->iflist[ifp->idx] = NULL; +#ifdef SOFTAP + flags = dhd_os_spin_lock(&dhd->pub); + if (ifp->net == ap_net_dev) + ap_net_dev = NULL; /* NULL SOFTAP global wl0.1 as well */ + dhd_os_spin_unlock(&dhd->pub, flags); +#endif /* SOFTAP */ + MFREE(dhd->pub.osh, ifp, sizeof(*ifp)); +} + static int dhd_cleanup_virt_ifaces(dhd_info_t *dhd) { int i = 1; /* Leave ifidx 0 [Primary Interface] */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) - int rollback_lock = FALSE; -#endif DHD_TRACE(("%s: Enter \n", __func__)); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) - /* release lock for unregister_netdev */ - if (rtnl_is_locked()) { - rtnl_unlock(); - rollback_lock = TRUE; - } -#endif - for (i = 1; i < DHD_MAX_IFS; i++) { dhd_net_if_lock_local(dhd); if (dhd->iflist[i]) { @@ -2689,17 +2988,12 @@ dhd_cleanup_virt_ifaces(dhd_info_t *dhd) (dhd->iflist[i]->state != DHD_IF_DELETING)) { dhd->iflist[i]->state = DHD_IF_DEL; dhd->iflist[i]->idx = i; - dhd_op_if(dhd->iflist[i]); + dhd_delete_virt_iface(dhd->iflist[i]); } } dhd_net_if_unlock_local(dhd); } -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) - if (rollback_lock) - rtnl_lock(); -#endif - return 0; } #endif /* WL_CFG80211 */ @@ -2708,8 +3002,8 @@ dhd_cleanup_virt_ifaces(dhd_info_t *dhd) /* Flags to indicate if we distingish power off policy when * user set the memu "Keep Wi-Fi on during sleep" to "Never" */ -int sleep_never = 0; -#endif +int trigger_deep_sleep = 0; +#endif /* WL_CFG80211 && SUPPORT_DEEP_SLEEP */ static int dhd_stop(struct net_device *net) @@ -2744,33 +3038,28 @@ dhd_stop(struct net_device *net) #endif #ifdef PROP_TXSTATUS - dhd_os_wlfc_block(&dhd->pub); - dhd_wlfc_cleanup(&dhd->pub); - dhd_os_wlfc_unblock(&dhd->pub); + dhd_wlfc_cleanup(&dhd->pub, NULL, 0); #endif - /* Stop the protocol module */ dhd_prot_stop(&dhd->pub); OLD_MOD_DEC_USE_COUNT; exit: #if defined(WL_CFG80211) - if (ifidx == 0) { - if (!dhd_download_fw_on_driverload) - wl_android_wifi_off(net); + if (ifidx == 0 && !dhd_download_fw_on_driverload) + wl_android_wifi_off(net); #ifdef SUPPORT_DEEP_SLEEP - else { - /* CSP#505233: Flags to indicate if we distingish - * power off policy when user set the memu - * "Keep Wi-Fi on during sleep" to "Never" - */ - if (sleep_never) { - dhd_deepsleep(net, 1); - sleep_never = 0; - } + else { + /* CSP#505233: Flags to indicate if we distingish + * power off policy when user set the memu + * "Keep Wi-Fi on during sleep" to "Never" + */ + if (trigger_deep_sleep) { + dhd_deepsleep(net, 1); + trigger_deep_sleep = 0; } -#endif /* SUPPORT_DEEP_SLEEP */ } +#endif /* SUPPORT_DEEP_SLEEP */ #endif dhd->pub.rxcnt_timeout = 0; dhd->pub.txcnt_timeout = 0; @@ -2789,31 +3078,49 @@ dhd_open(struct net_device *net) int ifidx; int32 ret = 0; + /* WAR : to prevent calling dhd_open abnormally in quick succession after hang event */ + if (dhd->pub.hang_was_sent == 1) { + DHD_ERROR(("%s: HANG was sent up earlier\n", __FUNCTION__)); + return -1; + } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 && 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 + DHD_OS_WAKE_LOCK(&dhd->pub); - DHD_ERROR(("%s: Enter, net[%p]\n", __FUNCTION__, net)); /* Update FW path if it was changed */ if (strlen(firmware_path) != 0) { if (firmware_path[strlen(firmware_path)-1] == '\n') firmware_path[strlen(firmware_path)-1] = '\0'; + bzero(fw_path, MOD_PARAM_PATHLEN); strncpy(fw_path, firmware_path, sizeof(fw_path)-1); - fw_path[sizeof(fw_path)-1] = '\0'; -#if defined(SUPPORT_MULTIPLE_REVISION) - ret = concate_revision(dhd->pub.bus, fw_path, MOD_PARAM_PATHLEN); - if (ret != 0) { - DHD_ERROR(("%s: fail to concatnate revison \n", __FUNCTION__)); - goto exit; - } -#endif firmware_path[0] = '\0'; } +#ifdef CUSTOMER_HW4 /* Update NVRAM path if it was changed */ if (!dhd_download_fw_on_driverload && (strlen(nvram_path) != 0)) { if (nvram_path[strlen(nvram_path)-1] == '\n') nvram_path[strlen(nvram_path)-1] = '\0'; - strcpy(nv_path, nvram_path); - nvram_path[0] = '\0'; + bzero(nv_path, MOD_PARAM_PATHLEN); + strncpy(nv_path, nvram_path, sizeof(nv_path)-1); } +#endif /* CUSTOMER_HW4 */ + +#if defined(CUSTOMER_HW4) && defined(SUPPORT_MULTIPLE_REVISION) + /* dhd_open() can be call several times when loading failed */ + if (strlen(firmware_path) != 0) { + ret = concate_revision(dhd->pub.bus, fw_path, MOD_PARAM_PATHLEN, + nv_path, MOD_PARAM_PATHLEN); + if (ret != 0) { + DHD_ERROR(("%s: fail to concatnate revison \n", __FUNCTION__)); + goto exit; + } + } +#endif /* CUSTOMER_HW4 && SUPPORT_MULTIPLE_REVISION */ dhd->pub.dongle_trap_occured = 0; dhd->pub.hang_was_sent = 0; @@ -2854,52 +3161,34 @@ dhd_open(struct net_device *net) if (!dhd_download_fw_on_driverload) { ret = wl_android_wifi_on(net); if (ret != 0) { - DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret)); + DHD_ERROR(("%s : wl_android_wifi_on failed (%d)\n", + __FUNCTION__, ret)); ret = -1; goto exit; } - } else { + } #ifdef SUPPORT_DEEP_SLEEP + else { /* Flags to indicate if we distingish * power off policy when user set the memu * "Keep Wi-Fi on during sleep" to "Never" */ - if (sleep_never) { + if (trigger_deep_sleep) { dhd_deepsleep(net, 0); - sleep_never = 0; + trigger_deep_sleep = 0; } -#endif /* SUPPORT_DEEP_SLEEP */ } +#endif /* SUPPORT_DEEP_SLEEP */ #endif if (dhd->pub.busstate != DHD_BUS_DATA) { -#if defined(CUSTOMER_HW4) -#define WAIT_DHDBUS_READY 5 - /* Delay ifup until insmod completed in case of module type */ - if (dhd_download_fw_on_driverload) { - uint retry = 0; - - do { - OSL_DELAY(100*1000); - } while ((dhd->pub.busstate != DHD_BUS_DATA) && - (retry++ < WAIT_DHDBUS_READY)); - - if (dhd->pub.busstate != DHD_BUS_DATA) { - DHD_ERROR(("%s: call dev open before insmod complete!\n", - __FUNCTION__)); - ret = -1; - goto exit; - } + /* try to bring up bus */ + if ((ret = dhd_bus_start(&dhd->pub)) != 0) { + DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret)); + ret = -1; + goto exit; } - else -#endif /* CUSTOMER_HW4 */ - /* try to bring up bus */ - if ((ret = dhd_bus_start(&dhd->pub)) != 0) { - DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret)); - ret = -1; - goto exit; - } } @@ -2937,6 +3226,11 @@ exit: dhd_stop(net); DHD_OS_WAKE_UNLOCK(&dhd->pub); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 && 1 + mutex_unlock(&_dhd_sdio_mutex_lock_); +#endif + return ret; } @@ -2949,6 +3243,15 @@ int dhd_do_driver_init(struct net_device *net) return -EINVAL; } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 && 1 +#ifdef MULTIPLE_SUPPLICANT + if (mutex_is_locked(&_dhd_sdio_mutex_lock_) != 0) { + DHD_ERROR(("%s : dhdsdio_probe is already running!\n", __FUNCTION__)); + return 0; + } +#endif +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */ + /* && defined(OEM_ANDROID) && defined(BCMSDIO) */ dhd = *(dhd_info_t **)netdev_priv(net); /* If driver is already initialized, do nothing @@ -2957,7 +3260,7 @@ int dhd_do_driver_init(struct net_device *net) DHD_TRACE(("Driver already Inititalized. Nothing to do")); return 0; } - DHD_ERROR(("%s: call dhd_open\n", __FUNCTION__)); + if (dhd_open(net) < 0) { DHD_ERROR(("Driver Init Failed \n")); return -1; @@ -3007,7 +3310,7 @@ dhd_add_if(dhd_info_t *dhd, int ifidx, void *handle, char *name, } } else if ((ifp = MALLOC(dhd->pub.osh, sizeof(dhd_if_t))) == NULL) { - DHD_ERROR(("%s: OOM - dhd_if_t\n", __FUNCTION__)); + DHD_ERROR(("%s: OOM - dhd_if_t(%d)\n", __FUNCTION__, sizeof(dhd_if_t))); return -ENOMEM; } @@ -3095,20 +3398,21 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) /* updates firmware nvram path if it was provided as module parameters */ if (strlen(firmware_path) != 0) { + bzero(fw_path, MOD_PARAM_PATHLEN); strncpy(fw_path, firmware_path, sizeof(fw_path) - 1); - fw_path[sizeof(fw_path) - 1] = '\0'; } if (strlen(nvram_path) != 0) { + bzero(nv_path, MOD_PARAM_PATHLEN); strncpy(nv_path, nvram_path, sizeof(nv_path) -1); - nv_path[sizeof(nv_path) -1] = '\0'; } -#if defined(SUPPORT_MULTIPLE_REVISION) +#if defined(CUSTOMER_HW4) && defined(SUPPORT_MULTIPLE_REVISION) if (strlen(fw_path) != 0 && - concate_revision(bus, fw_path, MOD_PARAM_PATHLEN) != 0) { + concate_revision(bus, fw_path, MOD_PARAM_PATHLEN, + nv_path, MOD_PARAM_PATHLEN) != 0) { DHD_ERROR(("%s: fail to concatnate revison \n", __FUNCTION__)); goto fail; } -#endif +#endif /* CUSTOMER_HW4 && SUPPORT_MULTIPLE_REVISION */ /* Allocate etherdev, including space for private structure */ if (!(net = alloc_etherdev(sizeof(dhd)))) { @@ -3118,10 +3422,18 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) dhd_state |= DHD_ATTACH_STATE_NET_ALLOC; /* Allocate primary dhd_info */ - if (!(dhd = MALLOC(osh, sizeof(dhd_info_t)))) { - DHD_ERROR(("%s: OOM - alloc dhd_info\n", __FUNCTION__)); - goto fail; +#if defined(CONFIG_DHD_USE_STATIC_BUF) + dhd = (void *)dhd_os_prealloc(osh, DHD_PREALLOC_DHD_INFO, sizeof(dhd_info_t)); + if (!dhd) { + DHD_INFO(("%s: OOM - Pre-alloc dhd_info\n", __FUNCTION__)); +#endif /* CONFIG_DHD_USE_STATIC_BUF */ + if (!(dhd = MALLOC(osh, sizeof(dhd_info_t)))) { + DHD_ERROR(("%s: OOM - alloc dhd_info\n", __FUNCTION__)); + goto fail; + } +#if defined(CONFIG_DHD_USE_STATIC_BUF) } +#endif /* CONFIG_DHD_USE_STATIC_BUF */ memset(dhd, 0, sizeof(dhd_info_t)); #ifdef DHDTHREAD @@ -3185,20 +3497,33 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) spin_lock_init(&dhd->sdlock); spin_lock_init(&dhd->txqlock); spin_lock_init(&dhd->dhd_lock); +#if defined(DHDTHREAD) && defined(RXFRAME_THREAD) + spin_lock_init(&dhd->rxf_lock); +#endif /* defined(DHDTHREAD) && 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"); -#if defined(CUSTOMER_HW4) && defined(PNO_SUPPORT) - wake_lock_init(&dhd->pub.pno_wakelock, WAKE_LOCK_SUSPEND, "pno_wake_lock"); -#endif -#endif + dhd->wl_wifi = MALLOC(osh, sizeof(struct wake_lock)); + dhd->wl_rxwake = MALLOC(osh, sizeof(struct wake_lock)); + dhd->wl_ctrlwake = MALLOC(osh, sizeof(struct wake_lock)); + dhd->wl_wdwake = MALLOC(osh, sizeof(struct wake_lock)); + if (!dhd->wl_wifi || !dhd->wl_rxwake || !dhd->wl_ctrlwake || !dhd->wl_wdwake) { + DHD_ERROR(("%s: mem alloc for wake lock failed\n", __FUNCTION__)); + goto fail; + } + 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); @@ -3249,13 +3574,10 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) dhd->threads_only = FALSE; } - if (dhd_dpc_prio >= 0) { + if (dhd_watchdog_prio >= 0) { /* Initialize watchdog thread */ -#ifdef USE_KTHREAD_API - PROC_START2(dhd_watchdog_thread, dhd, &dhd->thr_wdt_ctl, 0, "dhd_watchdog_thread"); -#else - PROC_START(dhd_watchdog_thread, dhd, &dhd->thr_wdt_ctl, 0); -#endif + PROC_START(dhd_watchdog_thread, dhd, &dhd->thr_wdt_ctl, 0, "dhd_watchdog_thread"); + } else { dhd->thr_wdt_ctl.thr_pid = -1; } @@ -3263,16 +3585,17 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) /* Set up the bottom half handler */ if (dhd_dpc_prio >= 0) { /* Initialize DPC thread */ -#ifdef USE_KTHREAD_API - PROC_START2(dhd_dpc_thread, dhd, &dhd->thr_dpc_ctl, 0, "dhd_dpc"); -#else - PROC_START(dhd_dpc_thread, dhd, &dhd->thr_dpc_ctl, 0); -#endif + 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; } +#ifdef RXFRAME_THREAD + bzero(&dhd->pub.skbbuf[0], sizeof(void *) * MAXSKBPEND); + /* Initialize RXF thread */ + PROC_START(dhd_rxf_thread, dhd, &dhd->thr_rxf_ctl, 0, "dhd_rxf"); +#endif #else /* Set up the bottom half handler */ tasklet_init(&dhd->tasklet, dhd_dpc, (ulong)dhd); @@ -3280,18 +3603,16 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) #endif /* DHDTHREAD */ if (dhd_sysioc) { -#ifdef USE_KTHREAD_API - PROC_START2(_dhd_sysioc_thread, dhd, &dhd->thr_sysioc_ctl, 0, "dhd_sysioc"); -#else - PROC_START(_dhd_sysioc_thread, dhd, &dhd->thr_sysioc_ctl, 0); -#endif + PROC_START(_dhd_sysioc_thread, dhd, &dhd->thr_sysioc_ctl, 0, "dhd_sysioc"); } else { dhd->thr_sysioc_ctl.thr_pid = -1; } dhd_state |= DHD_ATTACH_STATE_THREADS_CREATED; + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (1) INIT_WORK(&dhd->work_hang, dhd_hang_process); #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ + /* * Save the dhd_info into the priv */ @@ -3307,13 +3628,18 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) dhd->early_suspend.resume = dhd_late_resume; register_early_suspend(&dhd->early_suspend); dhd_state |= DHD_ATTACH_STATE_EARLYSUSPEND_DONE; -#endif +#endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */ #ifdef ARP_OFFLOAD_SUPPORT dhd->pend_ipaddr = 0; register_inetaddr_notifier(&dhd_notifier); #endif /* ARP_OFFLOAD_SUPPORT */ +#ifdef DHDTCPACK_SUPPRESS + dhd->pub.tcp_ack_info_cnt = 0; + bzero(dhd->pub.tcp_ack_info_tbl, sizeof(struct tcp_ack_info)*MAXTCPSTREAMS); +#endif /* DHDTCPACK_SUPPRESS */ + dhd_state |= DHD_ATTACH_STATE_DONE; dhd->dhd_state = dhd_state; return &dhd->pub; @@ -3351,13 +3677,31 @@ dhd_bus_start(dhd_pub_t *dhdp) /* try to download image and nvram to the dongle */ if ((dhd->pub.busstate == DHD_BUS_DOWN) && - (fw_path != NULL) && (fw_path[0] != '\0') && - (nv_path != NULL) && (nv_path[0] != '\0')) { + (fw_path[0] != '\0') && + (nv_path[0] != '\0')) { +#ifdef SHOW_NVRAM_TYPE + { /* Show nvram type in the kernel log */ + int i; + for (i = 0; nv_path[i] != '\0'; ++i) { + if (nv_path[i] == '.') { + ++i; + break; + } + } + DHD_ERROR(("%s: nvram_type = [%s]\n", __FUNCTION__, &nv_path[i])); + } +#endif /* SHOW_NVRAM_TYPE */ /* wake lock moved to dhdsdio_download_firmware */ if (!(dhd_bus_download_firmware(dhd->pub.bus, dhd->pub.osh, - fw_path, nv_path))) { - DHD_ERROR(("%s: dhdsdio_probe_download failed. firmware or nvram path is wrong\n", - __FUNCTION__)); + fw_path, nv_path))) { +#ifdef CUSTOMER_HW4 + DHD_ERROR(("%s: dhdsdio_probe_download failed. " + "firmware or nvram wrong\n", + __FUNCTION__)); +#else + DHD_ERROR(("%s: dhdsdio_probe_download failed. firmware = %s nvram = %s\n", + __FUNCTION__, fw_path, nv_path)); +#endif /* CUSTOMER_HW4 */ #ifdef DHDTHREAD if (dhd->threads_only) dhd_os_sdunlock(dhdp); @@ -3402,6 +3746,7 @@ dhd_bus_start(dhd_pub_t *dhdp) if (dhd->threads_only) dhd_os_sdunlock(dhdp); #endif /* DHDTHREAD */ + DHD_OS_WD_WAKE_UNLOCK(&dhd->pub); return -ENODEV; } @@ -3422,6 +3767,7 @@ dhd_bus_start(dhd_pub_t *dhdp) if (dhd->threads_only) dhd_os_sdunlock(dhdp); #endif /* DHDTHREAD */ + DHD_OS_WD_WAKE_UNLOCK(&dhd->pub); return -ENODEV; } @@ -3478,7 +3824,7 @@ dhd_bus_start(dhd_pub_t *dhdp) #ifdef ARP_OFFLOAD_SUPPORT if (dhd->pend_ipaddr) { #ifdef AOE_IP_ALIAS_SUPPORT - aoe_update_host_ipv4_table(&dhd->pub, dhd->pend_ipaddr, TRUE); + aoe_update_host_ipv4_table(&dhd->pub, dhd->pend_ipaddr, TRUE, 0); #endif /* AOE_IP_ALIAS_SUPPORT */ dhd->pend_ipaddr = 0; } @@ -3500,7 +3846,6 @@ bool dhd_is_concurrent_mode(dhd_pub_t *dhd) 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 @@ -3550,7 +3895,7 @@ dhd_get_concurrent_capabilites(dhd_pub_t *dhd) ret = DHD_FLAG_CONCURR_SINGLE_CHAN_MODE; if (mchan_supported) ret |= DHD_FLAG_CONCURR_MULTI_CHAN_MODE; -#if defined(WL_ENABLE_P2P_IF) +#if defined(WL_ENABLE_P2P_IF) || defined(CUSTOMER_HW4) /* For customer_hw4, although ICS, * we still support concurrent mode */ @@ -3570,26 +3915,35 @@ 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 */ - -#if !defined(WL_CFG80211) - uint up = 0; -#endif /* !defined(WL_CFG80211) */ + uint32 buf_key_b4_m4 = 1; +#if defined(BCMSUP_4WAY_HANDSHAKE) && defined(WLAN_AKM_SUITE_FT_8021X) + uint32 sup_wpa = 0; +#endif +#ifdef CUSTOM_AMPDU_BA_WSIZE + uint32 ampdu_ba_wsize = CUSTOM_AMPDU_BA_WSIZE; +#endif /* CUSTOM_AMPDU_BA_WSIZE */ + uint32 lpc = 1; uint power_mode = PM_FAST; uint32 dongle_align = DHD_SDALIGN; uint32 glom = CUSTOM_GLOM_SETTING; -#if defined(VSDB) || defined(ROAM_ENABLE) +#if (defined(CUSTOMER_HW4) || defined(BOARD_PANDA)) && (defined(VSDB) || \ + defined(ROAM_ENABLE)) uint bcn_timeout = 8; #else uint bcn_timeout = 4; -#endif -#ifdef ENABLE_BCN_LI_BCN_WAKEUP +#endif /* CUSTOMER_HW4 && (VSDB || ROAM_ENABLE) */ +#if defined(CUSTOMER_HW4) && defined(ENABLE_BCN_LI_BCN_WAKEUP) uint32 bcn_li_bcn = 1; -#endif /* ENABLE_BCN_LI_BCN_WAKEUP */ +#endif /* CUSTOMER_HW4 && ENABLE_BCN_LI_BCN_WAKEUP */ uint retry_max = 3; #if defined(ARP_OFFLOAD_SUPPORT) int arpoe = 1; #endif +#if defined(CUSTOMER_HW4) + int scan_assoc_time = 80; +#else int scan_assoc_time = DHD_SCAN_ASSOC_ACTIVE_TIME; +#endif int scan_unassoc_time = DHD_SCAN_UNASSOC_ACTIVE_TIME; int scan_passive_time = DHD_SCAN_PASSIVE_TIME; char buf[WLC_IOCTL_SMLEN]; @@ -3599,10 +3953,10 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) 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 ROAM_AP_ENV_DETECTION int roam_env_mode = AP_ENV_INDETERMINATE; #endif /* ROAM_AP_ENV_DETECTION */ - 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 */ @@ -3631,24 +3985,48 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #ifdef OKC_SUPPORT uint32 okc = 1; #endif -#ifdef DISABLE_11N - uint32 nmode = 0; -#else -#ifdef AMPDU_HOSTREORDER - uint32 hostreorder = 1; +#ifdef WLTDLS + uint32 tdls = 1; +#ifdef CUSTOMER_HW4 + uint32 tdls_idle_time = 10000; /* 10sec */ + uint32 tdls_auto_op = 1; + int32 tdls_rssi_high = -80; + int32 tdls_rssi_low = -85; #endif +#endif /* WLTDLS */ + +#ifdef DISABLE_11N + uint32 nmode = 0; #endif /* DISABLE_11N */ + +#ifdef DISABLE_11AC + uint32 vhtmode = 0; +#endif /* DISABLE_11AC */ + #if defined(VSDB) && defined(CUSTOMER_HW4) int interference_mode = 3; #endif +#ifdef USE_WL_TXBF + uint32 txbf = 1; +#endif /* USE_WL_TXBF */ +#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 PROP_TXSTATUS #ifdef PROP_TXSTATUS_VSDB + /* In case the host does not support proptxstatus, hostreorder in dongle should be off */ + uint32 hostreorder = 0; dhd->wlfc_enabled = FALSE; /* enable WLFC only if the firmware is VSDB */ #else dhd->wlfc_enabled = TRUE; #endif /* PROP_TXSTATUS_VSDB */ #endif /* PROP_TXSTATUS */ + dhd->suspend_bcn_li_dtim = CUSTOM_SUSPEND_BCN_LI_DTIM; DHD_TRACE(("Enter %s\n", __FUNCTION__)); dhd->op_mode = 0; #ifdef GET_CUSTOM_MAC_ENABLE @@ -3679,6 +4057,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) } #endif /* GET_CUSTOM_MAC_ENABLE */ + DHD_TRACE(("Firmware = %s\n", fw_path)); if ((!op_mode && strstr(fw_path, "_apsta") != NULL) || (op_mode == DHD_FLAG_HOSTAP_MODE)) { @@ -3717,7 +4096,6 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) DHD_ERROR(("%s mpc for HostAPD failed %d\n", __FUNCTION__, ret)); } #endif - } else { uint32 concurrent_mode = 0; @@ -3776,6 +4154,10 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) DHD_ERROR(("%s: country code setting failed\n", __FUNCTION__)); } +#ifdef DISABLE_11AC + bcm_mkiovar("vhtmode", (char *)&vhtmode, 4, iovbuf, sizeof(iovbuf)); + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); +#endif /* Set Listen Interval */ bcm_mkiovar("assoc_listen", (char *)&listen_interval, 4, iovbuf, sizeof(iovbuf)); @@ -3787,7 +4169,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) 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 */ -#ifdef ROAM_ENABLE +#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)); @@ -3806,8 +4188,9 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) 4, iovbuf, sizeof(iovbuf)); if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0) == BCME_OK) dhd->roam_env_detection = TRUE; - else + else { dhd->roam_env_detection = FALSE; + } } #endif /* ROAM_AP_ENV_DETECTION */ #endif /* ROAM_ENABLE */ @@ -3816,13 +4199,37 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) bcm_mkiovar("okc_enable", (char *)&okc, 4, iovbuf, sizeof(iovbuf)); dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); #endif +#ifdef WLTDLS + bcm_mkiovar("tdls_enable", (char *)&tdls, 4, iovbuf, sizeof(iovbuf)); + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); +#ifdef CUSTOMER_HW4 + bcm_mkiovar("tdls_auto_op", (char *)&tdls_auto_op, 4, iovbuf, sizeof(iovbuf)); + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + + bcm_mkiovar("tdls_idle_time", (char *)&tdls_idle_time, 4, iovbuf, sizeof(iovbuf)); + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + + bcm_mkiovar("tdls_rssi_high", (char *)&tdls_rssi_high, 4, iovbuf, sizeof(iovbuf)); + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + + bcm_mkiovar("tdls_rssi_low", (char *)&tdls_rssi_low, 4, iovbuf, sizeof(iovbuf)); + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); +#endif +#endif /* WLTDLS */ -#ifdef CONFIG_CONTROL_PM + /* 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)); + } + +#if defined(CUSTOMER_HW4) && defined(CONFIG_CONTROL_PM) sec_control_pm(dhd, &power_mode); #else /* Set PowerSave mode */ dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, sizeof(power_mode), TRUE, 0); -#endif +#endif /* CUSTOMER_HW4 && CONFIG_CONTROL_PM */ /* Match Host and Dongle rx alignment */ bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf, sizeof(iovbuf)); @@ -3873,6 +4280,60 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) } } #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 +#if defined(CUSTOMER_HW4) + frameburst = sec_control_frameburst(); +#endif /* CUSTOMER_HW4 */ + /* 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 */ +#ifdef CUSTOM_AMPDU_BA_WSIZE + /* Set ampdu ba wsize to 64 */ + 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__, CUSTOM_AMPDU_BA_WSIZE, ret)); + } +#endif /* CUSTOM_AMPDU_BA_WSIZE */ +#if defined(BCMSUP_4WAY_HANDSHAKE) && defined(WLAN_AKM_SUITE_FT_8021X) + /* Read 4-way handshake requirements. */ + 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); + if (ret >= 0) + 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 */ + + bcm_mkiovar("buf_key_b4_m4", (char *)&buf_key_b4_m4, 4, iovbuf, sizeof(iovbuf)); + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); /* Read event_msgs mask */ bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf)); @@ -3919,6 +4380,9 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) 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) { @@ -3961,21 +4425,19 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) 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 = 5; - /* Setup filter to allow only unicast */ - dhd->pktfilter[0] = "100 0 0 0 0x01 0x00"; dhd->pktfilter[1] = NULL; dhd->pktfilter[2] = NULL; dhd->pktfilter[3] = NULL; /* Add filter to pass multicastDNS packet and NOT filter out as Broadcast */ dhd->pktfilter[4] = "104 0 0 0 0xFFFFFFFFFFFF 0x01005E0000FB"; -#ifdef CUSTOMER_HW4 -#ifdef GAN_LITE_NAT_KEEPALIVE_FILTER +#if defined(CUSTOMER_HW4) && defined(GAN_LITE_NAT_KEEPALIVE_FILTER) dhd->pktfilter_count = 4; /* Setup filter to block broadcast and NAT Keepalive packets */ dhd->pktfilter[0] = "100 0 0 0 0xffffff 0xffffff"; /* discard all broadcast packets */ @@ -3984,23 +4446,19 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) dhd->pktfilter[3] = NULL; #else /* Setup filter to allow only unicast */ -#if defined(BLOCK_IPV6_PACKET) +#if defined(BLOCK_IPV6_PACKET) && defined(CUSTOMER_HW4) dhd->pktfilter[0] = "100 0 0 0 " HEX_PREF_STR UNI_FILTER_STR ZERO_ADDR_STR ETHER_TYPE_STR IPV6_FILTER_STR " " HEX_PREF_STR ZERO_ADDR_STR ZERO_ADDR_STR ETHER_TYPE_STR ZERO_TYPE_STR; #else dhd->pktfilter[0] = "100 0 0 0 0x01 0x00"; -#endif /* BLOCK_IPV6_PACKET */ -#if defined(PASS_IPV4_SUSPEND) +#endif /* BLOCK_IPV6_PACKET && CUSTOMER_HW4 */ +#if defined(PASS_IPV4_SUSPEND) && defined(CUSTOMER_HW4) dhd->pktfilter_count = 5; dhd->pktfilter[4] = "104 0 0 0 0xFFFFFF 0x01005E"; -#endif -#endif /* GAN_LITE_NAT_KEEPALIVE_FILTER */ -#ifdef PASS_ARP_PACKET - dhd->pktfilter[dhd->pktfilter_count++] = "105 0 0 12 0xFFFF 0x0806"; -#endif -#endif /* CUSTOMER_HW4 */ +#endif /* PASS_IPV4_SUSPEND && CUSTOMER_HW4 */ +#endif /* GAN_LITE_NAT_KEEPALIVE_FILTER && CUSTOMER_HW4 */ #if defined(SOFTAP) if (ap_fw_loaded) { @@ -4014,30 +4472,21 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) 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)); #else -#ifdef AMPDU_HOSTREORDER +#if defined(PROP_TXSTATUS) && defined(PROP_TXSTATUS_VSDB) bcm_mkiovar("ampdu_hostreorder", (char *)&hostreorder, 4, buf, sizeof(buf)); dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0); -#endif /* AMPDU_HOSTREORDER */ +#endif #endif /* DISABLE_11N */ -#if !defined(WL_CFG80211) - /* Force STA UP */ - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_UP, (char *)&up, sizeof(up), TRUE, 0)) < 0) { - DHD_ERROR(("%s Setting WL UP failed %d\n", __FUNCTION__, ret)); - goto done; - } -#endif - #if defined(VSDB) && defined(CUSTOMER_HW4) dhd_wl_ioctl_cmd(dhd, WLC_SET_INTERFERENCE_MODE, (int *)&interference_mode, sizeof(int), TRUE, 0); #endif -#ifdef ENABLE_BCN_LI_BCN_WAKEUP +#if defined(CUSTOMER_HW4) && defined(ENABLE_BCN_LI_BCN_WAKEUP) bcm_mkiovar("bcn_li_bcn", (char *)&bcn_li_bcn, 4, iovbuf, sizeof(iovbuf)); dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -#endif /* ENABLE_BCN_LI_BCN_WAKEUP */ - +#endif /* CUSTOMER_HW4 && ENABLE_BCN_LI_BCN_WAKEUP */ /* query for 'ver' to get version info from firmware */ memset(buf, 0, sizeof(buf)); ptr = buf; @@ -4049,14 +4498,9 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) /* Print fw version info */ DHD_ERROR(("Firmware version = %s\n", buf)); - dhd_set_version_info(dhd, buf); - - DHD_BLOG(buf, strlen(buf) + 1); - DHD_BLOG(dhd_version, strlen(dhd_version) + 1); - /* Check and adjust IOCTL response timeout for Manufactring firmware */ if (strstr(buf, MANUFACTRING_FW) != NULL) { - dhd_os_set_ioctl_resp_timeout(IOCTL_RESP_TIMEOUT * 10); + dhd_os_set_ioctl_resp_timeout(20000); DHD_ERROR(("%s : adjust IOCTL response time for Manufactring Firmware\n", __FUNCTION__)); } @@ -4120,7 +4564,7 @@ int dhd_change_mtu(dhd_pub_t *dhdp, int new_mtu, int ifidx) #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) +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; @@ -4129,13 +4573,13 @@ aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add) 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)); + 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); + dhd_aoe_hostip_clr(dhd_pub, idx); if (ret) { DHD_ERROR(("%s failed\n", __FUNCTION__)); @@ -4156,19 +4600,24 @@ aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add) if (ipv4_buf[i] != 0) { /* add back host_ip entries from our local cache */ - dhd_arp_offload_add_ip(dhd_pub, ipv4_buf[i]); + 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)); + 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_device_event(struct notifier_block *this, unsigned long event, void *ptr) @@ -4177,19 +4626,48 @@ static int dhd_device_event(struct notifier_block *this, dhd_info_t *dhd; dhd_pub_t *dhd_pub; + int idx; - if (!ifa) + 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)) { +#ifdef WLP2P + if (!wl_cfgp2p_is_ifops(ifa->ifa_dev->dev->netdev_ops)) +#endif + return NOTIFY_DONE; + } +#endif /* LINUX_VERSION_CODE */ dhd = *(dhd_info_t **)netdev_priv(ifa->ifa_dev->dev); + if (!dhd) + return NOTIFY_DONE; + dhd_pub = &dhd->pub; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) - if (ifa->ifa_dev->dev->netdev_ops == &dhd_ops_pri) { -#else - if (ifa->ifa_dev->dev) { -#endif - switch (event) { + 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)); @@ -4205,17 +4683,10 @@ static int dhd_device_event(struct notifier_block *this, } #ifdef AOE_IP_ALIAS_SUPPORT - if (!(dhd_pub->op_mode & DHD_FLAG_HOSTAP_MODE)) { - if (ifa->ifa_label[strlen(ifa->ifa_label)-2] == 0x3a) { - /* 0x3a = ':' */ - DHD_ARPOE(("%s:add aliased IP to AOE hostip cache\n", - __FUNCTION__)); - aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, TRUE); - } - else - aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, TRUE); - } -#endif + 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: @@ -4223,20 +4694,12 @@ static int dhd_device_event(struct notifier_block *this, __FUNCTION__, ifa->ifa_label, ifa->ifa_address)); dhd->pend_ipaddr = 0; #ifdef AOE_IP_ALIAS_SUPPORT - if (!(dhd_pub->op_mode & DHD_FLAG_HOSTAP_MODE)) { - if (!(ifa->ifa_label[strlen(ifa->ifa_label)-2] == 0x3a)) { - /* 0x3a = ':' */ - DHD_ARPOE(("%s: primary interface is down," - " AOE clr all\n", __FUNCTION__)); - dhd_aoe_hostip_clr(&dhd->pub); - dhd_aoe_arp_clr(&dhd->pub); - } else - aoe_update_host_ipv4_table(dhd_pub, - ifa->ifa_address, FALSE); - } + 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); - dhd_aoe_arp_clr(&dhd->pub); + dhd_aoe_hostip_clr(&dhd->pub, idx); + dhd_aoe_arp_clr(&dhd->pub, idx); #endif /* AOE_IP_ALIAS_SUPPORT */ break; @@ -4244,7 +4707,6 @@ static int dhd_device_event(struct notifier_block *this, DHD_ARPOE(("%s: do noting for [%s] Event: %lu\n", __func__, ifa->ifa_label, event)); break; - } } return NOTIFY_DONE; } @@ -4258,7 +4720,7 @@ dhd_net_attach(dhd_pub_t *dhdp, int ifidx) int err = 0; uint8 temp_addr[ETHER_ADDR_LEN] = { 0x00, 0x90, 0x4c, 0x11, 0x22, 0x33 }; - DHD_ERROR(("%s: ifidx %d\n", __FUNCTION__, ifidx)); + DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx)); ASSERT(dhd && dhd->iflist[ifidx]); @@ -4431,7 +4893,7 @@ void dhd_detach(dhd_pub_t *dhdp) if (dhd->early_suspend.suspend) unregister_early_suspend(&dhd->early_suspend); } -#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */ +#endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) cancel_work_sync(&dhd->work_hang); @@ -4501,11 +4963,15 @@ void dhd_detach(dhd_pub_t *dhdp) if (dhd->thr_dpc_ctl.thr_pid >= 0) { PROC_STOP(&dhd->thr_dpc_ctl); } +#ifdef RXFRAME_THREAD + if (dhd->thr_rxf_ctl.thr_pid >= 0) { + PROC_STOP(&dhd->thr_rxf_ctl); + } +#endif else #endif /* DHDTHREAD */ tasklet_kill(&dhd->tasklet); } - #ifdef WL_CFG80211 if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) { wl_cfg80211_detach(NULL); @@ -4520,16 +4986,32 @@ void dhd_detach(dhd_pub_t *dhdp) /* && defined(CONFIG_PM_SLEEP) */ if (dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT) { + printk("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); -#if defined(CUSTOMER_HW4) && defined(PNO_SUPPORT) - wake_lock_destroy(&dhdp->pno_wakelock); -#endif + if (dhd->wl_wifi) { + wake_lock_destroy(dhd->wl_wifi); + MFREE(dhd->pub.osh, dhd->wl_wifi, sizeof(struct wake_lock)); + dhd->wl_wifi = NULL; + } + if (dhd->wl_rxwake) { + wake_lock_destroy(dhd->wl_rxwake); + MFREE(dhd->pub.osh, dhd->wl_rxwake, sizeof(struct wake_lock)); + dhd->wl_rxwake = NULL; + } + if (dhd->wl_ctrlwake) { + wake_lock_destroy(dhd->wl_ctrlwake); + MFREE(dhd->pub.osh, dhd->wl_ctrlwake, sizeof(struct wake_lock)); + dhd->wl_ctrlwake = NULL; + } + if (dhd->wl_wdwake) { + wake_lock_destroy(dhd->wl_wdwake); + MFREE(dhd->pub.osh, dhd->wl_wdwake, sizeof(struct wake_lock)); + dhd->wl_wdwake = NULL; + } #endif /* CONFIG_HAS_WAKELOCK */ } } @@ -4559,8 +5041,19 @@ dhd_free(dhd_pub_t *dhdp) } } dhd = (dhd_info_t *)dhdp->info; - if (dhd) - MFREE(dhd->pub.osh, dhd, sizeof(*dhd)); +#if defined(CONFIG_DHD_USE_STATIC_BUF) + /* If pointer is allocated by dhd_os_prealloc then avoid MFREE */ + if (dhd != (dhd_info_t *)dhd_os_prealloc(NULL, DHD_PREALLOC_DHD_INFO, 0)) { +#endif /* CONFIG_DHD_USE_STATIC_BUF */ + if (dhd) + MFREE(dhd->pub.osh, dhd, sizeof(*dhd)); +#if defined(CONFIG_DHD_USE_STATIC_BUF) + } + else { + if (dhd) + dhd = NULL; + } +#endif /* CONFIG_DHD_USE_STATIC_BUF */ } } @@ -4581,6 +5074,10 @@ dhd_module_cleanup(void) } +#if defined(CONFIG_WIFI_CONTROL_FUNC) +extern bool g_wifi_poweron; +#endif /* CONFIG_WIFI_CONTROL_FUNC */ + static int __init dhd_module_init(void) { @@ -4650,6 +5147,17 @@ dhd_module_init(void) #endif +#if defined(CONFIG_WIFI_CONTROL_FUNC) + /* If the wifi_set_power() is failed, + * we need to jump error handling routines. + */ + if (!g_wifi_poweron) { + printk("%s: wifi_set_power() failed\n", __FUNCTION__); + error = -ENODEV; + goto fail_1; + } +#endif /* defined(CONFIG_WIFI_CONTROL_FUNC) */ + #if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) sema_init(&dhd_registration_sem, 0); #endif @@ -4788,18 +5296,23 @@ dhd_os_wd_timer(void *bus, uint wdtick) DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - if (!dhd) + if (!dhd) { + DHD_ERROR(("%s: dhd NULL\n", __FUNCTION__)); return; + } + if (wdtick) + DHD_OS_WD_WAKE_LOCK(pub); flags = dhd_os_spin_lock(pub); /* don't start the wd until fw is loaded */ if (pub->busstate == DHD_BUS_DOWN) { dhd_os_spin_unlock(pub, flags); + DHD_OS_WD_WAKE_UNLOCK(pub); return; } - /* totally stop the timer */ + /* Totally stop the timer */ if (!wdtick && dhd->wd_timer_valid == TRUE) { dhd->wd_timer_valid = FALSE; dhd_os_spin_unlock(pub, flags); @@ -4808,6 +5321,7 @@ dhd_os_wd_timer(void *bus, uint wdtick) #else del_timer(&dhd->timer); #endif /* DHDTHREAD */ + DHD_OS_WD_WAKE_UNLOCK(pub); return; } @@ -4932,6 +5446,48 @@ dhd_os_sdtxunlock(dhd_pub_t *pub) dhd_os_sdunlock(pub); } +#if defined(DHDTHREAD) && defined(RXFRAME_THREAD) +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); +} +#endif /* defined(DHDTHREAD) && defined(RXFRAME_THREAD) */ + +#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 */ + #if defined(CONFIG_DHD_USE_STATIC_BUF) uint8* dhd_os_prealloc(void *osh, int section, uint size) { @@ -5129,9 +5685,9 @@ void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar) struct dhd_info *dhdinfo = dhd->info; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) - int timeout = msecs_to_jiffies(2000); + int timeout = msecs_to_jiffies(IOCTL_RESP_TIMEOUT); #else - int timeout = 2 * HZ; + int timeout = (IOCTL_RESP_TIMEOUT / 1000) * HZ; #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ dhd_os_sdunlock(dhd); @@ -5197,19 +5753,16 @@ int net_os_set_suspend(struct net_device *dev, int val, int force) #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_dtim_skip(struct net_device *dev, int val) +int net_os_set_suspend_bcn_li_dtim(struct net_device *dev, int val) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); if (dhd) - dhd->pub.dtim_skip = val; + dhd->pub.suspend_bcn_li_dtim = val; return 0; } @@ -5236,10 +5789,10 @@ int net_os_rxfilter_add_remove(struct net_device *dev, int add_remove, int num) filterp = "102 0 0 0 0xFFFFFF 0x01005E"; break; case DHD_MULTICAST6_FILTER_NUM: -#if defined(BLOCK_IPV6_PACKET) +#if defined(BLOCK_IPV6_PACKET) && defined(CUSTOMER_HW4) /* customer want to use NO IPV6 packets only */ return ret; -#endif +#endif /* BLOCK_IPV6_PACKET && CUSTOMER_HW4 */ filterp = "103 0 0 0 0xFFFF 0x3333"; break; default: @@ -5254,9 +5807,9 @@ int net_os_rxfilter_add_remove(struct net_device *dev, int add_remove, int num) #endif /* GAN_LITE_NAT_KEEPALIVE_FILTER */ } -int net_os_enable_packet_filter(struct net_device *dev, int val) +int dhd_os_enable_packet_filter(dhd_pub_t *dhdp, int val) + { - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); int ret = 0; /* Packet filtering is set only if we still in early-suspend and @@ -5264,26 +5817,35 @@ int net_os_enable_packet_filter(struct net_device *dev, int val) * 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 (dhd && dhd->pub.up) { - if (dhd->pub.in_suspend) { - if (!val || (val && !dhd->pub.suspend_disable_flag)) { - dhd_enable_packet_filter(val, &dhd->pub); - } + 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_info_t **)netdev_priv(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_info_t **)netdev_priv(dev); -#if defined(USE_STAMAC_4SOFTAP) + +#if defined(CUSTOMER_HW4) && defined(USE_STAMAC_4SOFTAP) /* Writing STA's MAC ID to the Dongle for SOFTAP */ if (_dhd_set_mac_address(dhd, 0, &dhd->pub.mac) == 0) DHD_INFO(("dhd_bus_start: MAC ID is overwritten\n")); -#endif +#endif /* CUSTOMER_HW4 && USE_STAMAC_4SOFTAP */ + return dhd_preinit_ioctls(&dhd->pub); } @@ -5354,12 +5916,20 @@ static void dhd_hang_process(struct work_struct *work) int dhd_os_send_hang_message(dhd_pub_t *dhdp) { int ret = 0; + DHD_ERROR(("%s : Enter \n",__FUNCTION__)); + if (dhdp) { if (!dhdp->hang_was_sent) { dhdp->hang_was_sent = 1; - schedule_work(&dhdp->info->work_hang); + ret = schedule_work(&dhdp->info->work_hang); + if(!ret) + DHD_ERROR(("%s : schedule_task fail \n",__FUNCTION__)); + else + DHD_ERROR(("%s : schedule_task success \n",__FUNCTION__)); } } + else + DHD_ERROR(("%s : dhdp is null \n",__FUNCTION__)); return ret; } @@ -5376,7 +5946,7 @@ int net_os_send_hang_message(struct net_device *dev) #endif return ret; } -#endif /* (OEM_ANDROID) */ +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) && OEM_ANDROID */ void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec) { @@ -5388,6 +5958,7 @@ void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec) #endif } } + void dhd_bus_band_set(struct net_device *dev, uint band) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); @@ -5398,7 +5969,6 @@ void dhd_bus_band_set(struct net_device *dev, uint band) } } - void dhd_net_if_lock(struct net_device *dev) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); @@ -5470,7 +6040,7 @@ dhd_get_pend_8021x_cnt(dhd_info_t *dhd) return (atomic_read(&dhd->pend_8021x_cnt)); } -#define MAX_WAIT_FOR_8021X_TX 25 +#define MAX_WAIT_FOR_8021X_TX 50 int dhd_wait_pend8021x(struct net_device *dev) @@ -5490,7 +6060,10 @@ dhd_wait_pend8021x(struct net_device *dev) 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; } @@ -5543,10 +6116,10 @@ int dhd_os_wake_lock_timeout(dhd_pub_t *pub) 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, + 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, + wake_lock_timeout(dhd->wl_ctrlwake, msecs_to_jiffies(dhd->wakelock_ctrl_timeout_enable)); #endif dhd->wakelock_rx_timeout_enable = 0; @@ -5566,22 +6139,6 @@ int net_os_wake_lock_timeout(struct net_device *dev) return ret; } -#if defined(CUSTOMER_HW4) && defined(PNO_SUPPORT) && defined(CONFIG_HAS_WAKELOCK) -int net_os_wake_lock_timeout_for_pno(struct net_device *dev, int sec) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - int ret = 0; - unsigned long flags; - - if (dhd) { - spin_lock_irqsave(&dhd->wakelock_spinlock, flags); - wake_lock_timeout(&dhd->pub.pno_wakelock, HZ * sec); - spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); - } - return ret; -} -#endif - int dhd_os_wake_lock_rx_timeout_enable(dhd_pub_t *pub, int val) { dhd_info_t *dhd = (dhd_info_t *)(pub->info); @@ -5640,11 +6197,11 @@ int dhd_os_wake_lock(dhd_pub_t *pub) spin_lock_irqsave(&dhd->wakelock_spinlock, flags); #ifdef CONFIG_HAS_WAKELOCK if (!dhd->wakelock_counter) - wake_lock(&dhd->wl_wifi); -#elif defined(CUSTOMER_HW4) && defined(CONFIG_PM_SLEEP) && defined(PLATFORM_SLP) - /* SLP_wakelock_alternative_code */ - pm_stay_awake(pm_dev); -#endif /* CUSTOMER_HW4 && CONFIG_PM_SLEEP && PLATFORM_SLP */ + wake_lock(dhd->wl_wifi); +#elif 1 && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) + if (pm_dev) + pm_stay_awake(pm_dev); +#endif dhd->wakelock_counter++; ret = dhd->wakelock_counter; spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); @@ -5675,11 +6232,11 @@ int dhd_os_wake_unlock(dhd_pub_t *pub) dhd->wakelock_counter--; #ifdef CONFIG_HAS_WAKELOCK if (!dhd->wakelock_counter) - wake_unlock(&dhd->wl_wifi); -#elif defined(CUSTOMER_HW4) && defined(CONFIG_PM_SLEEP) && defined(PLATFORM_SLP) - /* SLP_wakelock_alternative_code */ - pm_relax(pm_dev); -#endif /* CUSTOMER_HW4 && CONFIG_PM_SLEEP && PLATFORM_SLP */ + wake_unlock(dhd->wl_wifi); +#elif 1 && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) + if (pm_dev) + pm_relax(pm_dev); +#endif ret = dhd->wakelock_counter; } spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); @@ -5689,30 +6246,23 @@ int dhd_os_wake_unlock(dhd_pub_t *pub) int dhd_os_check_wakelock(void *dhdp) { -#ifdef CONFIG_HAS_WAKELOCK +#if defined(CONFIG_HAS_WAKELOCK) || (1 && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, \ + 36))) dhd_pub_t *pub = (dhd_pub_t *)dhdp; dhd_info_t *dhd; if (!pub) return 0; dhd = (dhd_info_t *)(pub->info); +#endif /* CONFIG_HAS_WAKELOCK || BCMSDIO */ - if (dhd && wake_lock_active(&dhd->wl_wifi)) +#ifdef CONFIG_HAS_WAKELOCK + if (dhd && wake_lock_active(dhd->wl_wifi)) return 1; -#elif defined(CUSTOMER_HW4) && defined(CONFIG_PM_SLEEP) && defined(PLATFORM_SLP) - /* SLP_wakelock_alternative_code */ - dhd_pub_t *pub = (dhd_pub_t *)dhdp; - dhd_info_t *dhd; - - if (!pub) - return 0; - dhd = (dhd_info_t *)(pub->info); - - DHD_ERROR(("%s : wakelock_count = %d\n", __func__, dhd->wakelock_counter)); - - if (dhd && (dhd->wakelock_counter > 0)) +#elif 1 && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) + if (dhd && (dhd->wakelock_counter > 0) && pm_dev) return 1; -#endif /* CUSTOMER_HW4 && CONFIG_PM_SLEEP && PLATFORM_SLP */ +#endif return 0; } int net_os_wake_unlock(struct net_device *dev) @@ -5725,31 +6275,58 @@ int net_os_wake_unlock(struct net_device *dev) return ret; } -int dhd_os_check_if_up(void *dhdp) +int dhd_os_wd_wake_lock(dhd_pub_t *pub) { - dhd_pub_t *pub = (dhd_pub_t *)dhdp; + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + unsigned long flags; + int ret = 0; - if (!pub) - return 0; - return pub->up; + 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) { + if (dhd->wl_wdwake) + wake_lock(dhd->wl_wdwake); + else { + spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); + return 0; + } + } +#endif + dhd->wakelock_wd_counter++; + ret = dhd->wakelock_wd_counter; + spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); + } + return ret; } -/* function to collect firmware, chip id and chip version info */ -void dhd_set_version_info(dhd_pub_t *dhdp, char *fw) +int dhd_os_wd_wake_unlock(dhd_pub_t *pub) { - int i; - - i = snprintf(info_string, sizeof(info_string), - " Driver: %s\n Firmware: %s ", EPI_VERSION_STR, fw); - - if (!dhdp) - return; + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + unsigned long flags; + int ret = 0; - 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)); + 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; } +int dhd_os_check_if_up(void *dhdp) +{ + dhd_pub_t *pub = (dhd_pub_t *)dhdp; + if (!pub) + return 0; + return pub->up; +} int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd) { int ifidx; @@ -5762,6 +6339,9 @@ int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd) } dhd = *(dhd_info_t **)netdev_priv(net); + if (!dhd) + return -EINVAL; + ifidx = dhd_net2idx(dhd, net); if (ifidx == DHD_BAD_IF) { DHD_ERROR(("%s bad ifidx\n", __FUNCTION__)); @@ -5785,7 +6365,7 @@ bool dhd_os_check_hang(dhd_pub_t *dhdp, int ifidx, int ret) } #if defined(WL_CFG80211) && defined(SUPPORT_DEEP_SLEEP) -#define MAX_TRY_CNT 5 /* Number of tries to disable deepsleep */ +#define MAX_TRY_CNT 5 /* Number of tries to disable deepsleep */ int dhd_deepsleep(struct net_device *dev, int flag) { char iovbuf[20]; @@ -5799,62 +6379,67 @@ int dhd_deepsleep(struct net_device *dev, int flag) dhdp = &dhd->pub; switch (flag) { - case 1 : /* Deepsleep on */ - DHD_ERROR(("[WiFi] Deepsleep On\n")); - /* give some time to _dhd_sysioc_thread() before deepsleep */ - msleep(200); + case 1 : /* Deepsleep on */ + DHD_ERROR(("[WiFi] Deepsleep On\n")); + /* give some time to _dhd_sysioc_thread() before deepsleep */ + msleep(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(("[WiFi] Deepsleep Off\n")); - - /* Disable Deepsleep */ - for (cnt = 0; cnt < MAX_TRY_CNT; cnt++) { + /* Disable MPC */ powervar = 0; memset(iovbuf, 0, sizeof(iovbuf)); - bcm_mkiovar("deepsleep", (char *)&powervar, 4, iovbuf, 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)); - 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, ok , count : %d\n", cnt)); - break; + dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + break; + + case 0: /* Deepsleep Off */ + DHD_ERROR(("[WiFi] 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; + /* 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; } -#endif /* SUPPORT_DEEP_SLEEP */ +#endif /* WL_CFG80211 && SUPPORT_DEEP_SLEEP */ #ifdef PROP_TXSTATUS extern int dhd_wlfc_interface_entry_update(void* state, ewlfc_mac_entry_action_t action, uint8 ifid, @@ -5864,34 +6449,23 @@ extern int dhd_wlfc_FIFOcreditmap_update(void* state, uint8* credits); int dhd_wlfc_interface_event(struct dhd_info *dhd, ewlfc_mac_entry_action_t action, uint8 ifid, uint8 iftype, uint8* ea) { - int ret = BCME_OK; + if (dhd->pub.wlfc_state == NULL) + return BCME_OK; - dhd_os_wlfc_block(&dhd->pub); - if (dhd->pub.wlfc_state != NULL) - ret = dhd_wlfc_interface_entry_update(dhd->pub.wlfc_state, action, ifid, iftype, ea); - dhd_os_wlfc_unblock(&dhd->pub); - return ret; + return dhd_wlfc_interface_entry_update(dhd->pub.wlfc_state, action, ifid, iftype, ea); } int dhd_wlfc_FIFOcreditmap_event(struct dhd_info *dhd, uint8* event_data) { - int ret = BCME_OK; + if (dhd->pub.wlfc_state == NULL) + return BCME_OK; - dhd_os_wlfc_block(&dhd->pub); - if (dhd->pub.wlfc_state != NULL) - ret = dhd_wlfc_FIFOcreditmap_update(dhd->pub.wlfc_state, event_data); - dhd_os_wlfc_unblock(&dhd->pub); - return ret; + return dhd_wlfc_FIFOcreditmap_update(dhd->pub.wlfc_state, event_data); } int dhd_wlfc_event(struct dhd_info *dhd) { - int ret; - - dhd_os_wlfc_block(&dhd->pub); - ret = dhd_wlfc_enable(&dhd->pub); - dhd_os_wlfc_unblock(&dhd->pub); - return ret; + return dhd_wlfc_enable(&dhd->pub); } #endif /* PROP_TXSTATUS */ -- cgit v1.1