2014-12-29 06:24:19

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 01/13] wlcore: fix WLCORE_VENDOR_ATTR_GROUP_KEY policy

The attribute type is binary data (with max length).

Signed-off-by: Eliad Peller <[email protected]>
---
drivers/net/wireless/ti/wlcore/vendor_cmd.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ti/wlcore/vendor_cmd.c b/drivers/net/wireless/ti/wlcore/vendor_cmd.c
index ad86a48..fd4e9ba 100644
--- a/drivers/net/wireless/ti/wlcore/vendor_cmd.c
+++ b/drivers/net/wireless/ti/wlcore/vendor_cmd.c
@@ -21,7 +21,7 @@ static const
struct nla_policy wlcore_vendor_attr_policy[NUM_WLCORE_VENDOR_ATTR] = {
[WLCORE_VENDOR_ATTR_FREQ] = { .type = NLA_U32 },
[WLCORE_VENDOR_ATTR_GROUP_ID] = { .type = NLA_U32 },
- [WLCORE_VENDOR_ATTR_GROUP_KEY] = { .type = NLA_U32,
+ [WLCORE_VENDOR_ATTR_GROUP_KEY] = { .type = NLA_BINARY,
.len = WLAN_MAX_KEY_LEN },
};

--
1.8.5.2.229.g4448466.dirty



2014-12-29 06:24:29

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 07/13] wl18xx: add radar detection implementation

Add support for CAC start/stop commands, and pass
radar detection events from the fw to mac80211.

Bump fw name (to wl18xx-fw-4.bin) and min fw version
(to 8.9.*.*.11), and align event mailbox accordingly.

Signed-off-by: Guy Mishol <[email protected]>
Signed-off-by: Eliad Peller <[email protected]>
---
drivers/net/wireless/ti/wl18xx/cmd.c | 31 ++++++
drivers/net/wireless/ti/wl18xx/cmd.h | 11 +++
drivers/net/wireless/ti/wl18xx/event.c | 21 ++++
drivers/net/wireless/ti/wl18xx/event.h | 14 ++-
drivers/net/wireless/ti/wl18xx/main.c | 4 +-
drivers/net/wireless/ti/wl18xx/wl18xx.h | 4 +-
drivers/net/wireless/ti/wlcore/cmd.c | 3 +-
drivers/net/wireless/ti/wlcore/cmd.h | 6 ++
drivers/net/wireless/ti/wlcore/hw_ops.h | 9 ++
drivers/net/wireless/ti/wlcore/main.c | 159 +++++++++++++++++++++++++++++-
drivers/net/wireless/ti/wlcore/wlcore.h | 2 +
drivers/net/wireless/ti/wlcore/wlcore_i.h | 2 +
12 files changed, 257 insertions(+), 9 deletions(-)

diff --git a/drivers/net/wireless/ti/wl18xx/cmd.c b/drivers/net/wireless/ti/wl18xx/cmd.c
index 44f0b20..10f9d1c 100644
--- a/drivers/net/wireless/ti/wl18xx/cmd.c
+++ b/drivers/net/wireless/ti/wl18xx/cmd.c
@@ -167,3 +167,34 @@ out_free:
out:
return ret;
}
+
+int wl18xx_cmd_set_cac(struct wl1271 *wl, struct wl12xx_vif *wlvif, bool start)
+{
+ struct wlcore_cmd_cac_start *cmd;
+ int ret = 0;
+
+ wl1271_debug(DEBUG_CMD, "cmd cac (channel %d) %s",
+ wlvif->channel, start ? "start" : "stop");
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd)
+ return -ENOMEM;
+
+ cmd->role_id = wlvif->role_id;
+ cmd->channel = wlvif->channel;
+ if (wlvif->band == IEEE80211_BAND_5GHZ)
+ cmd->band = WLCORE_BAND_5GHZ;
+ cmd->bandwidth = wlcore_get_native_channel_type(wlvif->channel_type);
+
+ ret = wl1271_cmd_send(wl,
+ start ? CMD_CAC_START : CMD_CAC_STOP,
+ cmd, sizeof(*cmd), 0);
+ if (ret < 0) {
+ wl1271_error("failed to send cac command");
+ goto out_free;
+ }
+
+out_free:
+ kfree(cmd);
+ return ret;
+}
diff --git a/drivers/net/wireless/ti/wl18xx/cmd.h b/drivers/net/wireless/ti/wl18xx/cmd.h
index 92499e2..91b3e2f 100644
--- a/drivers/net/wireless/ti/wl18xx/cmd.h
+++ b/drivers/net/wireless/ti/wl18xx/cmd.h
@@ -59,6 +59,16 @@ struct wl18xx_cmd_smart_config_set_group_key {
u8 key[16];
} __packed;

+/* cac_start and cac_stop share the same params */
+struct wlcore_cmd_cac_start {
+ struct wl1271_cmd_header header;
+
+ u8 role_id;
+ u8 channel;
+ u8 band;
+ u8 bandwidth;
+} __packed;
+
int wl18xx_cmd_channel_switch(struct wl1271 *wl,
struct wl12xx_vif *wlvif,
struct ieee80211_channel_switch *ch_switch);
@@ -66,4 +76,5 @@ int wl18xx_cmd_smart_config_start(struct wl1271 *wl, u32 group_bitmap);
int wl18xx_cmd_smart_config_stop(struct wl1271 *wl);
int wl18xx_cmd_smart_config_set_group_key(struct wl1271 *wl, u16 group_id,
u8 key_len, u8 *key);
+int wl18xx_cmd_set_cac(struct wl1271 *wl, struct wl12xx_vif *wlvif, bool start);
#endif
diff --git a/drivers/net/wireless/ti/wl18xx/event.c b/drivers/net/wireless/ti/wl18xx/event.c
index eb1848e..c28f068 100644
--- a/drivers/net/wireless/ti/wl18xx/event.c
+++ b/drivers/net/wireless/ti/wl18xx/event.c
@@ -47,6 +47,19 @@ int wl18xx_wait_for_event(struct wl1271 *wl, enum wlcore_wait_event event,
return wlcore_cmd_wait_for_event_or_timeout(wl, local_event, timeout);
}

+static const char *wl18xx_radar_type_decode(u8 radar_type)
+{
+ switch (radar_type) {
+ case RADAR_TYPE_REGULAR:
+ return "REGULAR";
+ case RADAR_TYPE_CHIRP:
+ return "CHIRP";
+ case RADAR_TYPE_NONE:
+ default:
+ return "N/A";
+ }
+}
+
static int wlcore_smart_config_sync_event(struct wl1271 *wl, u8 sync_channel,
u8 sync_band)
{
@@ -115,6 +128,14 @@ int wl18xx_process_mailbox_events(struct wl1271 *wl)
wl18xx_scan_completed(wl, wl->scan_wlvif);
}

