2011-04-18 11:15:42

by Arik Nemtsov

[permalink] [raw]
Subject: [PATCH 01/10] wl12xx: add BT-coexistance for AP

Initialize AP specific BT coexitance parameters to default values and
enable them in AP mode.

Signed-off-by: Arik Nemtsov <[email protected]>
---
drivers/net/wireless/wl12xx/acx.c | 40 ++++++++++++++++++++++---
drivers/net/wireless/wl12xx/acx.h | 16 ++++++++--
drivers/net/wireless/wl12xx/conf.h | 35 +++++++++++++++++++++-
drivers/net/wireless/wl12xx/init.c | 15 ++++++----
drivers/net/wireless/wl12xx/main.c | 57 +++++++++++++++++++++++++++++++++++-
5 files changed, 146 insertions(+), 17 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c
index b277947..cda546b 100644
--- a/drivers/net/wireless/wl12xx/acx.c
+++ b/drivers/net/wireless/wl12xx/acx.c
@@ -540,13 +540,13 @@ out:
return ret;
}

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

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

param = kzalloc(sizeof(*param), GFP_KERNEL);
if (!param) {
@@ -555,8 +555,38 @@ int wl1271_acx_sg_cfg(struct wl1271 *wl)
}

/* BT-WLAN coext parameters */
- for (i = 0; i < CONF_SG_PARAMS_MAX; i++)
- param->params[i] = cpu_to_le32(c->params[i]);
+ 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]);
param->param_idx = CONF_SG_PARAMS_ALL;

ret = wl1271_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param));
diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h
index 0a40cae..b35ebf5 100644
--- a/drivers/net/wireless/wl12xx/acx.h
+++ b/drivers/net/wireless/wl12xx/acx.h
@@ -370,14 +370,23 @@ struct acx_bt_wlan_coex {
u8 pad[3];
} __packed;

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

