2011-08-25 09:43:23

by Arik Nemtsov

[permalink] [raw]
Subject: [PATCH 1/6] wl12xx: don't indicate up PS-filtered dummy packets

Dummy packets are currently only sent on the system_hlid link. The
system_hlid link should never be filtered for PS (as it is not
a STA link). Even so, for correctness, don't indicate dummy packets up.
The skb does not belong to mac80211 and as such does not contain a
correct skb->cb.

Signed-off-by: Arik Nemtsov <[email protected]>
---
drivers/net/wireless/wl12xx/ps.c | 8 ++++++--
drivers/net/wireless/wl12xx/tx.c | 2 +-
drivers/net/wireless/wl12xx/tx.h | 1 +
3 files changed, 8 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/ps.c
index 4b720b1..c15ebf2 100644
--- a/drivers/net/wireless/wl12xx/ps.c
+++ b/drivers/net/wireless/wl12xx/ps.c
@@ -199,15 +199,19 @@ static void wl1271_ps_filter_frames(struct wl1271 *wl, u8 hlid)
unsigned long flags;
int filtered[NUM_TX_QUEUES];

- /* filter all frames currently the low level queus for this hlid */
+ /* filter all frames currently in the low level queues for this hlid */
for (i = 0; i < NUM_TX_QUEUES; i++) {
filtered[i] = 0;
while ((skb = skb_dequeue(&wl->links[hlid].tx_queue[i]))) {
+ filtered[i]++;
+
+ if (WARN_ON(wl12xx_is_dummy_packet(wl, skb)))
+ continue;
+
info = IEEE80211_SKB_CB(skb);
info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
info->status.rates[0].idx = -1;
ieee80211_tx_status_ni(wl->hw, skb);
- filtered[i]++;
}
}

diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c
index 0f15785..eb98832 100644
--- a/drivers/net/wireless/wl12xx/tx.c
+++ b/drivers/net/wireless/wl12xx/tx.c
@@ -143,7 +143,7 @@ static void wl1271_tx_regulate_link(struct wl1271 *wl, u8 hlid)
wl1271_ps_link_start(wl, hlid, true);
}

-static bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb)
+bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb)
{
return wl->dummy_packet == skb;
}
diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/tx.h
index 7da35c0..1515f4a 100644
--- a/drivers/net/wireless/wl12xx/tx.h
+++ b/drivers/net/wireless/wl12xx/tx.h
@@ -213,5 +213,6 @@ u32 wl1271_tx_min_rate_get(struct wl1271 *wl);
u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct sk_buff *skb);
void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid);
void wl1271_handle_tx_low_watermark(struct wl1271 *wl);
+bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb);

#endif
--
1.7.4.1



2011-08-25 09:43:26

by Arik Nemtsov

[permalink] [raw]
Subject: [PATCH 3/6] wl12xx: support up to 8 stations in AP-mode

Change the max number of AP stations to 8, up from 5.