+ if (vector & RADAR_DETECTED_EVENT_ID) {
+ wl1271_info("radar event: channel %d type %s",
+ mbox->radar_channel,
+ wl18xx_radar_type_decode(mbox->radar_type));
+
+ ieee80211_radar_detected(wl->hw);
+ }
+
if (vector & PERIODIC_SCAN_REPORT_EVENT_ID) {
wl1271_debug(DEBUG_EVENT,
"PERIODIC_SCAN_REPORT_EVENT (results %d)",
diff --git a/drivers/net/wireless/ti/wl18xx/event.h b/drivers/net/wireless/ti/wl18xx/event.h
index 0680312..266ee87 100644
--- a/drivers/net/wireless/ti/wl18xx/event.h
+++ b/drivers/net/wireless/ti/wl18xx/event.h
@@ -42,6 +42,12 @@ enum {
SMART_CONFIG_DECODE_EVENT_ID = BIT(23),
};

+enum wl18xx_radar_types {
+ RADAR_TYPE_NONE,
+ RADAR_TYPE_REGULAR,
+ RADAR_TYPE_CHIRP
+};
+
struct wl18xx_event_mailbox {
__le32 events_vector;

@@ -83,13 +89,19 @@ struct wl18xx_event_mailbox {
u8 sc_token_len;
u8 padding1;
u8 sc_ssid[32];
- u8 sc_pwd[32];
+ u8 sc_pwd[64];
u8 sc_token[32];

/* smart config sync channel */
u8 sc_sync_channel;
u8 sc_sync_band;
u8 padding2[2];
+
+ /* radar detect */
+ u8 radar_channel;
+ u8 radar_type;
+
+ u8 padding3[2];
} __packed;

int wl18xx_wait_for_event(struct wl1271 *wl, enum wlcore_wait_event event,
diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c
index 9e648a1..48f7628 100644
--- a/drivers/net/wireless/ti/wl18xx/main.c
+++ b/drivers/net/wireless/ti/wl18xx/main.c
@@ -655,7 +655,7 @@ static const struct wl18xx_clk_cfg wl18xx_clk_table[NUM_CLOCK_CONFIGS] = {
};

/* TODO: maybe move to a new header file? */
-#define WL18XX_FW_NAME "ti-connectivity/wl18xx-fw-3.bin"
+#define WL18XX_FW_NAME "ti-connectivity/wl18xx-fw-4.bin"

static int wl18xx_identify_chip(struct wl1271 *wl)
{
@@ -990,6 +990,7 @@ static int wl18xx_boot(struct wl1271 *wl)

wl->event_mask = BSS_LOSS_EVENT_ID |
SCAN_COMPLETE_EVENT_ID |
+ RADAR_DETECTED_EVENT_ID |
RSSI_SNR_TRIGGER_0_EVENT_ID |
PERIODIC_SCAN_COMPLETE_EVENT_ID |
PERIODIC_SCAN_REPORT_EVENT_ID |
@@ -1703,6 +1704,7 @@ static struct wlcore_ops wl18xx_ops = {
.interrupt_notify = wl18xx_acx_interrupt_notify_config,
.rx_ba_filter = wl18xx_acx_rx_ba_filter,
.ap_sleep = wl18xx_acx_ap_sleep,
+ .set_cac = wl18xx_cmd_set_cac,
};

/* HT cap appropriate for wide channels in 2Ghz */
diff --git a/drivers/net/wireless/ti/wl18xx/wl18xx.h b/drivers/net/wireless/ti/wl18xx/wl18xx.h
index 6a2b880..71e9e38 100644
--- a/drivers/net/wireless/ti/wl18xx/wl18xx.h
+++ b/drivers/net/wireless/ti/wl18xx/wl18xx.h
@@ -26,10 +26,10 @@

/* minimum FW required for driver */
#define WL18XX_CHIP_VER 8
-#define WL18XX_IFTYPE_VER 8
+#define WL18XX_IFTYPE_VER 9
#define WL18XX_MAJOR_VER WLCORE_FW_VER_IGNORE
#define WL18XX_SUBTYPE_VER WLCORE_FW_VER_IGNORE
-#define WL18XX_MINOR_VER 13
+#define WL18XX_MINOR_VER 11

#define WL18XX_CMD_MAX_SIZE 740

diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c
index b826619..aacad4e 100644
--- a/drivers/net/wireless/ti/wlcore/cmd.c
+++ b/drivers/net/wireless/ti/wlcore/cmd.c
@@ -403,7 +403,7 @@ void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid)
WARN_ON_ONCE(wl->active_link_count < 0);
}

-static u8 wlcore_get_native_channel_type(u8 nl_channel_type)
+u8 wlcore_get_native_channel_type(u8 nl_channel_type)
{
switch (nl_channel_type) {
case NL80211_CHAN_NO_HT:
@@ -419,6 +419,7 @@ static u8 wlcore_get_native_channel_type(u8 nl_channel_type)
return WLCORE_CHAN_NO_HT;
}
}
+EXPORT_SYMBOL_GPL(wlcore_get_native_channel_type);

static int wl12xx_cmd_role_start_dev(struct wl1271 *wl,
struct wl12xx_vif *wlvif,
diff --git a/drivers/net/wireless/ti/wlcore/cmd.h b/drivers/net/wireless/ti/wlcore/cmd.h
index 453684a..06bdee2 100644
--- a/drivers/net/wireless/ti/wlcore/cmd.h
+++ b/drivers/net/wireless/ti/wlcore/cmd.h
@@ -105,6 +105,7 @@ int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif,
void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid);
int wlcore_cmd_wait_for_event_or_timeout(struct wl1271 *wl,
u32 mask, bool *timeout);
+u8 wlcore_get_native_channel_type(u8 nl_channel_type);

enum wl1271_commands {
CMD_INTERROGATE = 1, /* use this to read information elements */
@@ -172,6 +173,11 @@ enum wl1271_commands {
CMD_SMART_CONFIG_STOP = 62,
CMD_SMART_CONFIG_SET_GROUP_KEY = 63,

+ CMD_CAC_START = 64,
+ CMD_CAC_STOP = 65,
+ CMD_DFS_MASTER_RESTART = 66,
+ CMD_DFS_RADAR_DETECTION_DEBUG = 67,
+
MAX_COMMAND_ID = 0xFFFF,
};

diff --git a/drivers/net/wireless/ti/wlcore/hw_ops.h b/drivers/net/wireless/ti/wlcore/hw_ops.h
index 449050b..42fef84 100644
--- a/drivers/net/wireless/ti/wlcore/hw_ops.h
+++ b/drivers/net/wireless/ti/wlcore/hw_ops.h
@@ -311,4 +311,13 @@ wlcore_smart_config_set_group_key(struct wl1271 *wl, u16 group_id,

return wl->ops->smart_config_set_group_key(wl, group_id, key_len, key);
}
+
+static inline int
+wlcore_hw_set_cac(struct wl1271 *wl, struct wl12xx_vif *wlvif, bool start)
+{
+ if (!wl->ops->set_cac)
+ return -EINVAL;
+
+ return wl->ops->set_cac(wl, wlvif, start);
+}
#endif
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index 0d67e39..673bfc4 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -4630,10 +4630,46 @@ static void wlcore_op_change_chanctx(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *ctx,
u32 changed)
{
+ struct wl1271 *wl = hw->priv;
+ struct wl12xx_vif *wlvif;
+ int ret;
+ int channel = ieee80211_frequency_to_channel(
+ ctx->def.chan->center_freq);
+
wl1271_debug(DEBUG_MAC80211,
"mac80211 change chanctx %d (type %d) changed 0x%x",
- ieee80211_frequency_to_channel(ctx->def.chan->center_freq),
- cfg80211_get_chandef_type(&ctx->def), changed);
+ channel, cfg80211_get_chandef_type(&ctx->def), changed);
+
+ mutex_lock(&wl->mutex);
+
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
+ wl12xx_for_each_wlvif(wl, wlvif) {
+ struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
+
+ rcu_read_lock();
+ if (rcu_access_pointer(vif->chanctx_conf) != ctx) {
+ rcu_read_unlock();
+ continue;
+ }
+ rcu_read_unlock();
+
+ /* start radar if needed */
+ if (changed & IEEE80211_CHANCTX_CHANGE_RADAR &&
+ wlvif->bss_type == BSS_TYPE_AP_BSS &&
+ ctx->radar_enabled && !wlvif->radar_enabled &&
+ ctx->def.chan->dfs_state == NL80211_DFS_USABLE) {
+ wl1271_debug(DEBUG_MAC80211, "Start radar detection");
+ wlcore_hw_set_cac(wl, wlvif, true);
+ wlvif->radar_enabled = true;
+ }
+ }
+
+ wl1271_ps_elp_sleep(wl);
+out:
+ mutex_unlock(&wl->mutex);
}

static int wlcore_op_assign_vif_chanctx(struct ieee80211_hw *hw,
@@ -4644,13 +4680,26 @@ static int wlcore_op_assign_vif_chanctx(struct ieee80211_hw *hw,
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
int channel = ieee80211_frequency_to_channel(
ctx->def.chan->center_freq);
+ int ret = -EINVAL;

wl1271_debug(DEBUG_MAC80211,
- "mac80211 assign chanctx (role %d) %d (type %d)",
- wlvif->role_id, channel, cfg80211_get_chandef_type(&ctx->def));
+ "mac80211 assign chanctx (role %d) %d (type %d) (radar %d dfs_state %d)",
+ wlvif->role_id, channel,
+ cfg80211_get_chandef_type(&ctx->def),
+ ctx->radar_enabled, ctx->def.chan->dfs_state);

mutex_lock(&wl->mutex);

+ if (unlikely(wl->state != WLCORE_STATE_ON))
+ goto out;
+
+ if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)))
+ goto out;
+
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
wlvif->band = ctx->def.chan->band;
wlvif->channel = channel;
wlvif->channel_type = cfg80211_get_chandef_type(&ctx->def);
@@ -4658,6 +4707,15 @@ static int wlcore_op_assign_vif_chanctx(struct ieee80211_hw *hw,
/* update default rates according to the band */
wl1271_set_band_rate(wl, wlvif);

+ if (ctx->radar_enabled &&
+ ctx->def.chan->dfs_state == NL80211_DFS_USABLE) {
+ wl1271_debug(DEBUG_MAC80211, "Start radar detection");
+ wlcore_hw_set_cac(wl, wlvif, true);
+ wlvif->radar_enabled = true;
+ }
+
+ wl1271_ps_elp_sleep(wl);
+out:
mutex_unlock(&wl->mutex);

return 0;
@@ -4669,6 +4727,7 @@ static void wlcore_op_unassign_vif_chanctx(struct ieee80211_hw *hw,
{
struct wl1271 *wl = hw->priv;
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
+ int ret;

wl1271_debug(DEBUG_MAC80211,
"mac80211 unassign chanctx (role %d) %d (type %d)",
@@ -4677,6 +4736,97 @@ static void wlcore_op_unassign_vif_chanctx(struct ieee80211_hw *hw,
cfg80211_get_chandef_type(&ctx->def));

wl1271_tx_flush(wl);
+
+ mutex_lock(&wl->mutex);
+
+ if (unlikely(wl->state != WLCORE_STATE_ON))
+ goto out;
+
+ if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)))
+ goto out;
+
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
+ if (wlvif->radar_enabled) {
+ wl1271_debug(DEBUG_MAC80211, "Stop radar detection");
+ wlcore_hw_set_cac(wl, wlvif, false);
+ wlvif->radar_enabled = false;
+ }
+
+ wl1271_ps_elp_sleep(wl);
+out:
+ mutex_unlock(&wl->mutex);
+}
+
+static int __wlcore_switch_vif_chan(struct wl1271 *wl,
+ struct wl12xx_vif *wlvif,
+ struct ieee80211_chanctx_conf *new_ctx)
+{
+ int channel = ieee80211_frequency_to_channel(
+ new_ctx->def.chan->center_freq);
+
+ wl1271_debug(DEBUG_MAC80211,
+ "switch vif (role %d) %d -> %d chan_type: %d",
+ wlvif->role_id, wlvif->channel, channel,
+ cfg80211_get_chandef_type(&new_ctx->def));
+
+ if (WARN_ON_ONCE(wlvif->bss_type != BSS_TYPE_AP_BSS))
+ return 0;
+
+ if (wlvif->radar_enabled) {
+ wl1271_debug(DEBUG_MAC80211, "Stop radar detection");
+ wlcore_hw_set_cac(wl, wlvif, false);
+ wlvif->radar_enabled = false;
+ }
+
+ wlvif->band = new_ctx->def.chan->band;
+ wlvif->channel = channel;
+ wlvif->channel_type = cfg80211_get_chandef_type(&new_ctx->def);
+
+ /* start radar if needed */
+ if (new_ctx->radar_enabled) {
+ wl1271_debug(DEBUG_MAC80211, "Start radar detection");
+ wlcore_hw_set_cac(wl, wlvif, true);
+ wlvif->radar_enabled = true;
+ }
+
+ return 0;
+}
+
+static int
+wlcore_op_switch_vif_chanctx(struct ieee80211_hw *hw,
+ struct ieee80211_vif_chanctx_switch *vifs,
+ int n_vifs,
+ enum ieee80211_chanctx_switch_mode mode)
+{
+ struct wl1271 *wl = hw->priv;
+ int i, ret;
+
+ wl1271_debug(DEBUG_MAC80211,
+ "mac80211 switch chanctx n_vifs %d mode %d",
+ n_vifs, mode);
+
+ mutex_lock(&wl->mutex);
+
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
+ for (i = 0; i < n_vifs; i++) {
+ struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vifs[i].vif);
+
+ ret = __wlcore_switch_vif_chan(wl, wlvif, vifs[i].new_ctx);
+ if (ret)
+ goto out_sleep;
+ }
+out_sleep:
+ wl1271_ps_elp_sleep(wl);
+out:
+ mutex_unlock(&wl->mutex);
+
+ return 0;
}

static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
@@ -5666,6 +5816,7 @@ static const struct ieee80211_ops wl1271_ops = {
.change_chanctx = wlcore_op_change_chanctx,
.assign_vif_chanctx = wlcore_op_assign_vif_chanctx,
.unassign_vif_chanctx = wlcore_op_unassign_vif_chanctx,
+ .switch_vif_chanctx = wlcore_op_switch_vif_chanctx,
.sta_rc_update = wlcore_op_sta_rc_update,
.get_rssi = wlcore_op_get_rssi,
CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h
index c8fe2ae..caee58f 100644
--- a/drivers/net/wireless/ti/wlcore/wlcore.h
+++ b/drivers/net/wireless/ti/wlcore/wlcore.h
@@ -123,6 +123,8 @@ struct wlcore_ops {
int (*smart_config_stop)(struct wl1271 *wl);
int (*smart_config_set_group_key)(struct wl1271 *wl, u16 group_id,
u8 key_len, u8 *key);
+ int (*set_cac)(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ bool start);
};

enum wlcore_partitions {
diff --git a/drivers/net/wireless/ti/wlcore/wlcore_i.h b/drivers/net/wireless/ti/wlcore/wlcore_i.h
index 811851d..b2bdb13 100644
--- a/drivers/net/wireless/ti/wlcore/wlcore_i.h
+++ b/drivers/net/wireless/ti/wlcore/wlcore_i.h
@@ -434,6 +434,8 @@ struct wl12xx_vif {

bool wmm_enabled;

+ bool radar_enabled;
+
/* Rx Streaming */
struct work_struct rx_streaming_enable_work;
struct work_struct rx_streaming_disable_work;
--
1.8.5.2.229.g4448466.dirty


2014-12-29 06:24:34

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 10/13] wlcore: add dfs master restart calls

call wlcore_cmd_dfs_master_restart when starting
the ap on a new channel (after csa is done).

Add a new WLVIF_FLAG_BEACON_DISABLED flag to
indicate that dfs_master_restart command
is required.

Signed-off-by: Eliad Peller <[email protected]>
---
drivers/net/wireless/ti/wl18xx/cmd.c | 25 +++++++++++++++++++++++++
drivers/net/wireless/ti/wl18xx/cmd.h | 8 ++++++++
drivers/net/wireless/ti/wl18xx/main.c | 1 +
drivers/net/wireless/ti/wlcore/event.c | 1 +
drivers/net/wireless/ti/wlcore/hw_ops.h | 9 +++++++++
drivers/net/wireless/ti/wlcore/main.c | 10 +++++++++-
drivers/net/wireless/ti/wlcore/wlcore.h | 1 +
drivers/net/wireless/ti/wlcore/wlcore_i.h | 1 +
8 files changed, 55 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ti/wl18xx/cmd.c b/drivers/net/wireless/ti/wl18xx/cmd.c
index 5731950..a8d176d 100644
--- a/drivers/net/wireless/ti/wl18xx/cmd.c
+++ b/drivers/net/wireless/ti/wl18xx/cmd.c
@@ -229,3 +229,28 @@ out_free:
kfree(cmd);
return ret;
}
+
+int wl18xx_cmd_dfs_master_restart(struct wl1271 *wl, struct wl12xx_vif *wlvif)
+{
+ struct wl18xx_cmd_dfs_master_restart *cmd;
+ int ret = 0;
+
+ wl1271_debug(DEBUG_CMD, "cmd dfs master restart (role %d)",
+ wlvif->role_id);
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd)
+ return -ENOMEM;
+
+ cmd->role_id = wlvif->role_id;
+
+ ret = wl1271_cmd_send(wl, CMD_DFS_MASTER_RESTART,
+ cmd, sizeof(*cmd), 0);
+ if (ret < 0) {
+ wl1271_error("failed to send dfs master restart command");
+ goto out_free;
+ }
+out_free:
+ kfree(cmd);
+ return ret;
+}
diff --git a/drivers/net/wireless/ti/wl18xx/cmd.h b/drivers/net/wireless/ti/wl18xx/cmd.h
index 0809b92..7f9440a 100644
--- a/drivers/net/wireless/ti/wl18xx/cmd.h
+++ b/drivers/net/wireless/ti/wl18xx/cmd.h
@@ -66,6 +66,13 @@ struct wl18xx_cmd_dfs_radar_debug {
u8 padding[3];
} __packed;

+struct wl18xx_cmd_dfs_master_restart {
+ struct wl1271_cmd_header header;
+
+ u8 role_id;
+ u8 padding[3];
+} __packed;
+
/* cac_start and cac_stop share the same params */
struct wlcore_cmd_cac_start {
struct wl1271_cmd_header header;
@@ -85,4 +92,5 @@ int wl18xx_cmd_smart_config_set_group_key(struct wl1271 *wl, u16 group_id,
u8 key_len, u8 *key);
int wl18xx_cmd_set_cac(struct wl1271 *wl, struct wl12xx_vif *wlvif, bool start);
int wl18xx_cmd_radar_detection_debug(struct wl1271 *wl, u8 channel);
+int wl18xx_cmd_dfs_master_restart(struct wl1271 *wl, struct wl12xx_vif *wlvif);
#endif
diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c
index 48f7628..604de24 100644
--- a/drivers/net/wireless/ti/wl18xx/main.c
+++ b/drivers/net/wireless/ti/wl18xx/main.c
@@ -1705,6 +1705,7 @@ static struct wlcore_ops wl18xx_ops = {
.rx_ba_filter = wl18xx_acx_rx_ba_filter,
.ap_sleep = wl18xx_acx_ap_sleep,
.set_cac = wl18xx_cmd_set_cac,
+ .dfs_master_restart = wl18xx_cmd_dfs_master_restart,
};

/* HT cap appropriate for wide channels in 2Ghz */
diff --git a/drivers/net/wireless/ti/wlcore/event.c b/drivers/net/wireless/ti/wlcore/event.c
index 69a2661..c42e789 100644
--- a/drivers/net/wireless/ti/wlcore/event.c
+++ b/drivers/net/wireless/ti/wlcore/event.c
@@ -154,6 +154,7 @@ void wlcore_event_channel_switch(struct wl1271 *wl,
ieee80211_chswitch_done(vif, success);
cancel_delayed_work(&wlvif->channel_switch_work);
} else {
+ set_bit(WLVIF_FLAG_BEACON_DISABLED, &wlvif->flags);
ieee80211_csa_finish(vif);
}
}
diff --git a/drivers/net/wireless/ti/wlcore/hw_ops.h b/drivers/net/wireless/ti/wlcore/hw_ops.h
index 42fef84..eec5693 100644
--- a/drivers/net/wireless/ti/wlcore/hw_ops.h
+++ b/drivers/net/wireless/ti/wlcore/hw_ops.h
@@ -320,4 +320,13 @@ wlcore_hw_set_cac(struct wl1271 *wl, struct wl12xx_vif *wlvif, bool start)