- __le32 params[CONF_SG_PARAMS_MAX];
+ __le32 params[CONF_SG_STA_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;

@@ -1263,7 +1272,8 @@ 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_sg_cfg(struct wl1271 *wl);
+int wl1271_acx_sta_sg_cfg(struct wl1271 *wl);
+int wl1271_acx_ap_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);
diff --git a/drivers/net/wireless/wl12xx/conf.h b/drivers/net/wireless/wl12xx/conf.h
index 743bd0b..0c1d0c7 100644
--- a/drivers/net/wireless/wl12xx/conf.h
+++ b/drivers/net/wireless/wl12xx/conf.h
@@ -396,12 +396,43 @@ enum {
CONF_SG_TEMP_PARAM_3,
CONF_SG_TEMP_PARAM_4,
CONF_SG_TEMP_PARAM_5,
- CONF_SG_PARAMS_MAX,
+
+ /*
+ * 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_ALL = 0xff
};

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

diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c
index cf46607..e8c979d 100644
--- a/drivers/net/wireless/wl12xx/init.c
+++ b/drivers/net/wireless/wl12xx/init.c
@@ -285,7 +285,10 @@ int wl1271_init_pta(struct wl1271 *wl)
{
int ret;

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

@@ -351,11 +354,6 @@ static int wl1271_sta_hw_init(struct wl1271 *wl)
if (ret < 0)
return ret;

- /* Bluetooth WLAN coexistence */
- ret = wl1271_init_pta(wl);
- if (ret < 0)
- return ret;
-
/* Beacons and broadcast settings */
ret = wl1271_init_beacon_broadcast(wl);
if (ret < 0)
@@ -563,6 +561,11 @@ int wl1271_hw_init(struct wl1271 *wl)
if (ret < 0)
return ret;

+ /* Bluetooth WLAN coexistence */
+ ret = wl1271_init_pta(wl);
+ if (ret < 0)
+ return ret;
+
/* Default memory configuration */
ret = wl1271_acx_init_mem_config(wl);
if (ret < 0)
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index 7126506..1c206ae 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -51,7 +51,7 @@

static struct conf_drv_settings default_conf = {
.sg = {
- .params = {
+ .sta_params = {
[CONF_SG_BT_PER_THRESHOLD] = 7500,
[CONF_SG_HV3_MAX_OVERRIDE] = 0,
[CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
@@ -101,6 +101,61 @@ static struct conf_drv_settings default_conf = {
[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,
+ },
.state = CONF_SG_PROTECTIVE,
},
.rx = {
--
1.7.1



2011-04-18 11:16:37

by Arik Nemtsov

[permalink] [raw]
Subject: [PATCH 10/10] wl12xx: export driver state to debugfs

By reading the "driver_state" debugfs value we get all the important
state information from the wl12xx driver. This helps testing and
debugging, particularly in situations where the driver seems "stuck".

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

diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c
index 6eb48b7..6970455 100644
--- a/drivers/net/wireless/wl12xx/debugfs.c
+++ b/drivers/net/wireless/wl12xx/debugfs.c
@@ -310,6 +310,92 @@ static const struct file_operations start_recovery_ops = {
.llseek = default_llseek,
};

+static ssize_t driver_state_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct wl1271 *wl = file->private_data;
+ int res = 0;
+ char buf[1024];
+
+ mutex_lock(&wl->mutex);
+
+#define DRIVER_STATE_PRINT(x, fmt) \
+ (res += scnprintf(buf + res, sizeof(buf) - res,\
+ #x " = " fmt "\n", wl->x))
+
+#define DRIVER_STATE_PRINT_LONG(x) DRIVER_STATE_PRINT(x, "%ld")
+#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);
+ DRIVER_STATE_PRINT_INT(tx_frames_cnt);
+ DRIVER_STATE_PRINT_LHEX(tx_frames_map[0]);
+ DRIVER_STATE_PRINT_INT(tx_queue_count);
+ 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_security_last_seq);
+ 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);
+ DRIVER_STATE_PRINT_HEX(rate_set);
+ 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);
+ DRIVER_STATE_PRINT_LHEX(ap_hlid_map[0]);
+ DRIVER_STATE_PRINT_INT(last_tx_hlid);
+ DRIVER_STATE_PRINT_INT(ba_support);
+ DRIVER_STATE_PRINT_HEX(ba_rx_bitmap);
+ DRIVER_STATE_PRINT_HEX(ap_fw_ps_map);
+ DRIVER_STATE_PRINT_LHEX(ap_ps_map);
+ DRIVER_STATE_PRINT_HEX(quirks);
+ DRIVER_STATE_PRINT_HEX(irq);
+ DRIVER_STATE_PRINT_HEX(ref_clock);
+ DRIVER_STATE_PRINT_HEX(tcxo_clock);
+ DRIVER_STATE_PRINT_HEX(hw_pg_ver);
+ DRIVER_STATE_PRINT_HEX(platform_quirks);
+ DRIVER_STATE_PRINT_HEX(chip.id);
+ DRIVER_STATE_PRINT_STR(chip.fw_ver_str);
+
+#undef DRIVER_STATE_PRINT_INT
+#undef DRIVER_STATE_PRINT_LONG
+#undef DRIVER_STATE_PRINT_HEX
+#undef DRIVER_STATE_PRINT_LHEX
+#undef DRIVER_STATE_PRINT_STR
+#undef DRIVER_STATE_PRINT
+
+ mutex_unlock(&wl->mutex);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, res);
+}
+
+static const struct file_operations driver_state_ops = {
+ .read = driver_state_read,
+ .open = wl1271_open_file_generic,
+ .llseek = default_llseek,
+};
+
static int wl1271_debugfs_add_files(struct wl1271 *wl,
struct dentry *rootdir)
{
@@ -419,6 +505,7 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl,

DEBUGFS_ADD(gpio_power, rootdir);
DEBUGFS_ADD(start_recovery, rootdir);
+ DEBUGFS_ADD(driver_state, rootdir);

return 0;

--
1.7.1


2011-04-29 21:17:12

by Luciano Coelho

[permalink] [raw]
Subject: Re: [PATCH 01/10] wl12xx: add BT-coexistance for AP

On Fri, 2011-04-29 at 23:02 +0300, Luciano Coelho wrote:
> On Mon, 2011-04-18 at 14:15 +0300, Arik Nemtsov wrote:
> > Initialize AP specific BT coexitance parameters to default values and
> > enable them in AP mode.
> >
> > Signed-off-by: Arik Nemtsov <[email protected]>
> > ---
>
> Applied the whole series, thanks Arik!

Ooops, these didn't go in yet. There were some conflicts and I have
mistakenly kept them out. I'll merge them and add them soon.

--
Cheers,
Luca.


2011-04-29 05:03:42

by Arik Nemtsov

[permalink] [raw]
Subject: Re: [PATCH 10/10] wl12xx: export driver state to debugfs

On Thu, Apr 28, 2011 at 16:21, Luciano Coelho <[email protected]> wrote:
> On Mon, 2011-04-18 at 14:15 +0300, Arik Nemtsov wrote:
>> By reading the "driver_state" debugfs value we get all the important
>> state information from the wl12xx driver. This helps testing and
>> debugging, particularly in situations where the driver seems "stuck".
>>
>> Signed-off-by: Arik Nemtsov <[email protected]>
>> ---
>> ?drivers/net/wireless/wl12xx/debugfs.c | ? 87 +++++++++++++++++++++++++++++++++
>> ?1 files changed, 87 insertions(+), 0 deletions(-)
>>
>> diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c
>> index 6eb48b7..6970455 100644
>> --- a/drivers/net/wireless/wl12xx/debugfs.c
>> +++ b/drivers/net/wireless/wl12xx/debugfs.c
>> @@ -310,6 +310,92 @@ static const struct file_operations start_recovery_ops = {
>> ? ? ? .llseek = default_llseek,
>> ?};
>>
>> +static ssize_t driver_state_read(struct file *file, char __user *user_buf,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?size_t count, loff_t *ppos)
>> +{
>> + ? ? struct wl1271 *wl = file->private_data;
>> + ? ? int res = 0;
>> + ? ? char buf[1024];
>> +
>> + ? ? mutex_lock(&wl->mutex);
>> +
>> +#define DRIVER_STATE_PRINT(x, fmt) ? \
>> + ? ? (res += scnprintf(buf + res, sizeof(buf) - res,\
>> + ? ? ? ? ? ? ? ? ? ? ? #x " = " fmt "\n", wl->x))
>> +
>> +#define DRIVER_STATE_PRINT_LONG(x) DRIVER_STATE_PRINT(x, "%ld")
>> +#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);
>> + ? ? DRIVER_STATE_PRINT_INT(tx_frames_cnt);
>> + ? ? DRIVER_STATE_PRINT_LHEX(tx_frames_map[0]);
>> + ? ? DRIVER_STATE_PRINT_INT(tx_queue_count);
>> + ? ? 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_security_last_seq);
>> + ? ? 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);
>> + ? ? DRIVER_STATE_PRINT_HEX(rate_set);
>> + ? ? 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);
>> + ? ? DRIVER_STATE_PRINT_LHEX(ap_hlid_map[0]);
>> + ? ? DRIVER_STATE_PRINT_INT(last_tx_hlid);
>> + ? ? DRIVER_STATE_PRINT_INT(ba_support);
>> + ? ? DRIVER_STATE_PRINT_HEX(ba_rx_bitmap);
>> + ? ? DRIVER_STATE_PRINT_HEX(ap_fw_ps_map);
>> + ? ? DRIVER_STATE_PRINT_LHEX(ap_ps_map);
>> + ? ? DRIVER_STATE_PRINT_HEX(quirks);
>> + ? ? DRIVER_STATE_PRINT_HEX(irq);
>> + ? ? DRIVER_STATE_PRINT_HEX(ref_clock);
>> + ? ? DRIVER_STATE_PRINT_HEX(tcxo_clock);
>> + ? ? DRIVER_STATE_PRINT_HEX(hw_pg_ver);
>> + ? ? DRIVER_STATE_PRINT_HEX(platform_quirks);
>> + ? ? DRIVER_STATE_PRINT_HEX(chip.id);
>> + ? ? DRIVER_STATE_PRINT_STR(chip.fw_ver_str);
>
> I'd prefer to have each of these values in separate files, like the FW
> stats. ?If you print this all out in one file, it's hard to know which
> value means what. ?With separate files it's easy to know and you can
> achieve the same thing as having in one file by doing something like
> this:
>
> cat driver_state/*
>

I think it's pretty easy to understand what means what. The print
looks like this:

power_level = 0
rssi_thold = 0
last_rssi_event = 0
sg_enabled = 1
enable_11a = 1
noise = 31

As for making separate files - I think its preferable if people don't
have an option to print only parts of the state. This can help bug
reports by non-developers by giving a fuller picture.
Perhaps we can add separate files in another patch later on?

Arik

2011-04-29 07:42:49

by Luciano Coelho

[permalink] [raw]
Subject: Re: [PATCH 10/10] wl12xx: export driver state to debugfs

On Fri, 2011-04-29 at 08:03 +0300, Arik Nemtsov wrote:
> On Thu, Apr 28, 2011 at 16:21, Luciano Coelho <[email protected]> wrote:
> > On Mon, 2011-04-18 at 14:15 +0300, Arik Nemtsov wrote:
> >> By reading the "driver_state" debugfs value we get all the important
> >> state information from the wl12xx driver. This helps testing and
> >> debugging, particularly in situations where the driver seems "stuck".
> >>
> >> Signed-off-by: Arik Nemtsov <[email protected]>
> >> ---
> >> drivers/net/wireless/wl12xx/debugfs.c | 87 +++++++++++++++++++++++++++++++++
> >> 1 files changed, 87 insertions(+), 0 deletions(-)
> >>
> >> diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c
> >> index 6eb48b7..6970455 100644
> >> --- a/drivers/net/wireless/wl12xx/debugfs.c
> >> +++ b/drivers/net/wireless/wl12xx/debugfs.c
> >> @@ -310,6 +310,92 @@ static const struct file_operations start_recovery_ops = {
> >> .llseek = default_llseek,
> >> };
> >>
> >> +static ssize_t driver_state_read(struct file *file, char __user *user_buf,
> >> + size_t count, loff_t *ppos)
> >> +{
> >> + struct wl1271 *wl = file->private_data;
> >> + int res = 0;
> >> + char buf[1024];
> >> +
> >> + mutex_lock(&wl->mutex);
> >> +
> >> +#define DRIVER_STATE_PRINT(x, fmt) \
> >> + (res += scnprintf(buf + res, sizeof(buf) - res,\
> >> + #x " = " fmt "\n", wl->x))
> >> +
> >> +#define DRIVER_STATE_PRINT_LONG(x) DRIVER_STATE_PRINT(x, "%ld")
> >> +#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);
> >> + DRIVER_STATE_PRINT_INT(tx_frames_cnt);
> >> + DRIVER_STATE_PRINT_LHEX(tx_frames_map[0]);
> >> + DRIVER_STATE_PRINT_INT(tx_queue_count);
> >> + 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_security_last_seq);
> >> + 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);
> >> + DRIVER_STATE_PRINT_HEX(rate_set);
> >> + 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);
> >> + DRIVER_STATE_PRINT_LHEX(ap_hlid_map[0]);
> >> + DRIVER_STATE_PRINT_INT(last_tx_hlid);
> >> + DRIVER_STATE_PRINT_INT(ba_support);
> >> + DRIVER_STATE_PRINT_HEX(ba_rx_bitmap);
> >> + DRIVER_STATE_PRINT_HEX(ap_fw_ps_map);
> >> + DRIVER_STATE_PRINT_LHEX(ap_ps_map);
> >> + DRIVER_STATE_PRINT_HEX(quirks);
> >> + DRIVER_STATE_PRINT_HEX(irq);
> >> + DRIVER_STATE_PRINT_HEX(ref_clock);
> >> + DRIVER_STATE_PRINT_HEX(tcxo_clock);
> >> + DRIVER_STATE_PRINT_HEX(hw_pg_ver);
> >> + DRIVER_STATE_PRINT_HEX(platform_quirks);
> >> + DRIVER_STATE_PRINT_HEX(chip.id);
> >> + DRIVER_STATE_PRINT_STR(chip.fw_ver_str);
> >
> > I'd prefer to have each of these values in separate files, like the FW
> > stats. If you print this all out in one file, it's hard to know which
> > value means what. With separate files it's easy to know and you can
> > achieve the same thing as having in one file by doing something like
> > this:
> >
> > cat driver_state/*
> >
>
> I think it's pretty easy to understand what means what. The print
> looks like this:
>
> power_level = 0
> rssi_thold = 0
> last_rssi_event = 0
> sg_enabled = 1
> enable_11a = 1
> noise = 31

True, I missed the part where you print the var names too.


> As for making separate files - I think its preferable if people don't
> have an option to print only parts of the state. This can help bug
> reports by non-developers by giving a fuller picture.
> Perhaps we can add separate files in another patch later on?

Yeah, it's okay for now. This just came to my mind, because IIRC when
we added the fw stats, there was some recommendation somewhere saying
that debugfs entries should contain only values (not name-value pairs)
and should be done as a single value per file.

But I guess this is true for sysfs and not for debugfs. At least
according to Documentation/filesystems/debugfs.txt:

"[...]Unlike /proc, which is only meant for information about a process,
or sysfs, which has strict one-value-per-file rules, debugfs has no
rules at all. Developers can put any information they want there."

So, fine, I'll take this patch. ;)

--
Cheers,
Luca.


2011-04-18 11:16:10

by Arik Nemtsov

[permalink] [raw]
Subject: [PATCH 06/10] wl12xx: AP-mode - overhaul rate policy configuration

Use the minimal rate configured in the basic rates set as the AP
broadcast and multicast rate. The minimal rate is used to ensure weak
links can still communicate.

When the basic rates contains at least one OFDM rate, configure all
unicast TX rates to OFDM only.

Unify rate configuration on initialization and on change notification
into a single function.

Signed-off-by: Arik Nemtsov <[email protected]>
---
drivers/net/wireless/wl12xx/acx.c | 3 +-
drivers/net/wireless/wl12xx/conf.h | 22 +++--------
drivers/net/wireless/wl12xx/init.c | 71 +++++++++++++++++++++++++++---------
drivers/net/wireless/wl12xx/init.h | 1 +
drivers/net/wireless/wl12xx/main.c | 53 ++-------------------------
5 files changed, 65 insertions(+), 85 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c
index e9bc995..ebd1cb7 100644
--- a/drivers/net/wireless/wl12xx/acx.c
+++ b/drivers/net/wireless/wl12xx/acx.c
@@ -841,7 +841,8 @@ int wl1271_acx_ap_rate_policy(struct wl1271 *wl, struct conf_tx_rate_class *c,
struct acx_ap_rate_policy *acx;
int ret = 0;

- wl1271_debug(DEBUG_ACX, "acx ap rate policy");
+ wl1271_debug(DEBUG_ACX, "acx ap rate policy %d rates 0x%x",
+ idx, c->enabled_rates);

acx = kzalloc(sizeof(*acx), GFP_KERNEL);
if (!acx) {
diff --git a/drivers/net/wireless/wl12xx/conf.h b/drivers/net/wireless/wl12xx/conf.h
index 0c1d0c7..d03e4f9 100644
--- a/drivers/net/wireless/wl12xx/conf.h
+++ b/drivers/net/wireless/wl12xx/conf.h
@@ -540,6 +540,12 @@ struct conf_rx_settings {
CONF_HW_BIT_RATE_36MBPS | CONF_HW_BIT_RATE_48MBPS | \
CONF_HW_BIT_RATE_54MBPS)

+#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)
+
+
/*
* Default rates for management traffic when operating in AP mode. This
* should be configured according to the basic rate set of the AP
@@ -698,22 +704,6 @@ struct conf_tx_settings {
struct conf_tx_ac_category ac_conf[CONF_TX_MAX_AC_COUNT];

/*
- * Configuration for rate classes in AP-mode. These rate classes
- * are for the AC TX queues
- */
- struct conf_tx_rate_class ap_rc_conf[CONF_TX_MAX_AC_COUNT];
-
- /*
- * Management TX rate class for AP-mode.
- */
- struct conf_tx_rate_class ap_mgmt_conf;
-
- /*
- * Broadcast TX rate class for AP-mode.
- */
- struct conf_tx_rate_class ap_bcst_conf;
-
- /*
* AP-mode - allow this number of TX retries to a station before an
* event is triggered from FW.
*/
diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c
index 645f740..5fc69de 100644
--- a/drivers/net/wireless/wl12xx/init.c
+++ b/drivers/net/wireless/wl12xx/init.c
@@ -408,7 +408,7 @@ static int wl1271_sta_hw_init_post_mem(struct wl1271 *wl)

static int wl1271_ap_hw_init(struct wl1271 *wl)
{
- int ret, i;
+ int ret;

ret = wl1271_ap_init_templates_config(wl);
if (ret < 0)
@@ -419,23 +419,7 @@ static int wl1271_ap_hw_init(struct wl1271 *wl)
if (ret < 0)
return ret;

- /* Configure initial TX rate classes */
- for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
- ret = wl1271_acx_ap_rate_policy(wl,
- &wl->conf.tx.ap_rc_conf[i], i);
- if (ret < 0)
- return ret;
- }
-
- ret = wl1271_acx_ap_rate_policy(wl,
- &wl->conf.tx.ap_mgmt_conf,
- ACX_TX_AP_MODE_MGMT_RATE);
- if (ret < 0)
- return ret;
-
- ret = wl1271_acx_ap_rate_policy(wl,
- &wl->conf.tx.ap_bcst_conf,
- ACX_TX_AP_MODE_BCST_RATE);
+ ret = wl1271_init_ap_rates(wl);
if (ret < 0)
return ret;

@@ -477,6 +461,57 @@ static int wl1271_ap_hw_init_post_mem(struct wl1271 *wl)
return 0;
}

+int wl1271_init_ap_rates(struct wl1271 *wl)
+{
+ int i, ret;
+ struct conf_tx_rate_class rc;
+ u32 supported_rates;
+
+ wl1271_debug(DEBUG_AP, "AP basic rate set: 0x%x", wl->basic_rate_set);
+
+ if (wl->basic_rate_set == 0)
+ return -EINVAL;
+
+ rc.enabled_rates = wl->basic_rate_set;
+ rc.long_retry_limit = 10;
+ rc.short_retry_limit = 10;
+ rc.aflags = 0;
+ ret = wl1271_acx_ap_rate_policy(wl, &rc, ACX_TX_AP_MODE_MGMT_RATE);
+ if (ret < 0)
+ return ret;
+
+ /* use the min basic rate for AP broadcast/multicast */
+ rc.enabled_rates = wl1271_tx_min_rate_get(wl);
+ rc.short_retry_limit = 10;
+ rc.long_retry_limit = 10;
+ rc.aflags = 0;
+ ret = wl1271_acx_ap_rate_policy(wl, &rc, ACX_TX_AP_MODE_BCST_RATE);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * If the basic rates contain OFDM rates, use OFDM only
+ * rates for unicast TX as well. Else use all supported rates.
+ */
+ if ((wl->basic_rate_set & CONF_TX_OFDM_RATES))
+ supported_rates = CONF_TX_OFDM_RATES;
+ else
+ supported_rates = CONF_TX_AP_ENABLED_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;
+ ret = wl1271_acx_ap_rate_policy(wl, &rc, i);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
static void wl1271_check_ba_support(struct wl1271 *wl)
{
/* validate FW cose ver x.x.x.50-60.x */
diff --git a/drivers/net/wireless/wl12xx/init.h b/drivers/net/wireless/wl12xx/init.h
index 4975270..0dd2414 100644
--- a/drivers/net/wireless/wl12xx/init.h
+++ b/drivers/net/wireless/wl12xx/init.h
@@ -33,5 +33,6 @@ int wl1271_init_pta(struct wl1271 *wl);
int wl1271_init_energy_detection(struct wl1271 *wl);
int wl1271_chip_specific_init(struct wl1271 *wl);
int wl1271_hw_init(struct wl1271 *wl);
+int wl1271_init_ap_rates(struct wl1271 *wl);

#endif
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index e0c8ca4..c7e2c09 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -209,44 +209,6 @@ static struct conf_drv_settings default_conf = {
.tx_op_limit = 1504,
},
},
- .ap_rc_conf = {
- [0] = {
- .enabled_rates = CONF_TX_AP_ENABLED_RATES,
- .short_retry_limit = 10,
- .long_retry_limit = 10,
- .aflags = 0,
- },
- [1] = {
- .enabled_rates = CONF_TX_AP_ENABLED_RATES,
- .short_retry_limit = 10,
- .long_retry_limit = 10,
- .aflags = 0,
- },
- [2] = {
- .enabled_rates = CONF_TX_AP_ENABLED_RATES,
- .short_retry_limit = 10,
- .long_retry_limit = 10,
- .aflags = 0,
- },
- [3] = {
- .enabled_rates = CONF_TX_AP_ENABLED_RATES,
- .short_retry_limit = 10,
- .long_retry_limit = 10,
- .aflags = 0,
- },
- },
- .ap_mgmt_conf = {
- .enabled_rates = CONF_TX_AP_DEFAULT_MGMT_RATES,
- .short_retry_limit = 10,
- .long_retry_limit = 10,
- .aflags = 0,
- },
- .ap_bcst_conf = {
- .enabled_rates = CONF_HW_BIT_RATE_1MBPS,
- .short_retry_limit = 10,
- .long_retry_limit = 10,
- .aflags = 0,
- },
.ap_max_tx_retries = 100,
.tid_conf_count = 4,
.tid_conf = {
@@ -2509,22 +2471,13 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl,

if ((changed & BSS_CHANGED_BASIC_RATES)) {
u32 rates = bss_conf->basic_rates;
- struct conf_tx_rate_class mgmt_rc;

wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
wl->basic_rate = wl1271_tx_min_rate_get(wl);
- wl1271_debug(DEBUG_AP, "basic rates: 0x%x",
- wl->basic_rate_set);
-
- /* update the AP management rate policy with the new rates */
- mgmt_rc.enabled_rates = wl->basic_rate_set;
- mgmt_rc.long_retry_limit = 10;
- mgmt_rc.short_retry_limit = 10;
- mgmt_rc.aflags = 0;
- ret = wl1271_acx_ap_rate_policy(wl, &mgmt_rc,
- ACX_TX_AP_MODE_MGMT_RATE);
+
+ ret = wl1271_init_ap_rates(wl);
if (ret < 0) {
- wl1271_error("AP mgmt policy change failed %d", ret);
+ wl1271_error("AP rate policy change failed %d", ret);
goto out;
}
}
--
1.7.1


2011-04-18 11:16:16

by Arik Nemtsov

[permalink] [raw]
Subject: [PATCH 07/10] wl12xx: AP-mode - reconfigure templates after basic rates change

When there's a change in the basic rates of the AP, reconfigure relevant
templates with the new rates.

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

diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c
index 5fc69de..b615275 100644
--- a/drivers/net/wireless/wl12xx/init.c
+++ b/drivers/net/wireless/wl12xx/init.c
@@ -434,7 +434,7 @@ static int wl1271_ap_hw_init(struct wl1271 *wl)
return 0;
}

-static int wl1271_ap_hw_init_post_mem(struct wl1271 *wl)
+int wl1271_ap_init_templates(struct wl1271 *wl)
{
int ret;

@@ -461,6 +461,11 @@ static int wl1271_ap_hw_init_post_mem(struct wl1271 *wl)
return 0;
}

+static int wl1271_ap_hw_init_post_mem(struct wl1271 *wl)
+{
+ return wl1271_ap_init_templates(wl);
+}
+
int wl1271_init_ap_rates(struct wl1271 *wl)
{
int i, ret;
diff --git a/drivers/net/wireless/wl12xx/init.h b/drivers/net/wireless/wl12xx/init.h
index 0dd2414..3a3c230 100644
--- a/drivers/net/wireless/wl12xx/init.h
+++ b/drivers/net/wireless/wl12xx/init.h
@@ -34,5 +34,6 @@ int wl1271_init_energy_detection(struct wl1271 *wl);
int wl1271_chip_specific_init(struct wl1271 *wl);
int wl1271_hw_init(struct wl1271 *wl);
int wl1271_init_ap_rates(struct wl1271 *wl);
+int wl1271_ap_init_templates(struct wl1271 *wl);

#endif
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index c7e2c09..d2a8b83 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -2480,6 +2480,10 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
wl1271_error("AP rate policy change failed %d", ret);
goto out;
}
+
+ ret = wl1271_ap_init_templates(wl);
+ if (ret < 0)
+ goto out;
}

ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
--
1.7.1


2011-04-18 11:15:57

by Arik Nemtsov

[permalink] [raw]
Subject: [PATCH 04/10] wl12xx: schedule recovery on command timeout

We use a long timeout (2 seconds) when sending commands to the FW.
When a command times out, it means the FW is stuck, and we should
commence recovery.

This should make recovery times shorter as we'll recover on the first
timeout indication.

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

diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c
index 2468044..8090026 100644
--- a/drivers/net/wireless/wl12xx/cmd.c
+++ b/drivers/net/wireless/wl12xx/cmd.c
@@ -76,7 +76,7 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
if (time_after(jiffies, timeout)) {
wl1271_error("command complete timeout");
ret = -ETIMEDOUT;
- goto out;
+ goto fail;
}

poll_count++;
@@ -96,14 +96,17 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
status = le16_to_cpu(cmd->status);
if (status != CMD_STATUS_SUCCESS) {
wl1271_error("command execute failure %d", status);
- ieee80211_queue_work(wl->hw, &wl->recovery_work);
ret = -EIO;
+ goto fail;
}

wl1271_write32(wl, ACX_REG_INTERRUPT_ACK,
WL1271_ACX_INTR_CMD_COMPLETE);
+ return 0;

-out:
+fail:
+ WARN_ON(1);
+ ieee80211_queue_work(wl->hw, &wl->recovery_work);
return ret;
}

--
1.7.1


2011-04-18 11:16:30

by Arik Nemtsov

[permalink] [raw]
Subject: [PATCH 09/10] wl12xx: fix race condition during recovery in AP mode

When operating as AP, the TX queues are not stopped when we start
recovery. mac80211 is notified only after the fact. When there is
pending TX, it will be queued even after the FW is down. This leads to
situations where the TX queues are stopped (because of the TX-watermark
mechanism), and are never woken up when we return from recovery.

Fix this by explicitly stopping the TX queues when before initiating
recovery.

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

diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index d2a8b83..d7cb84b 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -338,7 +338,8 @@ static struct conf_drv_settings default_conf = {
},
};

-static void __wl1271_op_remove_interface(struct wl1271 *wl);
+static void __wl1271_op_remove_interface(struct wl1271 *wl,
+ bool reset_tx_queues);
static void wl1271_free_ap_keys(struct wl1271 *wl);


@@ -953,10 +954,19 @@ static void wl1271_recovery_work(struct work_struct *work)
if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
ieee80211_connection_loss(wl->vif);

+ /* Prevent spurious TX during FW restart */
+ ieee80211_stop_queues(wl->hw);
+
/* reboot the chipset */
- __wl1271_op_remove_interface(wl);
+ __wl1271_op_remove_interface(wl, false);
ieee80211_restart_hw(wl->hw);

+ /*
+ * Its safe to enable TX now - the queues are stopped after a request
+ * to restart the HW.
+ */
+ ieee80211_wake_queues(wl->hw);
+
out:
mutex_unlock(&wl->mutex);
}
@@ -1456,7 +1466,8 @@ out:
return ret;
}

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

