2011-08-09 09:13:31

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 00/40] wl12xx: move to wl12xx-fw-3

The new wl12xx fw (ver 7.3.0.0.75) had some major api changes.
The main change was the addition of multi-role concept, which
will later allow using multiple vifs concurrently.

Consequently, this design change caused api changes for most
of the api commands, as a new role_id had to be added.

This patchset migrates the fw to use the new fw api (a new
fw filename is used, as there is no backward compatability
with older firmwares).

Additional patchsets will follow, with further bugfixes
and new features (e.g. p2p support).

Arik Nemtsov (17):
wl12xx: Revert "wl12xx: schedule TX packets according to FW
occupancy"
wl12xx: Use a single fw for both STA and AP roles
wl12xx: use 1 spare block in all cases
wl12xx: handle dummy packet event also in ap mode
wl12xx: fix session counter
wl12xx: use dynamic hlids for AP-mode
wl12xx: re-enable block ack session support
wl12xx: AP-mode - set STA HT capabilities when adding a STA
wl12xx: AP-mode - configure STA HT rates on join
wl12xx: AP-mode - configure HT rate support to the FW
wl12xx: track freed packets in FW by AC
wl12xx: schedule TX packets according to FW packet occupancy
wl12xx: handle wrap-around overflow in released Tx blocks FW counter
wl12xx: enable AP advanced functionality
wl12xx: set the AP-started flag only after setting keys
wl12xx: AP-mode - prevent Tx to stale/invalid stations
wl12xx: fix tx_queue_count spurious increment

Eliad Peller (23):
wl12xx: temporarily disable 11n and advanced ap functions
wl12xx: remove rx filtering stuff
wl12xx: wl12xx-fw-3 - Update fw status struct
wl12xx: wl12xx-fw-3 - update acx commands
wl12xx: wl12xx-fw-3 - update commands & events
wl12xx: enable/disable role on interface add/remove
wl12xx: add device role commands
wl12xx: wl12xx-fw-3 - update scan cmd api
wl12xx: wl12xx-fw-3 - rx/tx changes
wl12xx: wl12xx-fw-3 - change max/default template size
wl12xx: use wl1271_acx_beacon_filter_opt for both sta and ap
wl12xx: add set_rate_mgmt_params acx
wl12xx: add system_hlid
wl12xx: add ROC/CROC commands
wl12xx: replace dummy_join with ROC/CROC commands
wl12xx: update BT coex configuration params
wl12xx: call wl1271_cmd_set_peer_state() in AP mode
wl12xx: don't remove key if hlid was already deleted
wl12xx: add wl1271_cmd_role_start_ibss()
wl12xx: support IBSS vif type
wl12xx: use ap_bcast_hlid for recorded keys
wl12xx: don't remove key if hlid was already deleted
wl12xx: don't wait for disconnection event

drivers/net/wireless/wl12xx/acx.c | 325 ++++------
drivers/net/wireless/wl12xx/acx.h | 395 +++++--------
drivers/net/wireless/wl12xx/boot.c | 16 +-
drivers/net/wireless/wl12xx/cmd.c | 802 ++++++++++++++++++-------
drivers/net/wireless/wl12xx/cmd.h | 337 ++++++-----
drivers/net/wireless/wl12xx/conf.h | 345 ++++-------
drivers/net/wireless/wl12xx/debugfs.c | 17 +-
drivers/net/wireless/wl12xx/event.c | 6 +-
drivers/net/wireless/wl12xx/event.h | 83 +--
drivers/net/wireless/wl12xx/init.c | 96 +--
drivers/net/wireless/wl12xx/io.h | 1 -
drivers/net/wireless/wl12xx/main.c | 915 ++++++++++++++++-----------
drivers/net/wireless/wl12xx/ps.c | 4 +-
drivers/net/wireless/wl12xx/reg.h | 75 ---
drivers/net/wireless/wl12xx/rx.c | 17 +-
drivers/net/wireless/wl12xx/rx.h | 10 +-
drivers/net/wireless/wl12xx/scan.c | 38 +-
drivers/net/wireless/wl12xx/scan.h | 25 +-
drivers/net/wireless/wl12xx/sdio.c | 2 -
drivers/net/wireless/wl12xx/spi.c | 2 -
drivers/net/wireless/wl12xx/tx.c | 107 ++--
drivers/net/wireless/wl12xx/tx.h | 16 +-
drivers/net/wireless/wl12xx/wl12xx.h | 148 +++---
drivers/net/wireless/wl12xx/wl12xx_80211.h | 25 -
24 files changed, 2002 insertions(+), 1805 deletions(-)

--
1.7.6.401.g6a319



2011-08-09 09:13:37

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 03/40] wl12xx: use 1 spare block in all cases

From: Arik Nemtsov <[email protected]>

Remove support for firmwares that require 2 spare blocks for packet TX.

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

diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c
index 0696aed..c67340f 100644
--- a/drivers/net/wireless/wl12xx/tx.c
+++ b/drivers/net/wireless/wl12xx/tx.c
@@ -166,18 +166,15 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
{
struct wl1271_tx_hw_descr *desc;
u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra;
u32 len;
u32 total_blocks;
int id, ret = -EBUSY;
- u32 spare_blocks;

- if (unlikely(wl->quirks & WL12XX_QUIRK_USE_2_SPARE_BLOCKS))
- spare_blocks = 2;
- else
- spare_blocks = 1;
+ /* we use 1 spare block */
+ u32 spare_blocks = 1;

if (buf_offset + total_len > WL1271_AGGR_BUFFER_SIZE)
return -EAGAIN;

/* allocate free identifier for the packet */
id = wl1271_alloc_tx_id(wl, skb);
--
1.7.6.401.g6a319


2011-08-09 12:03:08

by Luciano Coelho

[permalink] [raw]
Subject: Re: [PATCH 03/40] wl12xx: use 1 spare block in all cases

On Tue, 2011-08-09 at 12:13 +0300, Eliad Peller wrote:
> From: Arik Nemtsov <[email protected]>
>
> Remove support for firmwares that require 2 spare blocks for packet TX.
>
> Signed-off-by: Arik Nemtsov <[email protected]>
> Signed-off-by: Eliad Peller <[email protected]>
> ---
> drivers/net/wireless/wl12xx/tx.c | 7 ++-----
> 1 files changed, 2 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c
> index 0696aed..c67340f 100644
> --- a/drivers/net/wireless/wl12xx/tx.c
> +++ b/drivers/net/wireless/wl12xx/tx.c
> @@ -166,18 +166,15 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
> {
> struct wl1271_tx_hw_descr *desc;
> u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra;
> u32 len;
> u32 total_blocks;
> int id, ret = -EBUSY;
> - u32 spare_blocks;
>
> - if (unlikely(wl->quirks & WL12XX_QUIRK_USE_2_SPARE_BLOCKS))
> - spare_blocks = 2;
> - else
> - spare_blocks = 1;
> + /* we use 1 spare block */
> + u32 spare_blocks = 1;
>
> if (buf_offset + total_len > WL1271_AGGR_BUFFER_SIZE)
> return -EAGAIN;
>
> /* allocate free identifier for the packet */
> id = wl1271_alloc_tx_id(wl, skb);

Please, remove the quirk completely as it is not used anymore after this
patch.

--
Cheers,
Luca.


2011-08-09 09:14:37

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 35/40] wl12xx: handle wrap-around overflow in released Tx blocks FW counter

From: Arik Nemtsov <[email protected]>

When the FW Tx released blocks counter wraps around, we should correct
our calculation of released blocks. Otherwise we add a large negative
figure to our driver freed blocks counter

Signed-off-by: Arik Nemtsov <[email protected]>
Signed-off-by: Eliad Peller <[email protected]>
---
drivers/net/wireless/wl12xx/main.c | 11 +++++++++--
1 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index 755415a..c8e9ba6 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -830,14 +830,21 @@ static void wl1271_fw_status(struct wl1271 *wl,
(status->tx_released_pkts[i] -
wl->tx_pkts_freed[i] + 256) % 256;

wl->tx_pkts_freed[i] = status->tx_released_pkts[i];
}

- freed_blocks = le32_to_cpu(status->total_released_blks) -
- wl->tx_blocks_freed;
+ /* prevent wrap-around in total blocks counter */
+ if (likely(wl->tx_blocks_freed <=
+ le32_to_cpu(status->total_released_blks)))
+ freed_blocks = le32_to_cpu(status->total_released_blks) -
+ wl->tx_blocks_freed;
+ else
+ freed_blocks = 0x100000000LL - wl->tx_blocks_freed +
+ le32_to_cpu(status->total_released_blks);
+
wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks);

wl->tx_allocated_blocks -= freed_blocks;

avail = le32_to_cpu(status->tx_total) - wl->tx_allocated_blocks;

--
1.7.6.401.g6a319


2011-08-10 09:53:34

by Eliad Peller

[permalink] [raw]
Subject: Re: [PATCH 08/40] wl12xx: wl12xx-fw-3 - update commands & events

hi Luca,

thanks for your (ongoing) reviews.
i'll apply your comments in the next version.
anyway, regarding some of non-trivial comments:

On Wed, Aug 10, 2011 at 12:19 PM, Luciano Coelho <[email protected]> wrote:
> On Tue, 2011-08-09 at 12:13 +0300, Eliad Peller wrote:
>> ? ? ? /* unmask required mbox events ?*/
>> ? ? ? wl->event_mask = BSS_LOSE_EVENT_ID |
>> ? ? ? ? ? ? ? SCAN_COMPLETE_EVENT_ID |
>> ? ? ? ? ? ? ? PS_REPORT_EVENT_ID |
>> - ? ? ? ? ? ? JOIN_EVENT_COMPLETE_ID |
>> ? ? ? ? ? ? ? DISCONNECT_EVENT_COMPLETE_ID |
>> ? ? ? ? ? ? ? RSSI_SNR_TRIGGER_0_EVENT_ID |
>> ? ? ? ? ? ? ? PSPOLL_DELIVERY_FAILURE_EVENT_ID |
>> ? ? ? ? ? ? ? SOFT_GEMINI_SENSE_EVENT_ID |
>> ? ? ? ? ? ? ? PERIODIC_SCAN_REPORT_EVENT_ID |
>> - ? ? ? ? ? ? PERIODIC_SCAN_COMPLETE_EVENT_ID;
>> + ? ? ? ? ? ? PERIODIC_SCAN_COMPLETE_EVENT_ID |
>> + ? ? ? ? ? ? DUMMY_PACKET_EVENT_ID |
>> + ? ? ? ? ? ? PEER_REMOVE_COMPLETE_EVENT_ID |
>> + ? ? ? ? ? ? BA_SESSION_RX_CONSTRAINT_EVENT_ID |
>> + ? ? ? ? ? ? REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID;
>>
>> ? ? ? if (wl->bss_type == BSS_TYPE_AP_BSS)
>> - ? ? ? ? ? ? wl->event_mask |= STA_REMOVE_COMPLETE_EVENT_ID |
>> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? INACTIVE_STA_EVENT_ID |
>> + ? ? ? ? ? ? wl->event_mask |= INACTIVE_STA_EVENT_ID |
>> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? MAX_TX_RETRY_EVENT_ID;
>
> Do we really need to mask this stuff separately?
>
we thought of masking the needed events according to the active role.
anyway, i since there is no overlapping, and in the future there will
be multiple roles, i guess we can just unmask them all together.


>> -int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type)
>> +int wl1271_cmd_role_enable(struct wl1271 *wl, u8 role_type, u8 *role_id)
>
> s/wl1271_cmd_role_enable/wl12xx_cmd_role_enable/
>
> Same thing for wl1271_cmd_role_disable and all the other functions whose
> declaration changed.
>
> I was thinking that we could use the role_id directly from the wl struct
> here, but then I changed my mind, because I think it's not good that the
> cmd functions themselves change the wl struct. ?At some point we need to
> split the HW-related part of wl (phy) from the context-related elements

well, that exactly our plan. after applying the all the pending series
we'll start splitting up wl into global and per-vif data, in order to
support multiple vifs.

> (vif). ?For most of the cases, if not all, the cmd functions only use
> the HW-related elements.
>
every command that takes role_id as param is basically per-vif, so i
guess you're wrong here :)

> Anyway, this small detour just supports the usage of role_id as a
> separate argument instead of taking it from wl. ;)
>
right :)

>> +
>> + ? ? ? memcpy(cmd->mac_address, wl->mac_addr, ETH_ALEN);
>
> To keep aligned with my comment about phy vs. vif context, I think it
> would be nicer to pass the MAC address as an argument to this function
> as well. ?When we implement multirole, we will need different MAC
> addresses for each role, so we can't really use the value from wl.
>
you are right, but let's leave it for a later stage.
(i have some patch that replaces all the wl->mac_addr to vif->addr)

>> +static int wl1271_allocate_link(struct wl1271 *wl, u8 *hlid)
>> +{
>> + ? ? u8 alloced = find_first_zero_bit(wl->links_map, WL1271_MAX_LINKS);
>
> This is *very* netpicky, but could you call this variable "link" or
> something instead of "alloced"? Alloced is annoying to read because of
> the missing apostrophe! :P
>
whatever :)

>> +int wl1271_cmd_role_stop_sta(struct wl1271 *wl)
>> +{

>> +
>> + ? ? cmd->role_id = wl->role_id;
>> + ? ? cmd->disc_type = WL1271_DISC_IMMEDIATE;
>> + ? ? cmd->reason = cpu_to_le16(1); /* STATUS_UNSPECIFIED */
>
> Isn't there a more reasonable reason? :) In any case, this should at
> least be in an enum together with the other possible reasons instead of
> hardcoded here.
>
in fact, i think it has meaning only if we configure the disassoc
template, so we can just delete it.


again, thanks for your reviews.
i'll just apply all the required changes instead of ACKing each one :)

Eliad.

2011-08-09 09:14:13

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 22/40] wl12xx: use dynamic hlids for AP-mode

From: Arik Nemtsov <[email protected]>

Using hlid=0 in AP mode is a bug. Dynamically allocate HLIDs.

Set the "first sta hlid" as 3. This will have to be changed
when multiple vifs will be supported.

Signed-off-by: Arik Nemtsov <[email protected]>
Signed-off-by: Eliad Peller <[email protected]>
---
drivers/net/wireless/wl12xx/cmd.c | 27 +++++++++++++++++++++++----
drivers/net/wireless/wl12xx/main.c | 9 +++++++--
drivers/net/wireless/wl12xx/tx.c | 17 ++++++-----------
drivers/net/wireless/wl12xx/wl12xx.h | 13 ++++++++++---
4 files changed, 46 insertions(+), 20 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c
index 3bbee10..6ef9d13 100644
--- a/drivers/net/wireless/wl12xx/cmd.c
+++ b/drivers/net/wireless/wl12xx/cmd.c
@@ -679,17 +679,25 @@ int wl1271_cmd_role_start_ap(struct wl1271 *wl)
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
ret = -ENOMEM;
goto out;
}

+ ret = wl1271_allocate_link(wl, &wl->ap_global_hlid);
+ if (ret < 0)
+ goto out_free;
+
+ ret = wl1271_allocate_link(wl, &wl->ap_bcast_hlid);
+ if (ret < 0)
+ goto out_free_global;
+
cmd->role_id = wl->role_id;
cmd->ap.aging_period = cpu_to_le16(wl->conf.tx.ap_aging_period);
cmd->ap.bss_index = WL1271_AP_BSS_INDEX;
- cmd->ap.global_hlid = WL1271_AP_GLOBAL_HLID;
- cmd->ap.broadcast_hlid = WL1271_AP_BROADCAST_HLID;
+ cmd->ap.global_hlid = wl->ap_global_hlid;
+ cmd->ap.broadcast_hlid = wl->ap_bcast_hlid;
cmd->ap.basic_rate_set = cpu_to_le32(wl->basic_rate_set);
cmd->ap.beacon_interval = cpu_to_le16(wl->beacon_int);
cmd->ap.dtim_interval = bss_conf->dtim_period;
cmd->ap.beacon_expiry = WL1271_AP_DEF_BEACON_EXP;
cmd->channel = wl->channel;
cmd->ap.ssid_len = wl->ssid_len;
@@ -710,15 +718,23 @@ int wl1271_cmd_role_start_ap(struct wl1271 *wl)
break;
}

ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0);
if (ret < 0) {
wl1271_error("failed to initiate cmd start bss");
- goto out_free;
+ goto out_free_bcast;
}

+ goto out_free;
+
+out_free_bcast:
+ wl1271_free_link(wl, &wl->ap_bcast_hlid);
+
+out_free_global:
+ wl1271_free_link(wl, &wl->ap_global_hlid);
+
out_free:
kfree(cmd);

out:
return ret;
}
@@ -741,12 +757,15 @@ int wl1271_cmd_role_stop_ap(struct wl1271 *wl)
ret = wl1271_cmd_send(wl, CMD_ROLE_STOP, cmd, sizeof(*cmd), 0);
if (ret < 0) {
wl1271_error("failed to initiate cmd role ap stop");
goto out_free;
}

+ wl1271_free_link(wl, &wl->ap_bcast_hlid);
+ wl1271_free_link(wl, &wl->ap_global_hlid);
+
out_free:
kfree(cmd);

out:
return ret;
}
@@ -1250,13 +1269,13 @@ int wl1271_cmd_set_ap_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
u8 lid_type;

cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd)
return -ENOMEM;

- if (hlid == WL1271_AP_BROADCAST_HLID) {
+ if (hlid == wl->ap_bcast_hlid) {
if (key_type == KEY_WEP)
lid_type = WEP_DEFAULT_LID_TYPE;
else
lid_type = BROADCAST_LID_TYPE;
} else {
lid_type = UNICAST_LID_TYPE;
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index ea4e89f..994a26d 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -1950,14 +1950,17 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
wl1271_cmd_role_disable(wl, &wl->dev_role_id);
wl1271_cmd_role_disable(wl, &wl->role_id);

wl1271_ps_elp_sleep(wl);
}

+ /* clear all hlids (except system_hlid) */
wl->sta_hlid = WL1271_INVALID_LINK_ID;
wl->dev_hlid = WL1271_INVALID_LINK_ID;
+ wl->ap_bcast_hlid = WL1271_INVALID_LINK_ID;
+ wl->ap_global_hlid = WL1271_INVALID_LINK_ID;

/*
* this must be before the cancel_work calls below, so that the work
* functions don't perform further work.
*/
wl->state = WL1271_STATE_OFF;
@@ -2504,13 +2507,13 @@ static int wl1271_ap_init_hwenc(struct wl1271 *wl)
if (key->key_type == KEY_WEP)
wep_key_added = true;
}

if (wep_key_added) {
ret = wl1271_cmd_set_default_wep_key(wl, wl->default_key,
- WL1271_AP_BROADCAST_HLID);
+ wl->ap_bcast_hlid);
if (ret < 0)
goto out;
}

out:
wl1271_free_ap_keys(wl);
@@ -2529,13 +2532,13 @@ static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
u8 hlid;

if (sta) {
wl_sta = (struct wl1271_station *)sta->drv_priv;
hlid = wl_sta->hlid;
} else {
- hlid = WL1271_AP_BROADCAST_HLID;
+ hlid = wl->ap_bcast_hlid;
}

if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
/*
* We do not support removing keys after AP shutdown.
* Pretend we do to make mac80211 happy.
@@ -4415,12 +4418,14 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
wl->role_id = WL1271_INVALID_ROLE_ID;
wl->system_hlid = WL1271_SYSTEM_HLID;
wl->sta_hlid = WL1271_INVALID_LINK_ID;
wl->dev_role_id = WL1271_INVALID_ROLE_ID;
wl->dev_hlid = WL1271_INVALID_LINK_ID;
wl->session_counter = 0;
+ wl->ap_bcast_hlid = WL1271_INVALID_LINK_ID;
+ wl->ap_global_hlid = WL1271_INVALID_LINK_ID;
setup_timer(&wl->rx_streaming_timer, wl1271_rx_streaming_timer,
(unsigned long) wl);
wl->fwlog_size = 0;
init_waitqueue_head(&wl->fwlog_waitq);

memset(wl->links_map, 0, sizeof(wl->links_map));
diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c
index 4e1c655..d99922c 100644
--- a/drivers/net/wireless/wl12xx/tx.c
+++ b/drivers/net/wireless/wl12xx/tx.c
@@ -35,13 +35,13 @@ static int wl1271_set_default_wep_key(struct wl1271 *wl, u8 id)
{
int ret;
bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);

if (is_ap)
ret = wl1271_cmd_set_default_wep_key(wl, id,
- WL1271_AP_BROADCAST_HLID);
+ wl->ap_bcast_hlid);
else
ret = wl1271_cmd_set_default_wep_key(wl, id, wl->sta_hlid);

if (ret < 0)
return ret;

@@ -160,15 +160,15 @@ u8 wl1271_tx_get_hlid(struct wl1271 *wl, struct sk_buff *skb)

if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags))
return wl->system_hlid;

hdr = (struct ieee80211_hdr *)skb->data;
if (ieee80211_is_mgmt(hdr->frame_control))
- return WL1271_AP_GLOBAL_HLID;
+ return wl->ap_global_hlid;
else
- return WL1271_AP_BROADCAST_HLID;
+ return wl->ap_bcast_hlid;
}
}

static unsigned int wl12xx_calc_packet_alignment(struct wl1271 *wl,
unsigned int packet_length)
{
@@ -300,23 +300,18 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
basic rates */
if (control->control.sta)
rate_idx = ACX_TX_AP_FULL_RATE;
else
rate_idx = ACX_TX_BASIC_RATE;
} else {
- switch (hlid) {
- case WL1271_AP_GLOBAL_HLID:
+ if (hlid == wl->ap_global_hlid)
rate_idx = ACX_TX_AP_MODE_MGMT_RATE;
- break;
- case WL1271_AP_BROADCAST_HLID:
+ else if (hlid == wl->ap_bcast_hlid)
rate_idx = ACX_TX_AP_MODE_BCST_RATE;
- break;
- default:
+ else
rate_idx = ac;
- break;
- }
}

tx_attr |= rate_idx << TX_HW_ATTR_OFST_RATE_POLICY;
desc->reserved = 0;

aligned_len = wl12xx_calc_packet_alignment(wl, skb->len);
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index 37b1d6b..8dba44d 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -138,16 +138,21 @@ extern u32 wl12xx_debug_level;
#define WL1271_DEFAULT_DTIM_PERIOD 1

#define WL1271_MAX_ROLES 4
#define WL1271_MAX_LINKS 8
#define WL1271_INVALID_ROLE_ID 0xff
#define WL1271_INVALID_LINK_ID 0xff
+
+/* Defined by FW as 0. Will not be freed or allocated. */
#define WL1271_SYSTEM_HLID 0
-#define WL1271_AP_GLOBAL_HLID 0
-#define WL1271_AP_BROADCAST_HLID 1
-#define WL1271_AP_STA_HLID_START 2
+
+/*
+ * TODO: we currently don't support multirole. remove
+ * this constant from the code when we do.
+ */
+#define WL1271_AP_STA_HLID_START 3

/*
* When in AP-mode, we allow (at least) this number of mem-blocks
* to be transmitted to FW for a STA in PS-mode. Only when packets are
* present in the FW buffers it will wake the sleeping STA. We want to put
* enough packets for the driver to transmit all of its buffered data before
@@ -396,12 +401,14 @@ struct wl1271 {
int channel;
u8 role_id;
u8 dev_role_id;
u8 system_hlid;
u8 sta_hlid;
u8 dev_hlid;
+ u8 ap_global_hlid;
+ u8 ap_bcast_hlid;

unsigned long links_map[BITS_TO_LONGS(WL1271_MAX_LINKS)];
unsigned long roles_map[BITS_TO_LONGS(WL1271_MAX_ROLES)];
unsigned long roc_map[BITS_TO_LONGS(WL1271_MAX_ROLES)];

struct wl1271_acx_mem_map *target_mem_map;
--
1.7.6.401.g6a319


2011-08-09 09:14:33

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 33/40] wl12xx: track freed packets in FW by AC

From: Arik Nemtsov <[email protected]>

Track the number of freed packets in each AC when receiving an interrupt
from the FW. This paves the way for tracking allocated packets per AC.

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

diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index b223c27..3bfd772 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -810,22 +810,32 @@ static void wl1271_irq_update_links_status(struct wl1271 *wl,
static void wl1271_fw_status(struct wl1271 *wl,
struct wl1271_fw_status *status)
{
struct timespec ts;
u32 old_tx_blk_count = wl->tx_blocks_available;
int avail, freed_blocks;
+ int i;

wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);

wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
"drv_rx_counter = %d, tx_results_counter = %d)",
status->intr,
status->fw_rx_counter,
status->drv_rx_counter,
status->tx_results_counter);

+ for (i = 0; i < NUM_TX_QUEUES; i++) {
+ /* prevent wrap-around in freed-packets counter */
+ wl->tx_allocated_pkts -=
+ (status->tx_released_pkts[i] -
+ wl->tx_pkts_freed[i] + 256) % 256;
+
+ wl->tx_pkts_freed[i] = status->tx_released_pkts[i];
+ }
+
freed_blocks = le32_to_cpu(status->total_released_blks) -
wl->tx_blocks_freed;
wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks);

wl->tx_allocated_blocks -= freed_blocks;

@@ -1913,13 +1923,13 @@ out:
return ret;
}

static void __wl1271_op_remove_interface(struct wl1271 *wl,
bool reset_tx_queues)
{
- int ret;
+ int ret, i;

wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");

/* because of hardware recovery, we may get here twice */
if (wl->state != WL1271_STATE_ON)
return;
@@ -2027,12 +2037,16 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
* get executed before all these vars have been reset.
*/
wl->flags = 0;

wl->tx_blocks_freed = 0;

+ wl->tx_allocated_pkts = 0;
+ for (i = 0; i < NUM_TX_QUEUES; i++)
+ wl->tx_pkts_freed[i] = 0;
+
wl1271_debugfs_reset(wl);

kfree(wl->fw_status);
wl->fw_status = NULL;
kfree(wl->tx_res_if);
wl->tx_res_if = NULL;
diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c
index 52a9ae9..4a40bc4 100644
--- a/drivers/net/wireless/wl12xx/tx.c
+++ b/drivers/net/wireless/wl12xx/tx.c
@@ -219,12 +219,14 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,

desc->id = id;

wl->tx_blocks_available -= total_blocks;
wl->tx_allocated_blocks += total_blocks;

+ wl->tx_allocated_pkts++;
+
if (wl->bss_type == BSS_TYPE_AP_BSS)
wl->links[hlid].allocated_blks += total_blocks;

ret = 0;

wl1271_debug(DEBUG_TX,
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index dfe08e5..3e2e0b3 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -265,14 +265,14 @@ struct wl1271_fw_status {
/* Cumulative counter of total released mem blocks since FW-reset */
__le32 total_released_blks;

/* Size (in Memory Blocks) of TX pool */
__le32 tx_total;

- /* Cumulative counter of released mem-blocks per AC */
- u8 tx_released_blks[NUM_TX_QUEUES];
+ /* Cumulative counter of released packets per AC */
+ u8 tx_released_pkts[NUM_TX_QUEUES];

/* Cumulative counter of freed MBs per HLID */
u8 tx_lnk_free_blks[WL1271_MAX_LINKS];

/* Cumulative counter of released Voice memory blocks */
u8 tx_voice_released_blks;
@@ -420,12 +420,16 @@ struct wl1271 {
/* Accounting for allocated / available TX blocks on HW */
u32 tx_blocks_freed;
u32 tx_blocks_available;
u32 tx_allocated_blocks;
u32 tx_results_count;

+ /* Accounting for allocated / available Tx packets in HW */
+ u32 tx_pkts_freed[NUM_TX_QUEUES];
+ u32 tx_allocated_pkts;
+
/* Transmitted TX packets counter for chipset interface */
u32 tx_packets_count;

/* Time-offset between host and chipset clocks */
s64 time_offset;

--
1.7.6.401.g6a319


2011-08-10 20:30:53

by Luciano Coelho

[permalink] [raw]
Subject: Re: [PATCH 30/40] wl12xx: AP-mode - configure HT rate support to the FW

On Tue, 2011-08-09 at 12:13 +0300, Eliad Peller wrote:
> From: Arik Nemtsov <[email protected]>
>
> Unconditionally configure HT rate support to the FW on all ACs
> when starting the AP.
>
> When 11n support is disabled by usermode (hostapd), each STA joining
> the AP will appear as a non-HT STA. This will stop us from accidentally
> transmitting using MCS rates.

Can we really trust this? I'd rather make sure we don't do anything
wrong in the driver itself.

Or is all this actually handled in userspace? I'm not very familiar with
how AP works, but is there any risk that someone tells us not to use 11n
but still don't change the STAs so that they appear as non-HT?

--
Cheers,
Luca.


2011-08-10 10:27:45

by Luciano Coelho

[permalink] [raw]
Subject: Re: [PATCH 08/40] wl12xx: wl12xx-fw-3 - update commands & events

On Wed, 2011-08-10 at 13:24 +0300, Eliad Peller wrote:
> On Wed, Aug 10, 2011 at 12:19 PM, Luciano Coelho <[email protected]> wrote:
> > On Tue, 2011-08-09 at 12:13 +0300, Eliad Peller wrote:
> >> +enum wl1271_cmd_lid_key_type {
> >> + UNICAST_LID_TYPE = 0,
> >> + BROADCAST_LID_TYPE = 1,
> >> + WEP_DEFAULT_LID_TYPE = 2
> >> +};
> >
> > Doesn't LID_TYPE_UNICAST, LID_TYPE_BROADCAST and so on look better?
> >
> it does, but i didn't touch this struct (it wasn't in the context diff
> expected, so it looks like it was deleted and re-added), and i should
> avoid adding more stuff (changing all the existing uses of this enum)
> to this already-too-big patch.

Right, right. I didn't realize that this was actually moved, not added
here.

--
Cheers,
Luca.


2011-08-09 09:14:11

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 20/40] wl12xx: update BT coex configuration params

The BT coex params api have been changed.
Update it, and init coex for both sta and ap.

Signed-off-by: Eliad Peller <[email protected]>
---
drivers/net/wireless/wl12xx/acx.c | 40 +----
drivers/net/wireless/wl12xx/acx.h | 16 +--
drivers/net/wireless/wl12xx/conf.h | 314 ++++++++++++------------------------
drivers/net/wireless/wl12xx/init.c | 10 +-
drivers/net/wireless/wl12xx/main.c | 165 +++++++------------
5 files changed, 175 insertions(+), 370 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c
index bb2e4fc..6885568 100644
--- a/drivers/net/wireless/wl12xx/acx.c
+++ b/drivers/net/wireless/wl12xx/acx.c
@@ -525,59 +525,29 @@ int wl1271_acx_sg_enable(struct wl1271 *wl, bool enable)

out:
kfree(pta);
return ret;
}

-int wl1271_acx_sta_sg_cfg(struct wl1271 *wl)
+int wl1271_acx_sg_cfg(struct wl1271 *wl)
{
- struct acx_sta_bt_wlan_coex_param *param;
+ struct acx_bt_wlan_coex_param *param;
struct conf_sg_settings *c = &wl->conf.sg;
int i, ret;

- wl1271_debug(DEBUG_ACX, "acx sg sta cfg");
+ wl1271_debug(DEBUG_ACX, "acx sg cfg");

param = kzalloc(sizeof(*param), GFP_KERNEL);
if (!param) {
ret = -ENOMEM;
goto out;
}

/* BT-WLAN coext parameters */
- for (i = 0; i < CONF_SG_STA_PARAMS_MAX; i++)
- param->params[i] = cpu_to_le32(c->sta_params[i]);
- param->param_idx = CONF_SG_PARAMS_ALL;
-
- ret = wl1271_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param));
- if (ret < 0) {
- wl1271_warning("failed to set sg config: %d", ret);
- goto out;
- }
-
-out:
- kfree(param);
- return ret;
-}
-
-int wl1271_acx_ap_sg_cfg(struct wl1271 *wl)
-{
- struct acx_ap_bt_wlan_coex_param *param;
- struct conf_sg_settings *c = &wl->conf.sg;
- int i, ret;
-
- wl1271_debug(DEBUG_ACX, "acx sg ap cfg");
-
- param = kzalloc(sizeof(*param), GFP_KERNEL);
- if (!param) {
- ret = -ENOMEM;
- goto out;
- }
-
- /* BT-WLAN coext parameters */
- for (i = 0; i < CONF_SG_AP_PARAMS_MAX; i++)
- param->params[i] = cpu_to_le32(c->ap_params[i]);
+ for (i = 0; i < CONF_SG_PARAMS_MAX; i++)
+ param->params[i] = cpu_to_le32(c->params[i]);
param->param_idx = CONF_SG_PARAMS_ALL;

ret = wl1271_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param));
if (ret < 0) {
wl1271_warning("failed to set sg config: %d", ret);
goto out;
diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h
index 2ea71d1..ac6194e 100644
--- a/drivers/net/wireless/wl12xx/acx.h
+++ b/drivers/net/wireless/wl12xx/acx.h
@@ -297,29 +297,20 @@ struct acx_bt_wlan_coex {
struct acx_header header;

u8 enable;
u8 pad[3];
} __packed;

-struct acx_sta_bt_wlan_coex_param {
+struct acx_bt_wlan_coex_param {
struct acx_header header;

- __le32 params[CONF_SG_STA_PARAMS_MAX];
+ __le32 params[CONF_SG_PARAMS_MAX];
u8 param_idx;
u8 padding[3];
} __packed;

-struct acx_ap_bt_wlan_coex_param {
- struct acx_header header;
-
- __le32 params[CONF_SG_AP_PARAMS_MAX];
- u8 param_idx;
- u8 padding[3];
-} __packed;
-
-
struct acx_dco_itrim_params {
struct acx_header header;

u8 enable;
u8 padding[3];
__le32 timeout;
@@ -1267,14 +1258,13 @@ int wl1271_acx_service_period_timeout(struct wl1271 *wl);
int wl1271_acx_rts_threshold(struct wl1271 *wl, u32 rts_threshold);
int wl1271_acx_dco_itrim_params(struct wl1271 *wl);
int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter);
int wl1271_acx_beacon_filter_table(struct wl1271 *wl);
int wl1271_acx_conn_monit_params(struct wl1271 *wl, bool enable);
int wl1271_acx_sg_enable(struct wl1271 *wl, bool enable);
-int wl1271_acx_sta_sg_cfg(struct wl1271 *wl);
-int wl1271_acx_ap_sg_cfg(struct wl1271 *wl);
+int wl1271_acx_sg_cfg(struct wl1271 *wl);
int wl1271_acx_cca_threshold(struct wl1271 *wl);
int wl1271_acx_bcn_dtim_options(struct wl1271 *wl);
int wl1271_acx_aid(struct wl1271 *wl, u16 aid);
int wl1271_acx_event_mbox_mask(struct wl1271 *wl, u32 event_mask);
int wl1271_acx_set_preamble(struct wl1271 *wl, enum acx_preamble_type preamble);
int wl1271_acx_cts_protect(struct wl1271 *wl,
diff --git a/drivers/net/wireless/wl12xx/conf.h b/drivers/net/wireless/wl12xx/conf.h
index ebc8c6b..e3a6b28 100644
--- a/drivers/net/wireless/wl12xx/conf.h
+++ b/drivers/net/wireless/wl12xx/conf.h
@@ -96,46 +96,81 @@ enum {
CONF_SG_PROTECTIVE,
CONF_SG_OPPORTUNISTIC
};

enum {
/*
- * PER threshold in PPM of the BT voice
+ * Configure the min and max time BT gains the antenna
+ * in WLAN / BT master basic rate
*
- * Range: 0 - 10000000
+ * Range: 0 - 255 (ms)
*/
- CONF_SG_BT_PER_THRESHOLD = 0,
+ CONF_SG_ACL_BT_MASTER_MIN_BR = 0,
+ CONF_SG_ACL_BT_MASTER_MAX_BR,

/*
- * Number of consequent RX_ACTIVE activities to override BT voice
- * frames to ensure WLAN connection
+ * Configure the min and max time BT gains the antenna
+ * in WLAN / BT slave basic rate
*
- * Range: 0 - 100
+ * Range: 0 - 255 (ms)
*/
- CONF_SG_HV3_MAX_OVERRIDE,
+ CONF_SG_ACL_BT_SLAVE_MIN_BR,
+ CONF_SG_ACL_BT_SLAVE_MAX_BR,

/*
- * Defines the PER threshold of the BT voice
+ * Configure the min and max time BT gains the antenna
+ * in WLAN / BT master EDR
*
- * Range: 0 - 65000
+ * Range: 0 - 255 (ms)
*/
- CONF_SG_BT_NFS_SAMPLE_INTERVAL,
+ CONF_SG_ACL_BT_MASTER_MIN_EDR,
+ CONF_SG_ACL_BT_MASTER_MAX_EDR,

/*
- * Defines the load ratio of BT
+ * Configure the min and max time BT gains the antenna
+ * in WLAN / BT slave EDR
*
- * Range: 0 - 100 (%)
+ * Range: 0 - 255 (ms)
*/
- CONF_SG_BT_LOAD_RATIO,
+ CONF_SG_ACL_BT_SLAVE_MIN_EDR,
+ CONF_SG_ACL_BT_SLAVE_MAX_EDR,

/*
- * Defines whether the SG will force WLAN host to enter/exit PSM
+ * The maximum time WLAN can gain the antenna for
+ * in WLAN PSM / BT master/slave BR
*
- * Range: 1 - SG can force, 0 - host handles PSM
+ * Range: 0 - 255 (ms)
*/
- CONF_SG_AUTO_PS_MODE,
+ CONF_SG_ACL_WLAN_PS_MASTER_BR,
+ CONF_SG_ACL_WLAN_PS_SLAVE_BR,
+
+ /*
+ * The maximum time WLAN can gain the antenna for
+ * in WLAN PSM / BT master/slave EDR
+ *
+ * Range: 0 - 255 (ms)
+ */
+ CONF_SG_ACL_WLAN_PS_MASTER_EDR,
+ CONF_SG_ACL_WLAN_PS_SLAVE_EDR,
+
+ /* ??? */
+ CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR,
+ CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR,
+ CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR,
+ CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR,
+ CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR,
+ CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR,
+ CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR,
+ CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR,
+
+ CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR,
+ CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR,
+ CONF_SG_ACL_PASSIVE_SCAN_BT_BR,
+ CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR,
+ CONF_SG_ACL_PASSIVE_SCAN_BT_EDR,
+ CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR,

/*
* Compensation percentage of probe requests when scan initiated
* during BT voice/ACL link.
*
* Range: 0 - 255 (%)
@@ -148,108 +183,76 @@ enum {
*
* Range: 0 - 255 (%)
*/
CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3,

/*
- * Defines antenna configuration (single/dual antenna)
- *
- * Range: 0 - single antenna, 1 - dual antenna
- */
- CONF_SG_ANTENNA_CONFIGURATION,
-
- /*
- * The threshold (percent) of max consequtive beacon misses before
- * increasing priority of beacon reception.
- *
- * Range: 0 - 100 (%)
- */
- CONF_SG_BEACON_MISS_PERCENT,
-
- /*
- * The rate threshold below which receiving a data frame from the AP
- * will increase the priority of the data frame above BT traffic.
- *
- * Range: 0,2, 5(=5.5), 6, 9, 11, 12, 18, 24, 36, 48, 54
- */
- CONF_SG_RATE_ADAPT_THRESH,
-
- /*
- * Not used currently.
+ * Compensation percentage of WLAN active scan window if initiated
+ * during BT A2DP
*
- * Range: 0
+ * Range: 0 - 1000 (%)
*/
- CONF_SG_RATE_ADAPT_SNR,
+ CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP,

/*
- * Configure the min and max time BT gains the antenna
- * in WLAN PSM / BT master basic rate
+ * Compensation percentage of WLAN passive scan window if initiated
+ * during BT A2DP BR
*
- * Range: 0 - 255 (ms)
+ * Range: 0 - 1000 (%)
*/
- CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR,
- CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR,
+ CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR,

/*
- * The time after it expires no new WLAN trigger frame is trasmitted
- * in WLAN PSM / BT master basic rate
+ * Compensation percentage of WLAN passive scan window if initiated
+ * during BT A2DP EDR
*
- * Range: 0 - 255 (ms)
+ * Range: 0 - 1000 (%)
*/
- CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR,
+ CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR,

/*
- * Configure the min and max time BT gains the antenna
- * in WLAN PSM / BT slave basic rate
+ * Compensation percentage of WLAN passive scan window if initiated
+ * during BT voice
*
- * Range: 0 - 255 (ms)
+ * Range: 0 - 1000 (%)
*/
- CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR,
- CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR,
+ CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3,

- /*
- * The time after it expires no new WLAN trigger frame is trasmitted
- * in WLAN PSM / BT slave basic rate
- *
- * Range: 0 - 255 (ms)
- */
- CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR,
+ /* ??? */
+ CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN,
+ CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN,
+ CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN,

/*
- * Configure the min and max time BT gains the antenna
- * in WLAN PSM / BT master EDR
+ * Defines whether the SG will force WLAN host to enter/exit PSM
*
- * Range: 0 - 255 (ms)
+ * Range: 1 - SG can force, 0 - host handles PSM
*/
- CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR,
- CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR,
+ CONF_SG_STA_FORCE_PS_IN_BT_SCO,

/*
- * The time after it expires no new WLAN trigger frame is trasmitted
- * in WLAN PSM / BT master EDR
+ * Defines antenna configuration (single/dual antenna)
*
- * Range: 0 - 255 (ms)
+ * Range: 0 - single antenna, 1 - dual antenna
*/
- CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR,
+ CONF_SG_ANTENNA_CONFIGURATION,

/*
- * Configure the min and max time BT gains the antenna
- * in WLAN PSM / BT slave EDR
+ * The threshold (percent) of max consequtive beacon misses before
+ * increasing priority of beacon reception.
*
- * Range: 0 - 255 (ms)
+ * Range: 0 - 100 (%)
*/
- CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR,
- CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR,
+ CONF_SG_BEACON_MISS_PERCENT,

/*
- * The time after it expires no new WLAN trigger frame is trasmitted
- * in WLAN PSM / BT slave EDR
+ * Protection time of the DHCP procedure.
*
- * Range: 0 - 255 (ms)
+ * Range: 0 - 100000 (ms)
*/
- CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR,
+ CONF_SG_DHCP_TIME,

/*
* RX guard time before the beginning of a new BT voice frame during
* which no new WLAN trigger frame is transmitted.
*
* Range: 0 - 100000 (us)
@@ -270,172 +273,65 @@ enum {
* will be utilized.
*
* Range: 0 - disable, 1 - enable
*/
CONF_SG_ADAPTIVE_RXT_TXT,

- /*
- * The used WLAN legacy service period during active BT ACL link
- *
- * Range: 0 - 255 (ms)
- */
- CONF_SG_PS_POLL_TIMEOUT,
+ /* ??? */
+ CONF_SG_GENERAL_USAGE_BIT_MAP,

/*
- * The used WLAN UPSD service period during active BT ACL link
- *
- * Range: 0 - 255 (ms)
- */
- CONF_SG_UPSD_TIMEOUT,
-
- /*
- * Configure the min and max time BT gains the antenna
- * in WLAN Active / BT master EDR
- *
- * Range: 0 - 255 (ms)
- */
- CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR,
- CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR,
-
- /*
- * The maximum time WLAN can gain the antenna for
- * in WLAN Active / BT master EDR
- *
- * Range: 0 - 255 (ms)
- */
- CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR,
-
- /*
- * Configure the min and max time BT gains the antenna
- * in WLAN Active / BT slave EDR
- *
- * Range: 0 - 255 (ms)
- */
- CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR,
- CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR,
-
- /*
- * The maximum time WLAN can gain the antenna for
- * in WLAN Active / BT slave EDR
+ * Number of consequent BT voice frames not interrupted by WLAN
*
- * Range: 0 - 255 (ms)
+ * Range: 0 - 100
*/
- CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR,
+ CONF_SG_HV3_MAX_SERVED,

/*
- * Configure the min and max time BT gains the antenna
- * in WLAN Active / BT basic rate
+ * The used WLAN legacy service period during active BT ACL link
*
* Range: 0 - 255 (ms)
*/
- CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR,
- CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR,
+ CONF_SG_PS_POLL_TIMEOUT,

/*
- * The maximum time WLAN can gain the antenna for
- * in WLAN Active / BT basic rate
+ * The used WLAN UPSD service period during active BT ACL link
*
* Range: 0 - 255 (ms)
*/
- CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR,
-
- /*
- * Compensation percentage of WLAN passive scan window if initiated
- * during BT voice
- *
- * Range: 0 - 1000 (%)
- */
- CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3,
-
- /*
- * Compensation percentage of WLAN passive scan window if initiated
- * during BT A2DP
- *
- * Range: 0 - 1000 (%)
- */
- CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP,
-
- /*
- * Fixed time ensured for BT traffic to gain the antenna during WLAN
- * passive scan.
- *
- * Range: 0 - 1000 ms
- */
- CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME,
-
- /*
- * Fixed time ensured for WLAN traffic to gain the antenna during WLAN
- * passive scan.
- *
- * Range: 0 - 1000 ms
- */
- CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME,
+ CONF_SG_UPSD_TIMEOUT,

- /*
- * Number of consequent BT voice frames not interrupted by WLAN
- *
- * Range: 0 - 100
- */
- CONF_SG_HV3_MAX_SERVED,
+ CONF_SG_CONSECUTIVE_CTS_THRESHOLD,
+ CONF_SG_STA_RX_WINDOW_AFTER_DTIM,
+ CONF_SG_STA_CONNECTION_PROTECTION_TIME,

- /*
- * Protection time of the DHCP procedure.
- *
- * Range: 0 - 100000 (ms)
- */
- CONF_SG_DHCP_TIME,
+ /* AP params */
+ CONF_AP_BEACON_MISS_TX,
+ CONF_AP_RX_WINDOW_AFTER_BEACON,
+ CONF_AP_BEACON_WINDOW_INTERVAL,
+ CONF_AP_CONNECTION_PROTECTION_TIME,
+ CONF_AP_BT_ACL_VAL_BT_SERVE_TIME,
+ CONF_AP_BT_ACL_VAL_WL_SERVE_TIME,

- /*
- * Compensation percentage of WLAN active scan window if initiated
- * during BT A2DP
- *
- * Range: 0 - 1000 (%)
- */
- CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP,
CONF_SG_TEMP_PARAM_1,
CONF_SG_TEMP_PARAM_2,
CONF_SG_TEMP_PARAM_3,
CONF_SG_TEMP_PARAM_4,
CONF_SG_TEMP_PARAM_5,
-
- /*
- * AP beacon miss
- *
- * Range: 0 - 255
- */
- CONF_SG_AP_BEACON_MISS_TX,
-
- /*
- * AP RX window length
- *
- * Range: 0 - 50
- */
- CONF_SG_RX_WINDOW_LENGTH,
-
- /*
- * AP connection protection time
- *
- * Range: 0 - 5000
- */
- CONF_SG_AP_CONNECTION_PROTECTION_TIME,
-
CONF_SG_TEMP_PARAM_6,
CONF_SG_TEMP_PARAM_7,
CONF_SG_TEMP_PARAM_8,
CONF_SG_TEMP_PARAM_9,
CONF_SG_TEMP_PARAM_10,

- CONF_SG_STA_PARAMS_MAX = CONF_SG_TEMP_PARAM_5 + 1,
- CONF_SG_AP_PARAMS_MAX = CONF_SG_TEMP_PARAM_10 + 1,
-
+ CONF_SG_PARAMS_MAX,
CONF_SG_PARAMS_ALL = 0xff
};

struct conf_sg_settings {
- u32 sta_params[CONF_SG_STA_PARAMS_MAX];
- u32 ap_params[CONF_SG_AP_PARAMS_MAX];
+ u32 params[CONF_SG_PARAMS_MAX];
u8 state;
};

enum conf_rx_queue_type {
CONF_RX_QUEUE_TYPE_LOW_PRIORITY, /* All except the high priority */
CONF_RX_QUEUE_TYPE_HIGH_PRIORITY, /* Management and voice packets */
diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c
index 4691297..b504ee1 100644
--- a/drivers/net/wireless/wl12xx/init.c
+++ b/drivers/net/wireless/wl12xx/init.c
@@ -274,16 +274,13 @@ static int wl1271_init_beacon_filter(struct wl1271 *wl)
}

int wl1271_init_pta(struct wl1271 *wl)
{
int ret;

- if (wl->bss_type == BSS_TYPE_AP_BSS)
- ret = wl1271_acx_ap_sg_cfg(wl);
- else
- ret = wl1271_acx_sta_sg_cfg(wl);
+ ret = wl1271_acx_sg_cfg(wl);
if (ret < 0)
return ret;

ret = wl1271_acx_sg_enable(wl, wl->sg_enabled);
if (ret < 0)
return ret;
@@ -357,17 +354,12 @@ static int wl1271_sta_hw_init(struct wl1271 *wl)

/* Beacon filtering */
ret = wl1271_init_beacon_filter(wl);
if (ret < 0)
return ret;

- /* FM WLAN coexistence */
- ret = wl1271_acx_fm_coex(wl);
- if (ret < 0)
- return ret;
-
/* Beacons and broadcast settings */
ret = wl1271_init_beacon_broadcast(wl);
if (ret < 0)
return ret;

/* Configure for ELP power saving */
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index fda2531..9fed917 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -49,116 +49,73 @@
#include "scan.h"

#define WL1271_BOOT_RETRIES 3

static struct conf_drv_settings default_conf = {
.sg = {
- .sta_params = {
- [CONF_SG_BT_PER_THRESHOLD] = 7500,
- [CONF_SG_HV3_MAX_OVERRIDE] = 0,
- [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
- [CONF_SG_BT_LOAD_RATIO] = 200,
- [CONF_SG_AUTO_PS_MODE] = 1,
- [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
- [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
- [CONF_SG_ANTENNA_CONFIGURATION] = 0,
- [CONF_SG_BEACON_MISS_PERCENT] = 60,
- [CONF_SG_RATE_ADAPT_THRESH] = 12,
- [CONF_SG_RATE_ADAPT_SNR] = 0,
- [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10,
- [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 30,
- [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 8,
- [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20,
- [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 50,
- /* Note: with UPSD, this should be 4 */
- [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 8,
- [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7,
- [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25,
- [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 20,
- /* Note: with UPDS, this should be 15 */
- [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8,
- /* Note: with UPDS, this should be 50 */
- [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 40,
- /* Note: with UPDS, this should be 10 */
- [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 20,
- [CONF_SG_RXT] = 1200,
- [CONF_SG_TXT] = 1000,
- [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
- [CONF_SG_PS_POLL_TIMEOUT] = 10,
- [CONF_SG_UPSD_TIMEOUT] = 10,
- [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
- [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
- [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
- [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8,
- [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20,
- [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15,
- [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20,
- [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50,
- [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10,
- [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
- [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
- [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75,
- [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15,
- [CONF_SG_HV3_MAX_SERVED] = 6,
- [CONF_SG_DHCP_TIME] = 5000,
- [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
- },
- .ap_params = {
- [CONF_SG_BT_PER_THRESHOLD] = 7500,
- [CONF_SG_HV3_MAX_OVERRIDE] = 0,
- [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
- [CONF_SG_BT_LOAD_RATIO] = 50,
- [CONF_SG_AUTO_PS_MODE] = 1,
- [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
- [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
- [CONF_SG_ANTENNA_CONFIGURATION] = 0,
- [CONF_SG_BEACON_MISS_PERCENT] = 60,
- [CONF_SG_RATE_ADAPT_THRESH] = 64,
- [CONF_SG_RATE_ADAPT_SNR] = 1,
- [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10,
- [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 25,
- [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 25,
- [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20,
- [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 25,
- [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 25,
- [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7,
- [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25,
- [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 25,
- [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8,
- [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 25,
- [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 25,
- [CONF_SG_RXT] = 1200,
- [CONF_SG_TXT] = 1000,
- [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
- [CONF_SG_PS_POLL_TIMEOUT] = 10,
- [CONF_SG_UPSD_TIMEOUT] = 10,
- [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
- [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
- [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
- [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8,
- [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20,
- [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15,
- [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20,
- [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50,
- [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10,
- [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
- [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
- [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75,
- [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15,
- [CONF_SG_HV3_MAX_SERVED] = 6,
- [CONF_SG_DHCP_TIME] = 5000,
- [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
- [CONF_SG_TEMP_PARAM_1] = 0,
- [CONF_SG_TEMP_PARAM_2] = 0,
- [CONF_SG_TEMP_PARAM_3] = 0,
- [CONF_SG_TEMP_PARAM_4] = 0,
- [CONF_SG_TEMP_PARAM_5] = 0,
- [CONF_SG_AP_BEACON_MISS_TX] = 3,
- [CONF_SG_RX_WINDOW_LENGTH] = 6,
- [CONF_SG_AP_CONNECTION_PROTECTION_TIME] = 50,
- [CONF_SG_TEMP_PARAM_6] = 1,
+ .params = {
+ [CONF_SG_ACL_BT_MASTER_MIN_BR] = 10,
+ [CONF_SG_ACL_BT_MASTER_MAX_BR] = 180,
+ [CONF_SG_ACL_BT_SLAVE_MIN_BR] = 10,
+ [CONF_SG_ACL_BT_SLAVE_MAX_BR] = 180,
+ [CONF_SG_ACL_BT_MASTER_MIN_EDR] = 10,
+ [CONF_SG_ACL_BT_MASTER_MAX_EDR] = 80,
+ [CONF_SG_ACL_BT_SLAVE_MIN_EDR] = 10,
+ [CONF_SG_ACL_BT_SLAVE_MAX_EDR] = 80,
+ [CONF_SG_ACL_WLAN_PS_MASTER_BR] = 8,
+ [CONF_SG_ACL_WLAN_PS_SLAVE_BR] = 8,
+ [CONF_SG_ACL_WLAN_PS_MASTER_EDR] = 20,
+ [CONF_SG_ACL_WLAN_PS_SLAVE_EDR] = 20,
+ [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR] = 20,
+ [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR] = 35,
+ [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR] = 16,
+ [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR] = 35,
+ [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR] = 32,
+ [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR] = 50,
+ [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR] = 28,
+ [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR] = 50,
+ [CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR] = 10,
+ [CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR] = 20,
+ [CONF_SG_ACL_PASSIVE_SCAN_BT_BR] = 75,
+ [CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR] = 15,
+ [CONF_SG_ACL_PASSIVE_SCAN_BT_EDR] = 27,
+ [CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR] = 17,
+ /* active scan params */
+ [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
+ [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
+ [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
+ /* passive scan params */
+ [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR] = 800,
+ [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR] = 200,
+ [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
+ /* passive scan in dual antenna params */
+ [CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN] = 0,
+ [CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN] = 0,
+ [CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN] = 0,
+ /* general params */
+ [CONF_SG_STA_FORCE_PS_IN_BT_SCO] = 1,
+ [CONF_SG_ANTENNA_CONFIGURATION] = 0,
+ [CONF_SG_BEACON_MISS_PERCENT] = 60,
+ [CONF_SG_DHCP_TIME] = 5000,
+ [CONF_SG_RXT] = 1200,
+ [CONF_SG_TXT] = 1000,
+ [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
+ [CONF_SG_GENERAL_USAGE_BIT_MAP] = 3,
+ [CONF_SG_HV3_MAX_SERVED] = 6,
+ [CONF_SG_PS_POLL_TIMEOUT] = 10,
+ [CONF_SG_UPSD_TIMEOUT] = 10,
+ [CONF_SG_CONSECUTIVE_CTS_THRESHOLD] = 2,
+ [CONF_SG_STA_RX_WINDOW_AFTER_DTIM] = 5,
+ [CONF_SG_STA_CONNECTION_PROTECTION_TIME] = 30,
+ /* AP params */
+ [CONF_AP_BEACON_MISS_TX] = 3,
+ [CONF_AP_RX_WINDOW_AFTER_BEACON] = 10,
+ [CONF_AP_BEACON_WINDOW_INTERVAL] = 2,
+ [CONF_AP_CONNECTION_PROTECTION_TIME] = 0,
+ [CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25,
+ [CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25,
},
.state = CONF_SG_PROTECTIVE,
},
.rx = {
.rx_msdu_life_time = 512000,
.packet_detection_threshold = 0,
--
1.7.6.401.g6a319


2011-08-09 11:54:12

by Luciano Coelho

[permalink] [raw]
Subject: Re: [PATCH 01/40] wl12xx: Revert "wl12xx: schedule TX packets according to FW occupancy"

On Tue, 2011-08-09 at 12:13 +0300, Eliad Peller wrote:
> From: Arik Nemtsov <[email protected]>
>
> This does not make sense in 7.3 firmware - we don't use Tx blocks to
> measure FW occupancy anymore.

Should we be more precise about the firmware versions here? Maybe
mentioning >= 7.3.0.0.75 for wl128x and >= 6.3.0.0.75 for wl127x would
be good?

Should we also add a file, eg. called firmware.txt, in order to make it
easy for people to know which firmware they need to use for that
specific version? Of course we already have the fw-3 thingy, and we
should try to keep the kernel mainline always in sync with the
linux-firmware mainline, but maybe being more explicit would help users
of older kernels... It seems to be a recurring problem.

--
Cheers,
Luca.


2011-08-10 12:57:49

by Luciano Coelho

[permalink] [raw]
Subject: Re: [PATCH 17/40] wl12xx: add ROC/CROC commands

On Tue, 2011-08-09 at 12:13 +0300, Eliad Peller wrote:
> +static int wl1271_cmd_roc(struct wl1271 *wl, u8 role_id)
> +{
> + struct wl1271_cmd_roc *cmd;
> + int ret = 0;
> +
> + wl1271_debug(DEBUG_CMD, "cmd roc %d (%d)", wl->channel, wl->band);
> +
> + if (WARN_ON(role_id == WL1271_INVALID_ROLE_ID))
> + return -EINVAL;
> +
> + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
> + if (!cmd) {
> + ret = -ENOMEM;
> + goto out;
> + }
> +
> + cmd->role_id = role_id;
> + cmd->channel = wl->channel;
> + switch (wl->band) {
> + case IEEE80211_BAND_2GHZ:
> + cmd->band = RADIO_BAND_2_4GHZ;
> + break;
> + case IEEE80211_BAND_5GHZ:
> + cmd->band = RADIO_BAND_5GHZ;
> + break;
> + default:
> + wl1271_warning("roc - unknown band: %d", (int)wl->band);
> + cmd->band = RADIO_BAND_2_4GHZ;
> + break;

Are you sure it's better to choose 2.4GHz here instead of bailing out?


--
Cheers,
Luca.


2011-08-09 09:13:41

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 05/40] wl12xx: remove rx filtering stuff

The new fw doesn't support rx_filtering configuration (as a
stand-alone command. the rx filtering is done automatically
according to the active role).

Signed-off-by: Eliad Peller <[email protected]>
---
drivers/net/wireless/wl12xx/acx.c | 28 --------
drivers/net/wireless/wl12xx/acx.h | 118 ---------------------------------
drivers/net/wireless/wl12xx/boot.c | 3 -
drivers/net/wireless/wl12xx/cmd.c | 4 -
drivers/net/wireless/wl12xx/debugfs.c | 3 -
drivers/net/wireless/wl12xx/init.c | 12 +---
drivers/net/wireless/wl12xx/io.h | 1 -
drivers/net/wireless/wl12xx/main.c | 62 ++----------------
drivers/net/wireless/wl12xx/reg.h | 75 ---------------------
drivers/net/wireless/wl12xx/rx.c | 11 ---
drivers/net/wireless/wl12xx/rx.h | 1 -
drivers/net/wireless/wl12xx/scan.c | 3 -
drivers/net/wireless/wl12xx/tx.c | 4 +-
drivers/net/wireless/wl12xx/wl12xx.h | 22 ------
14 files changed, 8 insertions(+), 339 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c
index 75cefa7..804bac9 100644
--- a/drivers/net/wireless/wl12xx/acx.c
+++ b/drivers/net/wireless/wl12xx/acx.c
@@ -180,40 +180,12 @@ int wl1271_acx_rx_msdu_life_time(struct wl1271 *wl)

out:
kfree(acx);
return ret;
}

-int wl1271_acx_rx_config(struct wl1271 *wl, u32 config, u32 filter)
-{
- struct acx_rx_config *rx_config;
- int ret;
-
- wl1271_debug(DEBUG_ACX, "acx rx config");
-
- rx_config = kzalloc(sizeof(*rx_config), GFP_KERNEL);
- if (!rx_config) {
- ret = -ENOMEM;
- goto out;
- }
-
- rx_config->config_options = cpu_to_le32(config);
- rx_config->filter_options = cpu_to_le32(filter);
-
- ret = wl1271_cmd_configure(wl, ACX_RX_CFG,
- rx_config, sizeof(*rx_config));
- if (ret < 0) {
- wl1271_warning("failed to set rx config: %d", ret);
- goto out;
- }
-
-out:
- kfree(rx_config);
- return ret;
-}
-
int wl1271_acx_pd_threshold(struct wl1271 *wl)
{
struct acx_packet_detection *pd;
int ret;

wl1271_debug(DEBUG_ACX, "acx data pd threshold");
diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h
index d2eb86e..4ae0085 100644
--- a/drivers/net/wireless/wl12xx/acx.h
+++ b/drivers/net/wireless/wl12xx/acx.h
@@ -157,100 +157,12 @@ struct acx_rx_msdu_lifetime {
* The maximum amount of time, in TU, before the
* firmware discards the MSDU.
*/
__le32 lifetime;
} __packed;

-/*
- * RX Config Options Table
- * Bit Definition
- * === ==========
- * 31:14 Reserved
- * 13 Copy RX Status - when set, write three receive status words
- * to top of rx'd MPDUs.
- * When cleared, do not write three status words (added rev 1.5)
- * 12 Reserved
- * 11 RX Complete upon FCS error - when set, give rx complete
- * interrupt for FCS errors, after the rx filtering, e.g. unicast
- * frames not to us with FCS error will not generate an interrupt.
- * 10 SSID Filter Enable - When set, the WiLink discards all beacon,
- * probe request, and probe response frames with an SSID that does
- * not match the SSID specified by the host in the START/JOIN
- * command.
- * When clear, the WiLink receives frames with any SSID.
- * 9 Broadcast Filter Enable - When set, the WiLink discards all
- * broadcast frames. When clear, the WiLink receives all received
- * broadcast frames.
- * 8:6 Reserved
- * 5 BSSID Filter Enable - When set, the WiLink discards any frames
- * with a BSSID that does not match the BSSID specified by the
- * host.
- * When clear, the WiLink receives frames from any BSSID.
- * 4 MAC Addr Filter - When set, the WiLink discards any frames
- * with a destination address that does not match the MAC address
- * of the adaptor.
- * When clear, the WiLink receives frames destined to any MAC
- * address.
- * 3 Promiscuous - When set, the WiLink receives all valid frames
- * (i.e., all frames that pass the FCS check).
- * When clear, only frames that pass the other filters specified
- * are received.
- * 2 FCS - When set, the WiLink includes the FCS with the received
- * frame.
- * When cleared, the FCS is discarded.
- * 1 PLCP header - When set, write all data from baseband to frame
- * buffer including PHY header.
- * 0 Reserved - Always equal to 0.
- *
- * RX Filter Options Table
- * Bit Definition
- * === ==========
- * 31:12 Reserved - Always equal to 0.
- * 11 Association - When set, the WiLink receives all association
- * related frames (association request/response, reassocation
- * request/response, and disassociation). When clear, these frames
- * are discarded.
- * 10 Auth/De auth - When set, the WiLink receives all authentication
- * and de-authentication frames. When clear, these frames are
- * discarded.
- * 9 Beacon - When set, the WiLink receives all beacon frames.
- * When clear, these frames are discarded.
- * 8 Contention Free - When set, the WiLink receives all contention
- * free frames.
- * When clear, these frames are discarded.
- * 7 Control - When set, the WiLink receives all control frames.
- * When clear, these frames are discarded.
- * 6 Data - When set, the WiLink receives all data frames.
- * When clear, these frames are discarded.
- * 5 FCS Error - When set, the WiLink receives frames that have FCS
- * errors.
- * When clear, these frames are discarded.
- * 4 Management - When set, the WiLink receives all management
- * frames.
- * When clear, these frames are discarded.
- * 3 Probe Request - When set, the WiLink receives all probe request
- * frames.
- * When clear, these frames are discarded.
- * 2 Probe Response - When set, the WiLink receives all probe
- * response frames.
- * When clear, these frames are discarded.
- * 1 RTS/CTS/ACK - When set, the WiLink receives all RTS, CTS and ACK
- * frames.
- * When clear, these frames are discarded.
- * 0 Rsvd Type/Sub Type - When set, the WiLink receives all frames
- * that have reserved frame types and sub types as defined by the
- * 802.11 specification.
- * When clear, these frames are discarded.
- */
-struct acx_rx_config {
- struct acx_header header;
-
- __le32 config_options;
- __le32 filter_options;
-} __packed;
-
struct acx_packet_detection {
struct acx_header header;

__le32 threshold;
} __packed;

@@ -421,41 +333,12 @@ struct acx_event_mask {
struct acx_header header;

__le32 event_mask;
__le32 high_event_mask; /* Unused */
} __packed;

-#define CFG_RX_FCS BIT(2)
-#define CFG_RX_ALL_GOOD BIT(3)
-#define CFG_UNI_FILTER_EN BIT(4)
-#define CFG_BSSID_FILTER_EN BIT(5)
-#define CFG_MC_FILTER_EN BIT(6)
-#define CFG_MC_ADDR0_EN BIT(7)
-#define CFG_MC_ADDR1_EN BIT(8)
-#define CFG_BC_REJECT_EN BIT(9)
-#define CFG_SSID_FILTER_EN BIT(10)
-#define CFG_RX_INT_FCS_ERROR BIT(11)
-#define CFG_RX_INT_ENCRYPTED BIT(12)
-#define CFG_RX_WR_RX_STATUS BIT(13)
-#define CFG_RX_FILTER_NULTI BIT(14)
-#define CFG_RX_RESERVE BIT(15)
-#define CFG_RX_TIMESTAMP_TSF BIT(16)
-
-#define CFG_RX_RSV_EN BIT(0)
-#define CFG_RX_RCTS_ACK BIT(1)
-#define CFG_RX_PRSP_EN BIT(2)
-#define CFG_RX_PREQ_EN BIT(3)
-#define CFG_RX_MGMT_EN BIT(4)
-#define CFG_RX_FCS_ERROR BIT(5)
-#define CFG_RX_DATA_EN BIT(6)
-#define CFG_RX_CTL_EN BIT(7)
-#define CFG_RX_CF_EN BIT(8)
-#define CFG_RX_BCN_EN BIT(9)
-#define CFG_RX_AUTH_EN BIT(10)
-#define CFG_RX_ASSOC_EN BIT(11)
-
#define SCAN_PASSIVE BIT(0)
#define SCAN_5GHZ_BAND BIT(1)
#define SCAN_TRIGGERED BIT(2)
#define SCAN_PRIORITY_HIGH BIT(3)

/* When set, disable HW encryption */
@@ -1339,13 +1222,12 @@ int wl1271_acx_wake_up_conditions(struct wl1271 *wl);
int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth);
int wl1271_acx_tx_power(struct wl1271 *wl, int power);
int wl1271_acx_feature_cfg(struct wl1271 *wl);
int wl1271_acx_mem_map(struct wl1271 *wl,
struct acx_header *mem_map, size_t len);
int wl1271_acx_rx_msdu_life_time(struct wl1271 *wl);
-int wl1271_acx_rx_config(struct wl1271 *wl, u32 config, u32 filter);
int wl1271_acx_pd_threshold(struct wl1271 *wl);
int wl1271_acx_slot(struct wl1271 *wl, enum acx_slot_type slot_time);
int wl1271_acx_group_address_tbl(struct wl1271 *wl, bool enable,
void *mc_list, u32 mc_list_len);
int wl1271_acx_service_period_timeout(struct wl1271 *wl);
int wl1271_acx_rts_threshold(struct wl1271 *wl, u32 rts_threshold);
diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c
index 5ebc64d..11b26d7 100644
--- a/drivers/net/wireless/wl12xx/boot.c
+++ b/drivers/net/wireless/wl12xx/boot.c
@@ -849,14 +849,11 @@ int wl1271_boot(struct wl1271 *wl)
wl1271_write32(wl, ACX_REG_INTERRUPT_MASK,
WL1271_ACX_ALL_EVENTS_VECTOR);

/* Enable firmware interrupts now */
wl1271_boot_enable_interrupts(wl);

- /* set the wl1271 default filters */
- wl1271_set_default_filters(wl);
-
wl1271_event_mbox_config(wl);

out:
return ret;
}
diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c
index 97dd237..b6ef65a 100644
--- a/drivers/net/wireless/wl12xx/cmd.c
+++ b/drivers/net/wireless/wl12xx/cmd.c
@@ -379,14 +379,12 @@ int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type)

/* Reverse order BSSID */
bssid = (u8 *) &join->bssid_lsb;
for (i = 0; i < ETH_ALEN; i++)
bssid[i] = wl->bssid[ETH_ALEN - i - 1];

- join->rx_config_options = cpu_to_le32(wl->rx_config);
- join->rx_filter_options = cpu_to_le32(wl->rx_filter);
join->bss_type = bss_type;
join->basic_rate_set = cpu_to_le32(wl->basic_rate_set);
join->supported_rate_set = cpu_to_le32(wl->rate_set);

if (wl->band == IEEE80211_BAND_5GHZ)
join->bss_type |= WL1271_JOIN_CMD_BSS_TYPE_5GHZ;
@@ -1001,14 +999,12 @@ int wl1271_cmd_disconnect(struct wl1271 *wl)
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
ret = -ENOMEM;
goto out;
}

- cmd->rx_config_options = cpu_to_le32(wl->rx_config);
- cmd->rx_filter_options = cpu_to_le32(wl->rx_filter);
/* disconnect reason is not used in immediate disconnections */
cmd->type = DISCONNECT_IMMEDIATE;

ret = wl1271_cmd_send(wl, CMD_DISCONNECT, cmd, sizeof(*cmd), 0);
if (ret < 0) {
wl1271_error("failed to send disconnect command");
diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c
index 3b5f240..fd1c301 100644
--- a/drivers/net/wireless/wl12xx/debugfs.c
+++ b/drivers/net/wireless/wl12xx/debugfs.c
@@ -363,15 +363,12 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf,
DRIVER_STATE_PRINT_HEX(basic_rate_set);
DRIVER_STATE_PRINT_HEX(basic_rate);
DRIVER_STATE_PRINT_INT(band);
DRIVER_STATE_PRINT_INT(beacon_int);
DRIVER_STATE_PRINT_INT(psm_entry_retry);
DRIVER_STATE_PRINT_INT(ps_poll_failures);
- DRIVER_STATE_PRINT_HEX(filters);
- DRIVER_STATE_PRINT_HEX(rx_config);
- DRIVER_STATE_PRINT_HEX(rx_filter);
DRIVER_STATE_PRINT_INT(power_level);
DRIVER_STATE_PRINT_INT(rssi_thold);
DRIVER_STATE_PRINT_INT(last_rssi_event);
DRIVER_STATE_PRINT_INT(sg_enabled);
DRIVER_STATE_PRINT_INT(enable_11a);
DRIVER_STATE_PRINT_INT(noise);
diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c
index c3e9a2e..7aa8fc7 100644
--- a/drivers/net/wireless/wl12xx/init.c
+++ b/drivers/net/wireless/wl12xx/init.c
@@ -224,24 +224,20 @@ static int wl1271_ap_init_templates_config(struct wl1271 *wl)
if (ret < 0)
return ret;

return 0;
}

-static int wl1271_init_rx_config(struct wl1271 *wl, u32 config, u32 filter)
+static int wl1271_init_rx_config(struct wl1271 *wl)
{
int ret;

ret = wl1271_acx_rx_msdu_life_time(wl);
if (ret < 0)
return ret;

- ret = wl1271_acx_rx_config(wl, config, filter);
- if (ret < 0)
- return ret;
-
return 0;
}

int wl1271_init_phy_config(struct wl1271 *wl)
{
int ret;
@@ -647,17 +643,13 @@ int wl1271_hw_init(struct wl1271 *wl)
/* Default memory configuration */
ret = wl1271_acx_init_mem_config(wl);
if (ret < 0)
return ret;

/* RX config */
- ret = wl1271_init_rx_config(wl,
- RX_CFG_PROMISCUOUS | RX_CFG_TSF,
- RX_FILTER_OPTION_DEF);
- /* RX_CONFIG_OPTION_ANY_DST_ANY_BSS,
- RX_FILTER_OPTION_FILTER_ALL); */
+ ret = wl1271_init_rx_config(wl);
if (ret < 0)
goto out_free_memmap;

/* PHY layer config */
ret = wl1271_init_phy_config(wl);
if (ret < 0)
diff --git a/drivers/net/wireless/wl12xx/io.h b/drivers/net/wireless/wl12xx/io.h
index cfb3588..e92725d 100644
--- a/drivers/net/wireless/wl12xx/io.h
+++ b/drivers/net/wireless/wl12xx/io.h
@@ -182,9 +182,8 @@ void wl1271_unregister_hw(struct wl1271 *wl);
int wl1271_init_ieee80211(struct wl1271 *wl);
struct ieee80211_hw *wl1271_alloc_hw(void);
int wl1271_free_hw(struct wl1271 *wl);
irqreturn_t wl1271_irq(int irq, void *data);
bool wl1271_set_block_size(struct wl1271 *wl);
int wl1271_tx_dummy_packet(struct wl1271 *wl);
-void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters);

#endif
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index 49ceee8..a1608f1 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -1982,13 +1982,12 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
wl->tx_results_count = 0;
wl->tx_packets_count = 0;
wl->time_offset = 0;
wl->session_counter = 0;
wl->rate_set = CONF_TX_RATE_MASK_BASIC;
wl->vif = NULL;
- wl->filters = 0;
wl1271_free_ap_keys(wl);
memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
wl->ap_fw_ps_map = 0;
wl->ap_ps_map = 0;
wl->sched_scanning = false;

@@ -2028,57 +2027,21 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
}

mutex_unlock(&wl->mutex);
cancel_work_sync(&wl->recovery_work);
}

-void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
-{
- wl1271_set_default_filters(wl);
-
- /* combine requested filters with current filter config */
- filters = wl->filters | filters;
-
- wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
-
- if (filters & FIF_PROMISC_IN_BSS) {
- wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
- wl->rx_config &= ~CFG_UNI_FILTER_EN;
- wl->rx_config |= CFG_BSSID_FILTER_EN;
- }
- if (filters & FIF_BCN_PRBRESP_PROMISC) {
- wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
- wl->rx_config &= ~CFG_BSSID_FILTER_EN;
- wl->rx_config &= ~CFG_SSID_FILTER_EN;
- }
- if (filters & FIF_OTHER_BSS) {
- wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
- wl->rx_config &= ~CFG_BSSID_FILTER_EN;
- }
- if (filters & FIF_CONTROL) {
- wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
- wl->rx_filter |= CFG_RX_CTL_EN;
- }
- if (filters & FIF_FCSFAIL) {
- wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
- wl->rx_filter |= CFG_RX_FCS_ERROR;
- }
-}
-
static int wl1271_dummy_join(struct wl1271 *wl)
{
int ret = 0;
/* we need to use a dummy BSSID for now */
static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
0xad, 0xbe, 0xef };

memcpy(wl->bssid, dummy_bssid, ETH_ALEN);

- /* pass through frames from all BSS */
- wl1271_configure_filters(wl, FIF_OTHER_BSS);
-
ret = wl1271_cmd_join(wl, wl->set_bss_type);
if (ret < 0)
goto out;

set_bit(WL1271_FLAG_JOINED, &wl->flags);

@@ -2154,15 +2117,12 @@ static int wl1271_unjoin(struct wl1271 *wl)
memset(wl->bssid, 0, ETH_ALEN);

/* reset TX security counters on a clean disconnect */
wl->tx_security_last_seq_lsb = 0;
wl->tx_security_seq = 0;

- /* stop filtering packets based on bssid */
- wl1271_configure_filters(wl, FIF_OTHER_BSS);
-
out:
return ret;
}

static void wl1271_set_band_rate(struct wl1271 *wl)
{
@@ -2425,24 +2385,17 @@ static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
fp->mc_list,
fp->mc_list_length);
if (ret < 0)
goto out_sleep;
}

- /* determine, whether supported filter values have changed */
- if (changed == 0)
- goto out_sleep;
-
- /* configure filters */
- wl->filters = *total;
- wl1271_configure_filters(wl, 0);
-
- /* apply configured filters */
- ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
- if (ret < 0)
- goto out_sleep;
+ /*
+ * the fw doesn't provide an api to configure the filters. instead,
+ * the filters configuration is based on the active roles / ROC
+ * state.
+ */

out_sleep:
wl1271_ps_elp_sleep(wl);

out:
mutex_unlock(&wl->mutex);
@@ -3159,15 +3112,12 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
goto out;

ret = wl1271_build_qos_null_data(wl);
if (ret < 0)
goto out;

- /* filter out all packets not from this BSSID */
- wl1271_configure_filters(wl, 0);
-
/* Need to update the BSSID (for filtering etc) */
do_join = true;
}
}

rcu_read_lock();
@@ -4354,14 +4304,12 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
}

wl->channel = WL1271_DEFAULT_CHANNEL;
wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
wl->default_key = 0;
wl->rx_counter = 0;
- wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
- wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
wl->psm_entry_retry = 0;
wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
wl->rate_set = CONF_TX_RATE_MASK_BASIC;
wl->band = IEEE80211_BAND_2GHZ;
diff --git a/drivers/net/wireless/wl12xx/reg.h b/drivers/net/wireless/wl12xx/reg.h
index 440a4ee..3f570f3 100644
--- a/drivers/net/wireless/wl12xx/reg.h
+++ b/drivers/net/wireless/wl12xx/reg.h
@@ -293,87 +293,12 @@
The information mailbox pointer is not valid
until after the host receives the Init Complete interrupt from
the Wlan hardware.
===============================================*/
#define REG_EVENT_MAILBOX_PTR (SCR_PAD1)

-
-/* Misc */
-
-#define REG_ENABLE_TX_RX (ENABLE)
-/*
- * Rx configuration (filter) information element
- * ---------------------------------------------
- */
-#define REG_RX_CONFIG (RX_CFG)
-#define REG_RX_FILTER (RX_FILTER_CFG)
-
-
-#define RX_CFG_ENABLE_PHY_HEADER_PLCP 0x0002
-
-/* promiscuous - receives all valid frames */
-#define RX_CFG_PROMISCUOUS 0x0008
-
-/* receives frames from any BSSID */
-#define RX_CFG_BSSID 0x0020
-
-/* receives frames destined to any MAC address */
-#define RX_CFG_MAC 0x0010
-
-#define RX_CFG_ENABLE_ONLY_MY_DEST_MAC 0x0010
-#define RX_CFG_ENABLE_ANY_DEST_MAC 0x0000
-#define RX_CFG_ENABLE_ONLY_MY_BSSID 0x0020
-#define RX_CFG_ENABLE_ANY_BSSID 0x0000
-
-/* discards all broadcast frames */
-#define RX_CFG_DISABLE_BCAST 0x0200
-
-#define RX_CFG_ENABLE_ONLY_MY_SSID 0x0400
-#define RX_CFG_ENABLE_RX_CMPLT_FCS_ERROR 0x0800
-#define RX_CFG_COPY_RX_STATUS 0x2000
-#define RX_CFG_TSF 0x10000
-
-#define RX_CONFIG_OPTION_ANY_DST_MY_BSS (RX_CFG_ENABLE_ANY_DEST_MAC | \
- RX_CFG_ENABLE_ONLY_MY_BSSID)
-
-#define RX_CONFIG_OPTION_MY_DST_ANY_BSS (RX_CFG_ENABLE_ONLY_MY_DEST_MAC\
- | RX_CFG_ENABLE_ANY_BSSID)
-
-#define RX_CONFIG_OPTION_ANY_DST_ANY_BSS (RX_CFG_ENABLE_ANY_DEST_MAC | \
- RX_CFG_ENABLE_ANY_BSSID)
-
-#define RX_CONFIG_OPTION_MY_DST_MY_BSS (RX_CFG_ENABLE_ONLY_MY_DEST_MAC\
- | RX_CFG_ENABLE_ONLY_MY_BSSID)
-
-#define RX_CONFIG_OPTION_FOR_SCAN (RX_CFG_ENABLE_PHY_HEADER_PLCP \
- | RX_CFG_ENABLE_RX_CMPLT_FCS_ERROR \
- | RX_CFG_COPY_RX_STATUS | RX_CFG_TSF)
-
-#define RX_CONFIG_OPTION_FOR_MEASUREMENT (RX_CFG_ENABLE_ANY_DEST_MAC)
-
-#define RX_CONFIG_OPTION_FOR_JOIN (RX_CFG_ENABLE_ONLY_MY_BSSID | \
- RX_CFG_ENABLE_ONLY_MY_DEST_MAC)
-
-#define RX_CONFIG_OPTION_FOR_IBSS_JOIN (RX_CFG_ENABLE_ONLY_MY_SSID | \
- RX_CFG_ENABLE_ONLY_MY_DEST_MAC)
-
-#define RX_FILTER_OPTION_DEF (CFG_RX_MGMT_EN | CFG_RX_DATA_EN\
- | CFG_RX_CTL_EN | CFG_RX_BCN_EN\
- | CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN)
-
-#define RX_FILTER_OPTION_FILTER_ALL 0
-
-#define RX_FILTER_OPTION_DEF_PRSP_BCN (CFG_RX_PRSP_EN | CFG_RX_MGMT_EN\
- | CFG_RX_RCTS_ACK | CFG_RX_BCN_EN)
-
-#define RX_FILTER_OPTION_JOIN (CFG_RX_MGMT_EN | CFG_RX_DATA_EN\
- | CFG_RX_BCN_EN | CFG_RX_AUTH_EN\
- | CFG_RX_ASSOC_EN | CFG_RX_RCTS_ACK\
- | CFG_RX_PRSP_EN)
-
-
/*===============================================
EEPROM Read/Write Request 32bit RW
------------------------------------------
1 EE_READ - EEPROM Read Request 1 - Setting this bit
loads a single byte of data into the EE_DATA
register from the EEPROM location specified in
diff --git a/drivers/net/wireless/wl12xx/rx.c b/drivers/net/wireless/wl12xx/rx.c
index 0450fb4..1a957d6 100644
--- a/drivers/net/wireless/wl12xx/rx.c
+++ b/drivers/net/wireless/wl12xx/rx.c
@@ -257,17 +257,6 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status)
&wl->rx_streaming_enable_work);

mod_timer(&wl->rx_streaming_timer,
jiffies + msecs_to_jiffies(timeout));
}
}
-
-void wl1271_set_default_filters(struct wl1271 *wl)
-{
- if (wl->bss_type == BSS_TYPE_AP_BSS) {
- wl->rx_config = WL1271_DEFAULT_AP_RX_CONFIG;
- wl->rx_filter = WL1271_DEFAULT_AP_RX_FILTER;
- } else {
- wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
- wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
- }
-}
diff --git a/drivers/net/wireless/wl12xx/rx.h b/drivers/net/wireless/wl12xx/rx.h
index c88e3fa..094fff8 100644
--- a/drivers/net/wireless/wl12xx/rx.h
+++ b/drivers/net/wireless/wl12xx/rx.h
@@ -126,9 +126,8 @@ struct wl1271_rx_descriptor {
u8 pad_len;
u8 reserved;
} __packed;

void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status);
u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band);
-void wl1271_set_default_filters(struct wl1271 *wl);

#endif
diff --git a/drivers/net/wireless/wl12xx/scan.c b/drivers/net/wireless/wl12xx/scan.c
index edfe01c..78a9b23 100644
--- a/drivers/net/wireless/wl12xx/scan.c
+++ b/drivers/net/wireless/wl12xx/scan.c
@@ -164,15 +164,12 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band,
if (cmd->params.n_ch == 0) {
ret = WL1271_NOTHING_TO_SCAN;
goto out;
}

cmd->params.tx_rate = cpu_to_le32(basic_rate);
- cmd->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD);
- cmd->params.rx_filter_options =
- cpu_to_le32(CFG_RX_PRSP_EN | CFG_RX_MGMT_EN | CFG_RX_BCN_EN);

cmd->params.n_probe_reqs = wl->conf.scan.num_probe_reqs;
cmd->params.tx_rate = cpu_to_le32(basic_rate);
cmd->params.tid_trigger = 0;
cmd->params.scan_tag = WL1271_SCAN_DEFAULT_TAG;

diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c
index 938af1d..8a745fb 100644
--- a/drivers/net/wireless/wl12xx/tx.c
+++ b/drivers/net/wireless/wl12xx/tx.c
@@ -87,15 +87,13 @@ static int wl1271_tx_update_filters(struct wl1271 *wl,
* responses coming from BSSIDs it isn't familiar with (e.g. on
* roaming)
*/
if (!ieee80211_is_auth(hdr->frame_control))
return 0;

- wl1271_configure_filters(wl, FIF_OTHER_BSS);
-
- return wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
+ return 0;
}

static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl,
struct sk_buff *skb)
{
struct ieee80211_hdr *hdr;
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index 21c5f95..360f3d2 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -109,30 +109,12 @@ extern u32 wl12xx_debug_level;
DUMP_PREFIX_OFFSET, 16, 1, \
buf, \
min_t(size_t, len, DEBUG_DUMP_LIMIT), \
true); \
} while (0)

-#define WL1271_DEFAULT_STA_RX_CONFIG (CFG_UNI_FILTER_EN | \
- CFG_BSSID_FILTER_EN | \
- CFG_MC_FILTER_EN)
-
-#define WL1271_DEFAULT_STA_RX_FILTER (CFG_RX_RCTS_ACK | CFG_RX_PRSP_EN | \
- CFG_RX_MGMT_EN | CFG_RX_DATA_EN | \
- CFG_RX_CTL_EN | CFG_RX_BCN_EN | \
- CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN)
-
-#define WL1271_DEFAULT_AP_RX_CONFIG 0
-
-#define WL1271_DEFAULT_AP_RX_FILTER (CFG_RX_RCTS_ACK | CFG_RX_PREQ_EN | \
- CFG_RX_MGMT_EN | CFG_RX_DATA_EN | \
- CFG_RX_CTL_EN | CFG_RX_AUTH_EN | \
- CFG_RX_ASSOC_EN)
-
-
-
#define WL1271_FW_NAME "ti-connectivity/wl1271-fw-3.bin"
#define WL128X_FW_NAME "ti-connectivity/wl128x-fw-3.bin"

/*
* wl127x and wl128x are using the same NVS file name. However, the
* ini parameters between them are different. The driver validates
@@ -529,16 +511,12 @@ struct wl1271 {

/* Rx Streaming */
struct work_struct rx_streaming_enable_work;
struct work_struct rx_streaming_disable_work;
struct timer_list rx_streaming_timer;

- unsigned int filters;
- unsigned int rx_config;
- unsigned int rx_filter;
-
struct completion *elp_compl;
struct completion *ps_compl;
struct delayed_work elp_work;
struct delayed_work pspoll_work;

/* counter for ps-poll delivery failures */
--
1.7.6.401.g6a319


2011-08-09 09:14:18

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 25/40] wl12xx: don't remove key if hlid was already deleted

If hlid was already removed, there is no need to remove
its key (it might cause a fw crash, as the key is invalid).

Signed-off-by: Eliad Peller <[email protected]>
---
drivers/net/wireless/wl12xx/cmd.c | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c
index 7cf4d53..41dee4f 100644
--- a/drivers/net/wireless/wl12xx/cmd.c
+++ b/drivers/net/wireless/wl12xx/cmd.c
@@ -1200,12 +1200,16 @@ int wl1271_cmd_set_sta_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
u8 key_size, const u8 *key, const u8 *addr,
u32 tx_seq_32, u16 tx_seq_16)
{
struct wl1271_cmd_set_keys *cmd;
int ret = 0;

+ /* hlid might have already been deleted */
+ if (wl->sta_hlid == WL1271_INVALID_LINK_ID)
+ return 0;
+
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
ret = -ENOMEM;
goto out;
}

--
1.7.6.401.g6a319


2011-08-09 09:14:07

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 19/40] wl12xx: handle dummy packet event also in ap mode

From: Arik Nemtsov <[email protected]>

Allow handling of DUMMY_PACKET_EVENT_ID also in ap mode.

Signed-off-by: Arik Nemtsov <[email protected]>
Signed-off-by: Eliad Peller <[email protected]>
---
drivers/net/wireless/wl12xx/event.c | 2 +-
drivers/net/wireless/wl12xx/tx.c | 12 ++++++++----
2 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/event.c b/drivers/net/wireless/wl12xx/event.c
index 431ceae..0bd7b02 100644
--- a/drivers/net/wireless/wl12xx/event.c
+++ b/drivers/net/wireless/wl12xx/event.c
@@ -288,13 +288,13 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
"ba_allowed = 0x%x", mbox->rx_ba_allowed);

if (wl->vif)
wl1271_stop_ba_event(wl, mbox->rx_ba_allowed);
}

- if ((vector & DUMMY_PACKET_EVENT_ID) && !is_ap) {
+ if ((vector & DUMMY_PACKET_EVENT_ID)) {
wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID");
if (wl->vif)
wl1271_tx_dummy_packet(wl);
}

/*
diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c
index ea05caf..4e1c655 100644
--- a/drivers/net/wireless/wl12xx/tx.c
+++ b/drivers/net/wireless/wl12xx/tx.c
@@ -826,16 +826,20 @@ void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid)
int total[NUM_TX_QUEUES];

for (i = 0; i < NUM_TX_QUEUES; i++) {
total[i] = 0;
while ((skb = skb_dequeue(&wl->links[hlid].tx_queue[i]))) {
wl1271_debug(DEBUG_TX, "link freeing skb 0x%p", skb);
- info = IEEE80211_SKB_CB(skb);
- info->status.rates[0].idx = -1;
- info->status.rates[0].count = 0;
- ieee80211_tx_status_ni(wl->hw, skb);
+
+ if (!wl12xx_is_dummy_packet(wl, skb)) {
+ info = IEEE80211_SKB_CB(skb);
+ info->status.rates[0].idx = -1;
+ info->status.rates[0].count = 0;
+ ieee80211_tx_status_ni(wl->hw, skb);
+ }
+
total[i]++;
}
}

spin_lock_irqsave(&wl->wl_lock, flags);
for (i = 0; i < NUM_TX_QUEUES; i++)
--
1.7.6.401.g6a319


2011-08-10 14:31:45

by Luciano Coelho

[permalink] [raw]
Subject: Re: [PATCH 18/40] wl12xx: replace dummy_join with ROC/CROC commands

On Tue, 2011-08-09 at 12:13 +0300, Eliad Peller wrote:
> The ROC command asks the fw stay on the channel of the given
> hlid. it currently has 2 primary functions:
>
> 1. Allow tx/rx from the device role.
>
> In order to tx/rx packets while the stations is not associated
> (e.g. auth req/resp), the device role has to be used, along
> with ROC on its link.
>
> Keep the logic similiar to the one used in dummy_join. However,
> since we can't scan while we ROC, we add CROC before starting
> a scan, and ROC again (if needed) on scan complete.
>
> 2. Keeping the antenna for a specific link.
>
> We ROC until the connection was completed (after EAPOLs exchange)
> in order to prevent BT coex operations from taking the antenna
> and failing the connection (after this stage, psm can be used).
>
> During association, we ROC on the station role, and then CROC
> the device role, thus assuring being ROC during all the connection
> process.

Nice explanations. I was wondering if we should have this somewhere in
the code too, so that it's easier to figure out what is going on without
digging into git logs...


> Replace the WL1271_FLAG_JOINED with a new WL1271_FLAG_ROC,
> indicating the fw was configured to ROC. Add a roc bitmap
> to indicate what roles are currently ROCed.

Is it really possible to be ROCed in more than one role? They could be
running on different channels, so how could we physically ROC more than
once at the same time?


> Add wl1271_roc/croc functions in order to wrap the roc/croc
> commands while taking care of the roc bitmap.
>
> The current ROC/CROC state-machine is a bit complicated. In
> the future we'll probably want to use wpa_supplicant to control
> the ROC during connection.

But when we have multirole, we may have several instances of
wpa_supplicant/hostap running, so there may be some conflicts of
interest there. I think it's better to keep ROCing in a centralized
place (ie. the driver).


> diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c
> index 3091351..918c46b 100644
> --- a/drivers/net/wireless/wl12xx/cmd.c
> +++ b/drivers/net/wireless/wl12xx/cmd.c
> @@ -1484,13 +1484,13 @@ out:
>
> static int wl1271_cmd_roc(struct wl1271 *wl, u8 role_id)
> {
> struct wl1271_cmd_roc *cmd;
> int ret = 0;
>
> - wl1271_debug(DEBUG_CMD, "cmd roc %d (%d)", wl->channel, wl->band);
> + wl1271_debug(DEBUG_CMD, "cmd roc %d (%d)", wl->channel, role_id);
>
> if (WARN_ON(role_id == WL1271_INVALID_ROLE_ID))
> return -EINVAL;
>
> cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
> if (!cmd) {
> @@ -1526,22 +1526,23 @@ out_free:
> out:
> return ret;
> }
>
> static int wl1271_cmd_croc(struct wl1271 *wl, u8 role_id)
> {
> - struct wl1271_cmd_header *cmd;
> + struct wl1271_cmd_croc *cmd;
> int ret = 0;
>
> - wl1271_debug(DEBUG_CMD, "cmd croc");
> + wl1271_debug(DEBUG_CMD, "cmd croc (%d)", role_id);
>
> cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
> if (!cmd) {
> ret = -ENOMEM;
> goto out;
> }
> + cmd->role_id = role_id;
>
> ret = wl1271_cmd_send(wl, CMD_CANCEL_REMAIN_ON_CHANNEL, cmd,
> sizeof(*cmd), 0);
> if (ret < 0) {
> wl1271_error("failed to send ROC command");
> goto out_free;

Could you squash the changes to these two commands into the previous
patch?


> +int wl1271_roc(struct wl1271 *wl, u8 role_id)
> +{
> + int ret = 0;
> +
> + if (WARN_ON(test_bit(role_id, wl->roc_map)))
> + return 0;
> +
> + ret = wl1271_cmd_roc(wl, role_id);
> + if (ret < 0)
> + goto out;
> +
> + ret = wl1271_cmd_wait_for_event(wl,
> + REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID);
> + if (ret < 0) {
> + wl1271_error("cmd roc event completion error");
> + goto out;
> + }
> +
> + __set_bit(role_id, wl->roc_map);
> + set_bit(WL1271_FLAG_ROC, &wl->flags);

As I asked before, can we really be ROCed in more than one role at the
same time?

In any case, I don't think we need the WL1271_FLAG_ROC. Can't you just
check whether any of the roc_map bits is set instead?


> @@ -579,12 +581,19 @@ struct wl1271_cmd_roc {
> u8 role_id;
> u8 channel;
> u8 band;
> u8 padding;
> };
>
> +struct wl1271_cmd_croc {
> + struct wl1271_cmd_header header;
> +
> + u8 role_id;
> + u8 padding[3];
> +};
> +

Squash this one into patch 17 too, please.


> @@ -2211,24 +2196,23 @@ static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
> wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
> ACX_KEEP_ALIVE_TPL_INVALID);
> if (ret < 0)
> goto out;
> set_bit(WL1271_FLAG_IDLE, &wl->flags);
> } else {
> - /* increment the session counter */
> - wl->session_counter++;
> - if (wl->session_counter >= SESSION_COUNTER_MAX)
> - wl->session_counter = 0;
> -

Shouldn't this be session_counter change be squashed into patch 21?


> @@ -2762,16 +2769,26 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
> }
>
> ret = wl1271_ps_elp_wakeup(wl);
> if (ret < 0)
> goto out;
>
> - ret = wl1271_scan(hw->priv, ssid, len, req);
> + /* cancel ROC before scanning */
> + if (test_bit(WL1271_FLAG_ROC, &wl->flags)) {
> + if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
> + /* don't allow scanning right now (?) */
> + ret = -EBUSY;
> + goto out_sleep;
> + }

This would happen in the case of roaming, right? Please add a TODO or
FIXME instead of the (?) so that it's easier to grep later. ;)

> @@ -3378,13 +3421,35 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
> if (do_join) {
> ret = wl1271_join(wl, set_assoc);
> if (ret < 0) {
> wl1271_warning("cmd join failed %d", ret);
> goto out;
> }
> - wl1271_check_operstate(wl, ieee80211_get_operstate(vif));
> +
> + /* ROC until interface is up (after EAPOL exchange) */

Do you mean, "ROC until connected"?


> + if (!is_ibss) {
> + ret = wl1271_roc(wl, wl->role_id);
> + if (ret < 0)
> + goto out;
> +
> + wl1271_check_operstate(wl,
> + ieee80211_get_operstate(vif));
> + }


--
Cheers,
Luca.


2011-08-09 09:14:39

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 36/40] wl12xx: enable AP advanced functionality

From: Arik Nemtsov <[email protected]>

This adjusts FW TX block allocation for connected stations in PS.
Firmware congestion is measured in allocated packets instead of blocks.

Allow a link in PS to queue up to 2 packets to the FW.

Signed-off-by: Arik Nemtsov <[email protected]>
Signed-off-by: Eliad Peller <[email protected]>
---
drivers/net/wireless/wl12xx/main.c | 48 +++++++++++++++++-----------------
drivers/net/wireless/wl12xx/ps.c | 4 +-
drivers/net/wireless/wl12xx/tx.c | 19 +++++--------
drivers/net/wireless/wl12xx/wl12xx.h | 25 ++++++++++--------
4 files changed, 48 insertions(+), 48 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index c8e9ba6..9f60f0f 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -751,64 +751,73 @@ static int wl1271_plt_init(struct wl1271 *wl)
kfree(wl->target_mem_map);
wl->target_mem_map = NULL;

return ret;
}

-#if 0
-static void wl1271_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_blks)
+static void wl1271_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_pkts)
{
bool fw_ps;

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

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

/*
* Wake up from high level PS if the STA is asleep with too little
- * blocks in FW or if the STA is awake.
+ * packets in FW or if the STA is awake.
*/
- if (!fw_ps || tx_blks < WL1271_PS_STA_MAX_BLOCKS)
+ 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_blks >= WL1271_PS_STA_MAX_BLOCKS)
+ else if (fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
wl1271_ps_link_start(wl, hlid, true);
}

+bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid)
+{
+ int id = hlid - WL1271_AP_STA_HLID_START;
+ return test_bit(id, wl->ap_hlid_map);
+}
+
static void wl1271_irq_update_links_status(struct wl1271 *wl,
- struct wl1271_fw_ap_status *status)
+ struct wl1271_fw_status *status)
{
u32 cur_fw_ps_map;
- u8 hlid;
+ u8 hlid, cnt;
+
+ /* TODO: also use link_fast_bitmap here */

cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
if (wl->ap_fw_ps_map != cur_fw_ps_map) {
wl1271_debug(DEBUG_PSM,
"link ps prev 0x%x cur 0x%x changed 0x%x",
wl->ap_fw_ps_map, cur_fw_ps_map,
wl->ap_fw_ps_map ^ cur_fw_ps_map);

wl->ap_fw_ps_map = cur_fw_ps_map;
}

for (hlid = WL1271_AP_STA_HLID_START; hlid < AP_MAX_LINKS; hlid++) {
- u8 cnt = status->tx_lnk_free_blks[hlid] -
- wl->links[hlid].prev_freed_blks;
+ if (!wl1271_is_active_sta(wl, hlid))
+ continue;

- wl->links[hlid].prev_freed_blks =
- status->tx_lnk_free_blks[hlid];
- wl->links[hlid].allocated_blks -= cnt;
+ cnt = status->tx_lnk_free_pkts[hlid] -
+ wl->links[hlid].prev_freed_pkts;
+
+ wl->links[hlid].prev_freed_pkts =
+ status->tx_lnk_free_pkts[hlid];
+ wl->links[hlid].allocated_pkts -= cnt;

wl1271_irq_ps_regulate_link(wl, hlid,
- wl->links[hlid].allocated_blks);
+ wl->links[hlid].allocated_pkts);
}
}
-#endif

static void wl1271_fw_status(struct wl1271 *wl,
struct wl1271_fw_status *status)
{
struct timespec ts;
u32 old_tx_blk_count = wl->tx_blocks_available;
@@ -861,17 +870,14 @@ static void wl1271_fw_status(struct wl1271 *wl,

/* if more blocks are available now, tx work can be scheduled */
if (wl->tx_blocks_available > old_tx_blk_count)
clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);

/* for AP update num of allocated TX blocks per link and ps status */
- if (wl->bss_type == BSS_TYPE_AP_BSS) {
-#if 0
+ if (wl->bss_type == BSS_TYPE_AP_BSS)
wl1271_irq_update_links_status(wl, status);
-#endif
- }

/* update the host-chipset time offset */
getnstimeofday(&ts);
wl->time_offset = (timespec_to_ns(&ts) >> 10) -
(s64)le32_to_cpu(status->fw_localtime);
}
@@ -3676,18 +3682,12 @@ static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
wl->links[hlid].ba_bitmap = 0;
wl1271_tx_reset_link_queues(wl, hlid);
__clear_bit(hlid, &wl->ap_ps_map);
__clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
}

-bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid)
-{
- int id = hlid - WL1271_AP_STA_HLID_START;
- return test_bit(id, wl->ap_hlid_map);
-}
-
static int wl1271_op_sta_add(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
struct wl1271 *wl = hw->priv;
int ret = 0;
diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/ps.c
index 3548377..4b720b1 100644
--- a/drivers/net/wireless/wl12xx/ps.c
+++ b/drivers/net/wireless/wl12xx/ps.c
@@ -223,14 +223,14 @@ void wl1271_ps_link_start(struct wl1271 *wl, u8 hlid, bool clean_queues)
{
struct ieee80211_sta *sta;

if (test_bit(hlid, &wl->ap_ps_map))
return;

- wl1271_debug(DEBUG_PSM, "start mac80211 PSM on hlid %d blks %d "
- "clean_queues %d", hlid, wl->links[hlid].allocated_blks,
+ wl1271_debug(DEBUG_PSM, "start mac80211 PSM on hlid %d pkts %d "
+ "clean_queues %d", hlid, wl->links[hlid].allocated_pkts,
clean_queues);

rcu_read_lock();
sta = ieee80211_find_sta(wl->vif, wl->links[hlid].addr);
if (!sta) {
wl1271_error("could not find sta %pM for starting ps",
diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c
index d184da1..a180c16 100644
--- a/drivers/net/wireless/wl12xx/tx.c
+++ b/drivers/net/wireless/wl12xx/tx.c
@@ -120,33 +120,31 @@ static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl,
hdr = (struct ieee80211_hdr *)(skb->data +
sizeof(struct wl1271_tx_hw_descr));
if (ieee80211_is_auth(hdr->frame_control))
wl1271_acx_set_inconnection_sta(wl, hdr->addr1);
}

-#if 0
static void wl1271_tx_regulate_link(struct wl1271 *wl, u8 hlid)
{
bool fw_ps;
- u8 tx_blks;
+ u8 tx_pkts;

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

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

/*
* 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.
*/
- if (fw_ps && tx_blks >= WL1271_PS_STA_MAX_BLOCKS)
+ if (fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
wl1271_ps_link_start(wl, hlid, true);
}
-#endif

u8 wl1271_tx_get_hlid(struct wl1271 *wl, struct sk_buff *skb)
{
struct ieee80211_tx_info *control = IEEE80211_SKB_CB(skb);

if (control->control.sta) {
@@ -222,14 +220,15 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
wl->tx_blocks_available -= total_blocks;
wl->tx_allocated_blocks += total_blocks;

ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
wl->tx_allocated_pkts[ac]++;

- if (wl->bss_type == BSS_TYPE_AP_BSS)
- wl->links[hlid].allocated_blks += total_blocks;
+ if (wl->bss_type == BSS_TYPE_AP_BSS &&
+ hlid >= WL1271_AP_STA_HLID_START)
+ wl->links[hlid].allocated_pkts++;

ret = 0;

wl1271_debug(DEBUG_TX,
"tx_allocate: size: %d, blocks: %d, id: %d",
total_len, total_blocks, id);
@@ -406,15 +405,13 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb,
return ret;

wl1271_tx_fill_hdr(wl, skb, extra, info, hlid);

if (wl->bss_type == BSS_TYPE_AP_BSS) {
wl1271_tx_ap_update_inconnection_sta(wl, skb);
-#if 0
wl1271_tx_regulate_link(wl, hlid);
-#endif
} else {
wl1271_tx_update_filters(wl, skb);
}

/*
* The length of each packet is stored in terms of
@@ -876,14 +873,14 @@ void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
struct ieee80211_tx_info *info;

/* TX failure */
if (wl->bss_type == BSS_TYPE_AP_BSS) {
for (i = 0; i < AP_MAX_LINKS; i++) {
wl1271_tx_reset_link_queues(wl, i);
- wl->links[i].allocated_blks = 0;
- wl->links[i].prev_freed_blks = 0;
+ wl->links[i].allocated_pkts = 0;
+ wl->links[i].prev_freed_pkts = 0;
}

wl->last_tx_hlid = 0;
} else {
for (i = 0; i < NUM_TX_QUEUES; i++) {
while ((skb = skb_dequeue(&wl->tx_queue[i]))) {
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index c3996b2..2563201 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -149,21 +149,20 @@ extern u32 wl12xx_debug_level;
* TODO: we currently don't support multirole. remove
* this constant from the code when we do.
*/
#define WL1271_AP_STA_HLID_START 3

/*
- * When in AP-mode, we allow (at least) this number of mem-blocks
+ * When in AP-mode, we allow (at least) this number of packets
* to be transmitted to FW for a STA in PS-mode. Only when packets are
* present in the FW buffers it will wake the sleeping STA. We want to put
* enough packets for the driver to transmit all of its buffered data before
- * the STA goes to sleep again. But we don't want to take too much mem-blocks
+ * the STA goes to sleep again. But we don't want to take too much memory
* as it might hurt the throughput of active STAs.
- * The number of blocks (18) is enough for 2 large packets.
*/
-#define WL1271_PS_STA_MAX_BLOCKS (2 * 9)
+#define WL1271_PS_STA_MAX_PACKETS 2

#define WL1271_AP_BSS_INDEX 0
#define WL1271_AP_DEF_BEACON_EXP 20

#define ACX_TX_DESCRIPTORS 16

@@ -234,14 +233,18 @@ struct wl1271_stats {

#define NUM_TX_QUEUES 4
#define NUM_RX_PKT_DESC 8

#define AP_MAX_STATIONS 5

-/* Broadcast and Global links + links to stations */
-#define AP_MAX_LINKS (AP_MAX_STATIONS + 2)
+/* 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)

/* FW status registers */
struct wl1271_fw_status {
__le32 intr;
u8 fw_rx_counter;
u8 drv_rx_counter;
@@ -268,14 +271,14 @@ struct wl1271_fw_status {
/* Size (in Memory Blocks) of TX pool */
__le32 tx_total;

/* Cumulative counter of released packets per AC */
u8 tx_released_pkts[NUM_TX_QUEUES];

- /* Cumulative counter of freed MBs per HLID */
- u8 tx_lnk_free_blks[WL1271_MAX_LINKS];
+ /* Cumulative counter of freed packets per HLID */
+ u8 tx_lnk_free_pkts[WL1271_MAX_LINKS];

/* Cumulative counter of released Voice memory blocks */
u8 tx_voice_released_blks;
u8 padding_1[7];
__le32 log_start_addr;
} __packed;
@@ -349,15 +352,15 @@ enum wl12xx_flags {
};

struct wl1271_link {
/* AP-mode - TX queue per AC in link */
struct sk_buff_head tx_queue[NUM_TX_QUEUES];

- /* accounting for allocated / available TX blocks in FW */
- u8 allocated_blks;
- u8 prev_freed_blks;
+ /* accounting for allocated / freed packets in FW */
+ u8 allocated_pkts;
+ u8 prev_freed_pkts;

u8 addr[ETH_ALEN];

/* bitmap of TIDs where RX BA sessions are active for this link */
u8 ba_bitmap;
};
--
1.7.6.401.g6a319


2011-08-10 11:54:11

by Luciano Coelho

[permalink] [raw]
Subject: Re: [PATCH 10/40] wl12xx: add device role commands

On Tue, 2011-08-09 at 12:13 +0300, Eliad Peller wrote:
> The device role is a special role used for rx and tx frames
> prior to association (as the STA role can get packets only
> from its associated bssid)
>
> Since this role is required for the sta association process,
> we enable it when a new sta interface is created.
>
> Signed-off-by: Eliad Peller <[email protected]>
> ---

This patch looks fine, except for the relevant s/wl1271/wl12xx/. And it
would also be good if you could add some comments in the code about what
this device role is about. Something similar to the commit description
here would be good.

--
Cheers,
Luca.


2011-08-11 16:11:37

by Arik Nemtsov

[permalink] [raw]
Subject: Re: [PATCH 33/40] wl12xx: track freed packets in FW by AC

On Thu, Aug 11, 2011 at 12:41, Eliad Peller <[email protected]> wrote:
>>> + ? ? for (i = 0; i < NUM_TX_QUEUES; i++) {
>>> + ? ? ? ? ? ? /* prevent wrap-around in freed-packets counter */
>>> + ? ? ? ? ? ? wl->tx_allocated_pkts -=
>>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? (status->tx_released_pkts[i] -
>>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? wl->tx_pkts_freed[i] + 256) % 256;
>>
>> Isn't the "+ 256" useless here, since you'll mod the result anyway?
>>
> modulus of negative numbers is not well defined.
>
> Eliad.
> --
> To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
> the body of a message to [email protected]
> More majordomo info at ?http://vger.kernel.org/majordomo-info.html
>

Actually (As pointed out by Ido) the whole (x+256) % 256 sequence can
be replaced by (x & 0xFF). I suspect the assembly code already
reflects this fact, but we can change it anyway.

Arik

2011-08-11 11:57:23

by Luciano Coelho

[permalink] [raw]
Subject: Re: [PATCH 00/40] wl12xx: move to wl12xx-fw-3

On Tue, 2011-08-09 at 12:13 +0300, Eliad Peller wrote:
> The new wl12xx fw (ver 7.3.0.0.75) had some major api changes.
> The main change was the addition of multi-role concept, which
> will later allow using multiple vifs concurrently.
>
> Consequently, this design change caused api changes for most
> of the api commands, as a new role_id had to be added.
>
> This patchset migrates the fw to use the new fw api (a new
> fw filename is used, as there is no backward compatability
> with older firmwares).

Okay, I'm done with my review! Lots of small nitpicking, but this in
general looks very good! Thanks a lot for the good work, guys!


--
Cheers,
Luca.


2011-08-09 19:12:06

by Luciano Coelho

[permalink] [raw]
Subject: Re: [PATCH 06/40] wl12xx: wl12xx-fw-3 - Update fw status struct

On Tue, 2011-08-09 at 12:13 +0300, Eliad Peller wrote:
> diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
> index a1608f1..1ac1762 100644
> --- a/drivers/net/wireless/wl12xx/main.c
> +++ b/drivers/net/wireless/wl12xx/main.c
> @@ -824,71 +824,57 @@ static void wl1271_irq_update_links_status(struct wl1271 *wl,
> wl->links[hlid].allocated_blks);
> }
> }
> #endif
>
> static void wl1271_fw_status(struct wl1271 *wl,
> - struct wl1271_fw_full_status *full_status)
> + struct wl1271_fw_status *status)

Can you change this function to wl12xx_fw_status(), as we discussed
before, to slowly move into using wl12xx instead of wl1271?


> @@ -1167,13 +1153,13 @@ static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
> */
> if (!wl1271_ps_elp_wakeup(wl))
> wl12xx_cmd_stop_fwlog(wl);
>
> /* Read the first memory block address */
> wl1271_fw_status(wl, wl->fw_status);
> - first_addr = __le32_to_cpu(wl->fw_status->sta.log_start_addr);
> + first_addr = __le32_to_cpu(wl->fw_status->log_start_addr);

why do you have to use __le32_to_cpu() here instead of le32_to_cpu()?


> diff --git a/drivers/net/wireless/wl12xx/rx.c b/drivers/net/wireless/wl12xx/rx.c
> index 1a957d6..4ed23a1 100644
> --- a/drivers/net/wireless/wl12xx/rx.c
> +++ b/drivers/net/wireless/wl12xx/rx.c
> @@ -27,20 +27,20 @@
> #include "wl12xx.h"
> #include "acx.h"
> #include "reg.h"
> #include "rx.h"
> #include "io.h"
>
> -static u8 wl1271_rx_get_mem_block(struct wl1271_fw_common_status *status,
> +static u8 wl1271_rx_get_mem_block(struct wl1271_fw_status *status,
> u32 drv_rx_counter)

Again, please s/wl1271/wl12xx/ in the function names.



> {
> return le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]) &
> RX_MEM_BLOCK_MASK;
> }
>
> -static u32 wl1271_rx_get_buf_size(struct wl1271_fw_common_status *status,
> +static u32 wl1271_rx_get_buf_size(struct wl1271_fw_status *status,
> u32 drv_rx_counter)

Same as above.


> @@ -160,13 +160,13 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length)
> skb_queue_tail(&wl->deferred_rx_queue, skb);
> queue_work(wl->freezable_wq, &wl->netstack_work);
>
> return is_data;
> }
>
> -void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status)
> +void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status)
> {

Same thing.


> diff --git a/drivers/net/wireless/wl12xx/rx.h b/drivers/net/wireless/wl12xx/rx.h
> index 094fff8..5ca482b 100644
> --- a/drivers/net/wireless/wl12xx/rx.h
> +++ b/drivers/net/wireless/wl12xx/rx.h
> @@ -124,10 +124,10 @@ struct wl1271_rx_descriptor {
> u8 hlid; /* AP FW */
> } __packed;
> u8 pad_len;
> u8 reserved;
> } __packed;
>
> -void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status);
> +void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status);

Ditto.


> diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
> index 360f3d2..260b78c 100644
> --- a/drivers/net/wireless/wl12xx/wl12xx.h
> +++ b/drivers/net/wireless/wl12xx/wl12xx.h
> @@ -134,12 +134,13 @@ extern u32 wl12xx_debug_level;
> #define WL1271_ELP_HW_STATE_ASLEEP 0
> #define WL1271_ELP_HW_STATE_IRQ 1
>
> #define WL1271_DEFAULT_BEACON_INT 100
> #define WL1271_DEFAULT_DTIM_PERIOD 1
>
> +#define WL1271_MAX_LINKS 8

Can we use WL12XX_MAX_LINKS here too?


> @@ -227,59 +228,51 @@ struct wl1271_stats {
>
> #define AP_MAX_STATIONS 5
>
> /* Broadcast and Global links + links to stations */
> #define AP_MAX_LINKS (AP_MAX_STATIONS + 2)
>
> -/* FW status registers common for AP/STA */
> -struct wl1271_fw_common_status {
> +/* FW status registers */
> +struct wl1271_fw_status {

Same thing here, can we change this to wl12xx_fw_status?


--
Cheers,
Luca.


2011-08-11 12:30:04

by Eliad Peller

[permalink] [raw]
Subject: Re: [PATCH 37/40] wl12xx: don't wait for disconnection event

On Thu, Aug 11, 2011 at 2:53 PM, Luciano Coelho <[email protected]> wrote:
> On Tue, 2011-08-09 at 12:13 +0300, Eliad Peller wrote:
>> Sometimes the fw doesn't send the DISCONNECT_EVENT_COMPLETE_ID
>> on station role stop, so don't wait for it.
>
> Why? A bug? Or any good reason for it?
>
i'm still waiting for a definite answer answer from the fw guys about
the expected behavior.

>
>> diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c
>> index 9ef8621..ad926d2 100644
>> --- a/drivers/net/wireless/wl12xx/cmd.c
>> +++ b/drivers/net/wireless/wl12xx/cmd.c
>> @@ -640,18 +640,12 @@ int wl1271_cmd_role_stop_sta(struct wl1271 *wl)
>> ? ? ? ret = wl1271_cmd_send(wl, CMD_ROLE_STOP, cmd, sizeof(*cmd), 0);
>> ? ? ? if (ret < 0) {
>> ? ? ? ? ? ? ? wl1271_error("failed to initiate cmd role stop");
>> ? ? ? ? ? ? ? goto out_free;
>> ? ? ? }
>>
>> - ? ? ret = wl1271_cmd_wait_for_event(wl, DISCONNECT_EVENT_COMPLETE_ID);
>> - ? ? if (ret < 0) {
>> - ? ? ? ? ? ? wl1271_error("cmd role stop sta event completion error");
>> - ? ? ? ? ? ? goto out_free;
>> - ? ? }
>> -
>
> Can't this cause possible race conditions in the firmware if, for
> instance, we stop and start the sta role quickly?
>
according to the fw guys, it should work.

Eliad.

2011-08-09 09:14:11

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 21/40] wl12xx: fix session counter

From: Arik Nemtsov <[email protected]>

Increment the session counter on every join command.

Signed-off-by: Arik Nemtsov <[email protected]>
Signed-off-by: Eliad Peller <[email protected]>
---
drivers/net/wireless/wl12xx/cmd.c | 12 +++++++++++-
drivers/net/wireless/wl12xx/main.c | 1 +
2 files changed, 12 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c
index 918c46b..3bbee10 100644
--- a/drivers/net/wireless/wl12xx/cmd.c
+++ b/drivers/net/wireless/wl12xx/cmd.c
@@ -455,12 +455,22 @@ static void wl1271_free_link(struct wl1271 *wl, u8 *hlid)
return;

__clear_bit(*hlid, wl->links_map);
*hlid = WL1271_INVALID_LINK_ID;
}

+static int wl1271_get_new_session_id(struct wl1271 *wl)
+{
+ if (wl->session_counter >= SESSION_COUNTER_MAX)
+ wl->session_counter = 0;
+
+ wl->session_counter++;
+
+ return wl->session_counter;
+}
+
int wl1271_cmd_role_start_dev(struct wl1271 *wl)
{
struct wl1271_cmd_role_start *cmd;
int ret;

cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
@@ -577,13 +587,13 @@ int wl1271_cmd_role_start_sta(struct wl1271 *wl)
if (wl->sta_hlid == WL1271_INVALID_LINK_ID) {
ret = wl1271_allocate_link(wl, &wl->sta_hlid);
if (ret)
goto out_free;
}
cmd->sta.hlid = wl->sta_hlid;
- cmd->sta.session = wl->session_counter;
+ cmd->sta.session = wl1271_get_new_session_id(wl);
cmd->sta.remote_rates = cpu_to_le32(wl->rate_set);

wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d "
"basic_rate_set: 0x%x, remote_rates: 0x%x",
wl->role_id, cmd->sta.hlid, cmd->sta.session,
wl->basic_rate_set, wl->rate_set);
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index 9fed917..ea4e89f 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -4414,12 +4414,13 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
wl->tx_security_last_seq_lsb = 0;
wl->role_id = WL1271_INVALID_ROLE_ID;
wl->system_hlid = WL1271_SYSTEM_HLID;
wl->sta_hlid = WL1271_INVALID_LINK_ID;
wl->dev_role_id = WL1271_INVALID_ROLE_ID;
wl->dev_hlid = WL1271_INVALID_LINK_ID;
+ wl->session_counter = 0;
setup_timer(&wl->rx_streaming_timer, wl1271_rx_streaming_timer,
(unsigned long) wl);
wl->fwlog_size = 0;
init_waitqueue_head(&wl->fwlog_waitq);

memset(wl->links_map, 0, sizeof(wl->links_map));
--
1.7.6.401.g6a319


2011-08-10 19:54:37

by Luciano Coelho

[permalink] [raw]
Subject: Re: [PATCH 23/40] wl12xx: re-enable block ack session support

On Tue, 2011-08-09 at 12:13 +0300, Eliad Peller wrote:
> diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c
> index 6885568..02b9c7e 100644
> --- a/drivers/net/wireless/wl12xx/acx.c
> +++ b/drivers/net/wireless/wl12xx/acx.c
> @@ -1320,25 +1320,21 @@ int wl1271_acx_set_ht_capabilities(struct wl1271 *wl,
> acx = kzalloc(sizeof(*acx), GFP_KERNEL);
> if (!acx) {
> ret = -ENOMEM;
> goto out;
> }
>
> - /* Allow HT Operation ? */
> if (allow_ht_operation) {
> - ht_capabilites =
> - WL1271_ACX_FW_CAP_HT_OPERATION;
> - if (ht_cap->cap & IEEE80211_HT_CAP_GRN_FLD)
> - ht_capabilites |=
> - WL1271_ACX_FW_CAP_GREENFIELD_FRAME_FORMAT;
> - if (ht_cap->cap & IEEE80211_HT_CAP_SGI_20)
> - ht_capabilites |=
> - WL1271_ACX_FW_CAP_SHORT_GI_FOR_20MHZ_PACKETS;
> - if (ht_cap->cap & IEEE80211_HT_CAP_LSIG_TXOP_PROT)
> - ht_capabilites |=
> - WL1271_ACX_FW_CAP_LSIG_TXOP_PROTECTION;
> + /* no need to translate capabilities - use the spec values */
> + ht_capabilites = ht_cap->cap;
> +
> + /*
> + * this bit is not employed by the spec but only by FW to
> + * indicate peer HT support
> + */
> + ht_capabilites |= WL12XX_HT_CAP_HT_OPERRATION;

Typo, OPERATION.


> /* setup BA session receiver setting in the FW. */
> -int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn,
> - bool enable)
> +int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index,
> + u16 ssn, bool enable, u8 peer_hlid)

Indentation.


> - /* Single link for now */
> - acx->link_id = 1;
> + acx->hlid = peer_hlid;
> acx->tid = tid_index;
> acx->enable = enable;
> - acx->win_size = 0;
> + acx->win_size = RX_BA_WIN_SIZE;

Shouldn't we put this one in the conf structure as well?


> diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h
> index ac6194e..ba70f38 100644
> --- a/drivers/net/wireless/wl12xx/acx.h
> +++ b/drivers/net/wireless/wl12xx/acx.h
> @@ -894,33 +894,26 @@ struct wl1271_acx_rssi_snr_avg_weights {
> u8 rssi_beacon;
> u8 rssi_data;
> u8 snr_beacon;
> u8 snr_data;
> };
>
> +
> +/* special capability bit (not employed by the 802.11n spec) */
> +#define WL12XX_HT_CAP_HT_OPERRATION BIT(16)

Same typo as earlier.


> @@ -1215,13 +1191,13 @@ enum {
> ACX_FRAG_CFG = 0x004F,
> ACX_BET_ENABLE = 0x0050,
> ACX_RSSI_SNR_TRIGGER = 0x0051,
> ACX_RSSI_SNR_WEIGHTS = 0x0052,
> ACX_KEEP_ALIVE_MODE = 0x0053,
> ACX_SET_KEEP_ALIVE_CONFIG = 0x0054,
> - ACX_BA_SESSION_POLICY_CFG = 0x0055,
> + ACX_BA_SESSION_INITIATOR_POLICY = 0x0055,

Use ACX_BA_SESSION_INIT_POLICY to keep it small. Unless you want to
realign all the values.


> @@ -1295,17 +1271,15 @@ int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, bool enable,
> int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl);
> int wl1271_acx_set_ht_capabilities(struct wl1271 *wl,
> struct ieee80211_sta_ht_cap *ht_cap,
> bool allow_ht_operation);
> int wl1271_acx_set_ht_information(struct wl1271 *wl,
> u16 ht_operation_mode);
> -int wl1271_acx_set_ba_session(struct wl1271 *wl,
> - enum ieee80211_back_parties direction,
> - u8 tid_index, u8 policy);
> -int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn,
> - bool enable);
> +int wl1271_acx_set_ba_initiator_policy(struct wl1271 *wl);
> +int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index,
> + u16 ssn, bool enable, u8 peer_hlid);

Indentation.


--
Cheers,
Luca.


2011-08-09 09:14:29

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 31/40] wl12xx: use ap_bcast_hlid for recorded keys

when the key was recorded, wl->ap_bcast_hlid was invalid
(since the role wasn't started), so when configuring the
key we need to use the current ap_bcast_hlid.

Signed-off-by: Eliad Peller <[email protected]>
---
drivers/net/wireless/wl12xx/main.c | 7 ++++++-
1 files changed, 6 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index 5d5ace8..c873f24 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -2498,20 +2498,25 @@ static int wl1271_ap_init_hwenc(struct wl1271 *wl)
{
int i, ret = 0;
struct wl1271_ap_key *key;
bool wep_key_added = false;

for (i = 0; i < MAX_NUM_KEYS; i++) {
+ u8 hlid;
if (wl->recorded_ap_keys[i] == NULL)
break;

key = wl->recorded_ap_keys[i];
+ hlid = key->hlid;
+ if (hlid == WL1271_INVALID_LINK_ID)
+ hlid = wl->ap_bcast_hlid;
+
ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
key->id, key->key_type,
key->key_size, key->key,
- key->hlid, key->tx_seq_32,
+ hlid, key->tx_seq_32,
key->tx_seq_16);
if (ret < 0)
goto out;

if (key->key_type == KEY_WEP)
wep_key_added = true;
--
1.7.6.401.g6a319


2011-08-09 09:13:47

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 08/40] wl12xx: wl12xx-fw-3 - update commands & events

Change the commands and events according to the new fw api.

The main change is the replacement of JOIN/DISCONNECT commands,
with ROLE_START/ROLE_START commands.

The use of these commands should be preceded by the ROLE_ENABLE
command (allocating role resources), and followed by the
ROLE_DISABLE command (freeing role resources).

Signed-off-by: Eliad Peller <[email protected]>
---
drivers/net/wireless/wl12xx/boot.c | 13 +-
drivers/net/wireless/wl12xx/cmd.c | 503 ++++++++++++++++++++--------------
drivers/net/wireless/wl12xx/cmd.h | 320 ++++++++++++----------
drivers/net/wireless/wl12xx/event.c | 4 +-
drivers/net/wireless/wl12xx/event.h | 83 +++----
drivers/net/wireless/wl12xx/init.c | 6 -
drivers/net/wireless/wl12xx/main.c | 26 +-
drivers/net/wireless/wl12xx/tx.c | 5 +-
drivers/net/wireless/wl12xx/wl12xx.h | 5 +
9 files changed, 530 insertions(+), 435 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c
index 11b26d7..7d8d09b 100644
--- a/drivers/net/wireless/wl12xx/boot.c
+++ b/drivers/net/wireless/wl12xx/boot.c
@@ -501,27 +501,26 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
*/

/* unmask required mbox events */
wl->event_mask = BSS_LOSE_EVENT_ID |
SCAN_COMPLETE_EVENT_ID |
PS_REPORT_EVENT_ID |
- JOIN_EVENT_COMPLETE_ID |
DISCONNECT_EVENT_COMPLETE_ID |
RSSI_SNR_TRIGGER_0_EVENT_ID |
PSPOLL_DELIVERY_FAILURE_EVENT_ID |
SOFT_GEMINI_SENSE_EVENT_ID |
PERIODIC_SCAN_REPORT_EVENT_ID |
- PERIODIC_SCAN_COMPLETE_EVENT_ID;
+ PERIODIC_SCAN_COMPLETE_EVENT_ID |
+ DUMMY_PACKET_EVENT_ID |
+ PEER_REMOVE_COMPLETE_EVENT_ID |
+ BA_SESSION_RX_CONSTRAINT_EVENT_ID |
+ REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID;

if (wl->bss_type == BSS_TYPE_AP_BSS)
- wl->event_mask |= STA_REMOVE_COMPLETE_EVENT_ID |
- INACTIVE_STA_EVENT_ID |
+ wl->event_mask |= INACTIVE_STA_EVENT_ID |
MAX_TX_RETRY_EVENT_ID;
- else
- wl->event_mask |= DUMMY_PACKET_EVENT_ID |
- BA_SESSION_RX_CONSTRAINT_EVENT_ID;

ret = wl1271_event_unmask(wl);
if (ret < 0) {
wl1271_error("EVENT mask setting failed");
return ret;
}
diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c
index b6ef65a..99d81b6 100644
--- a/drivers/net/wireless/wl12xx/cmd.c
+++ b/drivers/net/wireless/wl12xx/cmd.c
@@ -360,67 +360,300 @@ static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask)
return ret;
}

return 0;
}

-int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type)
+int wl1271_cmd_role_enable(struct wl1271 *wl, u8 role_type, u8 *role_id)
{
- struct wl1271_cmd_join *join;
- int ret, i;
- u8 *bssid;
+ struct wl1271_cmd_role_enable *cmd;
+ int ret;
+
+ wl1271_debug(DEBUG_CMD, "cmd role enable");
+
+ if (WARN_ON(*role_id != WL1271_INVALID_ROLE_ID))
+ return -EINVAL;

- join = kzalloc(sizeof(*join), GFP_KERNEL);
- if (!join) {
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
ret = -ENOMEM;
goto out;
}

- wl1271_debug(DEBUG_CMD, "cmd join");
+ /* get role id */
+ cmd->role_id = find_first_zero_bit(wl->roles_map, WL1271_MAX_ROLES);
+ if (cmd->role_id >= WL1271_MAX_ROLES) {
+ ret = -EBUSY;
+ goto out_free;
+ }
+
+ memcpy(cmd->mac_address, wl->mac_addr, ETH_ALEN);
+ cmd->role_type = role_type;

- /* Reverse order BSSID */
- bssid = (u8 *) &join->bssid_lsb;
- for (i = 0; i < ETH_ALEN; i++)
- bssid[i] = wl->bssid[ETH_ALEN - i - 1];
+ ret = wl1271_cmd_send(wl, CMD_ROLE_ENABLE, cmd, sizeof(*cmd), 0);
+ if (ret < 0) {
+ wl1271_error("failed to initiate cmd role enable");
+ goto out_free;
+ }
+
+ __set_bit(cmd->role_id, wl->roles_map);
+ *role_id = cmd->role_id;
+
+out_free:
+ kfree(cmd);
+
+out:
+ return ret;
+}

- join->bss_type = bss_type;
- join->basic_rate_set = cpu_to_le32(wl->basic_rate_set);
- join->supported_rate_set = cpu_to_le32(wl->rate_set);
+int wl1271_cmd_role_disable(struct wl1271 *wl, u8 *role_id)
+{
+ struct wl1271_cmd_role_disable *cmd;
+ int ret;
+
+ wl1271_debug(DEBUG_CMD, "cmd role disable");
+
+ if (WARN_ON(*role_id == WL1271_INVALID_ROLE_ID))
+ return -EINVAL;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ cmd->role_id = *role_id;
+
+ ret = wl1271_cmd_send(wl, CMD_ROLE_DISABLE, cmd, sizeof(*cmd), 0);
+ if (ret < 0) {
+ wl1271_error("failed to initiate cmd role disable");
+ goto out_free;
+ }
+
+ __clear_bit(*role_id, wl->roles_map);
+ *role_id = WL1271_INVALID_ROLE_ID;
+
+out_free:
+ kfree(cmd);

+out:
+ return ret;
+}
+
+static int wl1271_allocate_link(struct wl1271 *wl, u8 *hlid)
+{
+ u8 alloced = find_first_zero_bit(wl->links_map, WL1271_MAX_LINKS);
+ if (alloced >= WL1271_MAX_LINKS)
+ return -EBUSY;
+
+ __set_bit(alloced, wl->links_map);
+ *hlid = alloced;
+ return 0;
+}
+
+static void wl1271_free_link(struct wl1271 *wl, u8 *hlid)
+{
+ if (*hlid == WL1271_INVALID_LINK_ID)
+ return;
+
+ __clear_bit(*hlid, wl->links_map);
+ *hlid = WL1271_INVALID_LINK_ID;
+}
+
+int wl1271_cmd_role_start_sta(struct wl1271 *wl)
+{
+ struct wl1271_cmd_role_start *cmd;
+ int ret;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ wl1271_debug(DEBUG_CMD, "cmd role start sta %d", wl->role_id);
+
+ cmd->role_id = wl->role_id;
if (wl->band == IEEE80211_BAND_5GHZ)
- join->bss_type |= WL1271_JOIN_CMD_BSS_TYPE_5GHZ;
+ cmd->band |= WL1271_BAND_5GHZ;
+ cmd->channel = wl->channel;
+ cmd->sta.basic_rate_set = cpu_to_le32(wl->basic_rate_set);
+ cmd->sta.beacon_interval = cpu_to_le16(wl->beacon_int);
+ cmd->sta.ssid_type = WL1271_SSID_TYPE_ANY;
+ cmd->sta.ssid_len = wl->ssid_len;
+ memcpy(cmd->sta.ssid, wl->ssid, wl->ssid_len);
+ memcpy(cmd->sta.bssid, wl->bssid, ETH_ALEN);
+ cmd->sta.local_rates = cpu_to_le32(wl->rate_set);
+
+ if (wl->sta_hlid == WL1271_INVALID_LINK_ID) {
+ ret = wl1271_allocate_link(wl, &wl->sta_hlid);
+ if (ret)
+ goto out_free;
+ }
+ cmd->sta.hlid = wl->sta_hlid;
+ cmd->sta.session = wl->session_counter;
+ cmd->sta.remote_rates = cpu_to_le32(wl->rate_set);
+
+ wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d "
+ "basic_rate_set: 0x%x, remote_rates: 0x%x",
+ wl->role_id, cmd->sta.hlid, cmd->sta.session,
+ wl->basic_rate_set, wl->rate_set);
+
+ ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0);
+ if (ret < 0) {
+ wl1271_error("failed to initiate cmd role start sta");
+ goto err_hlid;
+ }

- join->beacon_interval = cpu_to_le16(wl->beacon_int);
- join->dtim_interval = WL1271_DEFAULT_DTIM_PERIOD;
+ goto out_free;

- join->channel = wl->channel;
- join->ssid_len = wl->ssid_len;
- memcpy(join->ssid, wl->ssid, wl->ssid_len);
+err_hlid:
+ /* clear links on error. */
+ wl1271_free_link(wl, &wl->sta_hlid);

- join->ctrl |= wl->session_counter << WL1271_JOIN_CMD_TX_SESSION_OFFSET;
+out_free:
+ kfree(cmd);

- wl1271_debug(DEBUG_CMD, "cmd join: basic_rate_set=0x%x, rate_set=0x%x",
- join->basic_rate_set, join->supported_rate_set);
+out:
+ return ret;
+}

- ret = wl1271_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join), 0);
+int wl1271_cmd_role_stop_sta(struct wl1271 *wl)
+{
+ struct wl1271_cmd_role_stop *cmd;
+ int ret;
+
+ if (WARN_ON(wl->sta_hlid == WL1271_INVALID_LINK_ID))
+ return -EINVAL;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ wl1271_debug(DEBUG_CMD, "cmd role stop");
+
+ cmd->role_id = wl->role_id;
+ cmd->disc_type = WL1271_DISC_IMMEDIATE;
+ cmd->reason = cpu_to_le16(1); /* STATUS_UNSPECIFIED */
+
+ ret = wl1271_cmd_send(wl, CMD_ROLE_STOP, cmd, sizeof(*cmd), 0);
if (ret < 0) {
- wl1271_error("failed to initiate cmd join");
+ wl1271_error("failed to initiate cmd role stop");
goto out_free;
}

- ret = wl1271_cmd_wait_for_event(wl, JOIN_EVENT_COMPLETE_ID);
- if (ret < 0)
- wl1271_error("cmd join event completion error");
+ ret = wl1271_cmd_wait_for_event(wl, DISCONNECT_EVENT_COMPLETE_ID);
+ if (ret < 0) {
+ wl1271_error("cmd role stop sta event completion error");
+ goto out_free;
+ }
+
+ wl1271_free_link(wl, &wl->sta_hlid);
+
+out_free:
+ kfree(cmd);
+
+out:
+ return ret;
+}
+
+int wl1271_cmd_role_start_ap(struct wl1271 *wl)
+{
+ struct wl1271_cmd_role_start *cmd;
+ struct ieee80211_bss_conf *bss_conf = &wl->vif->bss_conf;
+ int ret;
+
+ wl1271_debug(DEBUG_CMD, "cmd start ap role");
+
+ /*
+ * We currently do not support hidden SSID. The real SSID
+ * should be fetched from mac80211 first.
+ */
+ if (wl->ssid_len == 0) {
+ wl1271_warning("Hidden SSID currently not supported for AP");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ cmd->role_id = wl->role_id;
+ cmd->ap.aging_period = cpu_to_le16(wl->conf.tx.ap_aging_period);
+ cmd->ap.bss_index = WL1271_AP_BSS_INDEX;
+ cmd->ap.global_hlid = WL1271_AP_GLOBAL_HLID;
+ cmd->ap.broadcast_hlid = WL1271_AP_BROADCAST_HLID;
+ cmd->ap.basic_rate_set = cpu_to_le32(wl->basic_rate_set);
+ cmd->ap.beacon_interval = cpu_to_le16(wl->beacon_int);
+ cmd->ap.dtim_interval = bss_conf->dtim_period;
+ cmd->ap.beacon_expiry = WL1271_AP_DEF_BEACON_EXP;
+ cmd->channel = wl->channel;
+ cmd->ap.ssid_len = wl->ssid_len;
+ cmd->ap.ssid_type = WL1271_SSID_TYPE_PUBLIC;
+ memcpy(cmd->ap.ssid, wl->ssid, wl->ssid_len);
+ cmd->ap.local_rates = cpu_to_le32(0xffffffff);
+
+ switch (wl->band) {
+ case IEEE80211_BAND_2GHZ:
+ cmd->band = RADIO_BAND_2_4GHZ;
+ break;
+ case IEEE80211_BAND_5GHZ:
+ cmd->band = RADIO_BAND_5GHZ;
+ break;
+ default:
+ wl1271_warning("ap start - unknown band: %d", (int)wl->band);
+ cmd->band = RADIO_BAND_2_4GHZ;
+ break;
+ }
+
+ ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0);
+ if (ret < 0) {
+ wl1271_error("failed to initiate cmd start bss");
+ goto out_free;
+ }

out_free:
- kfree(join);
+ kfree(cmd);

out:
return ret;
}

+int wl1271_cmd_role_stop_ap(struct wl1271 *wl)
+{
+ struct wl1271_cmd_role_stop *cmd;
+ int ret;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ wl1271_debug(DEBUG_CMD, "cmd role ap stop");
+
+ cmd->role_id = wl->role_id;
+
+ ret = wl1271_cmd_send(wl, CMD_ROLE_STOP, cmd, sizeof(*cmd), 0);
+ if (ret < 0) {
+ wl1271_error("failed to initiate cmd role ap stop");
+ goto out_free;
+ }
+
+out_free:
+ kfree(cmd);
+
+out:
+ return ret;
+}
+
+
/**
* send test command to firmware
*
* @wl: wl struct
* @buf: buffer containing the command, with all headers, must work with dma
* @len: length of the buffer
@@ -562,12 +795,13 @@ int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode)
ps_params = kzalloc(sizeof(*ps_params), GFP_KERNEL);
if (!ps_params) {
ret = -ENOMEM;
goto out;
}

+ ps_params->role_id = wl->role_id;
ps_params->ps_mode = ps_mode;

ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params,
sizeof(*ps_params), 0);
if (ret < 0) {
wl1271_error("cmd set_ps_mode failed");
@@ -808,63 +1042,34 @@ int wl1271_build_qos_null_data(struct wl1271 *wl)

return wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, &template,
sizeof(template), 0,
wl->basic_rate);
}

-int wl1271_cmd_set_sta_default_wep_key(struct wl1271 *wl, u8 id)
+int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id, u8 hlid)
{
- struct wl1271_cmd_set_sta_keys *cmd;
+ struct wl1271_cmd_set_keys *cmd;
int ret = 0;

wl1271_debug(DEBUG_CMD, "cmd set_default_wep_key %d", id);

cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
ret = -ENOMEM;
goto out;
}

- cmd->id = id;
- cmd->key_action = cpu_to_le16(KEY_SET_ID);
- cmd->key_type = KEY_WEP;
-
- ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0);
- if (ret < 0) {
- wl1271_warning("cmd set_default_wep_key failed: %d", ret);
- goto out;
- }
-
-out:
- kfree(cmd);
-
- return ret;
-}
-
-int wl1271_cmd_set_ap_default_wep_key(struct wl1271 *wl, u8 id)
-{
- struct wl1271_cmd_set_ap_keys *cmd;
- int ret = 0;
-
- wl1271_debug(DEBUG_CMD, "cmd set_ap_default_wep_key %d", id);
-
- cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
- if (!cmd) {
- ret = -ENOMEM;
- goto out;
- }
-
- cmd->hlid = WL1271_AP_BROADCAST_HLID;
+ cmd->hlid = hlid;
cmd->key_id = id;
cmd->lid_key_type = WEP_DEFAULT_LID_TYPE;
cmd->key_action = cpu_to_le16(KEY_SET_ID);
cmd->key_type = KEY_WEP;

ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0);
if (ret < 0) {
- wl1271_warning("cmd set_ap_default_wep_key failed: %d", ret);
+ wl1271_warning("cmd set_default_wep_key failed: %d", ret);
goto out;
}

out:
kfree(cmd);

@@ -872,35 +1077,38 @@ out:
}

int wl1271_cmd_set_sta_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
u8 key_size, const u8 *key, const u8 *addr,
u32 tx_seq_32, u16 tx_seq_16)
{
- struct wl1271_cmd_set_sta_keys *cmd;
+ struct wl1271_cmd_set_keys *cmd;
int ret = 0;

cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
ret = -ENOMEM;
goto out;
}

- if (key_type != KEY_WEP)
- memcpy(cmd->addr, addr, ETH_ALEN);
+ cmd->hlid = wl->sta_hlid;
+
+ if (key_type == KEY_WEP)
+ cmd->lid_key_type = WEP_DEFAULT_LID_TYPE;
+ else if (is_broadcast_ether_addr(addr))
+ cmd->lid_key_type = BROADCAST_LID_TYPE;
+ else
+ cmd->lid_key_type = UNICAST_LID_TYPE;

cmd->key_action = cpu_to_le16(action);
cmd->key_size = key_size;
cmd->key_type = key_type;

cmd->ac_seq_num16[0] = cpu_to_le16(tx_seq_16);
cmd->ac_seq_num32[0] = cpu_to_le32(tx_seq_32);

- /* we have only one SSID profile */
- cmd->ssid_profile = 0;
-
- cmd->id = id;
+ cmd->key_id = id;

if (key_type == KEY_TKIP) {
/*
* We get the key in the following form:
* TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes)
* but the target is expecting:
@@ -925,17 +1133,21 @@ int wl1271_cmd_set_sta_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
out:
kfree(cmd);

return ret;
}

+/*
+ * TODO: merge with sta/ibss into 1 set_key function.
+ * note there are slight diffs
+ */
int wl1271_cmd_set_ap_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
u16 tx_seq_16)
{
- struct wl1271_cmd_set_ap_keys *cmd;
+ struct wl1271_cmd_set_keys *cmd;
int ret = 0;
u8 lid_type;

cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd)
return -ENOMEM;
@@ -986,169 +1198,43 @@ int wl1271_cmd_set_ap_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,

out:
kfree(cmd);
return ret;
}

-int wl1271_cmd_disconnect(struct wl1271 *wl)
-{
- struct wl1271_cmd_disconnect *cmd;
- int ret = 0;
-
- wl1271_debug(DEBUG_CMD, "cmd disconnect");
-
- cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
- if (!cmd) {
- ret = -ENOMEM;
- goto out;
- }
-
- /* disconnect reason is not used in immediate disconnections */
- cmd->type = DISCONNECT_IMMEDIATE;
-
- ret = wl1271_cmd_send(wl, CMD_DISCONNECT, cmd, sizeof(*cmd), 0);
- if (ret < 0) {
- wl1271_error("failed to send disconnect command");
- goto out_free;
- }
-
- ret = wl1271_cmd_wait_for_event(wl, DISCONNECT_EVENT_COMPLETE_ID);
- if (ret < 0)
- wl1271_error("cmd disconnect event completion error");
-
-out_free:
- kfree(cmd);
-
-out:
- return ret;
-}
-
-int wl1271_cmd_set_sta_state(struct wl1271 *wl)
+int wl1271_cmd_set_peer_state(struct wl1271 *wl)
{
- struct wl1271_cmd_set_sta_state *cmd;
+ struct wl1271_cmd_set_peer_state *cmd;
int ret = 0;

- wl1271_debug(DEBUG_CMD, "cmd set sta state");
+ wl1271_debug(DEBUG_CMD, "cmd set sta state (hlid=%d)", wl->sta_hlid);

cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
ret = -ENOMEM;
goto out;
}

+ cmd->hlid = wl->sta_hlid;
cmd->state = WL1271_CMD_STA_STATE_CONNECTED;

- ret = wl1271_cmd_send(wl, CMD_SET_STA_STATE, cmd, sizeof(*cmd), 0);
+ ret = wl1271_cmd_send(wl, CMD_SET_PEER_STATE, cmd, sizeof(*cmd), 0);
if (ret < 0) {
wl1271_error("failed to send set STA state command");
goto out_free;
}

out_free:
kfree(cmd);

out:
return ret;
}
-
-int wl1271_cmd_start_bss(struct wl1271 *wl)
-{
- struct wl1271_cmd_bss_start *cmd;
- struct ieee80211_bss_conf *bss_conf = &wl->vif->bss_conf;
- int ret;
-
- wl1271_debug(DEBUG_CMD, "cmd start bss");
-
- /*
- * FIXME: We currently do not support hidden SSID. The real SSID
- * should be fetched from mac80211 first.
- */
- if (wl->ssid_len == 0) {
- wl1271_warning("Hidden SSID currently not supported for AP");
- ret = -EINVAL;
- goto out;
- }
-
- cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
- if (!cmd) {
- ret = -ENOMEM;
- goto out;
- }
-
- memcpy(cmd->bssid, bss_conf->bssid, ETH_ALEN);
-
- cmd->aging_period = cpu_to_le16(wl->conf.tx.ap_aging_period);
- cmd->bss_index = WL1271_AP_BSS_INDEX;
- cmd->global_hlid = WL1271_AP_GLOBAL_HLID;
- cmd->broadcast_hlid = WL1271_AP_BROADCAST_HLID;
- cmd->basic_rate_set = cpu_to_le32(wl->basic_rate_set);
- cmd->beacon_interval = cpu_to_le16(wl->beacon_int);
- cmd->dtim_interval = bss_conf->dtim_period;
- cmd->beacon_expiry = WL1271_AP_DEF_BEACON_EXP;
- cmd->channel = wl->channel;
- cmd->ssid_len = wl->ssid_len;
- cmd->ssid_type = SSID_TYPE_PUBLIC;
- memcpy(cmd->ssid, wl->ssid, wl->ssid_len);
-
- switch (wl->band) {
- case IEEE80211_BAND_2GHZ:
- cmd->band = RADIO_BAND_2_4GHZ;
- break;
- case IEEE80211_BAND_5GHZ:
- cmd->band = RADIO_BAND_5GHZ;
- break;
- default:
- wl1271_warning("bss start - unknown band: %d", (int)wl->band);
- cmd->band = RADIO_BAND_2_4GHZ;
- break;
- }
-
- ret = wl1271_cmd_send(wl, CMD_BSS_START, cmd, sizeof(*cmd), 0);
- if (ret < 0) {
- wl1271_error("failed to initiate cmd start bss");
- goto out_free;
- }
-
-out_free:
- kfree(cmd);
-
-out:
- return ret;
-}
-
-int wl1271_cmd_stop_bss(struct wl1271 *wl)
-{
- struct wl1271_cmd_bss_start *cmd;
- int ret;
-
- wl1271_debug(DEBUG_CMD, "cmd stop bss");
-
- cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
- if (!cmd) {
- ret = -ENOMEM;
- goto out;
- }
-
- cmd->bss_index = WL1271_AP_BSS_INDEX;
-
- ret = wl1271_cmd_send(wl, CMD_BSS_STOP, cmd, sizeof(*cmd), 0);
- if (ret < 0) {
- wl1271_error("failed to initiate cmd stop bss");
- goto out_free;
- }
-
-out_free:
- kfree(cmd);
-
-out:
- return ret;
-}
-
-int wl1271_cmd_add_sta(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid)
+int wl1271_cmd_add_peer(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid)
{
- struct wl1271_cmd_add_sta *cmd;
+ struct wl1271_cmd_add_peer *cmd;
int ret;

wl1271_debug(DEBUG_CMD, "cmd add sta %d", (int)hlid);

cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
@@ -1167,28 +1253,28 @@ int wl1271_cmd_add_sta(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid)

cmd->supported_rates = cpu_to_le32(wl1271_tx_enabled_rates_get(wl,
sta->supp_rates[wl->band]));

wl1271_debug(DEBUG_CMD, "new sta rates: 0x%x", cmd->supported_rates);

- ret = wl1271_cmd_send(wl, CMD_ADD_STA, cmd, sizeof(*cmd), 0);
+ ret = wl1271_cmd_send(wl, CMD_ADD_PEER, cmd, sizeof(*cmd), 0);
if (ret < 0) {
wl1271_error("failed to initiate cmd add sta");
goto out_free;
}

out_free:
kfree(cmd);

out:
return ret;
}

-int wl1271_cmd_remove_sta(struct wl1271 *wl, u8 hlid)
+int wl1271_cmd_remove_peer(struct wl1271 *wl, u8 hlid)
{
- struct wl1271_cmd_remove_sta *cmd;
+ struct wl1271_cmd_remove_peer *cmd;
int ret;

wl1271_debug(DEBUG_CMD, "cmd remove sta %d", (int)hlid);

cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
@@ -1198,23 +1284,24 @@ int wl1271_cmd_remove_sta(struct wl1271 *wl, u8 hlid)

cmd->hlid = hlid;
/* We never send a deauth, mac80211 is in charge of this */
cmd->reason_opcode = 0;
cmd->send_deauth_flag = 0;

- ret = wl1271_cmd_send(wl, CMD_REMOVE_STA, cmd, sizeof(*cmd), 0);
+ ret = wl1271_cmd_send(wl, CMD_REMOVE_PEER, cmd, sizeof(*cmd), 0);
if (ret < 0) {
wl1271_error("failed to initiate cmd remove sta");
goto out_free;
}

/*
* We are ok with a timeout here. The event is sometimes not sent
* due to a firmware bug.
*/
- wl1271_cmd_wait_for_event_or_timeout(wl, STA_REMOVE_COMPLETE_EVENT_ID);
+ wl1271_cmd_wait_for_event_or_timeout(wl,
+ PEER_REMOVE_COMPLETE_EVENT_ID);

out_free:
kfree(cmd);

out:
return ret;
diff --git a/drivers/net/wireless/wl12xx/cmd.h b/drivers/net/wireless/wl12xx/cmd.h
index 1f70372..b948677 100644
--- a/drivers/net/wireless/wl12xx/cmd.h
+++ b/drivers/net/wireless/wl12xx/cmd.h
@@ -33,13 +33,20 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
size_t res_len);
int wl1271_cmd_general_parms(struct wl1271 *wl);
int wl128x_cmd_general_parms(struct wl1271 *wl);
int wl1271_cmd_radio_parms(struct wl1271 *wl);
int wl128x_cmd_radio_parms(struct wl1271 *wl);
int wl1271_cmd_ext_radio_parms(struct wl1271 *wl);
-int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type);
+int wl1271_cmd_role_enable(struct wl1271 *wl, u8 role_type, u8 *role_id);
+int wl1271_cmd_role_disable(struct wl1271 *wl, u8 *role_id);
+int wl1271_cmd_role_start_dev(struct wl1271 *wl);
+int wl1271_cmd_role_stop_dev(struct wl1271 *wl);
+int wl1271_cmd_role_start_sta(struct wl1271 *wl);
+int wl1271_cmd_role_stop_sta(struct wl1271 *wl);
+int wl1271_cmd_role_start_ap(struct wl1271 *wl);
+int wl1271_cmd_role_stop_ap(struct wl1271 *wl);
int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer);
int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len);
int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len);
int wl1271_cmd_data_path(struct wl1271 *wl, bool enable);
int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode);
int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer,
@@ -53,26 +60,22 @@ int wl1271_cmd_build_probe_req(struct wl1271 *wl,
const u8 *ie, size_t ie_len, u8 band);
struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl,
struct sk_buff *skb);
int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, __be32 ip_addr);
int wl1271_build_qos_null_data(struct wl1271 *wl);
int wl1271_cmd_build_klv_null_data(struct wl1271 *wl);
-int wl1271_cmd_set_sta_default_wep_key(struct wl1271 *wl, u8 id);
-int wl1271_cmd_set_ap_default_wep_key(struct wl1271 *wl, u8 id);
+int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id, u8 hlid);
int wl1271_cmd_set_sta_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
u8 key_size, const u8 *key, const u8 *addr,
u32 tx_seq_32, u16 tx_seq_16);
int wl1271_cmd_set_ap_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
u16 tx_seq_16);
-int wl1271_cmd_disconnect(struct wl1271 *wl);
-int wl1271_cmd_set_sta_state(struct wl1271 *wl);
-int wl1271_cmd_start_bss(struct wl1271 *wl);
-int wl1271_cmd_stop_bss(struct wl1271 *wl);
-int wl1271_cmd_add_sta(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid);
-int wl1271_cmd_remove_sta(struct wl1271 *wl, u8 hlid);
+int wl1271_cmd_set_peer_state(struct wl1271 *wl);
+int wl1271_cmd_add_peer(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid);
+int wl1271_cmd_remove_peer(struct wl1271 *wl, u8 hlid);
int wl12xx_cmd_config_fwlog(struct wl1271 *wl);
int wl12xx_cmd_start_fwlog(struct wl1271 *wl);
int wl12xx_cmd_stop_fwlog(struct wl1271 *wl);

enum wl1271_commands {
CMD_INTERROGATE = 1, /*use this to read information elements*/
@@ -80,48 +83,58 @@ enum wl1271_commands {
CMD_ENABLE_RX = 3,
CMD_ENABLE_TX = 4,
CMD_DISABLE_RX = 5,
CMD_DISABLE_TX = 6,
CMD_SCAN = 8,
CMD_STOP_SCAN = 9,
- CMD_START_JOIN = 11,
CMD_SET_KEYS = 12,
CMD_READ_MEMORY = 13,
CMD_WRITE_MEMORY = 14,
CMD_SET_TEMPLATE = 19,
CMD_TEST = 23,
CMD_NOISE_HIST = 28,
- CMD_LNA_CONTROL = 32,
+ CMD_QUIET_ELEMENT_SET_STATE = 29,
CMD_SET_BCN_MODE = 33,
CMD_MEASUREMENT = 34,
CMD_STOP_MEASUREMENT = 35,
- CMD_DISCONNECT = 36,
CMD_SET_PS_MODE = 37,
CMD_CHANNEL_SWITCH = 38,
CMD_STOP_CHANNEL_SWICTH = 39,
CMD_AP_DISCOVERY = 40,
CMD_STOP_AP_DISCOVERY = 41,
- CMD_SPS_SCAN = 42,
- CMD_STOP_SPS_SCAN = 43,
CMD_HEALTH_CHECK = 45,
CMD_DEBUG = 46,
CMD_TRIGGER_SCAN_TO = 47,
CMD_CONNECTION_SCAN_CFG = 48,
CMD_CONNECTION_SCAN_SSID_CFG = 49,
CMD_START_PERIODIC_SCAN = 50,
CMD_STOP_PERIODIC_SCAN = 51,
- CMD_SET_STA_STATE = 52,
- CMD_CONFIG_FWLOGGER = 53,
- CMD_START_FWLOGGER = 54,
- CMD_STOP_FWLOGGER = 55,
+ CMD_SET_PEER_STATE = 52,
+ CMD_REMAIN_ON_CHANNEL = 53,
+ CMD_CANCEL_REMAIN_ON_CHANNEL = 54,

- /* AP mode commands */
- CMD_BSS_START = 60,
- CMD_BSS_STOP = 61,
- CMD_ADD_STA = 62,
- CMD_REMOVE_STA = 63,
+ CMD_CONFIG_FWLOGGER = 55,
+ CMD_START_FWLOGGER = 56,
+ CMD_STOP_FWLOGGER = 57,
+
+ /* AP commands */
+ CMD_ADD_PEER = 62,
+ CMD_REMOVE_PEER = 63,
+
+ /* Role API */
+ CMD_ROLE_ENABLE = 70,
+ CMD_ROLE_DISABLE = 71,
+ CMD_ROLE_START = 72,
+ CMD_ROLE_STOP = 73,
+
+ /* WIFI Direct */
+ CMD_WFD_START_DISCOVERY = 80,
+ CMD_WFD_STOP_DISCOVERY = 81,
+ CMD_WFD_ATTRIBUTE_CONFIG = 82,
+
+ CMD_NOP = 100,

NUM_COMMANDS,
MAX_COMMAND_ID = 0xFFFF,
};

#define MAX_CMD_PARAMS 572
@@ -144,20 +157,18 @@ enum cmd_templ {
CMD_TEMPL_PROBE_REQ_2_4, /* for firmware internal use only */
CMD_TEMPL_PROBE_REQ_5, /* for firmware internal use only */
CMD_TEMPL_BAR, /* for firmware internal use only */
CMD_TEMPL_CTS, /*
* For CTS-to-self (FastCTS) mechanism
* for BT/WLAN coexistence (SoftGemini). */
- CMD_TEMPL_ARP_RSP,
- CMD_TEMPL_LINK_MEASUREMENT_REPORT,
-
- /* AP-mode specific */
- CMD_TEMPL_AP_BEACON = 13,
+ CMD_TEMPL_AP_BEACON,
CMD_TEMPL_AP_PROBE_RESPONSE,
- CMD_TEMPL_AP_ARP_RSP,
+ CMD_TEMPL_ARP_RSP,
CMD_TEMPL_DEAUTH_AP,
+ CMD_TEMPL_TEMPORARY,
+ CMD_TEMPL_LINK_MEASUREMENT_REPORT,

CMD_TEMPL_MAX = 0xff
};

/* unit ms */
#define WL1271_COMMAND_TIMEOUT 2000
@@ -190,12 +201,13 @@ enum {
CMD_STATUS_OUT_OF_MEMORY = 16,
CMD_STATUS_STA_TABLE_FULL = 17,
CMD_STATUS_RADIO_ERROR = 18,
CMD_STATUS_WRONG_NESTING = 19,
CMD_STATUS_TIMEOUT = 21, /* Driver internal use.*/
CMD_STATUS_FW_RESET = 22, /* Driver internal use.*/
+ CMD_STATUS_TEMPLATE_OUT_OF_TEMPORARY_MEMORY = 23,
MAX_COMMAND_STATUS = 0xff
};

#define CMDMBOX_HEADER_LEN 4
#define CMDMBOX_INFO_ELEM_HEADER_LEN 4

@@ -207,44 +219,128 @@ enum {
};

#define WL1271_JOIN_CMD_CTRL_TX_FLUSH 0x80 /* Firmware flushes all Tx */
#define WL1271_JOIN_CMD_TX_SESSION_OFFSET 1
#define WL1271_JOIN_CMD_BSS_TYPE_5GHZ 0x10

-struct wl1271_cmd_join {
+struct wl1271_cmd_role_enable {
struct wl1271_cmd_header header;

- __le32 bssid_lsb;
- __le16 bssid_msb;
- __le16 beacon_interval; /* in TBTTs */
- __le32 rx_config_options;
- __le32 rx_filter_options;
+ u8 role_id;
+ u8 role_type;
+ u8 mac_address[ETH_ALEN];
+} __packed;

- /*
- * The target uses this field to determine the rate at
- * which to transmit control frame responses (such as
- * ACK or CTS frames).
- */
- __le32 basic_rate_set;
- __le32 supported_rate_set;
- u8 dtim_interval;
- /*
- * bits 0-2: This bitwise field specifies the type
- * of BSS to start or join (BSS_TYPE_*).
- * bit 4: Band - The radio band in which to join
- * or start.
- * 0 - 2.4GHz band
- * 1 - 5GHz band
- * bits 3, 5-7: Reserved
- */
- u8 bss_type;
+struct wl1271_cmd_role_disable {
+ struct wl1271_cmd_header header;
+
+ u8 role_id;
+ u8 padding[3];
+} __packed;
+
+enum wl1271_band {
+ WL1271_BAND_2_4GHZ = 0, /* 2.4 Ghz band */
+ WL1271_BAND_5GHZ = 1, /* 5 Ghz band */
+ WL1271_BAND_JAPAN_4_9_GHZ = 2,
+ WL1271_BAND_DEFAULT = WL1271_BAND_2_4GHZ,
+ WL1271_BAND_INVALID = 0x7E,
+ WL1271_BAND_MAX_RADIO = 0x7F,
+};
+
+struct wl1271_cmd_role_start {
+ struct wl1271_cmd_header header;
+
+ u8 role_id;
+ u8 band;
u8 channel;
- u8 ssid_len;
- u8 ssid[IW_ESSID_MAX_SIZE];
- u8 ctrl; /* JOIN_CMD_CTRL_* */
- u8 reserved[3];
+ u8 padding;
+
+ union {
+ struct {
+ u8 hlid;
+ u8 session;
+ u8 padding_1[54];
+ } __packed device;
+ /* sta & p2p_cli use the same struct */
+ struct {
+ u8 bssid[ETH_ALEN];
+ u8 hlid; /* data hlid */
+ u8 session;
+ __le32 remote_rates; /* remote supported rates */
+
+ /*
+ * The target uses this field to determine the rate at
+ * which to transmit control frame responses (such as
+ * ACK or CTS frames).
+ */
+ __le32 basic_rate_set;
+ __le32 local_rates; /* local supported rates */
+
+ u8 ssid_type;
+ u8 ssid_len;
+ u8 ssid[IW_ESSID_MAX_SIZE];
+
+ __le16 beacon_interval; /* in TBTTs */
+ } __packed sta;
+ struct {
+ u8 bssid[ETH_ALEN];
+ u8 hlid; /* data hlid */
+ u8 dtim_interval;
+ __le32 remote_rates; /* remote supported rates */
+
+ __le32 basic_rate_set;
+ __le32 local_rates; /* local supported rates */
+
+ u8 ssid_type;
+ u8 ssid_len;
+ u8 ssid[IW_ESSID_MAX_SIZE];
+
+ __le16 beacon_interval; /* in TBTTs */
+
+ u8 padding_1[4];
+ } __packed ibss;
+ /* ap & p2p_go use the same struct */
+ struct {
+ /* Aging period in seconds*/
+ __le16 aging_period;
+ /* Beacon expiry time in ms */
+ u8 beacon_expiry;
+ u8 bss_index;
+ /* The host link id for the AP's global queue */
+ u8 global_hlid;
+ /* The host link id for the AP's broadcast queue */
+ u8 broadcast_hlid;
+
+ __le16 beacon_interval; /* in TBTTs */
+
+ __le32 basic_rate_set;
+ __le32 local_rates; /* local supported rates */
+
+ u8 dtim_interval;
+
+ u8 ssid_type;
+ u8 ssid_len;
+ u8 ssid[IW_ESSID_MAX_SIZE];
+
+ u8 padding_1[5];
+ } __packed ap;
+ };
+} __packed;
+
+enum wl1271_disconnection_type {
+ WL1271_DISC_IMMEDIATE,
+ WL1271_DISC_DE_AUTH,
+ WL1271_DISC_DIS_ASSOC,
+};
+
+struct wl1271_cmd_role_stop {
+ struct wl1271_cmd_header header;
+
+ u8 role_id;
+ u8 disc_type; /* de-auth/de-asso or not (only STA and P2P_CLI) */
+ __le16 reason; /* only STA and P2P_CLI */
} __packed;

struct cmd_enabledisable_path {
struct wl1271_cmd_header header;

u8 channel;
@@ -284,72 +380,42 @@ enum wl1271_cmd_ps_mode {
STATION_POWER_SAVE_MODE
};

struct wl1271_cmd_ps_params {
struct wl1271_cmd_header header;

+ u8 role_id;
u8 ps_mode; /* STATION_* */
- u8 padding[3];
+ u8 padding[2];
} __packed;

/* HW encryption keys */
#define NUM_ACCESS_CATEGORIES_COPY 4

enum wl1271_cmd_key_action {
KEY_ADD_OR_REPLACE = 1,
KEY_REMOVE = 2,
KEY_SET_ID = 3,
MAX_KEY_ACTION = 0xffff,
};

+enum wl1271_cmd_lid_key_type {
+ UNICAST_LID_TYPE = 0,
+ BROADCAST_LID_TYPE = 1,
+ WEP_DEFAULT_LID_TYPE = 2
+};
+
enum wl1271_cmd_key_type {
KEY_NONE = 0,
KEY_WEP = 1,
KEY_TKIP = 2,
KEY_AES = 3,
KEY_GEM = 4,
};

-/* FIXME: Add description for key-types */
-
-struct wl1271_cmd_set_sta_keys {
- struct wl1271_cmd_header header;
-
- /* Ignored for default WEP key */
- u8 addr[ETH_ALEN];
-
- /* key_action_e */
- __le16 key_action;
-
- __le16 reserved_1;
-
- /* key size in bytes */
- u8 key_size;
-
- /* key_type_e */
- u8 key_type;
- u8 ssid_profile;
-
- /*
- * TKIP, AES: frame's key id field.
- * For WEP default key: key id;
- */
- u8 id;
- u8 reserved_2[6];
- u8 key[MAX_KEY_SIZE];
- __le16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY];
- __le32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY];
-} __packed;
-
-enum wl1271_cmd_lid_key_type {
- UNICAST_LID_TYPE = 0,
- BROADCAST_LID_TYPE = 1,
- WEP_DEFAULT_LID_TYPE = 2
-};
-
-struct wl1271_cmd_set_ap_keys {
+struct wl1271_cmd_set_keys {
struct wl1271_cmd_header header;

/*
* Indicates whether the HLID is a unicast key set
* or broadcast key set. A special value 0xFF is
* used to indicate that the HLID is on WEP-default
@@ -493,75 +559,29 @@ struct wl1271_ext_radio_parms_cmd {
enum wl1271_disconnect_type {
DISCONNECT_IMMEDIATE,
DISCONNECT_DEAUTH,
DISCONNECT_DISASSOC
};

-struct wl1271_cmd_disconnect {
- struct wl1271_cmd_header header;
-
- __le32 rx_config_options;
- __le32 rx_filter_options;
-
- __le16 reason;
- u8 type;
-
- u8 padding;
-} __packed;
-
#define WL1271_CMD_STA_STATE_CONNECTED 1

-struct wl1271_cmd_set_sta_state {
+struct wl1271_cmd_set_peer_state {
struct wl1271_cmd_header header;

+ u8 hlid;
u8 state;
- u8 padding[3];
+ u8 padding[2];
} __packed;

enum wl1271_ssid_type {
- SSID_TYPE_PUBLIC = 0,
- SSID_TYPE_HIDDEN = 1
+ WL1271_SSID_TYPE_PUBLIC = 0,
+ WL1271_SSID_TYPE_HIDDEN = 1,
+ WL1271_SSID_TYPE_ANY = 2,
};

-struct wl1271_cmd_bss_start {
- struct wl1271_cmd_header header;
-
- /* wl1271_ssid_type */
- u8 ssid_type;
- u8 ssid_len;
- u8 ssid[IW_ESSID_MAX_SIZE];
- u8 padding_1[2];
-
- /* Basic rate set */
- __le32 basic_rate_set;
- /* Aging period in seconds*/
- __le16 aging_period;
-
- /*
- * This field specifies the time between target beacon
- * transmission times (TBTTs), in time units (TUs).
- * Valid values are 1 to 1024.
- */
- __le16 beacon_interval;
- u8 bssid[ETH_ALEN];
- u8 bss_index;
- /* Radio band */
- u8 band;
- u8 channel;
- /* The host link id for the AP's global queue */
- u8 global_hlid;
- /* The host link id for the AP's broadcast queue */
- u8 broadcast_hlid;
- /* DTIM count */
- u8 dtim_interval;
- /* Beacon expiry time in ms */
- u8 beacon_expiry;
- u8 padding_2[3];
-} __packed;
-
-struct wl1271_cmd_add_sta {
+struct wl1271_cmd_add_peer {
struct wl1271_cmd_header header;

u8 addr[ETH_ALEN];
u8 hlid;
u8 aid;
u8 psd_type[NUM_ACCESS_CATEGORIES_COPY];
@@ -569,13 +589,13 @@ struct wl1271_cmd_add_sta {
u8 bss_index;
u8 sp_len;
u8 wmm;
u8 padding1;
} __packed;

-struct wl1271_cmd_remove_sta {
+struct wl1271_cmd_remove_peer {
struct wl1271_cmd_header header;

u8 hlid;
u8 reason_opcode;
u8 send_deauth_flag;
u8 padding1;
diff --git a/drivers/net/wireless/wl12xx/event.c b/drivers/net/wireless/wl12xx/event.c
index 304aaa2..431ceae 100644
--- a/drivers/net/wireless/wl12xx/event.c
+++ b/drivers/net/wireless/wl12xx/event.c
@@ -282,16 +282,16 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
if (wl->vif)
wl1271_event_rssi_trigger(wl, mbox);
}

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

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

if ((vector & DUMMY_PACKET_EVENT_ID) && !is_ap) {
wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID");
if (wl->vif)
wl1271_tx_dummy_packet(wl);
diff --git a/drivers/net/wireless/wl12xx/event.h b/drivers/net/wireless/wl12xx/event.h
index e524ad6..2cc6788 100644
--- a/drivers/net/wireless/wl12xx/event.h
+++ b/drivers/net/wireless/wl12xx/event.h
@@ -46,106 +46,91 @@ enum {
RSSI_SNR_TRIGGER_5_EVENT_ID = BIT(5),
RSSI_SNR_TRIGGER_6_EVENT_ID = BIT(6),
RSSI_SNR_TRIGGER_7_EVENT_ID = BIT(7),
MEASUREMENT_START_EVENT_ID = BIT(8),
MEASUREMENT_COMPLETE_EVENT_ID = BIT(9),
SCAN_COMPLETE_EVENT_ID = BIT(10),
- SCHEDULED_SCAN_COMPLETE_EVENT_ID = BIT(11),
+ WFD_DISCOVERY_COMPLETE_EVENT_ID = BIT(11),
AP_DISCOVERY_COMPLETE_EVENT_ID = BIT(12),
PS_REPORT_EVENT_ID = BIT(13),
PSPOLL_DELIVERY_FAILURE_EVENT_ID = BIT(14),
DISCONNECT_EVENT_COMPLETE_ID = BIT(15),
- JOIN_EVENT_COMPLETE_ID = BIT(16),
+ RESERVED2 = BIT(16),
CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(17),
BSS_LOSE_EVENT_ID = BIT(18),
REGAINED_BSS_EVENT_ID = BIT(19),
MAX_TX_RETRY_EVENT_ID = BIT(20),
- /* STA: dummy paket for dynamic mem blocks */
- DUMMY_PACKET_EVENT_ID = BIT(21),
- /* AP: STA remove complete */
- STA_REMOVE_COMPLETE_EVENT_ID = BIT(21),
+ DUMMY_PACKET_EVENT_ID = BIT(21),
SOFT_GEMINI_SENSE_EVENT_ID = BIT(22),
- /* STA: SG prediction */
- SOFT_GEMINI_PREDICTION_EVENT_ID = BIT(23),
- /* AP: Inactive STA */
- INACTIVE_STA_EVENT_ID = BIT(23),
+ CHANGE_AUTO_MODE_TIMEOUT_EVENT_ID = BIT(23),
SOFT_GEMINI_AVALANCHE_EVENT_ID = BIT(24),
PLT_RX_CALIBRATION_COMPLETE_EVENT_ID = BIT(25),
- DBG_EVENT_ID = BIT(26),
- HEALTH_CHECK_REPLY_EVENT_ID = BIT(27),
+ INACTIVE_STA_EVENT_ID = BIT(26),
+ PEER_REMOVE_COMPLETE_EVENT_ID = BIT(27),
PERIODIC_SCAN_COMPLETE_EVENT_ID = BIT(28),
PERIODIC_SCAN_REPORT_EVENT_ID = BIT(29),
BA_SESSION_RX_CONSTRAINT_EVENT_ID = BIT(30),
+ REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID = BIT(31),
EVENT_MBOX_ALL_EVENT_ID = 0x7fffffff,
};

enum {
EVENT_ENTER_POWER_SAVE_FAIL = 0,
EVENT_ENTER_POWER_SAVE_SUCCESS,
};

-struct event_debug_report {
- u8 debug_event_id;
- u8 num_params;
- __le16 pad;
- __le32 report_1;
- __le32 report_2;
- __le32 report_3;
-} __packed;
-
#define NUM_OF_RSSI_SNR_TRIGGERS 8

struct event_mailbox {
__le32 events_vector;
__le32 events_mask;
__le32 reserved_1;
__le32 reserved_2;

- u8 dbg_event_id;
- u8 num_relevant_params;
- __le16 reserved_3;
- __le32 event_report_p1;
- __le32 event_report_p2;
- __le32 event_report_p3;
-
u8 number_of_scan_results;
u8 scan_tag;
- u8 reserved_4[2];
- __le32 compl_scheduled_scan_status;
+ u8 completed_scan_status;
+ u8 reserved_3[1];

- __le16 scheduled_scan_attended_channels;
u8 soft_gemini_sense_info;
u8 soft_gemini_protective_info;
s8 rssi_snr_trigger_metric[NUM_OF_RSSI_SNR_TRIGGERS];
u8 channel_switch_status;
u8 scheduled_scan_status;
u8 ps_status;
+ /* tuned channel (roc) */
+ u8 channel;

- /* AP FW only */
- u8 hlid_removed;
+ /* hlid removed (STA_REMOVE_COMPLETE_EVENT) */
+ __le16 hlid_removed_bitmap;

- /* a bitmap of hlids for stations that have been inactive too long */
+ /* bitmap of aged stations (by HLID) */
__le16 sta_aging_status;

- /* a bitmap of hlids for stations which didn't respond to TX */
+ /* bitmap of stations (by HLID) which exceeded max tx retries */
__le16 sta_tx_retry_exceeded;

- /*
- * Bitmap, Each bit set represents the Role ID for which this constraint
- * is set. Range: 0 - FF, FF means ANY role
- */
- u8 ba_role_id;
- /*
- * Bitmap, Each bit set represents the Link ID for which this constraint
- * is set. Not applicable if ba_role_id is set to ANY role (FF).
- * Range: 0 - FFFF, FFFF means ANY link in that role
- */
- u8 ba_link_id;
- u8 ba_allowed;
-
- u8 reserved_5[21];
+ /* discovery completed results */
+ u8 discovery_tag;
+ u8 number_of_preq_results;
+ u8 number_of_prsp_results;
+ u8 reserved_5;
+
+ /* rx ba constraint */
+
+ /* role id for which this constraint is set. 0xFF means any role. */
+ u8 role_id;
+ u8 rx_ba_allowed;
+ u8 reserved_6[2];
+
+ u8 ps_poll_delivery_failure_role_ids;
+ u8 stopped_role_ids;
+ u8 started_role_ids;
+ u8 change_auto_mode_timeout;
+
+ u8 reserved_7[12];
} __packed;

int wl1271_event_unmask(struct wl1271 *wl);
void wl1271_event_mbox_config(struct wl1271 *wl);
int wl1271_event_handle(struct wl1271 *wl, u8 mbox);
void wl1271_pspoll_work(struct work_struct *work);
diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c
index a02bfbb..0fdaba9 100644
--- a/drivers/net/wireless/wl12xx/init.c
+++ b/drivers/net/wireless/wl12xx/init.c
@@ -401,18 +401,12 @@ static int wl1271_sta_hw_init(struct wl1271 *wl)
}

static int wl1271_sta_hw_init_post_mem(struct wl1271 *wl)
{
int ret, i;

- ret = wl1271_cmd_set_sta_default_wep_key(wl, wl->default_key);
- if (ret < 0) {
- wl1271_warning("couldn't set default key");
- return ret;
- }
-
/* disable all keep-alive templates */
for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) {
ret = wl1271_acx_keep_alive_config(wl, i,
ACX_KEEP_ALIVE_TPL_INVALID);
if (ret < 0)
return ret;
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index 0ee98e0..a348d18 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -412,13 +412,13 @@ static int wl1271_check_operstate(struct wl1271 *wl, unsigned char operstate)
if (operstate != IF_OPER_UP)
return 0;

if (test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags))
return 0;

- ret = wl1271_cmd_set_sta_state(wl);
+ ret = wl1271_cmd_set_peer_state(wl);
if (ret < 0)
return ret;

wl1271_info("Association completed.");
return 0;
}
@@ -1973,12 +1973,14 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
wl1271_free_ap_keys(wl);
memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
wl->ap_fw_ps_map = 0;
wl->ap_ps_map = 0;
wl->sched_scanning = false;
wl->role_id = WL1271_INVALID_ROLE_ID;
+ memset(wl->roles_map, 0, sizeof(wl->roles_map));
+ memset(wl->links_map, 0, sizeof(wl->links_map));

/*
* this is performed after the cancel_work calls and the associated
* mutex_lock, so that wl1271_op_add_interface does not accidentally
* get executed before all these vars have been reset.
*/
@@ -2021,13 +2023,13 @@ static int wl1271_dummy_join(struct wl1271 *wl)
/* we need to use a dummy BSSID for now */
static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
0xad, 0xbe, 0xef };

memcpy(wl->bssid, dummy_bssid, ETH_ALEN);

- ret = wl1271_cmd_join(wl, wl->set_bss_type);
+ ret = wl1271_cmd_role_start_sta(wl);
if (ret < 0)
goto out;

set_bit(WL1271_FLAG_JOINED, &wl->flags);

out:
@@ -2050,13 +2052,13 @@ static int wl1271_join(struct wl1271 *wl, bool set_assoc)
if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
wl1271_info("JOIN while associated.");

if (set_assoc)
set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);

- ret = wl1271_cmd_join(wl, wl->set_bss_type);
+ ret = wl1271_cmd_role_start_sta(wl);
if (ret < 0)
goto out;

set_bit(WL1271_FLAG_JOINED, &wl->flags);

if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
@@ -2091,13 +2093,13 @@ out:

static int wl1271_unjoin(struct wl1271 *wl)
{
int ret;

/* to stop listening to a channel, we disconnect */
- ret = wl1271_cmd_disconnect(wl);
+ ret = wl1271_cmd_role_stop_sta(wl);
if (ret < 0)
goto out;

clear_bit(WL1271_FLAG_JOINED, &wl->flags);
memset(wl->bssid, 0, ETH_ALEN);

@@ -2463,13 +2465,14 @@ static int wl1271_ap_init_hwenc(struct wl1271 *wl)

if (key->key_type == KEY_WEP)
wep_key_added = true;
}

if (wep_key_added) {
- ret = wl1271_cmd_set_ap_default_wep_key(wl, wl->default_key);
+ ret = wl1271_cmd_set_default_wep_key(wl, wl->default_key,
+ WL1271_AP_BROADCAST_HLID);
if (ret < 0)
goto out;
}

out:
wl1271_free_ap_keys(wl);
@@ -2541,14 +2544,15 @@ static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
tx_seq_16);
if (ret < 0)
return ret;

/* the default WEP key needs to be configured at least once */
if (key_type == KEY_WEP) {
- ret = wl1271_cmd_set_sta_default_wep_key(wl,
- wl->default_key);
+ ret = wl1271_cmd_set_default_wep_key(wl,
+ wl->default_key,
+ wl->sta_hlid);
if (ret < 0)
return ret;
}
}

return 0;
@@ -2999,26 +3003,26 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
if (ret < 0)
goto out;

if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
if (bss_conf->enable_beacon) {
if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
- ret = wl1271_cmd_start_bss(wl);
+ ret = wl1271_cmd_role_start_ap(wl);
if (ret < 0)
goto out;

set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
wl1271_debug(DEBUG_AP, "started AP");

ret = wl1271_ap_init_hwenc(wl);
if (ret < 0)
goto out;
}
} else {
if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
- ret = wl1271_cmd_stop_bss(wl);
+ ret = wl1271_cmd_role_stop_ap(wl);
if (ret < 0)
goto out;

clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
wl1271_debug(DEBUG_AP, "stopped AP");
}
@@ -3523,13 +3527,13 @@ static int wl1271_op_sta_add(struct ieee80211_hw *hw,
goto out;

ret = wl1271_ps_elp_wakeup(wl);
if (ret < 0)
goto out_free_sta;

- ret = wl1271_cmd_add_sta(wl, sta, hlid);
+ ret = wl1271_cmd_add_peer(wl, sta, hlid);
if (ret < 0)
goto out_sleep;

out_sleep:
wl1271_ps_elp_sleep(wl);

@@ -3566,13 +3570,13 @@ static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
goto out;

ret = wl1271_ps_elp_wakeup(wl);
if (ret < 0)
goto out;

- ret = wl1271_cmd_remove_sta(wl, wl_sta->hlid);
+ ret = wl1271_cmd_remove_peer(wl, wl_sta->hlid);
if (ret < 0)
goto out_sleep;

wl1271_free_sta(wl, wl_sta->hlid);

out_sleep:
diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c
index 8a745fb..43f21a3 100644
--- a/drivers/net/wireless/wl12xx/tx.c
+++ b/drivers/net/wireless/wl12xx/tx.c
@@ -34,15 +34,16 @@
static int wl1271_set_default_wep_key(struct wl1271 *wl, u8 id)
{
int ret;
bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);

if (is_ap)
- ret = wl1271_cmd_set_ap_default_wep_key(wl, id);
+ ret = wl1271_cmd_set_default_wep_key(wl, id,
+ WL1271_AP_BROADCAST_HLID);
else
- ret = wl1271_cmd_set_sta_default_wep_key(wl, id);
+ ret = wl1271_cmd_set_default_wep_key(wl, id, wl->sta_hlid);

if (ret < 0)
return ret;

wl1271_debug(DEBUG_CRYPT, "default wep key idx: %d", (int)id);
return 0;
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index 4e4bafc..cc60da6 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -134,12 +134,13 @@ extern u32 wl12xx_debug_level;
#define WL1271_ELP_HW_STATE_ASLEEP 0
#define WL1271_ELP_HW_STATE_IRQ 1

#define WL1271_DEFAULT_BEACON_INT 100
#define WL1271_DEFAULT_DTIM_PERIOD 1

+#define WL1271_MAX_ROLES 4
#define WL1271_MAX_LINKS 8
#define WL1271_INVALID_ROLE_ID 0xff
#define WL1271_INVALID_LINK_ID 0xff
#define WL1271_AP_GLOBAL_HLID 0
#define WL1271_AP_BROADCAST_HLID 1
#define WL1271_AP_STA_HLID_START 2
@@ -391,12 +392,16 @@ struct wl1271 {
u8 set_bss_type;
u8 ssid[IW_ESSID_MAX_SIZE + 1];
u8 ssid_len;
int channel;
u8 role_id;
u8 sta_hlid;
+ u8 dev_hlid;
+
+ unsigned long links_map[BITS_TO_LONGS(WL1271_MAX_LINKS)];
+ unsigned long roles_map[BITS_TO_LONGS(WL1271_MAX_ROLES)];

struct wl1271_acx_mem_map *target_mem_map;

/* Accounting for allocated / available TX blocks on HW */
u32 tx_blocks_freed;
u32 tx_blocks_available;
--
1.7.6.401.g6a319


2011-08-09 09:14:22

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 27/40] wl12xx: support IBSS vif type

Start IBSS role when the interface type is IBSS.
As with sta role, use the dev role until the role
is started.

Signed-off-by: Eliad Peller <[email protected]>
---
drivers/net/wireless/wl12xx/main.c | 33 ++++++++++++++++++++++++++++-----
drivers/net/wireless/wl12xx/scan.c | 9 ++++++++-
drivers/net/wireless/wl12xx/tx.c | 3 ++-
drivers/net/wireless/wl12xx/wl12xx.h | 1 +
4 files changed, 39 insertions(+), 7 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index 6a87086..d81a735 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -1760,12 +1760,15 @@ static u8 wl1271_get_role_type(struct wl1271 *wl)
case BSS_TYPE_AP_BSS:
return WL1271_ROLE_AP;

case BSS_TYPE_STA_BSS:
return WL1271_ROLE_STA;

+ case BSS_TYPE_IBSS:
+ return WL1271_ROLE_IBSS;
+
default:
wl1271_info("invalid bss_type: %d", wl->bss_type);
}
return 0xff;
}

@@ -1832,13 +1835,14 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
goto power_off;

ret = wl1271_boot(wl);
if (ret < 0)
goto power_off;

- if (wl->bss_type == BSS_TYPE_STA_BSS) {
+ if (wl->bss_type == BSS_TYPE_STA_BSS ||
+ wl->bss_type == BSS_TYPE_IBSS) {
ret = wl1271_cmd_role_enable(wl,
WL1271_ROLE_DEVICE,
&wl->dev_role_id);
if (ret < 0)
goto irq_disable;
}
@@ -2055,12 +2059,13 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
cancel_work_sync(&wl->recovery_work);
}

static int wl1271_join(struct wl1271 *wl, bool set_assoc)
{
int ret;
+ bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);

/*
* One of the side effects of the JOIN command is that is clears
* WPA/WPA2 keys from the chipset. Performing a JOIN while associated
* to a WPA/WPA2 access point will therefore kill the data-path.
* Currently the only valid scenario for JOIN during association
@@ -2071,13 +2076,16 @@ static int wl1271_join(struct wl1271 *wl, bool set_assoc)
if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
wl1271_info("JOIN while associated.");

if (set_assoc)
set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);

- ret = wl1271_cmd_role_start_sta(wl);
+ if (is_ibss)
+ ret = wl1271_cmd_role_start_ibss(wl);
+ else
+ ret = wl1271_cmd_role_start_sta(wl);
if (ret < 0)
goto out;

if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
goto out;

@@ -3093,12 +3101,13 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf,
u32 changed)
{
bool do_join = false, set_assoc = false;
bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
+ bool ibss_joined = false;
u32 sta_rate_set = 0;
int ret;
struct ieee80211_sta *sta;
bool sta_exists = false;
struct ieee80211_sta_ht_cap sta_ht_cap;

@@ -3106,20 +3115,34 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
changed);
if (ret < 0)
goto out;
}

- if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss)
+ if (changed & BSS_CHANGED_IBSS) {
+ if (bss_conf->ibss_joined) {
+ set_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags);
+ ibss_joined = true;
+ } else {
+ if (test_and_clear_bit(WL1271_FLAG_IBSS_JOINED,
+ &wl->flags)) {
+ wl1271_unjoin(wl);
+ wl1271_cmd_role_start_dev(wl);
+ wl1271_roc(wl, wl->dev_role_id);
+ }
+ }
+ }
+
+ if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
do_join = true;

/* Need to update the SSID (for filtering etc) */
- if ((changed & BSS_CHANGED_BEACON) && is_ibss)
+ if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
do_join = true;

- if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) {
+ if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
bss_conf->enable_beacon ? "enabled" : "disabled");

if (bss_conf->enable_beacon)
wl->set_bss_type = BSS_TYPE_IBSS;
else
diff --git a/drivers/net/wireless/wl12xx/scan.c b/drivers/net/wireless/wl12xx/scan.c
index 52f2b6b..bb90002 100644
--- a/drivers/net/wireless/wl12xx/scan.c
+++ b/drivers/net/wireless/wl12xx/scan.c
@@ -31,12 +31,13 @@

void wl1271_scan_complete_work(struct work_struct *work)
{
struct delayed_work *dwork;
struct wl1271 *wl;
int ret;
+ bool is_sta, is_ibss;

dwork = container_of(work, struct delayed_work, work);
wl = container_of(dwork, struct wl1271, scan_complete_work);

wl1271_debug(DEBUG_SCAN, "Scanning complete");

@@ -56,13 +57,19 @@ void wl1271_scan_complete_work(struct work_struct *work)
if (ret < 0)
goto out;

if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
/* restore hardware connection monitoring template */
wl1271_cmd_build_ap_probe_req(wl, wl->probereq);
- } else {
+ }
+
+ /* return to ROC if needed */
+ is_sta = (wl->bss_type == BSS_TYPE_STA_BSS);
+ is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
+ if ((is_sta && !test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) ||
+ (is_ibss && !test_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags))) {
/* restore remain on channel */
wl1271_cmd_role_start_dev(wl);
wl1271_roc(wl, wl->dev_role_id);
}
wl1271_ps_elp_sleep(wl);

diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c
index d99922c..52a9ae9 100644
--- a/drivers/net/wireless/wl12xx/tx.c
+++ b/drivers/net/wireless/wl12xx/tx.c
@@ -384,13 +384,14 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb,

if (wl12xx_is_dummy_packet(wl, skb))
hlid = wl->system_hlid;
else if (wl->bss_type == BSS_TYPE_AP_BSS)
hlid = wl1271_tx_get_hlid(wl, skb);
else
- if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
+ if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) ||
+ test_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags))
hlid = wl->sta_hlid;
else
hlid = wl->dev_hlid;

if (hlid == WL1271_INVALID_LINK_ID) {
wl1271_error("invalid hlid. dropping skb 0x%p", skb);
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index 97a40c3..dfe08e5 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -321,12 +321,13 @@ struct wl1271_ap_key {
u32 tx_seq_32;
u16 tx_seq_16;
};

enum wl12xx_flags {
WL1271_FLAG_STA_ASSOCIATED,
+ WL1271_FLAG_IBSS_JOINED,
WL1271_FLAG_ROC,
WL1271_FLAG_GPIO_POWER,
WL1271_FLAG_TX_QUEUE_STOPPED,
WL1271_FLAG_TX_PENDING,
WL1271_FLAG_IN_ELP,
WL1271_FLAG_ELP_REQUESTED,
--
1.7.6.401.g6a319


2011-08-11 11:53:18

by Luciano Coelho

[permalink] [raw]
Subject: Re: [PATCH 37/40] wl12xx: don't wait for disconnection event

On Tue, 2011-08-09 at 12:13 +0300, Eliad Peller wrote:
> Sometimes the fw doesn't send the DISCONNECT_EVENT_COMPLETE_ID
> on station role stop, so don't wait for it.

Why? A bug? Or any good reason for it?


> diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c
> index 9ef8621..ad926d2 100644
> --- a/drivers/net/wireless/wl12xx/cmd.c
> +++ b/drivers/net/wireless/wl12xx/cmd.c
> @@ -640,18 +640,12 @@ int wl1271_cmd_role_stop_sta(struct wl1271 *wl)
> ret = wl1271_cmd_send(wl, CMD_ROLE_STOP, cmd, sizeof(*cmd), 0);
> if (ret < 0) {
> wl1271_error("failed to initiate cmd role stop");
> goto out_free;
> }
>
> - ret = wl1271_cmd_wait_for_event(wl, DISCONNECT_EVENT_COMPLETE_ID);
> - if (ret < 0) {
> - wl1271_error("cmd role stop sta event completion error");
> - goto out_free;
> - }
> -

Can't this cause possible race conditions in the firmware if, for
instance, we stop and start the sta role quickly?


--
Cheers,
Luca.


2011-08-09 09:14:03

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 17/40] wl12xx: add ROC/CROC commands

Add structs and functions to support the ROC/CROC commands.

Signed-off-by: Eliad Peller <[email protected]>
---
drivers/net/wireless/wl12xx/cmd.c | 72 +++++++++++++++++++++++++++++++++++++
drivers/net/wireless/wl12xx/cmd.h | 9 +++++
2 files changed, 81 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c
index 94942c1..3091351 100644
--- a/drivers/net/wireless/wl12xx/cmd.c
+++ b/drivers/net/wireless/wl12xx/cmd.c
@@ -1478,6 +1478,78 @@ int wl12xx_cmd_stop_fwlog(struct wl1271 *wl)
out_free:
kfree(cmd);

out:
return ret;
}
+
+static int wl1271_cmd_roc(struct wl1271 *wl, u8 role_id)
+{
+ struct wl1271_cmd_roc *cmd;
+ int ret = 0;
+
+ wl1271_debug(DEBUG_CMD, "cmd roc %d (%d)", wl->channel, wl->band);
+
+ if (WARN_ON(role_id == WL1271_INVALID_ROLE_ID))
+ return -EINVAL;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ cmd->role_id = role_id;
+ cmd->channel = wl->channel;
+ switch (wl->band) {
+ case IEEE80211_BAND_2GHZ:
+ cmd->band = RADIO_BAND_2_4GHZ;
+ break;
+ case IEEE80211_BAND_5GHZ:
+ cmd->band = RADIO_BAND_5GHZ;
+ break;
+ default:
+ wl1271_warning("roc - unknown band: %d", (int)wl->band);
+ cmd->band = RADIO_BAND_2_4GHZ;
+ break;
+ }
+
+
+ ret = wl1271_cmd_send(wl, CMD_REMAIN_ON_CHANNEL, cmd, sizeof(*cmd), 0);
+ if (ret < 0) {
+ wl1271_error("failed to send ROC command");
+ goto out_free;
+ }
+
+out_free:
+ kfree(cmd);
+
+out:
+ return ret;
+}
+
+static int wl1271_cmd_croc(struct wl1271 *wl, u8 role_id)
+{
+ struct wl1271_cmd_header *cmd;
+ int ret = 0;
+
+ wl1271_debug(DEBUG_CMD, "cmd croc");
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = wl1271_cmd_send(wl, CMD_CANCEL_REMAIN_ON_CHANNEL, cmd,
+ sizeof(*cmd), 0);
+ if (ret < 0) {
+ wl1271_error("failed to send ROC command");
+ goto out_free;
+ }
+
+out_free:
+ kfree(cmd);
+
+out:
+ return ret;
+}
diff --git a/drivers/net/wireless/wl12xx/cmd.h b/drivers/net/wireless/wl12xx/cmd.h
index 3734244..0ba4537 100644
--- a/drivers/net/wireless/wl12xx/cmd.h
+++ b/drivers/net/wireless/wl12xx/cmd.h
@@ -570,12 +570,21 @@ struct wl1271_cmd_set_peer_state {

u8 hlid;
u8 state;
u8 padding[2];
} __packed;

+struct wl1271_cmd_roc {
+ struct wl1271_cmd_header header;
+
+ u8 role_id;
+ u8 channel;
+ u8 band;
+ u8 padding;
+};
+
enum wl1271_ssid_type {
WL1271_SSID_TYPE_PUBLIC = 0,
WL1271_SSID_TYPE_HIDDEN = 1,
WL1271_SSID_TYPE_ANY = 2,
};

--
1.7.6.401.g6a319


2011-08-10 10:26:39

by Luciano Coelho

[permalink] [raw]
Subject: Re: [PATCH 08/40] wl12xx: wl12xx-fw-3 - update commands & events

On Wed, 2011-08-10 at 12:53 +0300, Eliad Peller wrote:
> hi Luca,
>
> thanks for your (ongoing) reviews.
> i'll apply your comments in the next version.

Thanks. It will still take some time for me to finish going through all
these 40 patches, as I don't want to starve my other workqueues. ;)


> On Wed, Aug 10, 2011 at 12:19 PM, Luciano Coelho <[email protected]> wrote:
> > On Tue, 2011-08-09 at 12:13 +0300, Eliad Peller wrote:
> >> /* unmask required mbox events */
> >> wl->event_mask = BSS_LOSE_EVENT_ID |
> >> SCAN_COMPLETE_EVENT_ID |
> >> PS_REPORT_EVENT_ID |
> >> - JOIN_EVENT_COMPLETE_ID |
> >> DISCONNECT_EVENT_COMPLETE_ID |
> >> RSSI_SNR_TRIGGER_0_EVENT_ID |
> >> PSPOLL_DELIVERY_FAILURE_EVENT_ID |
> >> SOFT_GEMINI_SENSE_EVENT_ID |
> >> PERIODIC_SCAN_REPORT_EVENT_ID |
> >> - PERIODIC_SCAN_COMPLETE_EVENT_ID;
> >> + PERIODIC_SCAN_COMPLETE_EVENT_ID |
> >> + DUMMY_PACKET_EVENT_ID |
> >> + PEER_REMOVE_COMPLETE_EVENT_ID |
> >> + BA_SESSION_RX_CONSTRAINT_EVENT_ID |
> >> + REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID;
> >>
> >> if (wl->bss_type == BSS_TYPE_AP_BSS)
> >> - wl->event_mask |= STA_REMOVE_COMPLETE_EVENT_ID |
> >> - INACTIVE_STA_EVENT_ID |
> >> + wl->event_mask |= INACTIVE_STA_EVENT_ID |
> >> MAX_TX_RETRY_EVENT_ID;
> >
> > Do we really need to mask this stuff separately?
> >
> we thought of masking the needed events according to the active role.
> anyway, i since there is no overlapping, and in the future there will
> be multiple roles, i guess we can just unmask them all together.

Yes, that was my point. I think we don't need to care about unmasking
different events for different roles, because the events shouldn't be
sent in the wrong roles.

Actually, I started wondering why do we need an event mask at all! Okay,
someone will say, for power-saving blahblah, but do we really have any
real use case where we can use this feature in a smart way?


> >> -int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type)
> >> +int wl1271_cmd_role_enable(struct wl1271 *wl, u8 role_type, u8 *role_id)
> >
> > s/wl1271_cmd_role_enable/wl12xx_cmd_role_enable/
> >
> > Same thing for wl1271_cmd_role_disable and all the other functions whose
> > declaration changed.
> >
> > I was thinking that we could use the role_id directly from the wl struct
> > here, but then I changed my mind, because I think it's not good that the
> > cmd functions themselves change the wl struct. At some point we need to
> > split the HW-related part of wl (phy) from the context-related elements
>
> well, that exactly our plan. after applying the all the pending series
> we'll start splitting up wl into global and per-vif data, in order to
> support multiple vifs.

Of course, I don't really see many different other options here. ;)


> > (vif). For most of the cases, if not all, the cmd functions only use
> > the HW-related elements.
> >
> every command that takes role_id as param is basically per-vif, so i
> guess you're wrong here :)

Right, but what I meant was *before* your patchset. And also I meant
the elements that are needed to send the command itself (like wl->flags,
wl->cmd_box_addr), not the elements that will actually go into the cmd
parameters. Anyway, what matters here is that we're aligned. :)


> >> +
> >> + memcpy(cmd->mac_address, wl->mac_addr, ETH_ALEN);
> >
> > To keep aligned with my comment about phy vs. vif context, I think it
> > would be nicer to pass the MAC address as an argument to this function
> > as well. When we implement multirole, we will need different MAC
> > addresses for each role, so we can't really use the value from wl.
> >
> you are right, but let's leave it for a later stage.
> (i have some patch that replaces all the wl->mac_addr to vif->addr)

Okay, when I wrote this I had actually not seen the other many commands
that take stuff from the wl struct. Let's do it all together.


> again, thanks for your reviews.
> i'll just apply all the required changes instead of ACKing each one :)

Yeah, easier like that.

--
Cheers,
Luca.


2011-08-09 09:13:57

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 13/40] wl12xx: wl12xx-fw-3 - change max/default template size

The max template size was increased in the new fw.
However, we should use the max size only when needed, as it
consumes some of the chip's memory.

Thus, by default initialize the templates to the default size.
Initialize to the maximum size only when required.

Use WL1271_CMD_TEMPL_DFLT_SIZE instead of some of the
predefined structs, as some of them didn't account
for additional IEs that might be added to the template.

Delete structs defintions not used after these changes.

Signed-off-by: Eliad Peller <[email protected]>
---
drivers/net/wireless/wl12xx/cmd.h | 3 ++-
drivers/net/wireless/wl12xx/init.c | 18 +++++++-----------
drivers/net/wireless/wl12xx/main.c | 2 +-
drivers/net/wireless/wl12xx/wl12xx_80211.h | 25 -------------------------
4 files changed, 10 insertions(+), 38 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/cmd.h b/drivers/net/wireless/wl12xx/cmd.h
index b948677..3734244 100644
--- a/drivers/net/wireless/wl12xx/cmd.h
+++ b/drivers/net/wireless/wl12xx/cmd.h
@@ -169,13 +169,14 @@ enum cmd_templ {

CMD_TEMPL_MAX = 0xff
};

/* unit ms */
#define WL1271_COMMAND_TIMEOUT 2000
-#define WL1271_CMD_TEMPL_MAX_SIZE 252
+#define WL1271_CMD_TEMPL_DFLT_SIZE 252
+#define WL1271_CMD_TEMPL_MAX_SIZE 548
#define WL1271_EVENT_TIMEOUT 750

struct wl1271_cmd_header {
__le16 id;
__le16 status;
/* payload */
diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c
index 0fdaba9..c733a63 100644
--- a/drivers/net/wireless/wl12xx/init.c
+++ b/drivers/net/wireless/wl12xx/init.c
@@ -36,19 +36,19 @@
int wl1271_sta_init_templates_config(struct wl1271 *wl)
{
int ret, i;

/* send empty templates for fw memory reservation */
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL,
- WL1271_CMD_TEMPL_MAX_SIZE,
+ WL1271_CMD_TEMPL_DFLT_SIZE,
0, WL1271_RATE_AUTOMATIC);
if (ret < 0)
return ret;

ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5,
- NULL, WL1271_CMD_TEMPL_MAX_SIZE, 0,
+ NULL, WL1271_CMD_TEMPL_DFLT_SIZE, 0,
WL1271_RATE_AUTOMATIC);
if (ret < 0)
return ret;

ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, NULL,
sizeof(struct wl12xx_null_data_template),
@@ -67,21 +67,19 @@ int wl1271_sta_init_templates_config(struct wl1271 *wl)
(struct wl12xx_qos_null_data_template),
0, WL1271_RATE_AUTOMATIC);
if (ret < 0)
return ret;

ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE, NULL,
- sizeof
- (struct wl12xx_probe_resp_template),
+ WL1271_CMD_TEMPL_DFLT_SIZE,
0, WL1271_RATE_AUTOMATIC);
if (ret < 0)
return ret;

ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON, NULL,
- sizeof
- (struct wl12xx_beacon_template),
+ WL1271_CMD_TEMPL_DFLT_SIZE,
0, WL1271_RATE_AUTOMATIC);
if (ret < 0)
return ret;

ret = wl1271_cmd_template_set(wl, CMD_TEMPL_ARP_RSP, NULL,
sizeof
@@ -89,13 +87,13 @@ int wl1271_sta_init_templates_config(struct wl1271 *wl)
0, WL1271_RATE_AUTOMATIC);
if (ret < 0)
return ret;

for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) {
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV, NULL,
- WL1271_CMD_TEMPL_MAX_SIZE, i,
+ WL1271_CMD_TEMPL_DFLT_SIZE, i,
WL1271_RATE_AUTOMATIC);
if (ret < 0)
return ret;
}

return 0;
@@ -188,21 +186,19 @@ static int wl1271_ap_init_templates_config(struct wl1271 *wl)

/*
* Put very large empty placeholders for all templates. These
* reserve memory for later.
*/
ret = wl1271_cmd_template_set(wl, CMD_TEMPL_AP_PROBE_RESPONSE, NULL,
- sizeof
- (struct wl12xx_probe_resp_template),
+ WL1271_CMD_TEMPL_MAX_SIZE,
0, WL1271_RATE_AUTOMATIC);
if (ret < 0)
return ret;

ret = wl1271_cmd_template_set(wl, CMD_TEMPL_AP_BEACON, NULL,
- sizeof
- (struct wl12xx_beacon_template),
+ WL1271_CMD_TEMPL_MAX_SIZE,
0, WL1271_RATE_AUTOMATIC);
if (ret < 0)
return ret;

ret = wl1271_cmd_template_set(wl, CMD_TEMPL_DEAUTH_AP, NULL,
sizeof
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index d254f2b..491c904f 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -4244,13 +4244,13 @@ int wl1271_init_ieee80211(struct wl1271 *wl)
wl->hw->wiphy->max_scan_ssids = 1;
/*
* Maximum length of elements in scanning probe request templates
* should be the maximum length possible for a template, without
* the IEEE80211 header of the template
*/
- wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
+ wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
sizeof(struct ieee80211_header);

/* make sure all our channels fit in the scanned_ch bitmask */
BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
ARRAY_SIZE(wl1271_channels_5ghz) >
WL1271_MAX_CHANNELS);
diff --git a/drivers/net/wireless/wl12xx/wl12xx_80211.h b/drivers/net/wireless/wl12xx/wl12xx_80211.h
index 18fe542..209aa8c 100644
--- a/drivers/net/wireless/wl12xx/wl12xx_80211.h
+++ b/drivers/net/wireless/wl12xx/wl12xx_80211.h
@@ -102,24 +102,12 @@ struct wl12xx_ie_country {
struct country_triplet triplets[MAX_COUNTRY_TRIPLETS];
} __packed;


/* Templates */

-struct wl12xx_beacon_template {
- struct ieee80211_header header;
- __le32 time_stamp[2];
- __le16 beacon_interval;
- __le16 capability;
- struct wl12xx_ie_ssid ssid;
- struct wl12xx_ie_rates rates;
- struct wl12xx_ie_rates ext_rates;
- struct wl12xx_ie_ds_params ds_params;
- struct wl12xx_ie_country country;
-} __packed;
-
struct wl12xx_null_data_template {
struct ieee80211_header header;
} __packed;

struct wl12xx_ps_poll_template {
__le16 fc;
@@ -143,25 +131,12 @@ struct wl12xx_arp_rsp_template {
u8 sender_hw[ETH_ALEN];
__be32 sender_ip;
u8 target_hw[ETH_ALEN];
__be32 target_ip;
} __packed;

-
-struct wl12xx_probe_resp_template {
- struct ieee80211_header header;
- __le32 time_stamp[2];
- __le16 beacon_interval;
- __le16 capability;
- struct wl12xx_ie_ssid ssid;
- struct wl12xx_ie_rates rates;
- struct wl12xx_ie_rates ext_rates;
- struct wl12xx_ie_ds_params ds_params;
- struct wl12xx_ie_country country;
-} __packed;
-
struct wl12xx_disconn_template {
struct ieee80211_header header;
__le16 disconn_reason;
} __packed;

#endif
--
1.7.6.401.g6a319


2011-08-09 09:14:17

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 24/40] wl12xx: call wl1271_cmd_set_peer_state() in AP mode

After adding a station, call wl1271_cmd_set_peer_state().
This is required for 11n support.

Change wl1271_cmd_set_peer_state() prototype to get hlid
as param.

Signed-off-by: Eliad Peller <[email protected]>
---
drivers/net/wireless/wl12xx/cmd.c | 6 +++---
drivers/net/wireless/wl12xx/cmd.h | 2 +-
drivers/net/wireless/wl12xx/main.c | 6 +++++-
3 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c
index 6ef9d13..7cf4d53 100644
--- a/drivers/net/wireless/wl12xx/cmd.c
+++ b/drivers/net/wireless/wl12xx/cmd.c
@@ -1318,26 +1318,26 @@ int wl1271_cmd_set_ap_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,

out:
kfree(cmd);
return ret;
}

-int wl1271_cmd_set_peer_state(struct wl1271 *wl)
+int wl1271_cmd_set_peer_state(struct wl1271 *wl, u8 hlid)
{
struct wl1271_cmd_set_peer_state *cmd;
int ret = 0;

- wl1271_debug(DEBUG_CMD, "cmd set sta state (hlid=%d)", wl->sta_hlid);
+ wl1271_debug(DEBUG_CMD, "cmd set sta state (hlid=%d)", hlid);

cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
ret = -ENOMEM;
goto out;
}

- cmd->hlid = wl->sta_hlid;
+ cmd->hlid = hlid;
cmd->state = WL1271_CMD_STA_STATE_CONNECTED;

ret = wl1271_cmd_send(wl, CMD_SET_PEER_STATE, cmd, sizeof(*cmd), 0);
if (ret < 0) {
wl1271_error("failed to send set STA state command");
goto out_free;
diff --git a/drivers/net/wireless/wl12xx/cmd.h b/drivers/net/wireless/wl12xx/cmd.h
index 6f2a831..2ae2d73 100644
--- a/drivers/net/wireless/wl12xx/cmd.h
+++ b/drivers/net/wireless/wl12xx/cmd.h
@@ -67,13 +67,13 @@ int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id, u8 hlid);
int wl1271_cmd_set_sta_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
u8 key_size, const u8 *key, const u8 *addr,
u32 tx_seq_32, u16 tx_seq_16);
int wl1271_cmd_set_ap_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
u16 tx_seq_16);
-int wl1271_cmd_set_peer_state(struct wl1271 *wl);
+int wl1271_cmd_set_peer_state(struct wl1271 *wl, u8 hlid);
int wl1271_roc(struct wl1271 *wl, u8 role_id);
int wl1271_croc(struct wl1271 *wl, u8 role_id);
int wl1271_cmd_add_peer(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid);
int wl1271_cmd_remove_peer(struct wl1271 *wl, u8 hlid);
int wl12xx_cmd_config_fwlog(struct wl1271 *wl);
int wl12xx_cmd_start_fwlog(struct wl1271 *wl);
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index e523f0b..6a87086 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -391,13 +391,13 @@ static int wl1271_check_operstate(struct wl1271 *wl, unsigned char operstate)
if (operstate != IF_OPER_UP)
return 0;

if (test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags))
return 0;

- ret = wl1271_cmd_set_peer_state(wl);
+ ret = wl1271_cmd_set_peer_state(wl, wl->sta_hlid);
if (ret < 0)
return ret;

wl1271_croc(wl, wl->role_id);

wl1271_info("Association completed.");
@@ -3641,12 +3641,16 @@ static int wl1271_op_sta_add(struct ieee80211_hw *hw,
goto out_free_sta;

ret = wl1271_cmd_add_peer(wl, sta, hlid);
if (ret < 0)
goto out_sleep;

+ ret = wl1271_cmd_set_peer_state(wl, hlid);
+ if (ret < 0)
+ goto out_sleep;
+
out_sleep:
wl1271_ps_elp_sleep(wl);

out_free_sta:
if (ret < 0)
wl1271_free_sta(wl, hlid);
--
1.7.6.401.g6a319


2011-08-09 09:13:38

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 04/40] wl12xx: temporarily disable 11n and advanced ap functions

In order to keep to driver compiling during the patchset,
while avoiding one-huge-patch, temporarily disable 11n
and some advanced ap functions.

These changes will be reverted later in the patchset, as
part of the patches for 11n and advanced ap functions
support for the new fw.

Signed-off-by: Eliad Peller <[email protected]>
---
drivers/net/wireless/wl12xx/acx.c | 8 ++++++++
drivers/net/wireless/wl12xx/main.c | 4 ++++
drivers/net/wireless/wl12xx/tx.c | 4 ++++
3 files changed, 16 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c
index 7e33f1f..75cefa7 100644
--- a/drivers/net/wireless/wl12xx/acx.c
+++ b/drivers/net/wireless/wl12xx/acx.c
@@ -1468,12 +1468,13 @@ out:

/* Configure BA session initiator/receiver parameters setting in the FW. */
int wl1271_acx_set_ba_session(struct wl1271 *wl,
enum ieee80211_back_parties direction,
u8 tid_index, u8 policy)
{
+#if 0
struct wl1271_acx_ba_session_policy *acx;
int ret;

wl1271_debug(DEBUG_ACX, "acx ba session setting");

acx = kzalloc(sizeof(*acx), GFP_KERNEL);
@@ -1512,18 +1513,22 @@ int wl1271_acx_set_ba_session(struct wl1271 *wl,
goto out;
}

out:
kfree(acx);
return ret;
+#endif
+ wl1271_info("11n is currently not supported");
+ return 0;
}

/* setup BA session receiver setting in the FW. */
int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn,
bool enable)
{
+#if 0
struct wl1271_acx_ba_receiver_setup *acx;
int ret;

wl1271_debug(DEBUG_ACX, "acx ba receiver session setting");

acx = kzalloc(sizeof(*acx), GFP_KERNEL);
@@ -1546,12 +1551,15 @@ int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn,
goto out;
}

out:
kfree(acx);
return ret;
+#endif
+ wl1271_info("11n is currently not supported");
+ return 0;
}

int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime)
{
struct wl1271_acx_fw_tsf_information *tsf_info;
int ret;
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index ba8dafaf..49ceee8 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -770,12 +770,13 @@ static int wl1271_plt_init(struct wl1271 *wl)
kfree(wl->target_mem_map);
wl->target_mem_map = NULL;

return ret;
}

+#if 0
static void wl1271_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_blks)
{
bool fw_ps;

/* only regulate station links */
if (hlid < WL1271_AP_STA_HLID_START)
@@ -820,12 +821,13 @@ static void wl1271_irq_update_links_status(struct wl1271 *wl,
wl->links[hlid].allocated_blks -= cnt;

wl1271_irq_ps_regulate_link(wl, hlid,
wl->links[hlid].allocated_blks);
}
}
+#endif

static void wl1271_fw_status(struct wl1271 *wl,
struct wl1271_fw_full_status *full_status)
{
struct wl1271_fw_common_status *status = &full_status->common;
struct timespec ts;
@@ -858,13 +860,15 @@ static void wl1271_fw_status(struct wl1271 *wl,
}

wl->tx_allocated_blocks -= freed_blocks;

if (wl->bss_type == BSS_TYPE_AP_BSS) {
/* Update num of allocated TX blocks per link and ps status */
+#if 0
wl1271_irq_update_links_status(wl, &full_status->ap);
+#endif
wl->tx_blocks_available += freed_blocks;
} else {
int avail = full_status->sta.tx_total - wl->tx_allocated_blocks;

/*
* The FW might change the total number of TX memblocks before
diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c
index c67340f..938af1d 100644
--- a/drivers/net/wireless/wl12xx/tx.c
+++ b/drivers/net/wireless/wl12xx/tx.c
@@ -108,12 +108,13 @@ static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl,
hdr = (struct ieee80211_hdr *)(skb->data +
sizeof(struct wl1271_tx_hw_descr));
if (ieee80211_is_auth(hdr->frame_control))
wl1271_acx_set_inconnection_sta(wl, hdr->addr1);
}

+#if 0
static void wl1271_tx_regulate_link(struct wl1271 *wl, u8 hlid)
{
bool fw_ps;
u8 tx_blks;

/* only regulate station links */
@@ -127,12 +128,13 @@ static void wl1271_tx_regulate_link(struct wl1271 *wl, u8 hlid)
* 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.
*/
if (fw_ps && tx_blks >= WL1271_PS_STA_MAX_BLOCKS)
wl1271_ps_link_start(wl, hlid, true);
}
+#endif

u8 wl1271_tx_get_hlid(struct sk_buff *skb)
{
struct ieee80211_tx_info *control = IEEE80211_SKB_CB(skb);

if (control->control.sta) {
@@ -381,13 +383,15 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb,
return ret;

wl1271_tx_fill_hdr(wl, skb, extra, info, hlid);

if (wl->bss_type == BSS_TYPE_AP_BSS) {
wl1271_tx_ap_update_inconnection_sta(wl, skb);
+#if 0
wl1271_tx_regulate_link(wl, hlid);
+#endif
} else {
wl1271_tx_update_filters(wl, skb);
}

/*
* The length of each packet is stored in terms of
--
1.7.6.401.g6a319


2011-08-09 09:14:31

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 32/40] wl12xx: don't remove key if hlid was already deleted

When wep key was removed after disconnection, sta_hlid was invalid,
and it resulted in a fw crash.

Signed-off-by: Eliad Peller <[email protected]>
---
drivers/net/wireless/wl12xx/main.c | 5 +++++
1 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index c873f24..b223c27 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -2590,12 +2590,17 @@ static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
will be cleared automatically on next CMD_JOIN. Ignore the
request silently, as we dont want the mac80211 to emit
an error message. */
if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
return 0;

+ /* don't remove key if hlid was already deleted */
+ if (action == KEY_REMOVE &&
+ wl->sta_hlid == WL1271_INVALID_LINK_ID)
+ return 0;
+
ret = wl1271_cmd_set_sta_key(wl, action,
id, key_type, key_size,
key, addr, tx_seq_32,
tx_seq_16);
if (ret < 0)
return ret;
--
1.7.6.401.g6a319


2011-08-10 09:19:26

by Luciano Coelho

[permalink] [raw]
Subject: Re: [PATCH 08/40] wl12xx: wl12xx-fw-3 - update commands & events

On Tue, 2011-08-09 at 12:13 +0300, Eliad Peller wrote:
> Change the commands and events according to the new fw api.
>
> The main change is the replacement of JOIN/DISCONNECT commands,
> with ROLE_START/ROLE_START commands.

I guess you meant ROLE_START/ROLE_STOP?


> diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c
> index 11b26d7..7d8d09b 100644
> --- a/drivers/net/wireless/wl12xx/boot.c
> +++ b/drivers/net/wireless/wl12xx/boot.c
> @@ -501,27 +501,26 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
> */
>
> /* unmask required mbox events */
> wl->event_mask = BSS_LOSE_EVENT_ID |
> SCAN_COMPLETE_EVENT_ID |
> PS_REPORT_EVENT_ID |
> - JOIN_EVENT_COMPLETE_ID |
> DISCONNECT_EVENT_COMPLETE_ID |
> RSSI_SNR_TRIGGER_0_EVENT_ID |
> PSPOLL_DELIVERY_FAILURE_EVENT_ID |
> SOFT_GEMINI_SENSE_EVENT_ID |
> PERIODIC_SCAN_REPORT_EVENT_ID |
> - PERIODIC_SCAN_COMPLETE_EVENT_ID;
> + PERIODIC_SCAN_COMPLETE_EVENT_ID |
> + DUMMY_PACKET_EVENT_ID |
> + PEER_REMOVE_COMPLETE_EVENT_ID |
> + BA_SESSION_RX_CONSTRAINT_EVENT_ID |
> + REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID;
>
> if (wl->bss_type == BSS_TYPE_AP_BSS)
> - wl->event_mask |= STA_REMOVE_COMPLETE_EVENT_ID |
> - INACTIVE_STA_EVENT_ID |
> + wl->event_mask |= INACTIVE_STA_EVENT_ID |
> MAX_TX_RETRY_EVENT_ID;

Do we really need to mask this stuff separately?


> diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c
> index b6ef65a..99d81b6 100644
> --- a/drivers/net/wireless/wl12xx/cmd.c
> +++ b/drivers/net/wireless/wl12xx/cmd.c
> @@ -360,67 +360,300 @@ static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask)
> return ret;
> }
>
> return 0;
> }
>
> -int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type)
> +int wl1271_cmd_role_enable(struct wl1271 *wl, u8 role_type, u8 *role_id)

s/wl1271_cmd_role_enable/wl12xx_cmd_role_enable/

Same thing for wl1271_cmd_role_disable and all the other functions whose
declaration changed.

I was thinking that we could use the role_id directly from the wl struct
here, but then I changed my mind, because I think it's not good that the
cmd functions themselves change the wl struct. At some point we need to
split the HW-related part of wl (phy) from the context-related elements
(vif). For most of the cases, if not all, the cmd functions only use
the HW-related elements.

Anyway, this small detour just supports the usage of role_id as a
separate argument instead of taking it from wl. ;)


> {
> - struct wl1271_cmd_join *join;
> - int ret, i;
> - u8 *bssid;
> + struct wl1271_cmd_role_enable *cmd;
> + int ret;
> +
> + wl1271_debug(DEBUG_CMD, "cmd role enable");
> +
> + if (WARN_ON(*role_id != WL1271_INVALID_ROLE_ID))
> + return -EINVAL;

Shouldn't we return -EBUSY here instead?

>
> - join = kzalloc(sizeof(*join), GFP_KERNEL);
> - if (!join) {
> + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
> + if (!cmd) {
> ret = -ENOMEM;
> goto out;
> }
>
> - wl1271_debug(DEBUG_CMD, "cmd join");
> + /* get role id */
> + cmd->role_id = find_first_zero_bit(wl->roles_map, WL1271_MAX_ROLES);
> + if (cmd->role_id >= WL1271_MAX_ROLES) {
> + ret = -EBUSY;
> + goto out_free;
> + }
> +
> + memcpy(cmd->mac_address, wl->mac_addr, ETH_ALEN);

To keep aligned with my comment about phy vs. vif context, I think it
would be nicer to pass the MAC address as an argument to this function
as well. When we implement multirole, we will need different MAC
addresses for each role, so we can't really use the value from wl.


> +int wl1271_cmd_role_disable(struct wl1271 *wl, u8 *role_id)
> +{
> + struct wl1271_cmd_role_disable *cmd;
> + int ret;
> +
> + wl1271_debug(DEBUG_CMD, "cmd role disable");
> +
> + if (WARN_ON(*role_id == WL1271_INVALID_ROLE_ID))
> + return -EINVAL;

Maybe we should return -ENOENT instead?


> +static int wl1271_allocate_link(struct wl1271 *wl, u8 *hlid)
> +{
> + u8 alloced = find_first_zero_bit(wl->links_map, WL1271_MAX_LINKS);

This is *very* netpicky, but could you call this variable "link" or
something instead of "alloced"? Alloced is annoying to read because of
the missing apostrophe! :P


> +int wl1271_cmd_role_start_sta(struct wl1271 *wl)
> +{
> + struct wl1271_cmd_role_start *cmd;
> + int ret;
> +
> + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
> + if (!cmd) {
> + ret = -ENOMEM;
> + goto out;
> + }
> +
> + wl1271_debug(DEBUG_CMD, "cmd role start sta %d", wl->role_id);
> +
> + cmd->role_id = wl->role_id;
> if (wl->band == IEEE80211_BAND_5GHZ)
> - join->bss_type |= WL1271_JOIN_CMD_BSS_TYPE_5GHZ;
> + cmd->band |= WL1271_BAND_5GHZ;
> + cmd->channel = wl->channel;
> + cmd->sta.basic_rate_set = cpu_to_le32(wl->basic_rate_set);
> + cmd->sta.beacon_interval = cpu_to_le16(wl->beacon_int);
> + cmd->sta.ssid_type = WL1271_SSID_TYPE_ANY;
> + cmd->sta.ssid_len = wl->ssid_len;
> + memcpy(cmd->sta.ssid, wl->ssid, wl->ssid_len);
> + memcpy(cmd->sta.bssid, wl->bssid, ETH_ALEN);
> + cmd->sta.local_rates = cpu_to_le32(wl->rate_set);
> +
> + if (wl->sta_hlid == WL1271_INVALID_LINK_ID) {
> + ret = wl1271_allocate_link(wl, &wl->sta_hlid);
> + if (ret)
> + goto out_free;
> + }
> + cmd->sta.hlid = wl->sta_hlid;
> + cmd->sta.session = wl->session_counter;
> + cmd->sta.remote_rates = cpu_to_le32(wl->rate_set);

Same thing here about all the vif context stuff that is in the wl
struct. But let's not care about it right now, in this case we can't
pass everything as separate args to this function. We'll need a
separate struct for it later on.


> +int wl1271_cmd_role_stop_sta(struct wl1271 *wl)
> +{
> + struct wl1271_cmd_role_stop *cmd;
> + int ret;
> +
> + if (WARN_ON(wl->sta_hlid == WL1271_INVALID_LINK_ID))
> + return -EINVAL;
> +
> + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
> + if (!cmd) {
> + ret = -ENOMEM;
> + goto out;
> + }
> +
> + wl1271_debug(DEBUG_CMD, "cmd role stop");

s/cmd role stop"/cmd role stop sta %d" wl->role_id/ just to keep it
consistent.


> +
> + cmd->role_id = wl->role_id;
> + cmd->disc_type = WL1271_DISC_IMMEDIATE;
> + cmd->reason = cpu_to_le16(1); /* STATUS_UNSPECIFIED */

Isn't there a more reasonable reason? :) In any case, this should at
least be in an enum together with the other possible reasons instead of
hardcoded here.


> +int wl1271_cmd_role_start_ap(struct wl1271 *wl)
> +{
> + struct wl1271_cmd_role_start *cmd;
> + struct ieee80211_bss_conf *bss_conf = &wl->vif->bss_conf;
> + int ret;
> +
> + wl1271_debug(DEBUG_CMD, "cmd start ap role");

Again, "cmd start role ap %d"...

> +
> + /*
> + * We currently do not support hidden SSID. The real SSID
> + * should be fetched from mac80211 first.
> + */
> + if (wl->ssid_len == 0) {
> + wl1271_warning("Hidden SSID currently not supported for AP");
> + ret = -EINVAL;
> + goto out;
> + }
> +
> + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
> + if (!cmd) {
> + ret = -ENOMEM;
> + goto out;
> + }
> +
> + cmd->role_id = wl->role_id;
> + cmd->ap.aging_period = cpu_to_le16(wl->conf.tx.ap_aging_period);
> + cmd->ap.bss_index = WL1271_AP_BSS_INDEX;
> + cmd->ap.global_hlid = WL1271_AP_GLOBAL_HLID;
> + cmd->ap.broadcast_hlid = WL1271_AP_BROADCAST_HLID;
> + cmd->ap.basic_rate_set = cpu_to_le32(wl->basic_rate_set);
> + cmd->ap.beacon_interval = cpu_to_le16(wl->beacon_int);
> + cmd->ap.dtim_interval = bss_conf->dtim_period;
> + cmd->ap.beacon_expiry = WL1271_AP_DEF_BEACON_EXP;
> + cmd->channel = wl->channel;
> + cmd->ap.ssid_len = wl->ssid_len;
> + cmd->ap.ssid_type = WL1271_SSID_TYPE_PUBLIC;
> + memcpy(cmd->ap.ssid, wl->ssid, wl->ssid_len);
> + cmd->ap.local_rates = cpu_to_le32(0xffffffff);
> +
> + switch (wl->band) {
> + case IEEE80211_BAND_2GHZ:
> + cmd->band = RADIO_BAND_2_4GHZ;
> + break;
> + case IEEE80211_BAND_5GHZ:
> + cmd->band = RADIO_BAND_5GHZ;
> + break;
> + default:
> + wl1271_warning("ap start - unknown band: %d", (int)wl->band);
> + cmd->band = RADIO_BAND_2_4GHZ;
> + break;
> + }
> +
> + ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0);
> + if (ret < 0) {
> + wl1271_error("failed to initiate cmd start bss");

"cmd start role"


> +int wl1271_cmd_role_stop_ap(struct wl1271 *wl)
> +{
> + struct wl1271_cmd_role_stop *cmd;
> + int ret;
> +
> + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
> + if (!cmd) {
> + ret = -ENOMEM;
> + goto out;
> + }
> +
> + wl1271_debug(DEBUG_CMD, "cmd role ap stop");

"cmd role stop ap %d"

This is all nitpicking again, but keeping this stuff consistent makes it
easier when grepping. ;)


> -int wl1271_cmd_set_sta_state(struct wl1271 *wl)
> +int wl1271_cmd_set_peer_state(struct wl1271 *wl)
> {
> - struct wl1271_cmd_set_sta_state *cmd;
> + struct wl1271_cmd_set_peer_state *cmd;
> int ret = 0;
>
> - wl1271_debug(DEBUG_CMD, "cmd set sta state");
> + wl1271_debug(DEBUG_CMD, "cmd set sta state (hlid=%d)", wl->sta_hlid);

"cmd set peer state"


> + cmd->hlid = wl->sta_hlid;
> cmd->state = WL1271_CMD_STA_STATE_CONNECTED;
>
> - ret = wl1271_cmd_send(wl, CMD_SET_STA_STATE, cmd, sizeof(*cmd), 0);
> + ret = wl1271_cmd_send(wl, CMD_SET_PEER_STATE, cmd, sizeof(*cmd), 0);
> if (ret < 0) {
> wl1271_error("failed to send set STA state command");

"...set peer state..."


> -int wl1271_cmd_add_sta(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid)
> +int wl1271_cmd_add_peer(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid)
> {
> - struct wl1271_cmd_add_sta *cmd;
> + struct wl1271_cmd_add_peer *cmd;
> int ret;
>
> wl1271_debug(DEBUG_CMD, "cmd add sta %d", (int)hlid);

"cmd add peer"


> @@ -1167,28 +1253,28 @@ int wl1271_cmd_add_sta(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid)
>
> cmd->supported_rates = cpu_to_le32(wl1271_tx_enabled_rates_get(wl,
> sta->supp_rates[wl->band]));
>
> wl1271_debug(DEBUG_CMD, "new sta rates: 0x%x", cmd->supported_rates);

s/sta/peer/


> - ret = wl1271_cmd_send(wl, CMD_ADD_STA, cmd, sizeof(*cmd), 0);
> + ret = wl1271_cmd_send(wl, CMD_ADD_PEER, cmd, sizeof(*cmd), 0);
> if (ret < 0) {
> wl1271_error("failed to initiate cmd add sta");

Again...


> -int wl1271_cmd_remove_sta(struct wl1271 *wl, u8 hlid)
> +int wl1271_cmd_remove_peer(struct wl1271 *wl, u8 hlid)
> {
> - struct wl1271_cmd_remove_sta *cmd;
> + struct wl1271_cmd_remove_peer *cmd;
> int ret;
>
> wl1271_debug(DEBUG_CMD, "cmd remove sta %d", (int)hlid);

and again...


> @@ -1198,23 +1284,24 @@ int wl1271_cmd_remove_sta(struct wl1271 *wl, u8 hlid)
>
> cmd->hlid = hlid;
> /* We never send a deauth, mac80211 is in charge of this */
> cmd->reason_opcode = 0;
> cmd->send_deauth_flag = 0;
>
> - ret = wl1271_cmd_send(wl, CMD_REMOVE_STA, cmd, sizeof(*cmd), 0);
> + ret = wl1271_cmd_send(wl, CMD_REMOVE_PEER, cmd, sizeof(*cmd), 0);
> if (ret < 0) {
> wl1271_error("failed to initiate cmd remove sta");

...and yet again.


> @@ -80,48 +83,58 @@ enum wl1271_commands {
> CMD_ENABLE_RX = 3,
> CMD_ENABLE_TX = 4,
> CMD_DISABLE_RX = 5,
> CMD_DISABLE_TX = 6,
> CMD_SCAN = 8,
> CMD_STOP_SCAN = 9,
> - CMD_START_JOIN = 11,
> CMD_SET_KEYS = 12,
> CMD_READ_MEMORY = 13,
> CMD_WRITE_MEMORY = 14,
> CMD_SET_TEMPLATE = 19,
> CMD_TEST = 23,
> CMD_NOISE_HIST = 28,
> - CMD_LNA_CONTROL = 32,
> + CMD_QUIET_ELEMENT_SET_STATE = 29,
> CMD_SET_BCN_MODE = 33,
> CMD_MEASUREMENT = 34,
> CMD_STOP_MEASUREMENT = 35,
> - CMD_DISCONNECT = 36,
> CMD_SET_PS_MODE = 37,
> CMD_CHANNEL_SWITCH = 38,
> CMD_STOP_CHANNEL_SWICTH = 39,
> CMD_AP_DISCOVERY = 40,
> CMD_STOP_AP_DISCOVERY = 41,
> - CMD_SPS_SCAN = 42,
> - CMD_STOP_SPS_SCAN = 43,
> CMD_HEALTH_CHECK = 45,
> CMD_DEBUG = 46,
> CMD_TRIGGER_SCAN_TO = 47,

Should we align all this?


> CMD_CONNECTION_SCAN_CFG = 48,
> CMD_CONNECTION_SCAN_SSID_CFG = 49,
> CMD_START_PERIODIC_SCAN = 50,
> CMD_STOP_PERIODIC_SCAN = 51,
> - CMD_SET_STA_STATE = 52,
> - CMD_CONFIG_FWLOGGER = 53,
> - CMD_START_FWLOGGER = 54,
> - CMD_STOP_FWLOGGER = 55,
> + CMD_SET_PEER_STATE = 52,
> + CMD_REMAIN_ON_CHANNEL = 53,
> + CMD_CANCEL_REMAIN_ON_CHANNEL = 54,
>
> - /* AP mode commands */
> - CMD_BSS_START = 60,
> - CMD_BSS_STOP = 61,
> - CMD_ADD_STA = 62,
> - CMD_REMOVE_STA = 63,
> + CMD_CONFIG_FWLOGGER = 55,
> + CMD_START_FWLOGGER = 56,
> + CMD_STOP_FWLOGGER = 57,
> +
> + /* AP commands */
> + CMD_ADD_PEER = 62,
> + CMD_REMOVE_PEER = 63,
> +
> + /* Role API */
> + CMD_ROLE_ENABLE = 70,
> + CMD_ROLE_DISABLE = 71,
> + CMD_ROLE_START = 72,
> + CMD_ROLE_STOP = 73,
> +
> + /* WIFI Direct */
> + CMD_WFD_START_DISCOVERY = 80,
> + CMD_WFD_STOP_DISCOVERY = 81,
> + CMD_WFD_ATTRIBUTE_CONFIG = 82,
> +
> + CMD_NOP = 100,

Please align.


> @@ -190,12 +201,13 @@ enum {
> CMD_STATUS_OUT_OF_MEMORY = 16,
> CMD_STATUS_STA_TABLE_FULL = 17,
> CMD_STATUS_RADIO_ERROR = 18,
> CMD_STATUS_WRONG_NESTING = 19,
> CMD_STATUS_TIMEOUT = 21, /* Driver internal use.*/
> CMD_STATUS_FW_RESET = 22, /* Driver internal use.*/
> + CMD_STATUS_TEMPLATE_OUT_OF_TEMPORARY_MEMORY = 23,

Should we use CMD_STATUS_TEMPLATE_OOM or something?

> +enum wl1271_band {
> + WL1271_BAND_2_4GHZ = 0, /* 2.4 Ghz band */
> + WL1271_BAND_5GHZ = 1, /* 5 Ghz band */
> + WL1271_BAND_JAPAN_4_9_GHZ = 2,
> + WL1271_BAND_DEFAULT = WL1271_BAND_2_4GHZ,
> + WL1271_BAND_INVALID = 0x7E,
> + WL1271_BAND_MAX_RADIO = 0x7F,
> +};

The comments here are unnecessary and could we align the ='s?


> + /* ap & p2p_go use the same struct */
> + struct {
> + /* Aging period in seconds*/
> + __le16 aging_period;

Maybe instead of having the comment in a separate line we could use:

__le16 aging_period; /* in secs */

> + /* Beacon expiry time in ms */
> + u8 beacon_expiry;

Same here.


> +enum wl1271_disconnection_type {
> + WL1271_DISC_IMMEDIATE,
> + WL1271_DISC_DE_AUTH,
> + WL1271_DISC_DIS_ASSOC,

Seems better if you use WL12XX_DISC_DEAUTH and WL12XX_DISC_DISASSOC.
But, in any case, this seems to be duplicate as it is already defined
below in enum wl1271_disconnect_type.


> +struct wl1271_cmd_role_stop {
> + struct wl1271_cmd_header header;
> +
> + u8 role_id;
> + u8 disc_type; /* de-auth/de-asso or not (only STA and P2P_CLI) */

I think we can remove the "de-auth/de-asso o not" as it doesn't really
say anything.


> +enum wl1271_cmd_lid_key_type {
> + UNICAST_LID_TYPE = 0,
> + BROADCAST_LID_TYPE = 1,
> + WEP_DEFAULT_LID_TYPE = 2
> +};

Doesn't LID_TYPE_UNICAST, LID_TYPE_BROADCAST and so on look better?


> @@ -493,75 +559,29 @@ struct wl1271_ext_radio_parms_cmd {
> enum wl1271_disconnect_type {
> DISCONNECT_IMMEDIATE,
> DISCONNECT_DEAUTH,
> DISCONNECT_DISASSOC
> };

Here, as I said above, the disconnection types are already defined.


> enum wl1271_ssid_type {
> - SSID_TYPE_PUBLIC = 0,
> - SSID_TYPE_HIDDEN = 1
> + WL1271_SSID_TYPE_PUBLIC = 0,
> + WL1271_SSID_TYPE_HIDDEN = 1,
> + WL1271_SSID_TYPE_ANY = 2,
> };

Since you're changing this, please use WL12XX and align the ='s.


> diff --git a/drivers/net/wireless/wl12xx/event.h b/drivers/net/wireless/wl12xx/event.h
> index e524ad6..2cc6788 100644
> --- a/drivers/net/wireless/wl12xx/event.h
> +++ b/drivers/net/wireless/wl12xx/event.h
> @@ -46,106 +46,91 @@ enum {
> RSSI_SNR_TRIGGER_5_EVENT_ID = BIT(5),
> RSSI_SNR_TRIGGER_6_EVENT_ID = BIT(6),
> RSSI_SNR_TRIGGER_7_EVENT_ID = BIT(7),
> MEASUREMENT_START_EVENT_ID = BIT(8),
> MEASUREMENT_COMPLETE_EVENT_ID = BIT(9),
> SCAN_COMPLETE_EVENT_ID = BIT(10),
> - SCHEDULED_SCAN_COMPLETE_EVENT_ID = BIT(11),
> + WFD_DISCOVERY_COMPLETE_EVENT_ID = BIT(11),
> AP_DISCOVERY_COMPLETE_EVENT_ID = BIT(12),
> PS_REPORT_EVENT_ID = BIT(13),
> PSPOLL_DELIVERY_FAILURE_EVENT_ID = BIT(14),
> DISCONNECT_EVENT_COMPLETE_ID = BIT(15),
> - JOIN_EVENT_COMPLETE_ID = BIT(16),
> + RESERVED2 = BIT(16),

Where is RESERVED1? Maybe this doesn't even have to be defined, just a
comment to make it clear we're jumping one value would suffice.


> struct event_mailbox {
> __le32 events_vector;
> __le32 events_mask;
> __le32 reserved_1;
> __le32 reserved_2;
>
> - u8 dbg_event_id;
> - u8 num_relevant_params;
> - __le16 reserved_3;
> - __le32 event_report_p1;
> - __le32 event_report_p2;
> - __le32 event_report_p3;
> -
> u8 number_of_scan_results;
> u8 scan_tag;
> - u8 reserved_4[2];
> - __le32 compl_scheduled_scan_status;
> + u8 completed_scan_status;
> + u8 reserved_3[1];

It doesn't have to be an array.


> + /* tuned channel (roc) */
> + u8 channel;

Maybe roc_channel would be clearer?


> + /* hlid removed (STA_REMOVE_COMPLETE_EVENT) */
> + __le16 hlid_removed_bitmap;

The comment doesn't help much here.


> + /* rx ba constraint */
> +
> + /* role id for which this constraint is set. 0xFF means any role. */
> + u8 role_id;

Can you move the comment about the role_id to the same line as it is
defined? Would look cleaner.

It would be nice if all these blocks would be defined in separate
structs, but you can decide. They actually seem to be different structs
in the firmware, because of all the "reserved" paddings. Even nicer if
they could be in a union, but that's not how the FW API is defined.
*sigh*


--
Cheers,
Luca.


2011-08-10 15:16:11

by Luciano Coelho

[permalink] [raw]
Subject: Re: [PATCH 20/40] wl12xx: update BT coex configuration params

On Tue, 2011-08-09 at 12:13 +0300, Eliad Peller wrote:
> - * Defines whether the SG will force WLAN host to enter/exit PSM
> + * The maximum time WLAN can gain the antenna for
> + * in WLAN PSM / BT master/slave BR

"WLAN can gain the antenna for"... for what?


> + /*
> + * The maximum time WLAN can gain the antenna for
> + * in WLAN PSM / BT master/slave EDR

Same here.


> + /* ??? */

[...]

> + /* ??? */

Can you figure out what this is? If not, add a "TODO: explain these
values".


> + * The threshold (percent) of max consequtive beacon misses before

s/consequtive/consecutive/


> + /* ??? */

Same as above.


> + CONF_SG_GENERAL_USAGE_BIT_MAP,



> + * Number of consequent BT voice frames not interrupted by WLAN

s/consequent/consecutive/



> @@ -357,17 +354,12 @@ static int wl1271_sta_hw_init(struct wl1271 *wl)
>
> /* Beacon filtering */
> ret = wl1271_init_beacon_filter(wl);
> if (ret < 0)
> return ret;
>
> - /* FM WLAN coexistence */
> - ret = wl1271_acx_fm_coex(wl);
> - if (ret < 0)
> - return ret;
> -

I guess this means that FM/WLAN coex is not used anymore. Can you say
it in the commit log too?

--
Cheers,
Luca.


2011-08-09 09:13:42

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 06/40] wl12xx: wl12xx-fw-3 - Update fw status struct

Update the fw status struct according to the new fw api.
All the roles use the same struct now.

The memory accounting was changed a bit according to
the struct changes.

Signed-off-by: Eliad Peller <[email protected]>
---
drivers/net/wireless/wl12xx/debugfs.c | 5 +--
drivers/net/wireless/wl12xx/main.c | 74 +++++++++++++--------------------
drivers/net/wireless/wl12xx/rx.c | 6 +-
drivers/net/wireless/wl12xx/rx.h | 2 +-
drivers/net/wireless/wl12xx/wl12xx.h | 55 +++++++++++--------------
5 files changed, 58 insertions(+), 84 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c
index fd1c301..3102652 100644
--- a/drivers/net/wireless/wl12xx/debugfs.c
+++ b/drivers/net/wireless/wl12xx/debugfs.c
@@ -346,16 +346,13 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf,
DRIVER_STATE_PRINT_INT(tx_queue_count[1]);
DRIVER_STATE_PRINT_INT(tx_queue_count[2]);
DRIVER_STATE_PRINT_INT(tx_queue_count[3]);
DRIVER_STATE_PRINT_INT(tx_packets_count);
DRIVER_STATE_PRINT_INT(tx_results_count);
DRIVER_STATE_PRINT_LHEX(flags);
- DRIVER_STATE_PRINT_INT(tx_blocks_freed[0]);
- DRIVER_STATE_PRINT_INT(tx_blocks_freed[1]);
- DRIVER_STATE_PRINT_INT(tx_blocks_freed[2]);
- DRIVER_STATE_PRINT_INT(tx_blocks_freed[3]);
+ DRIVER_STATE_PRINT_INT(tx_blocks_freed);
DRIVER_STATE_PRINT_INT(tx_security_last_seq_lsb);
DRIVER_STATE_PRINT_INT(rx_counter);
DRIVER_STATE_PRINT_INT(session_counter);
DRIVER_STATE_PRINT_INT(state);
DRIVER_STATE_PRINT_INT(bss_type);
DRIVER_STATE_PRINT_INT(channel);
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index a1608f1..1ac1762 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -824,71 +824,57 @@ static void wl1271_irq_update_links_status(struct wl1271 *wl,
wl->links[hlid].allocated_blks);
}
}
#endif

static void wl1271_fw_status(struct wl1271 *wl,
- struct wl1271_fw_full_status *full_status)
+ struct wl1271_fw_status *status)
{
- struct wl1271_fw_common_status *status = &full_status->common;
struct timespec ts;
u32 old_tx_blk_count = wl->tx_blocks_available;
- u32 freed_blocks = 0;
- int i;
+ int avail, freed_blocks;

- if (wl->bss_type == BSS_TYPE_AP_BSS) {
- wl1271_raw_read(wl, FW_STATUS_ADDR, status,
- sizeof(struct wl1271_fw_ap_status), false);
- } else {
- wl1271_raw_read(wl, FW_STATUS_ADDR, status,
- sizeof(struct wl1271_fw_sta_status), false);
- }
+ wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);

wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
"drv_rx_counter = %d, tx_results_counter = %d)",
status->intr,
status->fw_rx_counter,
status->drv_rx_counter,
status->tx_results_counter);

- /* update number of available TX blocks */
- for (i = 0; i < NUM_TX_QUEUES; i++) {
- freed_blocks += le32_to_cpu(status->tx_released_blks[i]) -
- wl->tx_blocks_freed[i];
-
- wl->tx_blocks_freed[i] =
- le32_to_cpu(status->tx_released_blks[i]);
- }
+ freed_blocks = le32_to_cpu(status->total_released_blks) -
+ wl->tx_blocks_freed;
+ wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks);

wl->tx_allocated_blocks -= freed_blocks;

- if (wl->bss_type == BSS_TYPE_AP_BSS) {
- /* Update num of allocated TX blocks per link and ps status */
-#if 0
- wl1271_irq_update_links_status(wl, &full_status->ap);
-#endif
- wl->tx_blocks_available += freed_blocks;
- } else {
- int avail = full_status->sta.tx_total - wl->tx_allocated_blocks;
+ avail = le32_to_cpu(status->tx_total) - wl->tx_allocated_blocks;

- /*
- * The FW might change the total number of TX memblocks before
- * we get a notification about blocks being released. Thus, the
- * available blocks calculation might yield a temporary result
- * which is lower than the actual available blocks. Keeping in
- * mind that only blocks that were allocated can be moved from
- * TX to RX, tx_blocks_available should never decrease here.
- */
- wl->tx_blocks_available = max((int)wl->tx_blocks_available,
- avail);
- }
+ /*
+ * The FW might change the total number of TX memblocks before
+ * we get a notification about blocks being released. Thus, the
+ * available blocks calculation might yield a temporary result
+ * which is lower than the actual available blocks. Keeping in
+ * mind that only blocks that were allocated can be moved from
+ * TX to RX, tx_blocks_available should never decrease here.
+ */
+ wl->tx_blocks_available = max((int)wl->tx_blocks_available,
+ avail);

/* if more blocks are available now, tx work can be scheduled */
if (wl->tx_blocks_available > old_tx_blk_count)
clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);

+ /* for AP update num of allocated TX blocks per link and ps status */
+ if (wl->bss_type == BSS_TYPE_AP_BSS) {
+#if 0
+ wl1271_irq_update_links_status(wl, status);
+#endif
+ }
+
/* update the host-chipset time offset */
getnstimeofday(&ts);
wl->time_offset = (timespec_to_ns(&ts) >> 10) -
(s64)le32_to_cpu(status->fw_localtime);
}

@@ -956,13 +942,13 @@ irqreturn_t wl1271_irq(int irq, void *cookie)
* wl1271_ps_elp_wakeup cannot be called concurrently.
*/
clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
smp_mb__after_clear_bit();

wl1271_fw_status(wl, wl->fw_status);
- intr = le32_to_cpu(wl->fw_status->common.intr);
+ intr = le32_to_cpu(wl->fw_status->intr);
intr &= WL1271_INTR_MASK;
if (!intr) {
done = true;
continue;
}

@@ -975,13 +961,13 @@ irqreturn_t wl1271_irq(int irq, void *cookie)
goto out;
}

if (likely(intr & WL1271_ACX_INTR_DATA)) {
wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");

- wl1271_rx(wl, &wl->fw_status->common);
+ wl1271_rx(wl, wl->fw_status);

/* Check if any tx blocks were freed */
spin_lock_irqsave(&wl->wl_lock, flags);
if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
wl1271_tx_total_queue_count(wl) > 0) {
spin_unlock_irqrestore(&wl->wl_lock, flags);
@@ -992,13 +978,13 @@ irqreturn_t wl1271_irq(int irq, void *cookie)
wl1271_tx_work_locked(wl);
} else {
spin_unlock_irqrestore(&wl->wl_lock, flags);
}

/* check for tx results */
- if (wl->fw_status->common.tx_results_counter !=
+ if (wl->fw_status->tx_results_counter !=
(wl->tx_results_count & 0xff))
wl1271_tx_complete(wl);

/* Make sure the deferred queues don't get too long */
defer_count = skb_queue_len(&wl->deferred_tx_queue) +
skb_queue_len(&wl->deferred_rx_queue);
@@ -1167,13 +1153,13 @@ static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
*/
if (!wl1271_ps_elp_wakeup(wl))
wl12xx_cmd_stop_fwlog(wl);

/* Read the first memory block address */
wl1271_fw_status(wl, wl->fw_status);
- first_addr = __le32_to_cpu(wl->fw_status->sta.log_start_addr);
+ first_addr = __le32_to_cpu(wl->fw_status->log_start_addr);
if (!first_addr)
goto out;

/* Traverse the memory blocks linked list */
addr = first_addr;
do {
@@ -1914,13 +1900,12 @@ out:
return ret;
}

static void __wl1271_op_remove_interface(struct wl1271 *wl,
bool reset_tx_queues)
{
- int i;

wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");

/* because of hardware recovery, we may get here twice */
if (wl->state != WL1271_STATE_ON)
return;
@@ -1995,14 +1980,13 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
* this is performed after the cancel_work calls and the associated
* mutex_lock, so that wl1271_op_add_interface does not accidentally
* get executed before all these vars have been reset.
*/
wl->flags = 0;

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

wl1271_debugfs_reset(wl);

kfree(wl->fw_status);
wl->fw_status = NULL;
kfree(wl->tx_res_if);
diff --git a/drivers/net/wireless/wl12xx/rx.c b/drivers/net/wireless/wl12xx/rx.c
index 1a957d6..4ed23a1 100644
--- a/drivers/net/wireless/wl12xx/rx.c
+++ b/drivers/net/wireless/wl12xx/rx.c
@@ -27,20 +27,20 @@
#include "wl12xx.h"
#include "acx.h"
#include "reg.h"
#include "rx.h"
#include "io.h"

-static u8 wl1271_rx_get_mem_block(struct wl1271_fw_common_status *status,
+static u8 wl1271_rx_get_mem_block(struct wl1271_fw_status *status,
u32 drv_rx_counter)
{
return le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]) &
RX_MEM_BLOCK_MASK;
}

-static u32 wl1271_rx_get_buf_size(struct wl1271_fw_common_status *status,
+static u32 wl1271_rx_get_buf_size(struct wl1271_fw_status *status,
u32 drv_rx_counter)
{
return (le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]) &
RX_BUF_SIZE_MASK) >> RX_BUF_SIZE_SHIFT_DIV;
}

@@ -160,13 +160,13 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length)
skb_queue_tail(&wl->deferred_rx_queue, skb);
queue_work(wl->freezable_wq, &wl->netstack_work);

return is_data;
}

-void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status)
+void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status)
{
struct wl1271_acx_mem_map *wl_mem_map = wl->target_mem_map;
u32 buf_size;
u32 fw_rx_counter = status->fw_rx_counter & NUM_RX_PKT_DESC_MOD_MASK;
u32 drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK;
u32 rx_counter;
diff --git a/drivers/net/wireless/wl12xx/rx.h b/drivers/net/wireless/wl12xx/rx.h
index 094fff8..5ca482b 100644
--- a/drivers/net/wireless/wl12xx/rx.h
+++ b/drivers/net/wireless/wl12xx/rx.h
@@ -124,10 +124,10 @@ struct wl1271_rx_descriptor {
u8 hlid; /* AP FW */
} __packed;
u8 pad_len;
u8 reserved;
} __packed;

-void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status);
+void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status);
u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band);

#endif
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index 360f3d2..260b78c 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -134,12 +134,13 @@ extern u32 wl12xx_debug_level;
#define WL1271_ELP_HW_STATE_ASLEEP 0
#define WL1271_ELP_HW_STATE_IRQ 1

#define WL1271_DEFAULT_BEACON_INT 100
#define WL1271_DEFAULT_DTIM_PERIOD 1

+#define WL1271_MAX_LINKS 8
#define WL1271_AP_GLOBAL_HLID 0
#define WL1271_AP_BROADCAST_HLID 1
#define WL1271_AP_STA_HLID_START 2

/*
* When in AP-mode, we allow (at least) this number of mem-blocks
@@ -227,59 +228,51 @@ struct wl1271_stats {

#define AP_MAX_STATIONS 5

/* Broadcast and Global links + links to stations */
#define AP_MAX_LINKS (AP_MAX_STATIONS + 2)

-/* FW status registers common for AP/STA */
-struct wl1271_fw_common_status {
+/* FW status registers */
+struct wl1271_fw_status {
__le32 intr;
u8 fw_rx_counter;
u8 drv_rx_counter;
u8 reserved;
u8 tx_results_counter;
__le32 rx_pkt_descs[NUM_RX_PKT_DESC];
- __le32 tx_released_blks[NUM_TX_QUEUES];
__le32 fw_localtime;
-} __packed;
-
-/* FW status registers for AP */
-struct wl1271_fw_ap_status {
- struct wl1271_fw_common_status common;
-
- /* Next fields valid only in AP FW */

/*
* A bitmap (where each bit represents a single HLID)
* to indicate if the station is in PS mode.
*/
__le32 link_ps_bitmap;

- /* Number of freed MBs per HLID */
- u8 tx_lnk_free_blks[AP_MAX_LINKS];
- u8 padding_1[1];
-} __packed;
+ /*
+ * A bitmap (where each bit represents a single HLID) to indicate
+ * if the station is in Fast mode
+ */
+ __le32 link_fast_bitmap;

-/* FW status registers for STA */
-struct wl1271_fw_sta_status {
- struct wl1271_fw_common_status common;
+ /* Cumulative counter of total released mem blocks since FW-reset */
+ __le32 total_released_blks;

- u8 tx_total;
- u8 reserved1;
- __le16 reserved2;
- __le32 log_start_addr;
-} __packed;
+ /* Size (in Memory Blocks) of TX pool */
+ __le32 tx_total;

-struct wl1271_fw_full_status {
- union {
- struct wl1271_fw_common_status common;
- struct wl1271_fw_sta_status sta;
- struct wl1271_fw_ap_status ap;
- };
-} __packed;
+ /* Cumulative counter of released mem-blocks per AC */
+ u8 tx_released_blks[NUM_TX_QUEUES];

+ /* Cumulative counter of freed MBs per HLID */
+ u8 tx_lnk_free_blks[WL1271_MAX_LINKS];
+
+ /* Cumulative counter of released Voice memory blocks */
+ u8 tx_voice_released_blks;
+ u8 padding_1[7];
+ __le32 log_start_addr;
+} __packed;

struct wl1271_rx_mem_pool_addr {
u32 addr;
u32 addr_extra;
};

@@ -398,13 +391,13 @@ struct wl1271 {
u8 ssid_len;
int channel;

struct wl1271_acx_mem_map *target_mem_map;

/* Accounting for allocated / available TX blocks on HW */
- u32 tx_blocks_freed[NUM_TX_QUEUES];
+ u32 tx_blocks_freed;
u32 tx_blocks_available;
u32 tx_allocated_blocks;
u32 tx_results_count;

/* Transmitted TX packets counter for chipset interface */
u32 tx_packets_count;
@@ -534,13 +527,13 @@ struct wl1271 {
struct wl1271_stats stats;

__le32 buffer_32;
u32 buffer_cmd;
u32 buffer_busyword[WL1271_BUSY_WORD_CNT];

- struct wl1271_fw_full_status *fw_status;
+ struct wl1271_fw_status *fw_status;
struct wl1271_tx_hw_res_if *tx_res_if;

struct ieee80211_vif *vif;

/* Current chipset configuration */
struct conf_drv_settings conf;
--
1.7.6.401.g6a319


2011-08-09 09:14:00

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 15/40] wl12xx: add set_rate_mgmt_params acx

Configure rate management parameters on hw init

Signed-off-by: Eliad Peller <[email protected]>
---
drivers/net/wireless/wl12xx/acx.c | 45 ++++++++++++++++++++++++++++++++++++
drivers/net/wireless/wl12xx/acx.h | 27 +++++++++++++++++++++
drivers/net/wireless/wl12xx/conf.h | 20 ++++++++++++++++
drivers/net/wireless/wl12xx/init.c | 4 +++
drivers/net/wireless/wl12xx/main.c | 21 ++++++++++++++++
5 files changed, 117 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c
index a545134..bb2e4fc 100644
--- a/drivers/net/wireless/wl12xx/acx.c
+++ b/drivers/net/wireless/wl12xx/acx.c
@@ -1704,6 +1704,51 @@ int wl1271_acx_fm_coex(struct wl1271 *wl)
}

out:
kfree(acx);
return ret;
}
+
+int wl1271_acx_set_rate_mgmt_params(struct wl1271 *wl)
+{
+ struct wl1271_acx_set_rate_mgmt_params *acx = NULL;
+ struct conf_rate_policy_settings *conf = &wl->conf.rate;
+ int ret;
+
+ wl1271_debug(DEBUG_ACX, "acx set rate mgmt params");
+ BUILD_BUG_ON(sizeof(conf->rate_retry_policy) !=
+ sizeof(acx->rate_retry_policy));
+ BUILD_BUG_ON(sizeof(*acx) % 4);
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx)
+ return -ENOMEM;
+
+ acx->index = ACX_RATE_MGMT_ALL_PARAMS;
+ acx->rate_retry_score = cpu_to_le16(conf->rate_retry_score);
+ acx->per_add = cpu_to_le16(conf->per_add);
+ acx->per_th1 = cpu_to_le16(conf->per_th1);
+ acx->per_th2 = cpu_to_le16(conf->per_th2);
+ acx->max_per = cpu_to_le16(conf->max_per);
+ acx->inverse_curiosity_factor = conf->inverse_curiosity_factor;
+ acx->tx_fail_low_th = conf->tx_fail_low_th;
+ acx->tx_fail_high_th = conf->tx_fail_high_th;
+ acx->per_alpha_shift = conf->per_alpha_shift;
+ acx->per_add_shift = conf->per_add_shift;
+ acx->per_beta1_shift = conf->per_beta1_shift;
+ acx->per_beta2_shift = conf->per_beta2_shift;
+ acx->rate_check_up = conf->rate_check_up;
+ acx->rate_check_down = conf->rate_check_down;
+ memcpy(acx->rate_retry_policy, conf->rate_retry_policy,
+ sizeof(acx->rate_retry_policy));
+
+ ret = wl1271_cmd_configure(wl, ACX_SET_RATE_MAMAGEMENT_PARAMS,
+ acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1271_warning("acx set rate mgmt params failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h
index 5a2e9bc..2ea71d1 100644
--- a/drivers/net/wireless/wl12xx/acx.h
+++ b/drivers/net/wireless/wl12xx/acx.h
@@ -1150,12 +1150,38 @@ struct wl1271_acx_fm_coex {
* The swallow clock difference of the swallowing mechanism.
* 0xFF = use FW default
*/
u8 swallow_clk_diff;
} __packed;

+#define ACX_RATE_MGMT_ALL_PARAMS 0xff
+#define ACX_RATE_MGMT_NUM_OF_RATES 13
+struct wl1271_acx_set_rate_mgmt_params {
+ struct acx_header header;
+
+ /* the param we configure */
+ u8 index;
+ u8 padding1; /* MISSING */
+ __le16 rate_retry_score;
+ __le16 per_add;
+ __le16 per_th1;
+ __le16 per_th2;
+ __le16 max_per;
+ u8 inverse_curiosity_factor;
+ u8 tx_fail_low_th;
+ u8 tx_fail_high_th;
+ u8 per_alpha_shift;
+ u8 per_add_shift;
+ u8 per_beta1_shift;
+ u8 per_beta2_shift;
+ u8 rate_check_up;
+ u8 rate_check_down;
+ u8 rate_retry_policy[ACX_RATE_MGMT_NUM_OF_RATES];
+ u8 padding2[2]; /* MISSING */
+} __packed;
+
enum {
ACX_WAKE_UP_CONDITIONS = 0x0002,
ACX_MEM_CFG = 0x0003,
ACX_SLOT = 0x0004,
ACX_AC_CFG = 0x0007,
ACX_MEM_MAP = 0x0008,
@@ -1290,8 +1316,9 @@ int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn,
int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime);
int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, bool enable);
int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl);
int wl1271_acx_config_ps(struct wl1271 *wl);
int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr);
int wl1271_acx_fm_coex(struct wl1271 *wl);
+int wl1271_acx_set_rate_mgmt_params(struct wl1271 *wl);

#endif /* __WL1271_ACX_H__ */
diff --git a/drivers/net/wireless/wl12xx/conf.h b/drivers/net/wireless/wl12xx/conf.h
index 6080e01..ebc8c6b 100644
--- a/drivers/net/wireless/wl12xx/conf.h
+++ b/drivers/net/wireless/wl12xx/conf.h
@@ -1306,12 +1306,31 @@ struct conf_fwlog {
u8 output;

/* Regulates the frequency of log messages */
u8 threshold;
};

+#define CONF_RATE_RETRY_POLICY_LEN 13
+struct conf_rate_policy_settings {
+ u16 rate_retry_score;
+ u16 per_add;
+ u16 per_th1;
+ u16 per_th2;
+ u16 max_per;
+ u8 inverse_curiosity_factor;
+ u8 tx_fail_low_th;
+ u8 tx_fail_high_th;
+ u8 per_alpha_shift;
+ u8 per_add_shift;
+ u8 per_beta1_shift;
+ u8 per_beta2_shift;
+ u8 rate_check_up;
+ u8 rate_check_down;
+ u8 rate_retry_policy[CONF_RATE_RETRY_POLICY_LEN];
+};
+
struct conf_drv_settings {
struct conf_sg_settings sg;
struct conf_rx_settings rx;
struct conf_tx_settings tx;
struct conf_conn_settings conn;
struct conf_itrim_settings itrim;
@@ -1324,9 +1343,10 @@ struct conf_drv_settings {
struct conf_memory_settings mem_wl127x;
struct conf_memory_settings mem_wl128x;
struct conf_fm_coex fm_coex;
struct conf_rx_streaming_settings rx_streaming;
struct conf_fwlog fwlog;
u8 hci_io_ds;
+ struct conf_rate_policy_settings rate;
};

#endif
diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c
index 10a66c7..4691297 100644
--- a/drivers/net/wireless/wl12xx/init.c
+++ b/drivers/net/wireless/wl12xx/init.c
@@ -712,12 +712,16 @@ int wl1271_hw_init(struct wl1271 *wl)
else
ret = wl1271_sta_hw_init_post_mem(wl);

if (ret < 0)
goto out_free_memmap;

+ ret = wl1271_acx_set_rate_mgmt_params(wl);
+ if (ret < 0)
+ goto out_free_memmap;
+
/* Configure initiator BA sessions policies */
ret = wl1271_set_ba_policies(wl);
if (ret < 0)
goto out_free_memmap;

return 0;
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index b0fd1fa..153189b 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -376,12 +376,33 @@ static struct conf_drv_settings default_conf = {
.severity = 0,
.timestamp = WL12XX_FWLOG_TIMESTAMP_DISABLED,
.output = WL12XX_FWLOG_OUTPUT_HOST,
.threshold = 0,
},
.hci_io_ds = HCI_IO_DS_6MA,
+ .rate = {
+ .rate_retry_score = 32000,
+ .per_add = 8192,
+ .per_th1 = 2048,
+ .per_th2 = 4096,
+ .max_per = 8100,
+ .inverse_curiosity_factor = 5,
+ .tx_fail_low_th = 4,
+ .tx_fail_high_th = 10,
+ .per_alpha_shift = 4,
+ .per_add_shift = 13,
+ .per_beta1_shift = 10,
+ .per_beta2_shift = 8,
+ .rate_check_up = 2,
+ .rate_check_down = 12,
+ .rate_retry_policy = {
+ 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00,
+ },
+ },
};

static char *fwlog_param;

static void __wl1271_op_remove_interface(struct wl1271 *wl,
bool reset_tx_queues);
--
1.7.6.401.g6a319


2011-08-11 12:31:07

by Eliad Peller

[permalink] [raw]
Subject: Re: [PATCH 00/40] wl12xx: move to wl12xx-fw-3

On Thu, Aug 11, 2011 at 2:57 PM, Luciano Coelho <[email protected]> wrote:
> On Tue, 2011-08-09 at 12:13 +0300, Eliad Peller wrote:
>> The new wl12xx fw (ver 7.3.0.0.75) had some major api changes.
>> The main change was the addition of multi-role concept, which
>> will later allow using multiple vifs concurrently.
>>
>> Consequently, this design change caused api changes for most
>> of the api commands, as a new role_id had to be added.
>>
>> This patchset migrates the fw to use the new fw api (a new
>> fw filename is used, as there is no backward compatability
>> with older firmwares).
>
> Okay, I'm done with my review! Lots of small nitpicking, but this in
> general looks very good! Thanks a lot for the good work, guys!
>
thanks a lot for your review.
i'm working on fixing all the issues, and i'll resubmit.

Eliad.

2011-08-09 09:13:55

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 12/40] wl12xx: wl12xx-fw-3 - rx/tx changes

Update the rx/tx descriptors according to the new fw api.

Signed-off-by: Eliad Peller <[email protected]>
---
drivers/net/wireless/wl12xx/rx.h | 7 ++-----
drivers/net/wireless/wl12xx/tx.c | 15 +++++++++++----
drivers/net/wireless/wl12xx/tx.h | 14 ++++----------
drivers/net/wireless/wl12xx/wl12xx.h | 2 +-
4 files changed, 18 insertions(+), 20 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/rx.h b/drivers/net/wireless/wl12xx/rx.h
index 5ca482b..87d4827 100644
--- a/drivers/net/wireless/wl12xx/rx.h
+++ b/drivers/net/wireless/wl12xx/rx.h
@@ -83,13 +83,13 @@
* RX Descriptor status
*
* Bits 0-2 - error code
* Bits 3-5 - process_id tag (AP mode FW)
* Bits 6-7 - reserved
*/
-#define WL1271_RX_DESC_STATUS_MASK 0x07
+#define WL1271_RX_DESC_STATUS_MASK 0x03

#define WL1271_RX_DESC_SUCCESS 0x00
#define WL1271_RX_DESC_DECRYPT_FAIL 0x01
#define WL1271_RX_DESC_MIC_FAIL 0x02
#define WL1271_RX_DESC_DRIVER_RX_Q_FAIL 0x03

@@ -116,16 +116,13 @@ struct wl1271_rx_descriptor {
u8 rate;
u8 channel;
s8 rssi;
u8 snr;
__le32 timestamp;
u8 packet_class;
- union {
- u8 process_id; /* STA FW */
- u8 hlid; /* AP FW */
- } __packed;
+ u8 hlid;
u8 pad_len;
u8 reserved;
} __packed;

void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status);
u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band);
diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c
index 43f21a3..2b17692 100644
--- a/drivers/net/wireless/wl12xx/tx.c
+++ b/drivers/net/wireless/wl12xx/tx.c
@@ -273,24 +273,23 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
} else {
/* configure the tx attributes */
tx_attr =
wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER;
}

- if (wl->bss_type != BSS_TYPE_AP_BSS) {
- desc->aid = hlid;
+ desc->hlid = hlid;

+ if (wl->bss_type != BSS_TYPE_AP_BSS) {
/* if the packets are destined for AP (have a STA entry)
send them with AP rate policies, otherwise use default
basic rates */
if (control->control.sta)
rate_idx = ACX_TX_AP_FULL_RATE;
else
rate_idx = ACX_TX_BASIC_RATE;
} else {
- desc->hlid = hlid;
switch (hlid) {
case WL1271_AP_GLOBAL_HLID:
rate_idx = ACX_TX_AP_MODE_MGMT_RATE;
break;
case WL1271_AP_BROADCAST_HLID:
rate_idx = ACX_TX_AP_MODE_BCST_RATE;
@@ -372,13 +371,21 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb,
}
}

if (wl->bss_type == BSS_TYPE_AP_BSS)
hlid = wl1271_tx_get_hlid(skb);
else
- hlid = TX_HW_DEFAULT_AID;
+ if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
+ hlid = wl->sta_hlid;
+ else
+ hlid = wl->dev_hlid;
+
+ if (hlid == WL1271_INVALID_LINK_ID) {
+ wl1271_error("invalid hlid. dropping skb 0x%p", skb);
+ return -EINVAL;
+ }

ret = wl1271_tx_allocate(wl, skb, extra, buf_offset, hlid);
if (ret < 0)
return ret;

wl1271_tx_fill_hdr(wl, skb, extra, info, hlid);
diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/tx.h
index 5d719b5..b712d7b 100644
--- a/drivers/net/wireless/wl12xx/tx.h
+++ b/drivers/net/wireless/wl12xx/tx.h
@@ -26,15 +26,12 @@
#define __TX_H__

#define TX_HW_BLOCK_SIZE 252

#define TX_HW_MGMT_PKT_LIFETIME_TU 2000
#define TX_HW_AP_MODE_PKT_LIFETIME_TU 8000
-/* The chipset reference driver states, that the "aid" value 1
- * is for infra-BSS, but is still always used */
-#define TX_HW_DEFAULT_AID 1

#define TX_HW_ATTR_SAVE_RETRIES BIT(0)
#define TX_HW_ATTR_HEADER_PAD BIT(1)
#define TX_HW_ATTR_SESSION_COUNTER (BIT(2) | BIT(3) | BIT(4))
#define TX_HW_ATTR_RATE_POLICY (BIT(5) | BIT(6) | BIT(7) | \
BIT(8) | BIT(9))
@@ -113,30 +110,27 @@ struct wl1271_tx_hw_descr {
/* Bitwise fields - see TX_ATTR... definitions above. */
__le16 tx_attr;
/* Packet identifier used also in the Tx-Result. */
u8 id;
/* The packet TID value (as User-Priority) */
u8 tid;
- union {
- /* STA - Identifier of the remote STA in IBSS, 1 in infra-BSS */
- u8 aid;
- /* AP - host link ID (HLID) */
- u8 hlid;
- } __packed;
+ /* host link ID (HLID) */
+ u8 hlid;
u8 reserved;
} __packed;

enum wl1271_tx_hw_res_status {
TX_SUCCESS = 0,
TX_HW_ERROR = 1,
TX_DISABLED = 2,
TX_RETRY_EXCEEDED = 3,
TX_TIMEOUT = 4,
TX_KEY_NOT_FOUND = 5,
TX_PEER_NOT_FOUND = 6,
- TX_SESSION_MISMATCH = 7
+ TX_SESSION_MISMATCH = 7,
+ TX_LINK_NOT_VALID = 8,
};

struct wl1271_tx_hw_res_descr {
/* Packet Identifier - same value used in the Tx descriptor.*/
u8 id;
/* The status of the transmission, indicating success or one of
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index b47cd06..a732932 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -156,13 +156,13 @@ extern u32 wl12xx_debug_level;
*/
#define WL1271_PS_STA_MAX_BLOCKS (2 * 9)

#define WL1271_AP_BSS_INDEX 0
#define WL1271_AP_DEF_BEACON_EXP 20

-#define ACX_TX_DESCRIPTORS 32
+#define ACX_TX_DESCRIPTORS 16

#define WL1271_AGGR_BUFFER_SIZE (4 * PAGE_SIZE)

enum wl1271_state {
WL1271_STATE_OFF,
WL1271_STATE_ON,
--
1.7.6.401.g6a319


2011-08-09 19:29:11

by Luciano Coelho

[permalink] [raw]
Subject: Re: [PATCH 07/40] wl12xx: wl12xx-fw-3 - update acx commands

On Tue, 2011-08-09 at 12:13 +0300, Eliad Peller wrote:
> Update the acx commands according to the new fw api.
>
> The main change in most of the ACXs is the addition
> of a new role_id/link_id field, which is required
> for multi-role operation.
>
> Currently, we don't really support multi-role, as
> most of our data (inside wl) is global.
> As the current fw doesn't support concurrent roles
> yet, keep it this way and add wl->role_id and
> wl->sta_hlid to save the active role/link.
>
> Signed-off-by: Eliad Peller <[email protected]>
> ---

Same thing here as with the previous patch. Can you use wl12xx instead
of wl1271 for the new (or renamed or re-argumented) functions and
structs?

Otherwise I don't have any other comments to this patch. There's
something I want to discuss with you about the role_id stuff, but I
think it's easier to do over IRC. ;)


--
Cheers,
Luca.


2011-08-10 19:39:46

by Luciano Coelho

[permalink] [raw]
Subject: Re: [PATCH 22/40] wl12xx: use dynamic hlids for AP-mode

On Tue, 2011-08-09 at 12:13 +0300, Eliad Peller wrote:
> @@ -300,23 +300,18 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
> basic rates */
> if (control->control.sta)
> rate_idx = ACX_TX_AP_FULL_RATE;
> else
> rate_idx = ACX_TX_BASIC_RATE;
> } else {
> - switch (hlid) {
> - case WL1271_AP_GLOBAL_HLID:
> + if (hlid == wl->ap_global_hlid)
> rate_idx = ACX_TX_AP_MODE_MGMT_RATE;
> - break;
> - case WL1271_AP_BROADCAST_HLID:
> + else if (hlid == wl->ap_bcast_hlid)

Extra whitespace after ==.


--
Cheers,
Luca.


2011-08-11 11:03:08

by Eliad Peller

[permalink] [raw]
Subject: Re: [PATCH 18/40] wl12xx: replace dummy_join with ROC/CROC commands

On Wed, Aug 10, 2011 at 5:31 PM, Luciano Coelho <[email protected]> wrote:
> On Tue, 2011-08-09 at 12:13 +0300, Eliad Peller wrote:
>> The ROC command asks the fw stay on the channel of the given
>> hlid. it currently has 2 primary functions:
>>
>> 1. Allow tx/rx from the device role.
>>
>> In order to tx/rx packets while the stations is not associated
>> (e.g. auth req/resp), the device role has to be used, along
>> with ROC on its link.
>>
>> Keep the logic similiar to the one used in dummy_join. However,
>> since we can't scan while we ROC, we add CROC before starting
>> a scan, and ROC again (if needed) on scan complete.
>>
>> 2. Keeping the antenna for a specific link.
>>
>> We ROC until the connection was completed (after EAPOLs exchange)
>> in order to prevent BT coex operations from taking the antenna
>> and failing the connection (after this stage, psm can be used).
>>
>> During association, we ROC on the station role, and then CROC
>> the device role, thus assuring being ROC during all the connection
>> process.
>
> Nice explanations. ?I was wondering if we should have this somewhere in
> the code too, so that it's easier to figure out what is going on without
> digging into git logs...
>
>
>> Replace the WL1271_FLAG_JOINED with a new WL1271_FLAG_ROC,
>> indicating the fw was configured to ROC. Add a roc bitmap
>> to indicate what roles are currently ROCed.
>
> Is it really possible to be ROCed in more than one role? They could be
> running on different channels, so how could we physically ROC more than
> once at the same time?
>
we can do multiple ROCs on the same channel (for different roles).
e.g. during connection, we ROC (concurrently) on the device and station roles.

>
>> Add wl1271_roc/croc functions in order to wrap the roc/croc
>> commands while taking care of the roc bitmap.
>>
>> The current ROC/CROC state-machine is a bit complicated. In
>> the future we'll probably want to use wpa_supplicant to control
>> the ROC during connection.
>
> But when we have multirole, we may have several instances of
> wpa_supplicant/hostap running, so there may be some conflicts of
> interest there. ?I think it's better to keep ROCing in a centralized
> place (ie. the driver).
>
still, some of the logic (i.e. ROC until connection) should be in the
supplicant.
of course the driver will have to organize it all (e.g. return -EBUSY).

Eliad.

2011-08-10 11:32:58

by Luciano Coelho

[permalink] [raw]
Subject: Re: [PATCH 09/40] wl12xx: enable/disable role on interface add/remove

On Tue, 2011-08-09 at 12:13 +0300, Eliad Peller wrote:
> +static u8 wl1271_get_role_type(struct wl1271 *wl)
> +{
> + switch (wl->bss_type) {
> + case BSS_TYPE_AP_BSS:
> + return WL1271_ROLE_AP;
> +
> + case BSS_TYPE_STA_BSS:
> + return WL1271_ROLE_STA;
> +
> + default:
> + wl1271_info("invalid bss_type: %d", wl->bss_type);
> + }
> + return 0xff;
> +}
> +
> static int wl1271_op_add_interface(struct ieee80211_hw *hw,
> struct ieee80211_vif *vif)
> {
> struct wl1271 *wl = hw->priv;
> struct wiphy *wiphy = hw->wiphy;
> int retries = WL1271_BOOT_RETRIES;
> @@ -1836,12 +1851,17 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
> goto power_off;
>
> ret = wl1271_boot(wl);
> if (ret < 0)
> goto power_off;
>
> + ret = wl1271_cmd_role_enable(wl, wl1271_get_role_type(wl),
> + &wl->role_id);
> + if (ret < 0)
> + goto irq_disable;
> +

This doesn't look right, because if the type is invalid, you will return
0xff and it will still be sent anyway to the firmware via
CMD_ROLE_ENABLE. It will _probably_ still work as expected, because the
firmware will hopefully return an error to that command and we will fail
the op_add_interface. But this will be ugly, because we'll print
"firmware boot failed", which is not true and so on.

Maybe you should add a role_type to wl (we will most likely need it in
the vif struct later anyway) or somehow merge this with the existing
bss_type. At least you could check the role type in the same "switch
(vif->type)".


> static void __wl1271_op_remove_interface(struct wl1271 *wl,
> bool reset_tx_queues)
> {
> + int ret;
>
> wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
>
> /* because of hardware recovery, we may get here twice */
> if (wl->state != WL1271_STATE_ON)
> return;
> @@ -1924,12 +1945,29 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
> wl->scan.state = WL1271_SCAN_STATE_IDLE;
> memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
> wl->scan.req = NULL;
> ieee80211_scan_completed(wl->hw, true);
> }
>
> + if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
> + /* disable active roles */
> + ret = wl1271_ps_elp_wakeup(wl);
> + if (ret < 0) {
> + /*
> + * do nothing. we are going to power off the chip
> + * anyway. handle this case when we'll really
> + * support multi-role...
> + */
> + }
> + wl1271_cmd_role_disable(wl, &wl->role_id);

Okay, we can do nothing for now, but should we then at least skip the
wl1271_cmd_role_disable() call? I guess that will also fail if we could
not wake up...

--
Cheers,
Luca.


2011-08-09 09:14:40

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 37/40] wl12xx: don't wait for disconnection event

Sometimes the fw doesn't send the DISCONNECT_EVENT_COMPLETE_ID
on station role stop, so don't wait for it.

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

diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c
index 9ef8621..ad926d2 100644
--- a/drivers/net/wireless/wl12xx/cmd.c
+++ b/drivers/net/wireless/wl12xx/cmd.c
@@ -640,18 +640,12 @@ int wl1271_cmd_role_stop_sta(struct wl1271 *wl)
ret = wl1271_cmd_send(wl, CMD_ROLE_STOP, cmd, sizeof(*cmd), 0);
if (ret < 0) {
wl1271_error("failed to initiate cmd role stop");
goto out_free;
}

- ret = wl1271_cmd_wait_for_event(wl, DISCONNECT_EVENT_COMPLETE_ID);
- if (ret < 0) {
- wl1271_error("cmd role stop sta event completion error");
- goto out_free;
- }
-
wl1271_free_link(wl, &wl->sta_hlid);

out_free:
kfree(cmd);

out:
--
1.7.6.401.g6a319


2011-08-09 09:13:51

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 10/40] wl12xx: add device role commands

The device role is a special role used for rx and tx frames
prior to association (as the STA role can get packets only
from its associated bssid)

Since this role is required for the sta association process,
we enable it when a new sta interface is created.

Signed-off-by: Eliad Peller <[email protected]>
---
drivers/net/wireless/wl12xx/cmd.c | 91 ++++++++++++++++++++++++++++++++++
drivers/net/wireless/wl12xx/main.c | 15 +++++-
drivers/net/wireless/wl12xx/wl12xx.h | 1 +
3 files changed, 106 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c
index 99d81b6..94942c1 100644
--- a/drivers/net/wireless/wl12xx/cmd.c
+++ b/drivers/net/wireless/wl12xx/cmd.c
@@ -455,12 +455,103 @@ static void wl1271_free_link(struct wl1271 *wl, u8 *hlid)
return;

__clear_bit(*hlid, wl->links_map);
*hlid = WL1271_INVALID_LINK_ID;
}

+int wl1271_cmd_role_start_dev(struct wl1271 *wl)
+{
+ struct wl1271_cmd_role_start *cmd;
+ int ret;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ wl1271_debug(DEBUG_CMD, "cmd role start dev %d", wl->dev_role_id);
+
+ cmd->role_id = wl->dev_role_id;
+ if (wl->band == IEEE80211_BAND_5GHZ)
+ cmd->band |= WL1271_BAND_5GHZ;
+ cmd->channel = wl->channel;
+
+ if (wl->dev_hlid == WL1271_INVALID_LINK_ID) {
+ ret = wl1271_allocate_link(wl, &wl->dev_hlid);
+ if (ret)
+ goto out_free;
+ }
+ cmd->device.hlid = wl->dev_hlid;
+ cmd->device.session = wl->session_counter;
+
+ wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d",
+ cmd->role_id, cmd->device.hlid, cmd->device.session);
+
+ ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0);
+ if (ret < 0) {
+ wl1271_error("failed to initiate cmd role enable");
+ goto err_hlid;
+ }
+
+ goto out_free;
+
+err_hlid:
+ /* clear links on error */
+ __clear_bit(wl->dev_hlid, wl->links_map);
+ wl->dev_hlid = WL1271_INVALID_LINK_ID;
+
+
+out_free:
+ kfree(cmd);
+
+out:
+ return ret;
+}
+
+int wl1271_cmd_role_stop_dev(struct wl1271 *wl)
+{
+ struct wl1271_cmd_role_stop *cmd;
+ int ret;
+
+ if (WARN_ON(wl->dev_hlid == WL1271_INVALID_LINK_ID))
+ return -EINVAL;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ wl1271_debug(DEBUG_CMD, "cmd role stop dev");
+
+ cmd->role_id = wl->dev_role_id;
+ cmd->disc_type = WL1271_DISC_IMMEDIATE;
+ cmd->reason = cpu_to_le16(1); /* STATUS_UNSPECIFIED */
+
+ ret = wl1271_cmd_send(wl, CMD_ROLE_STOP, cmd, sizeof(*cmd), 0);
+ if (ret < 0) {
+ wl1271_error("failed to initiate cmd role stop");
+ goto out_free;
+ }
+
+ ret = wl1271_cmd_wait_for_event(wl, DISCONNECT_EVENT_COMPLETE_ID);
+ if (ret < 0) {
+ wl1271_error("cmd role stop dev event completion error");
+ goto out_free;
+ }
+
+ wl1271_free_link(wl, &wl->dev_hlid);
+
+out_free:
+ kfree(cmd);
+
+out:
+ return ret;
+}
+
int wl1271_cmd_role_start_sta(struct wl1271 *wl)
{
struct wl1271_cmd_role_start *cmd;
int ret;

cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index ba0470f..d254f2b 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -1851,12 +1851,20 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
goto power_off;

ret = wl1271_boot(wl);
if (ret < 0)
goto power_off;

+ if (wl->bss_type == BSS_TYPE_STA_BSS) {
+ ret = wl1271_cmd_role_enable(wl,
+ WL1271_ROLE_DEVICE,
+ &wl->dev_role_id);
+ if (ret < 0)
+ goto irq_disable;
+ }
+
ret = wl1271_cmd_role_enable(wl, wl1271_get_role_type(wl),
&wl->role_id);
if (ret < 0)
goto irq_disable;

ret = wl1271_hw_init(wl);
@@ -1955,18 +1963,21 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
/*
* do nothing. we are going to power off the chip
* anyway. handle this case when we'll really
* support multi-role...
*/
}
+ if (wl->bss_type == BSS_TYPE_STA_BSS)
+ wl1271_cmd_role_disable(wl, &wl->dev_role_id);
wl1271_cmd_role_disable(wl, &wl->role_id);

wl1271_ps_elp_sleep(wl);
}

wl->sta_hlid = WL1271_INVALID_LINK_ID;
+ wl->dev_hlid = WL1271_INVALID_LINK_ID;

/*
* this must be before the cancel_work calls below, so that the work
* functions don't perform further work.
*/
wl->state = WL1271_STATE_OFF;
@@ -2011,12 +2022,13 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
wl1271_free_ap_keys(wl);
memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
wl->ap_fw_ps_map = 0;
wl->ap_ps_map = 0;
wl->sched_scanning = false;
wl->role_id = WL1271_INVALID_ROLE_ID;
+ wl->dev_role_id = WL1271_INVALID_ROLE_ID;
memset(wl->roles_map, 0, sizeof(wl->roles_map));
memset(wl->links_map, 0, sizeof(wl->links_map));

/*
* this is performed after the cancel_work calls and the associated
* mutex_lock, so that wl1271_op_add_interface does not accidentally
@@ -4353,13 +4365,14 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
wl->platform_quirks = 0;
wl->sched_scanning = false;
wl->tx_security_seq = 0;
wl->tx_security_last_seq_lsb = 0;
wl->role_id = WL1271_INVALID_ROLE_ID;
wl->sta_hlid = WL1271_INVALID_LINK_ID;
-
+ wl->dev_role_id = WL1271_INVALID_ROLE_ID;
+ wl->dev_hlid = WL1271_INVALID_LINK_ID;
setup_timer(&wl->rx_streaming_timer, wl1271_rx_streaming_timer,
(unsigned long) wl);
wl->fwlog_size = 0;
init_waitqueue_head(&wl->fwlog_waitq);

memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index cc60da6..b47cd06 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -391,12 +391,13 @@ struct wl1271 {
u8 bss_type;
u8 set_bss_type;
u8 ssid[IW_ESSID_MAX_SIZE + 1];
u8 ssid_len;
int channel;
u8 role_id;
+ u8 dev_role_id;
u8 sta_hlid;
u8 dev_hlid;

unsigned long links_map[BITS_TO_LONGS(WL1271_MAX_LINKS)];
unsigned long roles_map[BITS_TO_LONGS(WL1271_MAX_ROLES)];

--
1.7.6.401.g6a319


2011-08-09 09:14:47

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 40/40] wl12xx: fix tx_queue_count spurious increment

From: Arik Nemtsov <[email protected]>

Only increment the queue count after actually queuing the skb. This
avoids a spurious increment is case of dropped packets.

Also move the Tx-watermark checking code after the packet is enqueued.
This makes the count more accurate - it includes the just-queued
packet.

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

diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index 7d0bcd2..e63a516 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -1475,24 +1475,12 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)

if (wl->bss_type == BSS_TYPE_AP_BSS)
hlid = wl1271_tx_get_hlid(wl, skb);

spin_lock_irqsave(&wl->wl_lock, flags);

- wl->tx_queue_count[q]++;
-
- /*
- * The workqueue is slow to process the tx_queue and we need stop
- * the queue here, otherwise the queue will get too long.
- */
- if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
- wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
- ieee80211_stop_queue(wl->hw, mapping);
- set_bit(q, &wl->stopped_queues_map);
- }
-
/* queue the packet */
if (wl->bss_type == BSS_TYPE_AP_BSS) {
if (!wl1271_is_active_sta(wl, hlid)) {
wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d",
hlid, q);
dev_kfree_skb(skb);
@@ -1502,12 +1490,24 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
} else {
skb_queue_tail(&wl->tx_queue[q], skb);
}

+ wl->tx_queue_count[q]++;
+
+ /*
+ * The workqueue is slow to process the tx_queue and we need stop
+ * the queue here, otherwise the queue will get too long.
+ */
+ if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
+ wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
+ ieee80211_stop_queue(wl->hw, mapping);
+ set_bit(q, &wl->stopped_queues_map);
+ }
+
/*
* The chip specific setup must run before the first TX packet -
* before that, the tx_work will not be initialized!
*/

if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
--
1.7.6.401.g6a319


2011-08-09 13:19:39

by Luciano Coelho

[permalink] [raw]
Subject: Re: [PATCH 05/40] wl12xx: remove rx filtering stuff

On Tue, 2011-08-09 at 12:13 +0300, Eliad Peller wrote:
> The new fw doesn't support rx_filtering configuration (as a
> stand-alone command. the rx filtering is done automatically
> according to the active role).
>
> Signed-off-by: Eliad Peller <[email protected]>
> ---
> drivers/net/wireless/wl12xx/acx.c | 28 --------
> drivers/net/wireless/wl12xx/acx.h | 118 ---------------------------------
> drivers/net/wireless/wl12xx/boot.c | 3 -
> drivers/net/wireless/wl12xx/cmd.c | 4 -
> drivers/net/wireless/wl12xx/debugfs.c | 3 -
> drivers/net/wireless/wl12xx/init.c | 12 +---
> drivers/net/wireless/wl12xx/io.h | 1 -
> drivers/net/wireless/wl12xx/main.c | 62 ++----------------
> drivers/net/wireless/wl12xx/reg.h | 75 ---------------------
> drivers/net/wireless/wl12xx/rx.c | 11 ---
> drivers/net/wireless/wl12xx/rx.h | 1 -
> drivers/net/wireless/wl12xx/scan.c | 3 -
> drivers/net/wireless/wl12xx/tx.c | 4 +-
> drivers/net/wireless/wl12xx/wl12xx.h | 22 ------
> 14 files changed, 8 insertions(+), 339 deletions(-)

Yay! This looks good, lots of code could be removed! This filtering
things were a bit messy before. :)


> diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c
> index c3e9a2e..7aa8fc7 100644
> --- a/drivers/net/wireless/wl12xx/init.c
> +++ b/drivers/net/wireless/wl12xx/init.c
> @@ -224,24 +224,20 @@ static int wl1271_ap_init_templates_config(struct wl1271 *wl)
> if (ret < 0)
> return ret;
>
> return 0;
> }
>
> -static int wl1271_init_rx_config(struct wl1271 *wl, u32 config, u32 filter)
> +static int wl1271_init_rx_config(struct wl1271 *wl)

Could you change the wl1271_init_rx_config() to wl12xx_init_rx_config()?
We more or less agreed that we would start converting wl1271 to wl12xx
slowly, each time we need to change the function declaration. It gets a
bit inconsistent, but at least we don't screw up git-blame by doing this
in one go with a huge patch.


> @@ -2425,24 +2385,17 @@ static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
> fp->mc_list,
> fp->mc_list_length);
> if (ret < 0)
> goto out_sleep;
> }
>
> - /* determine, whether supported filter values have changed */
> - if (changed == 0)
> - goto out_sleep;
> -
> - /* configure filters */
> - wl->filters = *total;
> - wl1271_configure_filters(wl, 0);
> -
> - /* apply configured filters */
> - ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
> - if (ret < 0)
> - goto out_sleep;
> + /*
> + * the fw doesn't provide an api to configure the filters. instead,
> + * the filters configuration is based on the active roles / ROC
> + * state.
> + */

Is this really safe? I guess we should trust the firmware to set the
filters correctly, but isn't there *any* other reason why mac80211 would
want to change the filters? Just want to be sure. ;)

BTW, this patch could be before 04. If we really include those #if 0's,
we should try to keep them for as few commits as possible.

--
Cheers,
Luca.


2011-08-09 09:14:25

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 29/40] wl12xx: AP-mode - configure STA HT rates on join

From: Arik Nemtsov <[email protected]>

When a new STA joins the BSS, configure the HT rates it supports to the
FW.

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

diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c
index b8d6848..9ef8621 100644
--- a/drivers/net/wireless/wl12xx/cmd.c
+++ b/drivers/net/wireless/wl12xx/cmd.c
@@ -1411,16 +1411,18 @@ int wl1271_cmd_set_peer_state(struct wl1271 *wl, u8 hlid)
out_free:
kfree(cmd);

out:
return ret;
}
+
int wl1271_cmd_add_peer(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid)
{
struct wl1271_cmd_add_peer *cmd;
int ret;
+ u32 sta_rates;

wl1271_debug(DEBUG_CMD, "cmd add sta %d", (int)hlid);

cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
ret = -ENOMEM;
@@ -1433,14 +1435,18 @@ int wl1271_cmd_add_peer(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid)
memcpy(cmd->addr, sta->addr, ETH_ALEN);
cmd->bss_index = WL1271_AP_BSS_INDEX;
cmd->aid = sta->aid;
cmd->hlid = hlid;
cmd->wmm = sta->wme ? 1 : 0;

- cmd->supported_rates = cpu_to_le32(wl1271_tx_enabled_rates_get(wl,
- sta->supp_rates[wl->band]));
+ sta_rates = sta->supp_rates[wl->band];
+ if (sta->ht_cap.ht_supported)
+ sta_rates |= sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET;
+
+ cmd->supported_rates =
+ cpu_to_le32(wl1271_tx_enabled_rates_get(wl, sta_rates));

wl1271_debug(DEBUG_CMD, "new sta rates: 0x%x", cmd->supported_rates);

ret = wl1271_cmd_send(wl, CMD_ADD_PEER, cmd, sizeof(*cmd), 0);
if (ret < 0) {
wl1271_error("failed to initiate cmd add sta");
--
1.7.6.401.g6a319


2011-08-11 04:39:35

by Arik Nemtsov

[permalink] [raw]
Subject: Re: [PATCH 30/40] wl12xx: AP-mode - configure HT rate support to the FW

On Wed, Aug 10, 2011 at 23:30, Luciano Coelho <[email protected]> wrote:
> On Tue, 2011-08-09 at 12:13 +0300, Eliad Peller wrote:
>> From: Arik Nemtsov <[email protected]>
>>
>> Unconditionally configure HT rate support to the FW on all ACs
>> when starting the AP.
>>
>> When 11n support is disabled by usermode (hostapd), each STA joining
>> the AP will appear as a non-HT STA. This will stop us from accidentally
>> transmitting using MCS rates.
>
> Can we really trust this? I'd rather make sure we don't do anything
> wrong in the driver itself.

It doesn't hurt anything. The HT related IEs are advertised by
usermode. Nobody knows that the driver supports MCS rates.

>
> Or is all this actually handled in userspace? I'm not very familiar with
> how AP works, but is there any risk that someone tells us not to use 11n
> but still don't change the STAs so that they appear as non-HT?

Yes. The HT capabilities of the the STA are set to 0 when 11n is not
supported by usermode. This means we have sta->ht_cap.ht_supported ==
0 for any sta added by the sta_add() callback.
We use this information to correctly set the STA supported rates.

This is required anyway, as even when 11n is supported, some
connecting stations might be BG only.

Arik

2011-08-09 13:37:35

by Luciano Coelho

[permalink] [raw]
Subject: Re: [PATCH 06/40] wl12xx: wl12xx-fw-3 - Update fw status struct

On Tue, 2011-08-09 at 12:13 +0300, Eliad Peller wrote:
> Update the fw status struct according to the new fw api.
> All the roles use the same struct now.
>
> The memory accounting was changed a bit according to
> the struct changes.
>
> Signed-off-by: Eliad Peller <[email protected]>
> ---

I don't think we need the "wl12xx-fw-3 - " in the title of any of these
patches...

--
Cheers,
Luca.


2011-08-11 20:54:40

by Arik Nemtsov

[permalink] [raw]
Subject: Re: [PATCH 34/40] wl12xx: schedule TX packets according to FW packet occupancy

On Thu, Aug 11, 2011 at 14:38, Luciano Coelho <[email protected]> wrote:
> On Tue, 2011-08-09 at 12:13 +0300, Eliad Peller wrote:
>> +static struct sk_buff_head *wl1271_select_queue(struct wl1271 *wl,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? struct sk_buff_head *queues)
>> +{
>> + ? ? int i, q = -1;
>> + ? ? u32 min_pkts = 0xffffffff;
>> +
>> + ? ? /*
>> + ? ? ?* Find a non-empty ac where:
>> + ? ? ?* 1. There are packets to transmit
>> + ? ? ?* 2. The FW has the least allocated blocks
>> + ? ? ?*/
>> + ? ? for (i = 0; i < NUM_TX_QUEUES; i++)
>> + ? ? ? ? ? ? if (!skb_queue_empty(&queues[i]) &&
>> + ? ? ? ? ? ? ? ? (wl->tx_allocated_pkts[i] < min_pkts)) {
>> + ? ? ? ? ? ? ? ? ? ? q = i;
>> + ? ? ? ? ? ? ? ? ? ? min_pkts = wl->tx_allocated_pkts[q];
>> + ? ? ? ? ? ? }
>> +
>> + ? ? if (q == -1)
>> + ? ? ? ? ? ? return NULL;
>> +
>> + ? ? return &queues[q];
>> +}
>
> This is a nice algorithm, but now, if all queues have the same number of
> allocated packets in the FW, we'll start with BE, because the enum is
> like this:
>
> enum conf_tx_ac {
> CONF_TX_AC_BE = 0, ? ? ? ? /* best effort / legacy */
> CONF_TX_AC_BK = 1, ? ? ? ? /* background */
> CONF_TX_AC_VI = 2, ? ? ? ? /* video */
> CONF_TX_AC_VO = 3, ? ? ? ? /* voice */
> CONF_TX_AC_CTS2SELF = 4, ? /* fictitious AC, follows AC_VO */
> CONF_TX_AC_ANY_TID = 0x1f
> };
>
> ...and you select the first queue in case two or more are similarly
> full.
>
> Maybe you could make the for loop go backwards instead? Or changing the
> < to <= in the comparison would also work.

sure we can change it to <=. VO is usually a higher priority than BK.

>
> Another option would be to fix the enum so that it goes from higher prio
> to lower prio. ?If the firmware doesn't care about the actual order of
> the queues and actually respects our ac_conf, this would probably be the
> best solution, because we could even get rid of wl1271_tx_get_queue()
> and wl1271_tx_get_mac80211_queue().

I suspect the FW is using these constants, so we wouldn't want to touch those.

>
> Now something else came to my mind. ?Could it also happen that the other
> queues would still be starved? Let's say we keep getting packets
> continuously for the first queue we choose exactly at the interval it
> takes the FW to empty that queue. ?Meanwhile, we're getting some packets
> for other queues. ?In this case, we would keep selecting the same AC
> because all the queues would be empty and we would keep choosing the
> first one.
>

That is a theoretical starvation condition (among several others).
This was there before this patch as well. The ratio of packet
throughput/FW memory/air throughput has to be just right for this to
happen, and it doesn't occur with current hardware. We'll handle this
when the problem arises (at the cost of added complexity).

Arik

> Maybe we should still once in a while check the other queues?
>
> Or am I missing something again?
>
> --
> Cheers,
> Luca.
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
> the body of a message to [email protected]
> More majordomo info at ?http://vger.kernel.org/majordomo-info.html
>

2011-08-09 09:13:33

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 01/40] wl12xx: Revert "wl12xx: schedule TX packets according to FW occupancy"

From: Arik Nemtsov <[email protected]>

This does not make sense in 7.3 firmware - we don't use Tx blocks to
measure FW occupancy anymore.

This reverts commit 9e374a37b6fa2310b71d3c5657cd0c1e693120c6.

Signed-off-by: Arik Nemtsov <[email protected]>
Signed-off-by: Eliad Peller <[email protected]>
---
drivers/net/wireless/wl12xx/debugfs.c | 5 +--
drivers/net/wireless/wl12xx/main.c | 30 ++++-----------
drivers/net/wireless/wl12xx/tx.c | 68 +++++++++++----------------------
drivers/net/wireless/wl12xx/wl12xx.h | 2 +-
4 files changed, 33 insertions(+), 72 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c
index 37934b5..3b5f240 100644
--- a/drivers/net/wireless/wl12xx/debugfs.c
+++ b/drivers/net/wireless/wl12xx/debugfs.c
@@ -336,16 +336,13 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf,
#define DRIVER_STATE_PRINT_INT(x) DRIVER_STATE_PRINT(x, "%d")
#define DRIVER_STATE_PRINT_STR(x) DRIVER_STATE_PRINT(x, "%s")
#define DRIVER_STATE_PRINT_LHEX(x) DRIVER_STATE_PRINT(x, "0x%lx")
#define DRIVER_STATE_PRINT_HEX(x) DRIVER_STATE_PRINT(x, "0x%x")

DRIVER_STATE_PRINT_INT(tx_blocks_available);
- DRIVER_STATE_PRINT_INT(tx_allocated_blocks[0]);
- DRIVER_STATE_PRINT_INT(tx_allocated_blocks[1]);
- DRIVER_STATE_PRINT_INT(tx_allocated_blocks[2]);
- DRIVER_STATE_PRINT_INT(tx_allocated_blocks[3]);
+ DRIVER_STATE_PRINT_INT(tx_allocated_blocks);
DRIVER_STATE_PRINT_INT(tx_frames_cnt);
DRIVER_STATE_PRINT_LHEX(tx_frames_map[0]);
DRIVER_STATE_PRINT_INT(tx_queue_count[0]);
DRIVER_STATE_PRINT_INT(tx_queue_count[1]);
DRIVER_STATE_PRINT_INT(tx_queue_count[2]);
DRIVER_STATE_PRINT_INT(tx_queue_count[3]);
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index e58c22d..bf05a9f 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -821,30 +821,19 @@ static void wl1271_irq_update_links_status(struct wl1271 *wl,

wl1271_irq_ps_regulate_link(wl, hlid,
wl->links[hlid].allocated_blks);
}
}

-static u32 wl1271_tx_allocated_blocks(struct wl1271 *wl)
-{
- int i;
- u32 total_alloc_blocks = 0;
-
- for (i = 0; i < NUM_TX_QUEUES; i++)
- total_alloc_blocks += wl->tx_allocated_blocks[i];
-
- return total_alloc_blocks;
-}
-
static void wl1271_fw_status(struct wl1271 *wl,
struct wl1271_fw_full_status *full_status)
{
struct wl1271_fw_common_status *status = &full_status->common;
struct timespec ts;
u32 old_tx_blk_count = wl->tx_blocks_available;
- u32 freed_blocks = 0, ac_freed_blocks;
+ u32 freed_blocks = 0;
int i;

if (wl->bss_type == BSS_TYPE_AP_BSS) {
wl1271_raw_read(wl, FW_STATUS_ADDR, status,
sizeof(struct wl1271_fw_ap_status), false);
} else {
@@ -858,29 +847,27 @@ static void wl1271_fw_status(struct wl1271 *wl,
status->fw_rx_counter,
status->drv_rx_counter,
status->tx_results_counter);

/* update number of available TX blocks */
for (i = 0; i < NUM_TX_QUEUES; i++) {
- ac_freed_blocks = le32_to_cpu(status->tx_released_blks[i]) -
- wl->tx_blocks_freed[i];
- freed_blocks += ac_freed_blocks;
-
- wl->tx_allocated_blocks[i] -= ac_freed_blocks;
+ freed_blocks += le32_to_cpu(status->tx_released_blks[i]) -
+ wl->tx_blocks_freed[i];

wl->tx_blocks_freed[i] =
le32_to_cpu(status->tx_released_blks[i]);
}

+ wl->tx_allocated_blocks -= freed_blocks;
+
if (wl->bss_type == BSS_TYPE_AP_BSS) {
/* Update num of allocated TX blocks per link and ps status */
wl1271_irq_update_links_status(wl, &full_status->ap);
wl->tx_blocks_available += freed_blocks;
} else {
- int avail = full_status->sta.tx_total -
- wl1271_tx_allocated_blocks(wl);
+ int avail = full_status->sta.tx_total - wl->tx_allocated_blocks;

/*
* The FW might change the total number of TX memblocks before
* we get a notification about blocks being released. Thus, the
* available blocks calculation might yield a temporary result
* which is lower than the actual available blocks. Keeping in
@@ -2004,12 +1991,13 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
wl->band = IEEE80211_BAND_2GHZ;

wl->rx_counter = 0;
wl->psm_entry_retry = 0;
wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
wl->tx_blocks_available = 0;
+ wl->tx_allocated_blocks = 0;
wl->tx_results_count = 0;
wl->tx_packets_count = 0;
wl->time_offset = 0;
wl->session_counter = 0;
wl->rate_set = CONF_TX_RATE_MASK_BASIC;
wl->vif = NULL;
@@ -2024,16 +2012,14 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
* this is performed after the cancel_work calls and the associated
* mutex_lock, so that wl1271_op_add_interface does not accidentally
* get executed before all these vars have been reset.
*/
wl->flags = 0;

- for (i = 0; i < NUM_TX_QUEUES; i++) {
+ for (i = 0; i < NUM_TX_QUEUES; i++)
wl->tx_blocks_freed[i] = 0;
- wl->tx_allocated_blocks[i] = 0;
- }

wl1271_debugfs_reset(wl);

kfree(wl->fw_status);
wl->fw_status = NULL;
kfree(wl->tx_res_if);
diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c
index 48fde96..0696aed 100644
--- a/drivers/net/wireless/wl12xx/tx.c
+++ b/drivers/net/wireless/wl12xx/tx.c
@@ -165,13 +165,13 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
u32 buf_offset, u8 hlid)
{
struct wl1271_tx_hw_descr *desc;
u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra;
u32 len;
u32 total_blocks;
- int id, ret = -EBUSY, ac;
+ int id, ret = -EBUSY;
u32 spare_blocks;

if (unlikely(wl->quirks & WL12XX_QUIRK_USE_2_SPARE_BLOCKS))
spare_blocks = 2;
else
spare_blocks = 1;
@@ -203,15 +203,13 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
desc->wl127x_mem.total_mem_blocks = total_blocks;
}

desc->id = id;

wl->tx_blocks_available -= total_blocks;
-
- ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
- wl->tx_allocated_blocks[ac] += total_blocks;
+ wl->tx_allocated_blocks += total_blocks;

if (wl->bss_type == BSS_TYPE_AP_BSS)
wl->links[hlid].allocated_blks += total_blocks;

ret = 0;

@@ -456,47 +454,27 @@ void wl1271_handle_tx_low_watermark(struct wl1271 *wl)
clear_bit(i, &wl->stopped_queues_map);
spin_unlock_irqrestore(&wl->wl_lock, flags);
}
}
}

-static struct sk_buff_head *wl1271_select_queue(struct wl1271 *wl,
- struct sk_buff_head *queues)
-{
- int i, q = -1;
- u32 min_blks = 0xffffffff;
-
- /*
- * Find a non-empty ac where:
- * 1. There are packets to transmit
- * 2. The FW has the least allocated blocks
- */
- for (i = 0; i < NUM_TX_QUEUES; i++)
- if (!skb_queue_empty(&queues[i]) &&
- (wl->tx_allocated_blocks[i] < min_blks)) {
- q = i;
- min_blks = wl->tx_allocated_blocks[q];
- }
-
- if (q == -1)
- return NULL;
-
- return &queues[q];
-}
-
static struct sk_buff *wl1271_sta_skb_dequeue(struct wl1271 *wl)
{
struct sk_buff *skb = NULL;
unsigned long flags;
- struct sk_buff_head *queue;

- queue = wl1271_select_queue(wl, wl->tx_queue);
- if (!queue)
+ skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_VO]);
+ if (skb)
goto out;
-
- skb = skb_dequeue(queue);
+ skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_VI]);
+ if (skb)
+ goto out;
+ skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_BE]);
+ if (skb)
+ goto out;
+ skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_BK]);

out:
if (skb) {
int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
spin_lock_irqsave(&wl->wl_lock, flags);
wl->tx_queue_count[q]--;
@@ -508,35 +486,35 @@ out:

static struct sk_buff *wl1271_ap_skb_dequeue(struct wl1271 *wl)
{
struct sk_buff *skb = NULL;
unsigned long flags;
int i, h, start_hlid;
- struct sk_buff_head *queue;

/* start from the link after the last one */
start_hlid = (wl->last_tx_hlid + 1) % AP_MAX_LINKS;

/* dequeue according to AC, round robin on each link */
for (i = 0; i < AP_MAX_LINKS; i++) {
h = (start_hlid + i) % AP_MAX_LINKS;

- /* only consider connected stations */
- if (h >= WL1271_AP_STA_HLID_START &&
- !test_bit(h - WL1271_AP_STA_HLID_START, wl->ap_hlid_map))
- continue;
-
- queue = wl1271_select_queue(wl, wl->links[h].tx_queue);
- if (!queue)
- continue;
-
- skb = skb_dequeue(queue);
+ skb = skb_dequeue(&wl->links[h].tx_queue[CONF_TX_AC_VO]);
if (skb)
- break;
+ goto out;
+ skb = skb_dequeue(&wl->links[h].tx_queue[CONF_TX_AC_VI]);
+ if (skb)
+ goto out;
+ skb = skb_dequeue(&wl->links[h].tx_queue[CONF_TX_AC_BE]);
+ if (skb)
+ goto out;
+ skb = skb_dequeue(&wl->links[h].tx_queue[CONF_TX_AC_BK]);
+ if (skb)
+ goto out;
}

+out:
if (skb) {
int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
wl->last_tx_hlid = h;
spin_lock_irqsave(&wl->wl_lock, flags);
wl->tx_queue_count[q]--;
spin_unlock_irqrestore(&wl->wl_lock, flags);
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index 1a8751e..6c080e9 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -421,13 +421,13 @@ struct wl1271 {

struct wl1271_acx_mem_map *target_mem_map;

/* Accounting for allocated / available TX blocks on HW */
u32 tx_blocks_freed[NUM_TX_QUEUES];
u32 tx_blocks_available;
- u32 tx_allocated_blocks[NUM_TX_QUEUES];
+ u32 tx_allocated_blocks;
u32 tx_results_count;

/* Transmitted TX packets counter for chipset interface */
u32 tx_packets_count;

/* Time-offset between host and chipset clocks */
--
1.7.6.401.g6a319


2011-08-09 09:13:35

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 02/40] wl12xx: Use a single fw for both STA and AP roles

From: Arik Nemtsov <[email protected]>

The new wl12xx fw supports both STA and AP roles.

Signed-off-by: Arik Nemtsov <[email protected]>
Signed-off-by: Eliad Peller <[email protected]>
---
drivers/net/wireless/wl12xx/main.c | 31 +++++--------------------------
drivers/net/wireless/wl12xx/sdio.c | 2 --
drivers/net/wireless/wl12xx/spi.c | 2 --
drivers/net/wireless/wl12xx/wl12xx.h | 7 ++-----
4 files changed, 7 insertions(+), 35 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index bf05a9f..ba8dafaf 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -1040,31 +1040,16 @@ EXPORT_SYMBOL_GPL(wl1271_irq);
static int wl1271_fetch_firmware(struct wl1271 *wl)
{
const struct firmware *fw;
const char *fw_name;
int ret;

- switch (wl->bss_type) {
- case BSS_TYPE_AP_BSS:
- if (wl->chip.id == CHIP_ID_1283_PG20)
- fw_name = WL128X_AP_FW_NAME;
- else
- fw_name = WL127X_AP_FW_NAME;
- break;
- case BSS_TYPE_IBSS:
- case BSS_TYPE_STA_BSS:
- if (wl->chip.id == CHIP_ID_1283_PG20)
- fw_name = WL128X_FW_NAME;
- else
- fw_name = WL1271_FW_NAME;
- break;
- default:
- wl1271_error("no compatible firmware for bss_type %d",
- wl->bss_type);
- return -EINVAL;
- }
+ if (wl->chip.id == CHIP_ID_1283_PG20)
+ fw_name = WL128X_FW_NAME;
+ else
+ fw_name = WL1271_FW_NAME;

wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);

ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));

if (ret < 0) {
@@ -1087,13 +1072,12 @@ static int wl1271_fetch_firmware(struct wl1271 *wl)
wl1271_error("could not allocate memory for the firmware");
ret = -ENOMEM;
goto out;
}

memcpy(wl->fw, fw->data, wl->fw_len);
- wl->fw_bss_type = wl->bss_type;
ret = 0;

out:
release_firmware(fw);

return ret;
@@ -1358,14 +1342,13 @@ static int wl1271_chip_wakeup(struct wl1271 *wl)
default:
wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
ret = -ENODEV;
goto out;
}

- /* Make sure the firmware type matches the BSS type */
- if (wl->fw == NULL || wl->fw_bss_type != wl->bss_type) {
+ if (wl->fw == NULL) {
ret = wl1271_fetch_firmware(wl);
if (ret < 0)
goto out;
}

/* No NVS from netlink, try to get it from the filesystem */
@@ -1787,15 +1770,12 @@ static int wl1271_op_start(struct ieee80211_hw *hw)
* initializing the firmware. The MAC address cannot be changed
* after boot, and without the proper MAC address, the firmware
* will not function properly.
*
* The MAC address is first known when the corresponding interface
* is added. That is where we will initialize the hardware.
- *
- * In addition, we currently have different firmwares for AP and managed
- * operation. We will know which to boot according to interface type.
*/

return 0;
}

static void wl1271_op_stop(struct ieee80211_hw *hw)
@@ -4384,13 +4364,12 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
wl->vif = NULL;
wl->flags = 0;
wl->sg_enabled = true;
wl->hw_pg_ver = -1;
wl->bss_type = MAX_BSS_TYPE;
wl->set_bss_type = MAX_BSS_TYPE;
- wl->fw_bss_type = MAX_BSS_TYPE;
wl->last_tx_hlid = 0;
wl->ap_ps_map = 0;
wl->ap_fw_ps_map = 0;
wl->quirks = 0;
wl->platform_quirks = 0;
wl->sched_scanning = false;
diff --git a/drivers/net/wireless/wl12xx/sdio.c b/drivers/net/wireless/wl12xx/sdio.c
index 5cf18c2..5b4062f 100644
--- a/drivers/net/wireless/wl12xx/sdio.c
+++ b/drivers/net/wireless/wl12xx/sdio.c
@@ -411,8 +411,6 @@ module_exit(wl1271_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Luciano Coelho <[email protected]>");
MODULE_AUTHOR("Juuso Oikarinen <[email protected]>");
MODULE_FIRMWARE(WL1271_FW_NAME);
MODULE_FIRMWARE(WL128X_FW_NAME);
-MODULE_FIRMWARE(WL127X_AP_FW_NAME);
-MODULE_FIRMWARE(WL128X_AP_FW_NAME);
diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/spi.c
index b73cee1..cbf3542 100644
--- a/drivers/net/wireless/wl12xx/spi.c
+++ b/drivers/net/wireless/wl12xx/spi.c
@@ -484,9 +484,7 @@ module_exit(wl1271_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Luciano Coelho <[email protected]>");
MODULE_AUTHOR("Juuso Oikarinen <[email protected]>");
MODULE_FIRMWARE(WL1271_FW_NAME);
MODULE_FIRMWARE(WL128X_FW_NAME);
-MODULE_FIRMWARE(WL127X_AP_FW_NAME);
-MODULE_FIRMWARE(WL128X_AP_FW_NAME);
MODULE_ALIAS("spi:wl1271");
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index 6c080e9..21c5f95 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -127,16 +127,14 @@ extern u32 wl12xx_debug_level;
CFG_RX_MGMT_EN | CFG_RX_DATA_EN | \
CFG_RX_CTL_EN | CFG_RX_AUTH_EN | \
CFG_RX_ASSOC_EN)



-#define WL1271_FW_NAME "ti-connectivity/wl1271-fw-2.bin"
-#define WL128X_FW_NAME "ti-connectivity/wl128x-fw.bin"
-#define WL127X_AP_FW_NAME "ti-connectivity/wl1271-fw-ap.bin"
-#define WL128X_AP_FW_NAME "ti-connectivity/wl128x-fw-ap.bin"
+#define WL1271_FW_NAME "ti-connectivity/wl1271-fw-3.bin"
+#define WL128X_FW_NAME "ti-connectivity/wl128x-fw-3.bin"

/*
* wl127x and wl128x are using the same NVS file name. However, the
* ini parameters between them are different. The driver validates
* the correct NVS size in wl1271_boot_upload_nvs().
*/
@@ -402,13 +400,12 @@ struct wl1271 {

int cmd_box_addr;
int event_box_addr;

u8 *fw;
size_t fw_len;
- u8 fw_bss_type;
void *nvs;
size_t nvs_len;

s8 hw_pg_ver;

u8 bssid[ETH_ALEN];
--
1.7.6.401.g6a319


2011-08-09 11:59:31

by Luciano Coelho

[permalink] [raw]
Subject: Re: [PATCH 02/40] wl12xx: Use a single fw for both STA and AP roles

On Tue, 2011-08-09 at 12:13 +0300, Eliad Peller wrote:
> From: Arik Nemtsov <[email protected]>
>
> The new wl12xx fw supports both STA and AP roles.

Again, let's be more explicit here about the firmware versions.


> diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
> index 6c080e9..21c5f95 100644
> --- a/drivers/net/wireless/wl12xx/wl12xx.h
> +++ b/drivers/net/wireless/wl12xx/wl12xx.h
> @@ -127,16 +127,14 @@ extern u32 wl12xx_debug_level;
> CFG_RX_MGMT_EN | CFG_RX_DATA_EN | \
> CFG_RX_CTL_EN | CFG_RX_AUTH_EN | \
> CFG_RX_ASSOC_EN)
>
>
>
> -#define WL1271_FW_NAME "ti-connectivity/wl1271-fw-2.bin"
> -#define WL128X_FW_NAME "ti-connectivity/wl128x-fw.bin"
> -#define WL127X_AP_FW_NAME "ti-connectivity/wl1271-fw-ap.bin"
> -#define WL128X_AP_FW_NAME "ti-connectivity/wl128x-fw-ap.bin"
> +#define WL1271_FW_NAME "ti-connectivity/wl1271-fw-3.bin"
> +#define WL128X_FW_NAME "ti-connectivity/wl128x-fw-3.bin"

Should we use this opportunity to change the macro to WL127X_FW_NAME and
the file name to wl127x-fw.bin?


--
Cheers,
Luca.


2011-08-09 09:14:27

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 30/40] wl12xx: AP-mode - configure HT rate support to the FW

From: Arik Nemtsov <[email protected]>

Unconditionally configure HT rate support to the FW on all ACs
when starting the AP.

When 11n support is disabled by usermode (hostapd), each STA joining
the AP will appear as a non-HT STA. This will stop us from accidentally
transmitting using MCS rates.

Signed-off-by: Arik Nemtsov <[email protected]>
Signed-off-by: Eliad Peller <[email protected]>
---
drivers/net/wireless/wl12xx/conf.h | 5 +++++
drivers/net/wireless/wl12xx/init.c | 3 +++
2 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/conf.h b/drivers/net/wireless/wl12xx/conf.h
index a92df6e..b0a63b2 100644
--- a/drivers/net/wireless/wl12xx/conf.h
+++ b/drivers/net/wireless/wl12xx/conf.h
@@ -438,12 +438,17 @@ struct conf_rx_settings {

#define CONF_TX_OFDM_RATES (CONF_HW_BIT_RATE_6MBPS | \
CONF_HW_BIT_RATE_12MBPS | CONF_HW_BIT_RATE_24MBPS | \
CONF_HW_BIT_RATE_36MBPS | CONF_HW_BIT_RATE_48MBPS | \
CONF_HW_BIT_RATE_54MBPS)

+#define CONF_TX_MCS_RATES (CONF_HW_BIT_RATE_MCS_0 | \
+ CONF_HW_BIT_RATE_MCS_1 | CONF_HW_BIT_RATE_MCS_2 | \
+ CONF_HW_BIT_RATE_MCS_3 | CONF_HW_BIT_RATE_MCS_4 | \
+ CONF_HW_BIT_RATE_MCS_5 | CONF_HW_BIT_RATE_MCS_6 | \
+ CONF_HW_BIT_RATE_MCS_7)

/*
* Default rates for management traffic when operating in AP mode. This
* should be configured according to the basic rate set of the AP
*/
#define CONF_TX_AP_DEFAULT_MGMT_RATES (CONF_HW_BIT_RATE_1MBPS | \
diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c
index 67cd603..4a4736e 100644
--- a/drivers/net/wireless/wl12xx/init.c
+++ b/drivers/net/wireless/wl12xx/init.c
@@ -507,12 +507,15 @@ int wl1271_init_ap_rates(struct wl1271 *wl)
*/
if ((wl->basic_rate_set & CONF_TX_OFDM_RATES))
supported_rates = CONF_TX_OFDM_RATES;
else
supported_rates = CONF_TX_AP_ENABLED_RATES;

+ /* unconditionally enable HT rates */
+ supported_rates |= CONF_TX_MCS_RATES;
+
/* configure unicast TX rate classes */
for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
rc.enabled_rates = supported_rates;
rc.short_retry_limit = 10;
rc.long_retry_limit = 10;
rc.aflags = 0;
--
1.7.6.401.g6a319


2011-08-09 09:14:44

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 39/40] wl12xx: AP-mode - prevent Tx to stale/invalid stations

From: Arik Nemtsov <[email protected]>

Don't pollute the queues with Tx directed to invalid stations. This
can happen during recovery.

Signed-off-by: Arik Nemtsov <[email protected]>
Signed-off-by: Eliad Peller <[email protected]>
---
drivers/net/wireless/wl12xx/main.c | 20 +++++++++++++++++---
1 files changed, 17 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index e3c77da..7d0bcd2 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -775,13 +775,19 @@ static void wl1271_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_pkts)
else if (fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
wl1271_ps_link_start(wl, hlid, true);
}

bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid)
{
- int id = hlid - WL1271_AP_STA_HLID_START;
+ int id;
+
+ /* global/broadcast "stations" are always active */
+ if (hlid < WL1271_AP_STA_HLID_START)
+ return true;
+
+ id = hlid - WL1271_AP_STA_HLID_START;
return test_bit(id, wl->ap_hlid_map);
}

static void wl1271_irq_update_links_status(struct wl1271 *wl,
struct wl1271_fw_status *status)
{
@@ -1483,12 +1489,19 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
ieee80211_stop_queue(wl->hw, mapping);
set_bit(q, &wl->stopped_queues_map);
}

/* queue the packet */
if (wl->bss_type == BSS_TYPE_AP_BSS) {
+ if (!wl1271_is_active_sta(wl, hlid)) {
+ wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d",
+ hlid, q);
+ dev_kfree_skb(skb);
+ goto out;
+ }
+
wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
} else {
skb_queue_tail(&wl->tx_queue[q], skb);
}

@@ -1498,12 +1511,13 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
*/

if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
!test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
ieee80211_queue_work(wl->hw, &wl->tx_work);

+out:
spin_unlock_irqrestore(&wl->wl_lock, flags);
}

int wl1271_tx_dummy_packet(struct wl1271 *wl)
{
unsigned long flags;
@@ -3660,13 +3674,13 @@ static int wl1271_allocate_sta(struct wl1271 *wl,
if (id >= AP_MAX_STATIONS) {
wl1271_warning("could not allocate HLID - too much stations");
return -EBUSY;
}

wl_sta = (struct wl1271_station *)sta->drv_priv;
- __set_bit(id, wl->ap_hlid_map);
+ set_bit(id, wl->ap_hlid_map);
wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
*hlid = wl_sta->hlid;
memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
return 0;
}

@@ -3674,13 +3688,13 @@ static 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)))
return;

- __clear_bit(id, wl->ap_hlid_map);
+ clear_bit(id, wl->ap_hlid_map);
memset(wl->links[hlid].addr, 0, ETH_ALEN);
wl->links[hlid].ba_bitmap = 0;
wl1271_tx_reset_link_queues(wl, hlid);
__clear_bit(hlid, &wl->ap_ps_map);
__clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
}
--
1.7.6.401.g6a319


2011-08-10 12:48:43

by Luciano Coelho

[permalink] [raw]
Subject: Re: [PATCH 16/40] wl12xx: add system_hlid

On Tue, 2011-08-09 at 12:13 +0300, Eliad Peller wrote:
> @@ -4385,20 +4388,26 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
> wl->quirks = 0;
> wl->platform_quirks = 0;
> wl->sched_scanning = false;
> wl->tx_security_seq = 0;
> wl->tx_security_last_seq_lsb = 0;
> wl->role_id = WL1271_INVALID_ROLE_ID;
> + wl->system_hlid = WL1271_SYSTEM_HLID;
> wl->sta_hlid = WL1271_INVALID_LINK_ID;
> wl->dev_role_id = WL1271_INVALID_ROLE_ID;
> wl->dev_hlid = WL1271_INVALID_LINK_ID;
> setup_timer(&wl->rx_streaming_timer, wl1271_rx_streaming_timer,
> (unsigned long) wl);
> wl->fwlog_size = 0;
> init_waitqueue_head(&wl->fwlog_waitq);
>
> + memset(wl->links_map, 0, sizeof(wl->links_map));

Why do you now need to memset this here? And if you do, why not
roles_map as well? Of course all the wl struct is initialized to zeros
by default, but we should either be always explicit here or always
implicit. ;)


> @@ -368,14 +371,16 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb,
> if (ret < 0)
> return ret;
> wl->default_key = idx;
> }
> }
>
> - if (wl->bss_type == BSS_TYPE_AP_BSS)
> - hlid = wl1271_tx_get_hlid(skb);
> + if (wl12xx_is_dummy_packet(wl, skb))
> + hlid = wl->system_hlid;
> + else if (wl->bss_type == BSS_TYPE_AP_BSS)
> + hlid = wl1271_tx_get_hlid(wl, skb);
> else
> if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
> hlid = wl->sta_hlid;
> else
> hlid = wl->dev_hlid;

Can't you put this all in the wl1271_tx_get_hlid() function? At least
part of it seems repeated wherever it's called.


--
Cheers,
Luca.


2011-08-09 09:13:58

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 14/40] wl12xx: use wl1271_acx_beacon_filter_opt for both sta and ap

Use ACX_BEACON_FILTER_OPT for both station and ap roles
(use the generic wl1271_acx_beacon_filter_opt()
instead of wl1271_acx_set_ap_beacon_filter() ).

Signed-off-by: Eliad Peller <[email protected]>
---
drivers/net/wireless/wl12xx/acx.c | 25 -------------------------
drivers/net/wireless/wl12xx/acx.h | 9 ---------
drivers/net/wireless/wl12xx/init.c | 2 +-
drivers/net/wireless/wl12xx/main.c | 4 ++--
4 files changed, 3 insertions(+), 37 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c
index 42bfce8..a545134 100644
--- a/drivers/net/wireless/wl12xx/acx.c
+++ b/drivers/net/wireless/wl12xx/acx.c
@@ -1665,37 +1665,12 @@ int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr)

out:
kfree(acx);
return ret;
}

-int wl1271_acx_set_ap_beacon_filter(struct wl1271 *wl, bool enable)
-{
- struct acx_ap_beacon_filter *acx = NULL;
- int ret;
-
- wl1271_debug(DEBUG_ACX, "acx set ap beacon filter: %d", enable);
-
- acx = kzalloc(sizeof(*acx), GFP_KERNEL);
- if (!acx)
- return -ENOMEM;
-
- acx->enable = enable ? 1 : 0;
-
- ret = wl1271_cmd_configure(wl, ACX_AP_BEACON_FILTER_OPT,
- acx, sizeof(*acx));
- if (ret < 0) {
- wl1271_warning("acx set ap beacon filter failed: %d", ret);
- goto out;
- }
-
-out:
- kfree(acx);
- return ret;
-}
-
int wl1271_acx_fm_coex(struct wl1271 *wl)
{
struct wl1271_acx_fm_coex *acx;
int ret;

wl1271_debug(DEBUG_ACX, "acx fm coex setting");
diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h
index 9cc5d62..5a2e9bc 100644
--- a/drivers/net/wireless/wl12xx/acx.h
+++ b/drivers/net/wireless/wl12xx/acx.h
@@ -1091,19 +1091,12 @@ struct wl1271_acx_inconnection_sta {
struct acx_header header;

u8 addr[ETH_ALEN];
u8 padding1[2];
} __packed;

-struct acx_ap_beacon_filter {
- struct acx_header header;
-
- u8 enable;
- u8 pad[3];
-} __packed;
-
/*
* ACX_FM_COEX_CFG
* set the FM co-existence parameters.
*/
struct wl1271_acx_fm_coex {
struct acx_header header;
@@ -1172,13 +1165,12 @@ enum {
ACX_STATISTICS = 0x0013, /* Debug API */
ACX_PWR_CONSUMPTION_STATISTICS = 0x0014,
ACX_FEATURE_CFG = 0x0015,
ACX_TID_CFG = 0x001A,
ACX_PS_RX_STREAMING = 0x001B,
ACX_BEACON_FILTER_OPT = 0x001F,
- ACX_AP_BEACON_FILTER_OPT = 0x0020,
ACX_NOISE_HIST = 0x0021,
ACX_HDK_VERSION = 0x0022, /* ??? */
ACX_PD_THRESHOLD = 0x0023,
ACX_TX_CONFIG_OPT = 0x0024,
ACX_CCA_THRESHOLD = 0x0025,
ACX_EVENT_MBOX_MASK = 0x0026,
@@ -1297,10 +1289,9 @@ int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn,
bool enable);
int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime);
int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, bool enable);
int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl);
int wl1271_acx_config_ps(struct wl1271 *wl);
int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr);
-int wl1271_acx_set_ap_beacon_filter(struct wl1271 *wl, bool enable);
int wl1271_acx_fm_coex(struct wl1271 *wl);

#endif /* __WL1271_ACX_H__ */
diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c
index c733a63..10a66c7 100644
--- a/drivers/net/wireless/wl12xx/init.c
+++ b/drivers/net/wireless/wl12xx/init.c
@@ -466,13 +466,13 @@ int wl1271_ap_init_templates(struct wl1271 *wl)
return ret;

/*
* when operating as AP we want to receive external beacons for
* configuring ERP protection.
*/
- ret = wl1271_acx_set_ap_beacon_filter(wl, false);
+ ret = wl1271_acx_beacon_filter_opt(wl, false);
if (ret < 0)
return ret;

return 0;
}

diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index 491c904f..b0fd1fa 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -1630,13 +1630,13 @@ static int wl1271_configure_suspend_ap(struct wl1271 *wl)
goto out_unlock;

ret = wl1271_ps_elp_wakeup(wl);
if (ret < 0)
goto out_unlock;

- ret = wl1271_acx_set_ap_beacon_filter(wl, true);
+ ret = wl1271_acx_beacon_filter_opt(wl, true);

wl1271_ps_elp_sleep(wl);
out_unlock:
mutex_unlock(&wl->mutex);
return ret;

@@ -1668,13 +1668,13 @@ static void wl1271_configure_resume(struct wl1271 *wl)
if (is_sta) {
/* exit psm if it wasn't configured */
if (!test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags))
wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
wl->basic_rate, true);
} else if (is_ap) {
- wl1271_acx_set_ap_beacon_filter(wl, false);
+ wl1271_acx_beacon_filter_opt(wl, false);
}

wl1271_ps_elp_sleep(wl);
out:
mutex_unlock(&wl->mutex);
}
--
1.7.6.401.g6a319


2011-08-09 09:14:15

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 23/40] wl12xx: re-enable block ack session support

From: Arik Nemtsov <[email protected]>

Incorporate interface changes for HT support.

Add ba_bitmap field to the wl1271_link struct, to indicate
activate RX BA sessions (for AP mode).

Signed-off-by: Arik Nemtsov <[email protected]>
Signed-off-by: Eliad Peller <[email protected]>
---
drivers/net/wireless/wl12xx/acx.c | 74 +++++------------
drivers/net/wireless/wl12xx/acx.h | 82 +++++++------------
drivers/net/wireless/wl12xx/cmd.h | 1 +
drivers/net/wireless/wl12xx/conf.h | 6 ++
drivers/net/wireless/wl12xx/init.c | 37 +++------
drivers/net/wireless/wl12xx/main.c | 147 ++++++++++++++++++++++++----------
drivers/net/wireless/wl12xx/wl12xx.h | 6 ++
7 files changed, 176 insertions(+), 177 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c
index 6885568..02b9c7e 100644
--- a/drivers/net/wireless/wl12xx/acx.c
+++ b/drivers/net/wireless/wl12xx/acx.c
@@ -1320,25 +1320,21 @@ int wl1271_acx_set_ht_capabilities(struct wl1271 *wl,
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
if (!acx) {
ret = -ENOMEM;
goto out;
}

- /* Allow HT Operation ? */
if (allow_ht_operation) {
- ht_capabilites =
- WL1271_ACX_FW_CAP_HT_OPERATION;
- if (ht_cap->cap & IEEE80211_HT_CAP_GRN_FLD)
- ht_capabilites |=
- WL1271_ACX_FW_CAP_GREENFIELD_FRAME_FORMAT;
- if (ht_cap->cap & IEEE80211_HT_CAP_SGI_20)
- ht_capabilites |=
- WL1271_ACX_FW_CAP_SHORT_GI_FOR_20MHZ_PACKETS;
- if (ht_cap->cap & IEEE80211_HT_CAP_LSIG_TXOP_PROT)
- ht_capabilites |=
- WL1271_ACX_FW_CAP_LSIG_TXOP_PROTECTION;
+ /* no need to translate capabilities - use the spec values */
+ ht_capabilites = ht_cap->cap;
+
+ /*
+ * this bit is not employed by the spec but only by FW to
+ * indicate peer HT support
+ */
+ ht_capabilites |= WL12XX_HT_CAP_HT_OPERRATION;

/* get data from A-MPDU parameters field */
acx->ampdu_max_length = ht_cap->ampdu_factor;
acx->ampdu_min_spacing = ht_cap->ampdu_density;
}

@@ -1389,102 +1385,76 @@ int wl1271_acx_set_ht_information(struct wl1271 *wl,
out:
kfree(acx);
return ret;
}

/* Configure BA session initiator/receiver parameters setting in the FW. */
-int wl1271_acx_set_ba_session(struct wl1271 *wl,
- enum ieee80211_back_parties direction,
- u8 tid_index, u8 policy)
+int wl1271_acx_set_ba_initiator_policy(struct wl1271 *wl)
{
-#if 0
- struct wl1271_acx_ba_session_policy *acx;
+ struct wl1271_acx_ba_initiator_policy *acx;
int ret;

- wl1271_debug(DEBUG_ACX, "acx ba session setting");
+ wl1271_debug(DEBUG_ACX, "acx ba initiator policy");

acx = kzalloc(sizeof(*acx), GFP_KERNEL);
if (!acx) {
ret = -ENOMEM;
goto out;
}

- /* ANY role */
- acx->role_id = 0xff;
- acx->tid = tid_index;
- acx->enable = policy;
- acx->ba_direction = direction;
-
- switch (direction) {
- case WLAN_BACK_INITIATOR:
- acx->win_size = wl->conf.ht.tx_ba_win_size;
- acx->inactivity_timeout = wl->conf.ht.inactivity_timeout;
- break;
- case WLAN_BACK_RECIPIENT:
- acx->win_size = RX_BA_WIN_SIZE;
- acx->inactivity_timeout = 0;
- break;
- default:
- wl1271_error("Incorrect acx command id=%x\n", direction);
- ret = -EINVAL;
- goto out;
- }
+ /* set for the current role */
+ acx->role_id = wl->role_id;
+ acx->tid_bitmap = wl->conf.ht.tx_ba_tid_bitmap;
+ acx->win_size = wl->conf.ht.tx_ba_win_size;
+ acx->inactivity_timeout = wl->conf.ht.inactivity_timeout;

ret = wl1271_cmd_configure(wl,
- ACX_BA_SESSION_POLICY_CFG,
+ ACX_BA_SESSION_INITIATOR_POLICY,
acx,
sizeof(*acx));
if (ret < 0) {
- wl1271_warning("acx ba session setting failed: %d", ret);
+ wl1271_warning("acx ba initiator policy failed: %d", ret);
goto out;
}

out:
kfree(acx);
return ret;
-#endif
- wl1271_info("11n is currently not supported");
- return 0;
}

/* setup BA session receiver setting in the FW. */
-int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn,
- bool enable)
+int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index,
+ u16 ssn, bool enable, u8 peer_hlid)
{
-#if 0
struct wl1271_acx_ba_receiver_setup *acx;
int ret;

wl1271_debug(DEBUG_ACX, "acx ba receiver session setting");

acx = kzalloc(sizeof(*acx), GFP_KERNEL);
if (!acx) {
ret = -ENOMEM;
goto out;
}

- /* Single link for now */
- acx->link_id = 1;
+ acx->hlid = peer_hlid;
acx->tid = tid_index;
acx->enable = enable;
- acx->win_size = 0;
+ acx->win_size = RX_BA_WIN_SIZE;
acx->ssn = ssn;

ret = wl1271_cmd_configure(wl, ACX_BA_SESSION_RX_SETUP, acx,
sizeof(*acx));
if (ret < 0) {
wl1271_warning("acx ba receiver session failed: %d", ret);
goto out;
}

out:
kfree(acx);
return ret;
-#endif
- wl1271_info("11n is currently not supported");
- return 0;
}

int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime)
{
struct wl1271_acx_fw_tsf_information *tsf_info;
int ret;
diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h
index ac6194e..ba70f38 100644
--- a/drivers/net/wireless/wl12xx/acx.h
+++ b/drivers/net/wireless/wl12xx/acx.h
@@ -894,33 +894,26 @@ struct wl1271_acx_rssi_snr_avg_weights {
u8 rssi_beacon;
u8 rssi_data;
u8 snr_beacon;
u8 snr_data;
};

+
+/* special capability bit (not employed by the 802.11n spec) */
+#define WL12XX_HT_CAP_HT_OPERRATION BIT(16)
+
+
/*
* ACX_PEER_HT_CAP
* Configure HT capabilities - declare the capabilities of the peer
* we are connected to.
*/
struct wl1271_acx_ht_capabilities {
struct acx_header header;

- /*
- * bit 0 - Allow HT Operation
- * bit 1 - Allow Greenfield format in TX
- * bit 2 - Allow Short GI in TX
- * bit 3 - Allow L-SIG TXOP Protection in TX
- * bit 4 - Allow HT Control fields in TX.
- * Note, driver will still leave space for HT control in packets
- * regardless of the value of this field. FW will be responsible
- * to drop the HT field from any frame when this Bit set to 0.
- * bit 5 - Allow RD initiation in TXOP. FW is allowed to initate RD.
- * Exact policy setting for this feature is TBD.
- * Note, this bit can only be set to 1 if bit 3 is set to 1.
- */
+ /* bitmask of capability bits supported by the peer */
__le32 ht_capabilites;

/* Indicates to which link these capabilities apply. */
u8 hlid;

/*
@@ -932,21 +925,12 @@ struct wl1271_acx_ht_capabilities {
/* This is the minimal spacing required when sending A-MPDUs to the AP*/
u8 ampdu_min_spacing;

u8 padding;
} __packed;

-/* HT Capabilites Fw Bit Mask Mapping */
-#define WL1271_ACX_FW_CAP_HT_OPERATION BIT(0)
-#define WL1271_ACX_FW_CAP_GREENFIELD_FRAME_FORMAT BIT(1)
-#define WL1271_ACX_FW_CAP_SHORT_GI_FOR_20MHZ_PACKETS BIT(2)
-#define WL1271_ACX_FW_CAP_LSIG_TXOP_PROTECTION BIT(3)
-#define WL1271_ACX_FW_CAP_HT_CONTROL_FIELDS BIT(4)
-#define WL1271_ACX_FW_CAP_RD_INITIATION BIT(5)
-
-
/*
* ACX_HT_BSS_OPERATION
* Configure HT capabilities - AP rules for behavior in the BSS.
*/
struct wl1271_acx_ht_information {
struct acx_header header;
@@ -975,62 +959,54 @@ struct wl1271_acx_ht_information {
u8 dual_cts_protection;

u8 padding[2];
} __packed;

#define RX_BA_WIN_SIZE 8
+#define RX_BA_MAX_SESSIONS 2

-struct wl1271_acx_ba_session_policy {
+struct wl1271_acx_ba_initiator_policy {
struct acx_header header;
- /*
- * Specifies role Id, Range 0-7, 0xFF means ANY role.
- * Future use. For now this field is irrelevant
- */
+
+ /* Specifies role Id, Range 0-7, 0xFF means ANY role. */
u8 role_id;
+
/*
- * Specifies Link Id, Range 0-31, 0xFF means ANY Link Id.
- * Not applicable if Role Id is set to ANY.
+ * Per TID setting for allowing TX BA. Set a bit to 1 to allow
+ * TX BA sessions for the corresponding TID.
*/
- u8 link_id;
-
- u8 tid;
-
- u8 enable;
+ u8 tid_bitmap;

/* Windows size in number of packets */
- u16 win_size;
+ u8 win_size;

- /*
- * As initiator inactivity timeout in time units(TU) of 1024us.
- * As receiver reserved
- */
- u16 inactivity_timeout;
+ u8 padding1[1];

- /* Initiator = 1/Receiver = 0 */
- u8 ba_direction;
+ /* As initiator inactivity timeout in time units(TU) of 1024us */
+ u16 inactivity_timeout;

- u8 padding[3];
+ u8 padding[2];
} __packed;

struct wl1271_acx_ba_receiver_setup {
struct acx_header header;

- /* Specifies Link Id, Range 0-31, 0xFF means ANY Link Id */
- u8 link_id;
+ /* Specifies link id, range 0-31 */
+ u8 hlid;

u8 tid;

u8 enable;

- u8 padding[1];
-
/* Windows size in number of packets */
- u16 win_size;
+ u8 win_size;

/* BA session starting sequence number. RANGE 0-FFF */
u16 ssn;
+
+ u8 padding[2];
} __packed;

struct wl1271_acx_fw_tsf_information {
struct acx_header header;

__le32 current_tsf_high;
@@ -1215,13 +1191,13 @@ enum {
ACX_FRAG_CFG = 0x004F,
ACX_BET_ENABLE = 0x0050,
ACX_RSSI_SNR_TRIGGER = 0x0051,
ACX_RSSI_SNR_WEIGHTS = 0x0052,
ACX_KEEP_ALIVE_MODE = 0x0053,
ACX_SET_KEEP_ALIVE_CONFIG = 0x0054,
- ACX_BA_SESSION_POLICY_CFG = 0x0055,
+ ACX_BA_SESSION_INITIATOR_POLICY = 0x0055,
ACX_BA_SESSION_RX_SETUP = 0x0056,
ACX_PEER_HT_CAP = 0x0057,
ACX_HT_BSS_OPERATION = 0x0058,
ACX_COEX_ACTIVITY = 0x0059,
ACX_BURST_MODE = 0x005C,

@@ -1295,17 +1271,15 @@ int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, bool enable,
int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl);
int wl1271_acx_set_ht_capabilities(struct wl1271 *wl,
struct ieee80211_sta_ht_cap *ht_cap,
bool allow_ht_operation);
int wl1271_acx_set_ht_information(struct wl1271 *wl,
u16 ht_operation_mode);
-int wl1271_acx_set_ba_session(struct wl1271 *wl,
- enum ieee80211_back_parties direction,
- u8 tid_index, u8 policy);
-int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn,
- bool enable);
+int wl1271_acx_set_ba_initiator_policy(struct wl1271 *wl);
+int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index,
+ u16 ssn, bool enable, u8 peer_hlid);
int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime);
int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, bool enable);
int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl);
int wl1271_acx_config_ps(struct wl1271 *wl);
int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr);
int wl1271_acx_fm_coex(struct wl1271 *wl);
diff --git a/drivers/net/wireless/wl12xx/cmd.h b/drivers/net/wireless/wl12xx/cmd.h
index bb727d7..6f2a831 100644
--- a/drivers/net/wireless/wl12xx/cmd.h
+++ b/drivers/net/wireless/wl12xx/cmd.h
@@ -205,12 +205,13 @@ enum {
CMD_STATUS_STA_TABLE_FULL = 17,
CMD_STATUS_RADIO_ERROR = 18,
CMD_STATUS_WRONG_NESTING = 19,
CMD_STATUS_TIMEOUT = 21, /* Driver internal use.*/
CMD_STATUS_FW_RESET = 22, /* Driver internal use.*/
CMD_STATUS_TEMPLATE_OUT_OF_TEMPORARY_MEMORY = 23,
+ CMD_STATUS_NO_RX_BA_SESSION = 24,
MAX_COMMAND_STATUS = 0xff
};

#define CMDMBOX_HEADER_LEN 4
#define CMDMBOX_INFO_ELEM_HEADER_LEN 4

diff --git a/drivers/net/wireless/wl12xx/conf.h b/drivers/net/wireless/wl12xx/conf.h
index e3a6b28..a92df6e 100644
--- a/drivers/net/wireless/wl12xx/conf.h
+++ b/drivers/net/wireless/wl12xx/conf.h
@@ -554,12 +554,15 @@ struct conf_tx_ac_category {
*/
u16 tx_op_limit;
};

#define CONF_TX_MAX_TID_COUNT 8

+/* Allow TX BA on all TIDs but 6,7. These are currently reserved in the FW */
+#define CONF_TX_BA_ENABLED_TID_BITMAP 0x3F
+
enum {
CONF_CHANNEL_TYPE_DCF = 0, /* DC/LEGACY*/
CONF_CHANNEL_TYPE_EDCF = 1, /* EDCA*/
CONF_CHANNEL_TYPE_HCCA = 2, /* HCCA*/
};

@@ -1094,12 +1097,15 @@ struct conf_rf_settings {
u8 tx_per_channel_power_compensation_5[CONF_TX_PWR_COMPENSATION_LEN_5];
};

struct conf_ht_setting {
u16 tx_ba_win_size;
u16 inactivity_timeout;
+
+ /* bitmap of enabled TIDs for TX BA sessions */
+ u8 tx_ba_tid_bitmap;
};

struct conf_memory_settings {
/* Number of stations supported in IBSS mode */
u8 num_stations;

diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c
index b504ee1..67cd603 100644
--- a/drivers/net/wireless/wl12xx/init.c
+++ b/drivers/net/wireless/wl12xx/init.c
@@ -521,47 +521,30 @@ int wl1271_init_ap_rates(struct wl1271 *wl)
return ret;
}

return 0;
}

-static void wl1271_check_ba_support(struct wl1271 *wl)
-{
- /* validate FW cose ver x.x.x.50-60.x */
- if ((wl->chip.fw_ver[3] >= WL12XX_BA_SUPPORT_FW_COST_VER2_START) &&
- (wl->chip.fw_ver[3] < WL12XX_BA_SUPPORT_FW_COST_VER2_END)) {
- wl->ba_support = true;
- return;
- }
-
- wl->ba_support = false;
-}
-
static int wl1271_set_ba_policies(struct wl1271 *wl)
{
- u8 tid_index;
- int ret = 0;
-
/* Reset the BA RX indicators */
wl->ba_rx_bitmap = 0;
wl->ba_allowed = true;
+ wl->ba_rx_session_count = 0;

- /* validate that FW support BA */
- wl1271_check_ba_support(wl);
+ /* BA is supported in STA/AP modes */
+ if (wl->bss_type != BSS_TYPE_AP_BSS &&
+ wl->bss_type != BSS_TYPE_STA_BSS) {
+ wl->ba_support = false;
+ return 0;
+ }

- if (wl->ba_support)
- /* 802.11n initiator BA session setting */
- for (tid_index = 0; tid_index < CONF_TX_MAX_TID_COUNT;
- ++tid_index) {
- ret = wl1271_acx_set_ba_session(wl, WLAN_BACK_INITIATOR,
- tid_index, true);
- if (ret < 0)
- break;
- }
+ wl->ba_support = true;

- return ret;
+ /* 802.11n initiator BA session setting */
+ return wl1271_acx_set_ba_initiator_policy(wl);
}

int wl1271_chip_specific_init(struct wl1271 *wl)
{
int ret = 0;

diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index 994a26d..e523f0b 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -283,14 +283,15 @@ static struct conf_drv_settings default_conf = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
},
},
.ht = {
- .tx_ba_win_size = 64,
+ .tx_ba_win_size = 8,
.inactivity_timeout = 10000,
+ .tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP,
},
.mem_wl127x = {
.num_stations = 1,
.ssid_profiles = 1,
.rx_block_num = 70,
.tx_min_block_num = 40,
@@ -3157,54 +3158,28 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,

/* Need to update the BSSID (for filtering etc) */
do_join = true;
}
}

- rcu_read_lock();
- sta = ieee80211_find_sta(vif, bss_conf->bssid);
- if (sta) {
+ if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
+ rcu_read_lock();
+ sta = ieee80211_find_sta(vif, bss_conf->bssid);
+ if (!sta)
+ goto sta_not_found;
+
/* save the supp_rates of the ap */
sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
if (sta->ht_cap.ht_supported)
sta_rate_set |=
(sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
sta_ht_cap = sta->ht_cap;
sta_exists = true;
- }
- rcu_read_unlock();

- if (sta_exists) {
- /* handle new association with HT and HT information change */
- if ((changed & BSS_CHANGED_HT) &&
- (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
- ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
- true);
- if (ret < 0) {
- wl1271_warning("Set ht cap true failed %d",
- ret);
- goto out;
- }
- ret = wl1271_acx_set_ht_information(wl,
- bss_conf->ht_operation_mode);
- if (ret < 0) {
- wl1271_warning("Set ht information failed %d",
- ret);
- goto out;
- }
- }
- /* handle new association without HT and disassociation */
- else if (changed & BSS_CHANGED_ASSOC) {
- ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
- false);
- if (ret < 0) {
- wl1271_warning("Set ht cap false failed %d",
- ret);
- goto out;
- }
- }
+sta_not_found:
+ rcu_read_unlock();
}

if ((changed & BSS_CHANGED_ASSOC)) {
if (bss_conf->assoc) {
u32 rates;
int ieoffset;
@@ -3406,12 +3381,47 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
ret = wl1271_cmd_role_stop_dev(wl);
if (ret < 0)
goto out;
}
}

+ /* Handle new association with HT. Do this only after join. */
+ if (sta_exists) {
+ if ((changed & BSS_CHANGED_HT) &&
+ (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
+ ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
+ true);
+ if (ret < 0) {
+ wl1271_warning("Set ht cap true failed %d",
+ ret);
+ goto out;
+ }
+ }
+ /* handle new association without HT and disassociation */
+ else if (changed & BSS_CHANGED_ASSOC) {
+ ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
+ false);
+ if (ret < 0) {
+ wl1271_warning("Set ht cap false failed %d",
+ ret);
+ goto out;
+ }
+ }
+ }
+
+ /* Handle HT information change. Only after join. */
+ if (sta_exists && (changed & BSS_CHANGED_HT) &&
+ (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
+ ret = wl1271_acx_set_ht_information(wl,
+ bss_conf->ht_operation_mode);
+ if (ret < 0) {
+ wl1271_warning("Set ht information failed %d", ret);
+ goto out;
+ }
+ }
+
out:
return;
}

static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
@@ -3589,12 +3599,13 @@ static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)

if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
return;

__clear_bit(id, wl->ap_hlid_map);
memset(wl->links[hlid].addr, 0, ETH_ALEN);
+ wl->links[hlid].ba_bitmap = 0;
wl1271_tx_reset_link_queues(wl, hlid);
__clear_bit(hlid, &wl->ap_ps_map);
__clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
}

bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid)
@@ -3691,43 +3702,91 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
enum ieee80211_ampdu_mlme_action action,
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
u8 buf_size)
{
struct wl1271 *wl = hw->priv;
int ret;
+ u8 hlid, *ba_bitmap;
+
+ wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
+ tid);
+
+ /* sanity check - the fields in FW are only 8bits wide */
+ if (WARN_ON(tid > 0xFF))
+ return -ENOTSUPP;

mutex_lock(&wl->mutex);

if (unlikely(wl->state == WL1271_STATE_OFF)) {
ret = -EAGAIN;
goto out;
}

+ if (wl->bss_type == BSS_TYPE_STA_BSS) {
+ hlid = wl->sta_hlid;
+ ba_bitmap = &wl->ba_rx_bitmap;
+ } else if (wl->bss_type == BSS_TYPE_AP_BSS) {
+ struct wl1271_station *wl_sta;
+
+ wl_sta = (struct wl1271_station *)sta->drv_priv;
+ hlid = wl_sta->hlid;
+ ba_bitmap = &wl->links[hlid].ba_bitmap;
+ } else {
+ ret = -EINVAL;
+ goto out;
+ }
+
ret = wl1271_ps_elp_wakeup(wl);
if (ret < 0)
goto out;

wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
tid, action);

switch (action) {
case IEEE80211_AMPDU_RX_START:
- if ((wl->ba_support) && (wl->ba_allowed)) {
- ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn,
- true);
- if (!ret)
- wl->ba_rx_bitmap |= BIT(tid);
- } else {
+ if (!wl->ba_support || !wl->ba_allowed) {
ret = -ENOTSUPP;
+ break;
+ }
+
+ if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
+ ret = -EBUSY;
+ wl1271_error("exceeded max RX BA sessions");
+ break;
+ }
+
+ if (*ba_bitmap & BIT(tid)) {
+ ret = -EINVAL;
+ wl1271_error("cannot enable RX BA session on active "
+ "tid: %d", tid);
+ break;
+ }
+
+ ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn, true,
+ hlid);
+ if (!ret) {
+ *ba_bitmap |= BIT(tid);
+ wl->ba_rx_session_count++;
}
break;

case IEEE80211_AMPDU_RX_STOP:
- ret = wl1271_acx_set_ba_receiver_session(wl, tid, 0, false);
- if (!ret)
- wl->ba_rx_bitmap &= ~BIT(tid);
+ if (!(*ba_bitmap & BIT(tid))) {
+ ret = -EINVAL;
+ wl1271_error("no active RX BA session on tid: %d",
+ tid);
+ break;
+ }
+
+ ret = wl1271_acx_set_ba_receiver_session(wl, tid, 0, false,
+ hlid);
+ if (!ret) {
+ *ba_bitmap &= ~BIT(tid);
+ wl->ba_rx_session_count--;
+ }
break;

/*
* The BA initiator session management in FW independently.
* Falling break here on purpose for all TX APDU commands.
*/
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index 8dba44d..97a40c3 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -353,12 +353,15 @@ struct wl1271_link {

/* accounting for allocated / available TX blocks in FW */
u8 allocated_blks;
u8 prev_freed_blks;

u8 addr[ETH_ALEN];
+
+ /* bitmap of TIDs where RX BA sessions are active for this link */
+ u8 ba_bitmap;
};

struct wl1271 {
struct platform_device *plat_dev;
struct ieee80211_hw *hw;
bool mac80211_registered;
@@ -607,12 +610,15 @@ struct wl1271 {

/* Quirks of specific hardware revisions */
unsigned int quirks;

/* Platform limitations */
unsigned int platform_quirks;
+
+ /* number of currently active RX BA sessions */
+ int ba_rx_session_count;
};

struct wl1271_station {
u8 hlid;
};

--
1.7.6.401.g6a319


2011-08-09 09:14:02

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 16/40] wl12xx: add system_hlid

system_hlid is a const hlid (always 0), used by the fw and driver
for packets which are not bound to specific role (e.g. dynamic
memory packets).
indicate it as always allocated.

Signed-off-by: Eliad Peller <[email protected]>
---
drivers/net/wireless/wl12xx/main.c | 11 ++++++++++-
drivers/net/wireless/wl12xx/tx.c | 13 +++++++++----
drivers/net/wireless/wl12xx/tx.h | 2 +-
drivers/net/wireless/wl12xx/wl12xx.h | 2 ++
4 files changed, 22 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index 153189b..11909bb 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -1482,13 +1482,13 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
u8 hlid = 0;

mapping = skb_get_queue_mapping(skb);
q = wl1271_tx_get_queue(mapping);

if (wl->bss_type == BSS_TYPE_AP_BSS)
- hlid = wl1271_tx_get_hlid(skb);
+ hlid = wl1271_tx_get_hlid(wl, skb);

spin_lock_irqsave(&wl->wl_lock, flags);

wl->tx_queue_count[q]++;

/*
@@ -2047,12 +2047,15 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
wl->sched_scanning = false;
wl->role_id = WL1271_INVALID_ROLE_ID;
wl->dev_role_id = WL1271_INVALID_ROLE_ID;
memset(wl->roles_map, 0, sizeof(wl->roles_map));
memset(wl->links_map, 0, sizeof(wl->links_map));

+ /* The system link is always allocated */
+ __set_bit(WL1271_SYSTEM_HLID, wl->links_map);
+
/*
* this is performed after the cancel_work calls and the associated
* mutex_lock, so that wl1271_op_add_interface does not accidentally
* get executed before all these vars have been reset.
*/
wl->flags = 0;
@@ -4385,20 +4388,26 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
wl->quirks = 0;
wl->platform_quirks = 0;
wl->sched_scanning = false;
wl->tx_security_seq = 0;
wl->tx_security_last_seq_lsb = 0;
wl->role_id = WL1271_INVALID_ROLE_ID;
+ wl->system_hlid = WL1271_SYSTEM_HLID;
wl->sta_hlid = WL1271_INVALID_LINK_ID;
wl->dev_role_id = WL1271_INVALID_ROLE_ID;
wl->dev_hlid = WL1271_INVALID_LINK_ID;
setup_timer(&wl->rx_streaming_timer, wl1271_rx_streaming_timer,
(unsigned long) wl);
wl->fwlog_size = 0;
init_waitqueue_head(&wl->fwlog_waitq);

+ memset(wl->links_map, 0, sizeof(wl->links_map));
+
+ /* The system link is always allocated */
+ __set_bit(WL1271_SYSTEM_HLID, wl->links_map);
+
memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
wl->tx_frames[i] = NULL;

spin_lock_init(&wl->wl_lock);

diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c
index 2b17692..6a9be77 100644
--- a/drivers/net/wireless/wl12xx/tx.c
+++ b/drivers/net/wireless/wl12xx/tx.c
@@ -129,25 +129,28 @@ static void wl1271_tx_regulate_link(struct wl1271 *wl, u8 hlid)
*/
if (fw_ps && tx_blks >= WL1271_PS_STA_MAX_BLOCKS)
wl1271_ps_link_start(wl, hlid, true);
}
#endif

-u8 wl1271_tx_get_hlid(struct sk_buff *skb)
+u8 wl1271_tx_get_hlid(struct wl1271 *wl, struct sk_buff *skb)
{
struct ieee80211_tx_info *control = IEEE80211_SKB_CB(skb);

if (control->control.sta) {
struct wl1271_station *wl_sta;

wl_sta = (struct wl1271_station *)
control->control.sta->drv_priv;
return wl_sta->hlid;
} else {
struct ieee80211_hdr *hdr;

+ if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags))
+ return wl->system_hlid;
+
hdr = (struct ieee80211_hdr *)skb->data;
if (ieee80211_is_mgmt(hdr->frame_control))
return WL1271_AP_GLOBAL_HLID;
else
return WL1271_AP_BROADCAST_HLID;
}
@@ -368,14 +371,16 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb,
if (ret < 0)
return ret;
wl->default_key = idx;
}
}

- if (wl->bss_type == BSS_TYPE_AP_BSS)
- hlid = wl1271_tx_get_hlid(skb);
+ if (wl12xx_is_dummy_packet(wl, skb))
+ hlid = wl->system_hlid;
+ else if (wl->bss_type == BSS_TYPE_AP_BSS)
+ hlid = wl1271_tx_get_hlid(wl, skb);
else
if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
hlid = wl->sta_hlid;
else
hlid = wl->dev_hlid;

@@ -561,13 +566,13 @@ static void wl1271_skb_queue_head(struct wl1271 *wl, struct sk_buff *skb)
unsigned long flags;
int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));

if (wl12xx_is_dummy_packet(wl, skb)) {
set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
} else if (wl->bss_type == BSS_TYPE_AP_BSS) {
- u8 hlid = wl1271_tx_get_hlid(skb);
+ u8 hlid = wl1271_tx_get_hlid(wl, skb);
skb_queue_head(&wl->links[hlid].tx_queue[q], skb);

/* make sure we dequeue the same packet next time */
wl->last_tx_hlid = (hlid + AP_MAX_LINKS - 1) % AP_MAX_LINKS;
} else {
skb_queue_head(&wl->tx_queue[q], skb);
diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/tx.h
index b712d7b..62f55f6 100644
--- a/drivers/net/wireless/wl12xx/tx.h
+++ b/drivers/net/wireless/wl12xx/tx.h
@@ -207,11 +207,11 @@ void wl1271_tx_work_locked(struct wl1271 *wl);
void wl1271_tx_complete(struct wl1271 *wl);
void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues);
void wl1271_tx_flush(struct wl1271 *wl);
u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band);
u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set);
u32 wl1271_tx_min_rate_get(struct wl1271 *wl);
-u8 wl1271_tx_get_hlid(struct sk_buff *skb);
+u8 wl1271_tx_get_hlid(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);

#endif
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index a732932..9c5daae 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -138,12 +138,13 @@ extern u32 wl12xx_debug_level;
#define WL1271_DEFAULT_DTIM_PERIOD 1

#define WL1271_MAX_ROLES 4
#define WL1271_MAX_LINKS 8
#define WL1271_INVALID_ROLE_ID 0xff
#define WL1271_INVALID_LINK_ID 0xff
+#define WL1271_SYSTEM_HLID 0
#define WL1271_AP_GLOBAL_HLID 0
#define WL1271_AP_BROADCAST_HLID 1
#define WL1271_AP_STA_HLID_START 2

/*
* When in AP-mode, we allow (at least) this number of mem-blocks
@@ -392,12 +393,13 @@ struct wl1271 {
u8 set_bss_type;
u8 ssid[IW_ESSID_MAX_SIZE + 1];
u8 ssid_len;
int channel;
u8 role_id;
u8 dev_role_id;
+ u8 system_hlid;
u8 sta_hlid;
u8 dev_hlid;

unsigned long links_map[BITS_TO_LONGS(WL1271_MAX_LINKS)];
unsigned long roles_map[BITS_TO_LONGS(WL1271_MAX_ROLES)];

--
1.7.6.401.g6a319


2011-08-11 09:17:43

by Luciano Coelho

[permalink] [raw]
Subject: Re: [PATCH 33/40] wl12xx: track freed packets in FW by AC

On Tue, 2011-08-09 at 12:13 +0300, Eliad Peller wrote:
> From: Arik Nemtsov <[email protected]>
>
> Track the number of freed packets in each AC when receiving an interrupt
> from the FW. This paves the way for tracking allocated packets per AC.
>
> Signed-off-by: Arik Nemtsov <[email protected]>
> Signed-off-by: Eliad Peller <[email protected]>
> ---
> drivers/net/wireless/wl12xx/main.c | 16 +++++++++++++++-
> drivers/net/wireless/wl12xx/tx.c | 2 ++
> drivers/net/wireless/wl12xx/wl12xx.h | 8 ++++++--
> 3 files changed, 23 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
> index b223c27..3bfd772 100644
> --- a/drivers/net/wireless/wl12xx/main.c
> +++ b/drivers/net/wireless/wl12xx/main.c
> @@ -810,22 +810,32 @@ static void wl1271_irq_update_links_status(struct wl1271 *wl,
> static void wl1271_fw_status(struct wl1271 *wl,
> struct wl1271_fw_status *status)
> {
> struct timespec ts;
> u32 old_tx_blk_count = wl->tx_blocks_available;
> int avail, freed_blocks;
> + int i;
>
> wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
>
> wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
> "drv_rx_counter = %d, tx_results_counter = %d)",
> status->intr,
> status->fw_rx_counter,
> status->drv_rx_counter,
> status->tx_results_counter);
>
> + for (i = 0; i < NUM_TX_QUEUES; i++) {
> + /* prevent wrap-around in freed-packets counter */
> + wl->tx_allocated_pkts -=
> + (status->tx_released_pkts[i] -
> + wl->tx_pkts_freed[i] + 256) % 256;

Isn't the "+ 256" useless here, since you'll mod the result anyway?


--
Cheers,
Luca.


2011-08-09 09:13:49

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 09/40] wl12xx: enable/disable role on interface add/remove

According to the new multi-role flow, we have to enable the
role before using (starting) it, and disable it on cleanup
(after it's no longer needed).

Signed-off-by: Eliad Peller <[email protected]>
---
drivers/net/wireless/wl12xx/main.c | 38 ++++++++++++++++++++++++++++++++++++
1 files changed, 38 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index a348d18..ba0470f 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -1770,12 +1770,27 @@ static int wl1271_op_start(struct ieee80211_hw *hw)

static void wl1271_op_stop(struct ieee80211_hw *hw)
{
wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
}

+static u8 wl1271_get_role_type(struct wl1271 *wl)
+{
+ switch (wl->bss_type) {
+ case BSS_TYPE_AP_BSS:
+ return WL1271_ROLE_AP;
+
+ case BSS_TYPE_STA_BSS:
+ return WL1271_ROLE_STA;
+
+ default:
+ wl1271_info("invalid bss_type: %d", wl->bss_type);
+ }
+ return 0xff;
+}
+
static int wl1271_op_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct wl1271 *wl = hw->priv;
struct wiphy *wiphy = hw->wiphy;
int retries = WL1271_BOOT_RETRIES;
@@ -1836,12 +1851,17 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
goto power_off;

ret = wl1271_boot(wl);
if (ret < 0)
goto power_off;

+ ret = wl1271_cmd_role_enable(wl, wl1271_get_role_type(wl),
+ &wl->role_id);
+ if (ret < 0)
+ goto irq_disable;
+
ret = wl1271_hw_init(wl);
if (ret < 0)
goto irq_disable;

booted = true;
break;
@@ -1900,12 +1920,13 @@ out:
return ret;
}

static void __wl1271_op_remove_interface(struct wl1271 *wl,
bool reset_tx_queues)
{
+ int ret;

wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");

/* because of hardware recovery, we may get here twice */
if (wl->state != WL1271_STATE_ON)
return;
@@ -1924,12 +1945,29 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
wl->scan.state = WL1271_SCAN_STATE_IDLE;
memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
wl->scan.req = NULL;
ieee80211_scan_completed(wl->hw, true);
}

+ if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
+ /* disable active roles */
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0) {
+ /*
+ * do nothing. we are going to power off the chip
+ * anyway. handle this case when we'll really
+ * support multi-role...
+ */
+ }
+ wl1271_cmd_role_disable(wl, &wl->role_id);
+
+ wl1271_ps_elp_sleep(wl);
+ }
+
+ wl->sta_hlid = WL1271_INVALID_LINK_ID;
+
/*
* this must be before the cancel_work calls below, so that the work
* functions don't perform further work.
*/
wl->state = WL1271_STATE_OFF;

--
1.7.6.401.g6a319


2011-08-15 09:34:14

by Shahar Levi

[permalink] [raw]
Subject: Re: [PATCH 23/40] wl12xx: re-enable block ack session support

On Tue, Aug 9, 2011 at 12:13 PM, Eliad Peller <[email protected]> wrote:
> From: Arik Nemtsov <[email protected]>
- linux-wireless
+ mcs list

>
> Incorporate interface changes for HT support.
>
> Add ba_bitmap field to the wl1271_link struct, to indicate
> activate RX BA sessions (for AP mode).
>
> Signed-off-by: Arik Nemtsov <[email protected]>
> Signed-off-by: Eliad Peller <[email protected]>
> ---
...

> diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
> index 994a26d..e523f0b 100644
> --- a/drivers/net/wireless/wl12xx/main.c
> +++ b/drivers/net/wireless/wl12xx/main.c
> @@ -283,14 +283,15 @@ static struct conf_drv_settings default_conf = {
> ? ? ? ? ? ? ? ? ? ? ? ?0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> ? ? ? ? ? ? ? ? ? ? ? ?0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> ? ? ? ? ? ? ? ? ? ? ? ?0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> ? ? ? ? ? ? ? ?},
> ? ? ? ?},
> ? ? ? ?.ht = {
> - ? ? ? ? ? ? ? .tx_ba_win_size = 64,
> + ? ? ? ? ? ? ? .tx_ba_win_size = 8,
Is the FW stop supporting TX BA win of 64?

All the best,
Shahar

2011-08-09 12:49:15

by Luciano Coelho

[permalink] [raw]
Subject: Re: [PATCH 04/40] wl12xx: temporarily disable 11n and advanced ap functions

On Tue, 2011-08-09 at 12:13 +0300, Eliad Peller wrote:
> In order to keep to driver compiling during the patchset,
> while avoiding one-huge-patch, temporarily disable 11n
> and some advanced ap functions.
>
> These changes will be reverted later in the patchset, as
> part of the patches for 11n and advanced ap functions
> support for the new fw.
>
> Signed-off-by: Eliad Peller <[email protected]>
> ---

As discussed on IRC, please remove the #if 0's for the BA part as we
agreed they're not needed and recheck if all the other cases are really
necessary (and please explain why! :)


--
Cheers,
Luca.


2011-08-09 09:13:45

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 07/40] wl12xx: wl12xx-fw-3 - update acx commands

Update the acx commands according to the new fw api.

The main change in most of the ACXs is the addition
of a new role_id/link_id field, which is required
for multi-role operation.

Currently, we don't really support multi-role, as
most of our data (inside wl) is global.
As the current fw doesn't support concurrent roles
yet, keep it this way and add wl->role_id and
wl->sta_hlid to save the active role/link.

Signed-off-by: Eliad Peller <[email protected]>
---
drivers/net/wireless/wl12xx/acx.c | 113 ++++++++++++---------------
drivers/net/wireless/wl12xx/acx.h | 141 +++++++++++++++++++---------------
drivers/net/wireless/wl12xx/init.c | 4 +-
drivers/net/wireless/wl12xx/main.c | 5 +-
drivers/net/wireless/wl12xx/wl12xx.h | 4 +
5 files changed, 137 insertions(+), 130 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c
index 804bac9..42bfce8 100644
--- a/drivers/net/wireless/wl12xx/acx.c
+++ b/drivers/net/wireless/wl12xx/acx.c
@@ -43,12 +43,13 @@ int wl1271_acx_wake_up_conditions(struct wl1271 *wl)
wake_up = kzalloc(sizeof(*wake_up), GFP_KERNEL);
if (!wake_up) {
ret = -ENOMEM;
goto out;
}

+ wake_up->role_id = wl->role_id;
wake_up->wake_up_event = wl->conf.conn.wake_up_event;
wake_up->listen_interval = wl->conf.conn.listen_interval;

ret = wl1271_cmd_configure(wl, ACX_WAKE_UP_CONDITIONS,
wake_up, sizeof(*wake_up));
if (ret < 0) {
@@ -98,12 +99,13 @@ int wl1271_acx_tx_power(struct wl1271 *wl, int power)
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
if (!acx) {
ret = -ENOMEM;
goto out;
}

+ acx->role_id = wl->role_id;
acx->current_tx_power = power * 10;

ret = wl1271_cmd_configure(wl, DOT11_CUR_TX_PWR, acx, sizeof(*acx));
if (ret < 0) {
wl1271_warning("configure of tx power failed: %d", ret);
goto out;
@@ -125,12 +127,13 @@ int wl1271_acx_feature_cfg(struct wl1271 *wl)
if (!feature) {
ret = -ENOMEM;
goto out;
}

/* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */
+ feature->role_id = wl->role_id;
feature->data_flow_options = 0;
feature->options = 0;

ret = wl1271_cmd_configure(wl, ACX_FEATURE_CFG,
feature, sizeof(*feature));
if (ret < 0) {
@@ -219,12 +222,13 @@ int wl1271_acx_slot(struct wl1271 *wl, enum acx_slot_type slot_time)
slot = kzalloc(sizeof(*slot), GFP_KERNEL);
if (!slot) {
ret = -ENOMEM;
goto out;
}

+ slot->role_id = wl->role_id;
slot->wone_index = STATION_WONE_INDEX;
slot->slot_time = slot_time;

ret = wl1271_cmd_configure(wl, ACX_SLOT, slot, sizeof(*slot));
if (ret < 0) {
wl1271_warning("failed to set slot time: %d", ret);
@@ -248,12 +252,13 @@ int wl1271_acx_group_address_tbl(struct wl1271 *wl, bool enable,
if (!acx) {
ret = -ENOMEM;
goto out;
}

/* MAC filtering */
+ acx->role_id = wl->role_id;
acx->enabled = enable;
acx->num_groups = mc_list_len;
memcpy(acx->mac_table, mc_list, mc_list_len * ETH_ALEN);

ret = wl1271_cmd_configure(wl, DOT11_GROUP_ADDRESS_TBL,
acx, sizeof(*acx));
@@ -277,12 +282,13 @@ int wl1271_acx_service_period_timeout(struct wl1271 *wl)
ret = -ENOMEM;
goto out;
}

wl1271_debug(DEBUG_ACX, "acx service period timeout");

+ rx_timeout->role_id = wl->role_id;
rx_timeout->ps_poll_timeout = cpu_to_le16(wl->conf.rx.ps_poll_timeout);
rx_timeout->upsd_timeout = cpu_to_le16(wl->conf.rx.upsd_timeout);

ret = wl1271_cmd_configure(wl, ACX_SERVICE_PERIOD_TIMEOUT,
rx_timeout, sizeof(*rx_timeout));
if (ret < 0) {
@@ -313,12 +319,13 @@ int wl1271_acx_rts_threshold(struct wl1271 *wl, u32 rts_threshold)
rts = kzalloc(sizeof(*rts), GFP_KERNEL);
if (!rts) {
ret = -ENOMEM;
goto out;
}

+ rts->role_id = wl->role_id;
rts->threshold = cpu_to_le16((u16)rts_threshold);

ret = wl1271_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts));
if (ret < 0) {
wl1271_warning("failed to set rts threshold: %d", ret);
goto out;
@@ -372,12 +379,13 @@ int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter)
beacon_filter = kzalloc(sizeof(*beacon_filter), GFP_KERNEL);
if (!beacon_filter) {
ret = -ENOMEM;
goto out;
}

+ beacon_filter->role_id = wl->role_id;
beacon_filter->enable = enable_filter;

/*
* When set to zero, and the filter is enabled, beacons
* without the unicast TIM bit set are dropped.
*/
@@ -408,12 +416,13 @@ int wl1271_acx_beacon_filter_table(struct wl1271 *wl)
if (!ie_table) {
ret = -ENOMEM;
goto out;
}

/* configure default beacon pass-through rules */
+ ie_table->role_id = wl->role_id;
ie_table->num_ie = 0;
for (i = 0; i < wl->conf.conn.bcn_filt_ie_count; i++) {
struct conf_bcn_filt_rule *r = &(wl->conf.conn.bcn_filt_ie[i]);
ie_table->table[idx++] = r->ie;
ie_table->table[idx++] = r->rule;

@@ -469,12 +478,13 @@ int wl1271_acx_conn_monit_params(struct wl1271 *wl, bool enable)

if (enable) {
threshold = wl->conf.conn.synch_fail_thold;
timeout = wl->conf.conn.bss_lose_timeout;
}

+ acx->role_id = wl->role_id;
acx->synch_fail_thold = cpu_to_le32(threshold);
acx->bss_lose_timeout = cpu_to_le32(timeout);

ret = wl1271_cmd_configure(wl, ACX_CONN_MONIT_PARAMS,
acx, sizeof(*acx));
if (ret < 0) {
@@ -616,12 +626,13 @@ int wl1271_acx_bcn_dtim_options(struct wl1271 *wl)
bb = kzalloc(sizeof(*bb), GFP_KERNEL);
if (!bb) {
ret = -ENOMEM;
goto out;
}

+ bb->role_id = wl->role_id;
bb->beacon_rx_timeout = cpu_to_le16(wl->conf.conn.beacon_rx_timeout);
bb->broadcast_timeout = cpu_to_le16(wl->conf.conn.broadcast_timeout);
bb->rx_broadcast_in_ps = wl->conf.conn.rx_broadcast_in_ps;
bb->ps_poll_threshold = wl->conf.conn.ps_poll_threshold;

ret = wl1271_cmd_configure(wl, ACX_BCN_DTIM_OPTIONS, bb, sizeof(*bb));
@@ -645,12 +656,13 @@ int wl1271_acx_aid(struct wl1271 *wl, u16 aid)
acx_aid = kzalloc(sizeof(*acx_aid), GFP_KERNEL);
if (!acx_aid) {
ret = -ENOMEM;
goto out;
}

+ acx_aid->role_id = wl->role_id;
acx_aid->aid = cpu_to_le16(aid);

ret = wl1271_cmd_configure(wl, ACX_AID, acx_aid, sizeof(*acx_aid));
if (ret < 0) {
wl1271_warning("failed to set aid: %d", ret);
goto out;
@@ -700,12 +712,13 @@ int wl1271_acx_set_preamble(struct wl1271 *wl, enum acx_preamble_type preamble)
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
if (!acx) {
ret = -ENOMEM;
goto out;
}

+ acx->role_id = wl->role_id;
acx->preamble = preamble;

ret = wl1271_cmd_configure(wl, ACX_PREAMBLE_TYPE, acx, sizeof(*acx));
if (ret < 0) {
wl1271_warning("Setting of preamble failed: %d", ret);
goto out;
@@ -727,12 +740,13 @@ int wl1271_acx_cts_protect(struct wl1271 *wl,
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
if (!acx) {
ret = -ENOMEM;
goto out;
}

+ acx->role_id = wl->role_id;
acx->ctsprotect = ctsprotect;

ret = wl1271_cmd_configure(wl, ACX_CTS_PROTECTION, acx, sizeof(*acx));
if (ret < 0) {
wl1271_warning("Setting of ctsprotect failed: %d", ret);
goto out;
@@ -758,45 +772,49 @@ int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats)

return 0;
}

int wl1271_acx_sta_rate_policies(struct wl1271 *wl)
{
- struct acx_sta_rate_policy *acx;
+ struct acx_rate_policy *acx;
struct conf_tx_rate_class *c = &wl->conf.tx.sta_rc_conf;
- int idx = 0;
int ret = 0;

wl1271_debug(DEBUG_ACX, "acx rate policies");

acx = kzalloc(sizeof(*acx), GFP_KERNEL);

if (!acx) {
ret = -ENOMEM;
goto out;
}

+ wl1271_debug(DEBUG_ACX, "basic_rate: 0x%x, full_rate: 0x%x",
+ wl->basic_rate, wl->rate_set);
+
/* configure one basic rate class */
- idx = ACX_TX_BASIC_RATE;
- acx->rate_class[idx].enabled_rates = cpu_to_le32(wl->basic_rate);
- acx->rate_class[idx].short_retry_limit = c->short_retry_limit;
- acx->rate_class[idx].long_retry_limit = c->long_retry_limit;
- acx->rate_class[idx].aflags = c->aflags;
+ acx->rate_policy_idx = cpu_to_le32(ACX_TX_BASIC_RATE);
+ acx->rate_policy.enabled_rates = cpu_to_le32(wl->basic_rate);
+ acx->rate_policy.short_retry_limit = c->short_retry_limit;
+ acx->rate_policy.long_retry_limit = c->long_retry_limit;
+ acx->rate_policy.aflags = c->aflags;
+
+ ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1271_warning("Setting of rate policies failed: %d", ret);
+ goto out;
+ }

/* configure one AP supported rate class */
- idx = ACX_TX_AP_FULL_RATE;
- acx->rate_class[idx].enabled_rates = cpu_to_le32(wl->rate_set);
- acx->rate_class[idx].short_retry_limit = c->short_retry_limit;
- acx->rate_class[idx].long_retry_limit = c->long_retry_limit;
- acx->rate_class[idx].aflags = c->aflags;
+ acx->rate_policy_idx = cpu_to_le32(ACX_TX_AP_FULL_RATE);
+ acx->rate_policy.enabled_rates = cpu_to_le32(wl->rate_set);
+ acx->rate_policy.short_retry_limit = c->short_retry_limit;
+ acx->rate_policy.long_retry_limit = c->long_retry_limit;
+ acx->rate_policy.aflags = c->aflags;

- acx->rate_class_cnt = cpu_to_le32(ACX_TX_RATE_POLICY_CNT);

- wl1271_debug(DEBUG_ACX, "basic_rate: 0x%x, full_rate: 0x%x",
- acx->rate_class[ACX_TX_BASIC_RATE].enabled_rates,
- acx->rate_class[ACX_TX_AP_FULL_RATE].enabled_rates);

ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx));
if (ret < 0) {
wl1271_warning("Setting of rate policies failed: %d", ret);
goto out;
}
@@ -806,13 +824,13 @@ out:
return ret;
}

int wl1271_acx_ap_rate_policy(struct wl1271 *wl, struct conf_tx_rate_class *c,
u8 idx)
{
- struct acx_ap_rate_policy *acx;
+ struct acx_rate_policy *acx;
int ret = 0;

wl1271_debug(DEBUG_ACX, "acx ap rate policy %d rates 0x%x",
idx, c->enabled_rates);

acx = kzalloc(sizeof(*acx), GFP_KERNEL);
@@ -852,12 +870,13 @@ int wl1271_acx_ac_cfg(struct wl1271 *wl, u8 ac, u8 cw_min, u16 cw_max,

if (!acx) {
ret = -ENOMEM;
goto out;
}

+ acx->role_id = wl->role_id;
acx->ac = ac;
acx->cw_min = cw_min;
acx->cw_max = cpu_to_le16(cw_max);
acx->aifsn = aifsn;
acx->tx_op_limit = cpu_to_le16(txop);

@@ -885,12 +904,13 @@ int wl1271_acx_tid_cfg(struct wl1271 *wl, u8 queue_id, u8 channel_type,

if (!acx) {
ret = -ENOMEM;
goto out;
}

+ acx->role_id = wl->role_id;
acx->queue_id = queue_id;
acx->channel_type = channel_type;
acx->tsid = tsid;
acx->ps_scheme = ps_scheme;
acx->ack_policy = ack_policy;
acx->apsd_conf[0] = cpu_to_le32(apsd_conf0);
@@ -964,58 +984,15 @@ int wl1271_acx_tx_config_options(struct wl1271 *wl)

out:
kfree(acx);
return ret;
}

-int wl1271_acx_ap_mem_cfg(struct wl1271 *wl)
-{
- struct wl1271_acx_ap_config_memory *mem_conf;
- struct conf_memory_settings *mem;
- int ret;
-
- wl1271_debug(DEBUG_ACX, "wl1271 mem cfg");
-
- mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL);
- if (!mem_conf) {
- ret = -ENOMEM;
- goto out;
- }
-
- if (wl->chip.id == CHIP_ID_1283_PG20)
- /*
- * FIXME: The 128x AP FW does not yet support dynamic memory.
- * Use the base memory configuration for 128x for now. This
- * should be fine tuned in the future.
- */
- mem = &wl->conf.mem_wl128x;
- else
- mem = &wl->conf.mem_wl127x;
-
- /* memory config */
- mem_conf->num_stations = mem->num_stations;
- mem_conf->rx_mem_block_num = mem->rx_block_num;
- mem_conf->tx_min_mem_block_num = mem->tx_min_block_num;
- mem_conf->num_ssid_profiles = mem->ssid_profiles;
- mem_conf->total_tx_descriptors = cpu_to_le32(ACX_TX_DESCRIPTORS);
-
- ret = wl1271_cmd_configure(wl, ACX_MEM_CFG, mem_conf,
- sizeof(*mem_conf));
- if (ret < 0) {
- wl1271_warning("wl1271 mem config failed: %d", ret);
- goto out;
- }
-
-out:
- kfree(mem_conf);
- return ret;
-}
-
-int wl1271_acx_sta_mem_cfg(struct wl1271 *wl)
+int wl1271_acx_mem_cfg(struct wl1271 *wl)
{
- struct wl1271_acx_sta_config_memory *mem_conf;
+ struct wl1271_acx_config_memory *mem_conf;
struct conf_memory_settings *mem;
int ret;

wl1271_debug(DEBUG_ACX, "wl1271 mem cfg");

mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL);
@@ -1152,12 +1129,13 @@ int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable)
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
if (!acx) {
ret = -ENOMEM;
goto out;
}

+ acx->role_id = wl->role_id;
acx->enable = enable ? CONF_BET_MODE_ENABLE : CONF_BET_MODE_DISABLE;
acx->max_consecutive = wl->conf.conn.bet_max_consecutive;

ret = wl1271_cmd_configure(wl, ACX_BET_ENABLE, acx, sizeof(*acx));
if (ret < 0) {
wl1271_warning("acx bet enable failed: %d", ret);
@@ -1179,12 +1157,13 @@ int wl1271_acx_arp_ip_filter(struct wl1271 *wl, u8 enable, __be32 address)
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
if (!acx) {
ret = -ENOMEM;
goto out;
}

+ acx->role_id = wl->role_id;
acx->version = ACX_IPV4_VERSION;
acx->enable = enable;

if (enable)
memcpy(acx->address, &address, ACX_IPV4_ADDR_SIZE);

@@ -1238,12 +1217,13 @@ int wl1271_acx_keep_alive_mode(struct wl1271 *wl, bool enable)
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
if (!acx) {
ret = -ENOMEM;
goto out;
}

+ acx->role_id = wl->role_id;
acx->enabled = enable;

ret = wl1271_cmd_configure(wl, ACX_KEEP_ALIVE_MODE, acx, sizeof(*acx));
if (ret < 0) {
wl1271_warning("acx keep alive mode failed: %d", ret);
goto out;
@@ -1264,12 +1244,13 @@ int wl1271_acx_keep_alive_config(struct wl1271 *wl, u8 index, u8 tpl_valid)
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
if (!acx) {
ret = -ENOMEM;
goto out;
}

+ acx->role_id = wl->role_id;
acx->period = cpu_to_le32(wl->conf.conn.keep_alive_interval);
acx->index = index;
acx->tpl_validation = tpl_valid;
acx->trigger = ACX_KEEP_ALIVE_NO_TX;

ret = wl1271_cmd_configure(wl, ACX_SET_KEEP_ALIVE_CONFIG,
@@ -1297,12 +1278,13 @@ int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, bool enable,
ret = -ENOMEM;
goto out;
}

wl->last_rssi_event = -1;

+ acx->role_id = wl->role_id;
acx->pacing = cpu_to_le16(wl->conf.roam_trigger.trigger_pacing);
acx->metric = WL1271_ACX_TRIG_METRIC_RSSI_BEACON;
acx->type = WL1271_ACX_TRIG_TYPE_EDGE;
if (enable)
acx->enable = WL1271_ACX_TRIG_ENABLE;
else
@@ -1335,12 +1317,13 @@ int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl)
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
if (!acx) {
ret = -ENOMEM;
goto out;
}

+ acx->role_id = wl->role_id;
acx->rssi_beacon = c->avg_weight_rssi_beacon;
acx->rssi_data = c->avg_weight_rssi_data;
acx->snr_beacon = c->avg_weight_snr_beacon;
acx->snr_data = c->avg_weight_snr_data;

ret = wl1271_cmd_configure(wl, ACX_RSSI_SNR_WEIGHTS, acx, sizeof(*acx));
@@ -1356,13 +1339,12 @@ out:

int wl1271_acx_set_ht_capabilities(struct wl1271 *wl,
struct ieee80211_sta_ht_cap *ht_cap,
bool allow_ht_operation)
{
struct wl1271_acx_ht_capabilities *acx;
- u8 mac_address[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
int ret = 0;
u32 ht_capabilites = 0;

wl1271_debug(DEBUG_ACX, "acx ht capabilities setting");

acx = kzalloc(sizeof(*acx), GFP_KERNEL);
@@ -1387,13 +1369,13 @@ int wl1271_acx_set_ht_capabilities(struct wl1271 *wl,

/* get data from A-MPDU parameters field */
acx->ampdu_max_length = ht_cap->ampdu_factor;
acx->ampdu_min_spacing = ht_cap->ampdu_density;
}

- memcpy(acx->mac_address, mac_address, ETH_ALEN);
+ acx->hlid = wl->sta_hlid;
acx->ht_capabilites = cpu_to_le32(ht_capabilites);

ret = wl1271_cmd_configure(wl, ACX_PEER_HT_CAP, acx, sizeof(*acx));
if (ret < 0) {
wl1271_warning("acx ht capabilities setting failed: %d", ret);
goto out;
@@ -1415,12 +1397,13 @@ int wl1271_acx_set_ht_information(struct wl1271 *wl,
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
if (!acx) {
ret = -ENOMEM;
goto out;
}

+ acx->role_id = wl->role_id;
acx->ht_protection =
(u8)(ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION);
acx->rifs_mode = 0;
acx->gf_protection =
!!(ht_operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
acx->ht_tx_burst_limit = 0;
@@ -1583,12 +1566,13 @@ int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, bool enable)
* this check assumes conf.rx_streaming.queues can't
* be changed while rx_streaming is enabled.
*/
if (!(conf_queues & BIT(i)))
continue;

+ rx_streaming->role_id = wl->role_id;
rx_streaming->tid = i;
rx_streaming->enable = enable_queues & BIT(i);
rx_streaming->period = wl->conf.rx_streaming.interval;
rx_streaming->timeout = wl->conf.rx_streaming.interval;

ret = wl1271_cmd_configure(wl, ACX_PS_RX_STREAMING,
@@ -1612,12 +1596,13 @@ int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl)
wl1271_debug(DEBUG_ACX, "acx ap max tx retry");

acx = kzalloc(sizeof(*acx), GFP_KERNEL);
if (!acx)
return -ENOMEM;

+ acx->role_id = wl->role_id;
acx->max_tx_retry = cpu_to_le16(wl->conf.tx.max_tx_retries);

ret = wl1271_cmd_configure(wl, ACX_MAX_TX_FAILURE, acx, sizeof(*acx));
if (ret < 0) {
wl1271_warning("acx ap max tx retry failed: %d", ret);
goto out;
diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h
index 4ae0085..9cc5d62 100644
--- a/drivers/net/wireless/wl12xx/acx.h
+++ b/drivers/net/wireless/wl12xx/acx.h
@@ -98,12 +98,21 @@ struct acx_error_counter {

/* the number of missed sequence numbers in the squentially */
/* values of frames seq numbers */
__le32 seq_num_miss;
} __packed;

+enum wl1271_role {
+ WL1271_ROLE_STA = 0,
+ WL1271_ROLE_IBSS,
+ WL1271_ROLE_AP,
+ WL1271_ROLE_DEVICE,
+ WL1271_ROLE_P2P_CL,
+ WL1271_ROLE_P2P_GO,
+};
+
enum wl1271_psm_mode {
/* Active mode */
WL1271_PSM_CAM = 0,

/* Power save mode */
WL1271_PSM_PS = 1,
@@ -176,57 +185,64 @@ enum acx_slot_type {

#define STATION_WONE_INDEX 0

struct acx_slot {
struct acx_header header;

+ u8 role_id;
u8 wone_index; /* Reserved */
u8 slot_time;
- u8 reserved[6];
+ u8 reserved[5];
} __packed;


#define ACX_MC_ADDRESS_GROUP_MAX (8)
#define ADDRESS_GROUP_MAX_LEN (ETH_ALEN * ACX_MC_ADDRESS_GROUP_MAX)

struct acx_dot11_grp_addr_tbl {
struct acx_header header;

+ u8 role_id;
u8 enabled;
u8 num_groups;
- u8 pad[2];
+ u8 pad[1];
u8 mac_table[ADDRESS_GROUP_MAX_LEN];
} __packed;

struct acx_rx_timeout {
struct acx_header header;

+ u8 role_id;
+ u8 reserved;
__le16 ps_poll_timeout;
__le16 upsd_timeout;
+ u8 padding[2];
} __packed;

struct acx_rts_threshold {
struct acx_header header;

+ u8 role_id;
+ u8 reserved;
__le16 threshold;
- u8 pad[2];
} __packed;

struct acx_beacon_filter_option {
struct acx_header header;

+ u8 role_id;
u8 enable;
/*
* The number of beacons without the unicast TIM
* bit set that the firmware buffers before
* signaling the host about ready frames.
* When set to 0 and the filter is enabled, beacons
* without the unicast TIM bit set are dropped.
*/
u8 max_num_beacons;
- u8 pad[2];
+ u8 pad[1];
} __packed;

/*
* ACXBeaconFilterEntry (not 221)
* Byte Offset Size (Bytes) Definition
* =========== ============ ==========
@@ -259,20 +275,23 @@ struct acx_beacon_filter_option {
(BEACON_FILTER_TABLE_MAX_VENDOR_SPECIFIC_IE_NUM * \
BEACON_FILTER_TABLE_EXTRA_VENDOR_SPECIFIC_IE_SIZE))

struct acx_beacon_filter_ie_table {
struct acx_header header;

+ u8 role_id;
u8 num_ie;
- u8 pad[3];
+ u8 pad[2];
u8 table[BEACON_FILTER_TABLE_MAX_SIZE];
} __packed;

struct acx_conn_monit_params {
struct acx_header header;

+ u8 role_id;
+ u8 padding[3];
__le32 synch_fail_thold; /* number of beacons missed */
__le32 bss_lose_timeout; /* number of TU's from synch fail */
} __packed;

struct acx_bt_wlan_coex {
struct acx_header header;
@@ -315,21 +334,22 @@ struct acx_energy_detection {
u8 pad;
} __packed;

struct acx_beacon_broadcast {
struct acx_header header;

- __le16 beacon_rx_timeout;
- __le16 broadcast_timeout;
-
+ u8 role_id;
/* Enables receiving of broadcast packets in PS mode */
u8 rx_broadcast_in_ps;

+ __le16 beacon_rx_timeout;
+ __le16 broadcast_timeout;
+
/* Consecutive PS Poll failures before updating the host */
u8 ps_poll_threshold;
- u8 pad[2];
+ u8 pad[1];
} __packed;

struct acx_event_mask {
struct acx_header header;

__le32 event_mask;
@@ -345,39 +365,44 @@ struct acx_event_mask {
#define DF_ENCRYPTION_DISABLE 0x01
#define DF_SNIFF_MODE_ENABLE 0x80

struct acx_feature_config {
struct acx_header header;

+ u8 role_id;
+ u8 padding[3];
__le32 options;
__le32 data_flow_options;
} __packed;

struct acx_current_tx_power {
struct acx_header header;

+ u8 role_id;
u8 current_tx_power;
- u8 padding[3];
+ u8 padding[2];
} __packed;

struct acx_wake_up_condition {
struct acx_header header;

+ u8 role_id;
u8 wake_up_event; /* Only one bit can be set */
u8 listen_interval;
- u8 pad[2];
+ u8 pad[1];
} __packed;

struct acx_aid {
struct acx_header header;

/*
* To be set when associated with an AP.
*/
+ u8 role_id;
+ u8 reserved;
__le16 aid;
- u8 pad[2];
} __packed;

enum acx_preamble_type {
ACX_PREAMBLE_LONG = 0,
ACX_PREAMBLE_SHORT = 1
};
@@ -386,25 +411,27 @@ struct acx_preamble {
struct acx_header header;

/*
* When set, the WiLink transmits the frames with a short preamble and
* when cleared, the WiLink transmits the frames with a long preamble.
*/
+ u8 role_id;
u8 preamble;
- u8 padding[3];
+ u8 padding[2];
} __packed;

enum acx_ctsprotect_type {
CTSPROTECT_DISABLE = 0,
CTSPROTECT_ENABLE = 1
};

struct acx_ctsprotect {
struct acx_header header;
+ u8 role_id;
u8 ctsprotect;
- u8 padding[3];
+ u8 padding[2];
} __packed;

struct acx_tx_statistics {
__le32 internal_desc_overflow;
} __packed;

@@ -633,48 +660,40 @@ struct acx_rate_class {
u8 aflags;
u8 reserved;
};

#define ACX_TX_BASIC_RATE 0
#define ACX_TX_AP_FULL_RATE 1
-#define ACX_TX_RATE_POLICY_CNT 2
-struct acx_sta_rate_policy {
- struct acx_header header;
-
- __le32 rate_class_cnt;
- struct acx_rate_class rate_class[CONF_TX_MAX_RATE_CLASSES];
-} __packed;
-
-
#define ACX_TX_AP_MODE_MGMT_RATE 4
#define ACX_TX_AP_MODE_BCST_RATE 5
-struct acx_ap_rate_policy {
+struct acx_rate_policy {
struct acx_header header;

__le32 rate_policy_idx;
struct acx_rate_class rate_policy;
} __packed;

struct acx_ac_cfg {
struct acx_header header;
+ u8 role_id;
u8 ac;
+ u8 aifsn;
u8 cw_min;
__le16 cw_max;
- u8 aifsn;
- u8 reserved;
__le16 tx_op_limit;
} __packed;

struct acx_tid_config {
struct acx_header header;
+ u8 role_id;
u8 queue_id;
u8 channel_type;
u8 tsid;
u8 ps_scheme;
u8 ack_policy;
- u8 padding[3];
+ u8 padding[2];
__le32 apsd_conf[2];
} __packed;

struct acx_frag_threshold {
struct acx_header header;
__le16 frag_threshold;
@@ -684,25 +703,13 @@ struct acx_frag_threshold {
struct acx_tx_config_options {
struct acx_header header;
__le16 tx_compl_timeout; /* msec */
__le16 tx_compl_threshold; /* number of packets */
} __packed;

-#define ACX_TX_DESCRIPTORS 32
-
-struct wl1271_acx_ap_config_memory {
- struct acx_header header;
-
- u8 rx_mem_block_num;
- u8 tx_min_mem_block_num;
- u8 num_stations;
- u8 num_ssid_profiles;
- __le32 total_tx_descriptors;
-} __packed;
-
-struct wl1271_acx_sta_config_memory {
+struct wl1271_acx_config_memory {
struct acx_header header;

u8 rx_mem_block_num;
u8 tx_min_mem_block_num;
u8 num_stations;
u8 num_ssid_profiles;
@@ -770,30 +777,32 @@ struct wl1271_acx_rx_config_opt {
} __packed;


struct wl1271_acx_bet_enable {
struct acx_header header;

+ u8 role_id;
u8 enable;
u8 max_consecutive;
- u8 padding[2];
+ u8 padding[1];
} __packed;

#define ACX_IPV4_VERSION 4
#define ACX_IPV6_VERSION 6
#define ACX_IPV4_ADDR_SIZE 4

/* bitmap of enabled arp_filter features */
#define ACX_ARP_FILTER_ARP_FILTERING BIT(0)
#define ACX_ARP_FILTER_AUTO_ARP BIT(1)

struct wl1271_acx_arp_filter {
struct acx_header header;
+ u8 role_id;
u8 version; /* ACX_IPV4_VERSION, ACX_IPV6_VERSION */
u8 enable; /* bitmap of enabled ARP filtering features */
- u8 padding[2];
+ u8 padding[1];
u8 address[16]; /* The configured device IP address - all ARP
requests directed to this IP address will pass
through. For IPv4, the first four bytes are
used. */
} __packed;

@@ -805,14 +814,15 @@ struct wl1271_acx_pm_config {
u8 padding[3];
} __packed;

struct wl1271_acx_keep_alive_mode {
struct acx_header header;

+ u8 role_id;
u8 enabled;
- u8 padding[3];
+ u8 padding[2];
} __packed;

enum {
ACX_KEEP_ALIVE_NO_TX = 0,
ACX_KEEP_ALIVE_PERIOD_ONLY
};
@@ -822,17 +832,17 @@ enum {
ACX_KEEP_ALIVE_TPL_VALID
};

struct wl1271_acx_keep_alive_config {
struct acx_header header;

- __le32 period;
+ u8 role_id;
u8 index;
u8 tpl_validation;
u8 trigger;
- u8 padding;
+ __le32 period;
} __packed;

#define HOST_IF_CFG_RX_FIFO_ENABLE BIT(0)
#define HOST_IF_CFG_TX_EXTRA_BLKS_SWAP BIT(1)
#define HOST_IF_CFG_TX_PAD_TO_SDIO_BLK BIT(3)

@@ -870,26 +880,29 @@ enum {
WL1271_ACX_TRIG_COUNT = 8,
};

struct wl1271_acx_rssi_snr_trigger {
struct acx_header header;

- __le16 threshold;
- __le16 pacing; /* 0 - 60000 ms */
+ u8 role_id;
u8 metric;
u8 type;
u8 dir;
+ __le16 threshold;
+ __le16 pacing; /* 0 - 60000 ms */
u8 hysteresis;
u8 index;
u8 enable;
- u8 padding[2];
+ u8 padding[1];
};

struct wl1271_acx_rssi_snr_avg_weights {
struct acx_header header;

+ u8 role_id;
+ u8 padding[3];
u8 rssi_beacon;
u8 rssi_data;
u8 snr_beacon;
u8 snr_data;
};

@@ -913,28 +926,25 @@ struct wl1271_acx_ht_capabilities {
* bit 5 - Allow RD initiation in TXOP. FW is allowed to initate RD.
* Exact policy setting for this feature is TBD.
* Note, this bit can only be set to 1 if bit 3 is set to 1.
*/
__le32 ht_capabilites;

- /*
- * Indicates to which peer these capabilities apply.
- * For infrastructure use ff:ff:ff:ff:ff:ff that indicates relevance
- * for all peers.
- * Only valid for IBSS/DLS operation.
- */
- u8 mac_address[ETH_ALEN];
+ /* Indicates to which link these capabilities apply. */
+ u8 hlid;

/*
* This the maximum A-MPDU length supported by the AP. The FW may not
* exceed this length when sending A-MPDUs
*/
u8 ampdu_max_length;

/* This is the minimal spacing required when sending A-MPDUs to the AP*/
u8 ampdu_min_spacing;
+
+ u8 padding;
} __packed;

/* HT Capabilites Fw Bit Mask Mapping */
#define WL1271_ACX_FW_CAP_HT_OPERATION BIT(0)
#define WL1271_ACX_FW_CAP_GREENFIELD_FRAME_FORMAT BIT(1)
#define WL1271_ACX_FW_CAP_SHORT_GI_FOR_20MHZ_PACKETS BIT(2)
@@ -947,12 +957,14 @@ struct wl1271_acx_ht_capabilities {
* ACX_HT_BSS_OPERATION
* Configure HT capabilities - AP rules for behavior in the BSS.
*/
struct wl1271_acx_ht_information {
struct acx_header header;

+ u8 role_id;
+
/* Values: 0 - RIFS not allowed, 1 - RIFS allowed */
u8 rifs_mode;

/* Values: 0 - 3 like in spec */
u8 ht_protection;

@@ -968,13 +980,13 @@ struct wl1271_acx_ht_information {
* Note: When this value is set to 1 FW will protect all TXOP with RTS
* frame and will not use CTS-to-self regardless of the value of the
* ACX_CTS_PROTECTION information element
*/
u8 dual_cts_protection;

- u8 padding[3];
+ u8 padding[2];
} __packed;

#define RX_BA_WIN_SIZE 8

struct wl1271_acx_ba_session_policy {
struct acx_header header;
@@ -1038,31 +1050,35 @@ struct wl1271_acx_fw_tsf_information {
u8 padding[3];
} __packed;

struct wl1271_acx_ps_rx_streaming {
struct acx_header header;

+ u8 role_id;
u8 tid;
u8 enable;

/* interval between triggers (10-100 msec) */
u8 period;

/* timeout before first trigger (0-200 msec) */
u8 timeout;
+ u8 padding[3];
} __packed;

struct wl1271_acx_ap_max_tx_retry {
struct acx_header header;

+ u8 role_id;
+ u8 padding_1;
+
/*
* the number of frames transmission failures before
* issuing the aging event.
*/
__le16 max_tx_retry;
- u8 padding_1[2];
} __packed;

struct wl1271_acx_config_ps {
struct acx_header header;

u8 exit_retries;
@@ -1148,16 +1164,13 @@ enum {
ACX_WAKE_UP_CONDITIONS = 0x0002,
ACX_MEM_CFG = 0x0003,
ACX_SLOT = 0x0004,
ACX_AC_CFG = 0x0007,
ACX_MEM_MAP = 0x0008,
ACX_AID = 0x000A,
- /* ACX_FW_REV is missing in the ref driver, but seems to work */
- ACX_FW_REV = 0x000D,
ACX_MEDIUM_USAGE = 0x000F,
- ACX_RX_CFG = 0x0010,
ACX_TX_QUEUE_CFG = 0x0011, /* FIXME: only used by wl1251 */
ACX_STATISTICS = 0x0013, /* Debug API */
ACX_PWR_CONSUMPTION_STATISTICS = 0x0014,
ACX_FEATURE_CFG = 0x0015,
ACX_TID_CFG = 0x001A,
ACX_PS_RX_STREAMING = 0x001B,
@@ -1167,13 +1180,12 @@ enum {
ACX_HDK_VERSION = 0x0022, /* ??? */
ACX_PD_THRESHOLD = 0x0023,
ACX_TX_CONFIG_OPT = 0x0024,
ACX_CCA_THRESHOLD = 0x0025,
ACX_EVENT_MBOX_MASK = 0x0026,
ACX_CONN_MONIT_PARAMS = 0x002D,
- ACX_CONS_TX_FAILURE = 0x002F,
ACX_BCN_DTIM_OPTIONS = 0x0031,
ACX_SG_ENABLE = 0x0032,
ACX_SG_CFG = 0x0033,
ACX_FM_COEX_CFG = 0x0034,
ACX_BEACON_FILTER_TABLE = 0x0038,
ACX_ARP_IP_FILTER = 0x0039,
@@ -1199,12 +1211,16 @@ enum {
ACX_SET_KEEP_ALIVE_CONFIG = 0x0054,
ACX_BA_SESSION_POLICY_CFG = 0x0055,
ACX_BA_SESSION_RX_SETUP = 0x0056,
ACX_PEER_HT_CAP = 0x0057,
ACX_HT_BSS_OPERATION = 0x0058,
ACX_COEX_ACTIVITY = 0x0059,
+ ACX_BURST_MODE = 0x005C,
+
+ ACX_SET_RATE_MAMAGEMENT_PARAMS = 0x005D,
+ ACX_SET_RATE_ADAPT_PARAMS = 0x0060,
ACX_SET_DCO_ITRIM_PARAMS = 0x0061,
ACX_GEN_FW_CMD = 0x0070,
ACX_HOST_IF_CFG_BITMAP = 0x0071,
ACX_MAX_TX_FAILURE = 0x0072,
ACX_UPDATE_INCONNECTION_STA_LIST = 0x0073,
DOT11_RX_MSDU_LIFE_TIME = 0x1004,
@@ -1253,14 +1269,13 @@ int wl1271_acx_ac_cfg(struct wl1271 *wl, u8 ac, u8 cw_min, u16 cw_max,
u8 aifsn, u16 txop);
int wl1271_acx_tid_cfg(struct wl1271 *wl, u8 queue_id, u8 channel_type,
u8 tsid, u8 ps_scheme, u8 ack_policy,
u32 apsd_conf0, u32 apsd_conf1);
int wl1271_acx_frag_threshold(struct wl1271 *wl, u32 frag_threshold);
int wl1271_acx_tx_config_options(struct wl1271 *wl);
-int wl1271_acx_ap_mem_cfg(struct wl1271 *wl);
-int wl1271_acx_sta_mem_cfg(struct wl1271 *wl);
+int wl1271_acx_mem_cfg(struct wl1271 *wl);
int wl1271_acx_init_mem_config(struct wl1271 *wl);
int wl1271_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap);
int wl1271_acx_init_rx_interrupt(struct wl1271 *wl);
int wl1271_acx_smart_reflex(struct wl1271 *wl);
int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable);
int wl1271_acx_arp_ip_filter(struct wl1271 *wl, u8 enable, __be32 address);
diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c
index 7aa8fc7..a02bfbb 100644
--- a/drivers/net/wireless/wl12xx/init.c
+++ b/drivers/net/wireless/wl12xx/init.c
@@ -385,13 +385,13 @@ static int wl1271_sta_hw_init(struct wl1271 *wl)
return ret;

ret = wl1271_acx_sta_rate_policies(wl);
if (ret < 0)
return ret;

- ret = wl1271_acx_sta_mem_cfg(wl);
+ ret = wl1271_acx_mem_cfg(wl);
if (ret < 0)
return ret;

/* Configure the FW logger */
ret = wl12xx_init_fwlog(wl);
if (ret < 0)
@@ -444,13 +444,13 @@ static int wl1271_ap_hw_init(struct wl1271 *wl)
return ret;

ret = wl1271_acx_ap_max_tx_retry(wl);
if (ret < 0)
return ret;

- ret = wl1271_acx_ap_mem_cfg(wl);
+ ret = wl1271_acx_mem_cfg(wl);
if (ret < 0)
return ret;

/* initialize Tx power */
ret = wl1271_acx_tx_power(wl, wl->power_level);
if (ret < 0)
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index 1ac1762..0ee98e0 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -715,13 +715,13 @@ static int wl1271_plt_init(struct wl1271 *wl)

/* Energy detection */
ret = wl1271_init_energy_detection(wl);
if (ret < 0)
goto out_free_memmap;

- ret = wl1271_acx_sta_mem_cfg(wl);
+ ret = wl1271_acx_mem_cfg(wl);
if (ret < 0)
goto out_free_memmap;

/* Default fragmentation threshold */
ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
if (ret < 0)
@@ -1972,12 +1972,13 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
wl->vif = NULL;
wl1271_free_ap_keys(wl);
memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
wl->ap_fw_ps_map = 0;
wl->ap_ps_map = 0;
wl->sched_scanning = false;
+ wl->role_id = WL1271_INVALID_ROLE_ID;

/*
* this is performed after the cancel_work calls and the associated
* mutex_lock, so that wl1271_op_add_interface does not accidentally
* get executed before all these vars have been reset.
*/
@@ -4308,12 +4309,14 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
wl->ap_fw_ps_map = 0;
wl->quirks = 0;
wl->platform_quirks = 0;
wl->sched_scanning = false;
wl->tx_security_seq = 0;
wl->tx_security_last_seq_lsb = 0;
+ wl->role_id = WL1271_INVALID_ROLE_ID;
+ wl->sta_hlid = WL1271_INVALID_LINK_ID;

setup_timer(&wl->rx_streaming_timer, wl1271_rx_streaming_timer,
(unsigned long) wl);
wl->fwlog_size = 0;
init_waitqueue_head(&wl->fwlog_waitq);

diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index 260b78c..4e4bafc 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -135,12 +135,14 @@ extern u32 wl12xx_debug_level;
#define WL1271_ELP_HW_STATE_IRQ 1

#define WL1271_DEFAULT_BEACON_INT 100
#define WL1271_DEFAULT_DTIM_PERIOD 1

#define WL1271_MAX_LINKS 8
+#define WL1271_INVALID_ROLE_ID 0xff
+#define WL1271_INVALID_LINK_ID 0xff
#define WL1271_AP_GLOBAL_HLID 0
#define WL1271_AP_BROADCAST_HLID 1
#define WL1271_AP_STA_HLID_START 2

/*
* When in AP-mode, we allow (at least) this number of mem-blocks
@@ -387,12 +389,14 @@ struct wl1271 {
u8 mac_addr[ETH_ALEN];
u8 bss_type;
u8 set_bss_type;
u8 ssid[IW_ESSID_MAX_SIZE + 1];
u8 ssid_len;
int channel;
+ u8 role_id;
+ u8 sta_hlid;

struct wl1271_acx_mem_map *target_mem_map;

/* Accounting for allocated / available TX blocks on HW */
u32 tx_blocks_freed;
u32 tx_blocks_available;
--
1.7.6.401.g6a319


2011-08-09 09:13:53

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 11/40] wl12xx: wl12xx-fw-3 - update scan cmd api

Update the scan command to use the new fw api.

Signed-off-by: Eliad Peller <[email protected]>
---
drivers/net/wireless/wl12xx/scan.c | 8 +++++++-
drivers/net/wireless/wl12xx/scan.h | 25 ++++++++++++++++---------
2 files changed, 23 insertions(+), 10 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/scan.c b/drivers/net/wireless/wl12xx/scan.c
index 78a9b23..b34034c 100644
--- a/drivers/net/wireless/wl12xx/scan.c
+++ b/drivers/net/wireless/wl12xx/scan.c
@@ -153,24 +153,28 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band,
scan_options = WL1271_SCAN_OPT_PRIORITY_HIGH;

/* No SSIDs means that we have a forced passive scan */
if (passive || wl->scan.req->n_ssids == 0)
scan_options |= WL1271_SCAN_OPT_PASSIVE;

+ if (WARN_ON(wl->role_id == WL1271_INVALID_ROLE_ID)) {
+ ret = -EINVAL;
+ goto out;
+ }
+ cmd->params.role_id = wl->role_id;
cmd->params.scan_options = cpu_to_le16(scan_options);

cmd->params.n_ch = wl1271_get_scan_channels(wl, wl->scan.req,
cmd->channels,
band, passive);
if (cmd->params.n_ch == 0) {
ret = WL1271_NOTHING_TO_SCAN;
goto out;
}

cmd->params.tx_rate = cpu_to_le32(basic_rate);
-
cmd->params.n_probe_reqs = wl->conf.scan.num_probe_reqs;
cmd->params.tx_rate = cpu_to_le32(basic_rate);
cmd->params.tid_trigger = 0;
cmd->params.scan_tag = WL1271_SCAN_DEFAULT_TAG;

if (band == IEEE80211_BAND_2GHZ)
@@ -180,12 +184,14 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band,

if (wl->scan.ssid_len && wl->scan.ssid) {
cmd->params.ssid_len = wl->scan.ssid_len;
memcpy(cmd->params.ssid, wl->scan.ssid, wl->scan.ssid_len);
}

+ memcpy(cmd->addr, wl->mac_addr, ETH_ALEN);
+
ret = wl1271_cmd_build_probe_req(wl, wl->scan.ssid, wl->scan.ssid_len,
wl->scan.req->ie, wl->scan.req->ie_len,
band);
if (ret < 0) {
wl1271_error("PROBE request template failed");
goto out;
diff --git a/drivers/net/wireless/wl12xx/scan.h b/drivers/net/wireless/wl12xx/scan.h
index d882e4d..65930a8 100644
--- a/drivers/net/wireless/wl12xx/scan.h
+++ b/drivers/net/wireless/wl12xx/scan.h
@@ -43,13 +43,16 @@ void wl1271_scan_sched_scan_results(struct wl1271 *wl);

#define WL1271_SCAN_MAX_CHANNELS 24
#define WL1271_SCAN_DEFAULT_TAG 1
#define WL1271_SCAN_CURRENT_TX_PWR 0
#define WL1271_SCAN_OPT_ACTIVE 0
#define WL1271_SCAN_OPT_PASSIVE 1
+#define WL1271_SCAN_OPT_TRIGGERED_SCAN 2
#define WL1271_SCAN_OPT_PRIORITY_HIGH 4
+/* scan even if we fail to enter psm */
+#define WL1271_SCAN_OPT_FORCE 8
#define WL1271_SCAN_BAND_2_4_GHZ 0
#define WL1271_SCAN_BAND_5_GHZ 1

#define WL1271_SCAN_TIMEOUT 10000 /* msec */

enum {
@@ -59,33 +62,33 @@ enum {
WL1271_SCAN_STATE_5GHZ_ACTIVE,
WL1271_SCAN_STATE_5GHZ_PASSIVE,
WL1271_SCAN_STATE_DONE
};

struct basic_scan_params {
- __le32 rx_config_options;
- __le32 rx_filter_options;
/* Scan option flags (WL1271_SCAN_OPT_*) */
__le16 scan_options;
+ u8 role_id;
/* Number of scan channels in the list (maximum 30) */
u8 n_ch;
/* This field indicates the number of probe requests to send
per channel for an active scan */
u8 n_probe_reqs;
- /* Rate bit field for sending the probes */
- __le32 tx_rate;
u8 tid_trigger;
u8 ssid_len;
- /* in order to align */
- u8 padding1[2];
+ u8 use_ssid_list;
+
+ /* Rate bit field for sending the probes */
+ __le32 tx_rate;
+
u8 ssid[IW_ESSID_MAX_SIZE];
/* Band to scan */
u8 band;
- u8 use_ssid_list;
+
u8 scan_tag;
- u8 padding2;
+ u8 padding2[2];
} __packed;

struct basic_scan_channel_params {
/* Duration in TU to wait for frames on a channel for active scan */
__le32 min_duration;
__le32 max_duration;
@@ -102,12 +105,16 @@ struct basic_scan_channel_params {

struct wl1271_cmd_scan {
struct wl1271_cmd_header header;

struct basic_scan_params params;
struct basic_scan_channel_params channels[WL1271_SCAN_MAX_CHANNELS];
+
+ /* src mac address */
+ u8 addr[ETH_ALEN];
+ u8 padding[2];
} __packed;

struct wl1271_cmd_trigger_scan_to {
struct wl1271_cmd_header header;

__le32 timeout;
@@ -181,13 +188,13 @@ struct wl1271_cmd_sched_scan_config {
struct conn_scan_ch_params channels_2[MAX_CHANNELS_2GHZ];
struct conn_scan_ch_params channels_5[MAX_CHANNELS_5GHZ];
struct conn_scan_ch_params channels_4[MAX_CHANNELS_4GHZ];
} __packed;


-#define SCHED_SCAN_MAX_SSIDS 8
+#define SCHED_SCAN_MAX_SSIDS 16

enum {
SCAN_SSID_TYPE_PUBLIC = 0,
SCAN_SSID_TYPE_HIDDEN = 1,
};

--
1.7.6.401.g6a319


2011-08-09 09:14:24

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 28/40] wl12xx: AP-mode - set STA HT capabilities when adding a STA

From: Arik Nemtsov <[email protected]>

In addition, set global HT operation mode via ACX_HT_BSS_OPERATION when
a change is detected by usermode

Signed-off-by: Arik Nemtsov <[email protected]>
Signed-off-by: Eliad Peller <[email protected]>
---
drivers/net/wireless/wl12xx/acx.c | 10 ++++++----
drivers/net/wireless/wl12xx/acx.h | 2 +-
drivers/net/wireless/wl12xx/main.c | 34 +++++++++++++++++++++++++++-------
3 files changed, 34 insertions(+), 12 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c
index 02b9c7e..6a52400 100644
--- a/drivers/net/wireless/wl12xx/acx.c
+++ b/drivers/net/wireless/wl12xx/acx.c
@@ -1306,27 +1306,29 @@ out:
kfree(acx);
return ret;
}

int wl1271_acx_set_ht_capabilities(struct wl1271 *wl,
struct ieee80211_sta_ht_cap *ht_cap,
- bool allow_ht_operation)
+ bool allow_ht_operation, u8 hlid)
{
struct wl1271_acx_ht_capabilities *acx;
int ret = 0;
u32 ht_capabilites = 0;

- wl1271_debug(DEBUG_ACX, "acx ht capabilities setting");
+ wl1271_debug(DEBUG_ACX, "acx ht capabilities setting "
+ "sta supp: %d sta cap: %d", ht_cap->ht_supported,
+ ht_cap->cap);

acx = kzalloc(sizeof(*acx), GFP_KERNEL);
if (!acx) {
ret = -ENOMEM;
goto out;
}

- if (allow_ht_operation) {
+ if (allow_ht_operation && ht_cap->ht_supported) {
/* no need to translate capabilities - use the spec values */
ht_capabilites = ht_cap->cap;

/*
* this bit is not employed by the spec but only by FW to
* indicate peer HT support
@@ -1335,13 +1337,13 @@ int wl1271_acx_set_ht_capabilities(struct wl1271 *wl,

/* get data from A-MPDU parameters field */
acx->ampdu_max_length = ht_cap->ampdu_factor;
acx->ampdu_min_spacing = ht_cap->ampdu_density;
}

- acx->hlid = wl->sta_hlid;
+ acx->hlid = hlid;
acx->ht_capabilites = cpu_to_le32(ht_capabilites);

ret = wl1271_cmd_configure(wl, ACX_PEER_HT_CAP, acx, sizeof(*acx));
if (ret < 0) {
wl1271_warning("acx ht capabilities setting failed: %d", ret);
goto out;
diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h
index ba70f38..943b4d8 100644
--- a/drivers/net/wireless/wl12xx/acx.h
+++ b/drivers/net/wireless/wl12xx/acx.h
@@ -1268,13 +1268,13 @@ int wl1271_acx_keep_alive_mode(struct wl1271 *wl, bool enable);
int wl1271_acx_keep_alive_config(struct wl1271 *wl, u8 index, u8 tpl_valid);
int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, bool enable,
s16 thold, u8 hyst);
int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl);
int wl1271_acx_set_ht_capabilities(struct wl1271 *wl,
struct ieee80211_sta_ht_cap *ht_cap,
- bool allow_ht_operation);
+ bool allow_ht_operation, u8 hlid);
int wl1271_acx_set_ht_information(struct wl1271 *wl,
u16 ht_operation_mode);
int wl1271_acx_set_ba_initiator_policy(struct wl1271 *wl);
int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index,
u16 ssn, bool enable, u8 peer_hlid);
int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime);
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index d81a735..5d5ace8 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -3089,12 +3089,24 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
}
}

ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
if (ret < 0)
goto out;
+
+ /* Handle HT information change */
+ if ((changed & BSS_CHANGED_HT) &&
+ (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
+ ret = wl1271_acx_set_ht_information(wl,
+ bss_conf->ht_operation_mode);
+ if (ret < 0) {
+ wl1271_warning("Set ht information failed %d", ret);
+ goto out;
+ }
+ }
+
out:
return;
}

/* STA/IBSS mode changes */
static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
@@ -3404,38 +3416,42 @@ sta_not_found:
ret = wl1271_cmd_role_stop_dev(wl);
if (ret < 0)
goto out;
}
}

- /* Handle new association with HT. Do this only after join. */
+ /* Handle new association with HT. Do this after join. */
if (sta_exists) {
if ((changed & BSS_CHANGED_HT) &&
(bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
- ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
- true);
+ ret = wl1271_acx_set_ht_capabilities(wl,
+ &sta_ht_cap,
+ true,
+ wl->sta_hlid);
if (ret < 0) {
wl1271_warning("Set ht cap true failed %d",
ret);
goto out;
}
}
/* handle new association without HT and disassociation */
else if (changed & BSS_CHANGED_ASSOC) {
- ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
- false);
+ ret = wl1271_acx_set_ht_capabilities(wl,
+ &sta_ht_cap,
+ false,
+ wl->sta_hlid);
if (ret < 0) {
wl1271_warning("Set ht cap false failed %d",
ret);
goto out;
}
}
}

- /* Handle HT information change. Only after join. */
- if (sta_exists && (changed & BSS_CHANGED_HT) &&
+ /* Handle HT information change. Done after join. */
+ if ((changed & BSS_CHANGED_HT) &&
(bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
ret = wl1271_acx_set_ht_information(wl,
bss_conf->ht_operation_mode);
if (ret < 0) {
wl1271_warning("Set ht information failed %d", ret);
goto out;
@@ -3668,12 +3684,16 @@ static int wl1271_op_sta_add(struct ieee80211_hw *hw,
goto out_sleep;

ret = wl1271_cmd_set_peer_state(wl, hlid);
if (ret < 0)
goto out_sleep;

+ ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid);
+ if (ret < 0)
+ goto out_sleep;
+
out_sleep:
wl1271_ps_elp_sleep(wl);

out_free_sta:
if (ret < 0)
wl1271_free_sta(wl, hlid);
--
1.7.6.401.g6a319


2011-08-11 11:38:45

by Luciano Coelho

[permalink] [raw]
Subject: Re: [PATCH 34/40] wl12xx: schedule TX packets according to FW packet occupancy

On Tue, 2011-08-09 at 12:13 +0300, Eliad Peller wrote:
> +static struct sk_buff_head *wl1271_select_queue(struct wl1271 *wl,
> + struct sk_buff_head *queues)
> +{
> + int i, q = -1;
> + u32 min_pkts = 0xffffffff;
> +
> + /*
> + * Find a non-empty ac where:
> + * 1. There are packets to transmit
> + * 2. The FW has the least allocated blocks
> + */
> + for (i = 0; i < NUM_TX_QUEUES; i++)
> + if (!skb_queue_empty(&queues[i]) &&
> + (wl->tx_allocated_pkts[i] < min_pkts)) {
> + q = i;
> + min_pkts = wl->tx_allocated_pkts[q];
> + }
> +
> + if (q == -1)
> + return NULL;
> +
> + return &queues[q];
> +}

This is a nice algorithm, but now, if all queues have the same number of
allocated packets in the FW, we'll start with BE, because the enum is
like this:

enum conf_tx_ac {
CONF_TX_AC_BE = 0, /* best effort / legacy */
CONF_TX_AC_BK = 1, /* background */
CONF_TX_AC_VI = 2, /* video */
CONF_TX_AC_VO = 3, /* voice */
CONF_TX_AC_CTS2SELF = 4, /* fictitious AC, follows AC_VO */
CONF_TX_AC_ANY_TID = 0x1f
};

...and you select the first queue in case two or more are similarly
full.

Maybe you could make the for loop go backwards instead? Or changing the
< to <= in the comparison would also work.

Another option would be to fix the enum so that it goes from higher prio
to lower prio. If the firmware doesn't care about the actual order of
the queues and actually respects our ac_conf, this would probably be the
best solution, because we could even get rid of wl1271_tx_get_queue()
and wl1271_tx_get_mac80211_queue().

Now something else came to my mind. Could it also happen that the other
queues would still be starved? Let's say we keep getting packets
continuously for the first queue we choose exactly at the interval it
takes the FW to empty that queue. Meanwhile, we're getting some packets
for other queues. In this case, we would keep selecting the same AC
because all the queues would be empty and we would keep choosing the
first one.

Maybe we should still once in a while check the other queues?

Or am I missing something again?

--
Cheers,
Luca.


2011-08-09 09:14:35

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 34/40] wl12xx: schedule TX packets according to FW packet occupancy

From: Arik Nemtsov <[email protected]>

When selecting packets for transmission, prefer the ACs that are least
occupied in the FW. When packets for multiple ACs are present in the FW,
it decides which to transmit according to WMM QoS parameters.

With these changes, lower priority ACs should not be starved when higher
priority traffic is present.

Signed-off-by: Arik Nemtsov <[email protected]>
Signed-off-by: Eliad Peller <[email protected]>
---
drivers/net/wireless/wl12xx/debugfs.c | 4 ++
drivers/net/wireless/wl12xx/main.c | 7 ++-
drivers/net/wireless/wl12xx/tx.c | 67 +++++++++++++++++++++-----------
drivers/net/wireless/wl12xx/wl12xx.h | 2 +-
4 files changed, 53 insertions(+), 27 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c
index 3102652..d59354f 100644
--- a/drivers/net/wireless/wl12xx/debugfs.c
+++ b/drivers/net/wireless/wl12xx/debugfs.c
@@ -337,12 +337,16 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf,
#define DRIVER_STATE_PRINT_STR(x) DRIVER_STATE_PRINT(x, "%s")
#define DRIVER_STATE_PRINT_LHEX(x) DRIVER_STATE_PRINT(x, "0x%lx")
#define DRIVER_STATE_PRINT_HEX(x) DRIVER_STATE_PRINT(x, "0x%x")

DRIVER_STATE_PRINT_INT(tx_blocks_available);
DRIVER_STATE_PRINT_INT(tx_allocated_blocks);
+ DRIVER_STATE_PRINT_INT(tx_allocated_pkts[0]);
+ DRIVER_STATE_PRINT_INT(tx_allocated_pkts[1]);
+ DRIVER_STATE_PRINT_INT(tx_allocated_pkts[2]);
+ DRIVER_STATE_PRINT_INT(tx_allocated_pkts[3]);
DRIVER_STATE_PRINT_INT(tx_frames_cnt);
DRIVER_STATE_PRINT_LHEX(tx_frames_map[0]);
DRIVER_STATE_PRINT_INT(tx_queue_count[0]);
DRIVER_STATE_PRINT_INT(tx_queue_count[1]);
DRIVER_STATE_PRINT_INT(tx_queue_count[2]);
DRIVER_STATE_PRINT_INT(tx_queue_count[3]);
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index 3bfd772..755415a 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -823,13 +823,13 @@ static void wl1271_fw_status(struct wl1271 *wl,
status->fw_rx_counter,
status->drv_rx_counter,
status->tx_results_counter);

for (i = 0; i < NUM_TX_QUEUES; i++) {
/* prevent wrap-around in freed-packets counter */
- wl->tx_allocated_pkts -=
+ wl->tx_allocated_pkts[i] -=
(status->tx_released_pkts[i] -
wl->tx_pkts_freed[i] + 256) % 256;

wl->tx_pkts_freed[i] = status->tx_released_pkts[i];
}

@@ -2037,15 +2037,16 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
* get executed before all these vars have been reset.
*/
wl->flags = 0;

wl->tx_blocks_freed = 0;

- wl->tx_allocated_pkts = 0;
- for (i = 0; i < NUM_TX_QUEUES; i++)
+ for (i = 0; i < NUM_TX_QUEUES; i++) {
wl->tx_pkts_freed[i] = 0;
+ wl->tx_allocated_pkts[i] = 0;
+ }

wl1271_debugfs_reset(wl);

kfree(wl->fw_status);
wl->fw_status = NULL;
kfree(wl->tx_res_if);
diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c
index 4a40bc4..d184da1 100644
--- a/drivers/net/wireless/wl12xx/tx.c
+++ b/drivers/net/wireless/wl12xx/tx.c
@@ -182,13 +182,13 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
u32 buf_offset, u8 hlid)
{
struct wl1271_tx_hw_descr *desc;
u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra;
u32 len;
u32 total_blocks;
- int id, ret = -EBUSY;
+ int id, ret = -EBUSY, ac;

/* we use 1 spare block */
u32 spare_blocks = 1;

if (buf_offset + total_len > WL1271_AGGR_BUFFER_SIZE)
return -EAGAIN;
@@ -219,13 +219,14 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,

desc->id = id;

wl->tx_blocks_available -= total_blocks;
wl->tx_allocated_blocks += total_blocks;

- wl->tx_allocated_pkts++;
+ ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
+ wl->tx_allocated_pkts[ac]++;

if (wl->bss_type == BSS_TYPE_AP_BSS)
wl->links[hlid].allocated_blks += total_blocks;

ret = 0;

@@ -477,27 +478,47 @@ void wl1271_handle_tx_low_watermark(struct wl1271 *wl)
clear_bit(i, &wl->stopped_queues_map);
spin_unlock_irqrestore(&wl->wl_lock, flags);
}
}
}

+static struct sk_buff_head *wl1271_select_queue(struct wl1271 *wl,
+ struct sk_buff_head *queues)
+{
+ int i, q = -1;
+ u32 min_pkts = 0xffffffff;
+
+ /*
+ * Find a non-empty ac where:
+ * 1. There are packets to transmit
+ * 2. The FW has the least allocated blocks
+ */
+ for (i = 0; i < NUM_TX_QUEUES; i++)
+ if (!skb_queue_empty(&queues[i]) &&
+ (wl->tx_allocated_pkts[i] < min_pkts)) {
+ q = i;
+ min_pkts = wl->tx_allocated_pkts[q];
+ }
+
+ if (q == -1)
+ return NULL;
+
+ return &queues[q];
+}
+
static struct sk_buff *wl1271_sta_skb_dequeue(struct wl1271 *wl)
{
struct sk_buff *skb = NULL;
unsigned long flags;
+ struct sk_buff_head *queue;

- skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_VO]);
- if (skb)
- goto out;
- skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_VI]);
- if (skb)
+ queue = wl1271_select_queue(wl, wl->tx_queue);
+ if (!queue)
goto out;
- skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_BE]);
- if (skb)
- goto out;
- skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_BK]);
+
+ skb = skb_dequeue(queue);

out:
if (skb) {
int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
spin_lock_irqsave(&wl->wl_lock, flags);
wl->tx_queue_count[q]--;
@@ -509,35 +530,35 @@ out:

static struct sk_buff *wl1271_ap_skb_dequeue(struct wl1271 *wl)
{
struct sk_buff *skb = NULL;
unsigned long flags;
int i, h, start_hlid;
+ struct sk_buff_head *queue;

/* start from the link after the last one */
start_hlid = (wl->last_tx_hlid + 1) % AP_MAX_LINKS;

/* dequeue according to AC, round robin on each link */
for (i = 0; i < AP_MAX_LINKS; i++) {
h = (start_hlid + i) % AP_MAX_LINKS;

- skb = skb_dequeue(&wl->links[h].tx_queue[CONF_TX_AC_VO]);
- if (skb)
- goto out;
- skb = skb_dequeue(&wl->links[h].tx_queue[CONF_TX_AC_VI]);
- if (skb)
- goto out;
- skb = skb_dequeue(&wl->links[h].tx_queue[CONF_TX_AC_BE]);
- if (skb)
- goto out;
- skb = skb_dequeue(&wl->links[h].tx_queue[CONF_TX_AC_BK]);
+ /* only consider connected stations */
+ if (h >= WL1271_AP_STA_HLID_START &&
+ !test_bit(h - WL1271_AP_STA_HLID_START, wl->ap_hlid_map))
+ continue;
+
+ queue = wl1271_select_queue(wl, wl->links[h].tx_queue);
+ if (!queue)
+ continue;
+
+ skb = skb_dequeue(queue);
if (skb)
- goto out;
+ break;
}

-out:
if (skb) {
int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
wl->last_tx_hlid = h;
spin_lock_irqsave(&wl->wl_lock, flags);
wl->tx_queue_count[q]--;
spin_unlock_irqrestore(&wl->wl_lock, flags);
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index 3e2e0b3..c3996b2 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -422,13 +422,13 @@ struct wl1271 {
u32 tx_blocks_available;
u32 tx_allocated_blocks;
u32 tx_results_count;

/* Accounting for allocated / available Tx packets in HW */
u32 tx_pkts_freed[NUM_TX_QUEUES];
- u32 tx_allocated_pkts;
+ u32 tx_allocated_pkts[NUM_TX_QUEUES];

/* Transmitted TX packets counter for chipset interface */
u32 tx_packets_count;

/* Time-offset between host and chipset clocks */
s64 time_offset;
--
1.7.6.401.g6a319


2011-08-09 09:14:06

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 18/40] wl12xx: replace dummy_join with ROC/CROC commands

The ROC command asks the fw stay on the channel of the given
hlid. it currently has 2 primary functions:

1. Allow tx/rx from the device role.

In order to tx/rx packets while the stations is not associated
(e.g. auth req/resp), the device role has to be used, along
with ROC on its link.

Keep the logic similiar to the one used in dummy_join. However,
since we can't scan while we ROC, we add CROC before starting
a scan, and ROC again (if needed) on scan complete.

2. Keeping the antenna for a specific link.

We ROC until the connection was completed (after EAPOLs exchange)
in order to prevent BT coex operations from taking the antenna
and failing the connection (after this stage, psm can be used).

During association, we ROC on the station role, and then CROC
the device role, thus assuring being ROC during all the connection
process.

Replace the WL1271_FLAG_JOINED with a new WL1271_FLAG_ROC,
indicating the fw was configured to ROC. Add a roc bitmap
to indicate what roles are currently ROCed.

Add wl1271_roc/croc functions in order to wrap the roc/croc
commands while taking care of the roc bitmap.

The current ROC/CROC state-machine is a bit complicated. In
the future we'll probably want to use wpa_supplicant to control
the ROC during connection.

Signed-off-by: Eliad Peller <[email protected]>
---
drivers/net/wireless/wl12xx/cmd.c | 56 +++++++++++++-
drivers/net/wireless/wl12xx/cmd.h | 9 ++
drivers/net/wireless/wl12xx/main.c | 137 +++++++++++++++++++++++++---------
drivers/net/wireless/wl12xx/scan.c | 20 ++++--
drivers/net/wireless/wl12xx/tx.c | 13 +++
drivers/net/wireless/wl12xx/wl12xx.h | 3 +-
6 files changed, 192 insertions(+), 46 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c
index 3091351..918c46b 100644
--- a/drivers/net/wireless/wl12xx/cmd.c
+++ b/drivers/net/wireless/wl12xx/cmd.c
@@ -1484,13 +1484,13 @@ out:

static int wl1271_cmd_roc(struct wl1271 *wl, u8 role_id)
{
struct wl1271_cmd_roc *cmd;
int ret = 0;

- wl1271_debug(DEBUG_CMD, "cmd roc %d (%d)", wl->channel, wl->band);
+ wl1271_debug(DEBUG_CMD, "cmd roc %d (%d)", wl->channel, role_id);

if (WARN_ON(role_id == WL1271_INVALID_ROLE_ID))
return -EINVAL;

cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
@@ -1526,22 +1526,23 @@ out_free:
out:
return ret;
}

static int wl1271_cmd_croc(struct wl1271 *wl, u8 role_id)
{
- struct wl1271_cmd_header *cmd;
+ struct wl1271_cmd_croc *cmd;
int ret = 0;

- wl1271_debug(DEBUG_CMD, "cmd croc");
+ wl1271_debug(DEBUG_CMD, "cmd croc (%d)", role_id);

cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
ret = -ENOMEM;
goto out;
}
+ cmd->role_id = role_id;

ret = wl1271_cmd_send(wl, CMD_CANCEL_REMAIN_ON_CHANNEL, cmd,
sizeof(*cmd), 0);
if (ret < 0) {
wl1271_error("failed to send ROC command");
goto out_free;
@@ -1550,6 +1551,55 @@ static int wl1271_cmd_croc(struct wl1271 *wl, u8 role_id)
out_free:
kfree(cmd);

out:
return ret;
}
+
+int wl1271_roc(struct wl1271 *wl, u8 role_id)
+{
+ int ret = 0;
+
+ if (WARN_ON(test_bit(role_id, wl->roc_map)))
+ return 0;
+
+ ret = wl1271_cmd_roc(wl, role_id);
+ if (ret < 0)
+ goto out;
+
+ ret = wl1271_cmd_wait_for_event(wl,
+ REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID);
+ if (ret < 0) {
+ wl1271_error("cmd roc event completion error");
+ goto out;
+ }
+
+ __set_bit(role_id, wl->roc_map);
+ set_bit(WL1271_FLAG_ROC, &wl->flags);
+
+out:
+ return ret;
+}
+
+int wl1271_croc(struct wl1271 *wl, u8 role_id)
+{
+ int ret = 0;
+ u8 roc_role;
+
+ if (WARN_ON(!test_bit(WL1271_FLAG_ROC, &wl->flags)))
+ return 0;
+
+ if (WARN_ON(!test_bit(role_id, wl->roc_map)))
+ return 0;
+
+ ret = wl1271_cmd_croc(wl, role_id);
+ if (ret < 0)
+ goto out;
+
+ __clear_bit(role_id, wl->roc_map);
+ roc_role = find_first_bit(wl->roc_map, WL1271_MAX_ROLES);
+ if (roc_role >= WL1271_MAX_ROLES)
+ clear_bit(WL1271_FLAG_ROC, &wl->flags);
+
+out:
+ return ret;
+}
diff --git a/drivers/net/wireless/wl12xx/cmd.h b/drivers/net/wireless/wl12xx/cmd.h
index 0ba4537..bb727d7 100644
--- a/drivers/net/wireless/wl12xx/cmd.h
+++ b/drivers/net/wireless/wl12xx/cmd.h
@@ -68,12 +68,14 @@ int wl1271_cmd_set_sta_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
u8 key_size, const u8 *key, const u8 *addr,
u32 tx_seq_32, u16 tx_seq_16);
int wl1271_cmd_set_ap_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
u16 tx_seq_16);
int wl1271_cmd_set_peer_state(struct wl1271 *wl);
+int wl1271_roc(struct wl1271 *wl, u8 role_id);
+int wl1271_croc(struct wl1271 *wl, u8 role_id);
int wl1271_cmd_add_peer(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid);
int wl1271_cmd_remove_peer(struct wl1271 *wl, u8 hlid);
int wl12xx_cmd_config_fwlog(struct wl1271 *wl);
int wl12xx_cmd_start_fwlog(struct wl1271 *wl);
int wl12xx_cmd_stop_fwlog(struct wl1271 *wl);

@@ -579,12 +581,19 @@ struct wl1271_cmd_roc {
u8 role_id;
u8 channel;
u8 band;
u8 padding;
};

+struct wl1271_cmd_croc {
+ struct wl1271_cmd_header header;
+
+ u8 role_id;
+ u8 padding[3];
+};
+
enum wl1271_ssid_type {
WL1271_SSID_TYPE_PUBLIC = 0,
WL1271_SSID_TYPE_HIDDEN = 1,
WL1271_SSID_TYPE_ANY = 2,
};

diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index 11909bb..fda2531 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -437,12 +437,14 @@ static int wl1271_check_operstate(struct wl1271 *wl, unsigned char operstate)
return 0;

ret = wl1271_cmd_set_peer_state(wl);
if (ret < 0)
return ret;

+ wl1271_croc(wl, wl->role_id);
+
wl1271_info("Association completed.");
return 0;
}
static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
void *arg)
{
@@ -2046,12 +2048,13 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
wl->ap_ps_map = 0;
wl->sched_scanning = false;
wl->role_id = WL1271_INVALID_ROLE_ID;
wl->dev_role_id = WL1271_INVALID_ROLE_ID;
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));

/* The system link is always allocated */
__set_bit(WL1271_SYSTEM_HLID, wl->links_map);

/*
* this is performed after the cancel_work calls and the associated
@@ -2088,31 +2091,12 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
}

mutex_unlock(&wl->mutex);
cancel_work_sync(&wl->recovery_work);
}

-static int wl1271_dummy_join(struct wl1271 *wl)
-{
- int ret = 0;
- /* we need to use a dummy BSSID for now */
- static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
- 0xad, 0xbe, 0xef };
-
- memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
-
- ret = wl1271_cmd_role_start_sta(wl);
- if (ret < 0)
- goto out;
-
- set_bit(WL1271_FLAG_JOINED, &wl->flags);
-
-out:
- return ret;
-}
-
static int wl1271_join(struct wl1271 *wl, bool set_assoc)
{
int ret;

/*
* One of the side effects of the JOIN command is that is clears
@@ -2130,14 +2114,12 @@ static int wl1271_join(struct wl1271 *wl, bool set_assoc)
set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);

ret = wl1271_cmd_role_start_sta(wl);
if (ret < 0)
goto out;

- set_bit(WL1271_FLAG_JOINED, &wl->flags);
-
if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
goto out;

/*
* The join command disable the keep-alive mode, shut down its process,
* and also clear the template config, so we need to reset it all after
@@ -2171,13 +2153,12 @@ static int wl1271_unjoin(struct wl1271 *wl)

/* to stop listening to a channel, we disconnect */
ret = wl1271_cmd_role_stop_sta(wl);
if (ret < 0)
goto out;

- clear_bit(WL1271_FLAG_JOINED, &wl->flags);
memset(wl->bssid, 0, ETH_ALEN);

/* reset TX security counters on a clean disconnect */
wl->tx_security_last_seq_lsb = 0;
wl->tx_security_seq = 0;

@@ -2195,14 +2176,18 @@ static void wl1271_set_band_rate(struct wl1271 *wl)

static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
{
int ret;

if (idle) {
- if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
- ret = wl1271_unjoin(wl);
+ if (test_bit(WL1271_FLAG_ROC, &wl->flags)) {
+ ret = wl1271_croc(wl, wl->dev_role_id);
+ if (ret < 0)
+ goto out;
+
+ ret = wl1271_cmd_role_stop_dev(wl);
if (ret < 0)
goto out;
}
wl->rate_set = wl1271_tx_min_rate_get(wl);
ret = wl1271_acx_sta_rate_policies(wl);
if (ret < 0)
@@ -2211,24 +2196,23 @@ static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
ACX_KEEP_ALIVE_TPL_INVALID);
if (ret < 0)
goto out;
set_bit(WL1271_FLAG_IDLE, &wl->flags);
} else {
- /* increment the session counter */
- wl->session_counter++;
- if (wl->session_counter >= SESSION_COUNTER_MAX)
- wl->session_counter = 0;
-
/* The current firmware only supports sched_scan in idle */
if (wl->sched_scanning) {
wl1271_scan_sched_scan_stop(wl);
ieee80211_sched_scan_stopped(wl->hw);
}

- ret = wl1271_dummy_join(wl);
+ ret = wl1271_cmd_role_start_dev(wl);
+ if (ret < 0)
+ goto out;
+
+ ret = wl1271_roc(wl, wl->dev_role_id);
if (ret < 0)
goto out;
clear_bit(WL1271_FLAG_IDLE, &wl->flags);
}

out:
@@ -2302,17 +2286,40 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
wl->basic_rate = wl1271_tx_min_rate_get(wl);
ret = wl1271_acx_sta_rate_policies(wl);
if (ret < 0)
wl1271_warning("rate policy for channel "
"failed %d", ret);

- if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
+ if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
+ if (test_bit(WL1271_FLAG_ROC, &wl->flags)) {
+ /* roaming */
+ ret = wl1271_croc(wl, wl->dev_role_id);
+ if (ret < 0)
+ goto out_sleep;
+ }
ret = wl1271_join(wl, false);
if (ret < 0)
wl1271_warning("cmd join on channel "
"failed %d", ret);
+ } else {
+ /*
+ * change the ROC channel. do it only if we are
+ * not idle. otherwise, CROC will be called
+ * anyway.
+ */
+ if (test_bit(WL1271_FLAG_ROC, &wl->flags) &&
+ !(conf->flags & IEEE80211_CONF_IDLE)) {
+ ret = wl1271_croc(wl, wl->dev_role_id);
+ if (ret < 0)
+ goto out_sleep;
+
+ ret = wl1271_roc(wl, wl->dev_role_id);
+ if (ret < 0)
+ wl1271_warning("roc failed %d",
+ ret);
+ }
}
}
}

if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
ret = wl1271_sta_handle_idle(wl,
@@ -2762,16 +2769,26 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
}

ret = wl1271_ps_elp_wakeup(wl);
if (ret < 0)
goto out;

- ret = wl1271_scan(hw->priv, ssid, len, req);
+ /* cancel ROC before scanning */
+ if (test_bit(WL1271_FLAG_ROC, &wl->flags)) {
+ if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
+ /* don't allow scanning right now (?) */
+ ret = -EBUSY;
+ goto out_sleep;
+ }
+ wl1271_croc(wl, wl->dev_role_id);
+ wl1271_cmd_role_stop_dev(wl);
+ }

+ ret = wl1271_scan(hw->priv, ssid, len, req);
+out_sleep:
wl1271_ps_elp_sleep(wl);
-
out:
mutex_unlock(&wl->mutex);

return ret;
}

@@ -3289,13 +3306,15 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
}
} else {
/* use defaults when not associated */
bool was_assoc =
!!test_and_clear_bit(WL1271_FLAG_STA_ASSOCIATED,
&wl->flags);
- clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
+ bool was_ifup =
+ !!test_and_clear_bit(WL1271_FLAG_STA_STATE_SENT,
+ &wl->flags);
wl->aid = 0;

/* free probe-request template */
dev_kfree_skb(wl->probereq);
wl->probereq = NULL;

@@ -3316,14 +3335,38 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
ret = wl1271_acx_keep_alive_mode(wl, false);
if (ret < 0)
goto out;

/* restore the bssid filter and go to dummy bssid */
if (was_assoc) {
+ u32 conf_flags = wl->hw->conf.flags;
+ /*
+ * we might have to disable roc, if there was
+ * no IF_OPER_UP notification.
+ */
+ if (!was_ifup) {
+ ret = wl1271_croc(wl, wl->role_id);
+ if (ret < 0)
+ goto out;
+ }
+ /*
+ * (we also need to disable roc in case of
+ * roaming on the same channel. until we will
+ * have a better flow...)
+ */
+ if (test_bit(wl->dev_role_id, wl->roc_map)) {
+ ret = wl1271_croc(wl, wl->dev_role_id);
+ if (ret < 0)
+ goto out;
+ }
+
wl1271_unjoin(wl);
- wl1271_dummy_join(wl);
+ if (!(conf_flags & IEEE80211_CONF_IDLE)) {
+ wl1271_cmd_role_start_dev(wl);
+ wl1271_roc(wl, wl->dev_role_id);
+ }
}
}
}

if (changed & BSS_CHANGED_IBSS) {
wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
@@ -3378,13 +3421,35 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
if (do_join) {
ret = wl1271_join(wl, set_assoc);
if (ret < 0) {
wl1271_warning("cmd join failed %d", ret);
goto out;
}
- wl1271_check_operstate(wl, ieee80211_get_operstate(vif));
+
+ /* ROC until interface is up (after EAPOL exchange) */
+ if (!is_ibss) {
+ ret = wl1271_roc(wl, wl->role_id);
+ if (ret < 0)
+ goto out;
+
+ wl1271_check_operstate(wl,
+ ieee80211_get_operstate(vif));
+ }
+ /*
+ * stop device role if started (we might already be in
+ * STA role). TODO: make it better.
+ */
+ if (wl->dev_role_id != WL1271_INVALID_ROLE_ID) {
+ ret = wl1271_croc(wl, wl->dev_role_id);
+ if (ret < 0)
+ goto out;
+
+ ret = wl1271_cmd_role_stop_dev(wl);
+ if (ret < 0)
+ goto out;
+ }
}

out:
return;
}

diff --git a/drivers/net/wireless/wl12xx/scan.c b/drivers/net/wireless/wl12xx/scan.c
index b34034c..52f2b6b 100644
--- a/drivers/net/wireless/wl12xx/scan.c
+++ b/drivers/net/wireless/wl12xx/scan.c
@@ -30,12 +30,13 @@
#include "ps.h"

void wl1271_scan_complete_work(struct work_struct *work)
{
struct delayed_work *dwork;
struct wl1271 *wl;
+ int ret;

dwork = container_of(work, struct delayed_work, work);
wl = container_of(dwork, struct wl1271, scan_complete_work);

wl1271_debug(DEBUG_SCAN, "Scanning complete");

@@ -47,27 +48,34 @@ void wl1271_scan_complete_work(struct work_struct *work)
if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
goto out;

wl->scan.state = WL1271_SCAN_STATE_IDLE;
memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
wl->scan.req = NULL;
- ieee80211_scan_completed(wl->hw, false);

- /* restore hardware connection monitoring template */
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
- if (wl1271_ps_elp_wakeup(wl) == 0) {
- wl1271_cmd_build_ap_probe_req(wl, wl->probereq);
- wl1271_ps_elp_sleep(wl);
- }
+ /* restore hardware connection monitoring template */
+ wl1271_cmd_build_ap_probe_req(wl, wl->probereq);
+ } else {
+ /* restore remain on channel */
+ wl1271_cmd_role_start_dev(wl);
+ wl1271_roc(wl, wl->dev_role_id);
}
+ wl1271_ps_elp_sleep(wl);

if (wl->scan.failed) {
wl1271_info("Scan completed due to error.");
wl12xx_queue_recovery_work(wl);
}

+ ieee80211_scan_completed(wl->hw, false);
+
out:
mutex_unlock(&wl->mutex);

}


diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c
index 6a9be77..ea05caf 100644
--- a/drivers/net/wireless/wl12xx/tx.c
+++ b/drivers/net/wireless/wl12xx/tx.c
@@ -75,12 +75,13 @@ static void wl1271_free_tx_id(struct wl1271 *wl, int id)
}

static int wl1271_tx_update_filters(struct wl1271 *wl,
struct sk_buff *skb)
{
struct ieee80211_hdr *hdr;
+ int ret;

hdr = (struct ieee80211_hdr *)(skb->data +
sizeof(struct wl1271_tx_hw_descr));

/*
* stop bssid-based filtering before transmitting authentication
@@ -88,12 +89,24 @@ static int wl1271_tx_update_filters(struct wl1271 *wl,
* responses coming from BSSIDs it isn't familiar with (e.g. on
* roaming)
*/
if (!ieee80211_is_auth(hdr->frame_control))
return 0;

+ if (wl->dev_hlid != WL1271_INVALID_LINK_ID)
+ goto out;
+
+ wl1271_debug(DEBUG_CMD, "starting device role for roaming");
+ ret = wl1271_cmd_role_start_dev(wl);
+ if (ret < 0)
+ goto out;
+
+ ret = wl1271_roc(wl, wl->dev_role_id);
+ if (ret < 0)
+ goto out;
+out:
return 0;
}

static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl,
struct sk_buff *skb)
{
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index 9c5daae..37b1d6b 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -316,13 +316,13 @@ struct wl1271_ap_key {
u32 tx_seq_32;
u16 tx_seq_16;
};

enum wl12xx_flags {
WL1271_FLAG_STA_ASSOCIATED,
- WL1271_FLAG_JOINED,
+ WL1271_FLAG_ROC,
WL1271_FLAG_GPIO_POWER,
WL1271_FLAG_TX_QUEUE_STOPPED,
WL1271_FLAG_TX_PENDING,
WL1271_FLAG_IN_ELP,
WL1271_FLAG_ELP_REQUESTED,
WL1271_FLAG_PSM,
@@ -399,12 +399,13 @@ struct wl1271 {
u8 system_hlid;
u8 sta_hlid;
u8 dev_hlid;

unsigned long links_map[BITS_TO_LONGS(WL1271_MAX_LINKS)];
unsigned long roles_map[BITS_TO_LONGS(WL1271_MAX_ROLES)];
+ unsigned long roc_map[BITS_TO_LONGS(WL1271_MAX_ROLES)];

struct wl1271_acx_mem_map *target_mem_map;

/* Accounting for allocated / available TX blocks on HW */
u32 tx_blocks_freed;
u32 tx_blocks_available;
--
1.7.6.401.g6a319


2011-08-09 09:14:42

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 38/40] wl12xx: set the AP-started flag only after setting keys

From: Arik Nemtsov <[email protected]>

This fix eliminates a potential race between starting the AP role
and setting encryption keys.

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

diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index 9f60f0f..e3c77da 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -3105,18 +3105,18 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
if (bss_conf->enable_beacon) {
if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
ret = wl1271_cmd_role_start_ap(wl);
if (ret < 0)
goto out;

- set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
- wl1271_debug(DEBUG_AP, "started AP");
-
ret = wl1271_ap_init_hwenc(wl);
if (ret < 0)
goto out;
+
+ set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
+ wl1271_debug(DEBUG_AP, "started AP");
}
} else {
if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
ret = wl1271_cmd_role_stop_ap(wl);
if (ret < 0)
goto out;
--
1.7.6.401.g6a319


2011-08-11 09:41:26

by Eliad Peller

[permalink] [raw]
Subject: Re: [PATCH 33/40] wl12xx: track freed packets in FW by AC

On Thu, Aug 11, 2011 at 12:17 PM, Luciano Coelho <[email protected]> wrote:
> On Tue, 2011-08-09 at 12:13 +0300, Eliad Peller wrote:
>> From: Arik Nemtsov <[email protected]>
>>
>> Track the number of freed packets in each AC when receiving an interrupt
>> from the FW. This paves the way for tracking allocated packets per AC.
>>
>> Signed-off-by: Arik Nemtsov <[email protected]>
>> Signed-off-by: Eliad Peller <[email protected]>
>> ---
>> ?drivers/net/wireless/wl12xx/main.c ? | ? 16 +++++++++++++++-
>> ?drivers/net/wireless/wl12xx/tx.c ? ? | ? ?2 ++
>> ?drivers/net/wireless/wl12xx/wl12xx.h | ? ?8 ++++++--
>> ?3 files changed, 23 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
>> index b223c27..3bfd772 100644
>> --- a/drivers/net/wireless/wl12xx/main.c
>> +++ b/drivers/net/wireless/wl12xx/main.c
>> @@ -810,22 +810,32 @@ static void wl1271_irq_update_links_status(struct wl1271 *wl,
>> ?static void wl1271_fw_status(struct wl1271 *wl,
>> ? ? ? ? ? ? ? ? ? ? ? ? ? ?struct wl1271_fw_status *status)
>> ?{
>> ? ? ? struct timespec ts;
>> ? ? ? u32 old_tx_blk_count = wl->tx_blocks_available;
>> ? ? ? int avail, freed_blocks;
>> + ? ? int i;
>>
>> ? ? ? wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
>>
>> ? ? ? wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
>> ? ? ? ? ? ? ? ? ? ?"drv_rx_counter = %d, tx_results_counter = %d)",
>> ? ? ? ? ? ? ? ? ? ?status->intr,
>> ? ? ? ? ? ? ? ? ? ?status->fw_rx_counter,
>> ? ? ? ? ? ? ? ? ? ?status->drv_rx_counter,
>> ? ? ? ? ? ? ? ? ? ?status->tx_results_counter);
>>
>> + ? ? for (i = 0; i < NUM_TX_QUEUES; i++) {
>> + ? ? ? ? ? ? /* prevent wrap-around in freed-packets counter */
>> + ? ? ? ? ? ? wl->tx_allocated_pkts -=
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? (status->tx_released_pkts[i] -
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? wl->tx_pkts_freed[i] + 256) % 256;
>
> Isn't the "+ 256" useless here, since you'll mod the result anyway?
>
modulus of negative numbers is not well defined.

Eliad.

2011-08-09 09:14:20

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 26/40] wl12xx: add wl1271_cmd_role_start_ibss()

Add wl1271_cmd_role_start_ibss() implementation and defintion.
This function is used in order to start the IBSS role.

Stopping the IBSS is done by using the same api as stop STA,
so there is no need for a separate function.

Signed-off-by: Eliad Peller <[email protected]>
---
drivers/net/wireless/wl12xx/cmd.c | 61 +++++++++++++++++++++++++++++++++++++
drivers/net/wireless/wl12xx/cmd.h | 1 +
2 files changed, 62 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c
index 41dee4f..b8d6848 100644
--- a/drivers/net/wireless/wl12xx/cmd.c
+++ b/drivers/net/wireless/wl12xx/cmd.c
@@ -767,12 +767,73 @@ out_free:
kfree(cmd);

out:
return ret;
}

+int wl1271_cmd_role_start_ibss(struct wl1271 *wl)
+{
+ struct wl1271_cmd_role_start *cmd;
+ struct ieee80211_bss_conf *bss_conf = &wl->vif->bss_conf;
+ int ret;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ wl1271_debug(DEBUG_CMD, "cmd role start ibss %d", wl->role_id);
+
+ cmd->role_id = wl->role_id;
+ if (wl->band == IEEE80211_BAND_5GHZ)
+ cmd->band |= WL1271_BAND_5GHZ;
+ cmd->channel = wl->channel;
+ cmd->ibss.basic_rate_set = cpu_to_le32(wl->basic_rate_set);
+ cmd->ibss.beacon_interval = cpu_to_le16(wl->beacon_int);
+ cmd->ibss.dtim_interval = bss_conf->dtim_period;
+ cmd->ibss.ssid_type = WL1271_SSID_TYPE_ANY;
+ cmd->ibss.ssid_len = wl->ssid_len;
+ memcpy(cmd->ibss.ssid, wl->ssid, wl->ssid_len);
+ memcpy(cmd->ibss.bssid, wl->bssid, ETH_ALEN);
+ cmd->sta.local_rates = cpu_to_le32(wl->rate_set);
+
+ if (wl->sta_hlid == WL1271_INVALID_LINK_ID) {
+ ret = wl1271_allocate_link(wl, &wl->sta_hlid);
+ if (ret)
+ goto out_free;
+ }
+ cmd->ibss.hlid = wl->sta_hlid;
+ cmd->ibss.remote_rates = cpu_to_le32(wl->rate_set);
+
+ wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d "
+ "basic_rate_set: 0x%x, remote_rates: 0x%x",
+ wl->role_id, cmd->sta.hlid, cmd->sta.session,
+ wl->basic_rate_set, wl->rate_set);
+
+ wl1271_debug(DEBUG_CMD, "wl->bssid = %pM", wl->bssid);
+
+ ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0);
+ if (ret < 0) {
+ wl1271_error("failed to initiate cmd role enable");
+ goto err_hlid;
+ }
+
+ goto out_free;
+
+err_hlid:
+ /* clear links on error. */
+ wl1271_free_link(wl, &wl->sta_hlid);
+
+out_free:
+ kfree(cmd);
+
+out:
+ return ret;
+}
+

/**
* send test command to firmware
*
* @wl: wl struct
* @buf: buffer containing the command, with all headers, must work with dma
diff --git a/drivers/net/wireless/wl12xx/cmd.h b/drivers/net/wireless/wl12xx/cmd.h
index 2ae2d73..e62345b 100644
--- a/drivers/net/wireless/wl12xx/cmd.h
+++ b/drivers/net/wireless/wl12xx/cmd.h
@@ -41,12 +41,13 @@ int wl1271_cmd_role_disable(struct wl1271 *wl, u8 *role_id);
int wl1271_cmd_role_start_dev(struct wl1271 *wl);
int wl1271_cmd_role_stop_dev(struct wl1271 *wl);
int wl1271_cmd_role_start_sta(struct wl1271 *wl);
int wl1271_cmd_role_stop_sta(struct wl1271 *wl);
int wl1271_cmd_role_start_ap(struct wl1271 *wl);
int wl1271_cmd_role_stop_ap(struct wl1271 *wl);
+int wl1271_cmd_role_start_ibss(struct wl1271 *wl);
int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer);
int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len);
int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len);
int wl1271_cmd_data_path(struct wl1271 *wl, bool enable);
int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode);
int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer,
--
1.7.6.401.g6a319


2011-08-10 12:31:25

by Luciano Coelho

[permalink] [raw]
Subject: Re: [PATCH 15/40] wl12xx: add set_rate_mgmt_params acx

On Tue, 2011-08-09 at 12:13 +0300, Eliad Peller wrote:
> +int wl1271_acx_set_rate_mgmt_params(struct wl1271 *wl)
> +{
> + struct wl1271_acx_set_rate_mgmt_params *acx = NULL;
> + struct conf_rate_policy_settings *conf = &wl->conf.rate;
> + int ret;
> +
> + wl1271_debug(DEBUG_ACX, "acx set rate mgmt params");
> + BUILD_BUG_ON(sizeof(conf->rate_retry_policy) !=
> + sizeof(acx->rate_retry_policy));
> + BUILD_BUG_ON(sizeof(*acx) % 4);

I guess you shouldn't need these anymore?


> + ret = wl1271_cmd_configure(wl, ACX_SET_RATE_MAMAGEMENT_PARAMS,

Typo, should be MANAGEMENT. This should be fixed already where
declared, in patch 07.


> +#define ACX_RATE_MGMT_ALL_PARAMS 0xff
> +#define ACX_RATE_MGMT_NUM_OF_RATES 13
> +struct wl1271_acx_set_rate_mgmt_params {
> + struct acx_header header;
> +
> + /* the param we configure */

This comment doesn't seem very meaningful.


> + u8 index;
> + u8 padding1; /* MISSING */
> + __le16 rate_retry_score;
> + __le16 per_add;
> + __le16 per_th1;
> + __le16 per_th2;
> + __le16 max_per;
> + u8 inverse_curiosity_factor;
> + u8 tx_fail_low_th;
> + u8 tx_fail_high_th;
> + u8 per_alpha_shift;
> + u8 per_add_shift;
> + u8 per_beta1_shift;
> + u8 per_beta2_shift;
> + u8 rate_check_up;
> + u8 rate_check_down;
> + u8 rate_retry_policy[ACX_RATE_MGMT_NUM_OF_RATES];
> + u8 padding2[2]; /* MISSING */
> +} __packed;

Now that you found what was MISSING, please remove from here and inform
the firmware people so they can fix it on their side.


> @@ -1324,9 +1343,10 @@ struct conf_drv_settings {
> struct conf_memory_settings mem_wl127x;
> struct conf_memory_settings mem_wl128x;
> struct conf_fm_coex fm_coex;
> struct conf_rx_streaming_settings rx_streaming;
> struct conf_fwlog fwlog;
> u8 hci_io_ds;
> + struct conf_rate_policy_settings rate;
> };

The new struct could come before hci_io_ds, since there's no need to
keep backwards compatibility here yet.


--
Cheers,
Luca.


2011-08-10 15:20:34

by Luciano Coelho

[permalink] [raw]
Subject: Re: [PATCH 21/40] wl12xx: fix session counter

On Tue, 2011-08-09 at 12:13 +0300, Eliad Peller wrote:
> From: Arik Nemtsov <[email protected]>
>
> Increment the session counter on every join command.
>
> Signed-off-by: Arik Nemtsov <[email protected]>
> Signed-off-by: Eliad Peller <[email protected]>
> ---

Looks fine, but the commit log is misleading, because it's not done in
every join, but in every wl1271_cmd_role_start_sta() call (ie. it is
only used for STA).

--
Cheers,
Luca.


2011-08-10 10:24:01

by Eliad Peller

[permalink] [raw]
Subject: Re: [PATCH 08/40] wl12xx: wl12xx-fw-3 - update commands & events

On Wed, Aug 10, 2011 at 12:19 PM, Luciano Coelho <[email protected]> wrote:
> On Tue, 2011-08-09 at 12:13 +0300, Eliad Peller wrote:
>> +enum wl1271_cmd_lid_key_type {
>> + ? ? UNICAST_LID_TYPE ? ? = 0,
>> + ? ? BROADCAST_LID_TYPE ? = 1,
>> + ? ? WEP_DEFAULT_LID_TYPE = 2
>> +};
>
> Doesn't LID_TYPE_UNICAST, LID_TYPE_BROADCAST and so on look better?
>
it does, but i didn't touch this struct (it wasn't in the context diff
expected, so it looks like it was deleted and re-added), and i should
avoid adding more stuff (changing all the existing uses of this enum)
to this already-too-big patch.

Eliad.

2011-08-11 07:15:21

by Luciano Coelho

[permalink] [raw]
Subject: Re: [PATCH 26/40] wl12xx: add wl1271_cmd_role_start_ibss()

On Tue, 2011-08-09 at 12:13 +0300, Eliad Peller wrote:
> Add wl1271_cmd_role_start_ibss() implementation and defintion.
> This function is used in order to start the IBSS role.
>
> Stopping the IBSS is done by using the same api as stop STA,
> so there is no need for a separate function.

Not really important now, but maybe we should find a more generic name
for the wl1271_cmd_role_stop_sta() function then. Or add a nice comment
there saying that it is also used for bss.


> diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c
> index 41dee4f..b8d6848 100644
> --- a/drivers/net/wireless/wl12xx/cmd.c
> +++ b/drivers/net/wireless/wl12xx/cmd.c
> @@ -767,12 +767,73 @@ out_free:
> kfree(cmd);
>
> out:
> return ret;
> }
>
> +int wl1271_cmd_role_start_ibss(struct wl1271 *wl)
> +{
> + struct wl1271_cmd_role_start *cmd;
> + struct ieee80211_bss_conf *bss_conf = &wl->vif->bss_conf;
> + int ret;
> +
> + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
> + if (!cmd) {
> + ret = -ENOMEM;
> + goto out;
> + }
> +
> + wl1271_debug(DEBUG_CMD, "cmd role start ibss %d", wl->role_id);
> +
> + cmd->role_id = wl->role_id;
> + if (wl->band == IEEE80211_BAND_5GHZ)
> + cmd->band |= WL1271_BAND_5GHZ;

This looks wrong. I didn't see it before, but it was already introduced
in patch 08. The WL1271_BAND_* definitions are an enumeration defined
like this:

enum wl1271_band {
WL1271_BAND_2_4GHZ = 0, /* 2.4 Ghz band */
WL1271_BAND_5GHZ = 1, /* 5 Ghz band */
WL1271_BAND_JAPAN_4_9_GHZ = 2,
WL1271_BAND_DEFAULT = WL1271_BAND_2_4GHZ,
WL1271_BAND_INVALID = 0x7E,
WL1271_BAND_MAX_RADIO = 0x7F,
};

Why are we always ORing the value into cmd->band then? If these commands
can only work in single bands (which is probably the case), then we
should use "cmd->band = WL1271_BAND_5GHZ" instead. If the commands can
manage more than a band at once, then cmd->band should be a bitmask and
the enumeration should be defined using BIT(0), BIT(1) and so on.


--
Cheers,
Luca.