2012-06-16 19:31:55

by Grazvydas Ignotas

[permalink] [raw]
Subject: [PATCH 0/3] wl1251 filtering fixes

These paches handle some wl1251 filtering issues that seem to fix some
connection drop issues. These changes have been tested on Pandora units
by several users with positive results.

Grazvydas Ignotas (3):
wl1251: remove unused filter_work
wl1251: fix filtering support
wl1251: send filters to firmware as they are set

drivers/net/wireless/ti/wl1251/cmd.c | 9 ----
drivers/net/wireless/ti/wl1251/main.c | 67 +++++++++++++------------------
drivers/net/wireless/ti/wl1251/wl1251.h | 1 -
3 files changed, 28 insertions(+), 49 deletions(-)



2012-06-16 19:31:59

by Grazvydas Ignotas

[permalink] [raw]
Subject: [PATCH 3/3] wl1251: send filters to firmware as they are set

Firmware supports changing filters using ACX_RX_CFG command,
so use it in .configure_filter callback. Firmware also supports
probe request filtering, so add it too along the way.
This will also re-enable BSSID filter which is now removed by
join command while associating.

Signed-off-by: Grazvydas Ignotas <[email protected]>
---
drivers/net/wireless/ti/wl1251/main.c | 27 +++++++++++++++++++++++----
1 files changed, 23 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c
index 6094e3f..3118c42 100644
--- a/drivers/net/wireless/ti/wl1251/main.c
+++ b/drivers/net/wireless/ti/wl1251/main.c
@@ -659,13 +659,15 @@ out:
FIF_FCSFAIL | \
FIF_BCN_PRBRESP_PROMISC | \
FIF_CONTROL | \
- FIF_OTHER_BSS)
+ FIF_OTHER_BSS | \
+ FIF_PROBE_REQ)

static void wl1251_op_configure_filter(struct ieee80211_hw *hw,
unsigned int changed,
unsigned int *total,u64 multicast)
{
struct wl1251 *wl = hw->priv;
+ int ret;

wl1251_debug(DEBUG_MAC80211, "mac80211 configure filter");

@@ -676,7 +678,7 @@ static void wl1251_op_configure_filter(struct ieee80211_hw *hw,
/* no filters which we support changed */
return;

- /* FIXME: wl->rx_config and wl->rx_filter are not protected */
+ mutex_lock(&wl->mutex);

wl->rx_config = WL1251_DEFAULT_RX_CONFIG;
wl->rx_filter = WL1251_DEFAULT_RX_FILTER;
@@ -699,8 +701,25 @@ static void wl1251_op_configure_filter(struct ieee80211_hw *hw,
}
if (*total & FIF_CONTROL)
wl->rx_filter |= CFG_RX_CTL_EN;
- if (*total & FIF_OTHER_BSS)
- wl->rx_filter &= ~CFG_BSSID_FILTER_EN;
+ if (*total & FIF_OTHER_BSS || is_zero_ether_addr(wl->bssid))
+ wl->rx_config &= ~CFG_BSSID_FILTER_EN;
+ if (*total & FIF_PROBE_REQ)
+ wl->rx_filter |= CFG_RX_PREQ_EN;
+
+ if (wl->state == WL1251_STATE_OFF)
+ goto out;
+
+ ret = wl1251_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
+ /* send filters to firmware */
+ wl1251_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
+
+ wl1251_ps_elp_sleep(wl);
+
+out:
+ mutex_unlock(&wl->mutex);
}

/* HW encryption */
--
1.7.0.4


2012-06-16 19:31:56

by Grazvydas Ignotas

[permalink] [raw]
Subject: [PATCH 1/3] wl1251: remove unused filter_work

filter_work is never used, remove it.

Signed-off-by: Grazvydas Ignotas <[email protected]>
---
drivers/net/wireless/ti/wl1251/main.c | 36 -------------------------------
drivers/net/wireless/ti/wl1251/wl1251.h | 1 -
2 files changed, 0 insertions(+), 37 deletions(-)

diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c
index d1afb8e..ff60a7a 100644
--- a/drivers/net/wireless/ti/wl1251/main.c
+++ b/drivers/net/wireless/ti/wl1251/main.c
@@ -348,33 +348,6 @@ out:
return ret;
}