@@ -1502,7 +1513,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl)
mutex_lock(&wl->mutex);

/* let's notify MAC80211 about the remaining pending TX frames */
- wl1271_tx_reset(wl);
+ wl1271_tx_reset(wl, reset_tx_queues);
wl1271_power_off(wl);

memset(wl->bssid, 0, ETH_ALEN);
@@ -1563,7 +1574,7 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
*/
if (wl->vif) {
WARN_ON(wl->vif != vif);
- __wl1271_op_remove_interface(wl);
+ __wl1271_op_remove_interface(wl, true);
}

mutex_unlock(&wl->mutex);
diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c
index 7a3339f..5c7f963 100644
--- a/drivers/net/wireless/wl12xx/tx.c
+++ b/drivers/net/wireless/wl12xx/tx.c
@@ -766,8 +766,8 @@ void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid)
wl1271_handle_tx_low_watermark(wl);
}

-/* caller must hold wl->mutex */
-void wl1271_tx_reset(struct wl1271 *wl)
+/* caller must hold wl->mutex and TX must be stopped */
+void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
{
int i;
struct sk_buff *skb;
@@ -803,8 +803,10 @@ void wl1271_tx_reset(struct wl1271 *wl)
/*
* Make sure the driver is at a consistent state, in case this
* function is called from a context other than interface removal.
+ * This call will always wake the TX queues.
*/
- wl1271_handle_tx_low_watermark(wl);
+ if (reset_tx_queues)
+ wl1271_handle_tx_low_watermark(wl);

for (i = 0; i < ACX_TX_DESCRIPTORS; i++) {
if (wl->tx_frames[i] == NULL)
diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/tx.h
index fc7835c..832f925 100644
--- a/drivers/net/wireless/wl12xx/tx.h
+++ b/drivers/net/wireless/wl12xx/tx.h
@@ -185,7 +185,7 @@ static inline int wl1271_tx_get_queue(int queue)
void wl1271_tx_work(struct work_struct *work);
void wl1271_tx_work_locked(struct wl1271 *wl);
void wl1271_tx_complete(struct wl1271 *wl);
-void wl1271_tx_reset(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);
--
1.7.1


2011-04-18 11:16:04

by Arik Nemtsov

[permalink] [raw]
Subject: [PATCH 05/10] wl12xx: print firmware program counter during recovery

When performing recovery, print the firmware version and program
counter (by reading the SCR_PAD4 register). The value of the firmware
program counter during assert can be useful for debugging.

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

diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index a2a26df..e0c8ca4 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -985,7 +985,8 @@ static void wl1271_recovery_work(struct work_struct *work)
if (wl->state != WL1271_STATE_ON)
goto out;

- wl1271_info("Hardware recovery in progress.");
+ wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
+ wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));

