diff options
Diffstat (limited to 'drivers/net/wireless/marvell')
-rw-r--r-- | drivers/net/wireless/marvell/libertas/cfg.c | 9 | ||||
-rw-r--r-- | drivers/net/wireless/marvell/libertas/if_sdio.c | 3 | ||||
-rw-r--r-- | drivers/net/wireless/marvell/libertas/if_spi.c | 3 | ||||
-rw-r--r-- | drivers/net/wireless/marvell/libertas_tf/main.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/marvell/mwifiex/cfg80211.c | 12 | ||||
-rw-r--r-- | drivers/net/wireless/marvell/mwifiex/main.c | 9 | ||||
-rw-r--r-- | drivers/net/wireless/marvell/mwifiex/main.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/marvell/mwifiex/sta_cmd.c | 113 | ||||
-rw-r--r-- | drivers/net/wireless/marvell/mwifiex/sta_ioctl.c | 58 |
9 files changed, 197 insertions, 15 deletions
diff --git a/drivers/net/wireless/marvell/libertas/cfg.c b/drivers/net/wireless/marvell/libertas/cfg.c index 94dd488becaf..caba7491cd5a 100644 --- a/drivers/net/wireless/marvell/libertas/cfg.c +++ b/drivers/net/wireless/marvell/libertas/cfg.c @@ -1151,10 +1151,13 @@ static int lbs_associate(struct lbs_private *priv, /* add SSID TLV */ rcu_read_lock(); ssid_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SSID); - if (ssid_eid) - pos += lbs_add_ssid_tlv(pos, ssid_eid + 2, ssid_eid[1]); - else + if (ssid_eid) { + u32 ssid_len = min(ssid_eid[1], IEEE80211_MAX_SSID_LEN); + + pos += lbs_add_ssid_tlv(pos, ssid_eid + 2, ssid_len); + } else { lbs_deb_assoc("no SSID\n"); + } rcu_read_unlock(); /* add DS param TLV */ diff --git a/drivers/net/wireless/marvell/libertas/if_sdio.c b/drivers/net/wireless/marvell/libertas/if_sdio.c index 524034699972..fc5318035822 100644 --- a/drivers/net/wireless/marvell/libertas/if_sdio.c +++ b/drivers/net/wireless/marvell/libertas/if_sdio.c @@ -1181,7 +1181,8 @@ static int if_sdio_probe(struct sdio_func *func, spin_lock_init(&card->lock); INIT_LIST_HEAD(&card->packets); - card->workqueue = alloc_workqueue("libertas_sdio", WQ_MEM_RECLAIM, 0); + card->workqueue = alloc_workqueue("libertas_sdio", + WQ_MEM_RECLAIM | WQ_UNBOUND, 0); if (unlikely(!card->workqueue)) { ret = -ENOMEM; goto err_queue; diff --git a/drivers/net/wireless/marvell/libertas/if_spi.c b/drivers/net/wireless/marvell/libertas/if_spi.c index b722a6587fd3..8a2504a62840 100644 --- a/drivers/net/wireless/marvell/libertas/if_spi.c +++ b/drivers/net/wireless/marvell/libertas/if_spi.c @@ -1153,7 +1153,8 @@ static int if_spi_probe(struct spi_device *spi) priv->fw_ready = 1; /* Initialize interrupt handling stuff. */ - card->workqueue = alloc_workqueue("libertas_spi", WQ_MEM_RECLAIM, 0); + card->workqueue = alloc_workqueue("libertas_spi", + WQ_MEM_RECLAIM | WQ_UNBOUND, 0); if (!card->workqueue) { err = -ENOMEM; goto remove_card; diff --git a/drivers/net/wireless/marvell/libertas_tf/main.c b/drivers/net/wireless/marvell/libertas_tf/main.c index d1067874428f..fb20fe31cd36 100644 --- a/drivers/net/wireless/marvell/libertas_tf/main.c +++ b/drivers/net/wireless/marvell/libertas_tf/main.c @@ -708,7 +708,7 @@ EXPORT_SYMBOL_GPL(lbtf_bcn_sent); static int __init lbtf_init_module(void) { lbtf_deb_enter(LBTF_DEB_MAIN); - lbtf_wq = alloc_workqueue("libertastf", WQ_MEM_RECLAIM, 0); + lbtf_wq = alloc_workqueue("libertastf", WQ_MEM_RECLAIM | WQ_UNBOUND, 0); if (lbtf_wq == NULL) { printk(KERN_ERR "libertastf: couldn't create workqueue\n"); return -ENOMEM; diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c index 3498743d5ec0..be23a29e7de0 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c @@ -686,10 +686,9 @@ static void mwifiex_reg_notifier(struct wiphy *wiphy, return; } - /* Don't send world or same regdom info to firmware */ - if (strncmp(request->alpha2, "00", 2) && - strncmp(request->alpha2, adapter->country_code, - sizeof(request->alpha2))) { + /* Don't send same regdom info to firmware */ + if (strncmp(request->alpha2, adapter->country_code, + sizeof(request->alpha2)) != 0) { memcpy(adapter->country_code, request->alpha2, sizeof(request->alpha2)); mwifiex_send_domain_info_cmd_fw(wiphy); @@ -4673,8 +4672,9 @@ int mwifiex_init_channel_scan_gap(struct mwifiex_adapter *adapter) * additional active scan request for hidden SSIDs on passive channels. */ adapter->num_in_chan_stats = 2 * (n_channels_bg + n_channels_a); - adapter->chan_stats = vmalloc(array_size(sizeof(*adapter->chan_stats), - adapter->num_in_chan_stats)); + adapter->chan_stats = kcalloc(adapter->num_in_chan_stats, + sizeof(*adapter->chan_stats), + GFP_KERNEL); if (!adapter->chan_stats) return -ENOMEM; diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c index 7b50a88a18e5..ff177b06f42d 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.c +++ b/drivers/net/wireless/marvell/mwifiex/main.c @@ -494,6 +494,11 @@ static void mwifiex_free_adapter(struct mwifiex_adapter *adapter) return; } + if (adapter->rgpower_data) { + release_firmware(adapter->rgpower_data); + adapter->rgpower_data = NULL; + } + mwifiex_unregister(adapter); pr_debug("info: %s: free adapter\n", __func__); } @@ -642,7 +647,7 @@ static int _mwifiex_fw_dpc(const struct firmware *firmware, void *context) goto done; err_add_intf: - vfree(adapter->chan_stats); + kfree(adapter->chan_stats); err_init_chan_scan: wiphy_unregister(adapter->wiphy); wiphy_free(adapter->wiphy); @@ -1485,7 +1490,7 @@ static void mwifiex_uninit_sw(struct mwifiex_adapter *adapter) wiphy_free(adapter->wiphy); adapter->wiphy = NULL; - vfree(adapter->chan_stats); + kfree(adapter->chan_stats); mwifiex_free_cmd_buffers(adapter); } diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h index 9ac36bef980e..27559e2ddc31 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.h +++ b/drivers/net/wireless/marvell/mwifiex/main.h @@ -982,6 +982,7 @@ struct mwifiex_adapter { u8 country_code[IEEE80211_COUNTRY_STRING_LEN]; u16 max_mgmt_ie_index; const struct firmware *cal_data; + const struct firmware *rgpower_data; struct device_node *dt_node; /* 11AC */ @@ -1579,6 +1580,8 @@ int mwifiex_11h_handle_event_chanswann(struct mwifiex_private *priv); int mwifiex_dnld_dt_cfgdata(struct mwifiex_private *priv, struct device_node *node, const char *prefix); void mwifiex_dnld_txpwr_table(struct mwifiex_private *priv); +int mwifiex_send_rgpower_table(struct mwifiex_private *priv, const u8 *data, + const size_t size); extern const struct ethtool_ops mwifiex_ethtool_ops; diff --git a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c index c93281f5a47c..dcca71158fc6 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c @@ -1483,6 +1483,119 @@ int mwifiex_dnld_dt_cfgdata(struct mwifiex_private *priv, return 0; } +static int mwifiex_rgpower_table_advance_to_content(u8 **pos, const u8 *data, + const size_t size) +{ + while (*pos - data < size) { + /* skip spaces, tabs and empty lines */ + if (**pos == '\r' || **pos == '\n' || **pos == '\0' || + isspace(**pos)) { + (*pos)++; + continue; + } + /* skip line comments */ + if (**pos == '#') { + *pos = strchr(*pos, '\n'); + if (!*pos) + return -EINVAL; + (*pos)++; + continue; + } + return 0; + } + return 0; +} + +int mwifiex_send_rgpower_table(struct mwifiex_private *priv, const u8 *data, + const size_t size) +{ + int ret = 0; + bool start_raw = false; + u8 *ptr, *token, *pos = NULL; + u8 *_data __free(kfree) = NULL; + struct mwifiex_adapter *adapter = priv->adapter; + struct mwifiex_ds_misc_cmd *hostcmd __free(kfree) = NULL; + + hostcmd = kzalloc(sizeof(*hostcmd), GFP_KERNEL); + if (!hostcmd) + return -ENOMEM; + + _data = kmemdup(data, size, GFP_KERNEL); + if (!_data) + return -ENOMEM; + + pos = _data; + ptr = hostcmd->cmd; + while ((pos - _data) < size) { + ret = mwifiex_rgpower_table_advance_to_content(&pos, _data, size); + if (ret) { + mwifiex_dbg( + adapter, ERROR, + "%s: failed to advance to content in rgpower table\n", + __func__); + return ret; + } + + if (*pos == '}' && start_raw) { + hostcmd->len = get_unaligned_le16(&hostcmd->cmd[2]); + ret = mwifiex_send_cmd(priv, 0, 0, 0, hostcmd, false); + if (ret) { + mwifiex_dbg(adapter, ERROR, + "%s: failed to send hostcmd %d\n", + __func__, ret); + return ret; + } + + memset(hostcmd->cmd, 0, MWIFIEX_SIZE_OF_CMD_BUFFER); + ptr = hostcmd->cmd; + start_raw = false; + pos++; + continue; + } + + if (!start_raw) { + pos = strchr(pos, '='); + if (pos) { + pos = strchr(pos, '{'); + if (pos) { + start_raw = true; + pos++; + continue; + } + } + mwifiex_dbg(adapter, ERROR, + "%s: syntax error in hostcmd\n", __func__); + return -EINVAL; + } + + if (start_raw) { + while ((*pos != '\r' && *pos != '\n') && + (token = strsep((char **)&pos, " "))) { + if (ptr - hostcmd->cmd >= + MWIFIEX_SIZE_OF_CMD_BUFFER) { + mwifiex_dbg( + adapter, ERROR, + "%s: hostcmd is larger than %d, aborting\n", + __func__, MWIFIEX_SIZE_OF_CMD_BUFFER); + return -ENOMEM; + } + + ret = kstrtou8(token, 16, ptr); + if (ret < 0) { + mwifiex_dbg( + adapter, ERROR, + "%s: failed to parse hostcmd %d token: %s\n", + __func__, ret, token); + return ret; + } + ptr++; + } + } + } + + return ret; +} + /* This function prepares command of set_cfg_data. */ static int mwifiex_cmd_cfg_data(struct mwifiex_private *priv, struct host_cmd_ds_command *cmd, void *data_buf) diff --git a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c index f79589cafe57..ef6722ffdc74 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c @@ -180,7 +180,7 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv, return mwifiex_update_bss_desc_with_ie(priv->adapter, bss_desc); } -void mwifiex_dnld_txpwr_table(struct mwifiex_private *priv) +static void mwifiex_dnld_dt_txpwr_table(struct mwifiex_private *priv) { if (priv->adapter->dt_node) { char txpwr[] = {"marvell,00_txpwrlimit"}; @@ -190,6 +190,62 @@ void mwifiex_dnld_txpwr_table(struct mwifiex_private *priv) } } +static int mwifiex_request_rgpower_table(struct mwifiex_private *priv) +{ + struct mwifiex_802_11d_domain_reg *domain_info = &priv->adapter->domain_reg; + struct mwifiex_adapter *adapter = priv->adapter; + char rgpower_table_name[30]; + char country_code[3]; + + strscpy(country_code, domain_info->country_code, sizeof(country_code)); + + /* World regulatory domain "00" has WW as country code */ + if (strncmp(country_code, "00", 2) == 0) + strscpy(country_code, "WW", sizeof(country_code)); + + snprintf(rgpower_table_name, sizeof(rgpower_table_name), + "nxp/rgpower_%s.bin", country_code); + + mwifiex_dbg(adapter, INFO, "info: %s: requesting regulatory power table %s\n", + __func__, rgpower_table_name); + + if (adapter->rgpower_data) { + release_firmware(adapter->rgpower_data); + adapter->rgpower_data = NULL; + } + + if ((request_firmware(&adapter->rgpower_data, rgpower_table_name, + adapter->dev))) { + mwifiex_dbg( + adapter, INFO, + "info: %s: failed to request regulatory power table\n", + __func__); + return -EIO; + } + + return 0; +} + +static int mwifiex_dnld_rgpower_table(struct mwifiex_private *priv) +{ + int ret; + + ret = mwifiex_request_rgpower_table(priv); + if (ret) + return ret; + + return mwifiex_send_rgpower_table(priv, priv->adapter->rgpower_data->data, + priv->adapter->rgpower_data->size); +} + +void mwifiex_dnld_txpwr_table(struct mwifiex_private *priv) +{ + if (mwifiex_dnld_rgpower_table(priv) == 0) + return; + + mwifiex_dnld_dt_txpwr_table(priv); +} + static int mwifiex_process_country_ie(struct mwifiex_private *priv, struct cfg80211_bss *bss) { |