return wl->ops->set_cac(wl, wlvif, start);
}
+
+static inline int
+wlcore_hw_dfs_master_restart(struct wl1271 *wl, struct wl12xx_vif *wlvif)
+{
+ if (!wl->ops->dfs_master_restart)
+ return -EINVAL;
+
+ return wl->ops->dfs_master_restart(wl, wlvif);
+}
#endif
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index 9a35f30..362515f 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -4128,8 +4128,14 @@ static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
ret = wlcore_set_beacon_template(wl, vif, is_ap);
if (ret < 0)
goto out;
- }

+ if (test_and_clear_bit(WLVIF_FLAG_BEACON_DISABLED,
+ &wlvif->flags)) {
+ ret = wlcore_hw_dfs_master_restart(wl, wlvif);
+ if (ret < 0)
+ goto out;
+ }
+ }
out:
if (ret != 0)
wl1271_error("beacon info change failed: %d", ret);
@@ -4775,6 +4781,8 @@ static int __wlcore_switch_vif_chan(struct wl1271 *wl,
if (WARN_ON_ONCE(wlvif->bss_type != BSS_TYPE_AP_BSS))
return 0;

+ WARN_ON(!test_bit(WLVIF_FLAG_BEACON_DISABLED, &wlvif->flags));
+
if (wlvif->radar_enabled) {
wl1271_debug(DEBUG_MAC80211, "Stop radar detection");
wlcore_hw_set_cac(wl, wlvif, false);
diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h
index caee58f..581c479 100644
--- a/drivers/net/wireless/ti/wlcore/wlcore.h
+++ b/drivers/net/wireless/ti/wlcore/wlcore.h
@@ -125,6 +125,7 @@ struct wlcore_ops {
u8 key_len, u8 *key);
int (*set_cac)(struct wl1271 *wl, struct wl12xx_vif *wlvif,
bool start);
+ int (*dfs_master_restart)(struct wl1271 *wl, struct wl12xx_vif *wlvif);
};

enum wlcore_partitions {
diff --git a/drivers/net/wireless/ti/wlcore/wlcore_i.h b/drivers/net/wireless/ti/wlcore/wlcore_i.h
index b2bdb13..3396ce5 100644
--- a/drivers/net/wireless/ti/wlcore/wlcore_i.h
+++ b/drivers/net/wireless/ti/wlcore/wlcore_i.h
@@ -251,6 +251,7 @@ enum wl12xx_vif_flags {
WLVIF_FLAG_AP_PROBE_RESP_SET,
WLVIF_FLAG_IN_USE,
WLVIF_FLAG_ACTIVE,
+ WLVIF_FLAG_BEACON_DISABLED,
};

struct wl12xx_vif;
--
1.8.5.2.229.g4448466.dirty


2014-12-29 06:24:38

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 13/13] wl18xx: declare radar_detect_widths support for ap interfaces

After having all the dfs infrastructure in place, declare
radar_detect_widths support for the ap interfaces combination.

Signed-off-by: Eliad Peller <[email protected]>
---
drivers/net/wireless/ti/wl18xx/main.c | 4 ++++
1 file changed, 4 insertions(+)

diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c
index 604de24..e5bc557 100644
--- a/drivers/net/wireless/ti/wl18xx/main.c
+++ b/drivers/net/wireless/ti/wl18xx/main.c
@@ -1799,6 +1799,10 @@ wl18xx_iface_combinations[] = {
.limits = wl18xx_iface_ap_limits,
.n_limits = ARRAY_SIZE(wl18xx_iface_ap_limits),
.num_different_channels = 1,
+ .radar_detect_widths = BIT(NL80211_CHAN_NO_HT) |
+ BIT(NL80211_CHAN_HT20) |
+ BIT(NL80211_CHAN_HT40MINUS) |
+ BIT(NL80211_CHAN_HT40PLUS),
}
};

--
1.8.5.2.229.g4448466.dirty


2014-12-29 06:24:25

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 04/13] wlcore: add ability to reduce FW interrupts during suspend

From: Ram Amrani <[email protected]>

Add the ability to mask FW interrupts on RX BA activity, PSM
entry/exit and fast-link notifications. This is used when the host
is suspended in order to decrease redundant wake ups.

Signed-off-by: Ram Amrani <[email protected]>
Signed-off-by: Arik Nemtsov <[email protected]>
Signed-off-by: Eliad Peller <[email protected]>
---
drivers/net/wireless/ti/wl12xx/main.c | 3 ++
drivers/net/wireless/ti/wl18xx/acx.c | 56 +++++++++++++++++++++++++++
drivers/net/wireless/ti/wl18xx/acx.h | 25 +++++++++++-
drivers/net/wireless/ti/wl18xx/main.c | 3 ++
drivers/net/wireless/ti/wlcore/conf.h | 7 +++-
drivers/net/wireless/ti/wlcore/hw_ops.h | 16 ++++++++
drivers/net/wireless/ti/wlcore/main.c | 68 ++++++++++++++++++++++-----------
drivers/net/wireless/ti/wlcore/wlcore.h | 2 +
8 files changed, 155 insertions(+), 25 deletions(-)