if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
ieee80211_connection_loss(wl->vif);
--
1.7.1


2011-04-29 04:26:17

by Luciano Coelho

[permalink] [raw]
Subject: Re: [PATCH 10/10] wl12xx: export driver state to debugfs

On Mon, 2011-04-18 at 14:15 +0300, Arik Nemtsov wrote:
> By reading the "driver_state" debugfs value we get all the important
> state information from the wl12xx driver. This helps testing and
> debugging, particularly in situations where the driver seems "stuck".
>
> Signed-off-by: Arik Nemtsov <[email protected]>
> ---
> drivers/net/wireless/wl12xx/debugfs.c | 87 +++++++++++++++++++++++++++++++++
> 1 files changed, 87 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c
> index 6eb48b7..6970455 100644
> --- a/drivers/net/wireless/wl12xx/debugfs.c
> +++ b/drivers/net/wireless/wl12xx/debugfs.c
> @@ -310,6 +310,92 @@ static const struct file_operations start_recovery_ops = {
> .llseek = default_llseek,
> };
>
> +static ssize_t driver_state_read(struct file *file, char __user *user_buf,
> + size_t count, loff_t *ppos)
> +{
> + struct wl1271 *wl = file->private_data;
> + int res = 0;
> + char buf[1024];
> +
> + mutex_lock(&wl->mutex);
> +
> +#define DRIVER_STATE_PRINT(x, fmt) \
> + (res += scnprintf(buf + res, sizeof(buf) - res,\
> + #x " = " fmt "\n", wl->x))
> +
> +#define DRIVER_STATE_PRINT_LONG(x) DRIVER_STATE_PRINT(x, "%ld")
> +#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);
> + DRIVER_STATE_PRINT_INT(tx_frames_cnt);
> + DRIVER_STATE_PRINT_LHEX(tx_frames_map[0]);
> + DRIVER_STATE_PRINT_INT(tx_queue_count);
> + 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_security_last_seq);
> + 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);
> + DRIVER_STATE_PRINT_HEX(rate_set);
> + 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);
> + DRIVER_STATE_PRINT_LHEX(ap_hlid_map[0]);
> + DRIVER_STATE_PRINT_INT(last_tx_hlid);
> + DRIVER_STATE_PRINT_INT(ba_support);
> + DRIVER_STATE_PRINT_HEX(ba_rx_bitmap);
> + DRIVER_STATE_PRINT_HEX(ap_fw_ps_map);
> + DRIVER_STATE_PRINT_LHEX(ap_ps_map);
> + DRIVER_STATE_PRINT_HEX(quirks);
> + DRIVER_STATE_PRINT_HEX(irq);
> + DRIVER_STATE_PRINT_HEX(ref_clock);
> + DRIVER_STATE_PRINT_HEX(tcxo_clock);
> + DRIVER_STATE_PRINT_HEX(hw_pg_ver);
> + DRIVER_STATE_PRINT_HEX(platform_quirks);
> + DRIVER_STATE_PRINT_HEX(chip.id);
> + DRIVER_STATE_PRINT_STR(chip.fw_ver_str);

