mirror of https://gitee.com/openkylin/linux.git
wl12xx: dynamically change fw according to number of active roles
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> Signed-off-by: Luciano Coelho <coelho@ti.com>
This commit is contained in:
parent
3fcdab7066
commit
4549d09c57
|
@ -993,6 +993,35 @@ static irqreturn_t wl1271_irq(int irq, void *cookie)
|
||||||
return IRQ_HANDLED;
|
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)
|
static int wl12xx_fetch_firmware(struct wl1271 *wl, bool plt)
|
||||||
{
|
{
|
||||||
const struct firmware *fw;
|
const struct firmware *fw;
|
||||||
|
@ -1006,12 +1035,24 @@ static int wl12xx_fetch_firmware(struct wl1271 *wl, bool plt)
|
||||||
fw_name = WL128X_PLT_FW_NAME;
|
fw_name = WL128X_PLT_FW_NAME;
|
||||||
else
|
else
|
||||||
fw_name = WL127X_PLT_FW_NAME;
|
fw_name = WL127X_PLT_FW_NAME;
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* 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 {
|
} else {
|
||||||
fw_type = WL12XX_FW_TYPE_NORMAL;
|
fw_type = WL12XX_FW_TYPE_NORMAL;
|
||||||
if (wl->chip.id == CHIP_ID_1283_PG20)
|
if (wl->chip.id == CHIP_ID_1283_PG20)
|
||||||
fw_name = WL128X_FW_NAME;
|
fw_name = WL128X_FW_NAME_SINGLE;
|
||||||
else
|
else
|
||||||
fw_name = WL127X_FW_NAME;
|
fw_name = WL127X_FW_NAME_SINGLE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wl->fw_type == fw_type)
|
if (wl->fw_type == fw_type)
|
||||||
|
@ -2074,11 +2115,47 @@ static bool wl12xx_dev_role_started(struct wl12xx_vif *wlvif)
|
||||||
return wlvif->dev_hlid != WL12XX_INVALID_LINK_ID;
|
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,
|
static int wl1271_op_add_interface(struct ieee80211_hw *hw,
|
||||||
struct ieee80211_vif *vif)
|
struct ieee80211_vif *vif)
|
||||||
{
|
{
|
||||||
struct wl1271 *wl = hw->priv;
|
struct wl1271 *wl = hw->priv;
|
||||||
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
|
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
|
||||||
|
struct vif_counter_data vif_count;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
u8 role_type;
|
u8 role_type;
|
||||||
bool booted = false;
|
bool booted = false;
|
||||||
|
@ -2089,6 +2166,8 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
|
||||||
wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
|
wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
|
||||||
ieee80211_vif_type_p2p(vif), vif->addr);
|
ieee80211_vif_type_p2p(vif), vif->addr);
|
||||||
|
|
||||||
|
wl12xx_get_vif_count(hw, vif, &vif_count);
|
||||||
|
|
||||||
mutex_lock(&wl->mutex);
|
mutex_lock(&wl->mutex);
|
||||||
ret = wl1271_ps_elp_wakeup(wl);
|
ret = wl1271_ps_elp_wakeup(wl);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
@ -2124,6 +2203,12 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
|
||||||
goto out;
|
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
|
* TODO: after the nvs issue will be solved, move this block
|
||||||
* to start(), and make sure here the driver is ON.
|
* to start(), and make sure here the driver is ON.
|
||||||
|
@ -2287,7 +2372,10 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
|
||||||
struct wl1271 *wl = hw->priv;
|
struct wl1271 *wl = hw->priv;
|
||||||
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
|
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
|
||||||
struct wl12xx_vif *iter;
|
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);
|
mutex_lock(&wl->mutex);
|
||||||
|
|
||||||
if (wl->state == WL1271_STATE_OFF ||
|
if (wl->state == WL1271_STATE_OFF ||
|
||||||
|
@ -2306,8 +2394,13 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
WARN_ON(iter != wlvif);
|
WARN_ON(iter != wlvif);
|
||||||
|
if (wl12xx_need_fw_change(wl, vif_count, false)) {
|
||||||
|
wl12xx_queue_recovery_work(wl);
|
||||||
|
cancel_recovery = false;
|
||||||
|
}
|
||||||
out:
|
out:
|
||||||
mutex_unlock(&wl->mutex);
|
mutex_unlock(&wl->mutex);
|
||||||
|
if (cancel_recovery)
|
||||||
cancel_work_sync(&wl->recovery_work);
|
cancel_work_sync(&wl->recovery_work);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2315,11 +2408,18 @@ static int wl12xx_op_change_interface(struct ieee80211_hw *hw,
|
||||||
struct ieee80211_vif *vif,
|
struct ieee80211_vif *vif,
|
||||||
enum nl80211_iftype new_type, bool p2p)
|
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);
|
wl1271_op_remove_interface(hw, vif);
|
||||||
|
|
||||||
vif->type = ieee80211_iftype_p2p(new_type, p2p);
|
vif->type = ieee80211_iftype_p2p(new_type, p2p);
|
||||||
vif->p2p = 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,
|
static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||||
|
|
|
@ -370,7 +370,9 @@ module_exit(wl1271_exit);
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
|
MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
|
||||||
MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
|
MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
|
||||||
MODULE_FIRMWARE(WL127X_FW_NAME);
|
MODULE_FIRMWARE(WL127X_FW_NAME_SINGLE);
|
||||||
MODULE_FIRMWARE(WL128X_FW_NAME);
|
MODULE_FIRMWARE(WL127X_FW_NAME_MULTI);
|
||||||
MODULE_FIRMWARE(WL127X_PLT_FW_NAME);
|
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_FIRMWARE(WL128X_PLT_FW_NAME);
|
||||||
|
|
|
@ -433,8 +433,10 @@ module_exit(wl1271_exit);
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
|
MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
|
||||||
MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
|
MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
|
||||||
MODULE_FIRMWARE(WL127X_FW_NAME);
|
MODULE_FIRMWARE(WL127X_FW_NAME_SINGLE);
|
||||||
MODULE_FIRMWARE(WL128X_FW_NAME);
|
MODULE_FIRMWARE(WL127X_FW_NAME_MULTI);
|
||||||
MODULE_FIRMWARE(WL127X_PLT_FW_NAME);
|
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_FIRMWARE(WL128X_PLT_FW_NAME);
|
||||||
MODULE_ALIAS("spi:wl1271");
|
MODULE_ALIAS("spi:wl1271");
|
||||||
|
|
|
@ -35,8 +35,12 @@
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
#include "ini.h"
|
#include "ini.h"
|
||||||
|
|
||||||
#define WL127X_FW_NAME "ti-connectivity/wl127x-fw-4-sr.bin"
|
#define WL127X_FW_NAME_MULTI "ti-connectivity/wl127x-fw-4-mr.bin"
|
||||||
#define WL128X_FW_NAME "ti-connectivity/wl128x-fw-4-sr.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 WL127X_PLT_FW_NAME "ti-connectivity/wl127x-fw-4-plt.bin"
|
||||||
#define WL128X_PLT_FW_NAME "ti-connectivity/wl128x-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 {
|
enum wl12xx_fw_type {
|
||||||
WL12XX_FW_TYPE_NONE,
|
WL12XX_FW_TYPE_NONE,
|
||||||
WL12XX_FW_TYPE_NORMAL,
|
WL12XX_FW_TYPE_NORMAL,
|
||||||
|
WL12XX_FW_TYPE_MULTI,
|
||||||
WL12XX_FW_TYPE_PLT,
|
WL12XX_FW_TYPE_PLT,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -254,6 +259,7 @@ enum wl12xx_flags {
|
||||||
WL1271_FLAG_PENDING_WORK,
|
WL1271_FLAG_PENDING_WORK,
|
||||||
WL1271_FLAG_SOFT_GEMINI,
|
WL1271_FLAG_SOFT_GEMINI,
|
||||||
WL1271_FLAG_RECOVERY_IN_PROGRESS,
|
WL1271_FLAG_RECOVERY_IN_PROGRESS,
|
||||||
|
WL1271_FLAG_VIF_CHANGE_IN_PROGRESS,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum wl12xx_vif_flags {
|
enum wl12xx_vif_flags {
|
||||||
|
@ -303,6 +309,7 @@ struct wl1271 {
|
||||||
enum wl1271_state state;
|
enum wl1271_state state;
|
||||||
enum wl12xx_fw_type fw_type;
|
enum wl12xx_fw_type fw_type;
|
||||||
bool plt;
|
bool plt;
|
||||||
|
u8 last_vif_count;
|
||||||
struct mutex mutex;
|
struct mutex mutex;
|
||||||
|
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
Loading…
Reference in New Issue