summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/bcmdhd/dhd_linux.c
diff options
context:
space:
mode:
authorHoward M. Harte <hharte@broadcom.com>2011-06-15 18:52:15 -0700
committerDmitry Shmidt <dimitrysh@google.com>2011-06-17 10:42:54 -0700
commit0d9f3c2791c1e19796d3a41d8ec45093583817e7 (patch)
treee39143aca1da3943af7945677dd79f1ae6811ebf /drivers/net/wireless/bcmdhd/dhd_linux.c
parent097d39641dc94f9e5891481e066ef14b12cca408 (diff)
net: wireless: bcmdhd: Combined patch from 4.218.248-31
bcmdhd: Allocate skb with GFP_KERNEL flag if possible: fix for older kernels. bcmdhd: Fix race conditions for sysioc_thread * Fix up formatting and #ifdefs. net: wireless: bcmdhd: Fix get_customized_country_code() for older kernels. net: wireless: bcmdhd: Move PNO function prototypes to dhd.h. Add private command support. net: wireless: bcmdhd: Set proper read barrier net: wireless: bcmdhd: Fix memory leak in case of dhd_bus_init() failure net: wireless: bcmdhd: Fix wake_lock symmetry net: wireless: bcmdhd: Ignore error if scan results are empty net: wireless: bcmdhd: Add sdlock to firmware loading net: wireless: bcmdhd: Fix watchdog syncronization during start/stop net: wireless: bcmdhd: Fix Makefile to allow WEXT compilation Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
Diffstat (limited to 'drivers/net/wireless/bcmdhd/dhd_linux.c')
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_linux.c99
1 files changed, 45 insertions, 54 deletions
diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c
index 7d78bae0df0..57f38ee40fa 100644
--- a/drivers/net/wireless/bcmdhd/dhd_linux.c
+++ b/drivers/net/wireless/bcmdhd/dhd_linux.c
@@ -90,7 +90,7 @@ static histo_t vi_d1, vi_d2, vi_d3, vi_d4;
#endif /* WLMEDIA_HTSF */
#if defined(SOFTAP)
-extern bool ap_cfg_running;
+extern bool ap_cfg_running;
#endif
/* enable HOSTIP cache update from the host side when an eth0:N is up */
@@ -171,6 +171,7 @@ int wifi_get_mac_addr(unsigned char *buf)
}
#endif
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
void *wifi_get_country_code(char *ccode)
{
DHD_TRACE(("%s\n", __FUNCTION__));
@@ -181,6 +182,7 @@ void *wifi_get_country_code(char *ccode)
}
return NULL;
}
+#endif
static int wifi_probe(struct platform_device *pdev)
{
@@ -437,6 +439,7 @@ char nvram_path[MOD_PARAM_PATHLEN];
extern int wl_control_wl_start(struct net_device *dev);
extern int net_os_send_hang_message(struct net_device *dev);
+extern int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd);
#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 */
@@ -459,7 +462,7 @@ module_param(dhd_watchdog_ms, uint, 0);
#if defined(DHD_DEBUG)
/* Console poll interval */
-uint dhd_console_ms = 250;
+uint dhd_console_ms = 0;
module_param(dhd_console_ms, uint, 0);
#endif /* defined(DHD_DEBUG) */
@@ -1206,6 +1209,7 @@ _dhd_sysioc_thread(void *data)
}
dhd_os_start_lock(&dhd->pub);
+ DHD_OS_WAKE_LOCK(&dhd->pub);
for (i = 0; i < DHD_MAX_IFS; i++) {
if (dhd->iflist[i]) {
@@ -1251,7 +1255,6 @@ _dhd_sysioc_thread(void *data)
DHD_OS_WAKE_UNLOCK(&dhd->pub);
dhd_os_start_unlock(&dhd->pub);
-
}
DHD_TRACE(("%s: stopped\n", __FUNCTION__));
complete_and_exit(&tsk->completed, 0);
@@ -1762,11 +1765,10 @@ dhd_watchdog_thread(void *data)
break;
}
+ dhd_os_sdlock(&dhd->pub);
if (dhd->pub.dongle_reset == FALSE) {
DHD_TIMER(("%s:\n", __FUNCTION__));
- DHD_OS_WAKE_LOCK(&dhd->pub);
-
/* Call the bus module watchdog */
dhd_bus_watchdog(&dhd->pub);
@@ -1776,11 +1778,12 @@ dhd_watchdog_thread(void *data)
if (dhd->wd_timer_valid)
mod_timer(&dhd->timer,
jiffies + dhd_watchdog_ms * HZ / 1000);
- DHD_OS_WAKE_UNLOCK(&dhd->pub);
}
+ dhd_os_sdunlock(&dhd->pub);
+ DHD_OS_WAKE_UNLOCK(&dhd->pub);
} else {
break;
- }
+ }
complete_and_exit(&tsk->completed, 0);
}
@@ -1790,11 +1793,12 @@ static void dhd_watchdog(ulong data)
{
dhd_info_t *dhd = (dhd_info_t *)data;
+ DHD_OS_WAKE_LOCK(&dhd->pub);
if (dhd->pub.dongle_reset) {
+ DHD_OS_WAKE_UNLOCK(&dhd->pub);
return;
}
- DHD_OS_WAKE_LOCK(&dhd->pub);
#ifdef DHDTHREAD
if (dhd->thr_wdt_ctl.thr_pid >= 0) {
up(&dhd->thr_wdt_ctl.sema);
@@ -1802,6 +1806,7 @@ static void dhd_watchdog(ulong data)
}
#endif /* DHDTHREAD */
+ dhd_os_sdlock(&dhd->pub);
/* Call the bus module watchdog */
dhd_bus_watchdog(&dhd->pub);
@@ -1811,6 +1816,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);
+ dhd_os_sdunlock(&dhd->pub);
DHD_OS_WAKE_UNLOCK(&dhd->pub);
}
@@ -1852,7 +1858,6 @@ dhd_dpc_thread(void *data)
if (dhd->pub.busstate != DHD_BUS_DOWN) {
if (dhd_bus_dpc(dhd->pub.bus)) {
up(&tsk->sema);
- DHD_OS_WAKE_LOCK_TIMEOUT(&dhd->pub);
}
else {
DHD_OS_WAKE_UNLOCK(&dhd->pub);
@@ -2151,6 +2156,12 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd)
}
#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) */
+ if (cmd == SIOCDEVPRIVATE+1) {
+ ret = wl_android_priv_cmd(net, ifr, cmd);
+ DHD_OS_WAKE_UNLOCK(&dhd->pub);
+ return ret;
+ }
+
if (cmd != SIOCDEVPRIVATE) {
DHD_OS_WAKE_UNLOCK(&dhd->pub);
return -EOPNOTSUPP;
@@ -2695,6 +2706,8 @@ dhd_bus_start(dhd_pub_t *dhdp)
DHD_TRACE(("%s: \n", __FUNCTION__));
+ dhd_os_sdlock(dhdp);
+
/* try to download image and nvram to the dongle */
if ((dhd->pub.busstate == DHD_BUS_DOWN) &&
(fw_path != NULL) && (fw_path[0] != '\0') &&
@@ -2704,24 +2717,23 @@ dhd_bus_start(dhd_pub_t *dhdp)
fw_path, nv_path))) {
DHD_ERROR(("%s: dhdsdio_probe_download failed. firmware = %s nvram = %s\n",
__FUNCTION__, fw_path, nv_path));
+ dhd_os_sdunlock(dhdp);
return -1;
}
}
- if (dhd->pub.busstate != DHD_BUS_LOAD)
+ if (dhd->pub.busstate != DHD_BUS_LOAD) {
+ dhd_os_sdunlock(dhdp);
return -ENETDOWN;
+ }
/* Start the watchdog timer */
dhd->pub.tickcnt = 0;
dhd_os_wd_timer(&dhd->pub, dhd_watchdog_ms);
/* Bring up the bus */
-#ifdef DHDTHREAD
- if ((ret = dhd_bus_init(&dhd->pub, TRUE)) != 0) {
-#else
if ((ret = dhd_bus_init(&dhd->pub, FALSE)) != 0) {
-#endif
-
DHD_ERROR(("%s, dhd_bus_init failed %d\n", __FUNCTION__, ret));
+ dhd_os_sdunlock(dhdp);
return ret;
}
#if defined(OOB_INTR_ONLY)
@@ -2732,6 +2744,7 @@ dhd_bus_start(dhd_pub_t *dhdp)
del_timer_sync(&dhd->timer);
DHD_ERROR(("%s Host failed to register for OOB\n", __FUNCTION__));
+ dhd_os_sdunlock(dhdp);
return -ENODEV;
}
@@ -2744,9 +2757,12 @@ dhd_bus_start(dhd_pub_t *dhdp)
del_timer_sync(&dhd->timer);
dhd->wd_timer_valid = FALSE;
DHD_ERROR(("%s failed bus is not ready\n", __FUNCTION__));
+ dhd_os_sdunlock(dhdp);
return -ENODEV;
}
+ dhd_os_sdunlock(dhdp);
+
#ifdef EMBEDDED_PLATFORM
bcm_mkiovar("event_msgs", dhdp->eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf));
dhd_wl_ioctl_cmd(dhdp, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0);
@@ -3432,53 +3448,38 @@ void
dhd_os_wd_timer(void *bus, uint wdtick)
{
dhd_pub_t *pub = bus;
- static uint save_dhd_watchdog_ms = 0;
dhd_info_t *dhd = (dhd_info_t *)pub->info;
+ unsigned long flags;
DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+ flags = dhd_os_spin_lock(pub);
+
/* don't start the wd until fw is loaded */
- if (pub->busstate == DHD_BUS_DOWN)
+ if (pub->busstate == DHD_BUS_DOWN) {
+ dhd_os_spin_unlock(pub, flags);
return;
+ }
/* Totally stop the timer */
if (!wdtick && dhd->wd_timer_valid == TRUE) {
+ dhd->wd_timer_valid = FALSE;
+ dhd_os_spin_unlock(pub, flags);
#ifdef DHDTHREAD
del_timer_sync(&dhd->timer);
#else
del_timer(&dhd->timer);
#endif /* DHDTHREAD */
- dhd->wd_timer_valid = FALSE;
- save_dhd_watchdog_ms = wdtick;
return;
}
if (wdtick) {
- dhd_watchdog_ms = (uint)wdtick;
- if (save_dhd_watchdog_ms != dhd_watchdog_ms) {
-
- if (dhd->wd_timer_valid == TRUE)
- /* Stop timer and restart at new value */
-#ifdef DHDTHREAD
- del_timer_sync(&dhd->timer);
-#else
- del_timer(&dhd->timer);
-#endif /* DHDTHREAD */
-
- /* Create timer again when watchdog period is
- dynamically changed or in the first instance
- */
- dhd->timer.expires = jiffies + dhd_watchdog_ms * HZ / 1000;
- add_timer(&dhd->timer);
- } else {
- /* Re arm the timer, at last watchdog period */
- mod_timer(&dhd->timer, jiffies + dhd_watchdog_ms * HZ / 1000);
- }
-
- dhd->wd_timer_valid = TRUE;
-
- save_dhd_watchdog_ms = wdtick;
+ dhd_watchdog_ms = (uint)wdtick;
+ /* Re arm the timer, at last watchdog period */
+ mod_timer(&dhd->timer, jiffies + dhd_watchdog_ms * HZ / 1000);
+ dhd->wd_timer_valid = TRUE;
}
+ dhd_os_spin_unlock(pub, flags);
}
void *
@@ -3820,19 +3821,12 @@ dhd_dev_reset(struct net_device *dev, uint8 flag)
dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
- /* Turning off watchdog */
- if (flag)
- dhd_os_wd_timer(&dhd->pub, 0);
-
ret = dhd_bus_devreset(&dhd->pub, flag);
if (ret) {
DHD_ERROR(("%s: dhd_bus_devreset: %d\n", __FUNCTION__, ret));
return ret;
}
- /* Turning on watchdog back */
- if (!flag)
- dhd_os_wd_timer(&dhd->pub, dhd_watchdog_ms);
- DHD_ERROR(("%s: WLAN OFF DONE\n", __FUNCTION__));
+ DHD_ERROR(("%s: WLAN %s DONE\n", __FUNCTION__, flag ? "OFF" : "ON"));
return ret;
}
@@ -3987,8 +3981,6 @@ void dhd_os_start_unlock(dhd_pub_t *pub)
#endif
}
-
-#ifdef SOFTAP
unsigned long dhd_os_spin_lock(dhd_pub_t *pub)
{
dhd_info_t *dhd = (dhd_info_t *)(pub->info);
@@ -4007,7 +3999,6 @@ void dhd_os_spin_unlock(dhd_pub_t *pub, unsigned long flags)
if (dhd)
spin_unlock_irqrestore(&dhd->dhd_lock, flags);
}
-#endif /* SOFTAP */
static int
dhd_get_pend_8021x_cnt(dhd_info_t *dhd)