I'd prefer to have each of these values in separate files, like the FW
stats. If you print this all out in one file, it's hard to know which
value means what. With separate files it's easy to know and you can
achieve the same thing as having in one file by doing something like
this:

cat driver_state/*

--
Cheers,
Luca.


2011-04-18 11:16:22

by Arik Nemtsov

[permalink] [raw]
Subject: [PATCH 08/10] wl12xx: add debugfs entry for starting recovery

This entry is useful for debugging the driver state machine during
recovery.

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

diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c
index 8e75b09..6eb48b7 100644
--- a/drivers/net/wireless/wl12xx/debugfs.c
+++ b/drivers/net/wireless/wl12xx/debugfs.c
@@ -291,6 +291,25 @@ static const struct file_operations gpio_power_ops = {
.llseek = default_llseek,
};

+static ssize_t start_recovery_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct wl1271 *wl = file->private_data;
+
+ mutex_lock(&wl->mutex);
+ ieee80211_queue_work(wl->hw, &wl->recovery_work);
+ mutex_unlock(&wl->mutex);
+
+ return count;
+}
+
+static const struct file_operations start_recovery_ops = {
+ .write = start_recovery_write,
+ .open = wl1271_open_file_generic,
+ .llseek = default_llseek,
+};
+
static int wl1271_debugfs_add_files(struct wl1271 *wl,
struct dentry *rootdir)
{
@@ -399,6 +418,7 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl,
DEBUGFS_ADD(excessive_retries, rootdir);

DEBUGFS_ADD(gpio_power, rootdir);
+ DEBUGFS_ADD(start_recovery, rootdir);

return 0;

--
1.7.1


2011-04-29 20:02:50

by Luciano Coelho

[permalink] [raw]
Subject: Re: [PATCH 01/10] wl12xx: add BT-coexistance for AP

On Mon, 2011-04-18 at 14:15 +0300, Arik Nemtsov wrote:
> Initialize AP specific BT coexitance parameters to default values and
> enable them in AP mode.
>
> Signed-off-by: Arik Nemtsov <[email protected]>
> ---

Applied the whole series, thanks Arik!

--
Cheers,
Luca.


2011-04-18 11:15:45

by Arik Nemtsov

[permalink] [raw]
Subject: [PATCH 02/10] wl12xx: use wiphy values for setting rts, frag thresholds on init

Use the wiphy RTS and fragmentation thresholds for initializing the FW
when possible. This mitigates a bug where previously set values are
forgotten after interface down/up.

Add checks before settings these values to ensure they are valid. Use
default values when invalid thresholds are configured.

Update the default RTS threshold to the maximum value given by the
specification.

Signed-off-by: Arik Nemtsov <[email protected]>
---
drivers/net/wireless/wl12xx/acx.c | 26 ++++++++++++++++++++------
drivers/net/wireless/wl12xx/acx.h | 4 ++--
drivers/net/wireless/wl12xx/init.c | 4 ++--
drivers/net/wireless/wl12xx/main.c | 6 +++---
4 files changed, 27 insertions(+), 13 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c
index cda546b..6a0fd18 100644
--- a/drivers/net/wireless/wl12xx/acx.c
+++ b/drivers/net/wireless/wl12xx/acx.c
@@ -325,12 +325,19 @@ out:
return ret;
}

-int wl1271_acx_rts_threshold(struct wl1271 *wl, u16 rts_threshold)
+int wl1271_acx_rts_threshold(struct wl1271 *wl, u32 rts_threshold)
{
struct acx_rts_threshold *rts;
int ret;

- wl1271_debug(DEBUG_ACX, "acx rts threshold");
+ /*
+ * If the RTS threshold is not configured or out of range, use the
+ * default value.
+ */
+ if (rts_threshold > IEEE80211_MAX_RTS_THRESHOLD)
+ rts_threshold = wl->conf.rx.rts_threshold;
+
+ wl1271_debug(DEBUG_ACX, "acx rts threshold: %d", rts_threshold);