diff --git a/drivers/net/wireless/ti/wl12xx/main.c b/drivers/net/wireless/ti/wl12xx/main.c
index 0bccf12..b457069 100644
--- a/drivers/net/wireless/ti/wl12xx/main.c
+++ b/drivers/net/wireless/ti/wl12xx/main.c
@@ -250,6 +250,7 @@ static struct wlcore_conf wl12xx_conf = {
.keep_alive_interval = 55000,
.max_listen_interval = 20,
.sta_sleep_auth = WL1271_PSM_ILLEGAL,
+ .suspend_rx_ba_activity = 0,
},
.itrim = {
.enable = false,
@@ -1728,6 +1729,8 @@ static struct wlcore_ops wl12xx_ops = {
.convert_hwaddr = wl12xx_convert_hwaddr,
.lnk_high_prio = wl12xx_lnk_high_prio,
.lnk_low_prio = wl12xx_lnk_low_prio,
+ .interrupt_notify = NULL,
+ .rx_ba_filter = NULL,
};

static struct ieee80211_sta_ht_cap wl12xx_ht_cap = {
diff --git a/drivers/net/wireless/ti/wl18xx/acx.c b/drivers/net/wireless/ti/wl18xx/acx.c
index a169bb5..9d4b9aa 100644
--- a/drivers/net/wireless/ti/wl18xx/acx.c
+++ b/drivers/net/wireless/ti/wl18xx/acx.c
@@ -194,3 +194,59 @@ out:
kfree(acx);
return ret;
}
+
+/*
+ * When the host is suspended, we don't want to get any fast-link/PSM
+ * notifications
+ */
+int wl18xx_acx_interrupt_notify_config(struct wl1271 *wl,
+ bool action)
+{
+ struct wl18xx_acx_interrupt_notify *acx;
+ int ret = 0;
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ acx->enable = action;
+ ret = wl1271_cmd_configure(wl, ACX_INTERRUPT_NOTIFY, acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1271_warning("acx interrupt notify setting failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
+
+/*
+ * When the host is suspended, we can configure the FW to disable RX BA
+ * notifications.
+ */
+int wl18xx_acx_rx_ba_filter(struct wl1271 *wl, bool action)
+{
+ struct wl18xx_acx_rx_ba_filter *acx;
+ int ret = 0;
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ acx->enable = (u32)action;
+ ret = wl1271_cmd_configure(wl, ACX_RX_BA_FILTER, acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1271_warning("acx rx ba activity filter setting failed: %d",
+ ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
diff --git a/drivers/net/wireless/ti/wl18xx/acx.h b/drivers/net/wireless/ti/wl18xx/acx.h
index 0e636de..1234bdc 100644
--- a/drivers/net/wireless/ti/wl18xx/acx.h
+++ b/drivers/net/wireless/ti/wl18xx/acx.h
@@ -32,7 +32,10 @@ enum {
ACX_SIM_CONFIG = 0x0053,
ACX_CLEAR_STATISTICS = 0x0054,
ACX_AUTO_RX_STREAMING = 0x0055,
- ACX_PEER_CAP = 0x0056
+ ACX_PEER_CAP = 0x0056,
+ ACX_INTERRUPT_NOTIFY = 0x0057,
+ ACX_RX_BA_FILTER = 0x0058
+
};

/* numbers of bits the length field takes (add 1 for the actual number) */
@@ -326,6 +329,24 @@ struct wlcore_acx_peer_cap {
u8 padding;
} __packed;

+/*
+ * ACX_INTERRUPT_NOTIFY
+ * enable/disable fast-link/PSM notification from FW
+ */
+struct wl18xx_acx_interrupt_notify {
+ struct acx_header header;
+ u32 enable;
+};
+
+/*
+ * ACX_RX_BA_FILTER
+ * enable/disable RX BA filtering in FW
+ */
+struct wl18xx_acx_rx_ba_filter {
+ struct acx_header header;
+ u32 enable;
+};
+
int wl18xx_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap,
u32 sdio_blk_size, u32 extra_mem_blks,
u32 len_field_size);
@@ -336,5 +357,7 @@ int wl18xx_acx_set_peer_cap(struct wl1271 *wl,
struct ieee80211_sta_ht_cap *ht_cap,
bool allow_ht_operation,
u32 rate_set, u8 hlid);
+int wl18xx_acx_interrupt_notify_config(struct wl1271 *wl, bool action);
+int wl18xx_acx_rx_ba_filter(struct wl1271 *wl, bool action);

#endif /* __WL18XX_ACX_H__ */
diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c
index 6946d18..7edb8a1 100644
--- a/drivers/net/wireless/ti/wl18xx/main.c
+++ b/drivers/net/wireless/ti/wl18xx/main.c
@@ -378,6 +378,7 @@ static struct wlcore_conf wl18xx_conf = {
.keep_alive_interval = 55000,
.max_listen_interval = 20,
.sta_sleep_auth = WL1271_PSM_ILLEGAL,
+ .suspend_rx_ba_activity = 0,
},
.itrim = {
.enable = false,
@@ -1693,6 +1694,8 @@ static struct wlcore_ops wl18xx_ops = {
.smart_config_start = wl18xx_cmd_smart_config_start,
.smart_config_stop = wl18xx_cmd_smart_config_stop,
.smart_config_set_group_key = wl18xx_cmd_smart_config_set_group_key,
+ .interrupt_notify = wl18xx_acx_interrupt_notify_config,
+ .rx_ba_filter = wl18xx_acx_rx_ba_filter,
};

/* HT cap appropriate for wide channels in 2Ghz */
diff --git a/drivers/net/wireless/ti/wlcore/conf.h b/drivers/net/wireless/ti/wlcore/conf.h
index 40995c4..166add0 100644
--- a/drivers/net/wireless/ti/wlcore/conf.h
+++ b/drivers/net/wireless/ti/wlcore/conf.h
@@ -997,6 +997,11 @@ struct conf_conn_settings {
* whether we can go to ELP.
*/
u8 sta_sleep_auth;
+
+ /*
+ * Default RX BA Activity filter configuration
+ */
+ u8 suspend_rx_ba_activity;
} __packed;

enum {
@@ -1347,7 +1352,7 @@ struct conf_recovery_settings {
* version, the two LSB are the lower driver's private conf
* version.
*/
-#define WLCORE_CONF_VERSION (0x0005 << 16)
+#define WLCORE_CONF_VERSION (0x0006 << 16)
#define WLCORE_CONF_MASK 0xffff0000
#define WLCORE_CONF_SIZE (sizeof(struct wlcore_conf_header) + \
sizeof(struct wlcore_conf))
diff --git a/drivers/net/wireless/ti/wlcore/hw_ops.h b/drivers/net/wireless/ti/wlcore/hw_ops.h
index 29ce55f..c2545ce 100644
--- a/drivers/net/wireless/ti/wlcore/hw_ops.h
+++ b/drivers/net/wireless/ti/wlcore/hw_ops.h
@@ -218,6 +218,22 @@ wlcore_hw_sta_rc_update(struct wl1271 *wl, struct wl12xx_vif *wlvif)
}

static inline int
+wlcore_hw_interrupt_notify(struct wl1271 *wl, bool action)
+{
+ if (wl->ops->interrupt_notify)
+ return wl->ops->interrupt_notify(wl, action);
+ return 0;
+}
+
+static inline int
+wlcore_hw_rx_ba_filter(struct wl1271 *wl, bool action)
+{
+ if (wl->ops->rx_ba_filter)
+ return wl->ops->rx_ba_filter(wl, action);
+ return 0;
+}
+
+static inline int
wlcore_hw_set_peer_cap(struct wl1271 *wl,
struct ieee80211_sta_ht_cap *ht_cap,
bool allow_ht_operation,
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index f6e37d5..aaa836b 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -1685,19 +1685,15 @@ static int wl1271_configure_suspend_sta(struct wl1271 *wl,
if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
goto out;

- ret = wl1271_ps_elp_wakeup(wl);
- if (ret < 0)
- goto out;
-
ret = wl1271_configure_wowlan(wl, wow);
if (ret < 0)
- goto out_sleep;
+ goto out;

if ((wl->conf.conn.suspend_wake_up_event ==
wl->conf.conn.wake_up_event) &&
(wl->conf.conn.suspend_listen_interval ==
wl->conf.conn.listen_interval))
- goto out_sleep;
+ goto out;

ret = wl1271_acx_wake_up_conditions(wl, wlvif,
wl->conf.conn.suspend_wake_up_event,
@@ -1705,9 +1701,6 @@ static int wl1271_configure_suspend_sta(struct wl1271 *wl,

if (ret < 0)
wl1271_error("suspend: set wake up conditions failed: %d", ret);
-
-out_sleep:
- wl1271_ps_elp_sleep(wl);
out:
return ret;

@@ -1721,13 +1714,8 @@ static int wl1271_configure_suspend_ap(struct wl1271 *wl,
if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
goto out;

- ret = wl1271_ps_elp_wakeup(wl);
- if (ret < 0)
- goto out;
-
ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);

- wl1271_ps_elp_sleep(wl);
out:
return ret;

@@ -1756,10 +1744,6 @@ static void wl1271_configure_resume(struct wl1271 *wl, struct wl12xx_vif *wlvif)
if (is_sta && !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
return;

- ret = wl1271_ps_elp_wakeup(wl);
- if (ret < 0)
- return;
-
if (is_sta) {
wl1271_configure_wowlan(wl, NULL);

@@ -1767,7 +1751,7 @@ static void wl1271_configure_resume(struct wl1271 *wl, struct wl12xx_vif *wlvif)
wl->conf.conn.wake_up_event) &&
(wl->conf.conn.suspend_listen_interval ==
wl->conf.conn.listen_interval))
- goto out_sleep;
+ return;

ret = wl1271_acx_wake_up_conditions(wl, wlvif,
wl->conf.conn.wake_up_event,
@@ -1780,9 +1764,6 @@ static void wl1271_configure_resume(struct wl1271 *wl, struct wl12xx_vif *wlvif)
} else if (is_ap) {
ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false);
}
-
-out_sleep:
- wl1271_ps_elp_sleep(wl);
}

static int wl1271_op_suspend(struct ieee80211_hw *hw,
@@ -1804,6 +1785,11 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw,
wl1271_tx_flush(wl);

mutex_lock(&wl->mutex);
+
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0)
+ return ret;
+
wl->wow_enabled = true;
wl12xx_for_each_wlvif(wl, wlvif) {
ret = wl1271_configure_suspend(wl, wlvif, wow);
@@ -1813,7 +1799,27 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw,
return ret;
}
}
+
+ /* disable fast link flow control notifications from FW */
+ ret = wlcore_hw_interrupt_notify(wl, false);
+ if (ret < 0)
+ goto out_sleep;
+
+ /* if filtering is enabled, configure the FW to drop all RX BA frames */
+ ret = wlcore_hw_rx_ba_filter(wl,
+ !!wl->conf.conn.suspend_rx_ba_activity);
+ if (ret < 0)
+ goto out_sleep;
+
+out_sleep:
+ wl1271_ps_elp_sleep(wl);
mutex_unlock(&wl->mutex);
+
+ if (ret < 0) {
+ wl1271_warning("couldn't prepare device to suspend");
+ return ret;
+ }
+
/* flush any remaining work */
wl1271_debug(DEBUG_MAC80211, "flushing remaining works");

@@ -1887,13 +1893,29 @@ static int wl1271_op_resume(struct ieee80211_hw *hw)
if (pending_recovery) {
wl1271_warning("queuing forgotten recovery on resume");
ieee80211_queue_work(wl->hw, &wl->recovery_work);
- goto out;
+ goto out_sleep;
}

+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
wl12xx_for_each_wlvif(wl, wlvif) {
wl1271_configure_resume(wl, wlvif);
}

+ ret = wlcore_hw_interrupt_notify(wl, true);
+ if (ret < 0)
+ goto out_sleep;
+
+ /* if filtering is enabled, configure the FW to drop all RX BA frames */
+ ret = wlcore_hw_rx_ba_filter(wl, false);
+ if (ret < 0)
+ goto out_sleep;
+
+out_sleep:
+ wl1271_ps_elp_sleep(wl);
+
out:
wl->wow_enabled = false;

diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h
index 2440ebe..7860a4e 100644
--- a/drivers/net/wireless/ti/wlcore/wlcore.h
+++ b/drivers/net/wireless/ti/wlcore/wlcore.h
@@ -116,6 +116,8 @@ struct wlcore_ops {
struct wl1271_link *lnk);
bool (*lnk_low_prio)(struct wl1271 *wl, u8 hlid,
struct wl1271_link *lnk);
+ int (*interrupt_notify)(struct wl1271 *wl, bool action);
+ int (*rx_ba_filter)(struct wl1271 *wl, bool action);
int (*smart_config_start)(struct wl1271 *wl, u32 group_bitmap);
int (*smart_config_stop)(struct wl1271 *wl);
int (*smart_config_set_group_key)(struct wl1271 *wl, u16 group_id,
--
1.8.5.2.229.g4448466.dirty


2014-12-29 06:24:27

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 06/13] wlcore: enable sleep during AP mode operation

From: Kobi L <[email protected]>

Enable ELP authorization in AP mode and enable the use
of the wakeup bit in the ELP register.

Introduce AP role sleep configuration which is disabled
by default. When configured, it allows the AP to sleep
when ELP is authorized for it.

Signed-off-by: Kobi Leibovitch <[email protected]>
Signed-off-by: Arik Nemtsov <[email protected]>
Signed-off-by: Eliad Peller <[email protected]>
---
drivers/net/wireless/ti/wl12xx/main.c | 1 +
drivers/net/wireless/ti/wl18xx/acx.c | 32 ++++++++++++++++++++++++++++++++
drivers/net/wireless/ti/wl18xx/acx.h | 25 +++++++++++++++++++++++--
drivers/net/wireless/ti/wl18xx/conf.h | 23 ++++++++++++++++++++++-
drivers/net/wireless/ti/wl18xx/main.c | 7 +++++++
drivers/net/wireless/ti/wlcore/hw_ops.h | 9 +++++++++
drivers/net/wireless/ti/wlcore/init.c | 8 ++++++--
drivers/net/wireless/ti/wlcore/ps.c | 6 ------
drivers/net/wireless/ti/wlcore/wlcore.h | 1 +
9 files changed, 101 insertions(+), 11 deletions(-)

diff --git a/drivers/net/wireless/ti/wl12xx/main.c b/drivers/net/wireless/ti/wl12xx/main.c
index b457069..42264e5 100644
--- a/drivers/net/wireless/ti/wl12xx/main.c
+++ b/drivers/net/wireless/ti/wl12xx/main.c
@@ -1731,6 +1731,7 @@ static struct wlcore_ops wl12xx_ops = {
.lnk_low_prio = wl12xx_lnk_low_prio,
.interrupt_notify = NULL,
.rx_ba_filter = NULL,
+ .ap_sleep = NULL,
};

static struct ieee80211_sta_ht_cap wl12xx_ht_cap = {
diff --git a/drivers/net/wireless/ti/wl18xx/acx.c b/drivers/net/wireless/ti/wl18xx/acx.c
index 9d4b9aa..67f2a0e 100644
--- a/drivers/net/wireless/ti/wl18xx/acx.c
+++ b/drivers/net/wireless/ti/wl18xx/acx.c
@@ -24,6 +24,7 @@
#include "../wlcore/acx.h"

#include "acx.h"
+#include "wl18xx.h"

int wl18xx_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap,
u32 sdio_blk_size, u32 extra_mem_blks,
@@ -250,3 +251,34 @@ out:
kfree(acx);
return ret;
}
+
+int wl18xx_acx_ap_sleep(struct wl1271 *wl)
+{
+ struct wl18xx_priv *priv = wl->priv;
+ struct acx_ap_sleep_cfg *acx;
+ struct conf_ap_sleep_settings *conf = &priv->conf.ap_sleep;
+ int ret;
+
+ wl1271_debug(DEBUG_ACX, "acx config ap sleep");
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ acx->idle_duty_cycle = conf->idle_duty_cycle;
+ acx->connected_duty_cycle = conf->connected_duty_cycle;
+ acx->max_stations_thresh = conf->max_stations_thresh;
+ acx->idle_conn_thresh = conf->idle_conn_thresh;
+
+ ret = wl1271_cmd_configure(wl, ACX_AP_SLEEP_CFG, acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1271_warning("acx config ap-sleep failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
diff --git a/drivers/net/wireless/ti/wl18xx/acx.h b/drivers/net/wireless/ti/wl18xx/acx.h
index 1234bdc..4afccd4 100644
--- a/drivers/net/wireless/ti/wl18xx/acx.h
+++ b/drivers/net/wireless/ti/wl18xx/acx.h
@@ -34,8 +34,8 @@ enum {
ACX_AUTO_RX_STREAMING = 0x0055,
ACX_PEER_CAP = 0x0056,
ACX_INTERRUPT_NOTIFY = 0x0057,
- ACX_RX_BA_FILTER = 0x0058
-
+ ACX_RX_BA_FILTER = 0x0058,
+ ACX_AP_SLEEP_CFG = 0x0059
};

/* numbers of bits the length field takes (add 1 for the actual number) */
@@ -347,6 +347,26 @@ struct wl18xx_acx_rx_ba_filter {
u32 enable;
};

+struct acx_ap_sleep_cfg {
+ struct acx_header header;
+ /* Duty Cycle (20-80% of staying Awake) for IDLE AP
+ * (0: disable)
+ */
+ u8 idle_duty_cycle;
+ /* Duty Cycle (20-80% of staying Awake) for Connected AP
+ * (0: disable)
+ */
+ u8 connected_duty_cycle;
+ /* Maximum stations that are allowed to be connected to AP
+ * (255: no limit)
+ */
+ u8 max_stations_thresh;
+ /* Timeout till enabling the Sleep Mechanism after data stops
+ * [unit: 100 msec]
+ */
+ u8 idle_conn_thresh;
+} __packed;
+
int wl18xx_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap,
u32 sdio_blk_size, u32 extra_mem_blks,
u32 len_field_size);
@@ -359,5 +379,6 @@ int wl18xx_acx_set_peer_cap(struct wl1271 *wl,
u32 rate_set, u8 hlid);
int wl18xx_acx_interrupt_notify_config(struct wl1271 *wl, bool action);
int wl18xx_acx_rx_ba_filter(struct wl1271 *wl, bool action);
+int wl18xx_acx_ap_sleep(struct wl1271 *wl);

#endif /* __WL18XX_ACX_H__ */
diff --git a/drivers/net/wireless/ti/wl18xx/conf.h b/drivers/net/wireless/ti/wl18xx/conf.h
index e34302e..71f1ec4 100644
--- a/drivers/net/wireless/ti/wl18xx/conf.h
+++ b/drivers/net/wireless/ti/wl18xx/conf.h
@@ -23,7 +23,7 @@
#define __WL18XX_CONF_H__

#define WL18XX_CONF_MAGIC 0x10e100ca
-#define WL18XX_CONF_VERSION (WLCORE_CONF_VERSION | 0x0006)
+#define WL18XX_CONF_VERSION (WLCORE_CONF_VERSION | 0x0007)
#define WL18XX_CONF_MASK 0x0000ffff
#define WL18XX_CONF_SIZE (WLCORE_CONF_SIZE + \
sizeof(struct wl18xx_priv_conf))
@@ -110,12 +110,33 @@ struct wl18xx_ht_settings {
u8 mode;
} __packed;

+struct conf_ap_sleep_settings {
+ /* Duty Cycle (20-80% of staying Awake) for IDLE AP
+ * (0: disable)
+ */
+ u8 idle_duty_cycle;
+ /* Duty Cycle (20-80% of staying Awake) for Connected AP
+ * (0: disable)
+ */
+ u8 connected_duty_cycle;
+ /* Maximum stations that are allowed to be connected to AP
+ * (255: no limit)
+ */
+ u8 max_stations_thresh;
+ /* Timeout till enabling the Sleep Mechanism after data stops
+ * [unit: 100 msec]
+ */
+ u8 idle_conn_thresh;
+} __packed;
+
struct wl18xx_priv_conf {
/* Module params structures */
struct wl18xx_ht_settings ht;

/* this structure is copied wholesale to FW */
struct wl18xx_mac_and_phy_params phy;
+
+ struct conf_ap_sleep_settings ap_sleep;
} __packed;

#endif /* __WL18XX_CONF_H__ */
diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c
index 7edb8a1..9e648a1 100644
--- a/drivers/net/wireless/ti/wl18xx/main.c
+++ b/drivers/net/wireless/ti/wl18xx/main.c
@@ -568,6 +568,12 @@ static struct wl18xx_priv_conf wl18xx_default_priv_conf = {
.high_power_val_2nd = 0xff,
.tx_rf_margin = 1,
},
+ .ap_sleep = { /* disabled by default */
+ .idle_duty_cycle = 0,
+ .connected_duty_cycle = 0,
+ .max_stations_thresh = 0,
+ .idle_conn_thresh = 0,
+ },
};

static const struct wlcore_partition_set wl18xx_ptable[PART_TABLE_LEN] = {
@@ -1696,6 +1702,7 @@ static struct wlcore_ops wl18xx_ops = {
.smart_config_set_group_key = wl18xx_cmd_smart_config_set_group_key,
.interrupt_notify = wl18xx_acx_interrupt_notify_config,
.rx_ba_filter = wl18xx_acx_rx_ba_filter,
+ .ap_sleep = wl18xx_acx_ap_sleep,
};

/* HT cap appropriate for wide channels in 2Ghz */
diff --git a/drivers/net/wireless/ti/wlcore/hw_ops.h b/drivers/net/wireless/ti/wlcore/hw_ops.h
index c2545ce..449050b 100644
--- a/drivers/net/wireless/ti/wlcore/hw_ops.h
+++ b/drivers/net/wireless/ti/wlcore/hw_ops.h
@@ -234,6 +234,15 @@ wlcore_hw_rx_ba_filter(struct wl1271 *wl, bool action)
}

static inline int
+wlcore_hw_ap_sleep(struct wl1271 *wl)
+{
+ if (wl->ops->ap_sleep)
+ return wl->ops->ap_sleep(wl);
+
+ return 0;
+}
+
+static inline int
wlcore_hw_set_peer_cap(struct wl1271 *wl,
struct ieee80211_sta_ht_cap *ht_cap,
bool allow_ht_operation,
diff --git a/drivers/net/wireless/ti/wlcore/init.c b/drivers/net/wireless/ti/wlcore/init.c
index 199e941..5ca1fb1 100644
--- a/drivers/net/wireless/ti/wlcore/init.c
+++ b/drivers/net/wireless/ti/wlcore/init.c
@@ -392,6 +392,11 @@ static int wl1271_ap_hw_init(struct wl1271 *wl, struct wl12xx_vif *wlvif)
if (ret < 0)
return ret;

+ /* configure AP sleep, if enabled */
+ ret = wlcore_hw_ap_sleep(wl);
+ if (ret < 0)
+ return ret;
+
return 0;
}

@@ -567,8 +572,7 @@ int wl1271_init_vif_specific(struct wl1271 *wl, struct ieee80211_vif *vif)
/* consider all existing roles before configuring psm. */

if (wl->ap_count == 0 && is_ap) { /* first AP */
- /* Configure for power always on */
- ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
+ ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP);
if (ret < 0)
return ret;

diff --git a/drivers/net/wireless/ti/wlcore/ps.c b/drivers/net/wireless/ti/wlcore/ps.c
index b52516e..f3ed543 100644
--- a/drivers/net/wireless/ti/wlcore/ps.c
+++ b/drivers/net/wireless/ti/wlcore/ps.c
@@ -56,9 +56,6 @@ void wl1271_elp_work(struct work_struct *work)
goto out;

wl12xx_for_each_wlvif(wl, wlvif) {
- if (wlvif->bss_type == BSS_TYPE_AP_BSS)
- goto out;
-
if (!test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags) &&
test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags))
goto out;
@@ -95,9 +92,6 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl)
return;

wl12xx_for_each_wlvif(wl, wlvif) {
- if (wlvif->bss_type == BSS_TYPE_AP_BSS)
- return;
-
if (!test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags) &&
test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags))
return;
diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h
index 7860a4e..c8fe2ae 100644
--- a/drivers/net/wireless/ti/wlcore/wlcore.h
+++ b/drivers/net/wireless/ti/wlcore/wlcore.h
@@ -118,6 +118,7 @@ struct wlcore_ops {
struct wl1271_link *lnk);
int (*interrupt_notify)(struct wl1271 *wl, bool action);
int (*rx_ba_filter)(struct wl1271 *wl, bool action);
+ int (*ap_sleep)(struct wl1271 *wl);
int (*smart_config_start)(struct wl1271 *wl, u32 group_bitmap);
int (*smart_config_stop)(struct wl1271 *wl);
int (*smart_config_set_group_key)(struct wl1271 *wl, u16 group_id,
--
1.8.5.2.229.g4448466.dirty


2014-12-29 06:24:30

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 08/13] wl18xx: add debugfs file to emulate radar event

Add debugfs file to emulate radar detection through
a special fw cmd (which in turn will generate radar
event)

Signed-off-by: Eliad Peller <[email protected]>
---
drivers/net/wireless/ti/wl18xx/cmd.c | 26 +++++++++++++++++++
drivers/net/wireless/ti/wl18xx/cmd.h | 8 ++++++
drivers/net/wireless/ti/wl18xx/debugfs.c | 43 ++++++++++++++++++++++++++++++++
drivers/net/wireless/ti/wlcore/ps.c | 2 ++
4 files changed, 79 insertions(+)

diff --git a/drivers/net/wireless/ti/wl18xx/cmd.c b/drivers/net/wireless/ti/wl18xx/cmd.c
index 10f9d1c..68e12e5 100644
--- a/drivers/net/wireless/ti/wl18xx/cmd.c
+++ b/drivers/net/wireless/ti/wl18xx/cmd.c
@@ -198,3 +198,29 @@ out_free:
kfree(cmd);
return ret;
}
+
+int wl18xx_cmd_radar_detection_debug(struct wl1271 *wl, u8 channel)
+{
+ struct wl18xx_cmd_dfs_radar_debug *cmd;
+ int ret = 0;
+
+ wl1271_debug(DEBUG_CMD, "cmd radar detection debug (chan %d)",
+ channel);
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd)
+ return -ENOMEM;
+
+ cmd->channel = channel;
+
+ ret = wl1271_cmd_send(wl, CMD_DFS_RADAR_DETECTION_DEBUG,
+ cmd, sizeof(*cmd), 0);
+ if (ret < 0) {
+ wl1271_error("failed to send radar detection debug command");
+ goto out_free;
+ }
+
+out_free:
+ kfree(cmd);
+ return ret;
+}
diff --git a/drivers/net/wireless/ti/wl18xx/cmd.h b/drivers/net/wireless/ti/wl18xx/cmd.h
index 91b3e2f..0809b92 100644
--- a/drivers/net/wireless/ti/wl18xx/cmd.h
+++ b/drivers/net/wireless/ti/wl18xx/cmd.h
@@ -59,6 +59,13 @@ struct wl18xx_cmd_smart_config_set_group_key {
u8 key[16];
} __packed;

+struct wl18xx_cmd_dfs_radar_debug {
+ struct wl1271_cmd_header header;
+
+ u8 channel;
+ u8 padding[3];
+} __packed;
+
/* cac_start and cac_stop share the same params */
struct wlcore_cmd_cac_start {
struct wl1271_cmd_header header;
@@ -77,4 +84,5 @@ int wl18xx_cmd_smart_config_stop(struct wl1271 *wl);
int wl18xx_cmd_smart_config_set_group_key(struct wl1271 *wl, u16 group_id,
u8 key_len, u8 *key);
int wl18xx_cmd_set_cac(struct wl1271 *wl, struct wl12xx_vif *wlvif, bool start);
+int wl18xx_cmd_radar_detection_debug(struct wl1271 *wl, u8 channel);
#endif
diff --git a/drivers/net/wireless/ti/wl18xx/debugfs.c b/drivers/net/wireless/ti/wl18xx/debugfs.c
index 7f1669c..c93fae9 100644
--- a/drivers/net/wireless/ti/wl18xx/debugfs.c
+++ b/drivers/net/wireless/ti/wl18xx/debugfs.c
@@ -22,9 +22,12 @@

#include "../wlcore/debugfs.h"
#include "../wlcore/wlcore.h"
+#include "../wlcore/debug.h"
+#include "../wlcore/ps.h"

#include "wl18xx.h"
#include "acx.h"
+#include "cmd.h"
#include "debugfs.h"

#define WL18XX_DEBUGFS_FWSTATS_FILE(a, b, c) \
@@ -239,6 +242,45 @@ static const struct file_operations clear_fw_stats_ops = {
.llseek = default_llseek,
};

+static ssize_t radar_detection_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct wl1271 *wl = file->private_data;
+ int ret;
+ u8 channel;
+
+ ret = kstrtou8_from_user(user_buf, count, 10, &channel);
+ if (ret < 0) {
+ wl1271_warning("illegal channel");
+ return -EINVAL;
+ }
+
+ mutex_lock(&wl->mutex);
+
+ if (unlikely(wl->state != WLCORE_STATE_ON))
+ goto out;
+
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
+ ret = wl18xx_cmd_radar_detection_debug(wl, channel);
+ if (ret < 0)
+ count = ret;
+
+ wl1271_ps_elp_sleep(wl);
+out:
+ mutex_unlock(&wl->mutex);
+ return count;
+}
+
+static const struct file_operations radar_detection_ops = {
+ .write = radar_detection_write,
+ .open = simple_open,
+ .llseek = default_llseek,
+};
+
int wl18xx_debugfs_add_files(struct wl1271 *wl,
struct dentry *rootdir)
{
@@ -390,6 +432,7 @@ int wl18xx_debugfs_add_files(struct wl1271 *wl,
DEBUGFS_FWSTATS_ADD(mem, fw_gen_free_mem_blks);

DEBUGFS_ADD(conf, moddir);
+ DEBUGFS_ADD(radar_detection, moddir);

return 0;

diff --git a/drivers/net/wireless/ti/wlcore/ps.c b/drivers/net/wireless/ti/wlcore/ps.c
index f3ed543..4cd316e 100644
--- a/drivers/net/wireless/ti/wlcore/ps.c
+++ b/drivers/net/wireless/ti/wlcore/ps.c
@@ -102,6 +102,7 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl)
ieee80211_queue_delayed_work(wl->hw, &wl->elp_work,
msecs_to_jiffies(timeout));
}
+EXPORT_SYMBOL_GPL(wl1271_ps_elp_sleep);

int wl1271_ps_elp_wakeup(struct wl1271 *wl)
{
@@ -169,6 +170,7 @@ err:
out:
return 0;
}
+EXPORT_SYMBOL_GPL(wl1271_ps_elp_wakeup);

int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
enum wl1271_cmd_ps_mode mode)
--
1.8.5.2.229.g4448466.dirty


2014-12-29 06:24:26

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 05/13] wlcore: enable AP wowlan

configure wowlan when host is suspended in AP mode,
since the FW can now wake the host up on Rx.

Signed-off-by: Kobi Leibovitch <[email protected]>
Signed-off-by: Arik Nemtsov <[email protected]>
Signed-off-by: Eliad Peller <[email protected]>
---
drivers/net/wireless/ti/wlcore/main.c | 18 +++++++++++++-----
1 file changed, 13 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index aaa836b..0d67e39 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -1707,7 +1707,8 @@ out:
}

