net: wireless: bcm4329: Improve BT-coex for eSCO
authorGreg Goldman <ggoldman@broadcom.com>
Thu, 21 Oct 2010 21:04:41 +0000 (14:04 -0700)
committerDmitry Shmidt <dimitrysh@google.com>
Fri, 22 Oct 2010 17:44:23 +0000 (10:44 -0700)
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
drivers/net/wireless/bcm4329/dhd_linux.c
drivers/net/wireless/bcm4329/wl_iw.c

index fe7cbf116372352f50feec75a1e5aa2221c6049b..d7e72c8d12d201b0907792725f86ff9396101b42 100644 (file)
@@ -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))
index a9f3ee31f1dce92befce198df6d16f48b6a00157..82164edc6534679568a8916b6e167eb66da1175e 100644 (file)
@@ -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;