summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wireless/ath/wil6210/pm.c1
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2800lib.c35
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2800lib.h2
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2800pci.c3
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2800soc.c6
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2x00.h2
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2x00dev.c10
-rw-r--r--drivers/net/wireless/ti/wl18xx/debugfs.c3
-rw-r--r--drivers/net/wireless/ti/wlcore/cmd.c1
-rw-r--r--drivers/net/wireless/ti/wlcore/debugfs.c11
-rw-r--r--drivers/net/wireless/ti/wlcore/main.c36
-rw-r--r--drivers/net/wireless/ti/wlcore/scan.c1
-rw-r--r--drivers/net/wireless/ti/wlcore/sysfs.c1
-rw-r--r--drivers/net/wireless/ti/wlcore/testmode.c2
-rw-r--r--drivers/net/wireless/ti/wlcore/tx.c1
-rw-r--r--drivers/net/wireless/ti/wlcore/vendor_cmd.c3
-rw-r--r--drivers/net/wireless/virtual/mac80211_hwsim.c1
-rw-r--r--include/net/cfg80211.h18
-rw-r--r--include/net/ieee80211_radiotap.h20
-rw-r--r--include/net/mac80211.h2
-rw-r--r--net/mac80211/mlme.c14
-rw-r--r--net/mac80211/rx.c172
-rw-r--r--net/wireless/core.c15
-rw-r--r--net/wireless/debugfs.c33
-rw-r--r--net/wireless/nl80211.c3
-rw-r--r--net/wireless/util.c6
26 files changed, 288 insertions, 114 deletions
diff --git a/drivers/net/wireless/ath/wil6210/pm.c b/drivers/net/wireless/ath/wil6210/pm.c
index f521af575e9b..c866cfd144c7 100644
--- a/drivers/net/wireless/ath/wil6210/pm.c
+++ b/drivers/net/wireless/ath/wil6210/pm.c
@@ -458,6 +458,5 @@ void wil_pm_runtime_put(struct wil6210_priv *wil)
{
struct device *dev = wil_to_dev(wil);
- pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
}
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
index b264ed0af923..65d0f805459c 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -24,6 +24,7 @@
#include <linux/crc-ccitt.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/nvmem-consumer.h>
#include <linux/slab.h>
#include "rt2x00.h"
@@ -10962,6 +10963,36 @@ int rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev)
}
EXPORT_SYMBOL_GPL(rt2800_read_eeprom_efuse);
+int rt2800_read_eeprom_nvmem(struct rt2x00_dev *rt2x00dev)
+{
+ struct device_node *np = rt2x00dev->dev->of_node;
+ unsigned int len = rt2x00dev->ops->eeprom_size;
+ struct nvmem_cell *cell;
+ const void *data;
+ size_t retlen;
+
+ cell = of_nvmem_cell_get(np, "eeprom");
+ if (IS_ERR(cell))
+ return PTR_ERR(cell);
+
+ data = nvmem_cell_read(cell, &retlen);
+ nvmem_cell_put(cell);
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ if (retlen != len) {
+ dev_err(rt2x00dev->dev, "invalid eeprom size, required: 0x%04x\n", len);
+ kfree(data);
+ return -EINVAL;
+ }
+
+ memcpy(rt2x00dev->eeprom, data, len);
+ kfree(data);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt2800_read_eeprom_nvmem);
+
static u8 rt2800_get_txmixer_gain_24g(struct rt2x00_dev *rt2x00dev)
{
u16 word;
@@ -11011,7 +11042,9 @@ static int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev)
* Start validation of the data that has been read.
*/
mac = rt2800_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
- rt2x00lib_set_mac_address(rt2x00dev, mac);
+ retval = rt2x00lib_set_mac_address(rt2x00dev, mac);
+ if (retval)
+ return retval;
word = rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0);
if (word == 0xffff) {
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
index 620a3d9872ce..a3c3a751f57e 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
@@ -248,6 +248,8 @@ void rt2800_disable_radio(struct rt2x00_dev *rt2x00dev);
int rt2800_efuse_detect(struct rt2x00_dev *rt2x00dev);
int rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev);
+int rt2800_read_eeprom_nvmem(struct rt2x00_dev *rt2x00dev);
+
int rt2800_probe_hw(struct rt2x00_dev *rt2x00dev);
void rt2800_get_key_seq(struct ieee80211_hw *hw,
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800pci.c b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c
index 14c45aba836f..4fa14bb573ad 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c
@@ -278,6 +278,9 @@ static int rt2800pci_read_eeprom(struct rt2x00_dev *rt2x00dev)
{
int retval;
+ if (!rt2800_read_eeprom_nvmem(rt2x00dev))
+ return 0;
+
if (rt2800pci_efuse_detect(rt2x00dev))
retval = rt2800pci_read_eeprom_efuse(rt2x00dev);
else
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
index 8f510a84e7f1..5c29201b34c8 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
@@ -92,8 +92,12 @@ static int rt2800soc_set_device_state(struct rt2x00_dev *rt2x00dev,
static int rt2800soc_read_eeprom(struct rt2x00_dev *rt2x00dev)
{
- void __iomem *base_addr = ioremap(0x1F040000, EEPROM_SIZE);
+ void __iomem *base_addr;
+ if (!rt2800_read_eeprom_nvmem(rt2x00dev))
+ return 0;
+
+ base_addr = ioremap(0x1F040000, EEPROM_SIZE);
if (!base_addr)
return -ENOMEM;
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00.h b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
index 09b9d1f9f793..665887e9b118 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
@@ -1427,7 +1427,7 @@ static inline void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
*/
u32 rt2x00lib_get_bssidx(struct rt2x00_dev *rt2x00dev,
struct ieee80211_vif *vif);
-void rt2x00lib_set_mac_address(struct rt2x00_dev *rt2x00dev, u8 *eeprom_mac_addr);
+int rt2x00lib_set_mac_address(struct rt2x00_dev *rt2x00dev, u8 *eeprom_mac_addr);
/*
* Interrupt context handlers.
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
index f8a6f9c968a1..778a478ab53a 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
@@ -988,14 +988,20 @@ static void rt2x00lib_rate(struct ieee80211_rate *entry,
entry->flags |= IEEE80211_RATE_SHORT_PREAMBLE;
}
-void rt2x00lib_set_mac_address(struct rt2x00_dev *rt2x00dev, u8 *eeprom_mac_addr)
+int rt2x00lib_set_mac_address(struct rt2x00_dev *rt2x00dev, u8 *eeprom_mac_addr)
{
- of_get_mac_address(rt2x00dev->dev->of_node, eeprom_mac_addr);
+ int ret;
+
+ ret = of_get_mac_address(rt2x00dev->dev->of_node, eeprom_mac_addr);
+ if (ret == -EPROBE_DEFER)
+ return ret;
if (!is_valid_ether_addr(eeprom_mac_addr)) {
eth_random_addr(eeprom_mac_addr);
rt2x00_eeprom_dbg(rt2x00dev, "MAC: %pM\n", eeprom_mac_addr);
}
+
+ return 0;
}
EXPORT_SYMBOL_GPL(rt2x00lib_set_mac_address);
diff --git a/drivers/net/wireless/ti/wl18xx/debugfs.c b/drivers/net/wireless/ti/wl18xx/debugfs.c
index 80fbf740fe6d..ac756318e8ea 100644
--- a/drivers/net/wireless/ti/wl18xx/debugfs.c
+++ b/drivers/net/wireless/ti/wl18xx/debugfs.c
@@ -272,7 +272,6 @@ static ssize_t radar_detection_write(struct file *file,
if (ret < 0)
count = ret;
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
out:
mutex_unlock(&wl->mutex);
@@ -312,7 +311,6 @@ static ssize_t dynamic_fw_traces_write(struct file *file,
if (ret < 0)
count = ret;
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
out:
mutex_unlock(&wl->mutex);
@@ -374,7 +372,6 @@ static ssize_t radar_debug_mode_write(struct file *file,
wl->radar_debug_mode, 0);
}
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
out:
mutex_unlock(&wl->mutex);
diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c
index fa3a3f71dd15..9d73ba933a16 100644
--- a/drivers/net/wireless/ti/wlcore/cmd.c
+++ b/drivers/net/wireless/ti/wlcore/cmd.c
@@ -213,7 +213,6 @@ int wlcore_cmd_wait_for_event_or_timeout(struct wl1271 *wl,
} while (!event);
out:
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
free_vector:
kfree(events_vector);
diff --git a/drivers/net/wireless/ti/wlcore/debugfs.c b/drivers/net/wireless/ti/wlcore/debugfs.c
index eb3d3f0e0b4d..bbfd2725215b 100644
--- a/drivers/net/wireless/ti/wlcore/debugfs.c
+++ b/drivers/net/wireless/ti/wlcore/debugfs.c
@@ -63,7 +63,6 @@ void wl1271_debugfs_update_stats(struct wl1271 *wl)
wl->stats.fw_stats_update = jiffies;
}
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
out:
@@ -113,7 +112,6 @@ static void chip_op_handler(struct wl1271 *wl, unsigned long value,
chip_op = arg;
chip_op(wl);
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
}
@@ -287,7 +285,6 @@ static ssize_t dynamic_ps_timeout_write(struct file *file,
wl1271_ps_set_mode(wl, wlvif, STATION_AUTO_PS_MODE);
}
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
out:
@@ -357,7 +354,6 @@ static ssize_t forced_ps_write(struct file *file,
wl1271_ps_set_mode(wl, wlvif, ps_mode);
}
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
out:
@@ -830,7 +826,6 @@ static ssize_t rx_streaming_interval_write(struct file *file,
wl1271_recalc_rx_streaming(wl, wlvif);
}
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
out:
mutex_unlock(&wl->mutex);
@@ -886,7 +881,6 @@ static ssize_t rx_streaming_always_write(struct file *file,
wl1271_recalc_rx_streaming(wl, wlvif);
}
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
out:
mutex_unlock(&wl->mutex);
@@ -934,7 +928,6 @@ static ssize_t beacon_filtering_write(struct file *file,
ret = wl1271_acx_beacon_filter_opt(wl, wlvif, !!value);
}
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
out:
mutex_unlock(&wl->mutex);
@@ -1015,7 +1008,6 @@ static ssize_t sleep_auth_write(struct file *file,
goto out_sleep;
out_sleep:
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
out:
mutex_unlock(&wl->mutex);
@@ -1090,7 +1082,6 @@ read_err:
goto part_err;
part_err:
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
skip_read:
@@ -1172,7 +1163,6 @@ write_err:
goto part_err;
part_err:
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
skip_write:
@@ -1247,7 +1237,6 @@ static ssize_t fw_logger_write(struct file *file,
ret = wl12xx_cmd_config_fwlog(wl);
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
out:
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index 6116a8522d96..12f0167d7380 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -154,7 +154,6 @@ static void wl1271_rx_streaming_enable_work(struct work_struct *work)
jiffies + msecs_to_jiffies(wl->conf.rx_streaming.duration));
out_sleep:
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
out:
mutex_unlock(&wl->mutex);
@@ -181,7 +180,6 @@ static void wl1271_rx_streaming_disable_work(struct work_struct *work)
goto out_sleep;
out_sleep:
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
out:
mutex_unlock(&wl->mutex);
@@ -234,7 +232,6 @@ static void wlcore_rc_update_work(struct work_struct *work)
}
out_sleep:
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
out:
mutex_unlock(&wl->mutex);
@@ -711,7 +708,6 @@ static int wlcore_irq_locked(struct wl1271 *wl)
}
err_ret:
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
out:
@@ -1047,7 +1043,6 @@ static void wl1271_recovery_work(struct work_struct *work)
}
wlcore_op_stop_locked(wl);
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
ieee80211_restart_hw(wl->hw);
@@ -1943,7 +1938,6 @@ static int __maybe_unused wl1271_op_resume(struct ieee80211_hw *hw)
goto out_sleep;
out_sleep:
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
out:
@@ -2131,7 +2125,6 @@ static void wlcore_channel_switch_work(struct work_struct *work)
wl12xx_cmd_stop_channel_switch(wl, wlvif);
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
out:
mutex_unlock(&wl->mutex);
@@ -2201,7 +2194,6 @@ static void wlcore_pending_auth_complete_work(struct work_struct *work)
/* cancel the ROC if active */
wlcore_update_inconn_sta(wl, wlvif, NULL, false);
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
out:
mutex_unlock(&wl->mutex);
@@ -2694,7 +2686,6 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
else
wl->sta_count++;
out:
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
out_unlock:
mutex_unlock(&wl->mutex);
@@ -2774,7 +2765,6 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
}
}
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
}
deinit:
@@ -3200,7 +3190,6 @@ static int wl1271_op_config(struct ieee80211_hw *hw, int radio_idx, u32 changed)
}
out_sleep:
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
out:
@@ -3315,7 +3304,6 @@ static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
*/
out_sleep:
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
out:
@@ -3531,7 +3519,6 @@ static int wlcore_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
ret = wlcore_hw_set_key(wl, cmd, vif, sta, key_conf);
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
out_wake_queues:
@@ -3695,7 +3682,6 @@ static void wl1271_op_set_default_key_idx(struct ieee80211_hw *hw,
}
out_sleep:
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
out_unlock:
@@ -3724,7 +3710,6 @@ void wlcore_regdomain_config(struct wl1271 *wl)
goto out;
}
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
out:
mutex_unlock(&wl->mutex);
@@ -3772,7 +3757,6 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
ret = wlcore_scan(hw->priv, vif, ssid, len, req);
out_sleep:
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
out:
mutex_unlock(&wl->mutex);
@@ -3823,7 +3807,6 @@ static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
ieee80211_scan_completed(wl->hw, &info);
out_sleep:
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
out:
mutex_unlock(&wl->mutex);
@@ -3860,7 +3843,6 @@ static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
wl->sched_vif = wlvif;
out_sleep:
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
out:
mutex_unlock(&wl->mutex);
@@ -3887,7 +3869,6 @@ static int wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
wl->ops->sched_scan_stop(wl, wlvif);
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
out:
mutex_unlock(&wl->mutex);
@@ -3916,7 +3897,6 @@ static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw,
if (ret < 0)
wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
out:
@@ -3948,7 +3928,6 @@ static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx,
if (ret < 0)
wl1271_warning("set rts threshold failed: %d", ret);
}
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
out:
@@ -4714,7 +4693,6 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
else
wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
out:
@@ -4779,7 +4757,6 @@ static void wlcore_op_change_chanctx(struct ieee80211_hw *hw,
}
}
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
out:
mutex_unlock(&wl->mutex);
@@ -4828,7 +4805,6 @@ static int wlcore_op_assign_vif_chanctx(struct ieee80211_hw *hw,
wlvif->radar_enabled = true;
}
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
out:
mutex_unlock(&wl->mutex);
@@ -4871,7 +4847,6 @@ static void wlcore_op_unassign_vif_chanctx(struct ieee80211_hw *hw,
wlvif->radar_enabled = false;
}
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
out:
mutex_unlock(&wl->mutex);
@@ -4941,7 +4916,6 @@ wlcore_op_switch_vif_chanctx(struct ieee80211_hw *hw,
goto out_sleep;
}
out_sleep:
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
out:
mutex_unlock(&wl->mutex);
@@ -4995,7 +4969,6 @@ static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
0, 0);
out_sleep:
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
out:
@@ -5029,7 +5002,6 @@ static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
goto out_sleep;
out_sleep:
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
out:
@@ -5342,7 +5314,6 @@ static int wl12xx_op_sta_state(struct ieee80211_hw *hw,
ret = wl12xx_update_sta_state(wl, wlvif, sta, old_state, new_state);
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
out:
mutex_unlock(&wl->mutex);
@@ -5467,7 +5438,6 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
ret = -EINVAL;
}
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
out:
@@ -5511,7 +5481,6 @@ static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw,
wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
ret = wl1271_acx_sta_rate_policies(wl, wlvif);
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
}
out:
@@ -5566,7 +5535,6 @@ static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
}
out_sleep:
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
out:
@@ -5645,7 +5613,6 @@ static void wlcore_op_channel_switch_beacon(struct ieee80211_hw *hw,
set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags);
out_sleep:
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
out:
mutex_unlock(&wl->mutex);
@@ -5699,7 +5666,6 @@ static int wlcore_op_remain_on_channel(struct ieee80211_hw *hw,
ieee80211_queue_delayed_work(hw, &wl->roc_complete_work,
msecs_to_jiffies(duration));
out_sleep:
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
out:
mutex_unlock(&wl->mutex);
@@ -5748,7 +5714,6 @@ static int wlcore_roc_completed(struct wl1271 *wl)
ret = __wlcore_roc_completed(wl);
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
out:
mutex_unlock(&wl->mutex);
@@ -5839,7 +5804,6 @@ static void wlcore_op_sta_statistics(struct ieee80211_hw *hw,
sinfo->signal = rssi_dbm;
out_sleep:
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
out:
diff --git a/drivers/net/wireless/ti/wlcore/scan.c b/drivers/net/wireless/ti/wlcore/scan.c
index b414305acc32..f6dc54c1dbad 100644
--- a/drivers/net/wireless/ti/wlcore/scan.c
+++ b/drivers/net/wireless/ti/wlcore/scan.c
@@ -69,7 +69,6 @@ void wl1271_scan_complete_work(struct work_struct *work)
wlcore_cmd_regdomain_config_locked(wl);
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
ieee80211_scan_completed(wl->hw, &info);
diff --git a/drivers/net/wireless/ti/wlcore/sysfs.c b/drivers/net/wireless/ti/wlcore/sysfs.c
index 65ca5dc569a0..5ab6c1683675 100644
--- a/drivers/net/wireless/ti/wlcore/sysfs.c
+++ b/drivers/net/wireless/ti/wlcore/sysfs.c
@@ -58,7 +58,6 @@ static ssize_t bt_coex_state_store(struct device *dev,
goto out;
wl1271_acx_sg_enable(wl, wl->sg_enabled);
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
out:
diff --git a/drivers/net/wireless/ti/wlcore/testmode.c b/drivers/net/wireless/ti/wlcore/testmode.c
index fc8ea58bc165..7c0cb1b7fef0 100644
--- a/drivers/net/wireless/ti/wlcore/testmode.c
+++ b/drivers/net/wireless/ti/wlcore/testmode.c
@@ -127,7 +127,6 @@ static int wl1271_tm_cmd_test(struct wl1271 *wl, struct nlattr *tb[])
}
out_sleep:
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
out:
mutex_unlock(&wl->mutex);
@@ -192,7 +191,6 @@ static int wl1271_tm_cmd_interrogate(struct wl1271 *wl, struct nlattr *tb[])
out_free:
kfree(cmd);
out_sleep:
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
out:
mutex_unlock(&wl->mutex);
diff --git a/drivers/net/wireless/ti/wlcore/tx.c b/drivers/net/wireless/ti/wlcore/tx.c
index 464587d16ab2..f76087be2f75 100644
--- a/drivers/net/wireless/ti/wlcore/tx.c
+++ b/drivers/net/wireless/ti/wlcore/tx.c
@@ -863,7 +863,6 @@ void wl1271_tx_work(struct work_struct *work)
goto out;
}
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
out:
mutex_unlock(&wl->mutex);
diff --git a/drivers/net/wireless/ti/wlcore/vendor_cmd.c b/drivers/net/wireless/ti/wlcore/vendor_cmd.c
index e4269e2b0098..5bb9eb300f97 100644
--- a/drivers/net/wireless/ti/wlcore/vendor_cmd.c
+++ b/drivers/net/wireless/ti/wlcore/vendor_cmd.c
@@ -60,7 +60,6 @@ wlcore_vendor_cmd_smart_config_start(struct wiphy *wiphy,
ret = wlcore_smart_config_start(wl,
nla_get_u32(tb[WLCORE_VENDOR_ATTR_GROUP_ID]));
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
out:
mutex_unlock(&wl->mutex);
@@ -92,7 +91,6 @@ wlcore_vendor_cmd_smart_config_stop(struct wiphy *wiphy,
ret = wlcore_smart_config_stop(wl);
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
out:
mutex_unlock(&wl->mutex);
@@ -140,7 +138,6 @@ wlcore_vendor_cmd_smart_config_set_group_key(struct wiphy *wiphy,
nla_len(tb[WLCORE_VENDOR_ATTR_GROUP_KEY]),
nla_data(tb[WLCORE_VENDOR_ATTR_GROUP_KEY]));
- pm_runtime_mark_last_busy(wl->dev);
pm_runtime_put_autosuspend(wl->dev);
out:
mutex_unlock(&wl->mutex);
diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.c b/drivers/net/wireless/virtual/mac80211_hwsim.c
index 9f856042a67a..cd84dfd5b47e 100644
--- a/drivers/net/wireless/virtual/mac80211_hwsim.c
+++ b/drivers/net/wireless/virtual/mac80211_hwsim.c
@@ -5793,6 +5793,7 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
ieee80211_hw_set(hw, NO_AUTO_VIF);
wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
+ wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_PUNCT);
for (i = 0; i < ARRAY_SIZE(data->link_data); i++) {
hrtimer_setup(&data->link_data[i].beacon_timer, mac80211_hwsim_beacon,
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 781624f5913a..53490eb04e87 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1015,6 +1015,7 @@ const struct cfg80211_chan_def *
cfg80211_chandef_compatible(const struct cfg80211_chan_def *chandef1,
const struct cfg80211_chan_def *chandef2);
+
/**
* nl80211_chan_width_to_mhz - get the channel width in MHz
* @chan_width: the channel width from &enum nl80211_chan_width
@@ -5683,9 +5684,13 @@ struct wiphy_iftype_akm_suites {
*
* @rts_threshold: RTS threshold (dot11RTSThreshold);
* -1 (default) = RTS/CTS disabled
+ * @radio_debugfsdir: Pointer to debugfs directory containing the radio-
+ * specific parameters.
+ * NULL (default) = Debugfs directory not created
*/
struct wiphy_radio_cfg {
u32 rts_threshold;
+ struct dentry *radio_debugfsdir;
};
/**
@@ -6883,6 +6888,19 @@ static inline bool cfg80211_channel_is_psc(struct ieee80211_channel *chan)
}
/**
+ * ieee80211_radio_freq_range_valid - Check if the radio supports the
+ * specified frequency range
+ *
+ * @radio: wiphy radio
+ * @freq: the frequency (in KHz) to be queried
+ * @width: the bandwidth (in KHz) to be queried
+ *
+ * Return: whether or not the given frequency range is valid for the given radio
+ */
+bool ieee80211_radio_freq_range_valid(const struct wiphy_radio *radio,
+ u32 freq, u32 width);
+
+/**
* cfg80211_radio_chandef_valid - Check if the radio supports the chandef
*
* @radio: wiphy radio
diff --git a/include/net/ieee80211_radiotap.h b/include/net/ieee80211_radiotap.h
index 813e163ce27c..c60867e7e43c 100644
--- a/include/net/ieee80211_radiotap.h
+++ b/include/net/ieee80211_radiotap.h
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2017 Intel Deutschland GmbH
- * Copyright (c) 2018-2019, 2021-2022 Intel Corporation
+ * Copyright (c) 2018-2019, 2021-2022, 2025 Intel Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -202,6 +202,24 @@ enum ieee80211_radiotap_vht_coding {
IEEE80211_RADIOTAP_CODING_LDPC_USER3 = 0x08,
};
+enum ieee80211_radiotap_vht_bandwidth {
+ /* Note: more values are defined but can't really be used */
+ IEEE80211_RADIOTAP_VHT_BW_20 = 0,
+ IEEE80211_RADIOTAP_VHT_BW_40 = 1,
+ IEEE80211_RADIOTAP_VHT_BW_80 = 4,
+ IEEE80211_RADIOTAP_VHT_BW_160 = 11,
+};
+
+struct ieee80211_radiotap_vht {
+ __le16 known;
+ u8 flags;
+ u8 bandwidth;
+ u8 mcs_nss[4];
+ u8 coding;
+ u8 group_id;
+ __le16 partial_aid;
+} __packed;
+
/* for IEEE80211_RADIOTAP_TIMESTAMP */
enum ieee80211_radiotap_timestamp_unit_spos {
IEEE80211_RADIOTAP_TIMESTAMP_UNIT_MASK = 0x000F,
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index a55085cf4ec4..c326243e1f01 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1529,6 +1529,7 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info)
* known the frame shouldn't be reported.
* @RX_FLAG_8023: the frame has an 802.3 header (decap offload performed by
* hardware or driver)
+ * @RX_FLAG_RADIOTAP_VHT: VHT radiotap data is present
*/
enum mac80211_rx_flags {
RX_FLAG_MMIC_ERROR = BIT(0),
@@ -1564,6 +1565,7 @@ enum mac80211_rx_flags {
RX_FLAG_RADIOTAP_LSIG = BIT(28),
RX_FLAG_NO_PSDU = BIT(29),
RX_FLAG_8023 = BIT(30),
+ RX_FLAG_RADIOTAP_VHT = BIT(31),
};
/**
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 3b5827ea438e..025210d50405 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -2508,6 +2508,16 @@ static void ieee80211_csa_switch_work(struct wiphy *wiphy,
link->u.mgd.csa.waiting_bcn = true;
+ /*
+ * The next beacon really should always be different, so this should
+ * have no effect whatsoever. However, some APs (we observed this in
+ * an Asus AXE11000), the beacon after the CSA might be identical to
+ * the last beacon on the old channel - in this case we'd ignore it.
+ * Resetting the CRC will lead us to handle it better (albeit with a
+ * disconnect, but clearly the AP is broken.)
+ */
+ link->u.mgd.beacon_crc_valid = false;
+
/* apply new TPE restrictions immediately on the new channel */
if (link->u.mgd.csa.ap_chandef.chan->band == NL80211_BAND_6GHZ &&
link->u.mgd.conn.mode >= IEEE80211_CONN_MODE_HE) {
@@ -6610,8 +6620,8 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_link_data *link,
* Response frame shall be set to the broadcast address [..]"
* So, on 6GHz band we should also accept broadcast responses.
*/
- channel = ieee80211_get_channel(sdata->local->hw.wiphy,
- rx_status->freq);
+ channel = ieee80211_get_channel_khz(sdata->local->hw.wiphy,
+ ieee80211_rx_status_to_khz(rx_status));
if (!channel)
return;
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 6af43dfefdd6..80067ed1da2f 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -59,7 +59,8 @@ static struct sk_buff *ieee80211_clean_skb(struct sk_buff *skb,
status->flag &= ~(RX_FLAG_RADIOTAP_TLV_AT_END |
RX_FLAG_RADIOTAP_LSIG |
RX_FLAG_RADIOTAP_HE_MU |
- RX_FLAG_RADIOTAP_HE);
+ RX_FLAG_RADIOTAP_HE |
+ RX_FLAG_RADIOTAP_VHT);
hdr = (void *)skb->data;
fc = hdr->frame_control;
@@ -151,8 +152,10 @@ ieee80211_rx_radiotap_hdrlen(struct ieee80211_local *local,
}
if (status->encoding == RX_ENC_VHT) {
+ /* Included even if RX_FLAG_RADIOTAP_VHT is not set */
len = ALIGN(len, 2);
len += 12;
+ BUILD_BUG_ON(sizeof(struct ieee80211_radiotap_vht) != 12);
}
if (local->hw.radiotap_timestamp.units_pos >= 0) {
@@ -195,6 +198,9 @@ ieee80211_rx_radiotap_hdrlen(struct ieee80211_local *local,
* The position to look at depends on the existence (or non-
* existence) of other elements, so take that into account...
*/
+ if (status->flag & RX_FLAG_RADIOTAP_VHT)
+ tlv_offset +=
+ sizeof(struct ieee80211_radiotap_vht);
if (status->flag & RX_FLAG_RADIOTAP_HE)
tlv_offset +=
sizeof(struct ieee80211_radiotap_he);
@@ -319,10 +325,17 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
u32 tlvs_len = 0;
int mpdulen, chain;
unsigned long chains = status->chains;
+ struct ieee80211_radiotap_vht vht = {};
struct ieee80211_radiotap_he he = {};
struct ieee80211_radiotap_he_mu he_mu = {};
struct ieee80211_radiotap_lsig lsig = {};
+ if (status->flag & RX_FLAG_RADIOTAP_VHT) {
+ vht = *(struct ieee80211_radiotap_vht *)skb->data;
+ skb_pull(skb, sizeof(vht));
+ WARN_ON_ONCE(status->encoding != RX_ENC_VHT);
+ }
+
if (status->flag & RX_FLAG_RADIOTAP_HE) {
he = *(struct ieee80211_radiotap_he *)skb->data;
skb_pull(skb, sizeof(he));
@@ -530,45 +543,61 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
}
if (status->encoding == RX_ENC_VHT) {
- u16 known = local->hw.radiotap_vht_details;
+ u16 fill = local->hw.radiotap_vht_details;
- rthdr->it_present |= cpu_to_le32(BIT(IEEE80211_RADIOTAP_VHT));
- put_unaligned_le16(known, pos);
- pos += 2;
- /* flags */
- if (status->enc_flags & RX_ENC_FLAG_SHORT_GI)
- *pos |= IEEE80211_RADIOTAP_VHT_FLAG_SGI;
+ /* Leave driver filled fields alone */
+ fill &= ~le16_to_cpu(vht.known);
+ vht.known |= cpu_to_le16(fill);
+
+ if (fill & IEEE80211_RADIOTAP_VHT_KNOWN_GI &&
+ status->enc_flags & RX_ENC_FLAG_SHORT_GI)
+ vht.flags |= IEEE80211_RADIOTAP_VHT_FLAG_SGI;
/* in VHT, STBC is binary */
- if (status->enc_flags & RX_ENC_FLAG_STBC_MASK)
- *pos |= IEEE80211_RADIOTAP_VHT_FLAG_STBC;
- if (status->enc_flags & RX_ENC_FLAG_BF)
+ if (fill & IEEE80211_RADIOTAP_VHT_KNOWN_STBC &&
+ status->enc_flags & RX_ENC_FLAG_STBC_MASK)
+ vht.flags |= IEEE80211_RADIOTAP_VHT_FLAG_STBC;
+ if (fill & IEEE80211_RADIOTAP_VHT_KNOWN_BEAMFORMED &&
+ status->enc_flags & RX_ENC_FLAG_BF)
*pos |= IEEE80211_RADIOTAP_VHT_FLAG_BEAMFORMED;
- pos++;
- /* bandwidth */
- switch (status->bw) {
- case RATE_INFO_BW_80:
- *pos++ = 4;
- break;
- case RATE_INFO_BW_160:
- *pos++ = 11;
- break;
- case RATE_INFO_BW_40:
- *pos++ = 1;
- break;
- default:
- *pos++ = 0;
+
+ if (fill & IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH) {
+ switch (status->bw) {
+ case RATE_INFO_BW_40:
+ vht.bandwidth = IEEE80211_RADIOTAP_VHT_BW_40;
+ break;
+ case RATE_INFO_BW_80:
+ vht.bandwidth = IEEE80211_RADIOTAP_VHT_BW_80;
+ break;
+ case RATE_INFO_BW_160:
+ vht.bandwidth = IEEE80211_RADIOTAP_VHT_BW_160;
+ break;
+ default:
+ vht.bandwidth = IEEE80211_RADIOTAP_VHT_BW_20;
+ break;
+ }
}
- /* MCS/NSS */
- *pos = (status->rate_idx << 4) | status->nss;
- pos += 4;
- /* coding field */
- if (status->enc_flags & RX_ENC_FLAG_LDPC)
- *pos |= IEEE80211_RADIOTAP_CODING_LDPC_USER0;
- pos++;
- /* group ID */
- pos++;
- /* partial_aid */
- pos += 2;
+
+ /*
+ * If the driver filled in mcs_nss[0], then do not touch it.
+ *
+ * Otherwise, put some information about MCS/NSS into the
+ * user 0 field. Note that this is not technically correct for
+ * an MU frame as we might have decoded a different user.
+ */
+ if (!vht.mcs_nss[0]) {
+ vht.mcs_nss[0] = (status->rate_idx << 4) | status->nss;
+
+ /* coding field */
+ if (status->enc_flags & RX_ENC_FLAG_LDPC)
+ vht.coding |= IEEE80211_RADIOTAP_CODING_LDPC_USER0;
+ }
+
+ /* ensure 2 byte alignment */
+ while ((pos - (u8 *)rthdr) & 1)
+ pos++;
+ rthdr->it_present |= cpu_to_le32(BIT(IEEE80211_RADIOTAP_VHT));
+ memcpy(pos, &vht, sizeof(vht));
+ pos += sizeof(vht);
}
if (local->hw.radiotap_timestamp.units_pos >= 0) {
@@ -763,6 +792,51 @@ ieee80211_make_monitor_skb(struct ieee80211_local *local,
return skb;
}
+static bool
+ieee80211_validate_monitor_radio(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_local *local,
+ struct ieee80211_rx_status *status)
+{
+ struct wiphy *wiphy = local->hw.wiphy;
+ int i, freq, bw;
+
+ if (!wiphy->n_radio)
+ return true;
+
+ switch (status->bw) {
+ case RATE_INFO_BW_20:
+ bw = 20000;
+ break;
+ case RATE_INFO_BW_40:
+ bw = 40000;
+ break;
+ case RATE_INFO_BW_80:
+ bw = 80000;
+ break;
+ case RATE_INFO_BW_160:
+ bw = 160000;
+ break;
+ case RATE_INFO_BW_320:
+ bw = 320000;
+ break;
+ default:
+ return false;
+ }
+
+ freq = MHZ_TO_KHZ(status->freq);
+
+ for (i = 0; i < wiphy->n_radio; i++) {
+ if (!(sdata->wdev.radio_mask & BIT(i)))
+ continue;
+
+ if (!ieee80211_radio_freq_range_valid(&wiphy->radio[i], freq, bw))
+ continue;
+
+ return true;
+ }
+ return false;
+}
+
/*
* This function copies a received frame to all monitor interfaces and
* returns a cleaned-up SKB that no longer includes the FCS nor the
@@ -789,6 +863,9 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
return NULL;
}
+ if (status->flag & RX_FLAG_RADIOTAP_VHT)
+ rtap_space += sizeof(struct ieee80211_radiotap_vht);
+
if (status->flag & RX_FLAG_RADIOTAP_HE)
rtap_space += sizeof(struct ieee80211_radiotap_he);
@@ -855,6 +932,10 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
chandef->chan->center_freq != status->freq)
continue;
+ if (ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR) &&
+ !ieee80211_validate_monitor_radio(sdata, local, status))
+ continue;
+
if (!prev_sdata) {
prev_sdata = sdata;
continue;
@@ -3521,8 +3602,11 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
switch (mgmt->u.action.category) {
case WLAN_CATEGORY_HT:
- /* reject HT action frames from stations not supporting HT */
- if (!rx->link_sta->pub->ht_cap.ht_supported)
+ /* reject HT action frames from stations not supporting HT
+ * or not HE Capable
+ */
+ if (!rx->link_sta->pub->ht_cap.ht_supported &&
+ !rx->link_sta->pub->he_cap.has_he)
goto invalid;
if (sdata->vif.type != NL80211_IFTYPE_STATION &&
@@ -4903,6 +4987,11 @@ static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx,
/* after this point, don't punt to the slowpath! */
+ if (fast_rx->uses_rss)
+ stats = this_cpu_ptr(rx->link_sta->pcpu_rx_stats);
+ else
+ stats = &rx->link_sta->rx_stats;
+
if (rx->key && !(status->flag & RX_FLAG_MIC_STRIPPED) &&
pskb_trim(skb, skb->len - fast_rx->icv_len))
goto drop;
@@ -4937,6 +5026,8 @@ static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx,
res = ieee80211_rx_mesh_data(rx->sdata, rx->sta, rx->skb);
switch (res) {
case RX_QUEUED:
+ stats->last_rx = jiffies;
+ stats->last_rate = sta_stats_encode_rate(status);
return true;
case RX_CONTINUE:
break;
@@ -4950,11 +5041,6 @@ static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx,
drop:
dev_kfree_skb(skb);
- if (fast_rx->uses_rss)
- stats = this_cpu_ptr(rx->link_sta->pcpu_rx_stats);
- else
- stats = &rx->link_sta->rx_stats;
-
stats->dropped++;
return true;
}
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 797f9f2004a6..f3568eb5e592 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -34,6 +34,9 @@
/* name for sysfs, %d is appended */
#define PHY_NAME "phy"
+/* maximum length of radio debugfs directory name */
+#define RADIO_DEBUGFSDIR_MAX_LEN 8
+
MODULE_AUTHOR("Johannes Berg");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("wireless configuration support");
@@ -1042,6 +1045,18 @@ int wiphy_register(struct wiphy *wiphy)
/* add to debugfs */
rdev->wiphy.debugfsdir = debugfs_create_dir(wiphy_name(&rdev->wiphy),
ieee80211_debugfs_dir);
+ if (wiphy->n_radio > 0) {
+ int idx;
+ char radio_name[RADIO_DEBUGFSDIR_MAX_LEN];
+
+ for (idx = 0; idx < wiphy->n_radio; idx++) {
+ scnprintf(radio_name, sizeof(radio_name), "radio%d",
+ idx);
+ wiphy->radio_cfg[idx].radio_debugfsdir =
+ debugfs_create_dir(radio_name,
+ rdev->wiphy.debugfsdir);
+ }
+ }
cfg80211_debugfs_rdev_add(rdev);
nl80211_notify_wiphy(rdev, NL80211_CMD_NEW_WIPHY);
diff --git a/net/wireless/debugfs.c b/net/wireless/debugfs.c
index 40e49074e2ee..f9e7fff1ef25 100644
--- a/net/wireless/debugfs.c
+++ b/net/wireless/debugfs.c
@@ -29,6 +29,24 @@ static const struct file_operations name## _ops = { \
.llseek = generic_file_llseek, \
}
+#define DEBUGFS_RADIO_READONLY_FILE(name, buflen, fmt, value...) \
+static ssize_t name## _read(struct file *file, char __user *userbuf, \
+ size_t count, loff_t *ppos) \
+{ \
+ struct wiphy_radio_cfg *radio_cfg = file->private_data; \
+ char buf[buflen]; \
+ int res; \
+ \
+ res = scnprintf(buf, buflen, fmt "\n", ##value); \
+ return simple_read_from_buffer(userbuf, count, ppos, buf, res); \
+} \
+ \
+static const struct file_operations name## _ops = { \
+ .read = name## _read, \
+ .open = simple_open, \
+ .llseek = generic_file_llseek, \
+}
+
DEBUGFS_READONLY_FILE(rts_threshold, 20, "%d",
wiphy->rts_threshold);
DEBUGFS_READONLY_FILE(fragmentation_threshold, 20, "%d",
@@ -38,6 +56,9 @@ DEBUGFS_READONLY_FILE(short_retry_limit, 20, "%d",
DEBUGFS_READONLY_FILE(long_retry_limit, 20, "%d",
wiphy->retry_long);
+DEBUGFS_RADIO_READONLY_FILE(radio_rts_threshold, 20, "%d",
+ radio_cfg->rts_threshold);
+
static int ht_print_chan(struct ieee80211_channel *chan,
char *buf, int buf_size, int offset)
{
@@ -100,15 +121,27 @@ static const struct file_operations ht40allow_map_ops = {
#define DEBUGFS_ADD(name) \
debugfs_create_file(#name, 0444, phyd, &rdev->wiphy, &name## _ops)
+#define DEBUGFS_RADIO_ADD(name, radio_idx) \
+ debugfs_create_file(#name, 0444, radiod, \
+ &rdev->wiphy.radio_cfg[radio_idx], \
+ &name## _ops)
+
void cfg80211_debugfs_rdev_add(struct cfg80211_registered_device *rdev)
{
struct dentry *phyd = rdev->wiphy.debugfsdir;
+ struct dentry *radiod;
+ u8 i;
DEBUGFS_ADD(rts_threshold);
DEBUGFS_ADD(fragmentation_threshold);
DEBUGFS_ADD(short_retry_limit);
DEBUGFS_ADD(long_retry_limit);
DEBUGFS_ADD(ht40allow_map);
+
+ for (i = 0; i < rdev->wiphy.n_radio; i++) {
+ radiod = rdev->wiphy.radio_cfg[i].radio_debugfsdir;
+ DEBUGFS_RADIO_ADD(radio_rts_threshold, i);
+ }
}
struct debugfs_read_work {
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 346dfd2bd987..ceca47cd9e25 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -3544,6 +3544,9 @@ static int _nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
return -EINVAL;
}
+ if (cfg80211_chandef_is_s1g(chandef))
+ chandef->width = NL80211_CHAN_WIDTH_1;
+
if (attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
enum nl80211_channel_type chantype;
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 56724b33af04..97f40c6d1e9d 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -2942,9 +2942,8 @@ cfg80211_get_iftype_ext_capa(struct wiphy *wiphy, enum nl80211_iftype type)
}
EXPORT_SYMBOL(cfg80211_get_iftype_ext_capa);
-static bool
-ieee80211_radio_freq_range_valid(const struct wiphy_radio *radio,
- u32 freq, u32 width)
+bool ieee80211_radio_freq_range_valid(const struct wiphy_radio *radio,
+ u32 freq, u32 width)
{
const struct wiphy_radio_freq_range *r;
int i;
@@ -2958,6 +2957,7 @@ ieee80211_radio_freq_range_valid(const struct wiphy_radio *radio,
return false;
}
+EXPORT_SYMBOL(ieee80211_radio_freq_range_valid);
bool cfg80211_radio_chandef_valid(const struct wiphy_radio *radio,
const struct cfg80211_chan_def *chandef)