summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/bcmdhd/dhd_linux.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/bcmdhd/dhd_linux.c')
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_linux.c742
1 files changed, 497 insertions, 245 deletions
diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c
index 80a75699e270..6ba7df1cac32 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 291449 2011-10-22 12:16:26Z $
+ * $Id: dhd_linux.c 329682 2012-04-26 09:20:38Z $
*/
#include <typedefs.h>
@@ -50,6 +50,7 @@
#include <epivers.h>
#include <bcmutils.h>
#include <bcmendian.h>
+#include <bcmdevs.h>
#include <proto/ethernet.h>
#include <dngl_stats.h>
@@ -110,6 +111,7 @@ extern bool ap_fw_loaded;
#include <wl_android.h>
#ifdef ARP_OFFLOAD_SUPPORT
+void aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add);
static int dhd_device_event(struct notifier_block *this,
unsigned long event,
void *ptr);
@@ -128,6 +130,9 @@ DECLARE_WAIT_QUEUE_HEAD(dhd_dpc_wait);
#if defined(OOB_INTR_ONLY)
extern void dhd_enable_oob_intr(struct dhd_bus *bus, bool enable);
#endif /* defined(OOB_INTR_ONLY) */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
+static void dhd_hang_process(struct work_struct *work);
+#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
MODULE_LICENSE("GPL v2");
#endif /* LinuxVer */
@@ -154,11 +159,10 @@ print_tainted()
extern wl_iw_extra_params_t g_wl_iw_params;
#endif /* defined(CONFIG_BCMDHD_WEXT) */
-#if defined(CONFIG_HAS_EARLYSUSPEND)
+#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
#include <linux/earlysuspend.h>
-extern int dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len);
-extern int dhd_get_dtim_skip(dhd_pub_t *dhd);
#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */
+extern int dhd_get_dtim_skip(dhd_pub_t *dhd);
#ifdef PKT_FILTER_SUPPORT
extern void dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg);
@@ -247,11 +251,15 @@ typedef struct dhd_info {
bool dhd_tasklet_create;
#endif /* DHDTHREAD */
tsk_ctl_t thr_sysioc_ctl;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
+ struct work_struct work_hang;
+#endif
/* 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 */
#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
@@ -259,10 +267,12 @@ typedef struct dhd_info {
* calls and wifi_on or wifi_off
*/
struct mutex dhd_net_if_mutex;
+ struct mutex dhd_suspend_mutex;
#endif
spinlock_t wakelock_spinlock;
int wakelock_counter;
- int wakelock_timeout_enable;
+ int wakelock_rx_timeout_enable;
+ int wakelock_ctrl_timeout_enable;
/* Thread to issue ioctl for multicast */
bool set_macaddress;
@@ -271,9 +281,13 @@ typedef struct dhd_info {
atomic_t pend_8021x_cnt;
dhd_attach_states_t dhd_state;
-#ifdef CONFIG_HAS_EARLYSUSPEND
+#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
struct early_suspend early_suspend;
#endif /* CONFIG_HAS_EARLYSUSPEND */
+
+#ifdef ARP_OFFLOAD_SUPPORT
+ u32 pend_ipaddr;
+#endif /* ARP_OFFLOAD_SUPPORT */
} dhd_info_t;
/* Definitions to provide path to the firmware and nvram
@@ -282,6 +296,8 @@ typedef struct dhd_info {
char firmware_path[MOD_PARAM_PATHLEN];
char nvram_path[MOD_PARAM_PATHLEN];
+int op_mode = 0;
+module_param(op_mode, int, 0644);
extern int wl_control_wl_start(struct net_device *dev);
extern int net_os_send_hang_message(struct net_device *dev);
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
@@ -353,25 +369,6 @@ uint dhd_radio_up = 1;
char iface_name[IFNAMSIZ] = {'\0'};
module_param_string(iface_name, iface_name, IFNAMSIZ, 0);
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
-#define DAEMONIZE(a) daemonize(a); \
- allow_signal(SIGKILL); \
- allow_signal(SIGTERM);
-#else /* Linux 2.4 (w/o preemption patch) */
-#define RAISE_RX_SOFTIRQ() \
- cpu_raise_softirq(smp_processor_id(), NET_RX_SOFTIRQ)
-#define DAEMONIZE(a) daemonize(); \
- do { if (a) \
- strncpy(current->comm, a, MIN(sizeof(current->comm), (strlen(a) + 1))); \
- } while (0);
-#endif /* LINUX_VERSION_CODE */
-
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
-#define BLOCKABLE() (!in_atomic())
-#else
-#define BLOCKABLE() (!in_interrupt())
-#endif
-
/* The following are specific to the SDIO dongle */
/* IOCTL response timeout */
@@ -437,6 +434,11 @@ static char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR
;
static void dhd_net_if_lock_local(dhd_info_t *dhd);
static void dhd_net_if_unlock_local(dhd_info_t *dhd);
+static void dhd_suspend_lock(dhd_pub_t *dhdp);
+static void dhd_suspend_unlock(dhd_pub_t *dhdp);
+#if !defined(AP) && defined(WLP2P) && defined(WL_ENABLE_P2P_IF)
+static u32 dhd_concurrent_fw(dhd_pub_t *dhd);
+#endif
#ifdef WLMEDIA_HTSF
void htsf_update(dhd_info_t *dhd, void *data);
@@ -479,7 +481,7 @@ static int dhd_sleep_pm_callback(struct notifier_block *nfb, unsigned long actio
{
int ret = NOTIFY_DONE;
-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39))
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39))
switch (action) {
case PM_HIBERNATION_PREPARE:
case PM_SUSPEND_PREPARE:
@@ -499,7 +501,7 @@ static int dhd_sleep_pm_callback(struct notifier_block *nfb, unsigned long actio
static struct notifier_block dhd_sleep_pm_notifier = {
.notifier_call = dhd_sleep_pm_callback,
- .priority = 0
+ .priority = 10
};
extern int register_pm_notifier(struct notifier_block *nb);
extern int unregister_pm_notifier(struct notifier_block *nb);
@@ -511,7 +513,8 @@ static void dhd_set_packet_filter(int value, dhd_pub_t *dhd)
DHD_TRACE(("%s: %d\n", __FUNCTION__, value));
/* 1 - Enable packet filter, only allow unicast packet to send up */
/* 0 - Disable packet filter */
- if (dhd_pkt_filter_enable) {
+ if (dhd_pkt_filter_enable && (!value ||
+ (dhd_check_ap_wfd_mode_set(dhd) == FALSE))) {
int i;
for (i = 0; i < dhd->pktfilter_count; i++) {
@@ -523,7 +526,6 @@ static void dhd_set_packet_filter(int value, dhd_pub_t *dhd)
#endif
}
-#if defined(CONFIG_HAS_EARLYSUSPEND)
static int dhd_set_suspend(int value, dhd_pub_t *dhd)
{
int power_mode = PM_MAX;
@@ -535,70 +537,76 @@ static int dhd_set_suspend(int value, dhd_pub_t *dhd)
DHD_TRACE(("%s: enter, value = %d in_suspend=%d\n",
__FUNCTION__, value, dhd->in_suspend));
+ dhd_suspend_lock(dhd);
if (dhd && dhd->up) {
if (value && dhd->in_suspend) {
- /* Kernel suspended */
- DHD_ERROR(("%s: force extra Suspend setting \n", __FUNCTION__));
-
- dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode,
- sizeof(power_mode), TRUE, 0);
+ /* Kernel suspended */
+ DHD_ERROR(("%s: force extra Suspend setting \n", __FUNCTION__));
- /* Enable packet filter, only allow unicast packet to send up */
- dhd_set_packet_filter(1, dhd);
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode,
+ sizeof(power_mode), TRUE, 0);
- /* 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);
- 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);
+ /* Enable packet filter, only allow unicast packet to send up */
+ dhd_set_packet_filter(1, dhd);
- /* 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);
- } else {
+ /* 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);
+ 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);
+
+ /* 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);
+ } else {
- /* Kernel resumed */
- DHD_TRACE(("%s: Remove extra suspend setting \n", __FUNCTION__));
+ /* Kernel resumed */
+ DHD_TRACE(("%s: Remove extra suspend setting \n", __FUNCTION__));
- power_mode = PM_FAST;
- dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode,
- sizeof(power_mode), TRUE, 0);
+ power_mode = PM_FAST;
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode,
+ sizeof(power_mode), TRUE, 0);
- /* disable pkt filter */
- dhd_set_packet_filter(0, dhd);
+ /* disable pkt filter */
+ dhd_set_packet_filter(0, dhd);
- /* restore pre-suspend setting for dtim_skip */
- bcm_mkiovar("bcn_li_dtim", (char *)&dhd->dtim_skip,
- 4, iovbuf, sizeof(iovbuf));
+ /* restore pre-suspend setting for dtim_skip */
+ bcm_mkiovar("bcn_li_dtim", (char *)&dhd->dtim_skip,
+ 4, iovbuf, sizeof(iovbuf));
- dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
- roamvar = dhd_roam_disable;
- bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf,
- sizeof(iovbuf));
- dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
- }
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+ roamvar = dhd_roam_disable;
+ bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf,
+ sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+ }
}
-
+ dhd_suspend_unlock(dhd);
return 0;
}
-static void dhd_suspend_resume_helper(struct dhd_info *dhd, int val)
+static int dhd_suspend_resume_helper(struct dhd_info *dhd, int val, int force)
{
dhd_pub_t *dhdp = &dhd->pub;
+ int ret = 0;
DHD_OS_WAKE_LOCK(dhdp);
/* Set flag when early suspend was called */
dhdp->in_suspend = val;
- if ((!dhdp->suspend_disable_flag) && (dhd_check_ap_wfd_mode_set(dhdp) == FALSE))
- dhd_set_suspend(val, dhdp);
+ if ((force || !dhdp->suspend_disable_flag) &&
+ (dhd_check_ap_wfd_mode_set(dhdp) == FALSE)) {
+ ret = dhd_set_suspend(val, dhdp);
+ }
DHD_OS_WAKE_UNLOCK(dhdp);
+ return ret;
}
+#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
static void dhd_early_suspend(struct early_suspend *h)
{
struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend);
@@ -606,7 +614,7 @@ static void dhd_early_suspend(struct early_suspend *h)
DHD_TRACE(("%s: enter\n", __FUNCTION__));
if (dhd)
- dhd_suspend_resume_helper(dhd, 1);
+ dhd_suspend_resume_helper(dhd, 1, 0);
}
static void dhd_late_resume(struct early_suspend *h)
@@ -616,7 +624,7 @@ static void dhd_late_resume(struct early_suspend *h)
DHD_TRACE(("%s: enter\n", __FUNCTION__));
if (dhd)
- dhd_suspend_resume_helper(dhd, 0);
+ dhd_suspend_resume_helper(dhd, 0, 0);
}
#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */
@@ -664,16 +672,12 @@ dhd_timeout_expired(dhd_timeout_t *tmo)
} else {
wait_queue_head_t delay_wait;
DECLARE_WAITQUEUE(wait, current);
- int pending;
init_waitqueue_head(&delay_wait);
add_wait_queue(&delay_wait, &wait);
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(1);
- pending = signal_pending(current);
remove_wait_queue(&delay_wait, &wait);
set_current_state(TASK_RUNNING);
- if (pending)
- return 1; /* Interrupted */
}
return 0;
@@ -694,8 +698,9 @@ dhd_net2idx(dhd_info_t *dhd, struct net_device *net)
return DHD_BAD_IF;
}
-struct net_device * dhd_idx2net(struct dhd_pub *dhd_pub, int ifidx)
+struct net_device * dhd_idx2net(void *pub, int ifidx)
{
+ struct dhd_pub *dhd_pub = (struct dhd_pub *)pub;
struct dhd_info *dhd_info;
if (!dhd_pub || ifidx < 0 || ifidx >= DHD_MAX_IFS)
@@ -923,6 +928,7 @@ _dhd_set_mac_address(dhd_info_t *dhd, int ifidx, struct ether_addr *addr)
DHD_ERROR(("%s: set cur_etheraddr failed\n", dhd_ifname(&dhd->pub, ifidx)));
} else {
memcpy(dhd->iflist[ifidx]->net->dev_addr, addr, ETHER_ADDR_LEN);
+ memcpy(dhd->pub.mac.octet, addr, ETHER_ADDR_LEN);
}
return ret;
@@ -942,8 +948,9 @@ dhd_op_if(dhd_if_t *ifp)
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));
@@ -978,7 +985,7 @@ dhd_op_if(dhd_if_t *ifp)
#ifdef WL_CFG80211
if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211)
if (!wl_cfg80211_notify_ifadd(ifp->net, ifp->idx, ifp->bssidx,
- dhd_net_attach)) {
+ (void*)dhd_net_attach)) {
ifp->state = DHD_IF_NONE;
return;
}
@@ -1014,12 +1021,18 @@ dhd_op_if(dhd_if_t *ifp)
DHD_TRACE(("\n%s: got 'DHD_IF_DEL' state\n", __FUNCTION__));
#ifdef WL_CFG80211
if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) {
- wl_cfg80211_notify_ifdel(ifp->net);
+ wl_cfg80211_ifdel_ops(ifp->net);
}
#endif
netif_stop_queue(ifp->net);
unregister_netdev(ifp->net);
- ret = DHD_DEL_IF; /* Make sure the free_netdev() is called */
+ ret = DHD_DEL_IF;
+
+#ifdef WL_CFG80211
+ if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) {
+ wl_cfg80211_notify_ifdel();
+ }
+#endif
}
break;
case DHD_IF_DELETING:
@@ -1034,6 +1047,7 @@ dhd_op_if(dhd_if_t *ifp)
ifp->set_multicast = FALSE;
if (ifp->net) {
free_netdev(ifp->net);
+ ifp->net = NULL;
}
dhd->iflist[ifp->idx] = NULL;
#ifdef SOFTAP
@@ -1135,7 +1149,7 @@ dhd_set_mac_address(struct net_device *dev, void *addr)
if (ifidx == DHD_BAD_IF)
return -1;
- ASSERT(&dhd->thr_sysioc_ctl.thr_pid >= 0);
+ ASSERT(dhd->thr_sysioc_ctl.thr_pid >= 0);
memcpy(&dhd->macvalue, sa->sa_data, ETHER_ADDR_LEN);
dhd->set_macaddress = TRUE;
up(&dhd->thr_sysioc_ctl.sema);
@@ -1153,7 +1167,7 @@ dhd_set_multicast_list(struct net_device *dev)
if (ifidx == DHD_BAD_IF)
return;
- ASSERT(&dhd->thr_sysioc_ctl.thr_pid >= 0);
+ ASSERT(dhd->thr_sysioc_ctl.thr_pid >= 0);
dhd->iflist[ifidx]->set_multicast = TRUE;
up(&dhd->thr_sysioc_ctl.sema);
}
@@ -1164,6 +1178,7 @@ dhd_os_wlfc_block(dhd_pub_t *pub)
{
dhd_info_t *di = (dhd_info_t *)(pub->info);
ASSERT(di != NULL);
+
spin_lock_bh(&di->wlfc_spinlock);
return 1;
}
@@ -1197,7 +1212,7 @@ dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf)
}
/* Update multicast statistic */
- if (PKTLEN(dhdp->osh, pktbuf) >= ETHER_ADDR_LEN) {
+ if (PKTLEN(dhdp->osh, pktbuf) >= ETHER_HDR_LEN) {
uint8 *pktdata = (uint8 *)PKTDATA(dhdp->osh, pktbuf);
eh = (struct ether_header *)pktdata;
@@ -1205,6 +1220,9 @@ dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf)
dhdp->tx_multicast++;
if (ntoh16(eh->ether_type) == ETHER_TYPE_802_1X)
atomic_inc(&dhd->pend_8021x_cnt);
+ } else {
+ PKTFREE(dhd->pub.osh, pktbuf, TRUE);
+ return BCME_ERROR;
}
/* Look into the packet and update the packet priority */
@@ -1280,11 +1298,13 @@ dhd_start_xmit(struct sk_buff *skb, struct net_device *net)
DHD_ERROR(("%s: xmit rejected pub.up=%d busstate=%d \n",
__FUNCTION__, dhd->pub.up, dhd->pub.busstate));
netif_stop_queue(net);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
/* Send Event when bus down detected during data session */
if (dhd->pub.busstate == DHD_BUS_DOWN) {
DHD_ERROR(("%s: Event HANG sent up\n", __FUNCTION__));
net_os_send_hang_message(net);
}
+#endif
DHD_OS_WAKE_UNLOCK(&dhd->pub);
return -ENODEV;
}
@@ -1398,7 +1418,8 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan)
int i;
dhd_if_t *ifp;
wl_event_msg_t event;
- int tout = DHD_PACKET_TIMEOUT;
+ int tout_rx = 0;
+ int tout_ctrl = 0;
DHD_TRACE(("%s: Enter\n", __FUNCTION__));
@@ -1415,7 +1436,7 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan)
PKTFREE(dhdp->osh, pktbuf, TRUE);
continue;
}
-
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
/* Dropping packets before registering net device to avoid kernel panic */
if (!ifp->net || ifp->net->reg_state != NETREG_REGISTERED ||
!dhd->pub.up) {
@@ -1424,6 +1445,7 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan)
PKTFREE(dhdp->osh, pktbuf, TRUE);
continue;
}
+#endif
pnext = PKTNEXT(dhdp->osh, pktbuf);
PKTSETNEXT(wl->sh.osh, pktbuf, NULL);
@@ -1448,6 +1470,7 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan)
*/
((athost_wl_status_info_t*)dhdp->wlfc_state)->stats.wlfc_header_only_pkt++;
PKTFREE(dhdp->osh, pktbuf, TRUE);
+ DHD_TRACE(("RX: wlfc header \n"));
continue;
}
#endif
@@ -1499,10 +1522,15 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan)
&data);
wl_event_to_host_order(&event);
+ if (!tout_ctrl)
+ tout_ctrl = DHD_PACKET_TIMEOUT_MS;
if (event.event_type == WLC_E_BTA_HCI_EVENT) {
dhd_bta_doevt(dhdp, data, event.datalen);
+ } else if (event.event_type == WLC_E_PFN_NET_FOUND) {
+ tout_ctrl *= 2;
}
- tout = DHD_EVENT_TIMEOUT;
+ } else {
+ tout_rx = DHD_PACKET_TIMEOUT_MS;
}
ASSERT(ifidx < DHD_MAX_IFS && dhd->iflist[ifidx]);
@@ -1535,7 +1563,8 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan)
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */
}
}
- DHD_OS_WAKE_LOCK_TIMEOUT_ENABLE(dhdp, tout);
+ DHD_OS_WAKE_LOCK_RX_TIMEOUT_ENABLE(dhdp, tout_rx);
+ DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(dhdp, tout_ctrl);
}
void
@@ -1589,8 +1618,10 @@ dhd_get_stats(struct net_device *net)
DHD_TRACE(("%s: Enter\n", __FUNCTION__));
ifidx = dhd_net2idx(dhd, net);
- if (ifidx == DHD_BAD_IF)
+ if (ifidx == DHD_BAD_IF) {
+ DHD_ERROR(("%s: BAD_IF\n", __FUNCTION__));
return NULL;
+ }
ifp = dhd->iflist[ifidx];
ASSERT(dhd && ifp);
@@ -2001,6 +2032,7 @@ dhd_ethtool(dhd_info_t *dhd, void *uaddr)
static bool dhd_check_hang(struct net_device *net, dhd_pub_t *dhdp, int error)
{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
if (!dhdp)
return FALSE;
if ((error == -ETIMEDOUT) || ((dhdp->busstate == DHD_BUS_DOWN) &&
@@ -2010,6 +2042,7 @@ static bool dhd_check_hang(struct net_device *net, dhd_pub_t *dhdp, int error)
net_os_send_hang_message(net);
return TRUE;
}
+#endif
return FALSE;
}
@@ -2030,7 +2063,7 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd)
/* 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_TIMEOUT_ENABLE(&dhd->pub, DHD_EVENT_TIMEOUT);
+ 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);
}
@@ -2039,6 +2072,7 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd)
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;
}
@@ -2236,6 +2270,7 @@ dhd_cleanup_virt_ifaces(dhd_info_t *dhd)
#endif
for (i = 1; i < DHD_MAX_IFS; i++) {
+ dhd_net_if_lock_local(dhd);
if (dhd->iflist[i]) {
DHD_TRACE(("Deleting IF: %d \n", i));
if ((dhd->iflist[i]->state != DHD_IF_DEL) &&
@@ -2245,6 +2280,7 @@ dhd_cleanup_virt_ifaces(dhd_info_t *dhd)
dhd_op_if(dhd->iflist[i]);
}
}
+ dhd_net_if_unlock_local(dhd);
}
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
@@ -2259,10 +2295,10 @@ dhd_cleanup_virt_ifaces(dhd_info_t *dhd)
static int
dhd_stop(struct net_device *net)
{
- int ifidx;
+ int ifidx = 0;
dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net);
DHD_OS_WAKE_LOCK(&dhd->pub);
- DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+ DHD_TRACE(("%s: Enter %p\n", __FUNCTION__, net));
if (dhd->pub.up == 0) {
goto exit;
}
@@ -2270,7 +2306,7 @@ dhd_stop(struct net_device *net)
#ifdef WL_CFG80211
if (ifidx == 0) {
- wl_cfg80211_down();
+ wl_cfg80211_down(NULL);
/*
* For CFG80211: Clean up all the left over virtual interfaces
@@ -2293,15 +2329,15 @@ dhd_stop(struct net_device *net)
/* Stop the protocol module */
dhd_prot_stop(&dhd->pub);
+ OLD_MOD_DEC_USE_COUNT;
+exit:
#if defined(WL_CFG80211)
if (ifidx == 0 && !dhd_download_fw_on_driverload)
wl_android_wifi_off(net);
#endif
- dhd->pub.hang_was_sent = 0;
dhd->pub.rxcnt_timeout = 0;
dhd->pub.txcnt_timeout = 0;
- OLD_MOD_DEC_USE_COUNT;
-exit:
+
DHD_OS_WAKE_UNLOCK(&dhd->pub);
return 0;
}
@@ -2326,13 +2362,19 @@ dhd_open(struct net_device *net)
firmware_path[0] = '\0';
}
+ dhd->pub.hang_was_sent = 0;
#if !defined(WL_CFG80211)
/*
* Force start if ifconfig_up gets called before START command
* We keep WEXT's wl_control_wl_start to provide backward compatibility
* This should be removed in the future
*/
- wl_control_wl_start(net);
+ ret = wl_control_wl_start(net);
+ if (ret != 0) {
+ DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret));
+ ret = -1;
+ goto exit;
+ }
#endif
ifidx = dhd_net2idx(dhd, net);
@@ -2354,12 +2396,17 @@ dhd_open(struct net_device *net)
atomic_set(&dhd->pend_8021x_cnt, 0);
#if defined(WL_CFG80211)
DHD_ERROR(("\n%s\n", dhd_version));
- if (!dhd_download_fw_on_driverload)
- wl_android_wifi_on(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));
+ ret = -1;
+ goto exit;
+ }
+ }
#endif /* defined(WL_CFG80211) */
if (dhd->pub.busstate != DHD_BUS_DATA) {
- int ret;
/* try to bring up bus */
if ((ret = dhd_bus_start(&dhd->pub)) != 0) {
@@ -2382,7 +2429,7 @@ dhd_open(struct net_device *net)
#endif /* TOE */
#if defined(WL_CFG80211)
- if (unlikely(wl_cfg80211_up())) {
+ if (unlikely(wl_cfg80211_up(NULL))) {
DHD_ERROR(("%s: failed to bring up cfg80211\n", __FUNCTION__));
ret = -1;
goto exit;
@@ -2400,10 +2447,39 @@ dhd_open(struct net_device *net)
OLD_MOD_INC_USE_COUNT;
exit:
+ if (ret)
+ dhd_stop(net);
+
DHD_OS_WAKE_UNLOCK(&dhd->pub);
return ret;
}
+int dhd_do_driver_init(struct net_device *net)
+{
+ dhd_info_t *dhd = NULL;
+
+ if (!net) {
+ DHD_ERROR(("Primary Interface not initialized \n"));
+ return -EINVAL;
+ }
+
+ dhd = *(dhd_info_t **)netdev_priv(net);
+
+ /* If driver is already initialized, do nothing
+ */
+ if (dhd->pub.busstate == DHD_BUS_DATA) {
+ DHD_TRACE(("Driver already Inititalized. Nothing to do"));
+ return 0;
+ }
+
+ if (dhd_open(net) < 0) {
+ DHD_ERROR(("Driver Init Failed \n"));
+ return -1;
+ }
+
+ return 0;
+}
+
osl_t *
dhd_osl_attach(void *pdev, uint bustype)
{
@@ -2457,7 +2533,7 @@ dhd_add_if(dhd_info_t *dhd, int ifidx, void *handle, char *name,
ifp->state = DHD_IF_ADD;
ifp->idx = ifidx;
ifp->bssidx = bssidx;
- ASSERT(&dhd->thr_sysioc_ctl.thr_pid >= 0);
+ ASSERT(dhd->thr_sysioc_ctl.thr_pid >= 0);
up(&dhd->thr_sysioc_ctl.sema);
} else
ifp->net = (struct net_device *)handle;
@@ -2481,10 +2557,30 @@ dhd_del_if(dhd_info_t *dhd, int ifidx)
ifp->state = DHD_IF_DEL;
ifp->idx = ifidx;
- ASSERT(&dhd->thr_sysioc_ctl.thr_pid >= 0);
+ ASSERT(dhd->thr_sysioc_ctl.thr_pid >= 0);
up(&dhd->thr_sysioc_ctl.sema);
}
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31))
+static struct net_device_ops dhd_ops_pri = {
+ .ndo_open = dhd_open,
+ .ndo_stop = dhd_stop,
+ .ndo_get_stats = dhd_get_stats,
+ .ndo_do_ioctl = dhd_ioctl_entry,
+ .ndo_start_xmit = dhd_start_xmit,
+ .ndo_set_mac_address = dhd_set_mac_address,
+ .ndo_set_multicast_list = dhd_set_multicast_list,
+};
+
+static struct net_device_ops dhd_ops_virt = {
+ .ndo_get_stats = dhd_get_stats,
+ .ndo_do_ioctl = dhd_ioctl_entry,
+ .ndo_start_xmit = dhd_start_xmit,
+ .ndo_set_mac_address = dhd_set_mac_address,
+ .ndo_set_multicast_list = dhd_set_multicast_list,
+};
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) */
+
dhd_pub_t *
dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen, void *dev)
{
@@ -2577,13 +2673,16 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen, void *dev)
/* Initialize Wakelock stuff */
spin_lock_init(&dhd->wakelock_spinlock);
dhd->wakelock_counter = 0;
- dhd->wakelock_timeout_enable = 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");
#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
mutex_init(&dhd->dhd_net_if_mutex);
+ mutex_init(&dhd->dhd_suspend_mutex);
#endif
dhd_state |= DHD_ATTACH_STATE_WAKELOCKS_INIT;
@@ -2659,7 +2758,9 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen, void *dev)
dhd->thr_sysioc_ctl.thr_pid = -1;
}
dhd_state |= DHD_ATTACH_STATE_THREADS_CREATED;
-
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
+ INIT_WORK(&dhd->work_hang, dhd_hang_process);
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
/*
* Save the dhd_info into the priv
*/
@@ -2669,7 +2770,7 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen, void *dev)
register_pm_notifier(&dhd_sleep_pm_notifier);
#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */
-#ifdef CONFIG_HAS_EARLYSUSPEND
+#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
dhd->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 20;
dhd->early_suspend.suspend = dhd_early_suspend;
dhd->early_suspend.resume = dhd_late_resume;
@@ -2678,6 +2779,7 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen, void *dev)
#endif
#ifdef ARP_OFFLOAD_SUPPORT
+ dhd->pend_ipaddr = 0;
register_inetaddr_notifier(&dhd_notifier);
#endif /* ARP_OFFLOAD_SUPPORT */
@@ -2711,7 +2813,8 @@ dhd_bus_start(dhd_pub_t *dhdp)
DHD_TRACE(("Enter %s:\n", __FUNCTION__));
#ifdef DHDTHREAD
- dhd_os_sdlock(dhdp);
+ if (dhd->threads_only)
+ dhd_os_sdlock(dhdp);
#endif /* DHDTHREAD */
/* try to download image and nvram to the dongle */
@@ -2724,14 +2827,16 @@ dhd_bus_start(dhd_pub_t *dhdp)
DHD_ERROR(("%s: dhdsdio_probe_download failed. firmware = %s nvram = %s\n",
__FUNCTION__, fw_path, nv_path));
#ifdef DHDTHREAD
- dhd_os_sdunlock(dhdp);
+ if (dhd->threads_only)
+ dhd_os_sdunlock(dhdp);
#endif /* DHDTHREAD */
return -1;
}
}
if (dhd->pub.busstate != DHD_BUS_LOAD) {
#ifdef DHDTHREAD
- dhd_os_sdunlock(dhdp);
+ if (dhd->threads_only)
+ dhd_os_sdunlock(dhdp);
#endif /* DHDTHREAD */
return -ENETDOWN;
}
@@ -2745,7 +2850,8 @@ dhd_bus_start(dhd_pub_t *dhdp)
DHD_ERROR(("%s, dhd_bus_init failed %d\n", __FUNCTION__, ret));
#ifdef DHDTHREAD
- dhd_os_sdunlock(dhdp);
+ if (dhd->threads_only)
+ dhd_os_sdunlock(dhdp);
#endif /* DHDTHREAD */
return ret;
}
@@ -2761,7 +2867,8 @@ dhd_bus_start(dhd_pub_t *dhdp)
DHD_ERROR(("%s Host failed to register for OOB\n", __FUNCTION__));
#ifdef DHDTHREAD
- dhd_os_sdunlock(dhdp);
+ if (dhd->threads_only)
+ dhd_os_sdunlock(dhdp);
#endif /* DHDTHREAD */
return -ENODEV;
}
@@ -2778,13 +2885,15 @@ dhd_bus_start(dhd_pub_t *dhdp)
del_timer_sync(&dhd->timer);
DHD_ERROR(("%s failed bus is not ready\n", __FUNCTION__));
#ifdef DHDTHREAD
- dhd_os_sdunlock(dhdp);
+ if (dhd->threads_only)
+ dhd_os_sdunlock(dhdp);
#endif /* DHDTHREAD */
return -ENODEV;
}
#ifdef DHDTHREAD
- dhd_os_sdunlock(dhdp);
+ if (dhd->threads_only)
+ dhd_os_sdunlock(dhdp);
#endif /* DHDTHREAD */
#ifdef READ_MACADDR
@@ -2799,45 +2908,89 @@ dhd_bus_start(dhd_pub_t *dhdp)
dhd_write_macaddr(dhd->pub.mac.octet);
#endif
+#ifdef ARP_OFFLOAD_SUPPORT
+ if (dhd->pend_ipaddr) {
+#ifdef AOE_IP_ALIAS_SUPPORT
+ aoe_update_host_ipv4_table(&dhd->pub, dhd->pend_ipaddr, TRUE);
+#endif /* AOE_IP_ALIAS_SUPPORT */
+ dhd->pend_ipaddr = 0;
+ }
+#endif /* ARP_OFFLOAD_SUPPORT */
+
return 0;
}
+#if !defined(AP) && defined(WLP2P) && defined(WL_ENABLE_P2P_IF)
+/* For Android ICS MR2 release, the concurrent mode is enabled by default and the firmware
+ * name would be fw_bcmdhd.bin. So we need to determine whether P2P is enabled in the STA
+ * firmware and accordingly enable concurrent mode (Apply P2P settings). SoftAP firmware
+ * would still be named as fw_bcmdhd_apsta.
+ */
+static u32
+dhd_concurrent_fw(dhd_pub_t *dhd)
+{
+ int ret = 0;
+ char buf[WLC_IOCTL_SMLEN];
+
+ if ((!op_mode) && (strstr(fw_path, "_p2p") == NULL) &&
+ (strstr(fw_path, "_apsta") == NULL)) {
+ /* Given path is for the STA firmware. Check whether P2P support is present in
+ * the firmware. If so, set mode as P2P (concurrent support).
+ */
+ memset(buf, 0, sizeof(buf));
+ bcm_mkiovar("p2p", 0, 0, buf, sizeof(buf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf),
+ FALSE, 0)) < 0) {
+ DHD_TRACE(("%s: Get P2P failed (error=%d)\n", __FUNCTION__, ret));
+ } else if (buf[0] == 1) {
+ DHD_TRACE(("%s: P2P is supported\n", __FUNCTION__));
+ return 1;
+ }
+ }
+ return 0;
+}
+#endif
+
int
dhd_preinit_ioctls(dhd_pub_t *dhd)
{
int ret = 0;
char eventmask[WL_EVENTING_MASK_LEN];
char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */
-
+#if !defined(WL_CFG80211)
uint up = 0;
+#endif
uint power_mode = PM_FAST;
uint32 dongle_align = DHD_SDALIGN;
uint32 glom = 0;
- uint bcn_timeout = 4;
+ uint bcn_timeout = DHD_BEACON_TIMEOUT_NORMAL;
+
uint retry_max = 3;
#if defined(ARP_OFFLOAD_SUPPORT)
int arpoe = 1;
#endif
- int scan_assoc_time = 40;
+#if defined(KEEP_ALIVE)
+ int res;
+#endif /* defined(KEEP_ALIVE) */
+ int scan_assoc_time = DHD_SCAN_ACTIVE_TIME;
int scan_unassoc_time = 40;
- int scan_passive_time = 130;
+ int scan_passive_time = DHD_SCAN_PASSIVE_TIME;
char buf[WLC_IOCTL_SMLEN];
char *ptr;
uint32 listen_interval = LISTEN_INTERVAL; /* Default Listen Interval in Beacons */
+ uint16 chipID;
#if defined(SOFTAP)
uint dtim = 1;
#endif
#if (defined(AP) && !defined(WLP2P)) || (!defined(AP) && defined(WL_CFG80211))
uint32 mpc = 0; /* Turn MPC off for AP/APSTA mode */
#endif
-
#if defined(AP) || defined(WLP2P)
uint32 apsta = 1; /* Enable APSTA mode */
#endif /* defined(AP) || defined(WLP2P) */
#ifdef GET_CUSTOM_MAC_ENABLE
struct ether_addr ea_addr;
#endif /* GET_CUSTOM_MAC_ENABLE */
-
DHD_TRACE(("Enter %s\n", __FUNCTION__));
dhd->op_mode = 0;
#ifdef GET_CUSTOM_MAC_ENABLE
@@ -2847,9 +3000,10 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
bcm_mkiovar("cur_etheraddr", (void *)&ea_addr, ETHER_ADDR_LEN, buf, sizeof(buf));
ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0);
if (ret < 0) {
- DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret));
+ DHD_ERROR(("%s: can't set custom MAC address , error=%d\n", __FUNCTION__, ret));
return BCME_NOTUP;
}
+ memcpy(dhd->mac.octet, ea_addr.octet, ETHER_ADDR_LEN);
} else {
#endif /* GET_CUSTOM_MAC_ENABLE */
/* Get the default device MAC address directly from firmware */
@@ -2867,7 +3021,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
#endif /* GET_CUSTOM_MAC_ENABLE */
#ifdef SET_RANDOM_MAC_SOFTAP
- if (strstr(fw_path, "_apsta") != NULL) {
+ if ((!op_mode && strstr(fw_path, "_apsta") != NULL) || (op_mode == HOSTAPD_MASK)) {
uint rand_mac;
srandom32((uint)jiffies);
@@ -2889,26 +3043,53 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
#endif /* SET_RANDOM_MAC_SOFTAP */
DHD_TRACE(("Firmware = %s\n", fw_path));
-#if !defined(AP) && defined(WLP2P)
+#if !defined(AP) && defined(WLP2P)
/* Check if firmware with WFD support used */
- if (strstr(fw_path, "_p2p") != NULL) {
+ if ((!op_mode && strstr(fw_path, "_p2p") != NULL)
+#if defined(WL_ENABLE_P2P_IF)
+ || (op_mode == 0x04) ||(dhd_concurrent_fw(dhd))
+#endif
+ ) {
bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf));
if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
DHD_ERROR(("%s APSTA for WFD failed ret= %d\n", __FUNCTION__, ret));
} else {
dhd->op_mode |= WFD_MASK;
-#if defined(ARP_OFFLOAD_SUPPORT)
- arpoe = 0;
-#endif /* (ARP_OFFLOAD_SUPPORT) */
- dhd_pkt_filter_enable = FALSE;
}
}
#endif
#if !defined(AP) && defined(WL_CFG80211)
/* Check if firmware with HostAPD support used */
- if (strstr(fw_path, "_apsta") != NULL) {
+ if ((!op_mode && strstr(fw_path, "_apsta") != NULL) || (op_mode == HOSTAPD_MASK)) {
+ /* Disable A-band for HostAPD */
+ uint band = WLC_BAND_2G;
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_BAND, (char *)&band, sizeof(band),
+ TRUE, 0)) < 0) {
+ DHD_ERROR(("%s:set band failed error (%d)\n", __FUNCTION__, ret));
+ }
+
+ /* Turn off wme if we are having only g ONLY firmware */
+ bcm_mkiovar("nmode", 0, 0, buf, sizeof(buf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf),
+ FALSE, 0)) < 0) {
+ DHD_ERROR(("%s:get nmode failed error (%d)\n", __FUNCTION__, ret));
+ }
+ else {
+ DHD_TRACE(("%s:get nmode returned %d\n", __FUNCTION__,buf[0]));
+ }
+ if (buf[0] == 0) {
+ int wme = 0;
+ bcm_mkiovar("wme", (char *)&wme, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s set wme for HostAPD failed %d\n", __FUNCTION__, ret));
+ }
+ else {
+ DHD_TRACE(("%s set wme succeeded for g ONLY firmware\n", __FUNCTION__));
+ }
+ }
/* Turn off MPC in AP mode */
bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf));
if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
@@ -2957,9 +3138,13 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf, sizeof(iovbuf));
dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
- /* disable glom option per default */
- bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf));
- dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+ /* disable glom option for some chips */
+ chipID = (uint16)dhd_bus_chip_id(dhd);
+ if ((chipID == BCM4330_CHIP_ID) || (chipID == BCM4329_CHIP_ID)) {
+ DHD_INFO(("%s disable glom for chipID=0x%X\n", __FUNCTION__, chipID));
+ bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+ }
/* Setup timeout if Beacons are lost and roam is off to report link down */
bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, sizeof(iovbuf));
@@ -2967,6 +3152,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
/* Setup assoc_retry_max count to reconnect target AP in dongle */
bcm_mkiovar("assoc_retry_max", (char *)&retry_max, 4, iovbuf, sizeof(iovbuf));
dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+
#if defined(AP) && !defined(WLP2P)
/* Turn off MPC in AP mode */
bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf));
@@ -2982,17 +3168,13 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
#endif
#if defined(KEEP_ALIVE)
- {
/* Set Keep Alive : be sure to use FW with -keepalive */
- int res;
-
#if defined(SOFTAP)
if (ap_fw_loaded == FALSE)
#endif
if ((res = dhd_keep_alive_onoff(dhd)) < 0)
DHD_ERROR(("%s set keeplive failed %d\n",
__FUNCTION__, res));
- }
#endif /* defined(KEEP_ALIVE) */
/* Read event_msgs mask */
@@ -3019,6 +3201,8 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
setbit(eventmask, WLC_E_LINK);
setbit(eventmask, WLC_E_NDIS_LINK);
setbit(eventmask, WLC_E_MIC_ERROR);
+ setbit(eventmask, WLC_E_ASSOC_REQ_IE);
+ setbit(eventmask, WLC_E_ASSOC_RESP_IE);
setbit(eventmask, WLC_E_PMKID_CACHE);
setbit(eventmask, WLC_E_JOIN_START);
setbit(eventmask, WLC_E_SCAN_COMPLETE);
@@ -3072,12 +3256,13 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
#ifdef PKT_FILTER_SUPPORT
/* Setup defintions for pktfilter , enable in suspend */
- dhd->pktfilter_count = 4;
+ 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;
+ dhd->pktfilter[4] = "104 0 0 0 0xFFFFFFFFFFFF 0x01005E0000FB";
#if defined(SOFTAP)
if (ap_fw_loaded) {
int i;
@@ -3089,12 +3274,13 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
#endif /* defined(SOFTAP) */
#endif /* PKT_FILTER_SUPPORT */
+#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
/* query for 'ver' to get version info from firmware */
memset(buf, 0, sizeof(buf));
ptr = buf;
@@ -3105,8 +3291,15 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
bcmstrtok(&ptr, "\n", 0);
/* Print fw version info */
DHD_ERROR(("Firmware version = %s\n", 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_ERROR(("%s : adjust IOCTL response time for Manufactring Firmware\n", __FUNCTION__));
+ }
}
done:
@@ -3138,26 +3331,6 @@ dhd_iovar(dhd_pub_t *pub, int ifidx, char *name, char *cmd_buf, uint cmd_len, in
return ret;
}
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31))
-static struct net_device_ops dhd_ops_pri = {
- .ndo_open = dhd_open,
- .ndo_stop = dhd_stop,
- .ndo_get_stats = dhd_get_stats,
- .ndo_do_ioctl = dhd_ioctl_entry,
- .ndo_start_xmit = dhd_start_xmit,
- .ndo_set_mac_address = dhd_set_mac_address,
- .ndo_set_multicast_list = dhd_set_multicast_list,
-};
-
-static struct net_device_ops dhd_ops_virt = {
- .ndo_get_stats = dhd_get_stats,
- .ndo_do_ioctl = dhd_ioctl_entry,
- .ndo_start_xmit = dhd_start_xmit,
- .ndo_set_mac_address = dhd_set_mac_address,
- .ndo_set_multicast_list = dhd_set_multicast_list,
-};
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) */
-
int dhd_change_mtu(dhd_pub_t *dhdp, int new_mtu, int ifidx)
{
struct dhd_info *dhd = dhdp->info;
@@ -3261,9 +3434,13 @@ static int dhd_device_event(struct notifier_block *this,
DHD_ARPOE(("%s: [%s] Up IP: 0x%x\n",
__FUNCTION__, ifa->ifa_label, ifa->ifa_address));
- /* firmware not downloaded, do nothing */
- if (dhd->pub.busstate == DHD_BUS_DOWN) {
- DHD_ERROR(("%s: bus is down, exit\n", __FUNCTION__));
+ if (dhd->pub.busstate != DHD_BUS_DATA) {
+ DHD_ERROR(("%s: bus not ready, exit\n", __FUNCTION__));
+ if (dhd->pend_ipaddr) {
+ DHD_ERROR(("%s: overwrite pending ipaddr: 0x%x\n",
+ __FUNCTION__, dhd->pend_ipaddr));
+ }
+ dhd->pend_ipaddr = ifa->ifa_address;
break;
}
@@ -3281,7 +3458,7 @@ static int dhd_device_event(struct notifier_block *this,
case NETDEV_DOWN:
DHD_ARPOE(("%s: [%s] Down IP: 0x%x\n",
__FUNCTION__, ifa->ifa_label, ifa->ifa_address));
-
+ dhd->pend_ipaddr = 0;
#ifdef AOE_IP_ALIAS_SUPPORT
if (!(ifa->ifa_label[strlen(ifa->ifa_label)-2] == 0x3a)) {
DHD_ARPOE(("%s: primary interface is down, AOE clr all\n",
@@ -3355,7 +3532,8 @@ dhd_net_attach(dhd_pub_t *dhdp, int ifidx)
* portable hotspot. This will not work in simultaneous AP/STA mode,
* nor with P2P. Need to set the Donlge's MAC address, and then use that.
*/
- if (ifidx > 0) {
+ if (!memcmp(temp_addr, dhd->iflist[0]->mac_addr,
+ ETHER_ADDR_LEN)) {
DHD_ERROR(("%s interface [%s]: set locally administered bit in MAC\n",
__func__, net->name));
temp_addr[0] |= 0x02;
@@ -3468,13 +3646,17 @@ void dhd_detach(dhd_pub_t *dhdp)
unregister_inetaddr_notifier(&dhd_notifier);
#endif /* ARP_OFFLOAD_SUPPORT */
-#if defined(CONFIG_HAS_EARLYSUSPEND)
+#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
if (dhd->dhd_state & DHD_ATTACH_STATE_EARLYSUSPEND_DONE) {
if (dhd->early_suspend.suspend)
unregister_early_suspend(&dhd->early_suspend);
}
#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
+ cancel_work_sync(&dhd->work_hang);
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
+
#if defined(CONFIG_BCMDHD_WEXT)
if (dhd->dhd_state & DHD_ATTACH_STATE_WL_ATTACH) {
/* Detatch and unlink in the iw */
@@ -3482,7 +3664,7 @@ void dhd_detach(dhd_pub_t *dhdp)
}
#endif /* defined(CONFIG_BCMDHD_WEXT) */
- if (&dhd->thr_sysioc_ctl.thr_pid >= 0) {
+ if (dhd->thr_sysioc_ctl.thr_pid >= 0) {
PROC_STOP(&dhd->thr_sysioc_ctl);
}
@@ -3492,13 +3674,15 @@ void dhd_detach(dhd_pub_t *dhdp)
dhd_if_t *ifp;
/* Cleanup virtual interfaces */
- for (i = 1; i < DHD_MAX_IFS; i++)
+ for (i = 1; i < DHD_MAX_IFS; i++) {
+ dhd_net_if_lock_local(dhd);
if (dhd->iflist[i]) {
dhd->iflist[i]->state = DHD_IF_DEL;
dhd->iflist[i]->idx = i;
dhd_op_if(dhd->iflist[i]);
}
-
+ dhd_net_if_unlock_local(dhd);
+ }
/* delete primary interface 0 */
ifp = dhd->iflist[0];
ASSERT(ifp);
@@ -3549,7 +3733,7 @@ void dhd_detach(dhd_pub_t *dhdp)
#ifdef WL_CFG80211
if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) {
- wl_cfg80211_detach();
+ wl_cfg80211_detach(NULL);
dhd_monitor_uninit();
}
#endif
@@ -3562,6 +3746,7 @@ void dhd_detach(dhd_pub_t *dhdp)
#ifdef CONFIG_HAS_WAKELOCK
wake_lock_destroy(&dhd->wl_wifi);
wake_lock_destroy(&dhd->wl_rxwake);
+ wake_lock_destroy(&dhd->wl_ctrlwake);
#endif
}
}
@@ -3596,7 +3781,6 @@ dhd_module_cleanup(void)
dhd_customer_gpio_wlan_ctrl(WLAN_POWER_OFF);
}
-
static int __init
dhd_module_init(void)
{
@@ -3643,26 +3827,26 @@ dhd_module_init(void)
}
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
- /*
- * Wait till MMC sdio_register_driver callback called and made driver attach.
- * It's needed to make sync up exit from dhd insmod and
- * Kernel MMC sdio device callback registration
- */
+ /*
+ * Wait till MMC sdio_register_driver callback called and made driver attach.
+ * It's needed to make sync up exit from dhd insmod and
+ * Kernel MMC sdio device callback registration
+ */
if (down_timeout(&dhd_registration_sem, msecs_to_jiffies(DHD_REGISTRATION_TIMEOUT)) != 0) {
- error = -EINVAL;
+ error = -ENODEV;
DHD_ERROR(("%s: sdio_register_driver timeout\n", __FUNCTION__));
goto fail_2;
- }
+ }
#endif
#if defined(WL_CFG80211)
- error = wl_android_post_init();
-#endif
+ wl_android_post_init();
+#endif /* defined(WL_CFG80211) */
return error;
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && 1
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
fail_2:
dhd_bus_unregister();
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
+#endif
fail_1:
#if defined(CONFIG_WIFI_CONTROL_FUNC)
wl_android_wifictrl_func_del();
@@ -3674,7 +3858,11 @@ fail_1:
return error;
}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
late_initcall(dhd_module_init);
+#else
+module_init(dhd_module_init);
+#endif
module_exit(dhd_module_cleanup);
/*
@@ -3722,7 +3910,6 @@ int
dhd_os_ioctl_resp_wait(dhd_pub_t *pub, uint *condition, bool *pending)
{
dhd_info_t * dhd = (dhd_info_t *)(pub->info);
- DECLARE_WAITQUEUE(wait, current);
int timeout = dhd_ioctl_timeout_msec;
/* Convert timeout in millsecond to jiffies */
@@ -3732,26 +3919,7 @@ dhd_os_ioctl_resp_wait(dhd_pub_t *pub, uint *condition, bool *pending)
timeout = timeout * HZ / 1000;
#endif
- /* Wait until control frame is available */
- add_wait_queue(&dhd->ioctl_resp_wait, &wait);
- set_current_state(TASK_INTERRUPTIBLE);
-
- /* Memory barrier to support multi-processing
- * As the variable "condition", which points to dhd->rxlen (dhd_bus_rxctl[dhd_sdio.c])
- * Can be changed by another processor.
- */
- smp_mb();
- while (!(*condition) && (!signal_pending(current) && timeout)) {
- timeout = schedule_timeout(timeout);
- smp_mb();
- }
-
- if (signal_pending(current))
- *pending = TRUE;
-
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&dhd->ioctl_resp_wait, &wait);
-
+ timeout = wait_event_timeout(dhd->ioctl_resp_wait, (*condition), timeout);
return timeout;
}
@@ -3761,7 +3929,7 @@ dhd_os_ioctl_resp_wake(dhd_pub_t *pub)
dhd_info_t *dhd = (dhd_info_t *)(pub->info);
if (waitqueue_active(&dhd->ioctl_resp_wait)) {
- wake_up_interruptible(&dhd->ioctl_resp_wait);
+ wake_up(&dhd->ioctl_resp_wait);
}
return 0;
@@ -3917,7 +4085,7 @@ dhd_os_sdtxunlock(dhd_pub_t *pub)
dhd_os_sdunlock(pub);
}
-#if defined(DHD_USE_STATIC_BUF)
+#if defined(CONFIG_DHD_USE_STATIC_BUF)
uint8* dhd_os_prealloc(void *osh, int section, uint size)
{
return (uint8*)wl_android_prealloc(section, size);
@@ -3926,7 +4094,7 @@ uint8* dhd_os_prealloc(void *osh, int section, uint size)
void dhd_os_prefree(void *osh, void *addr, uint size)
{
}
-#endif /* defined(CONFIG_WIFI_CONTROL_FUNC) */
+#endif /* defined(CONFIG_DHD_USE_STATIC_BUF) */
#if defined(CONFIG_BCMDHD_WEXT)
struct iw_statistics *
@@ -3975,7 +4143,13 @@ dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata,
#endif /* defined(CONFIG_BCMDHD_WEXT) */
#ifdef WL_CFG80211
-
+ if ((ntoh32(event->event_type) == WLC_E_IF) &&
+ (((dhd_if_event_t *)*data)->action == WLC_E_IF_ADD))
+ /* If ADD_IF has been called directly by wl utility then we
+ * should not report this. In case if ADD_IF was called from
+ * CFG stack, then too this event need not be reported back
+ */
+ return (BCME_OK);
if ((wl_cfg80211_is_progress_ifchange() ||
wl_cfg80211_is_progress_ifadd()) && (*ifidx != 0)) {
/*
@@ -4104,8 +4278,13 @@ void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar)
{
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
struct dhd_info *dhdinfo = dhd->info;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
+ int timeout = msecs_to_jiffies(2000);
+#else
+ int timeout = 2 * HZ;
+#endif
dhd_os_sdunlock(dhd);
- wait_event_interruptible_timeout(dhdinfo->ctrl_wait, (*lockvar == FALSE), HZ * 2);
+ wait_event_timeout(dhdinfo->ctrl_wait, (*lockvar == FALSE), timeout);
dhd_os_sdlock(dhd);
#endif
return;
@@ -4116,7 +4295,7 @@ void dhd_wait_event_wakeup(dhd_pub_t *dhd)
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
struct dhd_info *dhdinfo = dhd->info;
if (waitqueue_active(&dhdinfo->ctrl_wait))
- wake_up_interruptible(&dhdinfo->ctrl_wait);
+ wake_up(&dhdinfo->ctrl_wait);
#endif
return;
}
@@ -4149,16 +4328,18 @@ int net_os_set_suspend_disable(struct net_device *dev, int val)
return ret;
}
-int net_os_set_suspend(struct net_device *dev, int val)
+int net_os_set_suspend(struct net_device *dev, int val, int force)
{
int ret = 0;
-#if defined(CONFIG_HAS_EARLYSUSPEND)
dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
if (dhd) {
+#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
ret = dhd_set_suspend(val, &dhd->pub);
+#else
+ ret = dhd_suspend_resume_helper(dhd, val, force);
+#endif
}
-#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */
return ret;
}
@@ -4178,7 +4359,8 @@ int net_os_rxfilter_add_remove(struct net_device *dev, int add_remove, int num)
char *filterp = NULL;
int ret = 0;
- if (!dhd || (num == DHD_UNICAST_FILTER_NUM))
+ if (!dhd || (num == DHD_UNICAST_FILTER_NUM) ||
+ (num == DHD_MDNS_FILTER_NUM))
return ret;
if (num >= dhd->pub.pktfilter_count)
return -EINVAL;
@@ -4201,9 +4383,8 @@ int net_os_rxfilter_add_remove(struct net_device *dev, int add_remove, int num)
return ret;
}
-int net_os_set_packet_filter(struct net_device *dev, int val)
+int dhd_os_set_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
@@ -4211,22 +4392,29 @@ int net_os_set_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_set_packet_filter(val, &dhd->pub);
+ if (dhdp && dhdp->up) {
+ if (dhdp->in_suspend) {
+ if (!val || (val && !dhdp->suspend_disable_flag))
+ dhd_set_packet_filter(val, dhdp);
}
}
return ret;
+
}
+int net_os_set_packet_filter(struct net_device *dev, int val)
+{
+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
-void
+ return dhd_os_set_packet_filter(&dhd->pub, val);
+}
+
+int
dhd_dev_init_ioctl(struct net_device *dev)
{
dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
- dhd_preinit_ioctls(&dhd->pub);
+ return dhd_preinit_ioctls(&dhd->pub);
}
#ifdef PNO_SUPPORT
@@ -4271,6 +4459,28 @@ dhd_dev_get_pno_status(struct net_device *dev)
#endif /* PNO_SUPPORT */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
+static void dhd_hang_process(struct work_struct *work)
+{
+ dhd_info_t *dhd;
+ struct net_device *dev;
+
+ dhd = (dhd_info_t *)container_of(work, dhd_info_t, work_hang);
+ dev = dhd->iflist[0]->net;
+
+ if (dev) {
+ rtnl_lock();
+ dev_close(dev);
+ rtnl_unlock();
+#if defined(WL_WIRELESS_EXT)
+ wl_iw_send_priv_event(dev, "HANG");
+#endif
+#if defined(WL_CFG80211)
+ wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED);
+#endif
+ }
+}
+
int net_os_send_hang_message(struct net_device *dev)
{
dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
@@ -4279,26 +4489,21 @@ int net_os_send_hang_message(struct net_device *dev)
if (dhd) {
if (!dhd->pub.hang_was_sent) {
dhd->pub.hang_was_sent = 1;
-#if defined(CONFIG_BCMDHD_WEXT)
- ret = wl_iw_send_priv_event(dev, "HANG");
-#endif
-#if defined(WL_CFG80211)
- ret = wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED);
-#endif
+ schedule_work(&dhd->work_hang);
}
}
return ret;
}
+#endif
void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec)
{
dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
if (dhd && dhd->pub.up)
- memcpy(&dhd->pub.dhd_cspec, cspec, sizeof(wl_country_t));
+ memcpy(&dhd->pub.dhd_cspec, cspec, sizeof(wl_country_t));
}
-
void dhd_net_if_lock(struct net_device *dev)
{
dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
@@ -4327,6 +4532,24 @@ static void dhd_net_if_unlock_local(dhd_info_t *dhd)
#endif
}
+static void dhd_suspend_lock(dhd_pub_t *pub)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
+ dhd_info_t *dhd = (dhd_info_t *)(pub->info);
+ if (dhd)
+ mutex_lock(&dhd->dhd_suspend_mutex);
+#endif
+}
+
+static void dhd_suspend_unlock(dhd_pub_t *pub)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
+ dhd_info_t *dhd = (dhd_info_t *)(pub->info);
+ if (dhd)
+ mutex_unlock(&dhd->dhd_suspend_mutex);
+#endif
+}
+
unsigned long dhd_os_spin_lock(dhd_pub_t *pub)
{
dhd_info_t *dhd = (dhd_info_t *)(pub->info);
@@ -4419,13 +4642,18 @@ int dhd_os_wake_lock_timeout(dhd_pub_t *pub)
if (dhd) {
spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
- ret = dhd->wakelock_timeout_enable;
+ ret = dhd->wakelock_rx_timeout_enable > dhd->wakelock_ctrl_timeout_enable ?
+ dhd->wakelock_rx_timeout_enable : dhd->wakelock_ctrl_timeout_enable;
#ifdef CONFIG_HAS_WAKELOCK
- if (dhd->wakelock_timeout_enable)
+ if (dhd->wakelock_rx_timeout_enable)
wake_lock_timeout(&dhd->wl_rxwake,
- dhd->wakelock_timeout_enable * HZ);
+ msecs_to_jiffies(dhd->wakelock_rx_timeout_enable));
+ if (dhd->wakelock_ctrl_timeout_enable)
+ wake_lock_timeout(&dhd->wl_ctrlwake,
+ msecs_to_jiffies(dhd->wakelock_ctrl_timeout_enable));
#endif
- dhd->wakelock_timeout_enable = 0;
+ dhd->wakelock_rx_timeout_enable = 0;
+ dhd->wakelock_ctrl_timeout_enable = 0;
spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
}
return ret;
@@ -4441,27 +4669,51 @@ int net_os_wake_lock_timeout(struct net_device *dev)
return ret;
}
-int dhd_os_wake_lock_timeout_enable(dhd_pub_t *pub, int val)
+int dhd_os_wake_lock_rx_timeout_enable(dhd_pub_t *pub, int val)
{
dhd_info_t *dhd = (dhd_info_t *)(pub->info);
unsigned long flags;
if (dhd) {
spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
- if (val > dhd->wakelock_timeout_enable)
- dhd->wakelock_timeout_enable = val;
+ if (val > dhd->wakelock_rx_timeout_enable)
+ dhd->wakelock_rx_timeout_enable = val;
spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
}
return 0;
}
-int net_os_wake_lock_timeout_enable(struct net_device *dev, int val)
+int dhd_os_wake_lock_ctrl_timeout_enable(dhd_pub_t *pub, int val)
+{
+ dhd_info_t *dhd = (dhd_info_t *)(pub->info);
+ unsigned long flags;
+
+ if (dhd) {
+ spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
+ if (val > dhd->wakelock_ctrl_timeout_enable)
+ dhd->wakelock_ctrl_timeout_enable = val;
+ spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
+ }
+ return 0;
+}
+
+int net_os_wake_lock_rx_timeout_enable(struct net_device *dev, int val)
{
dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
int ret = 0;
if (dhd)
- ret = dhd_os_wake_lock_timeout_enable(&dhd->pub, val);
+ ret = dhd_os_wake_lock_rx_timeout_enable(&dhd->pub, val);
+ return ret;
+}
+
+int net_os_wake_lock_ctrl_timeout_enable(struct net_device *dev, int val)
+{
+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
+ int ret = 0;
+
+ if (dhd)
+ ret = dhd_os_wake_lock_ctrl_timeout_enable(&dhd->pub, val);
return ret;
}
@@ -4532,15 +4784,6 @@ int dhd_os_check_wakelock(void *dhdp)
return 0;
}
-int dhd_os_check_if_up(void *dhdp)
-{
- dhd_pub_t *pub = (dhd_pub_t *)dhdp;
-
- if (!pub)
- return 0;
- return pub->up;
-}
-
int net_os_wake_unlock(struct net_device *dev)
{
dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
@@ -4551,6 +4794,15 @@ int net_os_wake_unlock(struct net_device *dev)
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;
@@ -4590,8 +4842,8 @@ extern int dhd_wlfc_interface_entry_update(void* state, ewlfc_mac_entry_action_t
uint8 iftype, uint8* ea);
extern int dhd_wlfc_FIFOcreditmap_update(void* state, uint8* credits);
-int dhd_wlfc_interface_event(struct dhd_info *dhd, uint8 action, uint8 ifid, uint8 iftype,
- uint8* ea)
+int dhd_wlfc_interface_event(struct dhd_info *dhd,
+ ewlfc_mac_entry_action_t action, uint8 ifid, uint8 iftype, uint8* ea)
{
if (dhd->pub.wlfc_state == NULL)
return BCME_OK;