diff options
Diffstat (limited to 'drivers/net/wireless/bcmdhd/dhd_linux.c')
-rw-r--r-- | drivers/net/wireless/bcmdhd/dhd_linux.c | 165 |
1 files changed, 114 insertions, 51 deletions
diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c index 96dd304..50b3a54 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 333885 2012-05-18 00:39:03Z $ + * $Id: dhd_linux.c 352789 2012-08-24 00:01:33Z $ */ #include <typedefs.h> @@ -295,10 +295,16 @@ typedef struct dhd_info { char firmware_path[MOD_PARAM_PATHLEN]; char nvram_path[MOD_PARAM_PATHLEN]; +/* load firmware and/or nvram values from the filesystem */ +module_param_string(firmware_path, firmware_path, MOD_PARAM_PATHLEN, 0660); +module_param_string(nvram_path, nvram_path, MOD_PARAM_PATHLEN, 0); + +char info_string[MOD_PARAM_INFOLEN]; +module_param_string(info_string, info_string, MOD_PARAM_INFOLEN, 0444); + 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; #define DHD_REGISTRATION_TIMEOUT 12000 /* msec : allowed time to finished dhd registration */ @@ -311,10 +317,6 @@ module_param(dhd_sysioc, uint, 0); /* Error bits */ module_param(dhd_msg_level, int, 0); -/* load firmware and/or nvram values from the filesystem */ -module_param_string(firmware_path, firmware_path, MOD_PARAM_PATHLEN, 0660); -module_param_string(nvram_path, nvram_path, MOD_PARAM_PATHLEN, 0); - /* Watchdog interval */ uint dhd_watchdog_ms = 10; module_param(dhd_watchdog_ms, uint, 0); @@ -325,8 +327,8 @@ 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; +/* ARP offload agent mode : enable ARP Peer Auto-Reply */ +uint dhd_arp_mode = ARP_OL_AGENT | ARP_OL_PEER_AUTO_REPLY; module_param(dhd_arp_mode, uint, 0); /* ARP offload enable */ @@ -347,14 +349,13 @@ module_param(dhd_master_mode, uint, 0); #ifdef DHDTHREAD /* Watchdog thread priority, -1 to use kernel timer */ -int dhd_watchdog_prio = 97; +int dhd_watchdog_prio = 0; module_param(dhd_watchdog_prio, int, 0); /* DPC thread priority, -1 to use tasklet */ -int dhd_dpc_prio = 98; +int dhd_dpc_prio = 1; module_param(dhd_dpc_prio, int, 0); -/* DPC thread priority, -1 to use tasklet */ extern int dhd_dongle_memsize; module_param(dhd_dongle_memsize, int, 0); #endif /* DHDTHREAD */ @@ -543,7 +544,7 @@ static int dhd_set_suspend(int value, dhd_pub_t *dhd) if (value && dhd->in_suspend) { /* Kernel suspended */ - DHD_ERROR(("%s: force extra Suspend setting \n", __FUNCTION__)); + DHD_ERROR(("%s: force extra Suspend setting\n", __FUNCTION__)); #ifndef CONFIG_MACH_ARIES dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, @@ -569,7 +570,7 @@ static int dhd_set_suspend(int value, dhd_pub_t *dhd) } else { /* Kernel resumed */ - DHD_TRACE(("%s: Remove extra suspend setting \n", __FUNCTION__)); + DHD_ERROR(("%s: Remove extra suspend setting\n", __FUNCTION__)); #ifndef CONFIG_MACH_ARIES power_mode = PM_FAST; @@ -651,7 +652,7 @@ dhd_timeout_start(dhd_timeout_t *tmo, uint usec) tmo->limit = usec; tmo->increment = 0; tmo->elapsed = 0; - tmo->tick = 1000000 / HZ; + tmo->tick = jiffies_to_usecs(1); } int @@ -1031,7 +1032,7 @@ dhd_op_if(dhd_if_t *ifp) #endif netif_stop_queue(ifp->net); unregister_netdev(ifp->net); - ret = DHD_DEL_IF; + ret = DHD_DEL_IF; /* Make sure the free_netdev() is called */ #ifdef WL_CFG80211 if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) { @@ -1366,10 +1367,11 @@ dhd_start_xmit(struct sk_buff *skb, struct net_device *net) done: - if (ret) + if (ret) { dhd->pub.dstats.tx_dropped++; - else + } else { dhd->pub.tx_packets++; + } DHD_OS_WAKE_UNLOCK(&dhd->pub); @@ -1697,7 +1699,7 @@ dhd_watchdog_thread(void *data) /* Reschedule the watchdog */ if (dhd->wd_timer_valid) mod_timer(&dhd->timer, - jiffies + dhd_watchdog_ms * HZ / 1000); + jiffies + msecs_to_jiffies(dhd_watchdog_ms)); dhd_os_spin_unlock(&dhd->pub, flags); } dhd_os_sdunlock(&dhd->pub); @@ -1738,7 +1740,7 @@ static void dhd_watchdog(ulong data) /* Reschedule the watchdog */ if (dhd->wd_timer_valid) - mod_timer(&dhd->timer, jiffies + dhd_watchdog_ms * HZ / 1000); + mod_timer(&dhd->timer, jiffies + msecs_to_jiffies(dhd_watchdog_ms)); dhd_os_spin_unlock(&dhd->pub, flags); dhd_os_sdunlock(&dhd->pub); DHD_OS_WAKE_UNLOCK(&dhd->pub); @@ -2652,17 +2654,10 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) strcat(net->name, "%d"); } - if (dhd_add_if(dhd, 0, (void *)net, net->name, NULL, 0, 0) == DHD_BAD_IF) - goto fail; - dhd_state |= DHD_ATTACH_STATE_ADD_IF; - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) - net->open = NULL; -#else - net->netdev_ops = NULL; -#endif - sema_init(&dhd->proto_sem, 1); +#ifdef DHDTHREAD + sema_init(&dhd->sdsem, 1); +#endif #ifdef PROP_TXSTATUS spin_lock_init(&dhd->wlfc_spinlock); @@ -2678,6 +2673,17 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) spin_lock_init(&dhd->txqlock); spin_lock_init(&dhd->dhd_lock); + + if (dhd_add_if(dhd, 0, (void *)net, net->name, NULL, 0, 0) == DHD_BAD_IF) + goto fail; + dhd_state |= DHD_ATTACH_STATE_ADD_IF; + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) + net->open = NULL; +#else + net->netdev_ops = NULL; +#endif + /* Initialize Wakelock stuff */ spin_lock_init(&dhd->wakelock_spinlock); dhd->wakelock_counter = 0; @@ -2730,7 +2736,6 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) #ifdef DHDTHREAD /* Initialize thread based operation and lock */ - sema_init(&dhd->sdsem, 1); if ((dhd_watchdog_prio >= 0) && (dhd_dpc_prio >= 0)) { dhd->threads_only = TRUE; } @@ -2991,6 +2996,8 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) char *ptr; uint32 listen_interval = LISTEN_INTERVAL; /* Default Listen Interval in Beacons */ uint16 chipID; + int roam_trigger[2] = {CUSTOM_ROAM_TRIGGER_SETTING, WLC_BAND_ALL}; + int roam_delta[2] = {CUSTOM_ROAM_DELTA_SETTING, WLC_BAND_ALL}; #if defined(SOFTAP) uint dtim = 1; #endif @@ -3158,6 +3165,14 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) DHD_ERROR(("%s assoc_listen failed %d\n", __FUNCTION__, ret)); + /* custom romaing setting */ + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_TRIGGER, roam_trigger, + sizeof(roam_trigger), TRUE, 0)) < 0) + DHD_ERROR(("%s: roam trigger set failed %d\n", __FUNCTION__, ret)); + if ((dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_DELTA, roam_delta, + sizeof(roam_delta), TRUE, 0)) < 0) + DHD_ERROR(("%s: roam delta set failed %d\n", __FUNCTION__, ret)); + /* Set PowerSave mode */ dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, sizeof(power_mode), TRUE, 0); @@ -3216,6 +3231,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) setbit(eventmask, WLC_E_SET_SSID); setbit(eventmask, WLC_E_PRUNE); setbit(eventmask, WLC_E_AUTH); + setbit(eventmask, WLC_E_ASSOC); setbit(eventmask, WLC_E_REASSOC); setbit(eventmask, WLC_E_REASSOC_IND); setbit(eventmask, WLC_E_DEAUTH); @@ -3230,8 +3246,10 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) setbit(eventmask, WLC_E_MIC_ERROR); setbit(eventmask, WLC_E_ASSOC_REQ_IE); setbit(eventmask, WLC_E_ASSOC_RESP_IE); +#ifndef WL_CFG80211 setbit(eventmask, WLC_E_PMKID_CACHE); setbit(eventmask, WLC_E_TXFAIL); +#endif setbit(eventmask, WLC_E_JOIN_START); setbit(eventmask, WLC_E_SCAN_COMPLETE); #ifdef WLMEDIA_HTSF @@ -3321,6 +3339,8 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) /* Print fw version info */ DHD_ERROR(("Firmware version = %s\n", buf)); + dhd_set_version_info(dhd, buf); + DHD_BLOG(buf, strlen(buf) + 1); DHD_BLOG(dhd_version, strlen(dhd_version) + 1); @@ -3939,14 +3959,10 @@ int dhd_os_ioctl_resp_wait(dhd_pub_t *pub, uint *condition, bool *pending) { dhd_info_t * dhd = (dhd_info_t *)(pub->info); - int timeout = dhd_ioctl_timeout_msec; + int timeout; /* Convert timeout in millsecond to jiffies */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) - timeout = msecs_to_jiffies(timeout); -#else - timeout = timeout * HZ / 1000; -#endif + timeout = msecs_to_jiffies(dhd_ioctl_timeout_msec); timeout = wait_event_timeout(dhd->ioctl_resp_wait, (*condition), timeout); return timeout; @@ -3996,7 +4012,7 @@ dhd_os_wd_timer(void *bus, uint wdtick) if (wdtick) { dhd_watchdog_ms = (uint)wdtick; /* Re arm the timer, at last watchdog period */ - mod_timer(&dhd->timer, jiffies + dhd_watchdog_ms * HZ / 1000); + mod_timer(&dhd->timer, jiffies + msecs_to_jiffies(dhd_watchdog_ms)); dhd->wd_timer_valid = TRUE; } dhd_os_spin_unlock(pub, flags); @@ -4307,11 +4323,7 @@ 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_timeout(dhdinfo->ctrl_wait, (*lockvar == FALSE), timeout); dhd_os_sdlock(dhd); @@ -4336,6 +4348,13 @@ dhd_dev_reset(struct net_device *dev, uint8 flag) dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + if (flag == TRUE) { + /* Issue wl down command before resetting the chip */ + if (dhd_wl_ioctl_cmd(&dhd->pub, WLC_DOWN, NULL, 0, TRUE, 0) < 0) { + DHD_TRACE(("%s: wl down failed\n", __FUNCTION__)); + } + } + ret = dhd_bus_devreset(&dhd->pub, flag); if (ret) { DHD_ERROR(("%s: dhd_bus_devreset: %d\n", __FUNCTION__, ret)); @@ -4368,6 +4387,9 @@ int net_os_set_suspend(struct net_device *dev, int val, int force) #else ret = dhd_suspend_resume_helper(dhd, val, force); #endif +#ifdef WL_CFG80211 + wl_cfg80211_update_power_mode(dev); +#endif } return ret; } @@ -4516,32 +4538,59 @@ static void dhd_hang_process(struct work_struct *work) wl_iw_send_priv_event(dev, "HANG"); #endif #if defined(WL_CFG80211) - wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED); + wl_cfg80211_hang(dev, WLAN_REASON_DRIVER_ERROR); #endif } } +#endif -int net_os_send_hang_message(struct net_device *dev) +int dhd_os_send_hang_message(dhd_pub_t *dhdp) { - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); int ret = 0; - if (dhd) { - if (!dhd->pub.hang_was_sent) { - dhd->pub.hang_was_sent = 1; - schedule_work(&dhd->work_hang); + if (dhdp) { + if (!dhdp->hang_was_sent) { + dhdp->hang_was_sent = 1; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) + schedule_work(&dhdp->info->work_hang); +#endif } } return ret; } -#endif + +int net_os_send_hang_message(struct net_device *dev) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + int ret = 0; + + if (dhd) + ret = dhd_os_send_hang_message(&dhd->pub); + + return ret; +} 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) + if (dhd && dhd->pub.up) { memcpy(&dhd->pub.dhd_cspec, cspec, sizeof(wl_country_t)); +#ifdef WL_CFG80211 + wl_update_wiphybands(NULL); +#endif + } +} + +void dhd_bus_band_set(struct net_device *dev, uint band) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + + if (dhd && dhd->pub.up) { +#ifdef WL_CFG80211 + wl_update_wiphybands(NULL); +#endif + } } void dhd_net_if_lock(struct net_device *dev) @@ -4621,7 +4670,7 @@ int dhd_wait_pend8021x(struct net_device *dev) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - int timeout = 10 * HZ / 1000; + int timeout = msecs_to_jiffies(10); int ntimes = MAX_WAIT_FOR_8021X_TX; int pend = dhd_get_pend_8021x_cnt(dhd); @@ -4843,6 +4892,20 @@ int dhd_os_check_if_up(void *dhdp) return pub->up; } +void dhd_set_version_info(dhd_pub_t *dhdp, char *fw) +{ + int i; + + i = snprintf(info_string, sizeof(info_string), + " Driver: %s\n Firmware: %s ", EPI_VERSION_STR, fw); + + if (!dhdp) + return; + i = snprintf(&info_string[i], sizeof(info_string) - i, + "\n Chip: %x Rev %x Pkg %x", dhd_bus_chip_id(dhdp), + dhd_bus_chiprev_id(dhdp), dhd_bus_chippkg_id(dhdp)); +} + int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd) { int ifidx; |