-static void wl1251_filter_work(struct work_struct *work)
-{
- struct wl1251 *wl =
- container_of(work, struct wl1251, filter_work);
- int ret;
-
- mutex_lock(&wl->mutex);
-
- if (wl->state == WL1251_STATE_OFF)
- goto out;
-
- ret = wl1251_ps_elp_wakeup(wl);
- if (ret < 0)
- goto out;
-
- ret = wl1251_join(wl, wl->bss_type, wl->channel, wl->beacon_int,
- wl->dtim_period);
- if (ret < 0)
- goto out_sleep;
-
-out_sleep:
- wl1251_ps_elp_sleep(wl);
-
-out:
- mutex_unlock(&wl->mutex);
-}
-
static void wl1251_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct wl1251 *wl = hw->priv;
@@ -478,7 +451,6 @@ static void wl1251_op_stop(struct ieee80211_hw *hw)

cancel_work_sync(&wl->irq_work);
cancel_work_sync(&wl->tx_work);
- cancel_work_sync(&wl->filter_work);
cancel_delayed_work_sync(&wl->elp_work);

mutex_lock(&wl->mutex);
@@ -723,13 +695,6 @@ static void wl1251_op_configure_filter(struct ieee80211_hw *hw,
wl->rx_filter |= CFG_RX_CTL_EN;
if (*total & FIF_OTHER_BSS)
wl->rx_filter &= ~CFG_BSSID_FILTER_EN;
-
- /*
- * FIXME: workqueues need to be properly cancelled on stop(), for
- * now let's just disable changing the filter settings. They will
- * be updated any on config().
- */
- /* schedule_work(&wl->filter_work); */
}

/* HW encryption */
@@ -1390,7 +1355,6 @@ struct ieee80211_hw *wl1251_alloc_hw(void)

skb_queue_head_init(&wl->tx_queue);

- INIT_WORK(&wl->filter_work, wl1251_filter_work);
INIT_DELAYED_WORK(&wl->elp_work, wl1251_elp_work);
wl->channel = WL1251_DEFAULT_CHANNEL;
wl->scanning = false;
diff --git a/drivers/net/wireless/ti/wl1251/wl1251.h b/drivers/net/wireless/ti/wl1251/wl1251.h
index 9d8f581..fd02060 100644
--- a/drivers/net/wireless/ti/wl1251/wl1251.h
+++ b/drivers/net/wireless/ti/wl1251/wl1251.h
@@ -315,7 +315,6 @@ struct wl1251 {
bool tx_queue_stopped;

struct work_struct tx_work;
- struct work_struct filter_work;

/* Pending TX frames */
struct sk_buff *tx_frames[16];
--
1.7.0.4


2012-06-16 19:31:58

by Grazvydas Ignotas

[permalink] [raw]
Subject: [PATCH 2/3] wl1251: fix filtering support

This driver has a hack in cmd.c which effectively disables all filtering.
This seems to be triggering a firmware bug where it stops reporting any
rx packets after random time on some routers, which is eliminated (or at
least appears much more rarely) when filtering is on.
I have found that only BSSID filter needs to be disabled for association
to work, so disable only that instead of all filtering.

Signed-off-by: Grazvydas Ignotas <[email protected]>
---
drivers/net/wireless/ti/wl1251/cmd.c | 9 ---------
drivers/net/wireless/ti/wl1251/main.c | 6 ++++++
2 files changed, 6 insertions(+), 9 deletions(-)

diff --git a/drivers/net/wireless/ti/wl1251/cmd.c b/drivers/net/wireless/ti/wl1251/cmd.c
index d14d69d..6822b84 100644
--- a/drivers/net/wireless/ti/wl1251/cmd.c
+++ b/drivers/net/wireless/ti/wl1251/cmd.c
@@ -277,15 +277,6 @@ int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 channel,
join->rx_config_options = wl->rx_config;
join->rx_filter_options = wl->rx_filter;

- /*
- * FIXME: disable temporarily all filters because after commit
- * 9cef8737 "mac80211: fix managed mode BSSID handling" broke
- * association. The filter logic needs to be implemented properly
- * and once that is done, this hack can be removed.
- */
- join->rx_config_options = 0;
- join->rx_filter_options = WL1251_DEFAULT_RX_FILTER;
-
join->basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS |
RATE_MASK_5_5MBPS | RATE_MASK_11MBPS;

diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c
index ff60a7a..6094e3f 100644
--- a/drivers/net/wireless/ti/wl1251/main.c
+++ b/drivers/net/wireless/ti/wl1251/main.c
@@ -334,6 +334,12 @@ static int wl1251_join(struct wl1251 *wl, u8 bss_type, u8 channel,
if (ret < 0)
goto out;

+ /*
+ * Join command applies filters, and if we are not associated,
+ * BSSID filter must be disabled for association to work.
+ */
+ if (is_zero_ether_addr(wl->bssid))
+ wl->rx_config &= ~CFG_BSSID_FILTER_EN;

ret = wl1251_cmd_join(wl, bss_type, channel, beacon_interval,
dtim_period);
--
1.7.0.4