static int wl1271_configure_suspend_ap(struct wl1271 *wl,
- struct wl12xx_vif *wlvif)
+ struct wl12xx_vif *wlvif,
+ struct cfg80211_wowlan *wow)
{
int ret = 0;

@@ -1715,6 +1716,12 @@ static int wl1271_configure_suspend_ap(struct wl1271 *wl,
goto out;

ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);
+ if (ret < 0)
+ goto out;
+
+ ret = wl1271_configure_wowlan(wl, wow);
+ if (ret < 0)
+ goto out;

out:
return ret;
@@ -1728,7 +1735,7 @@ static int wl1271_configure_suspend(struct wl1271 *wl,
if (wlvif->bss_type == BSS_TYPE_STA_BSS)
return wl1271_configure_suspend_sta(wl, wlvif, wow);
if (wlvif->bss_type == BSS_TYPE_AP_BSS)
- return wl1271_configure_suspend_ap(wl, wlvif);
+ return wl1271_configure_suspend_ap(wl, wlvif, wow);
return 0;
}

@@ -1741,12 +1748,13 @@ static void wl1271_configure_resume(struct wl1271 *wl, struct wl12xx_vif *wlvif)
if ((!is_ap) && (!is_sta))
return;

- if (is_sta && !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
+ if ((is_sta && !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) ||
+ (is_ap && !test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)))
return;

- if (is_sta) {
- wl1271_configure_wowlan(wl, NULL);
+ wl1271_configure_wowlan(wl, NULL);

+ if (is_sta) {
if ((wl->conf.conn.suspend_wake_up_event ==
wl->conf.conn.wake_up_event) &&
(wl->conf.conn.suspend_listen_interval ==
--
1.8.5.2.229.g4448466.dirty


2014-12-29 06:24:37

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 12/13] wlcore: add dfs region to reg domain update cmd

From: Guy Mishol <[email protected]>

Add dfs region to the reg domain channel update command.

Signed-off-by: Guy Mishol <[email protected]>
Signed-off-by: Eliad Peller <[email protected]>
---
drivers/net/wireless/ti/wlcore/cmd.c | 1 +
drivers/net/wireless/ti/wlcore/cmd.h | 2 ++
drivers/net/wireless/ti/wlcore/main.c | 4 ++++
drivers/net/wireless/ti/wlcore/wlcore.h | 3 +++
4 files changed, 10 insertions(+)

diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c
index 50ca10c..c26fc21 100644
--- a/drivers/net/wireless/ti/wlcore/cmd.c
+++ b/drivers/net/wireless/ti/wlcore/cmd.c
@@ -1736,6 +1736,7 @@ int wlcore_cmd_regdomain_config_locked(struct wl1271 *wl)

cmd->ch_bit_map1 = cpu_to_le32(tmp_ch_bitmap[0]);
cmd->ch_bit_map2 = cpu_to_le32(tmp_ch_bitmap[1]);
+ cmd->dfs_region = wl->dfs_region;

wl1271_debug(DEBUG_CMD,
"cmd reg domain bitmap1: 0x%08x, bitmap2: 0x%08x",
diff --git a/drivers/net/wireless/ti/wlcore/cmd.h b/drivers/net/wireless/ti/wlcore/cmd.h
index 06bdee2..e14cd40 100644
--- a/drivers/net/wireless/ti/wlcore/cmd.h
+++ b/drivers/net/wireless/ti/wlcore/cmd.h
@@ -648,6 +648,8 @@ struct wl12xx_cmd_regdomain_dfs_config {

__le32 ch_bit_map1;
__le32 ch_bit_map2;
+ u8 dfs_region;
+ u8 padding[3];
} __packed;

struct wl12xx_cmd_config_fwlog {
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index d99f289..ebb03b9 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -82,6 +82,10 @@ static void wl1271_reg_notify(struct wiphy *wiphy,
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
struct wl1271 *wl = hw->priv;

+ /* copy the current dfs region */
+ if (request)
+ wl->dfs_region = request->dfs_region;
+
wlcore_regdomain_config(wl);
}

diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h
index 581c479..d599c86 100644
--- a/drivers/net/wireless/ti/wlcore/wlcore.h
+++ b/drivers/net/wireless/ti/wlcore/wlcore.h
@@ -465,6 +465,9 @@ struct wl1271 {
/* HW HT (11n) capabilities */
struct ieee80211_sta_ht_cap ht_cap[WLCORE_NUM_BANDS];

+ /* the current dfs region */
+ enum nl80211_dfs_regions dfs_region;
+
/* size of the private FW status data */
size_t fw_status_len;
size_t fw_status_priv_len;
--
1.8.5.2.229.g4448466.dirty


2014-12-29 06:24:32

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 09/13] wlcore: add support for ap csa

Support ap csa support by implementing the channel_switch_beacon()
mac80211 op.

Signed-off-by: Eliad Peller <[email protected]>
---
drivers/net/wireless/ti/wl18xx/cmd.c | 11 +++--
drivers/net/wireless/ti/wlcore/event.c | 10 +++--
drivers/net/wireless/ti/wlcore/main.c | 81 +++++++++++++++++++++++++++++++++-
3 files changed, 95 insertions(+), 7 deletions(-)

diff --git a/drivers/net/wireless/ti/wl18xx/cmd.c b/drivers/net/wireless/ti/wl18xx/cmd.c
index 68e12e5..5731950 100644
--- a/drivers/net/wireless/ti/wl18xx/cmd.c
+++ b/drivers/net/wireless/ti/wl18xx/cmd.c
@@ -33,7 +33,8 @@ int wl18xx_cmd_channel_switch(struct wl1271 *wl,
u32 supported_rates;
int ret;

- wl1271_debug(DEBUG_ACX, "cmd channel switch");
+ wl1271_debug(DEBUG_ACX, "cmd channel switch (count=%d)",
+ ch_switch->count);

cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
@@ -60,8 +61,12 @@ int wl18xx_cmd_channel_switch(struct wl1271 *wl,
goto out_free;
}

- supported_rates = CONF_TX_ENABLED_RATES | CONF_TX_MCS_RATES |
- wlcore_hw_sta_get_ap_rate_mask(wl, wlvif);
+ supported_rates = CONF_TX_ENABLED_RATES | CONF_TX_MCS_RATES;
+ if (wlvif->bss_type == BSS_TYPE_STA_BSS)
+ supported_rates |= wlcore_hw_sta_get_ap_rate_mask(wl, wlvif);
+ else
+ supported_rates |=
+ wlcore_hw_ap_get_mimo_wide_rate_mask(wl, wlvif);
if (wlvif->p2p)
supported_rates &= ~CONF_TX_CCK_RATES;
cmd->local_supported_rates = cpu_to_le32(supported_rates);
diff --git a/drivers/net/wireless/ti/wlcore/event.c b/drivers/net/wireless/ti/wlcore/event.c
index 5153640..69a2661 100644
--- a/drivers/net/wireless/ti/wlcore/event.c
+++ b/drivers/net/wireless/ti/wlcore/event.c
@@ -139,7 +139,7 @@ void wlcore_event_channel_switch(struct wl1271 *wl,
wl1271_debug(DEBUG_EVENT, "%s: roles=0x%lx success=%d",
__func__, roles_bitmap, success);

- wl12xx_for_each_wlvif_sta(wl, wlvif) {
+ wl12xx_for_each_wlvif(wl, wlvif) {
if (wlvif->role_id == WL12XX_INVALID_ROLE_ID ||
!test_bit(wlvif->role_id , &roles_bitmap))
continue;
@@ -150,8 +150,12 @@ void wlcore_event_channel_switch(struct wl1271 *wl,

vif = wl12xx_wlvif_to_vif(wlvif);

- ieee80211_chswitch_done(vif, success);
- cancel_delayed_work(&wlvif->channel_switch_work);
+ if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
+ ieee80211_chswitch_done(vif, success);
+ cancel_delayed_work(&wlvif->channel_switch_work);
+ } else {
+ ieee80211_csa_finish(vif);
+ }
}
}
EXPORT_SYMBOL_GPL(wlcore_event_channel_switch);
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index 673bfc4..9a35f30 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -5434,6 +5434,83 @@ out:
mutex_unlock(&wl->mutex);
}

+static const void *wlcore_get_beacon_ie(struct wl1271 *wl,
+ struct wl12xx_vif *wlvif,
+ u8 eid)
+{
+ int ieoffset = offsetof(struct ieee80211_mgmt, u.beacon.variable);
+ struct sk_buff *beacon =
+ ieee80211_beacon_get(wl->hw, wl12xx_wlvif_to_vif(wlvif));
+
+ if (!beacon)
+ return NULL;
+
+ return cfg80211_find_ie(eid,
+ beacon->data + ieoffset,
+ beacon->len - ieoffset);
+}
+
+static int wlcore_get_csa_count(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ u8 *csa_count)
+{
+ const u8 *ie;
+ const struct ieee80211_channel_sw_ie *ie_csa;
+
+ ie = wlcore_get_beacon_ie(wl, wlvif, WLAN_EID_CHANNEL_SWITCH);
+ if (!ie)
+ return -EINVAL;
+
+ ie_csa = (struct ieee80211_channel_sw_ie *)&ie[2];
+ *csa_count = ie_csa->count;
+
+ return 0;
+}
+
+static void wlcore_op_channel_switch_beacon(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct cfg80211_chan_def *chandef)
+{
+ struct wl1271 *wl = hw->priv;
+ struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
+ struct ieee80211_channel_switch ch_switch = {
+ .block_tx = true,
+ .chandef = *chandef,
+ };
+ int ret;
+
+ wl1271_debug(DEBUG_MAC80211,
+ "mac80211 channel switch beacon (role %d)",
+ wlvif->role_id);
+
+ ret = wlcore_get_csa_count(wl, wlvif, &ch_switch.count);
+ if (ret < 0) {
+ wl1271_error("error getting beacon (for CSA counter)");
+ return;
+ }
+
+ mutex_lock(&wl->mutex);
+
+ if (unlikely(wl->state != WLCORE_STATE_ON)) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
+ ret = wl->ops->channel_switch(wl, wlvif, &ch_switch);
+ if (ret)
+ goto out_sleep;
+
+ set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags);
+
+out_sleep:
+ wl1271_ps_elp_sleep(wl);
+out:
+ mutex_unlock(&wl->mutex);
+}
+
static void wlcore_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u32 queues, bool drop)
{
@@ -5808,6 +5885,7 @@ static const struct ieee80211_ops wl1271_ops = {
.set_bitrate_mask = wl12xx_set_bitrate_mask,
.set_default_unicast_key = wl1271_op_set_default_key_idx,
.channel_switch = wl12xx_op_channel_switch,
+ .channel_switch_beacon = wlcore_op_channel_switch_beacon,
.flush = wlcore_op_flush,
.remain_on_channel = wlcore_op_remain_on_channel,
.cancel_remain_on_channel = wlcore_op_cancel_remain_on_channel,
@@ -6023,7 +6101,8 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)

wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD |
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
- WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
+ WIPHY_FLAG_SUPPORTS_SCHED_SCAN |
+ WIPHY_FLAG_HAS_CHANNEL_SWITCH;

/* make sure all our channels fit in the scanned_ch bitmask */
BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
--
1.8.5.2.229.g4448466.dirty


2014-12-29 06:24:23

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 03/13] wlcore/wl18xx: handle rc updates in a separate work

sta_rc_update runs in atomic context. thus, a new work
should be scheduled in order to configure the fw
with the required configuration.

Signed-off-by: Eliad Peller <[email protected]>
---
drivers/net/wireless/ti/wl18xx/main.c | 18 ++++------------
drivers/net/wireless/ti/wlcore/hw_ops.h | 5 ++---
drivers/net/wireless/ti/wlcore/main.c | 35 +++++++++++++++++++++++++++++--
drivers/net/wireless/ti/wlcore/wlcore.h | 3 +--
drivers/net/wireless/ti/wlcore/wlcore_i.h | 4 ++++
5 files changed, 44 insertions(+), 21 deletions(-)

diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c
index 7af1936..6946d18 100644
--- a/drivers/net/wireless/ti/wl18xx/main.c
+++ b/drivers/net/wireless/ti/wl18xx/main.c
@@ -1559,26 +1559,19 @@ static u32 wl18xx_pre_pkt_send(struct wl1271 *wl,
}

static void wl18xx_sta_rc_update(struct wl1271 *wl,
- struct wl12xx_vif *wlvif,
- struct ieee80211_sta *sta,
- u32 changed)
+ struct wl12xx_vif *wlvif)
{
- bool wide = sta->bandwidth >= IEEE80211_STA_RX_BW_40;
+ bool wide = wlvif->rc_update_bw >= IEEE80211_STA_RX_BW_40;

wl1271_debug(DEBUG_MAC80211, "mac80211 sta_rc_update wide %d", wide);

- if (!(changed & IEEE80211_RC_BW_CHANGED))
- return;
-
- mutex_lock(&wl->mutex);
-
/* sanity */
if (WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS))
- goto out;
+ return;

/* ignore the change before association */
if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
- goto out;
+ return;

/*
* If we started out as wide, we can change the operation mode. If we
@@ -1589,9 +1582,6 @@ static void wl18xx_sta_rc_update(struct wl1271 *wl,
wl18xx_acx_peer_ht_operation_mode(wl, wlvif->sta.hlid, wide);
else
ieee80211_connection_loss(wl12xx_wlvif_to_vif(wlvif));
-
-out:
- mutex_unlock(&wl->mutex);
}

static int wl18xx_set_peer_cap(struct wl1271 *wl,
diff --git a/drivers/net/wireless/ti/wlcore/hw_ops.h b/drivers/net/wireless/ti/wlcore/hw_ops.h
index aa9f82c..29ce55f 100644
--- a/drivers/net/wireless/ti/wlcore/hw_ops.h
+++ b/drivers/net/wireless/ti/wlcore/hw_ops.h
@@ -211,11 +211,10 @@ wlcore_hw_pre_pkt_send(struct wl1271 *wl, u32 buf_offset, u32 last_len)
}

static inline void
-wlcore_hw_sta_rc_update(struct wl1271 *wl, struct wl12xx_vif *wlvif,
- struct ieee80211_sta *sta, u32 changed)
+wlcore_hw_sta_rc_update(struct wl1271 *wl, struct wl12xx_vif *wlvif)
{
if (wl->ops->sta_rc_update)
- wl->ops->sta_rc_update(wl, wlvif, sta, changed);
+ wl->ops->sta_rc_update(wl, wlvif);
}

static inline int
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index 2a99456..f6e37d5 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -226,6 +226,29 @@ void wl12xx_rearm_tx_watchdog_locked(struct wl1271 *wl)
msecs_to_jiffies(wl->conf.tx.tx_watchdog_timeout));
}

+static void wlcore_rc_update_work(struct work_struct *work)
+{
+ int ret;
+ struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif,
+ rc_update_work);
+ struct wl1271 *wl = wlvif->wl;
+
+ mutex_lock(&wl->mutex);
+
+ if (unlikely(wl->state != WLCORE_STATE_ON))
+ goto out;
+
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
+ wlcore_hw_sta_rc_update(wl, wlvif);
+
+ wl1271_ps_elp_sleep(wl);
+out:
+ mutex_unlock(&wl->mutex);
+}
+
static void wl12xx_tx_watchdog_work(struct work_struct *work)
{
struct delayed_work *dwork;
@@ -2279,6 +2302,7 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
wl1271_rx_streaming_enable_work);
INIT_WORK(&wlvif->rx_streaming_disable_work,
wl1271_rx_streaming_disable_work);
+ INIT_WORK(&wlvif->rc_update_work, wlcore_rc_update_work);
INIT_DELAYED_WORK(&wlvif->channel_switch_work,
wlcore_channel_switch_work);
INIT_DELAYED_WORK(&wlvif->connection_loss_work,
@@ -2724,6 +2748,7 @@ unlock:
del_timer_sync(&wlvif->rx_streaming_timer);
cancel_work_sync(&wlvif->rx_streaming_enable_work);
cancel_work_sync(&wlvif->rx_streaming_disable_work);
+ cancel_work_sync(&wlvif->rc_update_work);
cancel_delayed_work_sync(&wlvif->connection_loss_work);
cancel_delayed_work_sync(&wlvif->channel_switch_work);
cancel_delayed_work_sync(&wlvif->pending_auth_complete_work);
@@ -5371,9 +5396,15 @@ static void wlcore_op_sta_rc_update(struct ieee80211_hw *hw,
u32 changed)
{
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
- struct wl1271 *wl = hw->priv;

- wlcore_hw_sta_rc_update(wl, wlvif, sta, changed);
+ wl1271_debug(DEBUG_MAC80211, "mac80211 sta_rc_update");
+
+ if (!(changed & IEEE80211_RC_BW_CHANGED))
+ return;
+
+ /* this callback is atomic, so schedule a new work */
+ wlvif->rc_update_bw = sta->bandwidth;
+ ieee80211_queue_work(hw, &wlvif->rc_update_work);
}

static int wlcore_op_get_rssi(struct ieee80211_hw *hw,
diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h
index df78cf1..2440ebe 100644
--- a/drivers/net/wireless/ti/wlcore/wlcore.h
+++ b/drivers/net/wireless/ti/wlcore/wlcore.h
@@ -106,8 +106,7 @@ struct wlcore_ops {
struct wl12xx_vif *wlvif,
struct ieee80211_channel_switch *ch_switch);
u32 (*pre_pkt_send)(struct wl1271 *wl, u32 buf_offset, u32 last_len);
- void (*sta_rc_update)(struct wl1271 *wl, struct wl12xx_vif *wlvif,
- struct ieee80211_sta *sta, u32 changed);
+ void (*sta_rc_update)(struct wl1271 *wl, struct wl12xx_vif *wlvif);
int (*set_peer_cap)(struct wl1271 *wl,
struct ieee80211_sta_ht_cap *ht_cap,
bool allow_ht_operation,
diff --git a/drivers/net/wireless/ti/wlcore/wlcore_i.h b/drivers/net/wireless/ti/wlcore/wlcore_i.h
index 0e52556..811851d 100644
--- a/drivers/net/wireless/ti/wlcore/wlcore_i.h
+++ b/drivers/net/wireless/ti/wlcore/wlcore_i.h
@@ -463,6 +463,10 @@ struct wl12xx_vif {
/* work for canceling ROC after pending auth reply */
struct delayed_work pending_auth_complete_work;

+ /* update rate conrol */
+ enum ieee80211_sta_rx_bandwidth rc_update_bw;
+ struct work_struct rc_update_work;
+
/*
* total freed FW packets on the link.
* For STA this holds the PN of the link to the AP.
--
1.8.5.2.229.g4448466.dirty


2014-12-29 06:24:21

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 02/13] wlcore: fix sparse warning

Use kstrtoul_from_user() for reading the user value,
and fix the following sparse warning:

drivers/net/wireless/ti/wlcore/debugfs.c:937:15: error: incompatible
types in comparison expression (different type sizes)

Signed-off-by: Eliad Peller <[email protected]>
---
drivers/net/wireless/ti/wlcore/debugfs.c | 9 +--------
1 file changed, 1 insertion(+), 8 deletions(-)

diff --git a/drivers/net/wireless/ti/wlcore/debugfs.c b/drivers/net/wireless/ti/wlcore/debugfs.c
index 0be21f6..68f3bf2 100644
--- a/drivers/net/wireless/ti/wlcore/debugfs.c
+++ b/drivers/net/wireless/ti/wlcore/debugfs.c
@@ -929,17 +929,10 @@ static ssize_t beacon_filtering_write(struct file *file,
{
struct wl1271 *wl = file->private_data;
struct wl12xx_vif *wlvif;
- char buf[10];
- size_t len;
unsigned long value;
int ret;

- len = min(count, sizeof(buf) - 1);
- if (copy_from_user(buf, user_buf, len))
- return -EFAULT;
- buf[len] = '\0';
-
- ret = kstrtoul(buf, 0, &value);
+ ret = kstrtoul_from_user(user_buf, count, 0, &value);
if (ret < 0) {
wl1271_warning("illegal value for beacon_filtering!");
return -EINVAL;
--
1.8.5.2.229.g4448466.dirty


2014-12-29 06:24:35

by Eliad Peller

[permalink] [raw]
Subject: [PATCH 11/13] wlcore: allow using dfs channels

Since we are going to support dfs channels, there
is no reason to mark them as NO_IR (having
the DFS flag is enough anyway).

Additionally, when setting the regdomain configuration,
enable usable dfs channels.

Signed-off-by: Eliad Peller <[email protected]>
---
drivers/net/wireless/ti/wlcore/cmd.c | 16 +++++++++-------
drivers/net/wireless/ti/wlcore/main.c | 14 --------------
2 files changed, 9 insertions(+), 21 deletions(-)

diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c
index aacad4e..50ca10c 100644
--- a/drivers/net/wireless/ti/wlcore/cmd.c
+++ b/drivers/net/wireless/ti/wlcore/cmd.c
@@ -1687,9 +1687,7 @@ int wlcore_cmd_regdomain_config_locked(struct wl1271 *wl)
{
struct wl12xx_cmd_regdomain_dfs_config *cmd = NULL;
int ret = 0, i, b, ch_bit_idx;
- struct ieee80211_channel *channel;
u32 tmp_ch_bitmap[2];
- u16 ch;
struct wiphy *wiphy = wl->hw->wiphy;
struct ieee80211_supported_band *band;
bool timeout = false;
@@ -1704,12 +1702,16 @@ int wlcore_cmd_regdomain_config_locked(struct wl1271 *wl)
for (b = IEEE80211_BAND_2GHZ; b <= IEEE80211_BAND_5GHZ; b++) {
band = wiphy->bands[b];
for (i = 0; i < band->n_channels; i++) {
- channel = &band->channels[i];
- ch = channel->hw_value;
+ struct ieee80211_channel *channel = &band->channels[i];
+ u16 ch = channel->hw_value;
+ u32 flags = channel->flags;

- if (channel->flags & (IEEE80211_CHAN_DISABLED |
- IEEE80211_CHAN_RADAR |
- IEEE80211_CHAN_NO_IR))
+ if (flags & (IEEE80211_CHAN_DISABLED |
+ IEEE80211_CHAN_NO_IR))
+ continue;
+
+ if ((flags & IEEE80211_CHAN_RADAR) &&
+ channel->dfs_state != NL80211_DFS_AVAILABLE)
continue;

ch_bit_idx = wlcore_get_reg_conf_ch_idx(b, ch);
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index 362515f..d99f289 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -79,23 +79,9 @@ static int wl12xx_set_authorized(struct wl1271 *wl, struct wl12xx_vif *wlvif)
static void wl1271_reg_notify(struct wiphy *wiphy,
struct regulatory_request *request)
{
- struct ieee80211_supported_band *band;
- struct ieee80211_channel *ch;
- int i;
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
struct wl1271 *wl = hw->priv;

- band = wiphy->bands[IEEE80211_BAND_5GHZ];
- for (i = 0; i < band->n_channels; i++) {
- ch = &band->channels[i];
- if (ch->flags & IEEE80211_CHAN_DISABLED)
- continue;
-
- if (ch->flags & IEEE80211_CHAN_RADAR)
- ch->flags |= IEEE80211_CHAN_NO_IR;
-
- }
-
wlcore_regdomain_config(wl);
}

--
1.8.5.2.229.g4448466.dirty


2015-01-07 17:55:45

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH 01/13] wlcore: fix WLCORE_VENDOR_ATTR_GROUP_KEY policy

Eliad Peller <[email protected]> writes:

> The attribute type is binary data (with max length).
>
> Signed-off-by: Eliad Peller <[email protected]>

Thanks, all 13 applied to wireless-drivers-next.git.

--
Kalle Valo

2015-03-25 12:27:48

by Marc Kleine-Budde

[permalink] [raw]
Subject: Re: [PATCH 06/13] wlcore: enable sleep during AP mode operation

On 12/29/2014 07:24 AM, Eliad Peller wrote:
> From: Kobi L <[email protected]>
>
> Enable ELP authorization in AP mode and enable the use
> of the wakeup bit in the ELP register.
>
> Introduce AP role sleep configuration which is disabled
> by default. When configured, it allows the AP to sleep
> when ELP is authorized for it.
>
> Signed-off-by: Kobi Leibovitch <[email protected]>
> Signed-off-by: Arik Nemtsov <[email protected]>
> Signed-off-by: Eliad Peller <[email protected]>

[...]

> diff --git a/drivers/net/wireless/ti/wl18xx/conf.h b/drivers/net/wireless/ti/wl18xx/conf.h
> index e34302e..71f1ec4 100644
> --- a/drivers/net/wireless/ti/wl18xx/conf.h
> +++ b/drivers/net/wireless/ti/wl18xx/conf.h
> @@ -23,7 +23,7 @@
> #define __WL18XX_CONF_H__
>
> #define WL18XX_CONF_MAGIC 0x10e100ca
> -#define WL18XX_CONF_VERSION (WLCORE_CONF_VERSION | 0x0006)
> +#define WL18XX_CONF_VERSION (WLCORE_CONF_VERSION | 0x0007)
> #define WL18XX_CONF_MASK 0x0000ffff
> #define WL18XX_CONF_SIZE (WLCORE_CONF_SIZE + \
> sizeof(struct wl18xx_priv_conf))
> @@ -110,12 +110,33 @@ struct wl18xx_ht_settings {
> u8 mode;
> } __packed;
>
> +struct conf_ap_sleep_settings {
> + /* Duty Cycle (20-80% of staying Awake) for IDLE AP
> + * (0: disable)
> + */
> + u8 idle_duty_cycle;
> + /* Duty Cycle (20-80% of staying Awake) for Connected AP
> + * (0: disable)
> + */
> + u8 connected_duty_cycle;
> + /* Maximum stations that are allowed to be connected to AP
> + * (255: no limit)
> + */
> + u8 max_stations_thresh;
> + /* Timeout till enabling the Sleep Mechanism after data stops
> + * [unit: 100 msec]
> + */
> + u8 idle_conn_thresh;
> +} __packed;
> +
> struct wl18xx_priv_conf {
> /* Module params structures */
> struct wl18xx_ht_settings ht;
>
> /* this structure is copied wholesale to FW */
> struct wl18xx_mac_and_phy_params phy;
> +
> + struct conf_ap_sleep_settings ap_sleep;
> } __packed;

This patch requires a new firmware, loading of "wl18xx-conf.bin" from
[1] fails with:

> wlcore: ERROR configuration binary file size is wrong, expected 1226 got 1221

regards,
Marc

[1]
http://git.kernel.org/cgit/linux/kernel/git/firmware/linux-firmware.git/tree/ti-connectivity

--
Pengutronix e.K. | Marc Kleine-Budde |
Industrial Linux Solutions | Phone: +49-231-2826-924 |
Vertretung West/Dortmund | Fax: +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |


Attachments:
signature.asc (819.00 B)
OpenPGP digital signature

2015-03-25 13:45:09

by Eliad Peller

[permalink] [raw]
Subject: Re: [PATCH 06/13] wlcore: enable sleep during AP mode operation

On Wed, Mar 25, 2015 at 3:24 PM, Marc Kleine-Budde <[email protected]> wrote:
> On 03/25/2015 01:58 PM, Eliad Peller wrote:
>> hi Marc,
>>
>> On Wed, Mar 25, 2015 at 2:27 PM, Marc Kleine-Budde <[email protected]> wrote:
>>> On 12/29/2014 07:24 AM, Eliad Peller wrote:
>>>> From: Kobi L <[email protected]>
>>>>
>>>> Enable ELP authorization in AP mode and enable the use
>>>> of the wakeup bit in the ELP register.
>>>>
>>>> Introduce AP role sleep configuration which is disabled
>>>> by default. When configured, it allows the AP to sleep
>>>> when ELP is authorized for it.
>>>>
>>>> Signed-off-by: Kobi Leibovitch <[email protected]>
>>>> Signed-off-by: Arik Nemtsov <[email protected]>
>>>> Signed-off-by: Eliad Peller <[email protected]>
>>>
>>> [...]
>>>
>>>
>>> This patch requires a new firmware, loading of "wl18xx-conf.bin" from
>>> [1] fails with:
>>>
>>>> wlcore: ERROR configuration binary file size is wrong, expected 1226 got 1221
>>>
>> thanks. seems you're right.
>>
>> anyway, note that this file is not actual fw, but only the default
>> configuration params.
>> you can just delete it, and the driver will load just fine.
>> you can then recreate it with something like:
>> cat /sys/kernel/debug/ieee80211/phy0/wlcore/wl18xx/conf >
>> /lib/firmware/ti-connectivity/wl18xx-conf.bin
>>
>> actually, i don't think it makes much sense to have this file in the
>> linux-firmware git at all.
>> i'll try handling it.
>
> Thanks, there are more file with size of ~1k, are they optional, too?
> What's the "error" message if these optional files are not present?
>
AFAIK, the other nvs files are basically required for proper operation.

> From working with $CUSTOMERS I gained the impression, messages like
> "error failed to load...." for optional file don't shine the best light
> on Linux, a neutral "using default values" is far better.
i agree :)

Eliad.

2015-03-25 13:24:08

by Marc Kleine-Budde

[permalink] [raw]
Subject: Re: [PATCH 06/13] wlcore: enable sleep during AP mode operation

On 03/25/2015 01:58 PM, Eliad Peller wrote:
> hi Marc,
>
> On Wed, Mar 25, 2015 at 2:27 PM, Marc Kleine-Budde <[email protected]> wrote:
>> On 12/29/2014 07:24 AM, Eliad Peller wrote:
>>> From: Kobi L <[email protected]>
>>>
>>> Enable ELP authorization in AP mode and enable the use
>>> of the wakeup bit in the ELP register.
>>>
>>> Introduce AP role sleep configuration which is disabled
>>> by default. When configured, it allows the AP to sleep
>>> when ELP is authorized for it.
>>>
>>> Signed-off-by: Kobi Leibovitch <[email protected]>
>>> Signed-off-by: Arik Nemtsov <[email protected]>
>>> Signed-off-by: Eliad Peller <[email protected]>
>>
>> [...]
>>
>>
>> This patch requires a new firmware, loading of "wl18xx-conf.bin" from
>> [1] fails with:
>>
>>> wlcore: ERROR configuration binary file size is wrong, expected 1226 got 1221
>>
> thanks. seems you're right.
>
> anyway, note that this file is not actual fw, but only the default
> configuration params.
> you can just delete it, and the driver will load just fine.
> you can then recreate it with something like:
> cat /sys/kernel/debug/ieee80211/phy0/wlcore/wl18xx/conf >
> /lib/firmware/ti-connectivity/wl18xx-conf.bin
>
> actually, i don't think it makes much sense to have this file in the
> linux-firmware git at all.
> i'll try handling it.

Thanks, there are more file with size of ~1k, are they optional, too?
What's the "error" message if these optional files are not present?

From working with $CUSTOMERS I gained the impression, messages like
"error failed to load...." for optional file don't shine the best light
on Linux, a neutral "using default values" is far better.

Marc

--
Pengutronix e.K. | Marc Kleine-Budde |
Industrial Linux Solutions | Phone: +49-231-2826-924 |
Vertretung West/Dortmund | Fax: +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |


Attachments:
signature.asc (819.00 B)
OpenPGP digital signature

2015-03-25 12:58:34

by Eliad Peller

[permalink] [raw]
Subject: Re: [PATCH 06/13] wlcore: enable sleep during AP mode operation

hi Marc,

On Wed, Mar 25, 2015 at 2:27 PM, Marc Kleine-Budde <[email protected]> wrote:
> On 12/29/2014 07:24 AM, Eliad Peller wrote:
>> From: Kobi L <[email protected]>
>>
>> Enable ELP authorization in AP mode and enable the use
>> of the wakeup bit in the ELP register.
>>
>> Introduce AP role sleep configuration which is disabled
>> by default. When configured, it allows the AP to sleep
>> when ELP is authorized for it.
>>
>> Signed-off-by: Kobi Leibovitch <[email protected]>
>> Signed-off-by: Arik Nemtsov <[email protected]>
>> Signed-off-by: Eliad Peller <[email protected]>
>
> [...]
>
>
> This patch requires a new firmware, loading of "wl18xx-conf.bin" from
> [1] fails with:
>
>> wlcore: ERROR configuration binary file size is wrong, expected 1226 got 1221
>
thanks. seems you're right.

anyway, note that this file is not actual fw, but only the default
configuration params.
you can just delete it, and the driver will load just fine.
you can then recreate it with something like:
cat /sys/kernel/debug/ieee80211/phy0/wlcore/wl18xx/conf >
/lib/firmware/ti-connectivity/wl18xx-conf.bin

actually, i don't think it makes much sense to have this file in the
linux-firmware git at all.
i'll try handling it.

Eliad.

2015-05-06 08:32:54

by Eliad Peller

[permalink] [raw]
Subject: Re: [PATCH 06/13] wlcore: enable sleep during AP mode operation

hi Yegor,

On Mon, May 4, 2015 at 12:16 PM, Yegor Yefremov
<[email protected]> wrote:
> On Wed, Mar 25, 2015 at 2:45 PM, Eliad Peller <[email protected]> wrote:
>> On Wed, Mar 25, 2015 at 3:24 PM, Marc Kleine-Budde <[email protected]> wrote:
>>> On 03/25/2015 01:58 PM, Eliad Peller wrote:
>>>> hi Marc,
>>>>
>>>> On Wed, Mar 25, 2015 at 2:27 PM, Marc Kleine-Budde <[email protected]> wrote:
>>>>> On 12/29/2014 07:24 AM, Eliad Peller wrote:
>>>>>> From: Kobi L <[email protected]>
>>>>>>
>>>>>> Enable ELP authorization in AP mode and enable the use
>>>>>> of the wakeup bit in the ELP register.
>>>>>>
>>>>>> Introduce AP role sleep configuration which is disabled
>>>>>> by default. When configured, it allows the AP to sleep
>>>>>> when ELP is authorized for it.
>>>>>>
>>>>>> Signed-off-by: Kobi Leibovitch <[email protected]>
>>>>>> Signed-off-by: Arik Nemtsov <[email protected]>
>>>>>> Signed-off-by: Eliad Peller <[email protected]>
>>>>>
>>>>> [...]
>>>>>
>>>>>
>>>>> This patch requires a new firmware, loading of "wl18xx-conf.bin" from
>>>>> [1] fails with:
>>>>>
>>>>>> wlcore: ERROR configuration binary file size is wrong, expected 1226 got 1221
>>>>>
>>>> thanks. seems you're right.
>>>>
>>>> anyway, note that this file is not actual fw, but only the default
>>>> configuration params.
>>>> you can just delete it, and the driver will load just fine.
>>>> you can then recreate it with something like:
>>>> cat /sys/kernel/debug/ieee80211/phy0/wlcore/wl18xx/conf >
>>>> /lib/firmware/ti-connectivity/wl18xx-conf.bin
>>>>
>>>> actually, i don't think it makes much sense to have this file in the
>>>> linux-firmware git at all.
>>>> i'll try handling it.
>>>
>>> Thanks, there are more file with size of ~1k, are they optional, too?
>>> What's the "error" message if these optional files are not present?
>>>
>> AFAIK, the other nvs files are basically required for proper operation.
>>
>>> From working with $CUSTOMERS I gained the impression, messages like
>>> "error failed to load...." for optional file don't shine the best light
>>> on Linux, a neutral "using default values" is far better.
>> i agree :)
>
> Added Yaniv Machani in CC.
>
> Any update on the wl18xx-conf.bin issue? This file is still in
> linux-firmware repo.
>
thanks for the reminder :)

just sent a patch to fallback to default conf in case of invalid/outdated conf.

Eliad.

2015-05-06 09:04:01

by Yegor Yefremov

[permalink] [raw]
Subject: Re: [PATCH 06/13] wlcore: enable sleep during AP mode operation

On Wed, May 6, 2015 at 10:32 AM, Eliad Peller <[email protected]> wrote:
> hi Yegor,
>
> On Mon, May 4, 2015 at 12:16 PM, Yegor Yefremov
> <[email protected]> wrote:
>> On Wed, Mar 25, 2015 at 2:45 PM, Eliad Peller <[email protected]> wrote:
>>> On Wed, Mar 25, 2015 at 3:24 PM, Marc Kleine-Budde <[email protected]> wrote:
>>>> On 03/25/2015 01:58 PM, Eliad Peller wrote:
>>>>> hi Marc,
>>>>>
>>>>> On Wed, Mar 25, 2015 at 2:27 PM, Marc Kleine-Budde <[email protected]> wrote:
>>>>>> On 12/29/2014 07:24 AM, Eliad Peller wrote:
>>>>>>> From: Kobi L <[email protected]>
>>>>>>>
>>>>>>> Enable ELP authorization in AP mode and enable the use
>>>>>>> of the wakeup bit in the ELP register.
>>>>>>>
>>>>>>> Introduce AP role sleep configuration which is disabled
>>>>>>> by default. When configured, it allows the AP to sleep
>>>>>>> when ELP is authorized for it.
>>>>>>>
>>>>>>> Signed-off-by: Kobi Leibovitch <[email protected]>
>>>>>>> Signed-off-by: Arik Nemtsov <[email protected]>
>>>>>>> Signed-off-by: Eliad Peller <[email protected]>
>>>>>>
>>>>>> [...]
>>>>>>
>>>>>>
>>>>>> This patch requires a new firmware, loading of "wl18xx-conf.bin" from
>>>>>> [1] fails with:
>>>>>>
>>>>>>> wlcore: ERROR configuration binary file size is wrong, expected 1226 got 1221
>>>>>>
>>>>> thanks. seems you're right.
>>>>>
>>>>> anyway, note that this file is not actual fw, but only the default
>>>>> configuration params.
>>>>> you can just delete it, and the driver will load just fine.
>>>>> you can then recreate it with something like:
>>>>> cat /sys/kernel/debug/ieee80211/phy0/wlcore/wl18xx/conf >
>>>>> /lib/firmware/ti-connectivity/wl18xx-conf.bin
>>>>>
>>>>> actually, i don't think it makes much sense to have this file in the
>>>>> linux-firmware git at all.
>>>>> i'll try handling it.
>>>>
>>>> Thanks, there are more file with size of ~1k, are they optional, too?
>>>> What's the "error" message if these optional files are not present?
>>>>
>>> AFAIK, the other nvs files are basically required for proper operation.
>>>
>>>> From working with $CUSTOMERS I gained the impression, messages like
>>>> "error failed to load...." for optional file don't shine the best light
>>>> on Linux, a neutral "using default values" is far better.
>>> i agree :)
>>
>> Added Yaniv Machani in CC.
>>
>> Any update on the wl18xx-conf.bin issue? This file is still in
>> linux-firmware repo.
>>
> thanks for the reminder :)
>
> just sent a patch to fallback to default conf in case of invalid/outdated conf.