Signed-off-by: Arik Nemtsov <[email protected]>
---
drivers/net/wireless/wl12xx/wl12xx.h | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index 61a7c21..27961e2 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -234,14 +234,14 @@ struct wl1271_stats {
#define NUM_TX_QUEUES 4
#define NUM_RX_PKT_DESC 8

-#define AP_MAX_STATIONS 5
+#define AP_MAX_STATIONS 8

/* Broadcast and Global links + system link + links to stations */
/*
* TODO: when WL1271_AP_STA_HLID_START is no longer constant, change all
* the places that use this.
*/
-#define AP_MAX_LINKS (AP_MAX_STATIONS + 3)
+#define AP_MAX_LINKS (AP_MAX_STATIONS + WL1271_AP_STA_HLID_START)

/* FW status registers */
struct wl12xx_fw_status {
--
1.7.4.1


2011-08-25 09:43:31

by Arik Nemtsov

[permalink] [raw]
Subject: [PATCH 6/6] wl12xx: AP mode - clean BA and queue state in tx_reset

Reset the BA state of all connected stations and explicitly clear the
Tx queues. The latter is needed for clearing dummy packets from
tx_queue_count.

Signed-off-by: Arik Nemtsov <[email protected]>
---
drivers/net/wireless/wl12xx/main.c | 7 +++++--
drivers/net/wireless/wl12xx/tx.c | 7 ++++++-
drivers/net/wireless/wl12xx/tx.h | 3 +++
3 files changed, 14 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index 0778567..7027a7e 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -3723,11 +3723,14 @@ static int wl1271_allocate_sta(struct wl1271 *wl,
return 0;
}

-static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
+void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
{
int id = hlid - WL1271_AP_STA_HLID_START;

- if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
+ if (hlid < WL1271_AP_STA_HLID_START)
+ return;
+
+ if (!test_bit(id, wl->ap_hlid_map))
return;

clear_bit(id, wl->ap_hlid_map);
diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c
index 09c1083..a28c33d 100644
--- a/drivers/net/wireless/wl12xx/tx.c
+++ b/drivers/net/wireless/wl12xx/tx.c
@@ -893,6 +893,7 @@ void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
/* TX failure */
if (wl->bss_type == BSS_TYPE_AP_BSS) {
for (i = 0; i < AP_MAX_LINKS; i++) {
+ wl1271_free_sta(wl, i);
wl1271_tx_reset_link_queues(wl, i);
wl->links[i].allocated_pkts = 0;
wl->links[i].prev_freed_pkts = 0;
@@ -912,10 +913,14 @@ void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
ieee80211_tx_status_ni(wl->hw, skb);
}
}
- wl->tx_queue_count[i] = 0;
}
+
+ wl->ba_rx_bitmap = 0;
}

+ for (i = 0; i < NUM_TX_QUEUES; i++)
+ wl->tx_queue_count[i] = 0;
+
wl->stopped_queues_map = 0;

/*
diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/tx.h
index 1515f4a..b29775b 100644
--- a/drivers/net/wireless/wl12xx/tx.h
+++ b/drivers/net/wireless/wl12xx/tx.h
@@ -215,4 +215,7 @@ void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid);
void wl1271_handle_tx_low_watermark(struct wl1271 *wl);
bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb);

+/* from main.c */
+void wl1271_free_sta(struct wl1271 *wl, u8 hlid);
+
#endif
--
1.7.4.1


2011-08-25 09:43:28

by Arik Nemtsov

[permalink] [raw]
Subject: [PATCH 4/6] wl12xx: don't regulate links when a single STA is connected

When operating as AP track the number of connected stations. When a
single STA is connected don't regulate the PS status of the link.
Since this is the only STA connected, there's no point holding space in
FW for other links. This will speed up communications with a single
connected STA in PSM.

Signed-off-by: Arik Nemtsov <[email protected]>
---
drivers/net/wireless/wl12xx/main.c | 15 ++++++++++++---
drivers/net/wireless/wl12xx/tx.c | 7 +++++--
drivers/net/wireless/wl12xx/wl12xx.h | 3 +++
3 files changed, 20 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index 82f4408..0778567 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -757,13 +757,14 @@ static int wl1271_plt_init(struct wl1271 *wl)

static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_pkts)
{
- bool fw_ps;
+ bool fw_ps, single_sta;

/* only regulate station links */
if (hlid < WL1271_AP_STA_HLID_START)
return;

fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
+ single_sta = (wl->active_sta_count == 1);

/*
* Wake up from high level PS if the STA is asleep with too little
@@ -772,8 +773,12 @@ static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_pkts)
if (!fw_ps || tx_pkts < WL1271_PS_STA_MAX_PACKETS)
wl1271_ps_link_end(wl, hlid);

- /* Start high-level PS if the STA is asleep with enough blocks in FW */
- else if (fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
+ /*
+ * Start high-level PS if the STA is asleep with enough blocks in FW.
+ * Make an exception if this is the only connected station. In this
+ * case FW-memory congestion is not a problem.
+ */
+ else if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
wl1271_ps_link_start(wl, hlid, true);
}

@@ -2074,6 +2079,7 @@ deinit:
memset(wl->roles_map, 0, sizeof(wl->roles_map));
memset(wl->links_map, 0, sizeof(wl->links_map));
memset(wl->roc_map, 0, sizeof(wl->roc_map));
+ wl->active_sta_count = 0;

/* The system link is always allocated */
__set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
@@ -3713,6 +3719,7 @@ static int wl1271_allocate_sta(struct wl1271 *wl,
wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
*hlid = wl_sta->hlid;
memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
+ wl->active_sta_count++;
return 0;
}

@@ -3729,6 +3736,7 @@ static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
wl1271_tx_reset_link_queues(wl, hlid);
__clear_bit(hlid, &wl->ap_ps_map);
__clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
+ wl->active_sta_count--;
}

