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.c406
1 files changed, 220 insertions, 186 deletions
diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c
index b57af00a048..0ef8ae5c0a9 100644
--- a/drivers/net/wireless/bcmdhd/dhd_linux.c
+++ b/drivers/net/wireless/bcmdhd/dhd_linux.c
@@ -2,9 +2,9 @@
* Broadcom Dongle Host Driver (DHD), Linux-specific network interface
* Basically selected code segments from usb-cdc.c and usb-rndis.c
*
- * Copyright (C) 1999-2011, Broadcom Corporation
+ * Copyright (C) 1999-2012, Broadcom Corporation
*
- * Unless you and Broadcom execute a separate written software license
+ * Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
@@ -22,7 +22,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: dhd_linux.c 308879 2012-01-17 22:03:47Z $
+ * $Id: dhd_linux.c 309571 2012-01-20 01:45:10Z $
*/
#include <typedefs.h>
@@ -63,9 +63,11 @@
#include <wl_cfg80211.h>
#endif
+#ifdef WLBTAMP
#include <proto/802.11_bta.h>
#include <proto/bt_amp_hci.h>
#include <dhd_bta.h>
+#endif
#ifdef WLMEDIA_HTSF
#include <linux/time.h>
@@ -101,6 +103,10 @@ extern bool ap_fw_loaded;
/* enable HOSTIP cache update from the host side when an eth0:N is up */
#define AOE_IP_ALIAS_SUPPORT 1
+#ifdef BCM_FD_AGGR
+#include <bcm_rpc.h>
+#include <bcm_rpc_tp.h>
+#endif
#ifdef PROP_TXSTATUS
#include <wlfc_proto.h>
#include <dhd_wlfc.h>
@@ -134,11 +140,15 @@ MODULE_LICENSE("GPL v2");
#include <dhd_bus.h>
+#ifdef BCM_FD_AGGR
+#define DBUS_RX_BUFFER_SIZE_DHD(net) (BCM_RPC_TP_DNGL_AGG_MAX_BYTE)
+#else
#ifndef PROP_TXSTATUS
#define DBUS_RX_BUFFER_SIZE_DHD(net) (net->mtu + net->hard_header_len + dhd->pub.hdrlen)
#else
#define DBUS_RX_BUFFER_SIZE_DHD(net) (net->mtu + net->hard_header_len + dhd->pub.hdrlen + 128)
#endif
+#endif /* BCM_FD_AGGR */
#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15)
const char *
@@ -254,7 +264,7 @@ typedef struct dhd_info {
struct wake_lock wl_rxwake; /* Wifi rx wakelock */
#endif
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1
/* net_device interface lock, prevent race conditions among net_dev interface
* calls and wifi_on or wifi_off
*/
@@ -278,6 +288,12 @@ typedef struct dhd_info {
#ifdef ARP_OFFLOAD_SUPPORT
u32 pend_ipaddr;
#endif /* ARP_OFFLOAD_SUPPORT */
+#ifdef BCM_FD_AGGR
+ void *rpc_th;
+ void *rpc_osh;
+ struct timer_list rpcth_timer;
+ bool rpcth_timer_active;
+#endif
} dhd_info_t;
/* Definitions to provide path to the firmware and nvram
@@ -286,12 +302,12 @@ 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))
struct semaphore dhd_registration_sem;
+struct semaphore dhd_chipup_sem;
+
#define DHD_REGISTRATION_TIMEOUT 12000 /* msec : allowed time to finished dhd registration */
#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
@@ -316,6 +332,7 @@ uint dhd_console_ms = 0;
module_param(dhd_console_ms, uint, 0644);
#endif /* defined(DHD_DEBUG) */
+
/* ARP offload agent mode : Enable ARP Host Auto-Reply and ARP Peer Auto-Reply */
uint dhd_arp_mode = 0xb;
module_param(dhd_arp_mode, uint, 0);
@@ -334,7 +351,7 @@ module_param(dhd_pkt_filter_init, uint, 0);
/* Pkt filter mode control */
uint dhd_master_mode = TRUE;
-module_param(dhd_master_mode, uint, 0);
+module_param(dhd_master_mode, uint, 1);
#ifdef DHDTHREAD
/* Watchdog thread priority, -1 to use kernel timer */
@@ -360,6 +377,19 @@ 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())
@@ -430,9 +460,6 @@ 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);
-#if !defined(AP) && defined(WLP2P)
-static u32 dhd_concurrent_fw(dhd_pub_t *dhd);
-#endif
#ifdef WLMEDIA_HTSF
void htsf_update(dhd_info_t *dhd, void *data);
@@ -477,15 +504,15 @@ static int dhd_sleep_pm_callback(struct notifier_block *nfb, unsigned long actio
#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39))
switch (action) {
- case PM_HIBERNATION_PREPARE:
- case PM_SUSPEND_PREPARE:
- dhd_mmc_suspend = TRUE;
- ret = NOTIFY_OK;
+ case PM_HIBERNATION_PREPARE:
+ case PM_SUSPEND_PREPARE:
+ dhd_mmc_suspend = TRUE;
+ ret = NOTIFY_OK;
break;
- case PM_POST_HIBERNATION:
- case PM_POST_SUSPEND:
- dhd_mmc_suspend = FALSE;
- ret = NOTIFY_OK;
+ case PM_POST_HIBERNATION:
+ case PM_POST_SUSPEND:
+ dhd_mmc_suspend = FALSE;
+ ret = NOTIFY_OK;
break;
}
smp_mb();
@@ -495,7 +522,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 = 10
+ .priority = 0
};
extern int register_pm_notifier(struct notifier_block *nb);
extern int unregister_pm_notifier(struct notifier_block *nb);
@@ -934,7 +961,7 @@ extern tsk_ctl_t ap_eth_ctl; /* ap netdev heper thread ctl */
static void
dhd_op_if(dhd_if_t *ifp)
{
- dhd_info_t *dhd;
+ dhd_info_t *dhd;
int ret = 0, err = 0;
#ifdef SOFTAP
unsigned long flags;
@@ -1135,7 +1162,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 +1180,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,7 +1191,6 @@ 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;
}
@@ -1173,6 +1199,8 @@ int
dhd_os_wlfc_unblock(dhd_pub_t *pub)
{
dhd_info_t *di = (dhd_info_t *)(pub->info);
+
+ (void)di;
ASSERT(di != NULL);
spin_unlock_bh(&di->wlfc_spinlock);
return 1;
@@ -1207,8 +1235,8 @@ dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf)
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;
+ PKTFREE(dhd->pub.osh, pktbuf, TRUE);
+ return BCME_ERROR;
}
/* Look into the packet and update the packet priority */
@@ -1240,7 +1268,7 @@ dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf)
#endif
#ifdef PROP_TXSTATUS
if (dhdp->wlfc_state && ((athost_wl_status_info_t*)dhdp->wlfc_state)->proptxstatus_mode
- != WLFC_FCMODE_NONE) {
+ != WLFC_FCMODE_NONE) {
dhd_os_wlfc_block(dhdp);
ret = dhd_wlfc_enque_sendq(dhdp->wlfc_state, DHD_PKTTAG_FIFO(PKTTAG(pktbuf)),
pktbuf);
@@ -1258,7 +1286,6 @@ dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf)
ret = dhd_bus_txdata(dhdp->bus, pktbuf);
#endif /* PROP_TXSTATUS */
-
return ret;
}
@@ -1398,19 +1425,21 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan)
struct sk_buff *skb;
uchar *eth;
uint len;
- void *data, *pnext = NULL, *save_pktbuf;
+ void *data, *pnext = NULL;
int i;
dhd_if_t *ifp;
wl_event_msg_t event;
int tout = DHD_PACKET_TIMEOUT_MS;
- DHD_TRACE(("%s: Enter\n", __FUNCTION__));
- save_pktbuf = pktbuf;
+ BCM_REFERENCE(tout);
+ DHD_TRACE(("%s: Enter\n", __FUNCTION__));
for (i = 0; pktbuf && i < numpkt; i++, pktbuf = pnext) {
+#ifdef WLBTAMP
struct ether_header *eh;
struct dot11_llc_snap_header *lsh;
+#endif
ifp = dhd->iflist[ifidx];
if (ifp == NULL) {
@@ -1433,6 +1462,7 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan)
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];
@@ -1444,6 +1474,7 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan)
((uint8 *)eh + RFC1042_HDR_LEN);
ACL_data = NULL;
}
+#endif /* WLBTAMP */
#ifdef PROP_TXSTATUS
if (dhdp->wlfc_state && PKTLEN(wl->sh.osh, pktbuf) == 0) {
@@ -1487,7 +1518,7 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan)
skb->len = len;
#ifdef WLMEDIA_HTSF
- dhd_htsf_addrxts(dhdp, pktbuf);
+ dhd_htsf_addrxts(dhdp, pktbuf);
#endif
/* Strip header, count, deliver upward */
skb_pull(skb, ETH_HLEN);
@@ -1503,13 +1534,13 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan)
&event,
&data);
+#ifdef WLBTAMP
wl_event_to_host_order(&event);
- tout = DHD_EVENT_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 *= 2;
}
+ tout = DHD_EVENT_TIMEOUT_MS;
+#endif /* WLBTAMP */
}
ASSERT(ifidx < DHD_MAX_IFS && dhd->iflist[ifidx]);
@@ -1559,9 +1590,11 @@ dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success)
dhd_info_t *dhd = (dhd_info_t *)(dhdp->info);
struct ether_header *eh;
uint16 type;
+#ifdef WLBTAMP
uint len;
+#endif
- dhd_prot_hdrpull(dhdp, &ifidx, txp);
+ dhd_prot_hdrpull(dhdp, &ifidx, txp, NULL, NULL);
eh = (struct ether_header *)PKTDATA(dhdp->osh, txp);
type = ntoh16(eh->ether_type);
@@ -1569,6 +1602,7 @@ dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success)
if (type == ETHER_TYPE_802_1X)
atomic_dec(&dhd->pend_8021x_cnt);
+#ifdef WLBTAMP
/* Crack open the packet and check to see if it is BT HCI ACL data packet.
* If yes generate packet completion event.
*/
@@ -1584,6 +1618,7 @@ dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success)
dhd_bta_tx_hcidata_complete(dhdp, txp, success);
}
}
+#endif /* WLBTAMP */
}
static struct net_device_stats *
@@ -1673,7 +1708,7 @@ dhd_watchdog_thread(void *data)
DHD_OS_WAKE_UNLOCK(&dhd->pub);
} else {
break;
- }
+ }
complete_and_exit(&tsk->completed, 0);
}
@@ -2093,6 +2128,11 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int 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 */
/*
@@ -2208,6 +2248,13 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd)
}
#endif /* WLMEDIA_HTSF */
+#ifdef BCM_FD_AGGR
+ if ((ioc.cmd == WLC_SET_VAR || ioc.cmd == WLC_GET_VAR) &&
+ ioc.buf != NULL && strncmp("rpc_", ioc.buf, 4) == 0) {
+ bcmerror = dhd_fdaggr_ioctl(&dhd->pub, ifidx, (wl_ioctl_t *)&ioc, buf, buflen);
+ goto done;
+ }
+#endif
bcmerror = dhd_wl_ioctl(&dhd->pub, ifidx, (wl_ioctl_t *)&ioc, buf, buflen);
done:
@@ -2246,17 +2293,17 @@ 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) &&
(dhd->iflist[i]->state != DHD_IF_DELETING)) {
dhd->iflist[i]->state = DHD_IF_DEL;
dhd->iflist[i]->idx = i;
+ dhd_net_if_lock_local(dhd);
dhd_op_if(dhd->iflist[i]);
+ dhd_net_if_unlock_local(dhd);
}
}
- dhd_net_if_unlock_local(dhd);
}
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
@@ -2279,6 +2326,7 @@ dhd_stop(struct net_device *net)
goto exit;
}
ifidx = dhd_net2idx(dhd, net);
+ BCM_REFERENCE(ifidx);
#ifdef WL_CFG80211
if (ifidx == 0) {
@@ -2308,7 +2356,8 @@ dhd_stop(struct net_device *net)
#if defined(WL_CFG80211)
if (ifidx == 0 && !dhd_download_fw_on_driverload)
wl_android_wifi_off(net);
-#endif
+#endif
+ dhd->pub.hang_was_sent = 0;
dhd->pub.rxcnt_timeout = 0;
dhd->pub.txcnt_timeout = 0;
OLD_MOD_DEC_USE_COUNT;
@@ -2327,7 +2376,6 @@ dhd_open(struct net_device *net)
#endif
int ifidx;
int32 ret = 0;
-
DHD_OS_WAKE_LOCK(&dhd->pub);
/* Update FW path if it was changed */
if ((firmware_path != NULL) && (firmware_path[0] != '\0')) {
@@ -2337,21 +2385,14 @@ 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
+ * We keep WEXT's wl_control_wl_start to provide backward compatibility
+ * This should be removed in the future
*/
- ret = wl_control_wl_start(net);
- if (ret != 0) {
- DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret));
- ret = -1;
- goto exit;
- }
-#endif
+ wl_control_wl_start(net);
+#endif
ifidx = dhd_net2idx(dhd, net);
DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx));
@@ -2375,12 +2416,11 @@ 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));
- ret = -1;
+ DHD_ERROR(("wl_android_wifi_on failed (%d)\n", ret));
goto exit;
}
}
-#endif /* defined(WL_CFG80211) */
+#endif
if (dhd->pub.busstate != DHD_BUS_DATA) {
@@ -2427,32 +2467,6 @@ exit:
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)
{
@@ -2466,9 +2480,10 @@ dhd_osl_detach(osl_t *osh)
DHD_ERROR(("%s: MEMORY LEAK %d bytes\n", __FUNCTION__, MALLOCED(osh)));
}
osl_detach(osh);
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
+#if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
up(&dhd_registration_sem);
-#endif
+ up(&dhd_chipup_sem);
+#endif
}
int
@@ -2506,7 +2521,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;
@@ -2530,7 +2545,7 @@ 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);
}
@@ -2542,7 +2557,11 @@ static struct net_device_ops dhd_ops_pri = {
.ndo_do_ioctl = dhd_ioctl_entry,
.ndo_start_xmit = dhd_start_xmit,
.ndo_set_mac_address = dhd_set_mac_address,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0))
.ndo_set_rx_mode = dhd_set_multicast_list,
+#else
+ .ndo_set_multicast_list = dhd_set_multicast_list,
+#endif
};
static struct net_device_ops dhd_ops_virt = {
@@ -2550,7 +2569,11 @@ static struct net_device_ops dhd_ops_virt = {
.ndo_do_ioctl = dhd_ioctl_entry,
.ndo_start_xmit = dhd_start_xmit,
.ndo_set_mac_address = dhd_set_mac_address,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0))
.ndo_set_rx_mode = dhd_set_multicast_list,
+#else
+ .ndo_set_multicast_list = dhd_set_multicast_list,
+#endif
};
#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) */
@@ -2650,7 +2673,7 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen)
wake_lock_init(&dhd->wl_wifi, WAKE_LOCK_SUSPEND, "wlan_wake");
wake_lock_init(&dhd->wl_rxwake, WAKE_LOCK_SUSPEND, "wlan_rx_wake");
#endif
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1
mutex_init(&dhd->dhd_net_if_mutex);
#endif
dhd_state |= DHD_ATTACH_STATE_WAKELOCKS_INIT;
@@ -2676,9 +2699,9 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen)
/* Attach and link in the iw */
if (!(dhd_state & DHD_ATTACH_STATE_CFG80211)) {
if (wl_iw_attach(net, (void *)&dhd->pub) != 0) {
- DHD_ERROR(("wl_iw_attach failed\n"));
- goto fail;
- }
+ DHD_ERROR(("wl_iw_attach failed\n"));
+ goto fail;
+ }
dhd_state |= DHD_ATTACH_STATE_WL_ATTACH;
}
#endif /* defined(CONFIG_WIRELESS_EXT) */
@@ -2784,6 +2807,7 @@ dhd_bus_start(dhd_pub_t *dhdp)
dhd_os_sdlock(dhdp);
#endif /* DHDTHREAD */
+
/* try to download image and nvram to the dongle */
if ((dhd->pub.busstate == DHD_BUS_DOWN) &&
(fw_path != NULL) && (fw_path[0] != '\0') &&
@@ -2887,37 +2911,6 @@ dhd_bus_start(dhd_pub_t *dhdp)
return 0;
}
-#if !defined(AP) && defined(WLP2P)
-/* 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)
{
@@ -2978,12 +2971,13 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
}
/* Update public MAC address after reading from Firmware */
memcpy(dhd->mac.octet, buf, ETHER_ADDR_LEN);
+
#ifdef GET_CUSTOM_MAC_ENABLE
}
#endif /* GET_CUSTOM_MAC_ENABLE */
#ifdef SET_RANDOM_MAC_SOFTAP
- if ((!op_mode && strstr(fw_path, "_apsta") != NULL) || (op_mode == 0x02)) {
+ if (strstr(fw_path, "_apsta") != NULL) {
uint rand_mac;
srandom32((uint)jiffies);
@@ -3007,8 +3001,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
DHD_TRACE(("Firmware = %s\n", fw_path));
#if !defined(AP) && defined(WLP2P)
/* Check if firmware with WFD support used */
- if ((!op_mode && strstr(fw_path, "_p2p") != NULL) || (op_mode == 0x04) ||
- (dhd_concurrent_fw(dhd))) {
+ if (strstr(fw_path, "_p2p") != NULL) {
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) {
@@ -3021,11 +3014,11 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
dhd_pkt_filter_enable = FALSE;
}
}
-#endif
+#endif
#if !defined(AP) && defined(WL_CFG80211)
/* Check if firmware with HostAPD support used */
- if ((!op_mode && strstr(fw_path, "_apsta") != NULL) || (op_mode == 0x02)) {
+ if (strstr(fw_path, "_apsta") != NULL) {
/* 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,
@@ -3039,7 +3032,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
dhd_pkt_filter_enable = FALSE;
}
}
-#endif
+#endif
if ((dhd->op_mode != WFD_MASK) && (dhd->op_mode != HOSTAPD_MASK)) {
/* STA only operation mode */
@@ -3095,7 +3088,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
if (ap_fw_loaded == TRUE) {
dhd_wl_ioctl_cmd(dhd, WLC_SET_DTIMPRD, (char *)&dtim, sizeof(dtim), TRUE, 0);
}
-#endif
+#endif
#if defined(KEEP_ALIVE)
{
@@ -3104,7 +3097,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
#if defined(SOFTAP)
if (ap_fw_loaded == FALSE)
-#endif
+#endif
if ((res = dhd_keep_alive_onoff(dhd)) < 0)
DHD_ERROR(("%s set keeplive failed %d\n",
__FUNCTION__, res));
@@ -3224,8 +3217,6 @@ 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);
}
done:
@@ -3435,7 +3426,7 @@ dhd_net_attach(dhd_pub_t *dhdp, int ifidx)
#else
ASSERT(!net->netdev_ops);
net->netdev_ops = &dhd_ops_virt;
-#endif
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */
/* Ok, link into the network layer... */
if (ifidx == 0) {
@@ -3447,7 +3438,7 @@ dhd_net_attach(dhd_pub_t *dhdp, int ifidx)
net->stop = dhd_stop;
#else
net->netdev_ops = &dhd_ops_pri;
-#endif
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */
} else {
/*
* We have to use the primary MAC for virtual interfaces
@@ -3498,12 +3489,11 @@ dhd_net_attach(dhd_pub_t *dhdp, int ifidx)
wl_iw_iscan_set_scan_broadcast_prep(net, 1);
#endif
-
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
+#if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
if (ifidx == 0) {
up(&dhd_registration_sem);
}
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
+#endif
return 0;
fail:
@@ -3528,7 +3518,7 @@ dhd_bus_detach(dhd_pub_t *dhdp)
/*
* In case of Android cfg80211 driver, the bus is down in dhd_stop,
- * calling stop again will cuase SD read/write errors.
+ * calling stop again will cuase SD read/write errors.
*/
if (dhd->pub.busstate != DHD_BUS_DOWN) {
/* Stop the protocol module */
@@ -3579,6 +3569,7 @@ void dhd_detach(dhd_pub_t *dhdp)
}
#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */
+
#if defined(CONFIG_WIRELESS_EXT)
if (dhd->dhd_state & DHD_ATTACH_STATE_WL_ATTACH) {
/* Detatch and unlink in the iw */
@@ -3586,7 +3577,7 @@ void dhd_detach(dhd_pub_t *dhdp)
}
#endif /* defined(CONFIG_WIRELESS_EXT) */
- if (dhd->thr_sysioc_ctl.thr_pid >= 0) {
+ if (&dhd->thr_sysioc_ctl.thr_pid >= 0) {
PROC_STOP(&dhd->thr_sysioc_ctl);
}
@@ -3596,19 +3587,17 @@ void dhd_detach(dhd_pub_t *dhdp)
dhd_if_t *ifp;
/* Cleanup virtual interfaces */
- for (i = 1; i < DHD_MAX_IFS; i++) {
- dhd_net_if_lock_local(dhd);
+ for (i = 1; i < DHD_MAX_IFS; i++)
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);
-
+ ASSERT(ifp->net);
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31))
if (ifp->net->open)
#else
@@ -3622,6 +3611,7 @@ void dhd_detach(dhd_pub_t *dhdp)
}
MFREE(dhd->pub.osh, ifp, sizeof(*ifp));
dhd->iflist[0] = NULL;
+
}
}
@@ -3660,9 +3650,11 @@ void dhd_detach(dhd_pub_t *dhdp)
}
#endif
+
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP)
unregister_pm_notifier(&dhd_sleep_pm_notifier);
#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */
+ /* && defined(CONFIG_PM_SLEEP) */
if (dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT) {
#ifdef CONFIG_HAS_WAKELOCK
@@ -3680,6 +3672,22 @@ dhd_free(dhd_pub_t *dhdp)
DHD_TRACE(("%s: Enter\n", __FUNCTION__));
if (dhdp) {
+ int i;
+ for (i = 0; i < ARRAYSIZE(dhdp->reorder_bufs); i++) {
+ if (dhdp->reorder_bufs[i]) {
+ reorder_info_t *ptr;
+ uint32 buf_size = sizeof(struct reorder_info);
+
+ ptr = dhdp->reorder_bufs[i];
+
+ buf_size += ((ptr->max_idx + 1) * sizeof(void*));
+ DHD_REORDER(("free flow id buf %d, maxidx is %d, buf_size %d\n",
+ i, ptr->max_idx, buf_size));
+
+ MFREE(dhdp->osh, dhdp->reorder_bufs[i], buf_size);
+ dhdp->reorder_bufs[i] = NULL;
+ }
+ }
dhd = (dhd_info_t *)dhdp->info;
if (dhd)
MFREE(dhd->pub.osh, dhd, sizeof(*dhd));
@@ -3702,16 +3710,22 @@ dhd_module_cleanup(void)
dhd_customer_gpio_wlan_ctrl(WLAN_POWER_OFF);
}
+
static int __init
dhd_module_init(void)
{
int error = 0;
+#if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
+ int retry = POWERUP_MAX_RETRY;
+ int chip_up = 0;
+#endif
+
DHD_TRACE(("%s: Enter\n", __FUNCTION__));
wl_android_init();
-#ifdef DHDTHREAD
+#if defined(DHDTHREAD)
/* Sanity check on the module parameters */
do {
/* Both watchdog and DPC as tasklets are ok */
@@ -3725,19 +3739,43 @@ dhd_module_init(void)
DHD_ERROR(("Invalid module parameters.\n"));
return -EINVAL;
} while (0);
-#endif /* DHDTHREAD */
-
- /* Call customer gpio to turn on power with WL_REG_ON signal */
- dhd_customer_gpio_wlan_ctrl(WLAN_POWER_ON);
+#endif
+#if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
+ do {
+ dhd_customer_gpio_wlan_ctrl(WLAN_POWER_ON);
#if defined(CONFIG_WIFI_CONTROL_FUNC)
- if (wl_android_wifictrl_func_add() < 0)
- goto fail_1;
-#endif
+ if (wl_android_wifictrl_func_add() < 0)
+ goto fail_1;
+#endif /* defined(CONFIG_WIFI_CONTROL_FUNC) */
+ sema_init(&dhd_chipup_sem, 0);
+ dhd_bus_reg_sdio_notify(&dhd_chipup_sem);
+ if (down_timeout(&dhd_chipup_sem,
+ msecs_to_jiffies(POWERUP_WAIT_MS)) == 0) {
+ dhd_bus_unreg_sdio_notify();
+ chip_up = 1;
+ break;
+ }
+ DHD_ERROR(("\nfailed to power up wifi chip, retry again (%d left) **\n\n",
+ retry+1));
+ dhd_bus_unreg_sdio_notify();
+#if defined(CONFIG_WIFI_CONTROL_FUNC)
+ wl_android_wifictrl_func_del();
+#endif /* defined(CONFIG_WIFI_CONTROL_FUNC) */
+ dhd_customer_gpio_wlan_ctrl(WLAN_POWER_OFF);
+ } while (retry-- > 0);
+
+ if (!chip_up) {
+ DHD_ERROR(("\nfailed to power up wifi chip, max retry reached, exits **\n\n"));
+ return -ENODEV;
+ }
+#endif
+
+#if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
+ sema_init(&dhd_registration_sem, 0);
+#endif
+
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
- sema_init(&dhd_registration_sem, 0);
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
error = dhd_bus_register();
if (!error)
@@ -3748,27 +3786,30 @@ 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
+ }
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
#if defined(WL_CFG80211)
wl_android_post_init();
-#endif
+#endif /* defined(WL_CFG80211) */
return error;
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && 1
+
+#if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
fail_2:
dhd_bus_unregister();
#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
+
fail_1:
+
#if defined(CONFIG_WIFI_CONTROL_FUNC)
wl_android_wifictrl_func_del();
#endif
@@ -3784,6 +3825,7 @@ late_initcall(dhd_module_init);
#else
module_init(dhd_module_init);
#endif
+
module_exit(dhd_module_cleanup);
/*
@@ -3926,10 +3968,10 @@ dhd_os_open_image(char *filename)
* fp = open_namei(AT_FDCWD, filename, O_RD, 0);
* ???
*/
- if (IS_ERR(fp))
+ if (IS_ERR(fp))
fp = NULL;
- return fp;
+ return fp;
}
int
@@ -4035,7 +4077,7 @@ uint8* dhd_os_prealloc(void *osh, int section, uint size)
void dhd_os_prefree(void *osh, void *addr, uint size)
{
}
-#endif /* defined(CONFIG_DHD_USE_STATIC_BUF) */
+#endif /* defined(CONFIG_WIFI_CONTROL_FUNC) */
#if defined(CONFIG_WIRELESS_EXT)
struct iw_statistics *
@@ -4074,23 +4116,17 @@ dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata,
* Wireless ext is on primary interface only
*/
- ASSERT(dhd->iflist[*ifidx] != NULL);
- ASSERT(dhd->iflist[*ifidx]->net != NULL);
+ ASSERT(dhd->iflist[*ifidx] != NULL);
+ ASSERT(dhd->iflist[*ifidx]->net != NULL);
if (dhd->iflist[*ifidx]->net) {
- wl_iw_event(dhd->iflist[*ifidx]->net, event, *data);
+ wl_iw_event(dhd->iflist[*ifidx]->net, event, *data);
}
}
#endif /* defined(CONFIG_WIRELESS_EXT) */
#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)) {
/*
@@ -4115,6 +4151,7 @@ void
dhd_sendup_event(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data)
{
switch (ntoh32(event->event_type)) {
+#ifdef WLBTAMP
/* Send up locally generated AMP HCI Events */
case WLC_E_BTA_HCI_EVENT: {
struct sk_buff *p, *skb;
@@ -4206,9 +4243,10 @@ dhd_sendup_event(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data)
else {
/* Could not allocate a sk_buf */
DHD_ERROR(("%s: unable to alloc sk_buf", __FUNCTION__));
- }
+}
break;
} /* case WLC_E_BTA_HCI_EVENT */
+#endif /* WLBTAMP */
default:
break;
@@ -4217,7 +4255,7 @@ dhd_sendup_event(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data)
void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar)
{
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
+#if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
struct dhd_info *dhdinfo = dhd->info;
dhd_os_sdunlock(dhd);
wait_event_interruptible_timeout(dhdinfo->ctrl_wait, (*lockvar == FALSE), HZ * 2);
@@ -4228,7 +4266,7 @@ void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar)
void dhd_wait_event_wakeup(dhd_pub_t *dhd)
{
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
+#if 1 && (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);
@@ -4399,8 +4437,6 @@ int net_os_send_hang_message(struct net_device *dev)
#endif
#if defined(WL_CFG80211)
ret = wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED);
- dev_close(dev);
- dev_open(dev);
#endif
}
}
@@ -4415,7 +4451,6 @@ void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec)
memcpy(&dhd->pub.dhd_cspec, cspec, sizeof(wl_country_t));
}
-
void dhd_net_if_lock(struct net_device *dev)
{
dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
@@ -4430,7 +4465,7 @@ void dhd_net_if_unlock(struct net_device *dev)
static void dhd_net_if_lock_local(dhd_info_t *dhd)
{
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1
if (dhd)
mutex_lock(&dhd->dhd_net_if_mutex);
#endif
@@ -4438,7 +4473,7 @@ static void dhd_net_if_lock_local(dhd_info_t *dhd)
static void dhd_net_if_unlock_local(dhd_info_t *dhd)
{
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1
if (dhd)
mutex_unlock(&dhd->dhd_net_if_mutex);
#endif
@@ -4648,7 +4683,6 @@ int dhd_os_check_wakelock(void *dhdp)
#endif
return 0;
}
-
int net_os_wake_unlock(struct net_device *dev)
{
dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
@@ -4667,7 +4701,6 @@ int dhd_os_check_if_up(void *dhdp)
return 0;
return pub->up;
}
-
int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd)
{
int ifidx;
@@ -4708,7 +4741,8 @@ extern int dhd_wlfc_interface_entry_update(void* state, ewlfc_mac_entry_action_t
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)
+ ewlfc_mac_entry_action_t action, uint8 ifid, uint8 iftype,
+ uint8* ea)
{
if (dhd->pub.wlfc_state == NULL)
return BCME_OK;