diff options
Diffstat (limited to 'drivers/net/wireless/bcmdhd/dhd_linux.c')
-rw-r--r-- | drivers/net/wireless/bcmdhd/dhd_linux.c | 406 |
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; |