Great.

@Yaniv: but how to create a new conf with 1226 bytes for existing ini file?

Yegor

2015-05-04 09:16:43

by Yegor Yefremov

[permalink] [raw]
Subject: Re: [PATCH 06/13] wlcore: enable sleep during AP mode operation

Hi Eliad,



On Wed, Mar 25, 2015 at 2:45 PM, Eliad Peller <[email protected]> wrote:
> On Wed, Mar 25, 2015 at 3:24 PM, Marc Kleine-Budde <[email protected]> wrote:
>> On 03/25/2015 01:58 PM, Eliad Peller wrote:
>>> hi Marc,
>>>
>>> On Wed, Mar 25, 2015 at 2:27 PM, Marc Kleine-Budde <[email protected]> wrote:
>>>> On 12/29/2014 07:24 AM, Eliad Peller wrote:
>>>>> From: Kobi L <[email protected]>
>>>>>
>>>>> Enable ELP authorization in AP mode and enable the use
>>>>> of the wakeup bit in the ELP register.
>>>>>
>>>>> Introduce AP role sleep configuration which is disabled
>>>>> by default. When configured, it allows the AP to sleep
>>>>> when ELP is authorized for it.
>>>>>
>>>>> Signed-off-by: Kobi Leibovitch <[email protected]>
>>>>> Signed-off-by: Arik Nemtsov <[email protected]>
>>>>> Signed-off-by: Eliad Peller <[email protected]>
>>>>
>>>> [...]
>>>>
>>>>
>>>> This patch requires a new firmware, loading of "wl18xx-conf.bin" from
>>>> [1] fails with:
>>>>
>>>>> wlcore: ERROR configuration binary file size is wrong, expected 1226 got 1221
>>>>
>>> thanks. seems you're right.
>>>
>>> anyway, note that this file is not actual fw, but only the default
>>> configuration params.
>>> you can just delete it, and the driver will load just fine.
>>> you can then recreate it with something like:
>>> cat /sys/kernel/debug/ieee80211/phy0/wlcore/wl18xx/conf >
>>> /lib/firmware/ti-connectivity/wl18xx-conf.bin
>>>
>>> actually, i don't think it makes much sense to have this file in the
>>> linux-firmware git at all.
>>> i'll try handling it.
>>
>> Thanks, there are more file with size of ~1k, are they optional, too?
>> What's the "error" message if these optional files are not present?
>>
> AFAIK, the other nvs files are basically required for proper operation.
>
>> From working with $CUSTOMERS I gained the impression, messages like
>> "error failed to load...." for optional file don't shine the best light
>> on Linux, a neutral "using default values" is far better.
> i agree :)

Added Yaniv Machani in CC.

Any update on the wl18xx-conf.bin issue? This file is still in
linux-firmware repo.

I have following problem. My Jorjin chip requires wl18xx-conf.bin
compiled from special *.ini file.
https://github.com/TI-OpenLink/18xx-ti-utils/tree/master/wlconf
doesn't seem to support v4 firmware as it creates 1221 bytes conf
file. Where can I get proper wlconf and companion files
(dictionary.txt, struct.bin etc.)?

Yegor