diff options
| author | Lior David <liord@codeaurora.org> | 2018-02-26 13:12:12 -0500 |
|---|---|---|
| committer | Kalle Valo <kvalo@codeaurora.org> | 2018-02-27 11:50:11 -0500 |
| commit | 7bfe9e22e487b0cb14bc3bd03e6e987d9789756b (patch) | |
| tree | 3f25c48d4b8f38eefb80fba09cc41de54936fba2 | |
| parent | 9f38f28624555af82a2909c9716688367d7297b1 (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.c | 69 | ||||
| -rw-r--r-- | drivers/net/wireless/ath/wil6210/fw.h | 38 | ||||
| -rw-r--r-- | drivers/net/wireless/ath/wil6210/fw_inc.c | 52 | ||||
| -rw-r--r-- | drivers/net/wireless/ath/wil6210/wil6210.h | 4 |
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 | ||
| 1900 | int 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 | |||
| 1899 | struct wil6210_priv *wil_cfg80211_init(struct device *dev) | 1965 | struct 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 | ||
| 83 | struct 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 | |||
| 88 | struct 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 | |||
| 97 | struct 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 | ||
| 175 | static int | 174 | static int |
| 175 | fw_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); | ||
| 207 | out_short: | ||
| 208 | wil_err_fw(wil, "concurrency record truncated\n"); | ||
| 209 | return 0; | ||
| 210 | } | ||
| 211 | |||
| 212 | static int | ||
| 176 | fw_handle_comment(struct wil6210_priv *wil, const void *data, | 213 | fw_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 | ||
| 30 | extern bool no_fw_recovery; | 31 | extern bool no_fw_recovery; |
| 31 | extern unsigned int mtu_max; | 32 | extern unsigned int mtu_max; |
| @@ -1012,6 +1013,9 @@ int wmi_stop_discovery(struct wil6210_priv *wil); | |||
| 1012 | int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, | 1013 | int 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); |
| 1016 | int 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) |
| 1017 | int wil6210_debugfs_init(struct wil6210_priv *wil); | 1021 | int wil6210_debugfs_init(struct wil6210_priv *wil); |
