* [PATCH 1/4] wl12xx: Use a dedicated fw for PLT
2012-02-06 10:47 [PATCH 0/4] wl12xx: support multiple vifs Eliad Peller
@ 2012-02-06 10:47 ` Eliad Peller
2012-02-06 10:47 ` [PATCH 2/4] wl12xx: dynamically change fw according to number of active roles Eliad Peller
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Eliad Peller @ 2012-02-06 10:47 UTC (permalink / raw)
To: Luciano Coelho; +Cc: linux-wireless, Gery Kahn
A special PLT firmware is used for calibration.
Add multiple fw support by introducing a new fw_type member,
representing the currently saved fw (the actual fw state
can be determined by wl->state).
Signed-off-by: Gery Kahn <geryk@ti.com>
Signed-off-by: Eliad Peller <eliad@wizery.com>
---
drivers/net/wireless/wl12xx/debugfs.c | 2 +-
drivers/net/wireless/wl12xx/main.c | 53 +++++++++++++++++++++-----------
drivers/net/wireless/wl12xx/rx.c | 2 +-
drivers/net/wireless/wl12xx/sdio.c | 2 +
drivers/net/wireless/wl12xx/spi.c | 2 +
drivers/net/wireless/wl12xx/wl12xx.h | 11 ++++++-
6 files changed, 51 insertions(+), 21 deletions(-)
diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c
index 00dbe15..e1cf727 100644
--- a/drivers/net/wireless/wl12xx/debugfs.c
+++ b/drivers/net/wireless/wl12xx/debugfs.c
@@ -113,7 +113,7 @@ static void wl1271_debugfs_update_stats(struct wl1271 *wl)
if (ret < 0)
goto out;
- if (wl->state == WL1271_STATE_ON &&
+ if (wl->state == WL1271_STATE_ON && !wl->plt &&
time_after(jiffies, wl->stats.fw_stats_update +
msecs_to_jiffies(WL1271_DEBUGFS_STATS_LIFETIME))) {
wl1271_acx_statistics(wl, wl->stats.fw_stats);
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index 52efe7d..591a3d7 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -993,16 +993,29 @@ out:
return IRQ_HANDLED;
}
-static int wl1271_fetch_firmware(struct wl1271 *wl)
+static int wl12xx_fetch_firmware(struct wl1271 *wl, bool plt)
{
const struct firmware *fw;
const char *fw_name;
+ enum wl12xx_fw_type fw_type;
int ret;
- if (wl->chip.id == CHIP_ID_1283_PG20)
- fw_name = WL128X_FW_NAME;
- else
- fw_name = WL127X_FW_NAME;
+ if (plt) {
+ fw_type = WL12XX_FW_TYPE_PLT;
+ if (wl->chip.id == CHIP_ID_1283_PG20)
+ fw_name = WL128X_PLT_FW_NAME;
+ else
+ fw_name = WL127X_PLT_FW_NAME;
+ } else {
+ fw_type = WL12XX_FW_TYPE_NORMAL;
+ if (wl->chip.id == CHIP_ID_1283_PG20)
+ fw_name = WL128X_FW_NAME;
+ else
+ fw_name = WL127X_FW_NAME;
+ }
+
+ if (wl->fw_type == fw_type)
+ return 0;
wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
@@ -1021,6 +1034,7 @@ static int wl1271_fetch_firmware(struct wl1271 *wl)
}
vfree(wl->fw);
+ wl->fw_type = WL12XX_FW_TYPE_NONE;
wl->fw_len = fw->size;
wl->fw = vmalloc(wl->fw_len);
@@ -1032,7 +1046,7 @@ static int wl1271_fetch_firmware(struct wl1271 *wl)
memcpy(wl->fw, fw->data, wl->fw_len);
ret = 0;
-
+ wl->fw_type = fw_type;
out:
release_firmware(fw);
@@ -1160,7 +1174,7 @@ static void wl1271_recovery_work(struct work_struct *work)
mutex_lock(&wl->mutex);
- if (wl->state != WL1271_STATE_ON)
+ if (wl->state != WL1271_STATE_ON || wl->plt)
goto out_unlock;
/* Avoid a recursive recovery */
@@ -1240,7 +1254,7 @@ static int wl1271_setup(struct wl1271 *wl)
return 0;
}
-static int wl1271_chip_wakeup(struct wl1271 *wl)
+static int wl12xx_chip_wakeup(struct wl1271 *wl, bool plt)
{
struct wl1271_partition_set partition;
int ret = 0;
@@ -1315,11 +1329,9 @@ static int wl1271_chip_wakeup(struct wl1271 *wl)
goto out;
}
- if (wl->fw == NULL) {
- ret = wl1271_fetch_firmware(wl);
- if (ret < 0)
- goto out;
- }
+ ret = wl12xx_fetch_firmware(wl, plt);
+ if (ret < 0)
+ goto out;
/* No NVS from netlink, try to get it from the filesystem */
if (wl->nvs == NULL) {
@@ -1351,7 +1363,7 @@ int wl1271_plt_start(struct wl1271 *wl)
while (retries) {
retries--;
- ret = wl1271_chip_wakeup(wl);
+ ret = wl12xx_chip_wakeup(wl, true);
if (ret < 0)
goto power_off;
@@ -1363,7 +1375,8 @@ int wl1271_plt_start(struct wl1271 *wl)
if (ret < 0)
goto irq_disable;
- wl->state = WL1271_STATE_PLT;
+ wl->plt = true;
+ wl->state = WL1271_STATE_ON;
wl1271_notice("firmware booted in PLT mode (%s)",
wl->chip.fw_ver_str);
@@ -1405,7 +1418,7 @@ static int __wl1271_plt_stop(struct wl1271 *wl)
wl1271_notice("power down");
- if (wl->state != WL1271_STATE_PLT) {
+ if (!wl->plt) {
wl1271_error("cannot power down because not in PLT "
"state: %d", wl->state);
ret = -EBUSY;
@@ -1415,6 +1428,7 @@ static int __wl1271_plt_stop(struct wl1271 *wl)
wl1271_power_off(wl);
wl->state = WL1271_STATE_OFF;
+ wl->plt = false;
wl->rx_counter = 0;
mutex_unlock(&wl->mutex);
@@ -1972,7 +1986,7 @@ static bool wl12xx_init_fw(struct wl1271 *wl)
while (retries) {
retries--;
- ret = wl1271_chip_wakeup(wl);
+ ret = wl12xx_chip_wakeup(wl, false);
if (ret < 0)
goto power_off;
@@ -2072,6 +2086,7 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
goto out;
}
+
ret = wl12xx_init_vif_data(wl, vif);
if (ret < 0)
goto out;
@@ -4870,7 +4885,7 @@ static int wl1271_register_hw(struct wl1271 *wl)
static void wl1271_unregister_hw(struct wl1271 *wl)
{
- if (wl->state == WL1271_STATE_PLT)
+ if (wl->plt)
__wl1271_plt_stop(wl);
unregister_netdevice_notifier(&wl1271_dev_notifier);
@@ -5049,6 +5064,7 @@ static struct ieee80211_hw *wl1271_alloc_hw(void)
spin_lock_init(&wl->wl_lock);
wl->state = WL1271_STATE_OFF;
+ wl->fw_type = WL12XX_FW_TYPE_NONE;
mutex_init(&wl->mutex);
/* Apply default driver configuration. */
@@ -5116,6 +5132,7 @@ static int wl1271_free_hw(struct wl1271 *wl)
vfree(wl->fw);
wl->fw = NULL;
+ wl->fw_type = WL12XX_FW_TYPE_NONE;
kfree(wl->nvs);
wl->nvs = NULL;
diff --git a/drivers/net/wireless/wl12xx/rx.c b/drivers/net/wireless/wl12xx/rx.c
index 4fbd2a7..cfa6071 100644
--- a/drivers/net/wireless/wl12xx/rx.c
+++ b/drivers/net/wireless/wl12xx/rx.c
@@ -113,7 +113,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
* In PLT mode we seem to get frames and mac80211 warns about them,
* workaround this by not retrieving them at all.
*/
- if (unlikely(wl->state == WL1271_STATE_PLT))
+ if (unlikely(wl->plt))
return -EINVAL;
/* the data read starts with the descriptor */
diff --git a/drivers/net/wireless/wl12xx/sdio.c b/drivers/net/wireless/wl12xx/sdio.c
index ce3b9a9..1c0264c 100644
--- a/drivers/net/wireless/wl12xx/sdio.c
+++ b/drivers/net/wireless/wl12xx/sdio.c
@@ -372,3 +372,5 @@ MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
MODULE_FIRMWARE(WL127X_FW_NAME);
MODULE_FIRMWARE(WL128X_FW_NAME);
+MODULE_FIRMWARE(WL127X_PLT_FW_NAME);
+MODULE_FIRMWARE(WL128X_PLT_FW_NAME);
diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/spi.c
index 92caa7c..5c2d4a0 100644
--- a/drivers/net/wireless/wl12xx/spi.c
+++ b/drivers/net/wireless/wl12xx/spi.c
@@ -435,4 +435,6 @@ MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
MODULE_FIRMWARE(WL127X_FW_NAME);
MODULE_FIRMWARE(WL128X_FW_NAME);
+MODULE_FIRMWARE(WL127X_PLT_FW_NAME);
+MODULE_FIRMWARE(WL128X_PLT_FW_NAME);
MODULE_ALIAS("spi:wl1271");
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index 70b15b5..348d1f6 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -37,6 +37,8 @@
#define WL127X_FW_NAME "ti-connectivity/wl127x-fw-4-sr.bin"
#define WL128X_FW_NAME "ti-connectivity/wl128x-fw-4-sr.bin"
+#define WL127X_PLT_FW_NAME "ti-connectivity/wl127x-fw-4-plt.bin"
+#define WL128X_PLT_FW_NAME "ti-connectivity/wl128x-fw-4-plt.bin"
/*
* wl127x and wl128x are using the same NVS file name. However, the
@@ -90,7 +92,12 @@
enum wl1271_state {
WL1271_STATE_OFF,
WL1271_STATE_ON,
- WL1271_STATE_PLT,
+};
+
+enum wl12xx_fw_type {
+ WL12XX_FW_TYPE_NONE,
+ WL12XX_FW_TYPE_NORMAL,
+ WL12XX_FW_TYPE_PLT,
};
enum wl1271_partition_type {
@@ -294,6 +301,8 @@ struct wl1271 {
spinlock_t wl_lock;
enum wl1271_state state;
+ enum wl12xx_fw_type fw_type;
+ bool plt;
struct mutex mutex;
unsigned long flags;
--
1.7.6.401.g6a319
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH 2/4] wl12xx: dynamically change fw according to number of active roles
2012-02-06 10:47 [PATCH 0/4] wl12xx: support multiple vifs Eliad Peller
2012-02-06 10:47 ` [PATCH 1/4] wl12xx: Use a dedicated fw for PLT Eliad Peller
@ 2012-02-06 10:47 ` Eliad Peller
2012-02-06 10:47 ` [PATCH 3/4] wl12xx: enter forced-psm on fw change Eliad Peller
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Eliad Peller @ 2012-02-06 10:47 UTC (permalink / raw)
To: Luciano Coelho; +Cc: linux-wireless
wl12xx uses different fw for single-role and multi-role
scenarios (due to lack of space, some of the fw advanced
features are disabled in the multi-role fw).
Add checks on add_interfae and remove_interface in order
to determine whether a fw switch is needed (and initiate
recovery in this case).
Signed-off-by: Eliad Peller <eliad@wizery.com>
---
drivers/net/wireless/wl12xx/main.c | 115 +++++++++++++++++++++++++++++++--
drivers/net/wireless/wl12xx/sdio.c | 6 +-
drivers/net/wireless/wl12xx/spi.c | 6 +-
drivers/net/wireless/wl12xx/wl12xx.h | 11 +++-
4 files changed, 125 insertions(+), 13 deletions(-)
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index 591a3d7..a3c464f 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -993,6 +993,35 @@ out:
return IRQ_HANDLED;
}
+struct vif_counter_data {
+ u8 counter;
+
+ struct ieee80211_vif *cur_vif;
+ bool cur_vif_running;
+};
+
+static void wl12xx_vif_count_iter(void *data, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ struct vif_counter_data *counter = data;
+
+ counter->counter++;
+ if (counter->cur_vif == vif)
+ counter->cur_vif_running = true;
+}
+
+/* caller must not hold wl->mutex, as it might deadlock */
+static void wl12xx_get_vif_count(struct ieee80211_hw *hw,
+ struct ieee80211_vif *cur_vif,
+ struct vif_counter_data *data)
+{
+ memset(data, 0, sizeof(*data));
+ data->cur_vif = cur_vif;
+
+ ieee80211_iterate_active_interfaces(hw,
+ wl12xx_vif_count_iter, data);
+}
+
static int wl12xx_fetch_firmware(struct wl1271 *wl, bool plt)
{
const struct firmware *fw;
@@ -1007,11 +1036,23 @@ static int wl12xx_fetch_firmware(struct wl1271 *wl, bool plt)
else
fw_name = WL127X_PLT_FW_NAME;
} else {
- fw_type = WL12XX_FW_TYPE_NORMAL;
- if (wl->chip.id == CHIP_ID_1283_PG20)
- fw_name = WL128X_FW_NAME;
- else
- fw_name = WL127X_FW_NAME;
+ /*
+ * we can't call wl12xx_get_vif_count() here because
+ * wl->mutex is taken, so use the cached last_vif_count value
+ */
+ if (wl->last_vif_count > 1) {
+ fw_type = WL12XX_FW_TYPE_MULTI;
+ if (wl->chip.id == CHIP_ID_1283_PG20)
+ fw_name = WL128X_FW_NAME_MULTI;
+ else
+ fw_name = WL127X_FW_NAME_MULTI;
+ } else {
+ fw_type = WL12XX_FW_TYPE_NORMAL;
+ if (wl->chip.id == CHIP_ID_1283_PG20)
+ fw_name = WL128X_FW_NAME_SINGLE;
+ else
+ fw_name = WL127X_FW_NAME_SINGLE;
+ }
}
if (wl->fw_type == fw_type)
@@ -2051,11 +2092,47 @@ static bool wl12xx_dev_role_started(struct wl12xx_vif *wlvif)
return wlvif->dev_hlid != WL12XX_INVALID_LINK_ID;
}
+/*
+ * Check whether a fw switch (i.e. moving from one loaded
+ * fw to another) is needed. This function is also responsible
+ * for updating wl->last_vif_count, so it must be called before
+ * loading a non-plt fw (so the correct fw (single-role/multi-role)
+ * will be used).
+ */
+static bool wl12xx_need_fw_change(struct wl1271 *wl,
+ struct vif_counter_data vif_counter_data,
+ bool add)
+{
+ enum wl12xx_fw_type current_fw = wl->fw_type;
+ u8 vif_count = vif_counter_data.counter;
+
+ if (test_bit(WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, &wl->flags))
+ return false;
+
+ /* increase the vif count if this is a new vif */
+ if (add && !vif_counter_data.cur_vif_running)
+ vif_count++;
+
+ wl->last_vif_count = vif_count;
+
+ /* no need for fw change if the device is OFF */
+ if (wl->state == WL1271_STATE_OFF)
+ return false;
+
+ if (vif_count > 1 && current_fw == WL12XX_FW_TYPE_NORMAL)
+ return true;
+ if (vif_count <= 1 && current_fw == WL12XX_FW_TYPE_MULTI)
+ return true;
+
+ return false;
+}
+
static int wl1271_op_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct wl1271 *wl = hw->priv;
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
+ struct vif_counter_data vif_count;
int ret = 0;
u8 role_type;
bool booted = false;
@@ -2063,6 +2140,8 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
ieee80211_vif_type_p2p(vif), vif->addr);
+ wl12xx_get_vif_count(hw, vif, &vif_count);
+
mutex_lock(&wl->mutex);
ret = wl1271_ps_elp_wakeup(wl);
if (ret < 0)
@@ -2098,10 +2177,17 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
goto out;
}
+ if (wl12xx_need_fw_change(wl, vif_count, true)) {
+ mutex_unlock(&wl->mutex);
+ wl1271_recovery_work(&wl->recovery_work);
+ return 0;
+ }
+
/*
* TODO: after the nvs issue will be solved, move this block
* to start(), and make sure here the driver is ON.
*/
+ wl1271_info("state: %d", wl->state);
if (wl->state == WL1271_STATE_OFF) {
/*
* we still need this in order to configure the fw
@@ -2261,7 +2347,10 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
struct wl1271 *wl = hw->priv;
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
struct wl12xx_vif *iter;
+ struct vif_counter_data vif_count;
+ bool cancel_recovery = true;
+ wl12xx_get_vif_count(hw, vif, &vif_count);
mutex_lock(&wl->mutex);
if (wl->state == WL1271_STATE_OFF ||
@@ -2280,20 +2369,32 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
break;
}
WARN_ON(iter != wlvif);
+ if (wl12xx_need_fw_change(wl, vif_count, false)) {
+ wl12xx_queue_recovery_work(wl);
+ cancel_recovery = false;
+ }
out:
mutex_unlock(&wl->mutex);
- cancel_work_sync(&wl->recovery_work);
+ if (cancel_recovery)
+ cancel_work_sync(&wl->recovery_work);
}
static int wl12xx_op_change_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
enum nl80211_iftype new_type, bool p2p)
{
+ struct wl1271 *wl = hw->priv;
+ int ret;
+
+ set_bit(WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, &wl->flags);
wl1271_op_remove_interface(hw, vif);
vif->type = ieee80211_iftype_p2p(new_type, p2p);
vif->p2p = p2p;
- return wl1271_op_add_interface(hw, vif);
+ ret = wl1271_op_add_interface(hw, vif);
+
+ clear_bit(WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, &wl->flags);
+ return ret;
}
static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
diff --git a/drivers/net/wireless/wl12xx/sdio.c b/drivers/net/wireless/wl12xx/sdio.c
index 1c0264c..4b3c327 100644
--- a/drivers/net/wireless/wl12xx/sdio.c
+++ b/drivers/net/wireless/wl12xx/sdio.c
@@ -370,7 +370,9 @@ module_exit(wl1271_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
-MODULE_FIRMWARE(WL127X_FW_NAME);
-MODULE_FIRMWARE(WL128X_FW_NAME);
+MODULE_FIRMWARE(WL127X_FW_NAME_SINGLE);
+MODULE_FIRMWARE(WL127X_FW_NAME_MULTI);
MODULE_FIRMWARE(WL127X_PLT_FW_NAME);
+MODULE_FIRMWARE(WL128X_FW_NAME_SINGLE);
+MODULE_FIRMWARE(WL128X_FW_NAME_MULTI);
MODULE_FIRMWARE(WL128X_PLT_FW_NAME);
diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/spi.c
index 5c2d4a0..2fc18a8 100644
--- a/drivers/net/wireless/wl12xx/spi.c
+++ b/drivers/net/wireless/wl12xx/spi.c
@@ -433,8 +433,10 @@ module_exit(wl1271_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
-MODULE_FIRMWARE(WL127X_FW_NAME);
-MODULE_FIRMWARE(WL128X_FW_NAME);
+MODULE_FIRMWARE(WL127X_FW_NAME_SINGLE);
+MODULE_FIRMWARE(WL127X_FW_NAME_MULTI);
MODULE_FIRMWARE(WL127X_PLT_FW_NAME);
+MODULE_FIRMWARE(WL128X_FW_NAME_SINGLE);
+MODULE_FIRMWARE(WL128X_FW_NAME_MULTI);
MODULE_FIRMWARE(WL128X_PLT_FW_NAME);
MODULE_ALIAS("spi:wl1271");
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index 348d1f6..021d84f 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -35,8 +35,12 @@
#include "conf.h"
#include "ini.h"
-#define WL127X_FW_NAME "ti-connectivity/wl127x-fw-4-sr.bin"
-#define WL128X_FW_NAME "ti-connectivity/wl128x-fw-4-sr.bin"
+#define WL127X_FW_NAME_MULTI "ti-connectivity/wl127x-fw-4-mr.bin"
+#define WL127X_FW_NAME_SINGLE "ti-connectivity/wl127x-fw-4-sr.bin"
+
+#define WL128X_FW_NAME_MULTI "ti-connectivity/wl128x-fw-4-mr.bin"
+#define WL128X_FW_NAME_SINGLE "ti-connectivity/wl128x-fw-4-sr.bin"
+
#define WL127X_PLT_FW_NAME "ti-connectivity/wl127x-fw-4-plt.bin"
#define WL128X_PLT_FW_NAME "ti-connectivity/wl128x-fw-4-plt.bin"
@@ -97,6 +101,7 @@ enum wl1271_state {
enum wl12xx_fw_type {
WL12XX_FW_TYPE_NONE,
WL12XX_FW_TYPE_NORMAL,
+ WL12XX_FW_TYPE_MULTI,
WL12XX_FW_TYPE_PLT,
};
@@ -254,6 +259,7 @@ enum wl12xx_flags {
WL1271_FLAG_PENDING_WORK,
WL1271_FLAG_SOFT_GEMINI,
WL1271_FLAG_RECOVERY_IN_PROGRESS,
+ WL1271_FLAG_VIF_CHANGE_IN_PROGRESS,
};
enum wl12xx_vif_flags {
@@ -303,6 +309,7 @@ struct wl1271 {
enum wl1271_state state;
enum wl12xx_fw_type fw_type;
bool plt;
+ u8 last_vif_count;
struct mutex mutex;
unsigned long flags;
--
1.7.6.401.g6a319
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH 3/4] wl12xx: enter forced-psm on fw change
2012-02-06 10:47 [PATCH 0/4] wl12xx: support multiple vifs Eliad Peller
2012-02-06 10:47 ` [PATCH 1/4] wl12xx: Use a dedicated fw for PLT Eliad Peller
2012-02-06 10:47 ` [PATCH 2/4] wl12xx: dynamically change fw according to number of active roles Eliad Peller
@ 2012-02-06 10:47 ` Eliad Peller
2012-02-06 10:47 ` [PATCH 4/4] wl12xx: delete wl->vif (and allow multiple vifs) Eliad Peller
2012-02-15 10:22 ` [PATCH 0/4] wl12xx: support multiple vifs Luciano Coelho
4 siblings, 0 replies; 6+ messages in thread
From: Eliad Peller @ 2012-02-06 10:47 UTC (permalink / raw)
To: Luciano Coelho; +Cc: linux-wireless
Enter forced psm when changing fw, in order to make the
sta a bit more disconnection-persistent.
(DPM doesn't know about the incoming recovery, so it
won't enter psm by itself)
Signed-off-by: Eliad Peller <eliad@wizery.com>
---
drivers/net/wireless/wl12xx/main.c | 15 +++++++++++++++
1 files changed, 15 insertions(+), 0 deletions(-)
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index a3c464f..eeb80f5 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -2127,6 +2127,19 @@ static bool wl12xx_need_fw_change(struct wl1271 *wl,
return false;
}
+/*
+ * Enter "forced psm". Make sure the sta is in psm against the ap,
+ * to make the fw switch a bit more disconnection-persistent.
+ */
+static void wl12xx_force_active_psm(struct wl1271 *wl)
+{
+ struct wl12xx_vif *wlvif;
+
+ wl12xx_for_each_wlvif_sta(wl, wlvif) {
+ wl1271_ps_set_mode(wl, wlvif, STATION_POWER_SAVE_MODE);
+ }
+}
+
static int wl1271_op_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
@@ -2178,6 +2191,7 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
}
if (wl12xx_need_fw_change(wl, vif_count, true)) {
+ wl12xx_force_active_psm(wl);
mutex_unlock(&wl->mutex);
wl1271_recovery_work(&wl->recovery_work);
return 0;
@@ -2370,6 +2384,7 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
}
WARN_ON(iter != wlvif);
if (wl12xx_need_fw_change(wl, vif_count, false)) {
+ wl12xx_force_active_psm(wl);
wl12xx_queue_recovery_work(wl);
cancel_recovery = false;
}
--
1.7.6.401.g6a319
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH 4/4] wl12xx: delete wl->vif (and allow multiple vifs)
2012-02-06 10:47 [PATCH 0/4] wl12xx: support multiple vifs Eliad Peller
` (2 preceding siblings ...)
2012-02-06 10:47 ` [PATCH 3/4] wl12xx: enter forced-psm on fw change Eliad Peller
@ 2012-02-06 10:47 ` Eliad Peller
2012-02-15 10:22 ` [PATCH 0/4] wl12xx: support multiple vifs Luciano Coelho
4 siblings, 0 replies; 6+ messages in thread
From: Eliad Peller @ 2012-02-06 10:47 UTC (permalink / raw)
To: Luciano Coelho; +Cc: linux-wireless
Delete the global wl->vif (and the checks on it),
so multiple vifs could be added.
Signed-off-by: Eliad Peller <eliad@wizery.com>
---
drivers/net/wireless/wl12xx/main.c | 11 -----------
drivers/net/wireless/wl12xx/wl12xx.h | 2 --
2 files changed, 0 insertions(+), 13 deletions(-)
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index eeb80f5..0434afa 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -2160,13 +2160,6 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
if (ret < 0)
goto out_unlock;
- if (wl->vif) {
- wl1271_debug(DEBUG_MAC80211,
- "multiple vifs are not supported yet");
- ret = -EBUSY;
- goto out;
- }
-
/*
* in some very corner case HW recovery scenarios its possible to
* get here before __wl1271_op_remove_interface is complete, so
@@ -2240,7 +2233,6 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
if (ret < 0)
goto out;
- wl->vif = vif;
list_add(&wlvif->list, &wl->wlvif_list);
set_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags);
@@ -2273,8 +2265,6 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
if (!test_and_clear_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
return;
- wl->vif = NULL;
-
/* because of hardware recovery, we may get here twice */
if (wl->state != WL1271_STATE_ON)
return;
@@ -5155,7 +5145,6 @@ static struct ieee80211_hw *wl1271_alloc_hw(void)
wl->rx_counter = 0;
wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
wl->band = IEEE80211_BAND_2GHZ;
- wl->vif = NULL;
wl->flags = 0;
wl->sg_enabled = true;
wl->hw_pg_ver = -1;
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index 021d84f..89467b2 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -440,8 +440,6 @@ struct wl1271 {
struct wl12xx_fw_status *fw_status;
struct wl1271_tx_hw_res_if *tx_res_if;
- struct ieee80211_vif *vif;
-
/* Current chipset configuration */
struct conf_drv_settings conf;
--
1.7.6.401.g6a319
^ permalink raw reply related [flat|nested] 6+ messages in thread* Re: [PATCH 0/4] wl12xx: support multiple vifs
2012-02-06 10:47 [PATCH 0/4] wl12xx: support multiple vifs Eliad Peller
` (3 preceding siblings ...)
2012-02-06 10:47 ` [PATCH 4/4] wl12xx: delete wl->vif (and allow multiple vifs) Eliad Peller
@ 2012-02-15 10:22 ` Luciano Coelho
4 siblings, 0 replies; 6+ messages in thread
From: Luciano Coelho @ 2012-02-15 10:22 UTC (permalink / raw)
To: Eliad Peller; +Cc: linux-wireless
On Mon, 2012-02-06 at 12:47 +0200, Eliad Peller wrote:
> Due to lack of space, wl12xx uses separate firmwares for PLT,
> single-role and multi-role (some advanced fw features are
> disabled in the multi-role fw, so we use the single-role fw
> when only a single vif is configured).
>
> Add support for loading the different firmwares, and initiate
> a recovery when a single<->multi transition is needed.
>
> Eliad Peller (4):
> wl12xx: Use a dedicated fw for PLT
> wl12xx: dynamically change fw according to number of active roles
> wl12xx: enter forced-psm on fw change
> wl12xx: delete wl->vif (and allow multiple vifs)
>
> drivers/net/wireless/wl12xx/debugfs.c | 2 +-
> drivers/net/wireless/wl12xx/main.c | 184 +++++++++++++++++++++++++++------
> drivers/net/wireless/wl12xx/rx.c | 2 +-
> drivers/net/wireless/wl12xx/sdio.c | 8 +-
> drivers/net/wireless/wl12xx/spi.c | 8 +-
> drivers/net/wireless/wl12xx/wl12xx.h | 24 ++++-
> 6 files changed, 186 insertions(+), 42 deletions(-)
Applied this series, with v2 of 2/4.
--
Cheers,
Luca.
^ permalink raw reply [flat|nested] 6+ messages in thread