aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLior David <liord@codeaurora.org>2018-02-26 13:12:12 -0500
committerKalle Valo <kvalo@codeaurora.org>2018-02-27 11:50:11 -0500
commit7bfe9e22e487b0cb14bc3bd03e6e987d9789756b (patch)
tree3f25c48d4b8f38eefb80fba09cc41de54936fba2
parent9f38f28624555af82a2909c9716688367d7297b1 (diff)
wil6210: support concurrency record in FW file
New FW which supports multiple virtual interfaces, reports its allowed interface combinations using a special comment record in the FW file. The format of the interface combinations is similar to the kernel wiphy->iface_combinations. When parsing FW file during module initialization, also parse and validate the concurrency record, and initialize wiphy->n_iface_combinations and wiphy->iface_combinations accordingly. Signed-off-by: Lior David <liord@codeaurora.org> Signed-off-by: Maya Erez <merez@codeaurora.org> Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
-rw-r--r--drivers/net/wireless/ath/wil6210/cfg80211.c69
-rw-r--r--drivers/net/wireless/ath/wil6210/fw.h38
-rw-r--r--drivers/net/wireless/ath/wil6210/fw_inc.c52
-rw-r--r--drivers/net/wireless/ath/wil6210/wil6210.h4
4 files changed, 158 insertions, 5 deletions
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index eeed85cf7b10..c959f152091f 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -20,6 +20,7 @@
20#include <net/netlink.h> 20#include <net/netlink.h>
21#include "wil6210.h" 21#include "wil6210.h"
22#include "wmi.h" 22#include "wmi.h"
23#include "fw.h"
23 24
24#define WIL_MAX_ROC_DURATION_MS 5000 25#define WIL_MAX_ROC_DURATION_MS 5000
25 26
@@ -1896,6 +1897,71 @@ static void wil_wiphy_init(struct wiphy *wiphy)
1896#endif 1897#endif
1897} 1898}
1898 1899
1900int wil_cfg80211_iface_combinations_from_fw(
1901 struct wil6210_priv *wil, const struct wil_fw_record_concurrency *conc)
1902{
1903 struct wiphy *wiphy = wil_to_wiphy(wil);
1904 u32 total_limits = 0;
1905 u16 n_combos;
1906 const struct wil_fw_concurrency_combo *combo;
1907 const struct wil_fw_concurrency_limit *limit;
1908 struct ieee80211_iface_combination *iface_combinations;
1909 struct ieee80211_iface_limit *iface_limit;
1910 int i, j;
1911
1912 if (wiphy->iface_combinations) {
1913 wil_dbg_misc(wil, "iface_combinations already set, skipping\n");
1914 return 0;
1915 }
1916
1917 combo = conc->combos;
1918 n_combos = le16_to_cpu(conc->n_combos);
1919 for (i = 0; i < n_combos; i++) {
1920 total_limits += combo->n_limits;
1921 limit = combo->limits + combo->n_limits;
1922 combo = (struct wil_fw_concurrency_combo *)limit;
1923 }
1924
1925 iface_combinations =
1926 kzalloc(n_combos * sizeof(struct ieee80211_iface_combination) +
1927 total_limits * sizeof(struct ieee80211_iface_limit),
1928 GFP_KERNEL);
1929 if (!iface_combinations)
1930 return -ENOMEM;
1931 iface_limit = (struct ieee80211_iface_limit *)(iface_combinations +
1932 n_combos);
1933 combo = conc->combos;
1934 for (i = 0; i < n_combos; i++) {
1935 iface_combinations[i].max_interfaces = combo->max_interfaces;
1936 iface_combinations[i].num_different_channels =
1937 combo->n_diff_channels;
1938 iface_combinations[i].beacon_int_infra_match =
1939 combo->same_bi;
1940 iface_combinations[i].n_limits = combo->n_limits;
1941 wil_dbg_misc(wil,
1942 "iface_combination %d: max_if %d, num_ch %d, bi_match %d\n",
1943 i, iface_combinations[i].max_interfaces,
1944 iface_combinations[i].num_different_channels,
1945 iface_combinations[i].beacon_int_infra_match);
1946 limit = combo->limits;
1947 for (j = 0; j < combo->n_limits; j++) {
1948 iface_limit[j].max = le16_to_cpu(limit[j].max);
1949 iface_limit[j].types = le16_to_cpu(limit[j].types);
1950 wil_dbg_misc(wil,
1951 "limit %d: max %d types 0x%x\n", j,
1952 iface_limit[j].max, iface_limit[j].types);
1953 }
1954 iface_combinations[i].limits = iface_limit;
1955 iface_limit += combo->n_limits;
1956 limit += combo->n_limits;
1957 combo = (struct wil_fw_concurrency_combo *)limit;
1958 }
1959
1960 wiphy->n_iface_combinations = n_combos;
1961 wiphy->iface_combinations = iface_combinations;
1962 return 0;
1963}
1964
1899struct wil6210_priv *wil_cfg80211_init(struct device *dev) 1965struct wil6210_priv *wil_cfg80211_init(struct device *dev)
1900{ 1966{
1901 struct wiphy *wiphy; 1967 struct wiphy *wiphy;
@@ -1934,6 +2000,9 @@ void wil_cfg80211_deinit(struct wil6210_priv *wil)
1934 if (!wiphy) 2000 if (!wiphy)
1935 return; 2001 return;
1936 2002
2003 kfree(wiphy->iface_combinations);
2004 wiphy->iface_combinations = NULL;
2005
1937 wiphy_free(wiphy); 2006 wiphy_free(wiphy);
1938 /* do not access wil6210_priv after returning from here */ 2007 /* do not access wil6210_priv after returning from here */
1939} 2008}
diff --git a/drivers/net/wireless/ath/wil6210/fw.h b/drivers/net/wireless/ath/wil6210/fw.h
index 2c7b24f61587..3e7a28045cab 100644
--- a/drivers/net/wireless/ath/wil6210/fw.h
+++ b/drivers/net/wireless/ath/wil6210/fw.h
@@ -14,6 +14,8 @@
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */ 16 */
17#ifndef __WIL_FW_H__
18#define __WIL_FW_H__
17 19
18#define WIL_FW_SIGNATURE (0x36323130) /* '0126' */ 20#define WIL_FW_SIGNATURE (0x36323130) /* '0126' */
19#define WIL_FW_FMT_VERSION (1) /* format version driver supports */ 21#define WIL_FW_FMT_VERSION (1) /* format version driver supports */
@@ -71,7 +73,39 @@ struct wil_fw_record_capabilities { /* type == wil_fw_type_comment */
71 struct wil_fw_record_comment_hdr hdr; 73 struct wil_fw_record_comment_hdr hdr;
72 /* capabilities (variable size), see enum wmi_fw_capability */ 74 /* capabilities (variable size), see enum wmi_fw_capability */
73 u8 capabilities[0]; 75 u8 capabilities[0];
74}; 76} __packed;
77
78/* FW VIF concurrency encoded inside a comment record
79 * Format is similar to wiphy->iface_combinations
80 */
81#define WIL_FW_CONCURRENCY_MAGIC (0xfedccdef)
82#define WIL_FW_CONCURRENCY_REC_VER 1
83struct wil_fw_concurrency_limit {
84 __le16 max; /* maximum number of interfaces of these types */
85 __le16 types; /* interface types (bit mask of enum nl80211_iftype) */
86} __packed;
87
88struct wil_fw_concurrency_combo {
89 u8 n_limits; /* number of wil_fw_concurrency_limit entries */
90 u8 max_interfaces; /* max number of concurrent interfaces allowed */
91 u8 n_diff_channels; /* total number of different channels allowed */
92 u8 same_bi; /* for APs, 1 if all APs must have same BI */
93 /* keep last - concurrency limits, variable size by n_limits */
94 struct wil_fw_concurrency_limit limits[0];
95} __packed;
96
97struct wil_fw_record_concurrency { /* type == wil_fw_type_comment */
98 /* identifies concurrency record */
99 __le32 magic;
100 /* structure version, currently always 1 */
101 u8 version;
102 /* maximum number of supported MIDs _in addition_ to MID 0 */
103 u8 n_mids;
104 /* number of concurrency combinations that follow */
105 __le16 n_combos;
106 /* keep last - combinations, variable size by n_combos */
107 struct wil_fw_concurrency_combo combos[0];
108} __packed;
75 109
76/* brd file info encoded inside a comment record */ 110/* brd file info encoded inside a comment record */
77#define WIL_BRD_FILE_MAGIC (0xabcddcbb) 111#define WIL_BRD_FILE_MAGIC (0xabcddcbb)
@@ -175,3 +209,5 @@ struct wil_fw_record_gateway_data4 { /* type == wil_fw_type_gateway_data4 */
175 __le32 command; 209 __le32 command;
176 struct wil_fw_data_gw4 data[0]; /* total size [data_size], see above */ 210 struct wil_fw_data_gw4 data[0]; /* total size [data_size], see above */
177} __packed; 211} __packed;
212
213#endif /* __WIL_FW_H__ */
diff --git a/drivers/net/wireless/ath/wil6210/fw_inc.c b/drivers/net/wireless/ath/wil6210/fw_inc.c
index 914c0106e94b..718161b829c2 100644
--- a/drivers/net/wireless/ath/wil6210/fw_inc.c
+++ b/drivers/net/wireless/ath/wil6210/fw_inc.c
@@ -136,8 +136,8 @@ fw_handle_capabilities(struct wil6210_priv *wil, const void *data,
136 size_t capa_size; 136 size_t capa_size;
137 137
138 if (size < sizeof(*rec)) { 138 if (size < sizeof(*rec)) {
139 wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1, 139 wil_err_fw(wil, "capabilities record too short: %zu\n", size);
140 data, size, true); 140 /* let the FW load anyway */
141 return 0; 141 return 0;
142 } 142 }
143 143
@@ -158,8 +158,7 @@ fw_handle_brd_file(struct wil6210_priv *wil, const void *data,
158 const struct wil_fw_record_brd_file *rec = data; 158 const struct wil_fw_record_brd_file *rec = data;
159 159
160 if (size < sizeof(*rec)) { 160 if (size < sizeof(*rec)) {
161 wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1, 161 wil_err_fw(wil, "brd_file record too short: %zu\n", size);
162 data, size, true);
163 return 0; 162 return 0;
164 } 163 }
165 164
@@ -173,6 +172,44 @@ fw_handle_brd_file(struct wil6210_priv *wil, const void *data,
173} 172}
174 173
175static int 174static int
175fw_handle_concurrency(struct wil6210_priv *wil, const void *data,
176 size_t size)
177{
178 const struct wil_fw_record_concurrency *rec = data;
179 const struct wil_fw_concurrency_combo *combo;
180 const struct wil_fw_concurrency_limit *limit;
181 size_t remain, lsize;
182 int i, n_combos;
183
184 if (size < sizeof(*rec)) {
185 wil_err_fw(wil, "concurrency record too short: %zu\n", size);
186 /* continue, let the FW load anyway */
187 return 0;
188 }
189
190 n_combos = le16_to_cpu(rec->n_combos);
191 remain = size - offsetof(struct wil_fw_record_concurrency, combos);
192 combo = rec->combos;
193 for (i = 0; i < n_combos; i++) {
194 if (remain < sizeof(*combo))
195 goto out_short;
196 remain -= sizeof(*combo);
197 limit = combo->limits;
198 lsize = combo->n_limits * sizeof(*limit);
199 if (remain < lsize)
200 goto out_short;
201 remain -= lsize;
202 limit += combo->n_limits;
203 combo = (struct wil_fw_concurrency_combo *)limit;
204 }
205
206 return wil_cfg80211_iface_combinations_from_fw(wil, rec);
207out_short:
208 wil_err_fw(wil, "concurrency record truncated\n");
209 return 0;
210}
211
212static int
176fw_handle_comment(struct wil6210_priv *wil, const void *data, 213fw_handle_comment(struct wil6210_priv *wil, const void *data,
177 size_t size) 214 size_t size)
178{ 215{
@@ -194,6 +231,13 @@ fw_handle_comment(struct wil6210_priv *wil, const void *data,
194 wil_dbg_fw(wil, "magic is WIL_BRD_FILE_MAGIC\n"); 231 wil_dbg_fw(wil, "magic is WIL_BRD_FILE_MAGIC\n");
195 rc = fw_handle_brd_file(wil, data, size); 232 rc = fw_handle_brd_file(wil, data, size);
196 break; 233 break;
234 case WIL_FW_CONCURRENCY_MAGIC:
235 wil_dbg_fw(wil, "magic is WIL_FW_CONCURRENCY_MAGIC\n");
236 rc = fw_handle_concurrency(wil, data, size);
237 break;
238 default:
239 wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1,
240 data, size, true);
197 } 241 }
198 242
199 return rc; 243 return rc;
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index b33aa7ddf24e..81cb27af64e4 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -26,6 +26,7 @@
26#include <linux/types.h> 26#include <linux/types.h>
27#include "wmi.h" 27#include "wmi.h"
28#include "wil_platform.h" 28#include "wil_platform.h"
29#include "fw.h"
29 30
30extern bool no_fw_recovery; 31extern bool no_fw_recovery;
31extern unsigned int mtu_max; 32extern unsigned int mtu_max;
@@ -1012,6 +1013,9 @@ int wmi_stop_discovery(struct wil6210_priv *wil);
1012int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, 1013int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
1013 struct cfg80211_mgmt_tx_params *params, 1014 struct cfg80211_mgmt_tx_params *params,
1014 u64 *cookie); 1015 u64 *cookie);
1016int wil_cfg80211_iface_combinations_from_fw(
1017 struct wil6210_priv *wil,
1018 const struct wil_fw_record_concurrency *conc);
1015 1019
1016#if defined(CONFIG_WIL6210_DEBUGFS) 1020#if defined(CONFIG_WIL6210_DEBUGFS)
1017int wil6210_debugfs_init(struct wil6210_priv *wil); 1021int wil6210_debugfs_init(struct wil6210_priv *wil);