aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/wl12xx
diff options
context:
space:
mode:
authorEliad Peller <eliad@wizery.com>2012-02-06 06:07:52 -0500
committerLuciano Coelho <coelho@ti.com>2012-02-15 01:38:36 -0500
commit4549d09c57cf44ae9ab6095c375bad5c100658c7 (patch)
treef6093845de683aa220183a85aab6e1bcd082b9bf /drivers/net/wireless/wl12xx
parent3fcdab7066a31ae90ac2beba7d38e8e606374998 (diff)
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>
Diffstat (limited to 'drivers/net/wireless/wl12xx')
-rw-r--r--drivers/net/wireless/wl12xx/main.c114
-rw-r--r--drivers/net/wireless/wl12xx/sdio.c6
-rw-r--r--drivers/net/wireless/wl12xx/spi.c6
-rw-r--r--drivers/net/wireless/wl12xx/wl12xx.h11
4 files changed, 124 insertions, 13 deletions
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index c10940703e8c..b3b4c4019787 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -993,6 +993,35 @@ out:
993 return IRQ_HANDLED; 993 return IRQ_HANDLED;
994} 994}
995 995
996struct vif_counter_data {
997 u8 counter;
998
999 struct ieee80211_vif *cur_vif;
1000 bool cur_vif_running;
1001};
1002
1003static void wl12xx_vif_count_iter(void *data, u8 *mac,
1004 struct ieee80211_vif *vif)
1005{
1006 struct vif_counter_data *counter = data;
1007
1008 counter->counter++;
1009 if (counter->cur_vif == vif)
1010 counter->cur_vif_running = true;
1011}
1012
1013/* caller must not hold wl->mutex, as it might deadlock */
1014static void wl12xx_get_vif_count(struct ieee80211_hw *hw,
1015 struct ieee80211_vif *cur_vif,
1016 struct vif_counter_data *data)
1017{
1018 memset(data, 0, sizeof(*data));
1019 data->cur_vif = cur_vif;
1020
1021 ieee80211_iterate_active_interfaces(hw,
1022 wl12xx_vif_count_iter, data);
1023}
1024
996static int wl12xx_fetch_firmware(struct wl1271 *wl, bool plt) 1025static int wl12xx_fetch_firmware(struct wl1271 *wl, bool plt)
997{ 1026{
998 const struct firmware *fw; 1027 const struct firmware *fw;
@@ -1007,11 +1036,23 @@ static int wl12xx_fetch_firmware(struct wl1271 *wl, bool plt)
1007 else 1036 else
1008 fw_name = WL127X_PLT_FW_NAME; 1037 fw_name = WL127X_PLT_FW_NAME;
1009 } else { 1038 } else {
1010 fw_type = WL12XX_FW_TYPE_NORMAL; 1039 /*
1011 if (wl->chip.id == CHIP_ID_1283_PG20) 1040 * we can't call wl12xx_get_vif_count() here because
1012 fw_name = WL128X_FW_NAME; 1041 * wl->mutex is taken, so use the cached last_vif_count value
1013 else 1042 */
1014 fw_name = WL127X_FW_NAME; 1043 if (wl->last_vif_count > 1) {
1044 fw_type = WL12XX_FW_TYPE_MULTI;
1045 if (wl->chip.id == CHIP_ID_1283_PG20)
1046 fw_name = WL128X_FW_NAME_MULTI;
1047 else
1048 fw_name = WL127X_FW_NAME_MULTI;
1049 } else {
1050 fw_type = WL12XX_FW_TYPE_NORMAL;
1051 if (wl->chip.id == CHIP_ID_1283_PG20)
1052 fw_name = WL128X_FW_NAME_SINGLE;
1053 else
1054 fw_name = WL127X_FW_NAME_SINGLE;
1055 }
1015 } 1056 }
1016 1057
1017 if (wl->fw_type == fw_type) 1058 if (wl->fw_type == fw_type)
@@ -2074,11 +2115,47 @@ static bool wl12xx_dev_role_started(struct wl12xx_vif *wlvif)
2074 return wlvif->dev_hlid != WL12XX_INVALID_LINK_ID; 2115 return wlvif->dev_hlid != WL12XX_INVALID_LINK_ID;
2075} 2116}
2076 2117
2118/*
2119 * Check whether a fw switch (i.e. moving from one loaded
2120 * fw to another) is needed. This function is also responsible
2121 * for updating wl->last_vif_count, so it must be called before
2122 * loading a non-plt fw (so the correct fw (single-role/multi-role)
2123 * will be used).
2124 */
2125static bool wl12xx_need_fw_change(struct wl1271 *wl,
2126 struct vif_counter_data vif_counter_data,
2127 bool add)
2128{
2129 enum wl12xx_fw_type current_fw = wl->fw_type;
2130 u8 vif_count = vif_counter_data.counter;
2131
2132 if (test_bit(WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, &wl->flags))
2133 return false;
2134
2135 /* increase the vif count if this is a new vif */
2136 if (add && !vif_counter_data.cur_vif_running)
2137 vif_count++;
2138
2139 wl->last_vif_count = vif_count;
2140
2141 /* no need for fw change if the device is OFF */
2142 if (wl->state == WL1271_STATE_OFF)
2143 return false;
2144
2145 if (vif_count > 1 && current_fw == WL12XX_FW_TYPE_NORMAL)
2146 return true;
2147 if (vif_count <= 1 && current_fw == WL12XX_FW_TYPE_MULTI)
2148 return true;
2149
2150 return false;
2151}
2152
2077static int wl1271_op_add_interface(struct ieee80211_hw *hw, 2153static int wl1271_op_add_interface(struct ieee80211_hw *hw,
2078 struct ieee80211_vif *vif) 2154 struct ieee80211_vif *vif)
2079{ 2155{
2080 struct wl1271 *wl = hw->priv; 2156 struct wl1271 *wl = hw->priv;
2081 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); 2157 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
2158 struct vif_counter_data vif_count;
2082 int ret = 0; 2159 int ret = 0;
2083 u8 role_type; 2160 u8 role_type;
2084 bool booted = false; 2161 bool booted = false;
@@ -2089,6 +2166,8 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
2089 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM", 2166 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
2090 ieee80211_vif_type_p2p(vif), vif->addr); 2167 ieee80211_vif_type_p2p(vif), vif->addr);
2091 2168
2169 wl12xx_get_vif_count(hw, vif, &vif_count);
2170
2092 mutex_lock(&wl->mutex); 2171 mutex_lock(&wl->mutex);
2093 ret = wl1271_ps_elp_wakeup(wl); 2172 ret = wl1271_ps_elp_wakeup(wl);
2094 if (ret < 0) 2173 if (ret < 0)
@@ -2124,6 +2203,12 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
2124 goto out; 2203 goto out;
2125 } 2204 }
2126 2205
2206 if (wl12xx_need_fw_change(wl, vif_count, true)) {
2207 mutex_unlock(&wl->mutex);
2208 wl1271_recovery_work(&wl->recovery_work);
2209 return 0;
2210 }
2211
2127 /* 2212 /*
2128 * TODO: after the nvs issue will be solved, move this block 2213 * TODO: after the nvs issue will be solved, move this block
2129 * to start(), and make sure here the driver is ON. 2214 * to start(), and make sure here the driver is ON.
@@ -2287,7 +2372,10 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2287 struct wl1271 *wl = hw->priv; 2372 struct wl1271 *wl = hw->priv;
2288 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); 2373 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
2289 struct wl12xx_vif *iter; 2374 struct wl12xx_vif *iter;
2375 struct vif_counter_data vif_count;
2376 bool cancel_recovery = true;
2290 2377
2378 wl12xx_get_vif_count(hw, vif, &vif_count);
2291 mutex_lock(&wl->mutex); 2379 mutex_lock(&wl->mutex);
2292 2380
2293 if (wl->state == WL1271_STATE_OFF || 2381 if (wl->state == WL1271_STATE_OFF ||
@@ -2306,20 +2394,32 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2306 break; 2394 break;
2307 } 2395 }
2308 WARN_ON(iter != wlvif); 2396 WARN_ON(iter != wlvif);
2397 if (wl12xx_need_fw_change(wl, vif_count, false)) {
2398 wl12xx_queue_recovery_work(wl);
2399 cancel_recovery = false;
2400 }
2309out: 2401out:
2310 mutex_unlock(&wl->mutex); 2402 mutex_unlock(&wl->mutex);
2311 cancel_work_sync(&wl->recovery_work); 2403 if (cancel_recovery)
2404 cancel_work_sync(&wl->recovery_work);
2312} 2405}
2313 2406
2314static int wl12xx_op_change_interface(struct ieee80211_hw *hw, 2407static int wl12xx_op_change_interface(struct ieee80211_hw *hw,
2315 struct ieee80211_vif *vif, 2408 struct ieee80211_vif *vif,
2316 enum nl80211_iftype new_type, bool p2p) 2409 enum nl80211_iftype new_type, bool p2p)
2317{ 2410{
2411 struct wl1271 *wl = hw->priv;
2412 int ret;
2413
2414 set_bit(WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, &wl->flags);
2318 wl1271_op_remove_interface(hw, vif); 2415 wl1271_op_remove_interface(hw, vif);
2319 2416
2320 vif->type = ieee80211_iftype_p2p(new_type, p2p); 2417 vif->type = ieee80211_iftype_p2p(new_type, p2p);
2321 vif->p2p = p2p; 2418 vif->p2p = p2p;
2322 return wl1271_op_add_interface(hw, vif); 2419 ret = wl1271_op_add_interface(hw, vif);
2420
2421 clear_bit(WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, &wl->flags);
2422 return ret;
2323} 2423}
2324 2424
2325static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif, 2425static 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 1c0264ca021f..4b3c32774bae 100644
--- a/drivers/net/wireless/wl12xx/sdio.c
+++ b/drivers/net/wireless/wl12xx/sdio.c
@@ -370,7 +370,9 @@ module_exit(wl1271_exit);
370MODULE_LICENSE("GPL"); 370MODULE_LICENSE("GPL");
371MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>"); 371MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
372MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>"); 372MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
373MODULE_FIRMWARE(WL127X_FW_NAME); 373MODULE_FIRMWARE(WL127X_FW_NAME_SINGLE);
374MODULE_FIRMWARE(WL128X_FW_NAME); 374MODULE_FIRMWARE(WL127X_FW_NAME_MULTI);
375MODULE_FIRMWARE(WL127X_PLT_FW_NAME); 375MODULE_FIRMWARE(WL127X_PLT_FW_NAME);
376MODULE_FIRMWARE(WL128X_FW_NAME_SINGLE);
377MODULE_FIRMWARE(WL128X_FW_NAME_MULTI);
376MODULE_FIRMWARE(WL128X_PLT_FW_NAME); 378MODULE_FIRMWARE(WL128X_PLT_FW_NAME);
diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/spi.c
index 5c2d4a0ef000..2fc18a8dcce8 100644
--- a/drivers/net/wireless/wl12xx/spi.c
+++ b/drivers/net/wireless/wl12xx/spi.c
@@ -433,8 +433,10 @@ module_exit(wl1271_exit);
433MODULE_LICENSE("GPL"); 433MODULE_LICENSE("GPL");
434MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>"); 434MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
435MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>"); 435MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
436MODULE_FIRMWARE(WL127X_FW_NAME); 436MODULE_FIRMWARE(WL127X_FW_NAME_SINGLE);
437MODULE_FIRMWARE(WL128X_FW_NAME); 437MODULE_FIRMWARE(WL127X_FW_NAME_MULTI);
438MODULE_FIRMWARE(WL127X_PLT_FW_NAME); 438MODULE_FIRMWARE(WL127X_PLT_FW_NAME);
439MODULE_FIRMWARE(WL128X_FW_NAME_SINGLE);
440MODULE_FIRMWARE(WL128X_FW_NAME_MULTI);
439MODULE_FIRMWARE(WL128X_PLT_FW_NAME); 441MODULE_FIRMWARE(WL128X_PLT_FW_NAME);
440MODULE_ALIAS("spi:wl1271"); 442MODULE_ALIAS("spi:wl1271");
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index 9b48aa48cdca..04cddaaf9498 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -35,8 +35,12 @@
35#include "conf.h" 35#include "conf.h"
36#include "ini.h" 36#include "ini.h"
37 37
38#define WL127X_FW_NAME "ti-connectivity/wl127x-fw-4-sr.bin" 38#define WL127X_FW_NAME_MULTI "ti-connectivity/wl127x-fw-4-mr.bin"
39#define WL128X_FW_NAME "ti-connectivity/wl128x-fw-4-sr.bin" 39#define WL127X_FW_NAME_SINGLE "ti-connectivity/wl127x-fw-4-sr.bin"
40
41#define WL128X_FW_NAME_MULTI "ti-connectivity/wl128x-fw-4-mr.bin"
42#define WL128X_FW_NAME_SINGLE "ti-connectivity/wl128x-fw-4-sr.bin"
43
40#define WL127X_PLT_FW_NAME "ti-connectivity/wl127x-fw-4-plt.bin" 44#define WL127X_PLT_FW_NAME "ti-connectivity/wl127x-fw-4-plt.bin"
41#define WL128X_PLT_FW_NAME "ti-connectivity/wl128x-fw-4-plt.bin" 45#define WL128X_PLT_FW_NAME "ti-connectivity/wl128x-fw-4-plt.bin"
42 46
@@ -97,6 +101,7 @@ enum wl1271_state {
97enum wl12xx_fw_type { 101enum wl12xx_fw_type {
98 WL12XX_FW_TYPE_NONE, 102 WL12XX_FW_TYPE_NONE,
99 WL12XX_FW_TYPE_NORMAL, 103 WL12XX_FW_TYPE_NORMAL,
104 WL12XX_FW_TYPE_MULTI,
100 WL12XX_FW_TYPE_PLT, 105 WL12XX_FW_TYPE_PLT,
101}; 106};
102 107
@@ -254,6 +259,7 @@ enum wl12xx_flags {
254 WL1271_FLAG_PENDING_WORK, 259 WL1271_FLAG_PENDING_WORK,
255 WL1271_FLAG_SOFT_GEMINI, 260 WL1271_FLAG_SOFT_GEMINI,
256 WL1271_FLAG_RECOVERY_IN_PROGRESS, 261 WL1271_FLAG_RECOVERY_IN_PROGRESS,
262 WL1271_FLAG_VIF_CHANGE_IN_PROGRESS,
257}; 263};
258 264
259enum wl12xx_vif_flags { 265enum wl12xx_vif_flags {
@@ -303,6 +309,7 @@ struct wl1271 {
303 enum wl1271_state state; 309 enum wl1271_state state;
304 enum wl12xx_fw_type fw_type; 310 enum wl12xx_fw_type fw_type;
305 bool plt; 311 bool plt;
312 u8 last_vif_count;
306 struct mutex mutex; 313 struct mutex mutex;
307 314
308 unsigned long flags; 315 unsigned long flags;