static int wl1271_op_sta_add(struct ieee80211_hw *hw,
@@ -4607,6 +4615,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
wl->session_counter = 0;
wl->ap_bcast_hlid = WL12XX_INVALID_LINK_ID;
wl->ap_global_hlid = WL12XX_INVALID_LINK_ID;
+ wl->active_sta_count = 0;
setup_timer(&wl->rx_streaming_timer, wl1271_rx_streaming_timer,
(unsigned long) wl);
wl->fwlog_size = 0;
diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c
index 572c6e6..09c1083 100644
--- a/drivers/net/wireless/wl12xx/tx.c
+++ b/drivers/net/wireless/wl12xx/tx.c
@@ -126,7 +126,7 @@ static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl,

static void wl1271_tx_regulate_link(struct wl1271 *wl, u8 hlid)
{
- bool fw_ps;
+ bool fw_ps, single_sta;
u8 tx_pkts;

/* only regulate station links */
@@ -140,12 +140,15 @@ static void wl1271_tx_regulate_link(struct wl1271 *wl, u8 hlid)

fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
tx_pkts = wl->links[hlid].allocated_pkts;
+ single_sta = (wl->active_sta_count == 1);

/*
* if in FW PS and there is enough data in FW we can put the link
* into high-level PS and clean out its TX queues.
+ * Make an exception if this is the only connected station. In this
+ * case FW-memory congestion is not a problem.
*/
- if (fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
+ if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
wl1271_ps_link_start(wl, hlid, true);
}

diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index 27961e2..b454b81 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -623,6 +623,9 @@ struct wl1271 {

/* number of currently active RX BA sessions */
int ba_rx_session_count;
+
+ /* AP-mode - number of currently connected stations */
+ int active_sta_count;
};

struct wl1271_station {
--
1.7.4.1


2011-08-25 09:43:24

by Arik Nemtsov

[permalink] [raw]
Subject: [PATCH 2/6] wl12xx: AP mode - don't regulate FW blocks for non-active STAs

Check a STA is associated before regulating its PS-status in mac80211.
Should never happen, so warn as a precaution.

Signed-off-by: Arik Nemtsov <[email protected]>
---
drivers/net/wireless/wl12xx/tx.c | 6 ++++++
1 files changed, 6 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c
index eb98832..572c6e6 100644
--- a/drivers/net/wireless/wl12xx/tx.c
+++ b/drivers/net/wireless/wl12xx/tx.c
@@ -30,6 +30,7 @@
#include "reg.h"
#include "ps.h"
#include "tx.h"
+#include "event.h"

static int wl1271_set_default_wep_key(struct wl1271 *wl, u8 id)
{
@@ -132,6 +133,11 @@ static void wl1271_tx_regulate_link(struct wl1271 *wl, u8 hlid)
if (hlid < WL1271_AP_STA_HLID_START)
return;

+ if (!wl1271_is_active_sta(wl, hlid)) {
+ WARN_ON(1);
+ return;
+ }
+
fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
tx_pkts = wl->links[hlid].allocated_pkts;

--
1.7.4.1


2011-08-25 10:05:30

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH 2/6] wl12xx: AP mode - don't regulate FW blocks for non-active STAs

Arik Nemtsov <[email protected]> writes:

> + if (!wl1271_is_active_sta(wl, hlid)) {
> + WARN_ON(1);
> + return;
> + }

I think this is neater:

if (WARN_ON(!wl1271_is_active_sta(wl, hlid))
return;

--
Kalle Valo

2011-08-25 09:43:30

by Arik Nemtsov

[permalink] [raw]
Subject: [PATCH 5/6] wl12xx: AP mode - enable the BA constraint event from the FW

Unblock the RX BA constraint event from firmware in AP mode as well.
This allows us to stop RX BA sessions when the FW requests it.

In addition refactor the handler for this event to make the flow
clearer.

Signed-off-by: Arik Nemtsov <[email protected]>
---
drivers/net/wireless/wl12xx/event.c | 39 +++++++++++++++++++++-------------
1 files changed, 24 insertions(+), 15 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/event.c b/drivers/net/wireless/wl12xx/event.c
index 0bd7b02..c73fe4c 100644
--- a/drivers/net/wireless/wl12xx/event.c
+++ b/drivers/net/wireless/wl12xx/event.c
@@ -171,19 +171,26 @@ static void wl1271_event_rssi_trigger(struct wl1271 *wl,
wl->last_rssi_event = event;
}

-static void wl1271_stop_ba_event(struct wl1271 *wl, u8 ba_allowed)
+static void wl1271_stop_ba_event(struct wl1271 *wl)
{
- /* Convert the value to bool */
- wl->ba_allowed = !!ba_allowed;
-
- /*
- * Return in case:
- * there are not BA open or the event indication is to allowed BA
- */
- if ((!wl->ba_rx_bitmap) || (wl->ba_allowed))
- return;
+ if (wl->bss_type != BSS_TYPE_AP_BSS) {
+ if (!wl->ba_rx_bitmap)
+ return;
+ ieee80211_stop_rx_ba_session(wl->vif, wl->ba_rx_bitmap,
+ wl->bssid);
+ } else {
+ int i;
+ struct wl1271_link *lnk;
+ for (i = WL1271_AP_STA_HLID_START; i < WL12XX_MAX_LINKS; i++) {
+ lnk = &wl->links[i];
+ if (!wl1271_is_active_sta(wl, i) || !lnk->ba_bitmap)
+ continue;

- ieee80211_stop_rx_ba_session(wl->vif, wl->ba_rx_bitmap, wl->bssid);
+ ieee80211_stop_rx_ba_session(wl->vif,
+ lnk->ba_bitmap,
+ lnk->addr);
+ }
+ }
}

static void wl12xx_event_soft_gemini_sense(struct wl1271 *wl,
@@ -283,12 +290,14 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
wl1271_event_rssi_trigger(wl, mbox);
}

- if ((vector & BA_SESSION_RX_CONSTRAINT_EVENT_ID) && !is_ap) {
+ if ((vector & BA_SESSION_RX_CONSTRAINT_EVENT_ID)) {
wl1271_debug(DEBUG_EVENT, "BA_SESSION_RX_CONSTRAINT_EVENT_ID. "
"ba_allowed = 0x%x", mbox->rx_ba_allowed);

- if (wl->vif)
- wl1271_stop_ba_event(wl, mbox->rx_ba_allowed);
+ wl->ba_allowed = !!mbox->rx_ba_allowed;
+
+ if (wl->vif && !wl->ba_allowed)
+ wl1271_stop_ba_event(wl);
}

if ((vector & DUMMY_PACKET_EVENT_ID)) {
--
1.7.4.1


2011-09-14 09:56:34

by Luciano Coelho

[permalink] [raw]
Subject: Re: [PATCH 1/6] wl12xx: don't indicate up PS-filtered dummy packets

On Thu, 2011-08-25 at 12:43 +0300, Arik Nemtsov wrote:
> Dummy packets are currently only sent on the system_hlid link. The
> system_hlid link should never be filtered for PS (as it is not
> a STA link). Even so, for correctness, don't indicate dummy packets up.
> The skb does not belong to mac80211 and as such does not contain a
> correct skb->cb.
>
> Signed-off-by: Arik Nemtsov <[email protected]>
> ---

Applied this patchset, thanks!

--
Cheers,
Luca.


2011-09-14 09:56:07

by Luciano Coelho

[permalink] [raw]
Subject: Re: [PATCH 2/6] wl12xx: AP mode - don't regulate FW blocks for non-active STAs

On Wed, 2011-09-14 at 12:44 +0300, Arik Nemtsov wrote:
> On Thu, Aug 25, 2011 at 13:05, Kalle Valo <[email protected]> wrote:
> > Arik Nemtsov <[email protected]> writes:
> >
> >> + if (!wl1271_is_active_sta(wl, hlid)) {
> >> + WARN_ON(1);
> >> + return;
> >> + }
> >
> > I think this is neater:
> >
> > if (WARN_ON(!wl1271_is_active_sta(wl, hlid))
> > return;
>
> (Sorry for the late response)
>
> It does look nicer. Luca - do you mind changing it before merging?

Done, and thanks for giving me more work to do! Oh, well, I deserved
it. :P

--
Cheers,
Luca.


2011-09-14 09:44:24

by Arik Nemtsov

[permalink] [raw]
Subject: Re: [PATCH 2/6] wl12xx: AP mode - don't regulate FW blocks for non-active STAs

On Thu, Aug 25, 2011 at 13:05, Kalle Valo <[email protected]> wrote:
> Arik Nemtsov <[email protected]> writes:
>
>> + ? ? if (!wl1271_is_active_sta(wl, hlid)) {
>> + ? ? ? ? ? ? WARN_ON(1);
>> + ? ? ? ? ? ? return;
>> + ? ? }
>
> I think this is neater:
>
> if (WARN_ON(!wl1271_is_active_sta(wl, hlid))
> ? ? ? ?return;

(Sorry for the late response)

It does look nicer. Luca - do you mind changing it before merging?

Arik