rts = kzalloc(sizeof(*rts), GFP_KERNEL);
if (!rts) {
@@ -338,7 +345,7 @@ int wl1271_acx_rts_threshold(struct wl1271 *wl, u16 rts_threshold)
goto out;
}

- rts->threshold = cpu_to_le16(rts_threshold);
+ rts->threshold = cpu_to_le16((u16)rts_threshold);

ret = wl1271_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts));
if (ret < 0) {
@@ -928,12 +935,19 @@ out:
return ret;
}

-int wl1271_acx_frag_threshold(struct wl1271 *wl, u16 frag_threshold)
+int wl1271_acx_frag_threshold(struct wl1271 *wl, u32 frag_threshold)
{
struct acx_frag_threshold *acx;
int ret = 0;

- wl1271_debug(DEBUG_ACX, "acx frag threshold");
+ /*
+ * If the fragmentation is not configured or out of range, use the
+ * default value.
+ */
+ if (frag_threshold > IEEE80211_MAX_FRAG_THRESHOLD)
+ frag_threshold = wl->conf.tx.frag_threshold;
+
+ wl1271_debug(DEBUG_ACX, "acx frag threshold: %d", frag_threshold);

acx = kzalloc(sizeof(*acx), GFP_KERNEL);

@@ -942,7 +956,7 @@ int wl1271_acx_frag_threshold(struct wl1271 *wl, u16 frag_threshold)
goto out;
}

