summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGreg Goldman <ggoldman@broadcom.com>2010-10-21 14:04:41 -0700
committerDmitry Shmidt <dimitrysh@google.com>2010-10-22 10:44:23 -0700
commit5f986025ba0b705731b36facc639d7e7957b0a09 (patch)
tree5a65383f754f943343942ca2e7a297323a76d0ea
parent5ff1b9cdb1791cab2759a2a073f0ba6b24579bc3 (diff)
net: wireless: bcm4329: Improve BT-coex for eSCO
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
-rw-r--r--drivers/net/wireless/bcm4329/dhd_linux.c2
-rw-r--r--drivers/net/wireless/bcm4329/wl_iw.c180
2 files changed, 158 insertions, 24 deletions
diff --git a/drivers/net/wireless/bcm4329/dhd_linux.c b/drivers/net/wireless/bcm4329/dhd_linux.c
index fe7cbf116372..d7e72c8d12d2 100644
--- a/drivers/net/wireless/bcm4329/dhd_linux.c
+++ b/drivers/net/wireless/bcm4329/dhd_linux.c
@@ -305,7 +305,7 @@ char nvram_path[MOD_PARAM_PATHLEN];
#if defined(CONFIG_HAS_EARLYSUSPEND)
#define KEEP_ALIVE
-#define KEEP_ALIVE_PERIOD 60000
+#define KEEP_ALIVE_PERIOD 55000
#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
diff --git a/drivers/net/wireless/bcm4329/wl_iw.c b/drivers/net/wireless/bcm4329/wl_iw.c
index a9f3ee31f1dc..82164edc6534 100644
--- a/drivers/net/wireless/bcm4329/wl_iw.c
+++ b/drivers/net/wireless/bcm4329/wl_iw.c
@@ -21,7 +21,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: wl_iw.c,v 1.51.4.9.2.6.4.142.4.13 2010/09/15 03:34:56 Exp $
+ * $Id: wl_iw.c,v 1.51.4.9.2.6.4.142.4.28 2010/10/19 22:55:15 Exp $
*/
@@ -54,6 +54,7 @@ typedef const struct si_pub si_t;
#define WL_INFORM(x)
#define WL_WSEC(x)
#define WL_SCAN(x)
+#define WL_TRACE_COEX(x)
#include <wl_iw.h>
@@ -219,6 +220,11 @@ typedef struct iscan_info {
int iscan_ex_param_size;
} iscan_info_t;
#define COEX_DHCP 1
+
+#define BT_DHCP_eSCO_FIX
+#define BT_DHCP_USE_FLAGS
+#define BT_DHCP_OPPORTUNITY_WINDOW_TIME 2500
+#define BT_DHCP_FLAG_FORCE_TIME 5500
static void wl_iw_bt_flag_set(struct net_device *dev, bool set);
static void wl_iw_bt_release(void);
@@ -228,18 +234,16 @@ typedef enum bt_coex_status {
BT_DHCP_OPPORTUNITY_WINDOW,
BT_DHCP_FLAG_FORCE_TIMEOUT
} coex_status_t;
-#define BT_DHCP_OPPORTUNITY_WINDOW_TIEM 2500
-#define BT_DHCP_FLAG_FORCE_TIME 5500
typedef struct bt_info {
struct net_device *dev;
struct timer_list timer;
uint32 timer_ms;
uint32 timer_on;
- int bt_state;
+ bool dhcp_done;
+ int bt_state;
-
- long bt_pid;
+ long bt_pid;
struct semaphore bt_sem;
struct completion bt_exited;
} bt_info_t;
@@ -664,29 +668,34 @@ wl_iw_set_power_mode(
int pm_local = PM_OFF;
char powermode_val = 0;
+ WL_TRACE_COEX(("%s: DHCP session cmd:%s\n", __FUNCTION__, extra));
+
strncpy((char *)&powermode_val, extra + strlen("POWERMODE") + 1, 1);
if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) {
- WL_TRACE(("%s: DHCP session starts\n", __FUNCTION__));
-
dev_wlc_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm));
dev_wlc_ioctl(dev, WLC_SET_PM, &pm_local, sizeof(pm_local));
/* Disable packet filtering if necessary */
net_os_set_packet_filter(dev, 0);
- } else if (strnicmp((char *)&powermode_val, "0", strlen("0")) == 0) {
+ g_bt->dhcp_done = false;
+ WL_TRACE_COEX(("%s: DHCP start, pm:%d changed to pm:%d\n",
+ __FUNCTION__, pm, pm_local));
- WL_TRACE(("%s: DHCP session done\n", __FUNCTION__));
+ } else if (strnicmp((char *)&powermode_val, "0", strlen("0")) == 0) {
dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm));
/* Enable packet filtering if was turned off */
net_os_set_packet_filter(dev, 1);
+ g_bt->dhcp_done = true;
+
} else {
- WL_ERROR(("Unkwown yet power setting, ignored\n"));
+ WL_ERROR(("%s Unkwown yet power setting, ignored\n",
+ __FUNCTION__));
}
p += snprintf(p, MAX_WX_STRING, "OK");
@@ -697,6 +706,99 @@ wl_iw_set_power_mode(
}
#endif
+
+#if defined(BT_DHCP_eSCO_FIX)
+
+static int set_btc_esco_params(struct net_device *dev, bool trump_sco)
+{
+ static bool saved_status = false;
+
+ char buf_reg50va_dhcp_on[8] = { 50, 00, 00, 00, 0x22, 0x80, 0x00, 0x00 };
+ char buf_reg51va_dhcp_on[8] = { 51, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
+ char buf_reg64va_dhcp_on[8] = { 64, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
+ char buf_reg65va_dhcp_on[8] = { 65, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
+ char buf_reg71va_dhcp_on[8] = { 71, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
+
+ uint32 regaddr;
+ static uint32 saved_reg50;
+ static uint32 saved_reg51;
+ static uint32 saved_reg64;
+ static uint32 saved_reg65;
+ static uint32 saved_reg71;
+
+ if (trump_sco) {
+
+ WL_TRACE_COEX(("Do new SCO/eSCO coex algo {save & override} \n"));
+
+ if ((!dev_wlc_intvar_get_reg(dev, "btc_params", 50, &saved_reg50)) &&
+ (!dev_wlc_intvar_get_reg(dev, "btc_params", 51, &saved_reg51)) &&
+ (!dev_wlc_intvar_get_reg(dev, "btc_params", 64, &saved_reg64)) &&
+ (!dev_wlc_intvar_get_reg(dev, "btc_params", 65, &saved_reg65)) &&
+ (!dev_wlc_intvar_get_reg(dev, "btc_params", 71, &saved_reg71))) {
+
+ saved_status = TRUE;
+ WL_TRACE_COEX(("%s saved bt_params[50,51,64,65,71]:"
+ " 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ __FUNCTION__, saved_reg50, saved_reg51,
+ saved_reg64, saved_reg65, saved_reg71));
+
+ } else {
+ WL_ERROR((":%s: save btc_params failed\n",
+ __FUNCTION__));
+ saved_status = false;
+ return -1;
+ }
+
+ WL_TRACE_COEX(("override with [50,51,64,65,71]:"
+ " 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ *(u32 *)(buf_reg50va_dhcp_on+4),
+ *(u32 *)(buf_reg51va_dhcp_on+4),
+ *(u32 *)(buf_reg64va_dhcp_on+4),
+ *(u32 *)(buf_reg65va_dhcp_on+4),
+ *(u32 *)(buf_reg71va_dhcp_on+4)));
+
+ dev_wlc_bufvar_set(dev, "btc_params", (char *)&buf_reg50va_dhcp_on[0], 8);
+ dev_wlc_bufvar_set(dev, "btc_params", (char *)&buf_reg51va_dhcp_on[0], 8);
+ dev_wlc_bufvar_set(dev, "btc_params", (char *)&buf_reg64va_dhcp_on[0], 8);
+ dev_wlc_bufvar_set(dev, "btc_params", (char *)&buf_reg65va_dhcp_on[0], 8);
+ dev_wlc_bufvar_set(dev, "btc_params", (char *)&buf_reg71va_dhcp_on[0], 8);
+
+ saved_status = true;
+
+ } else if (saved_status) {
+
+ WL_TRACE_COEX(("Do new SCO/eSCO coex algo {save & override} \n"));
+
+ regaddr = 50;
+ dev_wlc_intvar_set_reg(dev, "btc_params",
+ (char *)&regaddr, (char *)&saved_reg50);
+ regaddr = 51;
+ dev_wlc_intvar_set_reg(dev, "btc_params",
+ (char *)&regaddr, (char *)&saved_reg51);
+ regaddr = 64;
+ dev_wlc_intvar_set_reg(dev, "btc_params",
+ (char *)&regaddr, (char *)&saved_reg64);
+ regaddr = 65;
+ dev_wlc_intvar_set_reg(dev, "btc_params",
+ (char *)&regaddr, (char *)&saved_reg65);
+ regaddr = 71;
+ dev_wlc_intvar_set_reg(dev, "btc_params",
+ (char *)&regaddr, (char *)&saved_reg71);
+
+ WL_TRACE_COEX(("restore bt_params[50,51,64,65,71]: 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ saved_reg50, saved_reg51, saved_reg64,
+ saved_reg65, saved_reg71));
+
+ saved_status = false;
+ } else {
+ WL_ERROR((":%s att to restore not saved BTCOEX params\n",
+ __FUNCTION__));
+ return -1;
+ }
+ return 0;
+}
+#endif
+
static int
wl_iw_get_power_mode(
struct net_device *dev,
@@ -764,7 +866,7 @@ wl_iw_set_btcoex_dhcp(
if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) {
- WL_TRACE(("%s: DHCP session starts\n", __FUNCTION__));
+ WL_TRACE_COEX(("%s: DHCP session start, cmd:%s\n", __FUNCTION__, extra));
if ((saved_status == FALSE) &&
#ifndef CUSTOMER_HW2
@@ -774,7 +876,7 @@ wl_iw_set_btcoex_dhcp(
(!dev_wlc_intvar_get_reg(dev, "btc_params", 41, &saved_reg41)) &&
(!dev_wlc_intvar_get_reg(dev, "btc_params", 68, &saved_reg68))) {
saved_status = TRUE;
- WL_TRACE(("Saved 0x%x 0x%x 0x%x\n", \
+ WL_TRACE_COEX(("save regs {66,41,68} ->: 0x%x 0x%x 0x%x\n", \
saved_reg66, saved_reg41, saved_reg68));
#ifndef CUSTOMER_HW2
@@ -796,7 +898,7 @@ wl_iw_set_btcoex_dhcp(
g_bt->bt_state = BT_DHCP_START;
g_bt->timer_on = 1;
mod_timer(&g_bt->timer, g_bt->timer.expires);
- WL_TRACE(("%s enable BT DHCP Timer\n", \
+ WL_TRACE_COEX(("%s enable BT DHCP Timer\n", \
__FUNCTION__));
#ifndef CUSTOMER_HW2
}
@@ -812,16 +914,22 @@ wl_iw_set_btcoex_dhcp(
#else
else if (strnicmp((char *)&powermode_val, "0", strlen("0")) == 0) {
#endif
- WL_TRACE(("%s: DHCP session done\n", __FUNCTION__));
#ifndef CUSTOMER_HW2
dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm));
#endif
- WL_TRACE(("%s disable BT DHCP Timer\n", __FUNCTION__));
+ WL_TRACE_COEX(("%s disable BT DHCP Timer\n", __FUNCTION__));
if (g_bt->timer_on) {
g_bt->timer_on = 0;
del_timer_sync(&g_bt->timer);
+
+ if (g_bt->bt_state != BT_DHCP_IDLE) {
+ WL_TRACE_COEX(("%s bt->bt_state:%d\n",
+ __FUNCTION__, g_bt->bt_state));
+
+ up(&g_bt->bt_sem);
+ }
}
dev_wlc_bufvar_set(dev, "btc_flags", \
@@ -837,11 +945,15 @@ wl_iw_set_btcoex_dhcp(
regaddr = 68;
dev_wlc_intvar_set_reg(dev, "btc_params", \
(char *)&regaddr, (char *)&saved_reg68);
+
+ WL_TRACE_COEX(("restore regs {66,41,68} <- 0x%x 0x%x 0x%x\n", \
+ saved_reg66, saved_reg41, saved_reg68));
}
saved_status = FALSE;
}
else {
- WL_ERROR(("Unkwown yet power setting, ignored\n"));
+ WL_ERROR(("%s Unkwown yet power setting, ignored\n",
+ __FUNCTION__));
}
p += snprintf(p, MAX_WX_STRING, "OK");
@@ -1063,7 +1175,6 @@ wl_iw_set_band(
if ((band == WLC_BAND_AUTO) || (band == WLC_BAND_5G) || (band == WLC_BAND_2G)) {
-
if ((error = dev_wlc_ioctl(dev, WLC_SET_BAND,
&band, sizeof(band))) >= 0) {
p += snprintf(p, MAX_WX_STRING, "OK");
@@ -7611,13 +7722,21 @@ wl_iw_bt_flag_set(
struct net_device *dev,
bool set)
{
+#if defined(BT_DHCP_USE_FLAGS)
char buf_flag7_dhcp_on[8] = { 7, 00, 00, 00, 0x1, 0x0, 0x00, 0x00 };
char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00};
+#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
rtnl_lock();
#endif
+#if defined(BT_DHCP_eSCO_FIX)
+ set_btc_esco_params(dev, set);
+#endif
+
+#if defined(BT_DHCP_USE_FLAGS)
+ WL_TRACE_COEX(("WI-FI priority boost via bt flags, set:%d\n", set));
if (set == TRUE) {
dev_wlc_bufvar_set(dev, "btc_flags",
(char *)&buf_flag7_dhcp_on[0], sizeof(buf_flag7_dhcp_on));
@@ -7626,6 +7745,7 @@ wl_iw_bt_flag_set(
dev_wlc_bufvar_set(dev, "btc_flags",
(char *)&buf_flag7_default[0], sizeof(buf_flag7_default));
}
+#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
rtnl_unlock();
@@ -7658,14 +7778,23 @@ _bt_dhcp_sysioc_thread(void *data)
switch (g_bt->bt_state) {
case BT_DHCP_START:
+ WL_TRACE_COEX(("%s bt_dhcp stm: started \n", __FUNCTION__));
g_bt->bt_state = BT_DHCP_OPPORTUNITY_WINDOW;
- mod_timer(&g_bt->timer, jiffies + BT_DHCP_OPPORTUNITY_WINDOW_TIEM*HZ/1000);
+ mod_timer(&g_bt->timer, jiffies + BT_DHCP_OPPORTUNITY_WINDOW_TIME*HZ/1000);
g_bt->timer_on = 1;
break;
case BT_DHCP_OPPORTUNITY_WINDOW:
- WL_TRACE(("%s waiting for %d msec expired, force bt flag\n", \
- __FUNCTION__, BT_DHCP_OPPORTUNITY_WINDOW_TIEM));
+ if (g_bt->dhcp_done) {
+ WL_TRACE_COEX(("%s DHCP Done before T1 expiration\n", \
+ __FUNCTION__));
+ g_bt->bt_state = BT_DHCP_IDLE;
+ g_bt->timer_on = 0;
+ break;
+ }
+
+ WL_TRACE_COEX(("%s DHCP T1:%d expired\n", \
+ __FUNCTION__, BT_DHCP_OPPORTUNITY_WINDOW_TIME));
if (g_bt->dev) wl_iw_bt_flag_set(g_bt->dev, TRUE);
g_bt->bt_state = BT_DHCP_FLAG_FORCE_TIMEOUT;
mod_timer(&g_bt->timer, jiffies + BT_DHCP_FLAG_FORCE_TIME*HZ/1000);
@@ -7673,9 +7802,14 @@ _bt_dhcp_sysioc_thread(void *data)
break;
case BT_DHCP_FLAG_FORCE_TIMEOUT:
- WL_TRACE(("%s waiting for %d msec expired remove bt flag\n", \
+ if (g_bt->dhcp_done) {
+ WL_TRACE_COEX(("%s DHCP Done before T2 expiration\n", \
+ __FUNCTION__));
+ } else {
+ WL_TRACE_COEX(("%s DHCP wait interval T2:%d msec expired\n",
__FUNCTION__, BT_DHCP_FLAG_FORCE_TIME));
-
+ }
+
if (g_bt->dev) wl_iw_bt_flag_set(g_bt->dev, FALSE);
g_bt->bt_state = BT_DHCP_IDLE;
g_bt->timer_on = 0;