- acx->frag_threshold = cpu_to_le16(frag_threshold);
+ acx->frag_threshold = cpu_to_le16((u16)frag_threshold);
ret = wl1271_cmd_configure(wl, ACX_FRAG_CFG, acx, sizeof(*acx));
if (ret < 0) {
wl1271_warning("Setting of frag threshold failed: %d", ret);
diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h
index b35ebf5..31cb8c2 100644
--- a/drivers/net/wireless/wl12xx/acx.h
+++ b/drivers/net/wireless/wl12xx/acx.h
@@ -1266,7 +1266,7 @@ 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, u16 rts_threshold);
+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);
@@ -1290,7 +1290,7 @@ int wl1271_acx_ac_cfg(struct wl1271 *wl, u8 ac, u8 cw_min, u16 cw_max,
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, u16 frag_threshold);
+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);
diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c
index e8c979d..40015d0 100644
--- a/drivers/net/wireless/wl12xx/init.c
+++ b/drivers/net/wireless/wl12xx/init.c
@@ -258,7 +258,7 @@ int wl1271_init_phy_config(struct wl1271 *wl)
if (ret < 0)
return ret;

- ret = wl1271_acx_rts_threshold(wl, wl->conf.rx.rts_threshold);
+ ret = wl1271_acx_rts_threshold(wl, wl->hw->wiphy->rts_threshold);
if (ret < 0)
return ret;

@@ -605,7 +605,7 @@ int wl1271_hw_init(struct wl1271 *wl)
goto out_free_memmap;

/* Default fragmentation threshold */
- ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
+ ret = wl1271_acx_frag_threshold(wl, wl->hw->wiphy->frag_threshold);
if (ret < 0)
goto out_free_memmap;

diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index 1c206ae..a2a26df 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -163,7 +163,7 @@ static struct conf_drv_settings default_conf = {
.packet_detection_threshold = 0,
.ps_poll_timeout = 15,
.upsd_timeout = 15,
- .rts_threshold = 2347,
+ .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD,
.rx_cca_threshold = 0,
.irq_blk_threshold = 0xFFFF,
.irq_pkt_threshold = 0,
@@ -2337,7 +2337,7 @@ static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
if (ret < 0)
goto out;

- ret = wl1271_acx_frag_threshold(wl, (u16)value);
+ ret = wl1271_acx_frag_threshold(wl, value);
if (ret < 0)
wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);

@@ -2365,7 +2365,7 @@ static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
if (ret < 0)
goto out;

- ret = wl1271_acx_rts_threshold(wl, (u16) value);
+ ret = wl1271_acx_rts_threshold(wl, value);
if (ret < 0)
wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);

--
1.7.1


2011-04-18 11:15:50

by Arik Nemtsov

[permalink] [raw]
Subject: [PATCH 03/10] wl12xx: AP-mode - disable beacon filtering on start up

New AP-mode FWs filter external beacons by default. Disable this
filtering on start up so we can properly configure ERP protection.

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

diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c
index 6a0fd18..e9bc995 100644
--- a/drivers/net/wireless/wl12xx/acx.c
+++ b/drivers/net/wireless/wl12xx/acx.c
@@ -1646,3 +1646,28 @@ 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;
+}
diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h
index 31cb8c2..abbb214 100644
--- a/drivers/net/wireless/wl12xx/acx.h
+++ b/drivers/net/wireless/wl12xx/acx.h
@@ -303,7 +303,6 @@ struct acx_beacon_filter_option {
struct acx_header header;

u8 enable;
-
/*
* The number of beacons without the unicast TIM
* bit set that the firmware buffers before
@@ -1181,6 +1180,13 @@ struct wl1271_acx_inconnection_sta {
u8 padding1[2];
} __packed;

+struct acx_ap_beacon_filter {
+ struct acx_header header;
+
+ u8 enable;
+ u8 pad[3];
+} __packed;
+
enum {
ACX_WAKE_UP_CONDITIONS = 0x0002,
ACX_MEM_CFG = 0x0003,
@@ -1199,6 +1205,7 @@ enum {
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,
@@ -1320,5 +1327,6 @@ int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime);
int wl1271_acx_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);

#endif /* __WL1271_ACX_H__ */
diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c
index 40015d0..645f740 100644
--- a/drivers/net/wireless/wl12xx/init.c
+++ b/drivers/net/wireless/wl12xx/init.c
@@ -466,6 +466,14 @@ static int wl1271_ap_hw_init_post_mem(struct wl1271 *wl)
if (ret < 0)
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);
+ if (ret < 0)
+ return ret;
+
return 0;
}

--
1.7.1


2011-05-02 08:18:17

by Luciano Coelho

[permalink] [raw]
Subject: Re: [PATCH 01/10] wl12xx: add BT-coexistance for AP

On Sat, 2011-04-30 at 00:17 +0300, Luciano Coelho wrote:
> On Fri, 2011-04-29 at 23:02 +0300, Luciano Coelho wrote:
> > On Mon, 2011-04-18 at 14:15 +0300, Arik Nemtsov wrote:
> > > Initialize AP specific BT coexitance parameters to default values and
> > > enable them in AP mode.
> > >
> > > Signed-off-by: Arik Nemtsov <[email protected]>
> > > ---
> >
> > Applied the whole series, thanks Arik!
>
> Ooops, these didn't go in yet. There were some conflicts and I have
> mistakenly kept them out. I'll merge them and add them soon.

Okay, now this patchset has been applied and pushed. I had to reset the
master and wl12xx-next branches. I'll send a separate email telling
about that.

--
Cheers,
Luca.